Abstract
UC/OS2 是即時系統核心,跟其它微型作業系統一樣,它沒有shell, file system, network stack…等,所以對porting來說,改動的幅度不大
原始碼可在此網頁查看
在porting的過程中只需改動5個檔案,分別是
1.OS_CPU_A.s:增加4個函式的實作(OSStartHighRdy, OSIntCtxSw, OSCtxSw, OS_CPU_SR_Save, OS_CPU_SR_Restore)
2.OS_CPU_C.c:實做process stack的存放方式,和critical section進入和離開的函式
3.OS_CPU.H:宣告相關cpu-specified的變數
4.Vector.s:實做IRQ中斷時的uc/os context switch
5.timer.c:呼叫OS的計時函式

OS_CPU.H

宣告以ARM cpu資料型太為基準的OS相關的變數

typedef unsigned char  BOOLEAN; 
typedef unsigned char  INT8U;                   
typedef signed   char  INT8S;                   
typedef unsigned short INT16U;                 
typedef signed   short INT16S;                 
typedef unsigned int   INT32U;                 
typedef signed   int   INT32S;                 
typedef float          FP32;                   
typedef double         FP64;                   
typedef INT32U         OS_STK;

OS_CPU_C .c

1.    設置Process Stack(function name:OSTaskStkInit)
根據uc/os2的文件,當我們用OSTaskCreateExt去建立process時,會需要宣告這個process所需要用到的stack address,而uc/os2做context switch時,會根據stack內所存的內容而決定context switch時所需替換的暫存器和PC.uc/os2運作在ARM SVC模式,所以我們要存R0-R14,PC,和SPSR這些暫存器的值

在OSTaskStkInit內可看到程式碼如下

OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)
{
 INT32U *stk;
 
    stk = (INT32U*)ptos;   
    *stk-- = (INT32U)task;
    *stk-- = (INT32U)0x14141414;  //R14(LR)
    *stk-- = (INT32U)0x12121212;  //R12
    *stk-- = (INT32U)0x11111111;  //R11
    *stk-- = (INT32U)0x10101010;  //R10
    *stk-- = (INT32U)0x09090909;  //R9
    *stk-- = (INT32U)0x08080808;  //R8
    *stk-- = (INT32U)0x07070707;  //R7
    *stk-- = (INT32U)0x06060606;  //R6
    *stk-- = (INT32U)0x05050505;  //R5
    *stk-- = (INT32U)0x04040404;  //R4
    *stk-- = (INT32U)0x03030303;  //R3
    *stk-- = (INT32U)0x02020202;  //R2
    *stk-- = (INT32U)0x01010101;  //R1
    *stk-- = (INT32U)(pdata);     //R0   
    *stk   = (INT32U)0x13;        //SPSR(SVC MODE)
  
    return ((OS_STK *)stk);
}

2.Critical section的進入與離開(OS_ENTER_CRITICAL and OS_EXIT_CRITICAL)

這個函式目的在保存CPU切換模式時的CPSR暫存器的值

OS_CPU_A .s

1. OSStartHighRdy
此函式是uc/os2執行時呼叫的第一個函式,它會尋找最高優先權的process並執行它

; OSRunning = TRUE
 LDR     R0, =OSRunning //程式執行變數
MOV     R1, #1
 STRB    R1, [R0]
    
 ; Load First Task//把第一個high ready process拿來執行
 LDR     R0, OSTCBHighRdy    ; Load address of OSTCBHighRdy
 LDR     SP, [R0]            ; Load SP of task
 //開始還原最高優先權process的執行環境
 LDMFD   SP!, {R1}       ; get spsr of first task
 MSR     SPSR_cxsf, R1
 LDMFD   SP!, {R0-R12, LR, PC}^  ;run first task!

OSCtxSw   
    STMFD   SP!, {LR}           ; save context of previous task
    STMFD   SP!, {LR}
    STMFD   SP!, {R0-R12}
    MRS     R4, CPSR//保存CPSR
    STMFD   SP!, {R4}
    
    LDR     R4, =OSTCBCur       ; OSTCBCur->OSTCBStkPtr = SP;
    LDR     R5, [R4]
    STR     SP, [R5]
    
    LDR     R4, =OSPrioCur         ; OSPrioCur = OSPrioHighRdy   
    LDR     R6, =OSPrioHighRdy   
    LDRB    R6, [R6]
    STRB    R6, [R4]
    
    LDR     R4, =OSTCBCur          ; OSTCBCur = OSTCBHighRdy
    LDR     R6, =OSTCBHighRdy
    LDR     R6, [R6]
    STR     R6, [R4]
    
    LDR     SP, [R6]                ; SP = OSTCBCur->OSTCBStkPtr
    
    LDMFD   SP!, {R4}
    MSR     SPSR_cxsf, R4
    
    LDMFD   SP!, {R0-R12, LR, PC}^  ; pop new task's context

