📄 os_cpu_c.c
字号:
/*
*********************************************************************************************************
* uC/OS-II
* The Real-Time Kernel
*
* (c) Copyright 1992-2002, Jean J. Labrosse, Weston, FL
* All Rights Reserved
*
*
* 80x86/80x88 Specific code
* LARGE MEMORY MODEL
*
* Borland C/C++ V4.51
*
* File : OS_CPU_C.C
* By : Jean J. Labrosse
*********************************************************************************************************
*/
#define OS_CPU_GLOBALS
#include "includes.h"
/*
*********************************************************************************************************
* OS INITIALIZATION HOOK
* (BEGINNING)
*
* Description: This function is called by OSInit() at the beginning of OSInit().进入OSInit()函数后,OSInitHookBegin()就会
立即被调用。添加这个函数的原因在于,想把与OS有关的初始化代码也放在OSInit()函数中。这个函数使得用户可以将自己特定的代码也
放在OSInit()函数中。这样代码会简洁明了。
*
* Arguments : none
*
* Note(s) : 1) Interrupts should be disabled during this call.
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
void OSInitHookBegin (void)
{
}
#endif
/*
*********************************************************************************************************
* OS INITIALIZATION HOOK
* (END)
*
* Description: This function is called by OSInit() at the end of OSInit().OSInitHookEnd()与OSInitHookBegin()函数相似,只是
它在OSInit()函数返回之前被调用。添加这个函数的原因与添加OSInitHookBegin()的原因是相同的。可以在第15章看到OSInitHookEnd()的
例子。
*
* Arguments : none
*
* Note(s) : 1) Interrupts should be disabled during this call.
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
void OSInitHookEnd (void)
{
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
* TASK CREATION HOOK
*
* Description: This function is called when a task is created.每当添加任务时,OS_TCBInit()函数都会调用OSTaskCreateHook()函
数。该函数允许扩展UCOS的功能。当UCOS设置完任务控制块(OS_TCB)初始化的绝大部分工作后,但在任务控制块被链接到相应的任务链中之
前, 以及在该任务就绪运行之前,UCOS会调用OSTaskCreateHook()。该函数被调用时中断是开着的。
当OSTaskCreateHook()被调用时,它会收到指向刚刚建立任务的任务控制块的指针。这样,OSTaskCreateHook()就可访问任务控制块结构所
有的成员了。当用OSTaskCreate()建立任务时,OSTaskCreateHook()的功能是有限的;但当使用OSTaskCreateExt()建立任务时,会得到
OS_TCB中的扩展指针(OSTCBExtPtr)。该指针可用来访问任务的附加数据,如浮点寄存器,MMU寄存器,任务计数器以及调试信息。可以检查
OS_TCBInit(),看都做了哪些工作。
*
* Arguments : ptcb is a pointer to the task control block of the task being created.
*
* Note(s) : 1) Interrupts are disabled during this call.
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0 /*只有当OS_CFG.H中的OS_CPU_HOOKS_EN置一时,才会生成OS_CPU_C.C文件中的相应OS???Hook()
函数。这些在本节和以下各节描述的HOOK函数的代码中,OS???Hook()函数是始终需要的,'#define constant OS_CPU_HOOKS_EN'并不意味着
OS???Hook()是否被调用。OS_CPU_HOOKS_EN只是表明OS???Hook()函数是在OS_CPU_C.C文件中(OS_CPU_HOOKS_EN==1),还是在其他文件中
(OS_CPU_HOOKS_EN==0)。这个特点使得用户可以在自己的移植实例中,在OS_CPU_C.C文件之外定义自己的HOOK函数。显然,使用该移植范例
其他源文件的用户,应将OS_CPU_HOOKS_EN设置为0,以防止链接时出现重复定义错误。如果不需要使用HOOK函数这种机制来扩展UCOS的功能
,可以将这些HOOK函数写成空函数。需要再次强调的是,UCOS需要这些HOOK函数(这些函数必须在某处定义)。*/
void OSTaskCreateHook (OS_TCB *ptcb)
{
ptcb = ptcb; /* Prevent compiler warning */
}
#endif
/*
*********************************************************************************************************
* TASK DELETION HOOK
在任务从就绪态列表或等待列表(若任务在等待某事件发生)中被删除后,OSTaskDel()就会调用OSTaskDelHook()。该函数在将任务从UCOS
的内部有效任务链表中删除之前被调用。当调用OSTaskDelHook()时,它会收到一个指向正在被删除任务的任务控制块的指针,这样它就可
以访问该任务控制块所有的结构成员了。OSTaskDelHook()可以用来检验TCB扩展部分是否已建立了(一个非空的指针),并进行一些清0等操
作。OSTaskDelHook()被调用时,中断是关掉的,所以该函数的代码太长会影响中断响应时间。
*
* Description: This function is called when a task is deleted.
*
* Arguments : ptcb is a pointer to the task control block of the task being deleted.
*
* Note(s) : 1) Interrupts are disabled during this call.
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0
void OSTaskDelHook (OS_TCB *ptcb)
{
ptcb = ptcb; /* Prevent compiler warning */
}
#endif
/*
*********************************************************************************************************
* IDLE TASK HOOK
*
* Description: This function is called by the idle task. This hook has been added to allow you to do
* such things as STOP the CPU to conserve power.很多处理器都允许执行相应的指令,将CPU置于低功耗模式。而当接受
到中断信号时,CPU就会退出低功耗模式。OSTaskIdle()函数可调用OSTaskIdleHook()函数,实现CPU的这种低功耗模式。详见邵贝贝UCOSII
*P300
* Arguments : none
*
* Note(s) : 1) Interrupts are enabled during this call.
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION >= 251
void OSTaskIdleHook (void)
{
}
#endif
/*
*********************************************************************************************************
* STATISTIC TASK HOOK
*
* Description: This function is called every second by uC/OS-II's statistics task. This allows your
* application to add functionality to the statistics task.OSTaskStatHook函数每秒都会被统计任务OSTaskStat()调用
一次。可以用OSTaskStatHook()扩展统计任务的功能。例如,可以跟踪并显示每个任务的执行时间,每个任务所用的CPU份额以及每个任务
执行的频率等等。
*
* Arguments : none
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0
void OSTaskStatHook (void)
{
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
* INITIALIZE A TASK'S STACK
UCOS的移植范例要求用户编写10个简单的C函数。唯一必要的是OSTaskStkInit(),其他9个函数必须声明,但并不一定要包含任何代码。
在本移植中就是这么作的。用#define语句定义的常数OS_CPU_HOOKS_EN(见OS_CFG.H)应该置为1.该函数由OSTaskCreate()或
OSTaskCreateExt()调用,用来初始化任务堆栈。将堆栈的结构初始化成看起来好像刚刚发生过中断一样,处理器的所有寄存器被推入堆栈。
当调用OSTaskCreate()或OSTaskCreateExt()建立一个新任务时,须传递的参数是:任务代码的起始地址(task),参数指针(pdata),任务堆栈
顶端的地址(ptos)以及任务的优先级(prio).OSTaskCreateExt()还需要一些其他参数,但与OSTaskStkInit()没有关系。为了合理地初始化
堆栈结构,OSTaskStkInit()只需要以上提到的前三个参数(task,pdata,ptos)。关于opt是调用OSTaskStkInit()函数时须要传递过去的参数
。因为只有OSTaskCreate()函数不支持附加的opt选项,因此,当OSTaskCreate()调用OSTaskStkInit()时,将opt设置为0x0000.
*
* Description: This function is called by either OSTaskCreate() or OSTaskCreateExt() to initialize the
* stack frame of the task being created. This function is highly processor specific.
*
* Arguments : task is a pointer to the task code
*
* pdata is a pointer to a user supplied data area that will be passed to the task
* when the task first executes.
*
* ptos is a pointer to the top of stack. It is assumed that 'ptos' points to
* a 'free' entry on the task stack. If OS_STK_GROWTH is set to 1 then
* 'ptos' will contain the HIGHEST valid address of the stack. Similarly, if
* OS_STK_GROWTH is set to 0, the 'ptos' will contains the LOWEST valid address
* of the stack.
*
* opt specifies options that can be used to alter the behavior of OSTaskStkInit().
* (see uCOS_II.H for OS_TASK_OPT_???).
*
* Returns : Always returns the location of the new top-of-stack' once the processor registers have
* been placed on the stack in the proper order.
*
* Note(s) : Interrupts are enabled when your task starts executing. You can change this by setting the
* PSW to 0x0002 instead. In this case, interrupts would be disabled upon task startup. The
* application code would be responsible for enabling interrupts at the beginning of the task
* code. You will need to modify OSTaskIdle() and OSTaskStat() so that they enable
* interrupts. Failure to do this will make your system crash!
*********************************************************************************************************
*/
OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)
{
INT16U *stk;
opt = opt; /* 'opt' is not used, prevent warning */
stk = (INT16U *)ptos; /* Load stack pointer由于80x86堆栈是16位宽的(以字为单位),OSTaskStkInit()将建
立并初始化一个局部指针变量。该指针变量指向以字为单位的内存区,同时UCOS要求指针ptos指向空堆栈的入口。*/
*stk-- = (INT16U)FP_SEG(pdata); /* Simulate call to function with argument;BorlandC编译器用堆栈而不是寄存器来
传递参数pdata,此时从参数pdata得到的段地址和偏移量都将按次序保存在堆栈中。
函数名: FP_SEG
功 能: 获取远地址段值
用 法: unsigned FP_SEG(void far *farptr);
函数名: FP_OFF
功 能: 获取远地址偏移量
用 法: unsigned FP_OFF(void far *farptr);
*/
*stk-- = (INT16U)FP_OFF(pdata);
*stk-- = (INT16U)FP_SEG(task); /*堆栈中紧接着是任务函数的起始地址。理论上,此处应该为任务的返回地址;但在UCOS
中,任务函数必须为无限循环结构,不能有返回点,所以这里保存的内容实际上无关紧要。*/
*stk-- = (INT16U)FP_OFF(task);
*stk-- = (INT16U)0x0202; /* SW = Interrupts enabled返回地址下面是状态字SW,设置状态字也是为了模拟中断发
生或的堆栈结构。堆栈中的SW初始化为0x0202,这将使任务启动后中断是开着的;如果设为0x0002,则任务启动后将关中断。UCOS不能
设置成一些任务启动后中断是开着的,而另一些任务启动后中断是关掉的。也就是说,要么所有的任务启动时中断都是开着的,要么都
是关掉的。如果确实要突破上述限制,则可以在用OSTaskCreateExt()函数建立任务时,通过参数pdata或者opt向任务传递启动时想要
的中断状态。然而,目前没有这么作。如果选择任务启动后中断是关掉的,那么每个任务运行时都需要重新开中断。在这种情况下,还
要修改OSTaskIdle()和OSTaskStat()函数,运行时开中断。如果以上任何一个环节出了问题,系统就会崩溃,所以推荐设置SW为0x0202
,在任务启动时开中断。*/
*stk-- = (INT16U)FP_SEG(task); /* Put pointer to task on top of stack */
*stk-- = (INT16U)FP_OFF(task);
*stk-- = (INT16U)0xAAAA; /* AX = 0xAAAA堆栈中还须留出各个寄存器的空间。注意寄存器在堆栈中的位置要和运行
指令PUSHA,PUSH ES以及PUSH DS后压入堆栈的次序相同。AX,BX,CX,DX,SP,BP,SI,DI的次序是与指令PUSHA的压栈次序相同的。
PUSHA和POPA能用一系列的push和pop指令来代替
在8086cpu下
pusha等价于
push ax
push bx
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -