uC/OS-II 51单片机移植,汇编部分链接错误

vvsanny   2009-12-22 10:26 楼主
本人想移植一个uC/OS-II到51(C8051F040)单片机上,C语言部分编译链接成功,与MCU相关的汇编部分虽然编译成功无法链接(OS_CPU_A.ASM 文件)。

1. OS_CPU_A.ASM文件如下:

  1. $NOMOD51
  2. EA        BIT        0A8H.7
  3. SP        DATA        081H
  4. B        DATA        0F0H
  5. ACC        DATA        0E0H
  6. DPH        DATA        083H
  7. DPL        DATA        082H
  8. PSW        DATA        0D0H
  9. TR0        BIT        088H.4
  10. TH0        DATA        08CH
  11. TL0        DATA        08AH

  12. NAME OS_CPU_A    ;模块名      
  13. ;定义重定位段
  14. ?PR?OSStartHighRdy?OS_CPU_A    SEGMENT CODE
  15. ?PR?OSCtxSw?OS_CPU_A           SEGMENT CODE
  16. ?PR?OSIntCtxSw?OS_CPU_A        SEGMENT CODE
  17. ?PR?OSTickISR?OS_CPU_A         SEGMENT CODE

  18.         
  19. ;声明引用全局变量和外部子程序
  20.         EXTRN DATA  (?C_XBP)     ;仿真堆栈指针用于重入局部变量保存

  21.         EXTRN XDATA (OSTCBCur)
  22.         EXTRN XDATA (OSTCBHighRdy)
  23.         EXTRN XDATA (OSRunning)
  24.         EXTRN XDATA (OSPrioCur)
  25.         EXTRN XDATA (OSPrioHighRdy)
  26.    
  27.         EXTRN CODE  (OSTaskSwHook)
  28.         EXTRN CODE  (OSIntEnter)
  29.         EXTRN CODE  (OSIntExit)
  30.         EXTRN CODE  (OSTimeTick)        
  31.             
  32. ;对外声明4个不可重入函数
  33.         PUBLIC OSStartHighRdy
  34.         PUBLIC OSCtxSw
  35.         PUBLIC OSIntCtxSw
  36.         PUBLIC OSTickISR
  37.         
  38.         ;PUBLIC SerialISR        
  39.    
  40. ;分配堆栈空间。只关心大小,堆栈起点由keil决定,通过标号可以获得keil分配的SP起点。
  41. ?STACK SEGMENT IDATA
  42.         RSEG ?STACK
  43. OSStack:
  44.         DS 40H
  45. OSStkStart IDATA OSStack-1

  46. ;定义压栈出栈宏
  47. PUSHALL    MACRO
  48.         PUSH PSW
  49.         PUSH ACC
  50.         PUSH B
  51.         PUSH DPL
  52.         PUSH DPH
  53.         MOV  A,R0   ;R0-R7入栈
  54.         PUSH ACC
  55.         MOV  A,R1
  56.         PUSH ACC
  57.         MOV  A,R2
  58.         PUSH ACC
  59.         MOV  A,R3
  60.         PUSH ACC
  61.         MOV  A,R4
  62.         PUSH ACC
  63.         MOV  A,R5
  64.         PUSH ACC
  65.         MOV  A,R6
  66.         PUSH ACC
  67.         MOV  A,R7
  68.         PUSH ACC
  69.         ;PUSH SP    ;不必保存SP,任务切换时由相应程序调整
  70.         ENDM
  71.    
  72. POPALL    MACRO
  73.         ;POP  ACC   ;不必保存SP,任务切换时由相应程序调整
  74.         POP  ACC    ;R0-R7出栈
  75.         MOV  R7,A
  76.         POP  ACC
  77.         MOV  R6,A
  78.         POP  ACC
  79.         MOV  R5,A
  80.         POP  ACC
  81.         MOV  R4,A
  82.         POP  ACC
  83.         MOV  R3,A
  84.         POP  ACC
  85.         MOV  R2,A
  86.         POP  ACC
  87.         MOV  R1,A
  88.         POP  ACC
  89.         MOV  R0,A
  90.         POP  DPH
  91.         POP  DPL
  92.         POP  B
  93.         POP  ACC
  94.         POP  PSW
  95.         ENDM
  96.    
  97. ;子程序
  98. ;-------------------------------------------------------------------------
  99.         RSEG ?PR?OSStartHighRdy?OS_CPU_A
  100. OSStartHighRdy:
  101.         USING 0    ;上电后51自动关中断,此处不必用CLR EA指令,因为到此处还未开中断,本程序退出后,开中断。
  102.         LCALL OSTaskSwHook

  103. OSCtxSw_in:
  104.    
  105.         ;OSTCBCur ===> DPTR  获得当前TCB指针,详见C51.PDF第178页
  106.         MOV  R0,#LOW (OSTCBCur) ;获得OSTCBCur指针低地址,指针占3字节。+0类型+1高8位数据+2低8位数据
  107.         INC  R0
  108.         MOV  DPH,@R0    ;全局变量OSTCBCur在IDATA中
  109.         INC  R0
  110.         MOV  DPL,@R0
  111.    
  112.         ;OSTCBCur->OSTCBStkPtr ===> DPTR  获得用户堆栈指针
  113.         INC  DPTR        ;指针占3字节。+0类型+1高8位数据+2低8位数据
  114.         MOVX A,@DPTR     ;.OSTCBStkPtr是void指针
  115.         MOV  R0,A
  116.         INC  DPTR
  117.         MOVX A,@DPTR
  118.         MOV  R1,A
  119.         MOV  DPH,R0
  120.         MOV  DPL,R1
  121.    
  122.         ;*UserStkPtr ===> R5  用户堆栈起始地址内容(即用户堆栈长度放在此处)  详见文档说明  指针用法详见C51.PDF第178页   
  123.         MOVX A,@DPTR     ;用户堆栈中是unsigned char类型数据
  124.         MOV  R5,A        ;R5=用户堆栈长度
  125.    
  126.         ;恢复现场堆栈内容
  127.         MOV  R0,#OSStkStart
  128.         
  129. restore_stack:
  130.    
  131.         INC  DPTR
  132.         INC  R0
  133.         MOVX A,@DPTR
  134.         MOV  @R0,A
  135.         DJNZ R5,restore_stack
  136.    
  137.         ;恢复堆栈指针SP
  138.         MOV  SP,R0
  139.    
  140.         ;恢复仿真堆栈指针?C_XBP        
  141.         INC  DPTR
  142.         MOVX A,@DPTR
  143.         MOV  ?C_XBP,A    ;?C_XBP 仿真堆栈指针高8位
  144.         INC  DPTR
  145.         MOVX A,@DPTR
  146.         MOV  ?C_XBP+1,A  ;?C_XBP 仿真堆栈指针低8位
  147.    
  148.         ;OSRunning=TRUE
  149.         MOV  R0,#LOW (OSRunning)
  150.         MOV  @R0,#01
  151.    
  152.         POPALL
  153.         SETB EA    ;开中断
  154.         RETI
  155. ;-------------------------------------------------------------------------
  156.         RSEG ?PR?OSCtxSw?OS_CPU_A
  157. OSCtxSw:   
  158.         PUSHALL
  159. OSIntCtxSw_in:
  160.    
  161.         ;获得堆栈长度和起址
  162.         MOV  A,SP
  163.         CLR  C
  164.         SUBB A,#OSStkStart
  165.         MOV  R5,A     ;获得堆栈长度        
  166.    
  167.         ;OSTCBCur ===> DPTR  获得当前TCB指针,详见C51.PDF第178页
  168.         MOV  R0,#LOW (OSTCBCur) ;获得OSTCBCur指针低地址,指针占3字节。+0类型+1高8位数据+2低8位数据
  169.         INC  R0
  170.         MOV  DPH,@R0    ;全局变量OSTCBCur在IDATA中
  171.         INC  R0
  172.         MOV  DPL,@R0
  173.    
  174.         ;OSTCBCur->OSTCBStkPtr ===> DPTR  获得用户堆栈指针
  175.         INC  DPTR        ;指针占3字节。+0类型+1高8位数据+2低8位数据
  176.         MOVX A,@DPTR     ;.OSTCBStkPtr是void指针
  177.         MOV  R0,A
  178.         INC  DPTR
  179.         MOVX A,@DPTR
  180.         MOV  R1,A
  181.         MOV  DPH,R0
  182.         MOV  DPL,R1
  183.         
  184.         ;保存堆栈长度
  185.         MOV  A,R5
  186.         MOVX @DPTR,A
  187.    
  188.         MOV  R0,#OSStkStart  ;获得堆栈起址
  189. save_stack:
  190.    
  191.         INC  DPTR
  192.         INC  R0
  193.         MOV  A,@R0
  194.         MOVX @DPTR,A
  195.         DJNZ R5,save_stack
  196.         
  197.         ;保存仿真堆栈指针?C_XBP
  198.         INC  DPTR
  199.         MOV  A,?C_XBP    ;?C_XBP 仿真堆栈指针高8位
  200.         MOVX @DPTR,A
  201.         INC  DPTR
  202.         MOV  A,?C_XBP+1  ;?C_XBP 仿真堆栈指针低8位
  203.         MOVX @DPTR,A        
  204.    
  205.         ;调用用户程序
  206.         LCALL OSTaskSwHook
  207.         
  208.         ;OSTCBCur = OSTCBHighRdy,注意是三个字节
  209.         MOV  R0,#OSTCBCur
  210.                 MOV  R1,#OSTCBHighRdy
  211.                 MOV  A,@R1
  212.         MOV  @R0,A
  213.         INC  R0
  214.                 INC  R1
  215.                 MOV  A,@R1
  216.         MOV  @R0,A
  217.         INC  R0
  218.                 INC  R1
  219.                 MOV  A,@R1
  220.         MOV  @R0,A
  221.                
  222.         ;OSPrioCur = OSPrioHighRdy  使用这两个变量主要目的是为了使指针比较变为字节比较,以便节省时间。
  223.         MOV  R0,#OSPrioCur
  224.                 MOV  R1,#OSPrioHighRdy
  225.                 MOV  A,@R1
  226.         MOV  @R0,A
  227.         
  228.         LJMP OSCtxSw_in
  229. ;-------------------------------------------------------------------------
  230.         RSEG ?PR?OSIntCtxSw?OS_CPU_A
  231.         
  232. OSIntCtxSw:

  233.         ;调整SP指针去掉在调用OSIntExit(),OSIntCtxSw()过程中压入堆栈的多余内容
  234.         ;SP=SP-4

  235.         MOV  A,SP
  236.         CLR  C
  237.         SUBB A,#4
  238.         MOV  SP,A
  239.         
  240.         LJMP OSIntCtxSw_in
  241. ;-------------------------------------------------------------------------

  242.         CSEG AT 000BH    ;OSTickISR, 声明绝对段地址,即定时器0中断入口地址
  243.         LJMP OSTickISR   ;使用定时器0

  244.         RSEG ?PR?OSTickISR?OS_CPU_A

  245. OSTickISR:        
  246.         
  247.         USING 0        
  248.         PUSHALL
  249.         
  250.         CLR  TR0
  251.         MOV  TH0,#70H    ;定义Tick=50次/秒(即0.02秒/次)
  252.         MOV  TL0,#00H    ;OS_CPU_C.C  和  OS_TICKS_PER_SEC
  253.         SETB TR0
  254.         
  255.         LCALL OSIntEnter
  256.         LCALL OSTimeTick
  257.         LCALL OSIntExit
  258.         POPALL        
  259.         RETI
  260. ;-------------------------------------------------------------------------
  261.         END



2. 链接错误提示如下:
*** ERROR L121: IMPROPER FIXUP
    MODULE:  .\OS_CPU_A.obj (OS_CPU_A)
    SEGMENT: ?PR?OSCTXSW?OS_CPU_A
    OFFSET:  0050H
*** ERROR L121: IMPROPER FIXUP
    MODULE:  .\OS_CPU_A.obj (OS_CPU_A)
    SEGMENT: ?PR?OSCTXSW?OS_CPU_A
    OFFSET:  0052H
*** ERROR L121: IMPROPER FIXUP
    MODULE:  .\OS_CPU_A.obj (OS_CPU_A)
    SEGMENT: ?PR?OSCTXSW?OS_CPU_A
    OFFSET:  005EH
*** ERROR L121: IMPROPER FIXUP
    MODULE:  .\OS_CPU_A.obj (OS_CPU_A)
    SEGMENT: ?PR?OSCTXSW?OS_CPU_A
    OFFSET:  0060H

去Google了半天也没找到答案,望高手指点!

回复评论 (15)

好像设置的程序空间太小了

修改一下code rom size的设置
点赞  2009-12-22 10:34
说明:OS_CPU_A.ASM 是从网上下载的(自己不太会写汇编-_-), 有少许修改。
点赞  2009-12-22 10:34
看不明白...
点赞  2009-12-22 10:38
引用: 引用 1 楼 arnold9009 的回复:
好像设置的程序空间太小了

