51单片机SP指向的系统栈中都有什么?LCALL、RETI等解析

在调用函数时,也即当执行LCALL、ACALL等汇编指令时,硬件首先把PC指针压入到SP指向的系统栈(PC不可寻址,无法用程序出入栈,只能由硬件自动完成),随着函数调用链条不断加长,SP指向的系统栈被占用的空间越来越多。

下面看一下执行ACALL和LCALL时,硬件为我们自动做了什么? (这些信息都能从帮助文件中找到,keil->Help->uVision Help打开帮助文件,依次展开8051 instruction set指令集->Instructions)

ACALL等价于:
(下述代码由硬件自动完成)
PC = PC + 2
SP = SP + 1
(SP) = PC[7-0]
SP = SP + 1
(SP) = PC[15-8]
PC[10-0] = A[10-0]        
LCALL等价于:                          

PC = PC + 3
SP = SP + 1
(SP) = PC[7-0]
SP = SP + 1
(SP) = PC[15-8]
PC = addr16                     

PC存放的是下一条要执行的指令,在调用子函数前,要把紧跟ACALL/LCALL指令后面的一条指令的ROM地址入栈,因为ACALL指令本身占用2字节,LCALL占用3字节,所以上面

的代码才一个PC+2,一个PC+3。

这里顺便再提一下函数(子程序)的返回指令:RET和RETI,RET用于普通子程序返回,这两个指令对应的硬件自动代码如下(来自于keil的帮助文件):

RET:
PC[15-8] = (SP)
SP = SP - 1
PC[7-0] = (SP)
SP = SP - 1
|
|
|
RETI:
PC[15-8] = (SP)
SP = SP - 1
PC[7-0] = (SP)
SP = SP - 1
执行完上述伪代码之后,
恢复中断逻辑,
以便接收下一个中断。

可以看到,RET和RETI在对PC和SP的处理上一模一样,区别在于,RETI还额外地要恢复一下中断逻辑,(因为同优先级的中断不可嵌套,不可嵌套的实现机制就是靠的这个中断逻辑,如果我们在中断服务函数中使用了RET来返回,中断逻辑得不到恢复的话,那么同优先级以及更低优先级的中断将无法响应)


对于51单片机,SP指向的系统栈的内容就两部分:

(1)是上面所述的CALL指令压入的PC指针;

(2)是中断服务函数为保护现场而手动压入的A、B、PSW、DPTR等,(keil编译生成的汇编不会把Rn入栈,只会使用using指令切换工作寄存器组,也即切换BANK,但是如果中断服务代码我们使用汇编自己写的话,也可以不切换BANK,而把Rn入栈)。可参考keil帮助文件,依次展开CX51 Compiler User‘s Guide-> Language Extensions -> Function Declarations -Interrupt > Interrupt Functions

对于STM32等单片机,在仅使用MSP的情况下,MSP的栈中除了上述2个部分以外,还会有第3部分:函数的形参和局部变量(Rn不足时);若Rn足以容纳形参和局部变量,那么形参和局部变量就不占用栈了,但是如果本函数func1( )中又需要调别另一个函数func2( )的话,func2( )函数传参等也是需要使用Rn的,这样本函数func1()在调用func2( )之前,func1()就必须得把刚才存在Rn中的形参和局部变量压栈,以便腾出Rn供func2( )传参和导出返回值用)。

  • 17
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值