在μc/os中的OS_cpu_a.s中用汇编语言实现了一下函数,其中很多与硬件相关,如果要在不同的平台上面进行移植,要进行修改,准备将系统移植到我们的SHARC-DSP上面去试一试。下面的代码是ARM体系,吐槽一下CU的代码粘贴,对汇编的支持不够好啊。。
OSCtxSw()任务上下文切换, 将当前任务压栈,切换当前优先级和当前TCB,从新的TCB中弹栈
操作系统的核心
- OSCtxSw
- STMFD SP!, {LR} ;PC
- STMFD SP!, {R0-R12, LR} ;R0-R12 LR
- MRS R0, CPSR ;Push CPSR
- STMFD SP!, {R0}
- ;----------------------------------------------------------------------------------
- ; OSTCBCur->OSTCBStkPtr = SP
- ;----------------------------------------------------------------------------------
- LDR R0, =OSTCBCur
- LDR R0, [R0]
- STR SP, [R0]
- ;----------------------------------------------------------------------------------
- ; OSTaskSwHook();
- ;---------------------------------------------------------------------------------
- BL OSTaskSwHook
- ;----------------------------------------------------------------------------------
- ; OSTCBCur = OSTCBHighRdy;
- ;----------------------------------------------------------------------------------
- LDR R0, =OSTCBHighRdy
- LDR R1, =OSTCBCur
- LDR R0, [R0]
- STR R0, [R1]
- ;----------------------------------------------------------------------------------
- ; OSPrioCur = OSPrioHighRdy;
- ;----------------------------------------------------------------------------------
- LDR R0, =OSPrioHighRdy
- LDR R1, =OSPrioCur
- LDRB R0, [R0]
- STRB R0, [R1]
- ;----------------------------------------------------------------------------------
- ; OSTCBHighRdy->OSTCBStkPtr;
- ;----------------------------------------------------------------------------------
- LDR R0, =OSTCBHighRdy
- LDR R0, [R0]
- LDR SP, [R0]
- ;----------------------------------------------------------------------------------
- ;Restore New task context
- ;----------------------------------------------------------------------------------
- LDMFD SP!, {R0} ;POP CPSR
- MSR SPSR_cxsf, R0
- LDMFD SP!, {R0-R12, LR, PC}^
OSIntCtxSw() 中断中实现task的上下文切换,与上一个函数不同的是不需要压栈,因为是在中断中的实现
OSStartHighRdy()OS开始运行时,切换进入第一个任务的服务子程序,不是中断
关中断 SVC模式 将OSRunning置1 SP(R13)切换到最高优先级任务的堆栈指针 弹栈
OS_CPU_IRQ_ISR() 这个程序在汇编boot文件中进行了调用,调用中断服务子程序对应的地址
所有的IRQ都要经过这个函数跳转到相应的中断向量表指向的子函数,这个函数在boot中被装入HandlerIRQ中
- OS_CPU_IRQ_ISR
- STMFD SP!, {R1-R3} ; We will use R1-R3 as temporary registers
- ;----------------------------------------------------------------------------
- ; R1--SP
- ; R2--PC
- ; R3--SPSR
- ;------------------------------------------------------------------------
- MOV R1, SP
- ADD SP, SP, #12 ;Adjust IRQ stack pointer
- SUB R2, LR, #4 ;Adjust PC for return address to task
- MRS R3, SPSR ; Copy SPSR (Task CPSR)
- MSR CPSR_cxsf, #SVCMODE|NOINT ;Change to SVC mode
- ; SAVE TASK''S CONTEXT ONTO OLD TASK''S STACK
- STMFD SP!, {R2} ; Push task''s PC
- STMFD SP!, {R4-R12, LR} ; Push task''s LR,R12-R4
- LDMFD R1!, {R4-R6} ; Load Task''s R1-R3 from IRQ stack
- STMFD SP!, {R4-R6} ; Push Task''s R1-R3 to SVC stack
- STMFD SP!, {R0} ; Push Task''s R0 to SVC stack
- STMFD SP!, {R3} ; Push task''s CPSR
- LDR R0,=OSIntNesting ;OSIntNesting++
- LDRB R1,[R0]
- ADD R1,R1,#1
- STRB R1,[R0]
- CMP R1,#1 ;if(OSIntNesting==1){
- BNE %F1
- LDR R4,=OSTCBCur ;OSTCBHighRdy->OSTCBStkPtr=SP;
- LDR R5,[R4]
- STR SP,[R5] ;}
- 1
- MSR CPSR_c,#IRQMODE|NOINT ;Change to IRQ mode to use IRQ stack to handle interrupt
- LDR R0, =INTOFFSET
- LDR R0, [R0]
- LDR R1, IRQIsrVect
- MOV LR, PC ; Save LR befor jump to the C function we need return back
- LDR PC, [R1, R0, LSL #2] ; Call OS_CPU_IRQ_ISR_handler();
- MSR CPSR_c,#SVCMODE|NOINT ;Change to SVC mode
- BL OSIntExit ;Call OSIntExit
- LDMFD SP!,{R4} ;POP the task''s CPSR
- MSR SPSR_cxsf,R4
- LDMFD SP!,{R0-R12,LR,PC}^ ;POP new Task''s context
临时使用R1-R3作为SP PC SPSR寄存器
SVCmode 对于ARM来说,跳进中断模式会将PC值加4,即下一个指令地址赋值给LR,将LR-4会得到中断前PC的值
问题:利用ADD SP, SP, #12 返回中断前的SP?进行压栈?
将R2 R4-R12 R14(LR)压入中断前任务的堆栈
从中断的堆栈取出数据到R4-R6 将R4-R6压栈如SVC栈,将R0压入SVC栈
OSIntNesting++ ;if(OSIntNesting==1){OSTCBHighRdy->OSTCBStkPtr=SP;}
进入IRQ模式,关中断,调用OS_CPU_IRQ_ISR_handler();
返回SVC模式,调用OSIntExit退出中断,中间使用了OSIntCtxSw()函数,判定OSIntNesting是否为0,如果中断有嵌套返回当前IRQ_ISR函数
从SP中弹栈返回进入中断前的上下文和SP LR
OSTickISR() 实现时钟滴答中断服务,在中断子程序中实现所有任务的DELAY计时自减,当为0时进入就绪态
- OSTickISR
- MOV R5,LR
- MOV R1, #1
- MOV R1, R1, LSL #10 ; Timer0 Source Pending Reg.
- LDR R0, =SRCPND
- LDR R2, [R0]
- ORR R1, R1,R2
- STR R1, [R0]
- LDR R0, =INTPND
- LDR R1, [R0]
- STR R1, [R0]
- ;----------------------------------------------------------------------------------
- ; OSTimeTick();
- ;----------------------------------------------------------------------------------
- BL OSTimeTick
- MOV PC, R5 ; Return
将LR存入R5 SRCPND读取到R0 (SRCPND当一个中断发生后,那么相应的位会被置1,表示一个或一类中断发生了)
将寄存器值写入R2,R1=1<<10,R1 R2位或,赋值给R1,写入SRCPND//相当于给SRCPND|=(1<<10);
INTPND 优先级最高的中断裁决寄存器,只有最高优先级的中断才会被置位
读取INTPND的值到R1,跳转到OStimetick
将R5(原先LR的)的值赋给PC
阅读(2060) | 评论(0) | 转发(1) |