修改一下code rom size的设置

呵呵,谢谢arnold9009这么快的回复:
我在"Option for target.." -> "Target" ->"Code rom size:" 已经设置为:" Large: 64K ROM "
编译链接提示占用空间如下:
Program Size: data=75.0 xdata=2964 code=21625
code空间不大于22KB(<64K)左右,我想应该不会是code 空间太小。
点赞  2009-12-22 10:40
引用: 引用 3 楼 lihongfu 的回复:
看不明白...

呵呵,版面有限,只好贴出这么多的代码了。
点赞  2009-12-22 10:43
那可能是OSCTXSW函数的位置超过了跳转指令的寻址范围
点赞  2009-12-22 13:10
Error L121
Improper Fixup
Summary   *** Error L121
    Improper Fixup
    Module: filename (module-name)
    Segment: segment-name
    Offset: address


Description   After evaluation of absolute fix-ups, an address is not accessible. The improper address along with the specific module name, partial segment, and segment address are displayed. The fix-up command is not processed. This error occurs when an instruction tries do make a memory access that is outside the scope of this instruction (for example MOVX @Ri outside of the PDATA page, or ACALL outside of the 2KB code memory block).  
点赞  2009-12-22 14:04
KEIL的错误信息帮助....它说是你要访问的目标走出了指令所能达到的范围
点赞  2009-12-22 14:06
引用: 引用 6 楼 arnold9009 的回复:
那可能是OSCTXSW函数的位置超过了跳转指令的寻址范围


谢谢 arnold9009 的回复:

1.所有的跳转指令都是LJMP和LCALL,所以应该不会是OSCtxSw函数超出范围。
2.错误提示:
    SEGMENT: ?PR?OSCTXSW?OS_CPU_A
    OFFSET:  0050H
的意思应该是在OSCTXSW段内的0050H偏移地址处存在无效的地址访问。
点赞  2009-12-22 14:50
引用: 引用 7 楼 great_bug 的回复:
Error L121
Improper Fixup
Summary?  *** Error L121
? ? Improper Fixup
? ? Module: filename (module-name)
? ? Segment: segment-name
? ? Offset: address


Description?  After evaluation of absolute fix-ups, an address is not accessible. The improper address along with the specific module name, partial segment, and segment address are displayed. The fix-up command is not processed. This error occurs when an instruction tries do make a memory access that is outside the scope of this instruction (for example MOVX @Ri outside of the PDATA page, or ACALL outside of the 2KB code memory block).


呵呵,这个Great_Bug回复我第三次提问了,在此感谢下!!
问题已
经解决,谢谢大家:
1. 查看OS_CPU_A.LST文件,找到有出错提示的段和偏移地址:  

  1. 0000                 206     OSCtxSw:   
  2. 004F 7800     F      280          MOV  R0,#OSTCBCur
  3. 0051 7900     F      281          MOV  R1,#OSTCBHighRdy
  4. 005D 7800     F      295          MOV  R0,#OSPrioCur
  5. 005F 7900     F      296          MOV  R1,#OSPrioHighRdy

发现问题集中在OSTCBCur, OSTCBHighRdy, OSPrioCur, OSPrioHighRdy 四个变量上,查找他们的声明,可以发现:
  1.   
  2. EXTRN XDATA (OSTCBCur)
  3. EXTRN XDATA (OSTCBHighRdy)
  4. EXTRN XDATA (OSRunning)
  5. EXTRN XDATA (OSPrioCur)
  6. EXTRN XDATA (OSPrioHighRdy)

原来问题是在变量上,(变量都在XDATA区,却用没用MOVX指令)我还一直以为问题出在OSCTXSW函数上,无语!!

2. 修改如下:

  1.         ;OSTCBCur = OSTCBHighRdy,注意是三个字节
  2.                 ; 第一个字节
  3.                 MOV   DPTR, #OSTCBHighRdy
  4.                 MOVX  A,@DPTR          
  5.                 MOV   DPTR, #OSTCBCur
  6.                 MOVX  @DPTR,A
  7.                 ; 第二个字节
  8.                 MOV   DPTR, #OSTCBHighRdy  
  9.                 INC   DPTR
  10.                 MOVX  A,@DPTR         
  11.                 MOV   DPTR, #OSTCBCur
  12.                 INC   DPTR
  13.                 MOVX  @DPTR,A
  14.                 ; 第三个字节
  15.                 MOV   DPTR, #OSTCBHighRdy
  16.                 INC   DPTR
  17.                 INC   DPTR
  18.                 MOVX  A,@DPTR       
  19.                 MOV   DPTR, #OSTCBCur
  20.                 INC   DPTR
  21.                 INC   DPTR
  22.                 MOVX  @DPTR,A

  23.         ;OSPrioCur = OSPrioHighRdy  使用这两个变量主要目的是为了使指针比较变为字节比较,以便节 省时间。
  24.                 MOV  DPTR,#OSPrioHighRdy
  25.                 MOVX  A,@DPTR
  26.                 MOV  DPTR, #OSPrioCur
  27.                 MOVX  @DPTR,A


3. 编译链接,再也没有出现错误,GOD, 谢天谢地!
点赞  2009-12-22 15:12
引用: 引用 8 楼 great_bug 的回复:
KEIL的错误信息帮助....它说是你要访问的目标走出了指令所能达到的范围


呵呵,这是Great_Bug回复我第三次提问了,在此特别感谢下!!
点赞  2009-12-22 15:23
牛B。我也想移个玩玩
点赞  2009-12-22 16:38
  超级关注,疯狂Mark。
点赞  2009-12-24 12:55
MArk
点赞  2009-12-24 13:13
NB  顶一个
点赞  2012-5-21 16:39
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复