为什么你的仿真机只占用2个字节的堆栈,而keil的 Mon51要用6个字节的堆栈?


答: 我的仿真机只需要使用用户的两个字节的堆栈,用户可以使用最多254字节的ram(52类单片机),而mon51仿真机需要使用6个字节的堆栈,用户最多可以使用250字节的ram,etool的51emb-32k也是占用6个字节的堆栈.

keil mon51的堆栈占用分析:

仿真机是使用软件断点(跟专门的仿真机的硬件断点不同),是需要在用户程序的断点处写入一条 LCALL LF200H 指令(LF200H是监控程序的入口),(keil 的说明是有错误的,keil的说明是在断点处写入一条ACALL指令,我们知道ACALL指令的跳转范围是2k,而不是64K,如果是写入ACALL指令,那么用户程序最大不能超过2k).keil mon51的代码空间使用ram来存储的,用户代码可以被改写,我的仿真机是用SST89C58,SST89C58可以在运行中修改代码空间,改写用户代码),可以将位于断点处的用户代码改为LCALL监控程序代码.用户程序运行到断点处时,将执行一条LCALL指令跳到监控系统.举个例子:

地址 代码 指令 断点0005 代码 指令 堆栈占用
0000: 758107 MOV SP,#07H        
0003: 785F MOV R0,#05FH        
0005: 7401 MOV A,#01H 0005: 12F1 LCALL 0F1XXH 2个字节
0007: F6 MOV @R0,A 0007: F6    
0008: D8FD DJNZ R0,C:0007H        
000A: 78FF MOV R0,#0FFH        

上面是一个例子,要在0005处设置断点,0005处原来的代码为7401,是一条MOV指令,

监控系统将会修改0005处的代码,将0005-0006处的代码改为12F1 ,是一条LCALL指令,这里将 LCALL 0F1F6H .而监控程序的入口是0F100H-0F200H,0F1F6H落入监控程序入口.(根据用户install的参数不同,监控程序的入口不一样),0F100-0F200是我的仿真机的监控程序入口.

KEIL 的监控程序:

  ORG 0F100H       堆栈占用
LF100H: NOP        
  NOP        
  ....(256个NOP)        
  ORG 0F200H        
LF200H: PUSH DPH       1个字节
  PUSH DPL       1个字节
  MOV DPTR,#7F08H        
  LCALL WRITEBYTE       2个字节
  ......        
           
           
WRITEBYTE: MOVX @DPTR,A        
  RET        
           
           

一条LCALL 指令要入栈2个字节.一条PUSH指令要入栈1个字节,Keil的MON51使用了两条LCALL指令:LCALL 0F1XXH ; LCALL WRITEBYTE 需要占用4个字节的堆栈,使用了两个PUSH指令,占用2个字节的堆栈,共要占用6个字节的用户堆栈.如果用户可用堆栈少于6个字节,系统将会出错.

 

我的监控程序:

  ORG 0F100H 含义     堆栈占用
LF100H: NOP        
  NOP        
  ....(256个NOP)        
  ORG 0F200H        
LF200H: ORL SFCF,#40H IAP_enable      
  MOV SFAH,#7FH        
  MOV SFAL,#21H        
  MOV SFDT,PSW 保存PSW      
  MOV SFCM,#0EH 写入一个字节      
WAIT: MOV PSW,SFST        
  JB PSW.2, WAIT 等到写入完成      
  ......        
  ......        
  .....        
  .....        

我的监控程序的执行过程没有使用PUSH指令,也没有使用LCALL指令,只有断点处的LCALL 0F1XXH 占用2个字节的堆栈. SFCF,SFAH,SFAL 等是SST89C58的特殊寄存器,用于运行过程中修改代码.

除了对监控程序的入口(从用户程序返回监控程序)做了很大的改动之外,对监控程序的出口(从监控程序返回用户程序)作相应的改动.以实现2字节的堆栈占用.对运行中用中断停止的代码也做了类似的修改.

2字节的堆栈占用是我的独创.etool使用的代码跟keil提供的代码差不多,同样占用6个字节的堆栈.