200 likes | 374 Views
Chapter 9 80x86, Large Model Port. Porting to real mode and for the large model Real mode: 1Mb memory space (pointers in this model require 32 bits) In real mode, all registers are 16 bits wide, and they all need to be saved during a context switch. Figure 9.1 80x86 real-mode register map.
E N D
Chapter 980x86, Large Model Port • Porting to real mode and for the large model • Real mode: 1Mb memory space (pointers in this model require 32 bits) • In real mode, all registers are 16 bits wide, and they all need to be saved during a context switch
uC/OS-II Hardware/Software Architecture u u Setting the value of 1 #define constants (OS_CPU.H) Declaring 10 data types (OS_CPU.H) Declaring 3 #define macros (OS_CPU.H) Writing 6 simple functions in C (OS_CPU_C.C) Writing 4 assembly language functions (OS_CPU_A.ASM) u
OS_CPU.H #ifdef OS_CPU_GLOBALS #define OS_CPU_EXT #else #define OS_CPU_EXT extern #endif /* *************************************************************************** * DATA TYPES * (Compiler Specific) *************************************************************************** */ typedef unsigned char BOOLEAN; typedef unsigned char INT8U; /* Unsigned 8 bit quantity */ (1) typedef signed char INT8S; /* Signed 8 bit quantity */ typedef unsigned int INT16U; /* Unsigned 16 bit quantity */ typedef signed int INT16S; /* Signed 16 bit quantity */ typedef unsigned long INT32U; /* Unsigned 32 bit quantity */ typedef signed long INT32S; /* Signed 32 bit quantity */ typedef float FP32; /* Single precision floating point */ typedef double FP64; /* Double precision floating point */ typedef unsigned int OS_STK; /* Each stack entry is 16-bit wide */ #define BYTE INT8S /* Define data types for backward compatibility ... */ #define UBYTE INT8U /* ... to uC/OS V1.xx. Not actually needed for ... */ #define WORD INT16S /* ... uC/OS-II. */ #define UWORD INT16U #define LONG INT32S #define ULONG INT32U
#define OS_CRITICAL_METHOD 2 #if OS_CRITICAL_METHOD == 1 #define OS_ENTER_CRITICAL() asm CLI /* Disable interrupts */ (2) #define OS_EXIT_CRITICAL() asm STI /* Enable interrupts */ #endif #if OS_CRITICAL_METHOD == 2 #define OS_ENTER_CRITICAL() asm {PUSHF; CLI} /* Disable interrupts */ #define OS_EXIT_CRITICAL() asm POPF /* Enable interrupts */ #endif /* ***************************************************** * Intel 80x86 (Real-Mode, Large Model) Miscellaneous ***************************************************** */ #define OS_STK_GROWTH 1 /* Stack grows from HIGH to LOW memory on 80x86 */ (3) #define uCOS 0x80 /* Interrupt vector # used for context switch */ (4) #define OS_TASK_SW()asm INT uCOS //vector to the assembly language function OSCtxSw() (5) /* *********************************************************** * GLOBAL VARIABLES ********************************************************** */ OS_CPU_EXT INT8U OSTickDOSCtr; /* Counter used to invoke DOS's tick handler every 'n' ticks */ (6) // the defualt tick rate is 18.2Hz. if we set the clock tick to 200Hz, this allow you to chain into DOS once every 11 ticks.
Context Switch • In uC/OS-II, the stack frame for a ready task always looks as if an interrupt has just occurred and all processor registers were saved onto to it • OS_TASk_SW() is always called from task-level code • OSIntExit() is used to perform a context switch when an ISR makes a higher priority task ready for execution • OS_CPU_A.ASM • OSStartHighRdy() • OSCtxSw() • OSIntCtxSw() • OSTickISR()
OSStartHighRdy(): called by OSStart() Void OSStartHighRdy(void) { call user definable OSTaskSwHook() Get the stack pointer of the task to resume: stack pointer = OSTCBHighRdy->OSTCBStkPtr; OSRunning = True; Restore all processor registers from the new task’s stack; Execute a return from interrupt instruction: } _OSStartHighRdy PROC FAR MOV AX, SEG _OSTCBHighRdy ; Reload DS MOV DS, AX ; LES BX, DWORD PTR DS:_OSTCBHighRdy ; SS:SP = OSTCBHighRdy->OSTCBStkPtr (1) MOV SS, ES:[BX+2] ; MOV SP, ES:[BX+0] ; ; POP DS ; Load task's context (2) POP ES ; (3) POPA ; (4) ; IRET ; Run task (5) _OSStartHighRdy ENDP
OSCtxSw(): a task call an OS kernel call =>OSSched() => select a highest priority => INT 80H => OSCtxSw() void OSCtxSw(void) { Save processor registers; Save the current task’s stack pointer into the current task’s OS_TCB: OSTCBCur->OSTCBStkPtr = Stack pointer; Call user definable OSTaskSwHook(); OSTCBCur = OSTCBHighRdy; OSPrioCur = OSPrioHighRdy; Get the stack pointer of the task to resume: Stack pointer = OSTCBHighRdy->OSTCBStkPtr; Restore all processor registers from the new task’s stack; Execute a return from interrupt instruction; }
Figure 9.4 80x86 stack frames during a task-level context switch
Listing 9.4 OSCtxSw() _OSCtxSw PROC FAR ; (1) ; PUSHA ; Save current task's context (2) PUSH ES ; (3) PUSH DS ; (4) ; MOV AX, SEG _OSTCBCur ; Reload DS in case it was altered MOV DS, AX ; ; LES BX, DWORD PTR DS:_OSTCBCur ; OSTCBCur->OSTCBStkPtr = SS:SP (5) MOV ES:[BX+2], SS ; MOV ES:[BX+0], SP ; ; CALL FAR PTR _OSTaskSwHook (6) ; MOV AX, WORD PTR DS:_OSTCBHighRdy+2 ; OSTCBCur = OSTCBHighRdy (7) MOV DX, WORD PTR DS:_OSTCBHighRdy ; MOV WORD PTR DS:_OSTCBCur+2, AX ; MOV WORD PTR DS:_OSTCBCur, DX ; ; MOV AL, BYTE PTR DS:_OSPrioHighRdy ; OSPrioCur = OSPrioHighRdy (8) MOV BYTE PTR DS:_OSPrioCur, AL ; LES BX, DWORD PTR DS:_OSTCBHighRdy ; SS:SP = OSTCBHighRdy->OSTCBStkPtr (9) MOV SS, ES:[BX+2] ; MOV SP, ES:[BX] ; ; POP DS ; Load new task's context (10) POP ES ; (11) POPA ; (12) ; IRET ; Return to new task (13) ; _OSCtxSw ENDP
OSIntCtxSw(): called by OSIntExit() Figure 9.5 80x86 stack frames during an interrupt-level context switch
Pseudocode for OSIntCtxSw() void OSIntCtxSw(void) { Adjust the stack pointer to remove calls to: OSIntExit(), OSIntCtxSw() and possibly the push of the processor status word; Save the current task’s stack pointer into the current task’s OS_TCB: OSTCBCur->OSTCBStkPtr = Stack pointer; Call user definable OSTaskSwHook(); OSTCBCur = OSTCBHighRdy; OSPrioCur = OSPrioHighRdy; Get the stack pointer of the task to resume: Stack pointer = OSTCBHighRdy->OSTCBStkPtr; Restore all processor registers from the new task’s stack; Execute a return from interrupt instruction; }
Listing 9.5 OSIntCtxSw() _OSIntCtxSw PROC FAR ; ; Ignore calls to OSIntExit and OSIntCtxSw ; ADD SP,8 ; (Uncomment if OS_CRITICAL_METHOD is 1, see OS_CPU.H) (1) ADD SP,10 ; (Uncomment if OS_CRITICAL_METHOD is 2, see OS_CPU.H) ; MOV AX, SEG _OSTCBCur ; Reload DS in case it was altered MOV DS, AX ; ; LES BX, DWORD PTR DS:_OSTCBCur ; OSTCBCur->OSTCBStkPtr = SS:SP (2) MOV ES:[BX+2], SS ; MOV ES:[BX+0], SP ; ; CALL FAR PTR _OSTaskSwHook (3) ; MOV AX, WORD PTR DS:_OSTCBHighRdy+2 ; OSTCBCur = OSTCBHighRdy (4) MOV DX, WORD PTR DS:_OSTCBHighRdy ; MOV WORD PTR DS:_OSTCBCur+2, AX ; MOV WORD PTR DS:_OSTCBCur, DX ; ; MOV AL, BYTE PTR DS:_OSPrioHighRdy ; OSPrioCur = OSPrioHighRdy (5) MOV BYTE PTR DS:_OSPrioCur, AL ; LES BX, DWORD PTR DS:_OSTCBHighRdy ; SS:SP = OSTCBHighRdy->OSTCBStkPtr (6) MOV SS, ES:[BX+2] ; MOV SP, ES:[BX] ; ; POP DS ; Load new task's context (7) POP ES ; (8) POPA ; (9) ; IRET ; Return to new task (10) ; _OSIntCtxSw ENDP
OSTickISR() Figure 9.6 The PC interrupt vector table (IVT)
Pseudocode for tick ISR void OSTickISR (void) { Save processor registers; (1) OSIntNesting++; (2) OSTickDOSCtr—-; (3) if (OSTickDOSCtr == 0) { Chain into DOS by executing an ‘INT 81H’ instruction; (4) } else { Send EOI command to PIC (Priority Interrupt Controller); (5) } OSTimeTick(); (6) OSIntExit(); (7) Restore processor registers; (8) Execute a return from interrupt instruction (IRET); (9) }
Listing 9.7 OSTickISR() _OSTickISR PROC FAR ; PUSHA ; Save interrupted task's context PUSH ES PUSH DS ; MOV AX, SEG _OSTickDOSCtr ; Reload DS MOV DS, AX ; INC BYTE PTR _OSIntNesting ; Notify uC/OS-II of ISR ; DEC BYTE PTR DS:_OSTickDOSCtr CMP BYTE PTR DS:_OSTickDOSCtr, 0 JNE SHORT _OSTickISR1 ; Every 11 ticks (~199.99 Hz), chain into DOS ; MOV BYTE PTR DS:_OSTickDOSCtr, 11 INT 081H ; Chain into DOS's tick ISR JMP SHORT _OSTickISR2 _OSTickISR1: MOV AL, 20H ; Move EOI code into AL. MOV DX, 20H ; Address of 8259 PIC in DX. OUT DX, AL ; Send EOI to PIC if not processing DOS timer. ; _OSTickISR2: CALL FAR PTR _OSTimeTick ; Process system tick ; CALL FAR PTR _OSIntExit ; Notify uC/OS-II of end of ISR ; POP DS ; Restore interrupted task's context POP ES POPA ; IRET ; Return to interrupted task ; _OSTickISR ENDP
OSTaskStkInit() void MyTask (void *pdata) { /* Do something with argument ‘pdata’ */ for (;;) { /* Task code */ } } • Stack frame initialization with pdata passed on the stack