?? 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 + -