- 嵌入式實(shí)時操作系統(tǒng):基于ARM Mbed OS的應(yīng)用實(shí)踐
- 王宜懷等
- 3229字
- 2024-02-27 16:08:41
2.1 CPU內(nèi)部寄存器的分類及ARM Cortex-M處理器的主要寄存器
實(shí)時操作系統(tǒng)在運(yùn)行過程中需要對CPU的寄存器進(jìn)行頻繁操作。本書采用的是基于ARM Cortex-M系列內(nèi)核的MCU。理解和掌握其CPU的主要寄存器,熟悉各個寄存器的含義和操作方式,是深入理解實(shí)時操作系統(tǒng)的必要前提條件。
2.1.1 CPU內(nèi)部寄存器的分類
以軟件開發(fā)工程師視角來看,從底層學(xué)習(xí)一個CPU,理解其內(nèi)部寄存器用途是重要一環(huán)。計(jì)算機(jī)所有指令運(yùn)行均由CPU完成,CPU內(nèi)部寄存器負(fù)責(zé)信息暫存,其數(shù)量與處理能力直接影響CPU的性能。本節(jié)先從一般意義上闡述寄存器基礎(chǔ)知識及相關(guān)基本概念,第2.1.2節(jié)介紹ARM Cortex-M微處理器的內(nèi)部寄存器。
從共性知識角度及功能來看,CPU內(nèi)至少應(yīng)該有數(shù)據(jù)緩沖寄存器、堆棧指針寄存器、程序指針寄存器、程序狀態(tài)寄存器及其他功能寄存器。
1.數(shù)據(jù)緩沖寄存器
CPU內(nèi)數(shù)量最多的寄存器是數(shù)據(jù)緩沖寄存器,名字用寄存器的英文“Register”的首字母加數(shù)字組成,如R0、R1、R2等。不同的CPU,數(shù)據(jù)緩沖寄存器的種類也不同,如8086中的通用寄存器有8個,分別是AX、BX、CX、DX、SP、BP、SI、DI;Intel X86系列的通用寄存器也有8個,分別是EAX、EBX、ECX、EDX、ESP、EBP、ESI、EDI。
2.堆棧指針寄存器
在計(jì)算機(jī)編程中,有全局變量與局部變量的概念。從存儲器角度來看,對一個具有獨(dú)立功能的完整程序來說,全局變量具有固定的地址,每次讀寫都是那個地址。而在一個子程序中開辟的局部變量則不同,用RAM中的哪個地址是不固定的,采用后進(jìn)先出(Last In First Out,LIFO)原則使用一段RAM區(qū)域,這段RAM區(qū)域被稱為棧區(qū)[1]。它有個棧底的地址,是一開始就確定的,當(dāng)有數(shù)據(jù)進(jìn)棧或出棧時,地址會自動連續(xù)變動[2],不然就放到同一個存儲地址中。CPU中需要有個地方保存這個不斷變化的地址,這個地方就是堆棧指針寄存器(通常稱為堆棧指針)。
3.程序指針寄存器
計(jì)算機(jī)的程序存儲在存儲器中,CPU中有個寄存器指示將要執(zhí)行的指令在存儲器中的位置,這就是程序指針寄存器。在許多CPU中,它的名字叫作程序計(jì)數(shù)寄存器,它負(fù)責(zé)告訴CPU將要執(zhí)行的指令在存儲器的什么地方。
4.程序狀態(tài)寄存器
CPU在進(jìn)行計(jì)算過程中,會出現(xiàn)諸如進(jìn)位、借位、結(jié)果為0、溢出等情況,CPU內(nèi)需要有個地方把它們保存下來,以便下一條指令結(jié)合這些情況進(jìn)行處理,這類寄存器就是程序狀態(tài)寄存器。不同的CPU,其名稱也不同,有的叫作標(biāo)志寄存器,有的叫作程序狀態(tài)寄存器等,大同小異。在這類寄存器中,常用單個英文字母表示其含義。例如,N表示有符號運(yùn)算中結(jié)果為負(fù)(Negative),Z表示結(jié)果為零(Zero),C表示有進(jìn)位(Carry),V表示溢出(Overflow)等。
5.其他功能寄存器
不同的CPU,除了具有數(shù)據(jù)緩沖寄存器、堆棧指針、程序指針寄存器、程序狀態(tài)寄存器(也稱為程序狀態(tài)字寄存器),還有表示浮點(diǎn)數(shù)運(yùn)算、中斷屏蔽[3]等寄存器。
2.1.2 ARM Cortex-M處理器的主要寄存器
ARM Cortex-M處理器的寄存器主要有R0~R15及三個特殊功能寄存器,如圖2-1所示。
其中R0~R12為通用寄存器,R13為堆棧指針(Stack Pointer,SP),R14是連接寄存器,R15為程序計(jì)數(shù)(Program Counter,PC)寄存器(簡稱程序計(jì)算器)。特殊功能寄存器有預(yù)定義的功能,而且必須通過專用的指令來訪問。

