30
Porting – Intel 80x86 Large mode port 914390 周周周 914391 周周周 916304 周周周

05_Porting80x86

Embed Size (px)

DESCRIPTION

Porting to 8086 information

Citation preview

Porting – Intel 80x86 Large mode port

914390 周嘉政914391 高偉欽916304 孫佑銘

uC/OS-II HW/SW ArchitectureApplication Software

μC/OS-II(Processor-Independent Code)OS_CORE.C uCOS_II.COS_MBOX.C uCOS_II.HOS_MEM.C OS_Q.COS_SEM.C OS_TASK.COS_TIME.C

μC/OS-II Configuration(Application-Specific Code)

OS_CFG.HINCLUDES.H

μC/OS-II Port(Processor-Specific Code)

OS_CPU.HOS_CPU_A.ASM

OS_CPU_C.C

CPU Timer

SoftwareHardware

80x86 real-mode register map

Addressing with a Segment and an offset

Memory addressing relies on using a segment and offset register

A 20-bit address that can access up to 1Mb

A 16-bit segment register can point to any of 65,536 different paragraphs of 16 bytes

Development ToolsDirectories & Files Development Tools : Borland C/C++ V3.1

compiler along with the Borland Turbo Assembler

The compiler provides in-line assembly language instructions to be inserted in C code

The source code for the port is found in OS_CPU.H, OS_CPU_C.C and OS_CPU_A.ASM

Intel/AMD 80186 \SOFTWARE\uCOS-II\Ix86s

Motorola 68HC11

\SOFTWARE\uCOS-II\68HC11

\OS_CPU.H

\OS_CPU_A.ASM

\OS_CPU_C.C

\OS_CPU.H\OS_CPU_A.ASM\OS_CPU_C.C

OS_CPU.H -- Data Types (compiler specific)

typedef unsigned char BOOLEAN;typedef unsigned char INT8U; /* Unsigned 8 bit quantity */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 UBYTE INT8U #define UWORD INT16U#define LONG INT32S#define ULONG INT32U

OS_CPU.H -- Critical Section

#define OS_CRITICAL_METHOD 2

#if OS_CRITICAL_METHOD == 1#define OS_ENTER_CRITICAL() asm CLI /* Disable interrupts */#define OS_EXIT_CRITICAL() asm STI /* Enable interrupts */#endif Both the CLI and STI instructions execute in less that two clock cycles eac

h on this processor (a total of 4 cycles)

#if OS_CRITICAL_METHOD == 2#define OS_ENTER_CRITICAL() asm {PUSHF; CLI} /* Disable interrupts */#define OS_EXIT_CRITICAL() asm POPF /* Enable interrupts */#endif OS_ENTER_CRITICAL consumes 12 clock cycles. OS_EXIT_CRITICAL uses u

p another 8 clock cycles (a total of 20 cycles)

OS_CPU.H -- Miscellaneous#define OS_STK_GROWTH 1/* Stack grows from HIGH to LOW memory on 80x86 */

#define uCOS 0x80 /* Interrupt vector # used for context switch */

#define OS_TASK_SW() asm INT uCOS

OS_CPU_EXT INT8U OSTickDOSCtr; /* Counter used to invoke DOS's tick handler every 'n' ticks */

OS_CPU_A.ASM

A μC/OS-II port requires 4 assembly language functions: OSStartHighRdy() OSCtxSw() OSIntCtxSw() OSTickISR()

(1) OSStartHighRdy() 功能 : 系統一開始的時候 , 執行此 function, 使最高 priority task

執行 順序 :

系統一開始時呼叫 OSInit() ( 在 OS_CORE.C 中 ) 至少建立一個 task (by calling OSTaskCreate() and OSTask

CreateExt()) Called by OSStart(), OSStart() 中呼叫 OSStartHighRdy()

Pseudo codeCall user definable OSTaskSwHook();Get the stack pointer of the task to resume:

Stack Pointer = OSTCBHighRdy OSTCBStkPtr;OSRunning = TRUE;Execute a return from interrupt instruction

OSStartHighRdy() (cont.)

OSStartHighRdy() (cont.)_OSStartHighRdy PROC FAR

MOV AX, SEG _OSTCBHighRdy ; Reload DS MOV DS, AX ; ; CALL FAR PTR _OSTaskSwHook ; Call user defined task switch hook; INC BYTE PTR DS:_OSRunning ; Indicate that multitasking has started; LES BX, DWORD PTR DS:_OSTCBHighRdy ; SS:SP = OSTCBHighRdy->OSTCBStkPtr MOV SS, ES:[BX+2] ; MOV SP, ES:[BX+0] ; ; POP DS ; Load task's context POP ES ; POPA ; ; IRET ; Run task

_OSStartHighRdy ENDP

OSStartHighRdy() (cont.) OSRunning

declaration( in uCOS_II.H) OS_EXT BOOLEAN OSRunning;

initialization(in OS_CORE.C) OSRunning = FALSE; OSTaskSwHook() //in OS_CPU_C.C 內容 :void OSTaskSwHook (void) {} 功能 : 提供使用者操作 OSTCBCur 和 higest priority

task 之 TCB( 由 OSTCBHighRdy 指到 ), 為使用者自訂 .

OSStartHighRdy() (cont.) OSTaskSwHook() can examine OSRun

ning: OSRunning is FALSE – called from OSStar

tHighRdy() OSRunning is TRUE – called from regular

context switch

(2) OSCtxSw() 用途 :Task-level context switch Use software interrupt(int 0x80) 喚起 : 1. 每次作 context 喚起 OSSched() 其中呼叫 OS_TASK_SW(),OS_TASK_SW()

是一個 software interrupt, 此 interrupt 執行 OSCtxSw(),OSCtxSw() 使最高priority 的 task run

2. No context switch if current task is highest ready Pseudo code

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;POP DS,POP ES,POPAExecute a return from interrupt instruction;

OSCtxSw() (cont.)

OSSched () (in OS_CORE.C) void OSSched (void){ INT8U y;

OS_ENTER_CRITICAL(); if ((OSLockNesting | OSIntNesting) == 0) { /* Task scheduling must be enabled and not ISR level */ y = OSUnMapTbl[OSRdyGrp]; /* Get pointer to highest priority task ready to run */ OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]); if (OSPrioHighRdy != OSPrioCur) { /* No context switch if current task is highest ready */ OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; OSCtxSwCtr++; /* Increment context switch counter */ OS_TASK_SW(); /* Perform a context switch */ } } OS_EXIT_CRITICAL();}

OSCtxSw()

(3) OSIntCtxSw() 功能 :context switch from ISR to highe

st priority task 呼叫過程 : ISR 結束前會呼叫 OSIntExit(), OSIntExit

() 中呼叫 OSIntCtxSw().

OSIntCtxSw() (cont.)

TASK TASK

TASK

Task ResponseInterrupt disabled

Interrupt Response

Vectoring

Saving Context,saving all

Processor regisisters.

Notify kernels by call OSIntEnter()

User ISR code Notify kernel

Restore Context

Return from interrupt

Interrupt RecoveryInterrupt Request

New HPT

Interrupt RecoveryTask Response

No New HPT Or OSLockNesting=0

Return from interrupt

Notify kernel

Restore ContextCall OSIntExit()

OSIntCtxSw() (cont.) OSIntExit in OS_CPU_C.C

void OSIntExit (void){ OS_ENTER_CRITICAL(); if ((--OSIntNesting | OSLockNesting) == 0) { /* Reschedule only if all ISRs completed & not l

ocked */ OSIntExitY = OSUnMapTbl[OSRdyGrp]; OSPrioHighRdy = (INT8U)((OSIntExitY << 3) + OSUnMapTbl[OSRdyTbl[OSIntExitY]]); if (OSPrioHighRdy != OSPrioCur) { /* No context switch if current task is highest read

y */ OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; OSCtxSwCtr++; /* Keep track of the number of context switches */ OSIntCtxSw(); /* Perform interrupt level context switch */ } } OS_EXIT_CRITICAL();}

OSIntCtxSw() (cont.) called by OSIntExit(), 和 OSCtxSw() 相

似 , 不同之處為 : - 因為所有 processor reg 在 ISR 執行之

前已都被正確的放入 interrupt task stack,所以不必儲存 regisisters( 即 :no PUSHA,PUSH ES,PUSH DS)

執行此 function 時候 interrupt 為 disable

( 因為 OSIntExit() 設的 )

OSIntCtxSw() (cont.)

OSIntCtxSw() (cont.)_OSIntCtxSw PROC FAR; ; Ignore calls to OSIntExit and OSIntCtxSw; ADD SP,8 ; (Uncomment if OS_CRITICAL_METHOD is 1, see OS_CPU.H) 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 MOV ES:[BX+2], SS ; MOV ES:[BX+0], SP ; ; CALL FAR PTR _OSTaskSwHook ; Call user defined task switch hook; MOV AX, WORD PTR DS:_OSTCBHighRdy+2 ; OSTCBCur = OSTCBHighRdy 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 MOV BYTE PTR DS:_OSPrioCur, AL ; LES BX, DWORD PTR DS:_OSTCBHighRdy ; SS:SP = OSTCBHighRdy->OSTCBStkPtr MOV SS, ES:[BX+2] ; MOV SP, ES:[BX] ; ; POP DS ; Load new task's context POP ES ; POPA ; ; IRET ; Return to new task;_OSIntCtxSw ENDP

(4) OSTickISR() On PC, the ticker occurs ev

ery54.93ms(18.20648Hz), what needs to be done while changing tick rate to 200Hz?

Relocate the original ticker ISR from 0x08 to 0x81

Install OSCtxSw() ISR at 0x80

Create first task which should help to install OSTickISR() at 0x08 and change the tick rate if needed

Call OSStart() to start multitasking

OSTickISR() (cont.) Pseudo code

Save processor registers;OSIntNesting++;OSTickDOSCtr--;if (OSTickDOSCtr == 0) {

Chain into DOS by executing an ‘INT 81H’ instruction;} else {

Send EOI (End of Interrupt) command to PIC (Priority Interrupt Controller);

}OSTimeTick();OSIntExit();Restore processor registers;Execute a return from interrupt instruction (IRET);

OSTickISR() (cont.) Incorrect place to start the tick interrupt

void main(void){

…OSInit();…Enable TICKER interrupts; /*DO NOT DO THIS HERE */…OSStart();

}

OS_CPU_C.C

A μC/OS-II port requires 6 C functions: OSTaskStkInit() //necessary OSTaskCreateHook() OSTaskDelHook() OSTaskSwHook() OSTaskStatHook() OSTimeTickHook()

(1) OSTaskStkInit() Called by OSTaskCreate() and OSTask

CreateExt() OSTaskStkInit() needs the following a

rguments : the start address of the task (task) a pointer (pdata) the task’s TOS (ptos)

OSTaskStkInit() (cont.) Stack Frame Initialization with pdata passed on th

e stack

OSTaskStkInit() (cont.)void *OSTaskStkInit (void (*task)(void *pd), void *pdata, void *ptos, INT16U opt){ INT16U *stk; opt = opt; /* 'opt' is not used, prevent warning */ stk = (INT16U *)ptos; /* Load stack pointer */ *stk-- = (INT16U)FP_SEG(pdata); /* Simulate call to function with argument */ *stk-- = (INT16U)FP_OFF(pdata); *stk-- = (INT16U)FP_SEG(task); *stk-- = (INT16U)FP_OFF(task); *stk-- = (INT16U)0x0202; /* SW = Interrupts enabled */ *stk-- = (INT16U)FP_SEG(task); /* Put pointer to task on top of stack */ *stk-- = (INT16U)FP_OFF(task); *stk-- = (INT16U)0xAAAA; /* AX = 0xAAAA */ *stk-- = (INT16U)0xCCCC; /* CX = 0xCCCC */ *stk-- = (INT16U)0xDDDD; /* DX = 0xDDDD */ *stk-- = (INT16U)0xBBBB; /* BX = 0xBBBB */ *stk-- = (INT16U)0x0000; /* SP = 0x0000 */ *stk-- = (INT16U)0x1111; /* BP = 0x1111 */ *stk-- = (INT16U)0x2222; /* SI = 0x2222 */ *stk-- = (INT16U)0x3333; /* DI = 0x3333 */ *stk-- = (INT16U)0x4444; /* ES = 0x4444 */ *stk = _DS; /* DS = Current value of DS */ return ((void *)stk);}