星期四, 2月 17, 2005

uC/OS II

uC/OS是以function的集合作爲kernel,並沒有和RTXC一樣把所有的Kernel operation包裝在一個 .C檔裏,也就是說uC/OSkernal API沒有統一的entry point

uC/OS規定每一個task有一個prioritypriority不能重復,這個priority同時會拿來作task idid越小,priority越高。規定只有64task.

目前的執行的task id (priority)是放在OSPrioCurtask control block (TCB)OSTCBCur

uC/OStask switch動作在OSCtxSw裏,所有作task switchfunction最後都會執行這一段程式,OSCtxSwswitchtask idOSPrioHighRdytask,對應的TCBOSTCBHighRdy,同時upate這兩個變數,所以執行完OSCtxSw後,OSPrioHighRdy=OSPrioCutOSTCBHighRdy = OSTCBCur

所以任何有可能做task switchkernel API,都會找到ready taskpriority最高的taskupdateOSPrioHighRdyOSTCBHighRdy裏,再由OSCtxSwswitch

和其他的OS一樣,有機會作task switch的時機有1.Call kernel API. 2.Hardware interrupt

uC/OSsystem object: Message, MemoryPartition, Queue, Semaphore, Task, Timer

中斷服務常式的寫法:

1. 調整r14, 存入Stack[IRQ]

2. SPSR存入Stack[IRQ]

3. 清除中斷源

4. 切換SYS ModeDisable Interrupt

5. r0~r12, r14存入Stack[SYS]

6. 呼叫OSIntEnter ( C function )

7. 呼叫 這個中斷的C function

8. 呼叫OSIntExit ( C function )

9. r0~r12, r14Stack取出

10. 切換回IRQ Mode, Enable Interrupt

11. 回應硬體EOI (End Of Interrupt)

12. SPSRStack取出

13. ldmfd sp!, {pc}^

Timer Interrupt Service Routine

scratch reg: r12

IRQ Mode

1. IRQ 先存 Stack[IRQ]={ lr-4,SPSR,r12 }

2. IRQ 讀取AIC_IVR和TC0_Base[20]

3. IRQ Enable IRQ, Switch to SYS Mode

4. SYS 將所有reg存 Stack[SYS] = {r0~r12, r14}

5. SYS 呼叫 OSIntEnter, OSTimeTick

6. SYS 呼叫OSIntExit: -------------- 如果有需要,切回IRQ Mode,作Context Switch

7. SYS 取回r0 ~ r12, r14 Stack[SYS] = { }

8. SYS Disable IRQ, Switch to IRQ Mode

9. IRQ 讀取AIC_EOICR

10. IRQ 取回r12, r14(SPSR) Stack[IRQ]= {lr-4}

11. IRQ restore SPSR from r14

12. IRQ ldmfd sp!, {pc}^ 回到被中斷程式

OSIntExit

C function,所有Interrupt Service routine都要呼叫這個C function before ending, function主要工作是找出目前Priority最高的Ready Task,並且作Task Switch,會呼叫OSIntCtxSw (Assembly Code)作Context Switch

OSIntCtxSw

Assembly Code,主要工作是Content Switch,程式中負責Task Switch的有兩個,這是其中之一,另一個是OS_TASK_SW,不同的地方是OSIntCtxSw是在Interrupt Service Routine中作Task Switch, OS_TASK_SW是在呼叫System API時作Task Switch使用的。

1. 調整sp,sp = sp - 4

2. switch to IRQ Mode

3. 拿出所所有進入IRQ時Save的Stack, (3個register)

4. 通知EOI

5. Switch to SYS Mode

6. OSCtxSw執行

OS_TASK_SW

都是在SYS Mode

1. r0~r12, r14 Stack[SYS] = { r0~r12, r14 }

2. ---- OSCtxSw ---- label,以下和OSIntCtxSw共用

3. CPSR, SPSR Stack[SYS] = { r0~r12, r14, CPSR, SPSR }

4. OSPrioCur = OSPrioHighRdy

5. 將目前sp保存在tack的TCB結構 OSTCBCur.sp = SP

6. 切換目前的sp到新的task SP = OSTCBHighRdy.sp

7. OSTCBCur = OSTCBHighRdy

8. Stack中取回SPSR Stack[SYS] = { r0~r12, r14, CPSR }

9. Stack中取回CPSR Stack[SYS] = { r0~r12, r14 }

10. 取回r0~r12, r14 Stack[SYS] = { }

11. bx r14

uCOS_II用一個特殊的方法來找出目前ReadyList中priority最高的Task. 系統最多容許64個task,所以一個task用一個bit來代表,需要8個byte來代表所有Task。

8 bit OSRdyTbl[8] : bit=1代表Ready Task

8 bit OSRdyGrp. : bit=1代表OSRdyGrp的Entry不是0

當要從OSRdyTble[]找到最高priority的bit時(也就是bit order最小的task時)

uCOS_II利用一個Table

INT8U const OSUnMapTbl[] = {

0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0

};

Table有256entry,代表一個OSRdyTbl Entry (8 bit)的所有組合。這個Table就是最小bit的查表,舉例來說13的最bit是

OSUnMap[13]=0 /* 13 = 10011,最小是bit 0 */

所以先從

OSRdyGrp中找到最小不等於0的OSRdyTbl Entry

y = OSUnMapTbl [ OSRdyGrp ]

再由OSRdyTbl找到最小不為0的bit

x = OSUnMapTbl [ OSRdyTbl [ y ] ]

x + ( y <<>

沒有留言:

網誌存檔