Está en la página 1de 30

Porting

Intel 80x86 Large mode


port
914390
914391
916304

uC/OS-II HW/SW Architecture


Application Software
C/OS-II
(Processor-Independent Code)
OS_CORE.C
uCOS_II.C
OS_MBOX.C
uCOS_II.H
OS_MEM.C
OS_Q.C
OS_SEM.C
OS_TASK.C
OS_TIME.C

C/OS-II Configuration
(Application-Specific Code)
OS_CFG.H
INCLUDES.H

C/OS-II Port
(Processor-Specific Code)
OS_CPU.H
OS_CPU_A.ASM
OS_CPU_C.C

Software
Hardware
CPU

Timer

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 Tools
Directories & 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
Intel/AMD
80186
\SOFTWARE\uCOS-II\Ix86s
\OS_CPU.H
OS_CPU.H, OS_CPU_C.C
and
\OS_CPU_A.ASM
OS_CPU_A.ASM
\OS_CPU_C.C

Motorola
68HC11

\SOFTWARE\uCOS-II\68HC11
\OS_CPU.H
\OS_CPU_A.ASM
\OS_CPU_C.C

OS_CPU.H -Data Types (compiler


specific)

typedef
typedef
typedef
typedef
typedef
typedef
typedef
typedef
typedef

unsigned
unsigned
signed
unsigned
signed
unsigned
signed
float
double

BOOLEAN;
INT8U;
INT8S;
INT16U;
INT16S;
INT32U;
INT32S;
FP32;
FP64;

/*
/*
/*
/*
/*
/*
/*
/*

typedef unsigned int

OS_STK;

/* Each stack entry is 16-bit wide */

#define
#define
#define
#define
#define

INT8S
INT8U
INT16U
INT32S
INT32U

BYTE
UBYTE
UWORD
LONG
ULONG

char
char
char
int
int
long
long

Unsigned 8 bit quantity */


Signed
8 bit quantity */
Unsigned 16 bit quantity */
Signed
16 bit quantity */
Unsigned 32 bit quantity */
Signed
32 bit quantity */
Single precision floating point */
Double precision floating point */

OS_CPU.H -- Critical
Section
#define

OS_CRITICAL_METHOD

#if
#define
#define
#endif

OS_CRITICAL_METHOD == 1
OS_ENTER_CRITICAL() asm
OS_EXIT_CRITICAL()
asm

CLI /* Disable interrupts */


STI /* Enable interrupts */

Both the CLI and STI instructions execute in less that two clock
cycles each on this processor (a total of 4 cycles)

#if
#define
#define
#endif

OS_CRITICAL_METHOD == 2
OS_ENTER_CRITICAL() asm {PUSHF; CLI} /* Disable interrupts */
OS_EXIT_CRITICAL()
asm POPF /* Enable interrupts */

OS_ENTER_CRITICAL consumes 12 clock cycles. OS_EXIT_CRITICAL


uses up 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
OSTaskCreateExt())
Called by OSStart(), OSStart()
OSStartHighRdy()

Pseudo code
Call 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
MOV

AX, SEG _OSTCBHighRdy


DS, AX
;

; Reload DS

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
POP ES
POPA

; Load task's context


;
;

;
IRET
_OSStartHighRdy ENDP

; Run task

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


OSRunning:

OSRunning is FALSE called from


OSStartHighRdy()
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 tasks stack pointer into the current tasks 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,POPA
Execute 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


highest priority task
:
ISR OSIntExit(),
OSIntExit() OSIntCtxSw().

OSIntCtxSw() (cont.)
Task Response
Interrupt Request

Interrupt disabled

TASK
Vectoring

Interrupt Recovery
No New HPT Or
OSLockNesting=0

Saving Context,saving all

Return from interrupt


Restore Context

Processor regisisters.

Notify kernels by call


OSIntEnter()

TASK

User ISR code

Notify kernel

Interrupt Response

Notify kernel
Restore Context

Call OSIntExit()
New HPT

Return from interrupt

Interrupt Recovery

Task Response

TASK

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 locked */
OSIntExitY = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((OSIntExitY << 3) +
OSUnMapTbl[OSRdyTbl[OSIntExitY]]);
if (OSPrioHighRdy != OSPrioCur) {
/* No context switch if current task is
highest ready */
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


every54.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


OSTaskCreateExt()
OSTaskStkInit() needs the following
arguments :

the start address of the task (task)


a pointer (pdata)
the tasks TOS (ptos)

OSTaskStkInit() (cont.)

Stack Frame Initialization with pdata passed on


the 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);
}

También podría gustarte