2. OSCtxSw
此函式是在OS_Sched函式內呼叫,uc/os2執行context switch的時間點有兩個
(1)當函式執行OSTimeDly函式時
(2)當CPU碰到中斷時
而OSCtxSw是當第一個情況發生時(當函式執行OSTimeDly函式時)會呼叫的函式,所以,假設我們目前有兩個process分別是PA和PB,當PA執行到OSTimeDly,CPU會保存PA目前執行環境的所有暫存器並從process queue裡面拿出最高優先權的process,也就是PB,取得PB的TCB(task control buffer),並從PB的TCB內取得它的stack,然後根據PB stack的內容,逐一還原PB的執行環境

3. OSIntCtxSw
OSIntCtxSw這個函式是當第二個情況發生時(當CPU碰到中斷時)會呼叫的函式,當中斷執行完畢時,CPU會執行這個context switch函式,因為前一個執行的process已經在IRQ中斷周期發生前保存了自己的執行環境,所以這個函式只要選擇最高優先權的PROCESS並執行它就可以了

OSIntCtxSw
    LDR     R4, =OSPrioCur         ; OSPrioCur = OSPrioHighRdy
    LDR     R5, =OSPrioHighRdy
    LDRB    R6, [R5]
    STRB    R6, [R4]
    
    LDR     R4, =OSTCBCur          ; OSTCBCur = OSTCBHighRdy
    LDR     R5, =OSTCBHighRdy
    LDR     R6, [R5]
    STR     R6, [R4]
    
    LDR     SP, [R6]                ; SP = OSTCBCur->OSTCBStkPtr
    
    LDMFD   SP!, {R4}
    MSR     SPSR_cxsf, R4
    LDMFD   SP!, {R0-R12, LR, PC}^  ; pop new task's context

vector.s

1. IRQ_Handler
因為已經切換到IRQ模式,所以我們暫存器的LR,CPSR都已經改變了,當ARM切換IRQ中斷時,會把上一個模式的CPSR存在SPSR,所以我們所要做的動作如下
(1)計算LR和保存LR和SPSR

STMFD   SP!, {R0-R2}                         
    MOV     R1, SP
    ADD     SP, SP, #12//把IRQ SP的指標還原,我們只是暫時借用
    SUB     R2, LR, #4
    MRS     R0, SPSR

(2)切換還SVC模式並保存PROCESS CONTEXT

MSR     CPSR_c, #Mode_SVC | I_BIT | F_BIT   
    
    STMFD   SP!, {R2}           ; PC
    STMFD   SP!, {LR}           ; LR
    STMFD   SP!, {R3-R12}       ; R3-R12
 
    LDMFD   R1, {R4-R6}         ; get R1-R3 from IRQ's stack
    
    STMFD   SP!, {R4-R6}        ; push task's R1-R3
    STMFD   SP!, {R0}           ; push task's spsr

(3)呼叫OSIntEnter,切換回IRQ模式,並執行IRQ routine,再切回SVC模式然後再呼叫OSIntExit,並還原上一個PROCESS的執行環境

BL OSIntEnter
    ; switch to interrupt mode
    MSR     CPSR_c, #Mode_IRQ | I_BIT | F_BIT   ; change to IRQ mode and disable IRQ,FIQ       
    BL        ISR_IRQ       
    ;restore task after interrupt routine is finished
    MSR     CPSR_c, #Mode_SVC | I_BIT | F_BIT   ; change to SVC mdoe
    BL      OSIntExit
    LDMFD   SP!, {R4}
    MSR     SPSR_cxsf, R4
    LDMFD   SP!, {R0-R12, LR, PC}^              ; pop new task's context

timer.c

1. Timer0_ISR
在timer ISR內執行系統計時函式OSTimeTick()

void Timer0_ISR(void)
{
    OSTimeTick();
}

最後修改日期: 3 6 月, 2022

作者

留言

撰寫回覆或留言

發佈留言必須填寫的電子郵件地址不會公開。