⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os_cpu_a.asm

📁 c8051f040单片机上的UCOS 移植代码
💻 ASM
字号:
;/*
;*********************************************************************************************************
;*                                               uC/OS-II
;*                                               实时内核
;*
;*                        (c) Copyright 1992-1998, Jean J. Labrosse, Plantation, FL
;*                                               版权所有
;*
;*                                            MCU-51 专用代码
;*                                           KEIL C51大模式编译
;*
;* 文件名 : OS_CPU_A.ASM
;* 作者   : Jean J. Labrosse
;* 改编   : 杨屹 gdtyy@ri.gdt.com.cn 巨龙公司系统集成开发部 2002.09.27
;*********************************************************************************************************
;*/

;伪指令详细用法请查A51.PDF文件
;程序结构详见《uC/OS-II》193-198页

;不用此语句!!! $CASE    ;标号和变量名区分大小写

$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
SFRPAGE DATA 084H
        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

?PR?_?serial?OS_CPU_A          SEGMENT CODE
        
;声明引用全局变量和外部子程序
        EXTRN DATA  (?C_XBP)     ;仿真堆栈指针用于重入局部变量保存
		EXTRN XDATA  (inTxBuf)   
        EXTRN IDATA (OSTCBCur)
        EXTRN IDATA (OSTCBHighRdy)
        EXTRN IDATA (OSRunning)
        EXTRN IDATA (OSPrioCur)
        EXTRN IDATA (OSPrioHighRdy)
    
        EXTRN CODE  (_?OSTaskSwHook)
        EXTRN CODE  (_?serial)
        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
		MOV  A,SFRPAGE	  ;	将SFRPAGE入栈
		PUSH  ACC
        ;PUSH SP    ;不必保存SP,任务切换时由相应程序调整
        ENDM
    
POPALL    MACRO
        ;POP  ACC   ;不必保存SP,任务切换时由相应程序调整
		POP ACC
		MOV SFRPAGE,A
        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
    
;子程序
;-------------------------------------------------------------------------
 /*OSStartHighRdy()假设OSTCBHighRdy指向的是优先级最高的任务的任务控制块。
 OSStart()从任务就绪表中找出那个用户建立的优先级最高任务的任务控制块[L3.25(1)]。
 然后,OSStart()调用高优先级就绪任务启动函数OSStartHighRdy()[L3,25(2)],
 (见汇编语言文件OS_CPU_A.ASM),这个文件与选择的微处理器有关。
 实质上,函数OSStartHighRdy()是将任务栈中保存的值弹回到CPU寄存器中,
 然后执行一条中断返回指令,中断返回指令强制执行该任务代码。见9.04.01节,
 高优先级就绪任务启动函数OSStartHighRdy()。
 那一节详细介绍对于80x86微处理器是怎么做的。
 注意,OSStartHighRdy()将永远不返回到OSStart()。*/
        RSEG ?PR?OSStartHighRdy?OS_CPU_A
OSStartHighRdy:
        USING 0    ;上电后51自动关中断,此处不必用CLR EA指令,因为到此处还未开中断,本程序退出后,开中断。

//OSStartHighRdy()必须调用OSTaskSwHook()因为用户正在进行任务切换的部分工作--用户在恢复最高优先级任务的寄存器。而OSTaskSwHook()可以通过检查OSRunning来知道是OSStartHighRdy()在调用它(OSRunning为FALSE)还是正常的任务切换在调用它(OSRunning为TRUE).
        LCALL _?OSTaskSwHook
//1.恢复任务堆栈(恢复要想运行最高优先级任务,用户所要做的是将所有处理器寄存器按顺序从任务堆栈中恢复出来,)
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
//    Restore all processor registers from the new task's stack;             
                         
   
        POPALL
        SETB EA    ;开中断
//    Execute a return from interrupt instruction;  
        RETI
;-------------------------------------------------------------------------
/*
在?C/OS-Ⅱ中,处于就绪状态的任务的堆栈结构看起来就像刚发生过中断并将所有的寄存器保存到
堆栈中的情形一样。换句话说,?C/OS-Ⅱ要运行处于就绪状态的任务必须要做的事就是将所有处理
器寄存器从任务堆栈中恢复出来,并且执行中断的返回。为了切换任务可以通过执行OS_TASK_SW()
来产生中断。
*/

        RSEG ?PR?OSCtxSw?OS_CPU_A
OSCtxSw:    
        PUSHALL	  ;//1。低优先级任务切换到最高优先级任务时,将低优先级堆栈所有的寄存器保存到堆栈中
    
OSIntCtxSw_in:	  //2. 将当前任务的堆栈指针保存到当前任务的OS_TCB中:
    
        ;获得堆栈长度和起址
        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        
    
        ;3.调用用户程序
        LCALL _?OSTaskSwHook
        
        ;4.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
                
        ;5.OSPrioCur = OSPrioHighRdy  使用这两个变量主要目的是为了使指针比较变为字节比较,以便节省时间。
        MOV  R0,#OSPrioCur
	MOV  R1,#OSPrioHighRdy
	MOV  A,@R1
        MOV  @R0,A
 //6.程序跳转到OSCtxSw_in, Stack pointer = OSTCBHighRdy->OSTCBStkPtr;
//将所有处理器寄存器从新任务的堆栈中恢复出来;       
        LJMP OSCtxSw_in
;-------------------------------------------------------------------------
        RSEG ?PR?OSIntCtxSw?OS_CPU_A
/*OSIntExit()通过调用OSIntCtxSw()来从ISR中执行切换功能 */  
    
OSIntCtxSw:
//1.调整sp指针
        ;调整SP指针去掉在调用OSIntExit(),OSIntCtxSw()过程中压入堆栈的多余内容
        ;SP=SP-4

        MOV  A,SP
        CLR  C
        SUBB A,#4
        MOV  SP,A

        LJMP OSIntCtxSw_in	  //其它执行同OSCtxSw

/*OSTickISR()调用应该发生在  OSStart()之后*/
;-------------------------------------------------------------------------
        CSEG AT 000BH    ;OSTickISR
        LJMP OSTickISR   ;使用定时器0
        RSEG ?PR?OSTickISR?OS_CPU_A

OSTickISR:        ;//时钟节拍中断服务子程序||μC/OS需要用户提供周期性信号源,用于实现时间延时和确认超时。
        
        USING 0        
        PUSHALL
		MOV SFRPAGE,#0;TIMER01_PAGE
        CLR  TR0
        MOV  TH0,#0x60    ;定义Tick=50次/1秒(即0.02秒/次)
        MOV  TL0,#0x7F    ;OS_CPU_C.C  和  OS_TICKS_PER_SEC
        SETB TR0
        
        LCALL _?OSIntEnter	    ;//调用OSIntEnter()函数||汇编中如何调用C语言函数
        LCALL _?OSTimeTick		 ;//时钟节拍函数OSTimeTick()
        LCALL _?OSIntExit
        POPALL        
        RETI
;-------------------------------------------------------------------------
        CSEG AT 00A3H    ;串口1中断
        LJMP SerialISR   ;工作于系统态,无任务切换。
        RSEG ?PR?_?serial?OS_CPU_A
        
SerialISR:
        
        USING 0        
        PUSHALL
		MOV SFRPAGE,#0;UART1_PAGE
        CLR  EA
        LCALL _?serial        
        SETB EA
        POPALL        
        RETI
;-------------------------------------------------------------------------
        END
;-------------------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -