移植uC/OS-II的绝大部分工作都集中在os_cpu_a.s文件的移植,这个文件的实现集中体现了所要移植到处理器的体系结构和uC/OS-II的移植原理;在这个文件里,最困难的工作又集中体现在OSIntCtxSw和OSTickISR这两个函数的实现上。这是因为这两个函数的实现是和移植者的移植思路以及相关硬件定时器、中断寄存器的设置有关。在实际的移植工作中,这两个地方也比较容易出错。
OSIntCtxSw最重要的作用就是它完成了在中断ISR中直接进行任务切换,从而提高了实时响应的速度。它发生的时机是在ISR执行到OSIntExit时,如果发现有高优先级的任务因为等待的time tick到来获得了执行的条件,这样就可以马上被调度执行,而不用返回被中断的那个任务之后再进行任务切换,因为那样的话就不够实时了。
实现OSIntCtxSw的方法大致也有两种情况:一种是通过调整sp堆栈指针的方法,根据所用的编译器对于函数嵌套的处理,通过精确计算出所需要调整的sp位置来使得进入中断时所作的保存现场的工作可以被重用。这种方法的好处是直接在函数嵌套内部发生任务切换,使得高优先级的任务能够最快的被调度执行。但是这个办法需要和具体的编译器以及编译参数的设置相关,需要较多技巧。另一种是设置需要切换标志位的方法,在OSIntCtxSw里面不发生切换,而是设置一个需要切换的标志,等函数嵌套从进入OsIntExit => OS_ENTER_CRITICAL() => OSIntCtxSw()=>OS_EXIT_CRITICAL() => OSIntExit退出后,再根据标志位来判断是否需要进行中断级的任务切换。这种方法的好处是不需要考虑编译器的因素。也不用做计算,但是从实时响应上不是最快,不过刚开始学习这种方法比较容易理解,实现起来也简单。
在中断态下进行任务切换,需要特别说明的一个问题是如何获得被中断任务的lr_svc。因为进入中断态后,lr变成了lr_irq,原来任务的lr_svc无法在中断态下获得,这样要得到l_svc,就必须在中断ISR里面进行一次cpu mode强制转换,即对CPSR赋值为0x000000d3,只有返回到SVC态之后才能得到原来任务的lr,这个对于任务切换很重要。还有一个需要留意的问题是在强制CPSR变成SVC态之后,SPSR也会相应地变成SPSR_irq,这样就需要在强制转变之前保存SPSR,也就是被中断任务中断前的CPSR。