Download uC/OS-II, The Real Time Kernel

Transcript
The code for OSTaskStkInit() is shown in listing 9.9.
void *OSTaskStkInit (void (*task)(void *pd), void *pdata, void *ptos, INT16U opt)
{
INT16U *stk;
opt
= opt;
stk
= (INT16U *)ptos;
*stk-= (INT16U)FP_SEG(pdata);
*stk-= (INT16U)FP_OFF(pdata);
*stk-= (INT16U)FP_SEG(task);
*stk-= (INT16U)FP_OFF(task);
*stk-= (INT16U)0x0202;
*stk-= (INT16U)FP_SEG(task);
*stk-= (INT16U)FP_OFF(task);
*stk-= (INT16U)0xAAAA;
*stk-= (INT16U)0xCCCC;
*stk-= (INT16U)0xDDDD;
*stk-= (INT16U)0xBBBB;
*stk-= (INT16U)0x0000;
*stk-= (INT16U)0x1111;
*stk-= (INT16U)0x2222;
*stk-= (INT16U)0x3333;
*stk-= (INT16U)0x4444;
*stk
= _DS;
return ((void *)stk);
/* 'opt' is not used, prevent warning
/* Load stack pointer
/* Simulate call to function with argument
*/
(1) */
(2) */
/* Place return address of function call
(3) */
/* SW = Interrupts enabled
/* Put pointer to task
on top of stack
(4) */
*/
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
(5) */
*/
*/
*/
*/
*/
*/
*/
*/
(6) */
AX
CX
DX
BX
SP
BP
SI
DI
ES
DS
=
=
=
=
=
=
=
=
=
=
0xAAAA
0xCCCC
0xDDDD
0xBBBB
0x0000
0x1111
0x2222
0x3333
0x4444
Current value of DS
}
Listing 9.9, OSTaskStkInit()
OSTaskStkInit() creates and initializes a local pointer to 16-bit elements because stack entries are 16-bit wide
on the 80x86 L9.9(1). Note that µC/OS-II requires that the pointer ptos points to an empty stack entry.
The Borland C/C++ compiler passes the argument pdata on the stack instead of registers (at least with the compiler
options I selected). Because of this, pdata is placed on the stack frame with the OFFSET and SEGMENT in the order
shown L9.9(2).
The address of your task is placed on the stack next L9.9(3). In theory, this should be the return address of your task.
However, in µC/OS-II, a task must never return so, what is placed here is not really critical.
The Status Word (SW ) along with the task address are placed on the stack L9.9(4) to simulate the behavior of the
processor in response to an interrupt. The SW register is initialized to 0x0202 . This will allow the task to have
interrupts enabled when it starts. You can in fact start all your tasks with interrupts disabled by forcing the SW to
0x0002 instead. There are no options in µC/OS-II to selectively enable interrupts upon startup for some tasks and
disable interrupts upon task startup on others. In other words, either all tasks have interrupts disabled upon startup or
all tasks have them disabled. You could, however, overcome this limitation by passing the desired interrupt startup state
of a task by using pdata . If you chose to have interrupts disabled, each task will need to enable them when they
execute. You will also have to modify OSTaskIdle() and OSTaskStat() to enable interrupts in those
functions. If you don’t, your application will crash! I would thus recommend that you leave the SW initialized to
0x0202 and have interrupts enabled when the task starts.
Next, the remaining registers are placed on the stack to simulate the PUSHA, PUSH ES and PUSH DS instructions
which are assumed to be found at the beginning of every ISR L9.9(5). Note that the AX , BX , CX , DX, SP , BP , SI and
DI registers are placed to satisfy the order of the PUSHA instruction. If you were to port this code to a ‘plain’8086