本人想移植一个uC/OS-II到51(C8051F040)单片机上,C语言部分编译链接成功,与MCU相关的汇编部分虽然
编译成功却
无法链接(OS_CPU_A.ASM 文件)。
1. OS_CPU_A.ASM文件如下:
- $NOMOD51
- EA BIT 0A8H.7
- SP DATA 081H
- B DATA 0F0H
- ACC DATA 0E0H
- DPH DATA 083H
- DPL DATA 082H
- PSW DATA 0D0H
- TR0 BIT 088H.4
- TH0 DATA 08CH
- TL0 DATA 08AH
- NAME OS_CPU_A ;模块名
- ;定义重定位段
- ?PR?OSStartHighRdy?OS_CPU_A SEGMENT CODE
- ?PR?OSCtxSw?OS_CPU_A SEGMENT CODE
- ?PR?OSIntCtxSw?OS_CPU_A SEGMENT CODE
- ?PR?OSTickISR?OS_CPU_A SEGMENT CODE
-
- ;声明引用全局变量和外部子程序
- EXTRN DATA (?C_XBP) ;仿真堆栈指针用于重入局部变量保存
- EXTRN XDATA (OSTCBCur)
- EXTRN XDATA (OSTCBHighRdy)
- EXTRN XDATA (OSRunning)
- EXTRN XDATA (OSPrioCur)
- EXTRN XDATA (OSPrioHighRdy)
-
- EXTRN CODE (OSTaskSwHook)
- EXTRN CODE (OSIntEnter)
- EXTRN CODE (OSIntExit)
- EXTRN CODE (OSTimeTick)
-
- ;对外声明4个不可重入函数
- PUBLIC OSStartHighRdy
- PUBLIC OSCtxSw
- PUBLIC OSIntCtxSw
- PUBLIC OSTickISR
-
- ;PUBLIC SerialISR
-
- ;分配堆栈空间。只关心大小,堆栈起点由keil决定,通过标号可以获得keil分配的SP起点。
- ?STACK SEGMENT IDATA
- RSEG ?STACK
- OSStack:
- DS 40H
- OSStkStart IDATA OSStack-1
- ;定义压栈出栈宏
- PUSHALL MACRO
- PUSH PSW
- PUSH ACC
- PUSH B
- PUSH DPL
- PUSH DPH
- MOV A,R0 ;R0-R7入栈
- PUSH ACC
- MOV A,R1
- PUSH ACC
- MOV A,R2
- PUSH ACC
- MOV A,R3
- PUSH ACC
- MOV A,R4
- PUSH ACC
- MOV A,R5
- PUSH ACC
- MOV A,R6
- PUSH ACC
- MOV A,R7
- PUSH ACC
- ;PUSH SP ;不必保存SP,任务切换时由相应程序调整
- ENDM
-
- POPALL MACRO
- ;POP ACC ;不必保存SP,任务切换时由相应程序调整
- POP ACC ;R0-R7出栈
- MOV R7,A
- POP ACC
- MOV R6,A
- POP ACC
- MOV R5,A
- POP ACC
- MOV R4,A
- POP ACC
- MOV R3,A
- POP ACC
- MOV R2,A
- POP ACC
- MOV R1,A
- POP ACC
- MOV R0,A
- POP DPH
- POP DPL
- POP B
- POP ACC
- POP PSW
- ENDM
-
- ;子程序
- ;-------------------------------------------------------------------------
- RSEG ?PR?OSStartHighRdy?OS_CPU_A
- OSStartHighRdy:
- USING 0 ;上电后51自动关中断,此处不必用CLR EA指令,因为到此处还未开中断,本程序退出后,开中断。
- LCALL OSTaskSwHook
- OSCtxSw_in:
-
- ;OSTCBCur ===> DPTR 获得当前TCB指针,详见C51.PDF第178页
- MOV R0,#LOW (OSTCBCur) ;获得OSTCBCur指针低地址,指针占3字节。+0类型+1高8位数据+2低8位数据
- INC R0
- MOV DPH,@R0 ;全局变量OSTCBCur在IDATA中
- INC R0
- MOV DPL,@R0
-
- ;OSTCBCur->OSTCBStkPtr ===> DPTR 获得用户堆栈指针
- INC DPTR ;指针占3字节。+0类型+1高8位数据+2低8位数据
- MOVX A,@DPTR ;.OSTCBStkPtr是void指针
- MOV R0,A
- INC DPTR
- MOVX A,@DPTR
- MOV R1,A
- MOV DPH,R0
- MOV DPL,R1
-
- ;*UserStkPtr ===> R5 用户堆栈起始地址内容(即用户堆栈长度放在此处) 详见文档说明 指针用法详见C51.PDF第178页
- MOVX A,@DPTR ;用户堆栈中是unsigned char类型数据
- MOV R5,A ;R5=用户堆栈长度
-
- ;恢复现场堆栈内容
- MOV R0,#OSStkStart
-
- restore_stack:
-
- INC DPTR
- INC R0
- MOVX A,@DPTR
- MOV @R0,A
- DJNZ R5,restore_stack
-
- ;恢复堆栈指针SP
- MOV SP,R0
-
- ;恢复仿真堆栈指针?C_XBP
- INC DPTR
- MOVX A,@DPTR
- MOV ?C_XBP,A ;?C_XBP 仿真堆栈指针高8位
- INC DPTR
- MOVX A,@DPTR
- MOV ?C_XBP+1,A ;?C_XBP 仿真堆栈指针低8位
-
- ;OSRunning=TRUE
- MOV R0,#LOW (OSRunning)
- MOV @R0,#01
-
- POPALL
- SETB EA ;开中断
- RETI
- ;-------------------------------------------------------------------------
- RSEG ?PR?OSCtxSw?OS_CPU_A
- OSCtxSw:
- PUSHALL
- OSIntCtxSw_in:
-
- ;获得堆栈长度和起址
- MOV A,SP
- CLR C
- SUBB A,#OSStkStart
- MOV R5,A ;获得堆栈长度
-
- ;OSTCBCur ===> DPTR 获得当前TCB指针,详见C51.PDF第178页
- MOV R0,#LOW (OSTCBCur) ;获得OSTCBCur指针低地址,指针占3字节。+0类型+1高8位数据+2低8位数据
- INC R0
- MOV DPH,@R0 ;全局变量OSTCBCur在IDATA中
- INC R0
- MOV DPL,@R0
-
- ;OSTCBCur->OSTCBStkPtr ===> DPTR 获得用户堆栈指针
- INC DPTR ;指针占3字节。+0类型+1高8位数据+2低8位数据
- MOVX A,@DPTR ;.OSTCBStkPtr是void指针
- MOV R0,A
- INC DPTR
- MOVX A,@DPTR
- MOV R1,A
- MOV DPH,R0
- MOV DPL,R1
-
- ;保存堆栈长度
- MOV A,R5
- MOVX @DPTR,A
-
- MOV R0,#OSStkStart ;获得堆栈起址
- save_stack:
-
- INC DPTR
- INC R0
- MOV A,@R0
- MOVX @DPTR,A
- DJNZ R5,save_stack
-
- ;保存仿真堆栈指针?C_XBP
- INC DPTR
- MOV A,?C_XBP ;?C_XBP 仿真堆栈指针高8位
- MOVX @DPTR,A
- INC DPTR
- MOV A,?C_XBP+1 ;?C_XBP 仿真堆栈指针低8位
- MOVX @DPTR,A
-
- ;调用用户程序
- LCALL OSTaskSwHook
-
- ;OSTCBCur = OSTCBHighRdy,注意是三个字节
- MOV R0,#OSTCBCur
- MOV R1,#OSTCBHighRdy
- MOV A,@R1
- MOV @R0,A
- INC R0
- INC R1
- MOV A,@R1
- MOV @R0,A
- INC R0
- INC R1
- MOV A,@R1
- MOV @R0,A
-
- ;OSPrioCur = OSPrioHighRdy 使用这两个变量主要目的是为了使指针比较变为字节比较,以便节省时间。
- MOV R0,#OSPrioCur
- MOV R1,#OSPrioHighRdy
- MOV A,@R1
- MOV @R0,A
-
- LJMP OSCtxSw_in
- ;-------------------------------------------------------------------------
- RSEG ?PR?OSIntCtxSw?OS_CPU_A
-
- OSIntCtxSw:
- ;调整SP指针去掉在调用OSIntExit(),OSIntCtxSw()过程中压入堆栈的多余内容
- ;SP=SP-4
- MOV A,SP
- CLR C
- SUBB A,#4
- MOV SP,A
-
- LJMP OSIntCtxSw_in
- ;-------------------------------------------------------------------------
- CSEG AT 000BH ;OSTickISR, 声明绝对段地址,即定时器0中断入口地址
- LJMP OSTickISR ;使用定时器0
- RSEG ?PR?OSTickISR?OS_CPU_A
- OSTickISR:
-
- USING 0
- PUSHALL
-
- CLR TR0
- MOV TH0,#70H ;定义Tick=50次/秒(即0.02秒/次)
- MOV TL0,#00H ;OS_CPU_C.C 和 OS_TICKS_PER_SEC
- SETB TR0
-
- LCALL OSIntEnter
- LCALL OSTimeTick
- LCALL OSIntExit
- POPALL
- RETI
- ;-------------------------------------------------------------------------
- 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了半天也没找到答案,望高手指点!