马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 skyonline 于 2014-2-7 13:53 编辑
教材中关于调用子程序和中断子程序现场保护描述的原理性错误
杨成安
(开封大学信息工程学院,河南 开封 475000)
摘要: 本文论述了全国计算机专业《微机原理、接口电路和汇编语言程序设计》教材中关于调用子程序和中断子程序中现场保护描述的原理性错误。指明了二者的不同性质,并试图给出了不同的、正确现场保护与现场恢复的思维方法。 关键词: 调用子程序,中断子程序,现场保护,现场恢复,入口参数,出口参数 一、问题的提出 1.关于调用子程序现场保护的描述(注:文中下划线为本文作者所加) ①谭浩强主编,清华大学出版社,2001年版《微机原理与接口电路》,第97页 现场保护和返回 所谓保护现场就是主程序执行CALL指令之前,主程序使用的某些寄存器,在子程序中也要使用,因而在进入子程序之初,首先将这些寄存器的内容保护(压栈)起来,以免子程序中重复使用这些寄存器,破坏主程序的执行结果。恢复现场就是在子程序返回前,将原来保护的数据重新返回(出栈)相应的寄存器…… ②谭版P97举例: [例4.48] 子程序名:PZN 子程序功能:统计一组数据中的正数和零的个数。 入口参数:数组首址在SI中,数组个数在CX中。 出口参数:正数个数在AX中,零的个数在BX中。 使用的寄存器:AX、BX、SI、PSW(注:使用的寄存器漏掉了CX!) 子程序如下: PZN:PUSH SI ;保护现场 PUSH CX ; : : POP CX ; 恢复现场 POP SI ; RET ③谭版举例:共12个调用子程序举例 P127~P141 [例:5.42]~[例:5.53] 2.关于中断子程序现场保护的描述 ①谭版第188页描述 保护现场是把CPU转入中断服务程序前所使用的有关各寄存器的内容和标志位的状态,用PUSH指令压入堆栈保护起来。中断服务结束后,再POP指令弹出,恢复中断前各寄存器的内容和标志位的状态。 ②谭版第188页图8.11 ③引用谭版举例第255页[例:9.4] 中断服务程序 ORG 1200H CLI ;关中断 MOV AL,[DI] OUT DX, 02F0H : INC DI DEC AH STI ;开中断 IRET
④谭版256页[例9.5]及293页[例:9.10](略)
二、问题的分析 1.关于调用子程序现场保护错误的分析 ①谭版中第97页描述的错误 谭版认为调用子程序应在“进入程序之初”,进行现场保护,而且“在子程序返回前恢复现场”,错误在于“绝对化”,即应该视入口参数和入口参数的不同,而有不同的保护和恢复现场,理由请看下文结论。 ②谭版[例:4.48]错误分析 1>题目中,使用的寄存器漏掉了CX,丢三拉四是编不了程序的! 2>在PZN子程序中,按谭版前边所述理论,首先保护了SI和CX,但保护的是主程序中的内容吗?而题目中已注明,SI和CX中是入口参数,则必然在主程序中调用PZN子程序前,要先赋两个入口参数,那么此时在主程序中并没有保护SI和CX(因为谭版认为应在子程序执行中保护现场!)而主程序中原来SI和CX中的内容却已经丢失了! 同理,恢复现场的POP CX和POP SI指令,恢复的只能是原来的入口参数,并不是主程序应保护的内容。故而证明主程序中SI、CX内容确已丢失! 3>题目中是注明PZN子程序中还使用到AX、BX及PSW状态字。 莫名其妙,根本就没有进行保护! 4>所以我们认为,调用子程序中所用到的寄存器在使用寄存器做参数传递方法时是根本不能在子程序中保护的。 5>综观谭版[例:5.42]~[例:5.53]共12个调用子程序的举例,都犯同样的错误! 2.关于中断子程序谭版现场保护描述错误的分析 ①谭版的第188页关于中断子程序现场保护的描述,仅仅给出用PUSH指令压入堆栈保护和用POP指令弹出恢复,而根本没有指明为什么要保护和怎样保护。 ②谭版第188页图8.11中,在恢复现场前并没有进行关中断,即谭版认为恢复现场的过程中,是允许高级中断来破坏这恢复现场的过程的,显然是错误的,恢复现场应和保护现场一样应关中断,否则返回主程序时,照样会破坏原来寄存器的内容的! ③在上文中引用谭版第255页[例9.4]来看,中断子程序中根本就没有什么现场保护和现场恢复!为什么? ④是一时的笔误吗?非也,综观,谭版256页[例9.5]和293页[例:9.10]中的中断子程序,也都没有现场保护和恢复,这还是中断子程序吗?
三、问题的我见 1.关于调用子程序和中断子程序 ①调用子程序的性质 1>调用子程序是主程序的一部分,完成的是同一个算法。 2>主程序对所调用的子程序是已知的,是主动的,是在主程序的固定位置调用的。 3>主程序在调用子程序之前应先赋入口参数,调用后应处理出口参数。 4>参数传递(即入口参数和出口参数)的方法有三种,即CPU寄存器、内存数据区和内存堆栈区。 ②参数传递方式不同则现场保护和恢复的方法亦不同。 1>CPU寄存器参数传递方式中,由于主程序在调用子程序之前要对CPU寄存器赋入口参数,故此时已经被破坏了主程序原来的参数。故应在主程序中,赋入口参数之前压栈保护。同理,也应在主程序中,处理完出口参数后,出栈恢复现场。 2>内存数据区参数传递方式中,由于主程序无须动用CPU寄存器赋入口参数,故此方法可以在进入子程序之初保护那些子程序中用到的CPU寄存器内容!同理也可以在返回主程序之前恢复现场。 3>内存堆栈区参数传递方式,问题较难,故须小心使用,注意事项有: a.由于主程序传递的参数压在堆栈中主程序断点的下面,故应采用堆栈分区的办法解决,即必须充分掌握改变SS或SP指针的技巧。 b.用堆栈参数传递,由于堆栈必须顺序入栈,且反顺序出栈,使用参数时难度也很大。 2.关于中断子程序 ①中断子程序与主程序是风马牛不相及的两码事,完成的根本不是同一个算法。 ②主程序对中断子程序是未知的,是被动的;中断是随机地在主程序的某位置产生的。 ③故主程序根本无法在主程序中予赋参数、保护现场和恢复现场的。 ④故中断子程序的保护现场和恢复现场只能在中断子程序中完成。 ⑤而且在保护和恢复现场时,不能允许高级中断的产生,8086CPU在响应中断时,自动完成关中断(和保护PSW字即FR寄存器内容)故只有在恢复现场前须考虑再关中断的问题,而且应有两个关中断,即关中断和关单步中断。 ⑥在中断子程序返回主程序后,请注意:主程序应是开中断状态,而这个任务在8086CPU中则是由IRET来完成了,该指令包括开中断的隐含操作。(而在8080和Z80CPU中则无此隐含操作,应在中断返回指令前加上开中断指令,否则主程序以后就无法再响应其它中断,而且这个问题会隐蔽的很深,不易发现!并且此开中断指令是延时在中断返回指令后实施的,否则将会产生未返回主程序,又响应其它中断而产生错误。) ⑦中断子程序参数传递只能在内存数据区中进行,并且也只能主程序初始化时完成。
四、问题的意义 综上所述,汇编语言的编程问题很复杂,例如本文中的问题,单靠压栈和出栈是说不清楚的,也是会犯错误的!那么首先搞懂原理,再要有严格的逻辑思维能力,方能写出连一位0、1代码都不能错的可执行汇编源程序,站在高级语言层面上,来看待汇编语言的编程是行不通的。
参考文献: [1]《微机原理与接口技术》谭浩强主编 清华大学出版社 2001年9月1 [2]《微型计算机原理及其应用》陆一青编 哈尔滨工业大学出版社 1991年8月1日 [3]《微型计算机硬件软件及其应用》周明德编 清华大学出版社 1982年10月1日 [4]《计算机组成原理与汇编语言程序设计》俸远祯等 电子工业出版社 1997年6月2日 [5]《微型计算机》朱绍庐编 人民交通出版社 1983年 5月 [6]《微型计算机1BM—PC/XT(0520系列)系统原理及应用》周明德 清华大学出版社1991年7月 [7]《微型计算机原理及其应用》 陈卜锁主编 上海交通大学出版社 2001年1月 [8]《微型计算机组成原理与接口技术》 赵佩华等编 西安电子科技大学出版社 2001年8月 [9]《微机系统与接口技术》 吴产乐主编 华中科技大学出版社 2002年1月
作者简介:杨成安(1947-),男,北京市人,任课题组组长,1982年毕业于吉林大学计算机科学系系统结构专业,师从于王湘浩先生。现任开封大学信息工程学院教授,主要从事计算机专业基础教学和科研、主攻方向计算机系统结构,荣获日内瓦国际专利博览会金奖,日内瓦世界发明家公会会员等。
|