原文地址https://blog.csdn.net/astrotycoon/article/details/8881809
今天阅读巨龙公司系统集成开发部 杨屹 的《uCOS51移植心得》时看到一句话:RETI指令复位中断系统,RET则没有。实践表明,对于MCS-51,用子程序调用入栈,用中断返回指令RETI出栈是没有问题的,反之中断入栈RET出栈则不行。总之,对于入栈,子程序调用与中断调用效果是一样的,可以混用。在没有中断发生的情况下复位中断系统也不会影响系统正常运行。具体原因,文中并没有点明。由此引发ret和reti指令到底什么区别呢?
查看帮助手册,关于reti的说明如下:
RETI
The RETI instruction is used to end an interrupt service routine. This instruction pops the high-order and low-order bytes of the PC (and decrements the stack pointer by 2) and restores the interrput logic to accept additional interrupts. No other registers are affected by this instruction.
The RETI instruction does not restore the PSW to its value before the interrupt. The interrupt service routine must save and restore the PSW.
Execution returns to the instruction immediately after the point at which the interrupt was detected. If another interrupt was pending when the RETI instruction is executed, one instruction at the return address is executed before the pending interrupt is processed.
See Also: RET
关于ret的说明如下:
RET
The RET instruction pops the high-order and low-order bytes of the PC from the stack (and decrements the stack pointer by 2). Program execution resumes from the resulting address which is typically the instruction following an ACALL or LCALL instruction. No flags are affected by this instruction.
See Also: ACALL, LCALL
过一眼便知,reti做的事肯定比ret多(傻啊,只要不眼瞎都能看出来 ^_^)
先来说说两个指令做的相同的部分:从堆栈中依次弹出2个字节到PC的高位字节和低位字节, 都没有将PSW出栈的过程,所以系统在响应中断前,只将程序指针PC保存起来 PSW却没有保护起来。—— 这点与8086有些不同,8086中ret指令要做的就是从堆栈中弹出一个字到指令指针寄存器 IP 中,而iret从堆栈中弹出(恢复)IP、CS 和 FLAGS 的原始内容,于是转到主程序接着执行。
因为没有保存PSW,所以 中断服务程序中首先应该把PSW保存在栈中或者寄存器中,在中断服务程序结束前,再将PSW的值恢复,使正常程序流程不被破坏。
两者的区别呢? 从上面可以看到,reti还要恢复什么interrupt logic,那么interrupt logic是什么呢?
百度之 ... ...
以下内容来自网络:
------------------------------------------------------------------------------------------------------------------------------------------
资料指出“根据8051的结构特点,其中断系统中含有两个不可寻址的“优先级生效”触发器。一个用于指出CPU是否正在执行高优先级的中断服务程序,这个触发器为1时,系统将屏蔽所有的中断请求;另一个则指出CPU是否正在执行低优先级中断服务程序,该触发器为1时,将阻止除高优先级以外的一切中断请求。由此可见,若要响应同级甚至是低级中断请求,必须使得该“优先级生效”触发器清零。但该触发器又是不可寻址的,所以无法用软件直接清零。
通常情况下,在普通的汇编子程序中用RET做返回,在中断服务子程序中用RETI起中断返回作用。两条指令都能从堆栈中弹出断点地址并装入PC中,使 CPU回到原来主程序的断点处继续运行。然而,RET和RETI有本质的区别:当某一中断源响应后,单片机中的标志寄存器flag H和flag L其中的一个将会自动置位,用于阻止比它低级或同级的中断触发。RETI可以清除“优先级激活触发器”(即flag寄存器),以保证后续中断源的及时响应。所以,当把RETI替换为RET后,该程序在第一次运行时可能不会出错,但在第二次运行时就会出错了!
------------------------------------------------------------------------------------------------------------------------------------------
意思就是说:51内核中有两个不可见的中断优先级状态寄存器,用于指示发生了中断。 因为有二级中断,所以用了两个。 当用reti返回时,除了执行ret相同的功能外,还会清相应的的状态的寄存器。如果在中断中用ret返回,由于没清相应的状态寄存器,则此后不能进同级别中断。
reti除了相关的栈操作以外,还有可能要清除一些可以硬件清除的中断请求标志位,同时复位中断控制系统,以使后继发生的中断可以被有效响应。可以设想,如果允许在中断服务子程序中使用RET返回会导致CPU对该返回操作的二义理解:究竟是中断服务子程序的返回呢,还是在中断中调用了某一个子函数的返回呢?毕竟我们不能不允许在中断服务子程序中调用其他子函数吧?
所以,为了消除这种二义性,在中断服务子程序中使用reti返回~!
总结以下:
① 在非中断过程调用的子程序用ret和reti返回是可以相互替代的 -- 因为在没有中断发生的情况下复位中断系统也不会影响系统正常运行。
② 如果在中断过程中调用的子程序也用reti返回,那么中断状态寄存器触发器会被提前清除,那么实际上中断过程仍在继续,而这时又有其他中断源来临(即便中断源优先级和此时中断程序的优先级相比低或者相同),系统也会响应新的中断源。
③ 如果在中断服务程序中的返回用的是ret来代替,虽然响应完一次中断后能正常返回,但是中断状态寄存器触发器没有被清除。那么如果有比其优先级低或者优先级相同的中断请求,MCS-51将不会响应请求, 但是只要程序中任何地方再执行一次RETI(比如子程序返回),中断仍会继续响应
④ 在中断服务程序总PUSH和POP指令必须成对使用,否则不能正确返回断点(其实非中断过程调用也一样)
简而言之
中断函数返回用reti,
普通函数返回及中断函数中调用的普通函数返回用ret。
参考链接:
http://www.cnblogs.com/alimy/archive/2013/02/22/2921765.html
http://bbs.huazhoucn.com/Temp/Temp4180_1.html
http://wenku.baidu.com/view/a4416136b90d6c85ec3ac652.html
---------------------
作者:astrotycoon
来源:CSDN
原文:https://blog.csdn.net/astrotycoon/article/details/8881809
版权声明:本文为博主原创文章,转载请附上博文链接!