圖2-1 ARM Cortex-M處理器的寄存器
1.通用寄存器R0~R12
R0~R12是最具“通用目的”的32位通用寄存器,用于數(shù)據(jù)操作,復(fù)位后初始值為隨機(jī)值。32位的Thumb2[4]指令可以訪問所有通用寄存器,但絕大多數(shù)16位Thumb指令只能訪問R0~R7。因而R0~R7又被稱為低位寄存器,所有指令都能訪問它們。R8~R12被稱為高位寄存器,只有很少的16位Thumb指令能訪問它們,32位的指令則不受限制。在Mbed OS中,R12常用來存放函數(shù)地址。
2.堆棧指針R13(SP)
R13是堆棧指針SP。在ARM Cortex-M處理器中共有兩個堆棧指針:主堆棧指針MSP和進(jìn)程堆棧指針PSP。若用戶用到其中一個,另一個必須用特殊指令(MRS、MSR指令)來訪問,因此任一時刻只能使用其中一個。MSP是CPU復(fù)位后默認(rèn)使用的堆棧指針,它可由操作系統(tǒng)內(nèi)核、中斷服務(wù)程序及所有需要特權(quán)訪問的應(yīng)用程序代碼來使用。PSP用于常規(guī)的應(yīng)用程序代碼(不處于中斷服務(wù)程序中時),該堆棧一般供用戶的應(yīng)用程序代碼使用。需要注意的是,并不是每個應(yīng)用程序都要用到這兩個堆棧指針,簡單的應(yīng)用程序只用MSP就夠了,并且PUSH指令和POP指令默認(rèn)使用MSP(有時MSP直接記為SP)。另外,堆棧指針的最低兩位永遠(yuǎn)是0,即堆棧總是4字節(jié)對齊的。
3.連接寄存器R14(LR)
當(dāng)調(diào)用一個子程序時,由R14存儲返回地址。與其他處理器不同,ARM為了減少訪問內(nèi)存的次數(shù)[5],把返回地址直接放入CPU內(nèi)部寄存器中,這樣足以使很多只有一級子程序調(diào)用[6]的代碼無須訪問內(nèi)存(堆棧空間),從而提高子程序調(diào)用的效率。如果多于一級,那么需要把前一級的R14值壓到堆棧里;在其他情況下,可以將R14作為通用寄存器使用。
4.程序計(jì)數(shù)寄存器R15(PC)
R15是程序計(jì)數(shù)寄存器,其內(nèi)容為將要執(zhí)行指令的地址。如果修改它的值,就能改變程序的執(zhí)行流程(很多高級技巧隱藏其中)。在匯編代碼中也可以使用PC來訪問它,因?yàn)锳RM Cortex-M處理器使用了指令流水線,讀PC時返回的值是當(dāng)前指令的地址+4。ARM Cortex-M處理器中的指令至少是半字對齊的,所以PC的第0位總是0。然而,在使用一些跳轉(zhuǎn)或讀存儲器指令更新PC時,都必須保證新的PC值是奇數(shù)(即第0位為1),用以表明這是在Thumb狀態(tài)下執(zhí)行的,若第0位為0,則被視為企圖轉(zhuǎn)入ARM模式,ARM Cortex-M處理器將觸發(fā)錯誤異常。在理解實(shí)時操作系統(tǒng)運(yùn)行流程時,關(guān)鍵點(diǎn)是要理解PC值是如何變化的,這是因?yàn)镻C值的變化反映了程序的真實(shí)流程。
5.特殊功能寄存器
ARM Cortex-M處理器包括一組特殊功能寄存器,如程序狀態(tài)寄存器(xPSR)、中斷屏蔽寄存器(PRIMASK)和控制寄存器(CONTROL)。
1)程序狀態(tài)寄存器
程序狀態(tài)寄存器(xPSR)在內(nèi)部分為以下幾個子寄存器:APSR、IPSR、EPSR,用戶可以使用MRS和MSR指令訪問程序狀態(tài)寄存器。三個子寄存器既可以單獨(dú)訪問,又可以兩個或三個組合到一起訪問。使用三合一方式訪問時,把該寄存器稱為xPSR,如表2-1所示。
表2-1 ARM Cortex-M處理器的程序狀態(tài)寄存器(xPSR)

(1)應(yīng)用程序狀態(tài)寄存器(Application Program Status Register,APSR):存放算術(shù)運(yùn)算單元(ALU)狀態(tài)位的一些信息。負(fù)標(biāo)志N:若結(jié)果最高位為1,相當(dāng)于有符號運(yùn)算中結(jié)果為負(fù),則置1,否則清0。零標(biāo)志Z:若結(jié)果為0,則置1,否則清0。進(jìn)位標(biāo)志C:若有向最高位進(jìn)位(減法為借位),則置1,否則清0。溢出標(biāo)志V:若溢出,則置1,否則清0。在程序運(yùn)行過程中,這些位會根據(jù)運(yùn)算結(jié)果而改變,在條件轉(zhuǎn)移指令中也可能被用到。復(fù)位之后,這些位是隨機(jī)的。
(2)中斷程序狀態(tài)寄存器(Interrupt Program Status Register,IPSR):該寄存器的D31~D6位為0,D5~D0位存放中斷號(異常號)。每次中斷完成之后,處理器會實(shí)時更新IPSR內(nèi)的中斷號字段,IPSR只能被MRS指令讀寫。進(jìn)程模式下,值為0;Handler模式[7]下,存放當(dāng)前中斷的中斷號。復(fù)位之后,寄存器被自動清0。復(fù)位中斷號是一個暫時值,復(fù)位時是不可見的。
(3)執(zhí)行程序狀態(tài)寄存器(Execution Program Status Register,EPSR):T標(biāo)志位指示當(dāng)前運(yùn)行的是否為Thumb指令,該位是不能被軟件讀取的,運(yùn)行復(fù)位向量對應(yīng)的代碼時置1。如果該位為0,會發(fā)生硬件異常,進(jìn)入硬件中斷服務(wù)程序。
2)中斷屏蔽寄存器
中斷屏蔽寄存器(PRIMASK)的D31~D1位保留,只有D0位(記為PM)有意義,當(dāng)該位被置位時,除不可屏蔽中斷和硬件錯誤之外的所有中斷都被屏蔽。使用特殊指令(如MSR、MRS)可以訪問PRIMASK。除此之外,還有一條稱為改變處理器狀態(tài)的特殊指令CPS也能訪問PRIMASK,只在實(shí)時線程中才會用到。對于可屏蔽中斷,有開、關(guān)總中斷的匯編指令:“CPSIDi”,將D0位置1(關(guān)總中斷);“CPSIEi”,將D0位清0(開總中斷),其中i代表IRQ中斷,IRQ是非內(nèi)核中斷請求(Interrupt Request)的縮寫。由于沒有高級語言相關(guān)語句對應(yīng)這兩條指令,因此在編程中一般采用宏定義的方式來使用。
3)控制寄存器
控制寄存器(CONTROL)的D31~D2位保留,D1、D0位含義如下。
D1(SPSEL)——堆棧指針選擇位。默認(rèn)SPSEL=0,使用MSP為當(dāng)前堆棧指針(復(fù)位后默認(rèn)值);SPSEL=1,在進(jìn)程模式下,使用PSP為當(dāng)前堆棧指針。在特權(quán)、進(jìn)程模式下,軟件可以更新SPSEL位。在Handler模式下,寫該位無效。復(fù)位后,控制寄存器清0。可用MRS指令讀該寄存器,MSR指令寫該寄存器。非特權(quán)訪問無效。
D0(nPRIV)——如果權(quán)限擴(kuò)展,在進(jìn)程模式下定義執(zhí)行特權(quán)。nPRIV=0,進(jìn)程模式下可以特權(quán)訪問;nPRIV=1,進(jìn)程模式下無特權(quán)訪問。在Handler模式下,總是特權(quán)訪問。
- Linux設(shè)備驅(qū)動開發(fā)詳解:基于最新的Linux4.0內(nèi)核
- 全屋互聯(lián):智能家居系統(tǒng)開發(fā)指南
- Windows Server 2019 Cookbook
- Persistence in PHP with the Doctrine ORM
- Docker+Kubernetes應(yīng)用開發(fā)與快速上云
- Kubernetes從入門到實(shí)踐
- 零基礎(chǔ)學(xué)鴻蒙PC:新一代國產(chǎn)操作系統(tǒng)
- Windows Server 2019 Administration Fundamentals
- Linux自動化運(yùn)維:Shell與Ansible(微課版)
- Application Development in iOS 7
- 操作系統(tǒng)分析
- Hands-On UX Design for Developers
- VMware vSphere 5.1 Cookbook
- 操作系統(tǒng)之哲學(xué)原理第2版
- 再也不踩坑的kubernetes實(shí)戰(zhàn)指南