📄 os_cpu.h
字号:
/*
*********************************************************************************************************
* 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.H
* By : Jean J. Labrosse
*********************************************************************************************************
*/
#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 */
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 */
typedef unsigned short OS_CPU_SR; /* Define size of CPU status register (PSW = 16 bits) */
#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
/*
*********************************************************************************************************
* Intel 80x86 (Real-Mode, Large Model)
*
* Method #1: Disable/Enable interrupts using simple instructions. After critical section, interrupts
* will be enabled even if they were disabled before entering the critical section.
*
* Method #2: Disable/Enable interrupts by preserving the state of interrupts. In other words, if
* interrupts were disabled before entering the critical section, they will be disabled when
* leaving the critical section.
*
* Method #3: Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you
* would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then
* disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II's functions that need to
* disable interrupts. You would restore the interrupt disable state by copying back 'cpu_sr'
* into the CPU's status register.
*********************************************************************************************************
*/
#define OS_CRITICAL_METHOD 2
#if OS_CRITICAL_METHOD == 1 /*第一种方法是以最简单的方式来实现这2个宏调用的:用
处理器指令关中断,然而这种方法有点小问题,如果调用UCOS的功能函数时,中断是关掉的,则从UCOS的函数返回时,中断
就打开了。若调用UCOS的函数之前已将中断关掉,那么用户往往希望从UCOS的函数返回时,中断仍然是关掉的。在此情况下
,这种实现方法就不妥当;但是对于一些特定的处理器和编译器,使用这种方法是唯一的选择*/
#define OS_ENTER_CRITICAL() asm CLI /* Disable interrupts */
#define OS_EXIT_CRITICAL() asm STI /* Enable interrupts */
#endif
#if OS_CRITICAL_METHOD == 2 /*实现OS_ENTER_CRITICAL()的第二种方法是在堆栈中保存
中断的开关状态,然后再关中断。在实现OS_EXIT_CRITICAL()时,只需简单的从堆栈中弹出原来中断的开关状态即可。利用这种
机制,不论用户在调用UCOS的函数之前中断是开着的还是关着的,函数的进入和返回状态都得到了保护。换句话说,如果调用前
中断是关掉的,则调用后扔是关掉的。关中断后调用UCOS的函数要特别小心,因为关中断延长了应用程序的中断延迟时间;
任务切换时间和中断延迟时间是评估RTOS性能的两个重要指标。任务切换时间可以反映出RTOS执行任务的速度,而中断延迟时间
可以反映出RTOS对外界变化的反应速度。表3为这两种操作系统任务切换时间和中断延迟时间的比较 :任务切换时间/us 中断延迟
时间/μs 测试环境
μC/OS-II 29.7~34.2 78.8 Intel80186(33MHz)
eCos 15.84 19.2 MPC860A3(33MHz)
。*/
#define OS_ENTER_CRITICAL() asm {PUSHF; CLI} /* Disable interrupts */
#define OS_EXIT_CRITICAL() asm POPF /* Enable interrupts */
#endif
#if OS_CRITICAL_METHOD == 3 /*一些编译器提供了扩展功能,用户可以得到当前处理器状态字
的值,并保存在C函数的局部变量中这个变量可以用于恢复PSW*/
#define OS_ENTER_CRITICAL() (cpu_sr = OSCPUSaveSR()) /* Disable interrupts */
#define OS_EXIT_CRITICAL() (OSCPURestoreSR(cpu_sr)) /* Enable interrupts */
#endif
/*
*********************************************************************************************************
* Intel 80x86 (Real-Mode, Large Model) Miscellaneous
*********************************************************************************************************
*/
#define OS_STK_GROWTH 1 /* Stack grows from HIGH to LOW memory on 80x86绝大多数微处理器和
微控制器的堆栈是从上往下递减的,但是也有某些处理器使用的是相反的方式。UCOS被设计成2种情况都可以处理,只要在用被指常数
OS_STK_GROWTH指定堆栈的方向就可以了。OS_STK_GROWTH为0,表示堆栈从下(低地址)往上(高地址)递增;置OS_STK_GROWTH为1,表示堆栈
从上(高地址)往下(低地址)递减。之所以这样处理,是出于2个原因:首先,OSInit()需要知道,当OS_TaskIdle()和OS_TaskStat()函数建立
任务时,堆栈的顶端地址在哪里;其次,在调用OSTaskStkChk()时,UCOS需要知道堆栈的底端地址在哪里,从而得到堆栈的使用情况。*/
#define uCOS 0x80 /* Interrupt vector # used for context switch ;OS_TASK_SW()是一个宏
,是在UCOS从低优先级任务切换到高优先级任务时须用到的。OS_TASK_SW()总是在任务级代码中调用。另一个函数OSIntExit()用在中断服
务子程序ISR中。当中断服务子程序使更高优先级任务进入就绪态时,OSIntExit()完成任务切换功能。任务切换只是简单的将处理器的寄存
器保存到将被挂起的任务的堆栈中,并且从堆栈中恢复要运行的更高优先级的任务。
在UCOS中,处于就绪态任务的堆栈结构看起来就像刚刚发生过中断一样,所有的寄存器都保存在堆栈中。换句话说,UCOS要运行处于
就绪态的任务必须要作的事就是,从任务堆栈中恢复处理器所有的寄存器,并且执行中断返回指令。为了任务调度,可以通过执行
OS_TASK_SW()模仿中断的产生。绝大多数处理器会提供软中断或指令陷阱(TRAP)来完成这项功能。中断服务子程序或指令陷阱处理函数
也叫做异常处理函数的中断向量地址必须指向汇编语言函数OSCtxSw()。用户必须知道自己所使用的编译器和处理器是如何实现让中断向量
指向OSCtxSw()的。80X86有256个软中断可供选用。中断服务子程序ISR也称为异常处理的入口地址必须指向汇编函数OSCtxSw()见
OS_CPU_A.ASM文件。这里需要确认0x80中断向量指向OSCtxSw()。作者在PC机上做了测试,本章的代码用到了向量号为128(0x80)的中断,
因此此中断是提供给用户使用的。实际上,最初的PC将0x80~0xF0的中断给BASIC解释程序使用,后来机会在没有内植BASIC解释程序的PC机了
,所以用这些中断向量是安全的。类似的,可用的中断号还有0x4B~0x5B,0x5D~0x66以及0x68~0x6F。如果用的不是PC,而是其他嵌入式系统
,如80186处理器,则可能有更多的终端资源可供选用。*/
#define OS_TASK_SW() asm INT uCOS
/*
*********************************************************************************************************
* GLOBAL VARIABLES
*********************************************************************************************************
*/
OS_CPU_EXT INT8U OSTickDOSCtr; /* Counter used to invoke DOS's tick handler every 'n' ticks 在这里声明了一个8位
变量OSTickDOSCtr,用来保存时钟节拍发生的次数。每发生11次,调用1次DOS的时钟节拍函数,从而实现与DOS时钟的同步。OSTickDOSCtr
在OS_CPU_A.ASM中使用,是专门为PC环境而定义的。如果在其他非PC的嵌入式系统中运行UCOS,就不必使用这种方法了,直接设定时钟节拍
频率就可以了。*/
/*实时系统中时钟节拍的频率应该置为10~100HZ。通常但不是必须为了方便计
算,设为整数。不幸的是,在PC中,系统默认的时钟节拍频率是18.20648HZ,这对于计算和设置都不方便。本章中,将PC的时钟节拍频率从
18.20648HZ改为200HZ(间隔5ms)。这样做的原因有3个:
1,200HZ近似18.206 48HZ的11倍,可以经过11次延时,在调用DOS中断。在DOS中,时钟节拍处理程序要求每隔54.93ms进行一次有关系统
维护的操作;
2,设定的间隔5ms对于时间延时和时间超时设置都很有用。若pc机处理器是80386,那么时钟节拍最快也只能到200HZ;而如果是PentiumII
处理器,则很容易达到200HZ以上。
3,虽然将时钟节拍频率设定为20HZ或者100HZ也是可以的,但是这样将难以产生18.206 48HZ的DOS中断。这就是选择整数倍频,即选择200hz
的原因。当然也可以选择22倍频,这样就是400HZ间隔2.5ms。在一台更快的PC上,使用这种时钟节拍频率甚至更高的频率都不会有问题。
*/
/*
*********************************************************************************************************
* PROTOTYPES
*********************************************************************************************************
*/
void OSTaskStkInit_FPE_x86(OS_STK **pptos, OS_STK **ppbos, INT32U *psize);
/*如前面所述,Borland编译器提供了一个浮点仿真库。但是该库不具备可重入性。
增加了一个函数,使用户可以预处理任务的堆栈。这样使BorlandC任务只有一个任务在使用浮点仿真库,于是让浮点仿真库
具备可重入性*/
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR OSCPUSaveSR(void);
void OSCPURestoreSR(OS_CPU_SR cpu_sr);
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -