Skip to content

Instantly share code, notes, and snippets.

@iskl
Created February 11, 2012 12:58
Show Gist options
  • Save iskl/1799297 to your computer and use it in GitHub Desktop.
Save iskl/1799297 to your computer and use it in GitHub Desktop.
ARM9上运行的微型操作系统(汇编)
;****************************************************************************************
; 文件名:RTOS_ASM.S
; 功能: ARM9上运行的微型操作系统(汇编)
; 备注: 汇编主要完成维护任务堆栈和存取堆栈指针SP的操作
;
; By Lisuwei
;
;***************************************************************************************/
AREA ARM_OS_ASM, CODE, READONLY
;********************************************************************************************************
; 引用的外部标号
;********************************************************************************************************
IMPORT p_OSTCBCur
IMPORT p_OSTCBHighRdy
IMPORT Int_Return_Addr_Save
IMPORT OSIntCtxSwFlag
IMPORT C_IRQHandler
IMPORT OSIntExit
;********************************************************************************************************
; 系统第一个运行的任务出栈
;********************************************************************************************************
EXPORT OSStartHighRdy ; 输出的标号
OSStartHighRdy
ldr r4,=p_OSTCBHighRdy ; 取出最高优先级就绪任务的PCB的地址
ldr r4,[r4] ; 取得任务的栈顶指针(因为TaskCtrBlock地址亦即OSTCBStkPtr的地址)
ldr sp,[r4] ; 任务的栈顶指针赋给SP
b POP_ALL ; 根据设定的栈结构顺序出栈
;********************************************************************************************************
; 根据设定的栈结构顺序入栈
;********************************************************************************************************
EXPORT OS_TASK_SW
OS_TASK_SW_INT ; 中断级任务切换,中断服务时使用另外的堆栈,所以要回到管理模式中才进行任务切换
sub sp,sp,#4 ; 为PC保留位置
stmfd sp!,{r0-r12,lr} ; r0-r12,lr入栈
ldr r0,=Int_Return_Addr_Save; 取出进入中断之前保存的PC
ldr r0,[r0] ; Int_Return_Addr_Save -> r0
add sp,sp,#56 ; 调整SP
stmfd sp,{r0} ; r0(PC)入栈
sub sp,sp,#56 ; 调整SP回到栈顶
b PUAH_PSR
OS_TASK_SW ; 任务级的任务切换
stmfd sp!,{lr} ; PC 入栈
stmfd sp!,{r0-r12,lr} ; r0-r12,lr入栈
PUAH_PSR
mrs r4,cpsr
stmfd sp!,{r4} ; cpsr入栈
SaveSPToCurTcb ; 保存当前任务的堆顶指针到它的TCB. TCB[OSPrioCur].OSTCBStkPtr = SP;
ldr r4,=p_OSTCBCur ; 取出当前任务的PCB地址
ldr r5,[r4] ;
str sp,[r5] ; 保存当前任务的堆顶指针到它的TCB(因为TaskCtrBlock地址亦即OSTCBStkPtr的地址)
GetHigTcbSP ; 取出更高优先级任务的堆顶指针到SP ,SP = TCB[OSPrioCur].OSTCBStkPtr
ldr r6,=p_OSTCBHighRdy ; 取出更高优先级就绪任务的PCB的地址
ldr r6,[r6]
ldr sp,[r6] ; 取出更高优先级任务的堆顶指针到SP
b POP_ALL ; 根据设定的栈结构顺序出栈
;********************************************************************************************************
; 根据设定的栈结构顺序出栈
;********************************************************************************************************
POP_ALL
ldmfd sp!,{r4} ; psr出栈
msr CPSR_cxsf,r4
ldmfd sp!,{r0-r12,lr,pc} ; r0-r12,lr,pc出栈
;********************************************************************************************************
; 中断服务入口程序
;********************************************************************************************************
EXPORT ASM_IRQHandler
ASM_IRQHandler ; 中断入口地址,在中断向量表初始化时被设置
sub lr,lr,#4 ; 计算中断返回地址
stmfd sp!,{r0-r3,r12,lr} ; 保护现场,此时处于中断模式下,sp指向中断模式下的堆栈.不能进行任务切换(各任务堆栈处在管理模式堆栈).
; R4-R11装的是局部变量,在进行函数跳转时,编译器它会自动保护它们,
; 即C语言函数返回时,寄存器R4-R11、SP不会改变,无需人为保护
bl C_IRQHandler ; 调用c语言的中断处理程序
bl OSIntExit ; 判断中断后是否有更高优先级的任务进入就绪而需要进行任务切换
ldr r0,=OSIntCtxSwFlag ; if(OSIntCtxSwFlag == 1) OSIntCtxSw()
ldr r1,[r0]
cmp r1,#1
beq OSIntCtxSw ; 有更高优先级的任务进入了就绪状态,则跳转到OSIntCtxSw进行中断级的任务切换
ldmfd sp!,{r0-r3,r12,pc}^ ; 不进行任务切换,出栈返回被中断的任务。寄存器出栈同时将spsr_irq的值复制到CPSR,实现模式切换
;********************************************************************************************************
; 中断后需任务切换时的跳转程序。若中断后需任务切换,则中断结束后不返回先前的任务,而去执行中断级任务切换
; 函数OS_TASK_SW_INT。因为中断返回地址保存了在中断模式的堆栈中(中断时先保存在中断模式的lr中,之后压栈),
; 这里把它用一个变量保存下来,待后任务切换时再把它取出压入先前任务的堆栈中(管理模式下)。
;
;********************************************************************************************************
OSIntCtxSw ; 把中断的返回地址保存到Int_Return_Addr_Save变量中
ldr r0,=OSIntCtxSwFlag
mov r1,#0
str r1,[r0] ; OSIntCtxSwFlag = 0
add sp,sp,#20 ; 调整SP,使之指向之前入栈的lr(中断模式下的lr保存的是中断返回地址),
ldr r0,[sp] ; lr -> r0
ldr r1,=Int_Return_Addr_Save; &Int_Return_Addr_Save -> r1
str r0,[r1] ; lr -> Int_Return_Addr_Save
ldr r0,=OS_TASK_SW_INT
str r0,[sp] ; OS_TASK_SW -> lr
sub sp,sp,#20 ; 调整SP回到栈顶
ldmfd sp!,{r0-r3,r12,pc}^ ; 退出中断后跳到OS_TASK_SW而不返回中断前运行的程序
;********************************************************************************************************
; 进入临界代码区
;********************************************************************************************************
NOINT EQU 0xc0
EXPORT OSCPUSaveSR
OSCPUSaveSR
mrs r0,CPSR ; 保存当前中断状态,参阅汇编子程序调用ATPCS规则,r0保存传递的参数
orr r1,r0,#NOINT ; 关闭所有中断
msr CPSR_c,r1
mov pc,lr
;********************************************************************************************************
; 退出临界代码区
;********************************************************************************************************
EXPORT OSCPURestoreSR
OSCPURestoreSR
msr CPSR_c,r0 ; 恢复原来的中断状态
mov pc,lr
END
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment