ARM(CPU)內部寄存器學習筆記



本文的具體寄存器描述,以NXP LPC2000系列用到的內核ARM7TDMI-S processor為例,參考 ARM官網

提到ARM內部寄存器,就不得不提到ARM處理器狀態和處理器模式,因為不同狀態和模式下,訪問寄存器的權限是完全不一樣的。

ARM處理器狀態

嵌入式系統對存儲成本和空間要求比較高,為了讓用戶更好控制代碼量,因此設計了2套指令系統:ARM指令集Thumb指令集
ARM指令集:32bit字長,具有完整功能;
Thumb指令集:16bit字長(半字長),能實現ARM指令集絕大部分內容。

  • 二者關系
  1. 功能上,Thumb指令集是ARM指令集的子集。
  2. Thumb指令集具有極高代碼密度,平均縮減30%代碼量。
  • 2種指令集何時執行?
    有2個處理器狀態與這2套指令集對應,而這2種狀態由CPSR寄存器的T字段控制:
CPSR[T] = 0 <=> ARM狀態
CPSR[T] = 1 <=> Thumb狀態
  1. ARM狀態
    32bit,處理器執行ARM指令,處理器上電后默認狀態。

  2. Thumb狀態
    16bit,處理器執行半字方式的Thumb指令。

參見下圖對PSR寄存器(Program Status Register)描述,其中CPSR表示當前程序狀態寄存器(Current Program Status Register):

PS:

  1. 修改CPSR[T](或者說ARM狀態和Thumb狀態切換),並不影響處理器模式和其他寄存器內容;
  2. 不要使用MSR指令讓處理器切換狀態,雖然可以修改T位,但是因為不會清空流水線,所以是不安全的。推薦使用BX指令進行狀態切換;
  • 狀態切換
    BX指令控制處理器狀態切換,程序發生跳轉時,流水線會被清空:流水線中原來處理器狀態取值和譯碼的指令,也會被清除,不會引起處理器錯誤。
; 從ARM狀態 => Thumb狀態
        CODE32                   ; 下面的指令為ARM指令
        LDR R0,=Lable+1          ; R0[bit0]=1, BX自動將CPSR[T]置1
        BX R0                    ; 切換到Thumb狀態, 並跳轉到Lable處執行
        CODE16                   ; 下面的指令為Thumb指令
Lable MOVE R1,#12
; 從Thumb狀態 => ARM狀態
        CODE16                   ; 下面的指令為Thumb指令
        LDR R0,=Lable            ; R0[bit0]=0, BX自動將CPSR[T]置0
        BX R0                    ; 切換到ARM狀態, 並跳轉到Lable處執行
        CODE32                   ; 下面的指令為ARM指令
Lable MOV R1,#10

處理器模式

ARM處理器支持7種處理器模式,以CPSR_M[4:0]控制位反應處理器正在操作的模式。除用戶(user, usr)模式外,其他6種稱為特權(privileged)模式,分為2類,分別是:系統(system,sys)模式和異常模式,
其中,異常模式又包括5種模式: 管理(supervisor,svc)模式、中止(abort,abt)模式、未定義(undefined,und)模式、中斷(interrupt request,irq)模式、快速中斷(fast interrupt request,fiq)模式。

ARM處理器7種模式:

CPSR_M[4:0]表示當前處理器模式:

注:

  1. nM[4:0]是M[4:0]的反轉,nM[4:0]信號僅用於診斷和調試;
  2. 只有在特權模式下,才允許對CPSR進行讀寫。這也是為什么不能直接通過修改CPSR[T],以控制處理器狀態切換,而是需要一個流程的原因。

異常模式

異常模式

管理模式,中止模式,未定義模式,中斷模式,快速中斷模式 這5種處理器模式統稱異常模式。

每種異常都和一種處理器模式相對應,一旦應用程序發生特定異常中斷時,處理器進入相應的異常模式,內核立即跳轉到向量表中的某個入口地址,執行相應的處理程序。同時,每種異常模式都有與之對應的寄存器,供相應的異常處理程序用,用來確保處理器進入異常模式時,用戶模式下的寄存器不會被破壞。

  • 什么時候進入異常模式?規定:
  1. 處理器復位后進入管理模式,操作系統內核通常處於該模式;
  2. 當處理器訪問存儲器失敗時,進入數據訪問中止模式;
  3. 當處理器遇到不支持的指令時,進入未定義模式;
  4. 中斷模式與快速中斷模式分別對ARM處理器兩種不同級別的中斷做出響應;
  • 系統模式切換到異常模式

例,切換到管理模式(svc)

MSR CPSR_c, #(NoInt | SVC32Mode) // 相當於 CPSR_c = (NoInt | SVC32Mode) => I = 1, F = 1, M[4:0] = 0b10011(Supervisor)

MSR指令通常用於恢復或改變PSR內容;
CPSR_c 表示CPSR的控制域掩碼,而控制域指CSPR[7..0](control bits:I, F, T, M[4..0]);
SVC32Mode 指的管理模式;

CPSR_c,CPSR_f,CPSR_s,CPSR_x含義:

Tips:MSR(寫)和MRS(讀)指令
MRS指令:專門用於對狀態寄存器CPSR和SPSR(Saved PSR)進行讀操作。通過讀取CSPR,可以獲得當前處理器的工作狀態。通過讀取SPSR,可以獲得處理器進入異常前的處理器狀態(因為只有異常模式才有SPSR);
MSR指令:專門用於對狀態寄存器CPSR和SPSR進行寫操作。跟MRS配合,可以實現對CPSR/SPSR的讀寫操作,以切換處理器模式、允許或禁止IRQ(IRQ disable)和FIQ(FIQ disable)中斷等功能;

關於MRS和MSR更詳細內容,可參見這篇文章匯編指令-MRS(讀)和MSR(寫)指令操作CPSR寄存器和SPSR寄存器使用(1) | 博客園

系統模式 System,Sys

用戶模式

用戶模式是程序正常運行的工作模式。

系統模式與用戶模式
系統模式具有跟用戶模式完全系統的寄存器,不過系統模式有特權,可以訪問所有系統資源,也可以直接進行處理器模式切換。主要供OS的任務使用,當然也允許對CPSR讀寫。
系統模式下,OS可以訪問所有用戶模式下相應的寄存器,而不是使用異常模式下相應的寄存器,這樣可以保證當異常中斷發生時,任務的狀態不被破壞。

系統模式與異常模式
系統模式、用戶模式都不能由異常進入。要進入系統模式,必須通過修改CPSR實現。

例,從管理模式切換到系統模式

MSR CPSR_c, #(NoInt | SYS32Mode) // 從管理模式切換到系統模式 => I = 1, F = 1, M[4:0] = 0b1111(Mode = System)

ARM內部寄存器

ARM處理器內部共有37個用戶可訪問32bit寄存器,分別是:

  • 31個通用寄存器
    R0~R15, R13_svc, R14_svc, R13_abt, R14_abt, R13_und, R14_und, R13_irq, R14_irq, R8_fiq, R9_fiq, R10_fiq, R11_fiq, R12_fiq, R13_fiq, R14_fiq

  • 6個狀態寄存器(每個只使用其中12bit)
    CPSR, SPSR_svc, SPSR_abt, SPSR_und, SPSR_irq, SPSR_fiq

處理器有7種不同的處理器模式,每種模式都有一組相應的寄存器組,對應不同的后綴名,如R13_svc對應svc模式(管理模式)。
PS:

  1. 每種模式擁有的一組寄存器不相同,並非上面描述的全部;
  2. 這些寄存器不能同時訪問,何時訪問取決於處理器狀態和處理器模式。

ARM狀態和Thumb狀態下的寄存器訪問

可以看到,ARM狀態和Thumb狀態下,程序員能訪問的寄存器是不一樣的。
特別地,在ARM狀態下,特殊用途寄存器R13(堆棧指針SP),R14(鏈接寄存器LR),R15(程序計數器PC),盡管可以當做通用寄存器使用,但是編譯器通常認為R13始終指向一個有效的堆棧結構,所以一定要注意將R13當做通用寄存器來使用是非常危險的。

ARM狀態下,各種模式下能訪問的通用寄存器和PC(程序計數器)

Thumb狀態下,各種模式下能訪問的通用寄存器和PC(程序計數器)


一般通用寄存器

R0~R7 保存數據或地址值,任何處理器模式下通用,都是同一個32bit物理寄存器。

PS:由用戶模式進入中斷模式后,可能造成寄存器的數據丟失,因此應該先對重要數據進行備份。

R8~R14 所對應的物理寄存器取決於當前的處理器模式,幾乎所有允許使用通用寄存器的指令都允許使用R8~R14。具體參見上面圖“各種模式下能訪問的通用寄存器和PC(程序計數器)”。

不同模式下的寄存器

CSPR的位域M[4:0]控制不同的處理器模式。下圖展示了不同模式下、不同狀態下各寄存器的可見性:


堆棧指針R13(SP)

堆棧的概念
堆棧實際是指“堆”和“棧” 2個不同概念,但為了符合表達習慣,沒有特別指出僅表示“棧”。
堆棧是指

在內存中划分出一段存儲空間,這個存儲空間就像是一個大的數據倉庫,用於暫時保存一些數據。

堆棧操作通常發生在子程序調用、異常發生、程序運行過程中寄存器數量不夠時。

  • 程序調用、異常發生: 通常把子程序或異常服務程序將要用到的寄存器內容,保存到堆棧中,子程序或異常服務程序返回時再恢復,以確保原有程序不被破壞。
  • 程序運行過程中寄存器數量不夠:如果程序運行過程中,局部變量太多,以至於處理器內部的寄存器無法全部裝下,程序員或編譯器會使用堆棧來作為數據的暫存空間,將暫未用到的數據壓棧,需要用到時再出棧。

鏈接寄存器R14(LR)

ARM狀態下,子程序返回地址將自動放入到R14中。每種異常模式都有專用的R14寄存器,用於保存子程序返回地址,分別是R14_svc,R14_abt,R14_und,R14_irq,R14_fiq。
Thumb狀態下,LR會自動鏈接到ARM狀態R14。

R14有2種特殊功能:

  1. 使用BL指令調用子程序時,返回地址將自動存入R14中。在子程序結束時,將R14復制到PC即可實現子程序的返回。。
  • 通常有2種方式實現子程序的返回:
// 方式一
MOV PC,LR
// 方式二
BX LR

ARM7TDMI Technical Reference Manual 也提到異常服務程序的進入和退出


注意:異常不同於普通子程序調用,普通子程序調用一般是可預見的,由程序員設置;異常是不可預料的,一般由硬件或OS內核觸發。

  • 子程序入口,用寄存器寫指令STMFD保存R14和其他寄存器內容到SP
STMFD SP!,{<register>,LR}

//具體地,如果是保存R0~R7及LR(進棧)
STMFD SP!,{R0-R7,LR} 
//其含義是:
// SP指針變化
SP = SP - 9x4 //R0~7 + LR,共9個寄存器,而SP默認在高地址位置,往低地址方向移動
address = SP
// 寄存器賦值給內存地址的賦值過程
for i = 0 to 7
  memory[address] = Ri
  address = address + 4
memory[address] = LR
  • 子程序結束,用批量寄存器讀取指令LDMFD
    LDMFD是STMFD逆過程,即出棧的過程。
LDMFD SP!,[<registers>,PC]

// 具體地,將棧內容恢復至PC及R7~R0
LDMFD SP!,[R0-R7,PC]

  1. 當發生異常中斷時,應注意保證異常處理程序不會破壞LR,因為LR保存了程序返回地址。異常處理程序返回后,LR內容會寫入PC,同時從SPSR中恢復SPSR來實現。

也就是說,除了子程序(包括異常處理程序)調用時、返回時,其他任何時候,R14可以作為一個通用寄存器。

程序計數器R15(PC)

R15保存程序寄存器PC,R15總是指向正在“取指”的指令。

1. 讀R15
ARM指令集是字對齊的,PC保存下一條指令的地址也應該是4的倍數,因此PC[1:0]總是為0。
Thumb指令集半字對齊,PC保存的地址是2的倍數,因此PC[0]總是0。

盡量避免使用STR、STM指令來保存R15,因為不同的芯片使用STR或STM保存R15時,保存的可能是 當前指令地址 + 8byte 或 + 12byte。該偏移,針對具體的芯片是一個常量。

2. 寫R15
當執行一條寫R15的指令時,寫入R15的正常結果值被當成一個指令地址,程序從地址處繼續執行,相當於執行一次無條件跳轉。
ARM狀態下,指令字對齊,寫入R15值bit[1:0]必須是0b00,否則結果不可預測;
Thumb狀態下,指令半字對齊,寫入R15時將忽略bit[0]。

當前程序狀態寄存器CPSR

ARM core包含1個CPSR + 5個異常用的SPSR。每種異常模式都有一個對應的SPSR,用於保存異常發生前的CPSR值。CPSR和SPSR都可以用特殊指令MSR、MRS訪問(見上文)。

CPSR與SPSR

所有模式共享一個CPSR(程序狀態寄存器),ARM core通過使用CPSR監視控制內部操作。
異常模式下,允許訪問用於保存CPSR當前值的 SPSR(備份程序狀態寄存器),不過每種異常都有相應的SPSR共5個,分別是:SPSR_svc(管理), SPSR_abt(中止), SPSR_und(未定義), SPSR_irq(中斷), SPSR_fiq(快速中斷)。

CPSR和SPSR在不同模式下對應寄存器,見下圖:

注:為什么用戶模式和系統模式沒有SPSR?
因為用戶模式和系統模式不是異常中斷,因此沒有SPSR。因而在用戶模式和系統模式下,不能訪問SPSR,否則可能產生不可預知結果。

CPSR格式

條件代碼標志

條件代碼標志(Condition code flags)包括N, Z, C, V位,可以通過算術運算和邏輯操作設置,也可以通過MSR和LDM指令設置。ARM7TDMI處理器測試這些標志位,以決定是否執行一條指令,這樣。
一般地,如果指令帶后綴S,表明指令會修改條件代碼標志。不過也有些指令總是改變條件代碼標志。

各標志位含義:

  1. 負標志N 運算結果的第31位值,記錄標志設置操作的結果;
  2. 零標志Z 如果標志設置操作的結果為0,則置位;
  3. 進位標志C 記錄無符號加法溢出,減法無借位,循環移位;
  4. 溢出標志V 記錄標志設置操作的有符號溢出;
    ARM狀態中,所有指令都可以按條件來執行;Thumb狀態中,只有分支指令可按條件執行。詳見ARM Architecture Reference Manual (conditional execution)

控制標志位

控制標志位(Control bits)包括I, F, T, M4 ~ M0。

  1. I 中斷(IRQ)禁止位;
  2. F 快速中斷(FIQ)禁止位;
  3. T 狀態位;
  4. M4~M0 處理器模式位;
    發生異常時,控制位改變。特權模式下,可用軟件操作這些位。

中斷禁止標志位I和快速中斷禁止標志位F
中斷(IRQ)和快速中斷(FIQ)是ARM的2個不同模式,本質上來說都是中斷,不過FIQ優先級更高,而且FIQ的響應時間也比IRQ更快。發生中斷時,FIQ可以插隊,如果支持嵌套中斷,FIQ可以打斷當前正在執行的IRQ處理程序。

為什么FIQ比IRQ快?
因為,

  1. FIQ優先級比IRQ更高;
  2. FIQ有自己獨有的寄存器(R8~R14,SPSR等),IRQ需要和其他模式共用寄存器,中斷現場的保護和恢復會更快;
  3. FIQ在異常向量表的末尾,FIQ中斷處理程序緊接着存放,可以直接執行。而異常向量表只能保存IRQ的首地址,發生中斷時,進入IRQ中斷處理程序需要一次跳轉;

詳細可參見ARM中FIQ(快速中斷)比IRQ(普通中斷)響應快的原因

中斷禁止標志位:

  • I為1時,IRQ中斷禁止;為0時,IRQ中斷使能;
  • F為1時,FIQ中斷禁止;為0時,FIQ中斷使能;

控制位T
控制位T反應處理器正處於的狀態:

  • T為1時,處理器處於Thumb狀態;
  • T為0時,處理器處於ARM狀態;

模式控制位M[4:0]
見下圖

保留位
CPSR保留位被保留,以便將來使用。當改變CPSR標志位和控制位時,請確認沒有改變這些保留位,否則可能會導致未定義行為。


參考

[1]周立功, 王祖麟, 陳明計, 嚴寒亮,等. ARM嵌入式系統基礎教程[M]. 北京航空航天大學出版社, 2008.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM