|
移植需要改写的文件:OS_CPU.H, OS_CPU_A.S, OS_CPU_C.C
1.OS_CPU.H
定义了数据类型,与编译器相关,需要修改;
#define SVC32MODE 0x13 移植后的OS运行在SVC模式下;
typedef unsigned int OS_STK 因为处理器现场的寄存器在任务切换时都将会保存在当前运行任务的堆栈中,所以OS_STK数据类型应该是和处理器的寄存器长度一致。 定义了堆栈的方向,在S3C44B0X定义为:#define OS_STK_GROWTH 1
OS_ENTER_CRITICAL() 和 OS_EXIT_CRITICAL()的实现: 我们用第二种方式:#define OS_CRITICAL_METHOD 2,使用堆栈保存状态和恢复状态;
#define OS_ENTER_CRITICAL() ARMDisableInt() #define OS_EXIT_CRITICAL() ARMEnableInt() 在OS_CPU.A.S中实现:
EXPORT ARMDisableInt ARMDisableInt MRS r0, cpsr STMFD sp!, {r0} push current PSR ORR r0, r0, #0xC0 MSR cpsr_c, r0 disable IRQ Int s MOV pc, lr
EXPORT ARMEnableInt ARMEnableInt LDMFD sp!, {r0} pop current PSR MSR cpsr_c, r0 restore original cpsr MOV pc, lr
2. OS_CPU_C.C 钩子函数(HOOK)由用户实现,这里只有定义即可。 主要实现OSTaskStkInit函数:OSTaskCreate和OSTaskCreateExt通过调用OSTaskStkInit来初始化任务的堆栈结构。 堆栈看起来就像中断刚发生过一样,所有寄存器都保存在堆栈里。
OS_STK * OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt) { unsigned int *stk;
opt = opt; /* 'opt' is not used, prevent warning */ stk = (unsigned int *)ptos; /* Load stack pointer */
/* build a context for the new task */ *--stk = (unsigned int) task; /* pc */ *--stk = (unsigned int) task; /* lr */
*--stk = 0; /* r12 */ *--stk = 0; /* r11 */ *--stk = 0; /* r10 */ *--stk = 0; /* r9 */ *--stk = 0; /* r8 */ *--stk = 0; /* r7 */ *--stk = 0; /* r6 */ *--stk = 0; /* r5 */ *--stk = 0; /* r4 */ *--stk = 0; /* r3 */ *--stk = 0; /* r2 */ *--stk = 0; /* r1 */ *--stk = (unsigned int) pdata; /* r0 */ *--stk = (SVC32MODE|0x40); /* cpsr FIQ disable*/ //*--stk = (SVC32MODE|0x40); /* spsr FIQ disable */
return ((OS_STK *)stk); }
定义一个全局变量: INT32U OSIntCtxSwFlag = 0; /* Used to flag a context switch */ 3. OS_CPU_A.S
4个简单的汇编语言函数
(1) OSStartHighRdy() OSStart()函数调用OSStartHighRdy()来使就绪态任务中优先级最高的任务开始运行。
示意代码: void OSStartHighRdy(void) { 调用用户定义的OSTaskSwHook(); OSRunning = TRUE; 得到将要恢复运行任务的堆栈指针: Stack pointer = OSTCBHighRdy->OSTCBStkPtr; 从新任务堆栈中恢复处理器的所有寄存器; 执行中断返回指令; }
汇编代码:
OSStartHighRdy
BL OSTaskSwHook Call user-defined hook function
LDR r4,=OSRunning Indicate that multitasking has started MOV r5, #1 STRB r5, [r4] OSRunning = true
LDR r4, =OSTCBHighRdy Get highest priority task TCB address LDR r4, [r4] get stack pointer LDR sp, [r4] switch to the new stack
LDMFD sp!, {r4} pop new task s psr MSR cpsr_cxsf, r4 LDMFD sp!, {r0-r12,lr,pc} pop new task s r0-r12,lr & pc
(2) OSCtxSw() OSCtxSw():实现任务切换功能。
示意代码:
void OSCtxSw(void) { 保存处理器寄存器; 在当前任务的任务控制块中保存当前任务的堆栈指针: OSTCBur->OSTCBStkPtr = Stack pointer; OSTaskSwHook(); OSTCBCur = OSTCBHighRdy; OSPrioCur = OSPrioHighRdy; 得到将要重新开始的任务的堆栈指针: Stack Pointer = OSTCBHighRdy->OSTCBStkPtr; 从新任务的任务堆栈中恢复处理器所有寄存器的值; 执行中断返回指令; }
汇编代码: OSCtxSw STMFD sp!, {lr} push pc (lr is actually be pushed in place of PC) STMFD sp!, {r0-r12,lr} push lr & register file
MRS r4, cpsr STMFD sp!, {r4} push current psr
LDR r4, =OSTCBCur Get current task TCB address LDR r5, [r4] STR sp, [r5] store sp in preempted tasks s TCB IMPORT OSTaskSwHook OSIntCtxSw BL OSTaskSwHook LDR r4, =OSTCBHighRdy LDR r4, [r4] LDR r5, =OSTCBCur STR r4, [r5] OSTCBCur = OSTCBHighRdy
LDR r6, =OSPrioHighRdy LDRB r6, [r6] LDR r5, =OSPrioCur STRB r6, [r5] OSPrioCur = OSPrioHighRdy
LDR sp, [r4] LDMFD sp!, {r4} pop new task cpsr MSR cpsr_cxsf, r4 LDMFD sp!, {r0-r12,lr,pc} pop new task r0-r12,lr & pc
OSIntCtxSw是OSCtxSw的一部分。
(3) OSIntCtxSw() OSIntExit()通过调用OSintCtxSw(),在ISR中执行任务切换功能。
示意性代码: void OSIntCtxSw(void) { 调用用户定义的OSTaskSwHook(); OSTCBCur = OSTCBHIGHRdy; OSPrioCur = OSPrioHighRdy; 得到将要重新执行的任务的堆栈指针: Stack pointer = OSTCBHighRdy->OSTCBStkPtr; 从新任务堆栈中恢复所有处理器寄存器; 执行中断返回指令; }
汇编代码: 在上面已经实现。
(4) OSTickISR() 时钟节拍中断服务例程。
示意性代码: void OSTickISR(void) { 保存处理器的寄存器; 调用OSIntEnter()或者直接给OSIntNesting加1; if (OSIntNesting == 1) { OSTCBCur->OSTCBStkPtr = Stack Pointer; } 给产生中断的设备清中断; 重新允许中断(可选); OSTimeTick(); OSIntExit(); 恢复处理器寄存器; 执行中断返回指令; }
汇编代码: EXPORT OSTickISR IMPORT OSIntEnter IMPORT OSTimeTick IMPORT tick_hook IMPORT OSIntExit
LINK_SAVE DCD 0 PSR_SAVE DCD 0
OSTickISR STMFD sp!, {r4} 这个SP是IRQ模式下的! LDR r4, =LINK_SAVE STR lr, [r4] LINK_SAVE = lr_irq
MRS lr, spsr STR lr, [r4, #4] PSR_SAVE = spsr_irq LDMFD sp!, {r4} 只好重新恢复R4 ORR lr, lr, #0x80 Mask irq for context switching before MSR cpsr_cxsf, lr returning back from irq mode.我们还没有 保存好现场,如果打开中断,就有可能发生新的 抢占式调度,于是这个现场就OVER了。现场保 护和现场恢复都要一气呵成。
SUB sp, sp, #4 Space for PC STMFD sp!, {r0-r12, lr}
LDR r4, =LINK_SAVE LDR lr, [r4, #0] SUB lr, lr, #4 PC = LINK_SAVE - 4, STR lr, [sp, #(14*4)] SAVE PC [..]the return address for pc.
LDR r4, [r4, #4] r4 = PSR_SAVE, STMFD sp!, {r4} CPSR of the task LDR r4, =OSTCBCur LDR r4, [r4] STR sp, [r4] OSTCBCur -> stkptr = sp 保存现场完毕
BL OSIntEnter BL OSTimeTick BL tick_hook 我们在Tick_hook()里清除S3C44B0x的Tick_Int_Pend位,这个 函数在main.c里,是另加的. BL OSIntExit
LDMFD sp!, {r4} pop current task cpsr MSR cpsr_cxsf, r4 LDMFD sp!, {r0-r12,lr,pc} pop current task r0-r12,lr & pc
特别感谢: uCOS-II在 S3C44B0x 系统上的移置 Arming (实际上这个版本就是他移植好的)
参考文献: 嵌入式实时操作系统uc/os-II Jean J.Labrosse | |
| |