【MCS-51】【A51】程序跑飞怪相

       程序跑飞怪相

申明:本程序绝对原创,请转载本博文注明出处:http://blog.csdn.net/fly928sky/article/details/7679288   

1.跑飞的程序

        昨天凌晨写了个程序,太晚就睡了。昨天早晨9点多钟的时候,调试程序居然发现程序跑飞了。

跑飞程序部分代码如下:

TLeft:	MOV		1000H,#006H ;循环次数
		MOV		A,1001H
		PUSH	ACC
LLoop:	SETB	P1.2
		POP		ACC
		MOV		P0,A
		CLR		P1.2
		RR		A
		PUSH	ACC
		ACALL	Delay
		DEC		1000H
		MOV		A,1000H
		JNZ		LLoop
		RET

         本段代码是某个程序中的一个子程序,子程序主体运行结束时,再运行子程序返回指令(RET)。这时奇怪的跳到了0xFC00位置的空操作。

2.问题分析

        子程序返回跳转的地址为“0xFC00”,即可以得出是出栈的问题。

        不过我刚开始遇到该问题的时候,不是这么认为的。问题归咎于堆栈溢出,于是昨天下午查找了好多资料并综合了网友的一些方法来进行仿真测试。其中一个网友要求我把ACALL和RET全部换成LJMP指令,这样处理后虽然能够顺利运行,但是达不到汇编模块化编程的目的。其后又查找了一些资料,都没有派上用场。

       昨天晚上没开电脑,好好的休息了一晚上。今天早晨打开程序,用软件仿真调试时,发现SP长度的变化。于是重新进入仿真,一步步调试,并把每次调用ACALL指令的SP长度值记录下来。直到子程序主体部分运行结束,然后运行子程序返回指令(RET),发现SP长度比在执行“ACALL TLeft”时的SP长度多了一个。后来仔细想想,其实是在子程序中对累加器A压栈了,但是子程序返回之前没有出栈。

3.解决方案

        解决方案就是简单的一句话,在子程序返回指令(RET)之前加一条出栈语句就OK。

修改后的代码如下:

TLeft:	MOV		1000H,#006H ;循环次数
		MOV		A,1001H
		PUSH	ACC
LLoop:	SETB	P1.2
		POP		ACC
		MOV		P0,A
		CLR		P1.2
		RR		A
		PUSH	ACC
		ACALL	Delay
		DEC		1000H
		MOV		A,1000H
		JNZ		LLoop
		POP		ACC
		RET

4.深度分析

       其实根据上面的SP长度的判断,是可以判断出程序的返回问题致使程序跑飞。

       但是考虑问题时,需要从多方面着手,综合分析程序的问题所在。

       为什么程序会跑飞到“0xFC00”,而不是其他的地方呢?

       “0xFC00”可以分解成FC和00,那么FC是怎么来的呢?不妨我们仔细看看刚才那段跑飞的程序。一步步仿真调试后发现,到子程序主体部分运行结束时,累加器A的值正好是0xFC。这两者之间就有着莫大的关系,因为程序中有对累加器A的压栈操作。因此,需要再子程序返回(RET)之前对累加器A出栈。

        对“0xFC00”的分解判断,也可以从“ACALL TLeft”调用TLeft子程序时对堆栈的处理进行分析。

ACALL指令详解:

(PC)←(PC)+ 2
(SP)←(SP)+ 1,(SP)←(PC7-0)
(SP)←(SP)+ 1,(SP)←(PC15-8)
(PC10-0)←addr11

RET指令详解:

(PC15-8)←(SP),(SP)←(SP)-1
(PC7-0)←(SP),(SP)←(SP)-1

       由上面两条指令详解,可以看出“ACALL TLeft”下一条指令的高位地址为00。假设“ACALL TLeft”这条指令的地址为0x0012,那么“ACALL TLeft”下一条指令的低位地址为14。即“ACALL TLeft”下一条指令的地址为0x0014。
       跑飞程序主体部分运行结束时,堆栈图如下图。

       修改后程序主体部分运行结束是,堆栈图如下图。

5.心得体会

        刚开始的时候,我根本就没有深入“0xFC00”这个问题。如果直接从这个问题着手的话,或许昨天上午就能把问题解决。可惜是我没有那样做。不过现在想来,知识经验的积累就是从错误的点点滴滴开始的。

        今天的积累,铸就明日辉煌。故留此一笔。


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值