加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
    • 3.4  異常中斷處理
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

ARM微處理器的編程模型之:異常中斷處理

2013/09/13
1
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

?

3.4? 異常中斷處理

異?;蛑袛嗍怯脩舫绦蛑凶罨镜囊环N執(zhí)行流程和形態(tài)。這部分主要對(duì)ARM架構(gòu)下的異常中斷做詳細(xì)說(shuō)明。

ARM有7種類型的異常,按優(yōu)先級(jí)從高到低的排列如下:復(fù)位異常(Reset)、數(shù)據(jù)異常(Data Abort)、快速中斷異常(FIQ)、外部中斷異常(IRQ)、預(yù)取異常(Prefetch Abort)、軟件中斷(SWI)和未定義指令異常(Undefined instruction)。

注意

在ARM文檔中,使用術(shù)語(yǔ)Exception來(lái)描述異常。Exception主要是從處理器被動(dòng)接受異常的角度出發(fā),而Interrupt帶有向處理器主動(dòng)申請(qǐng)的色彩。在本書中,對(duì)“異?!焙汀爸袛唷辈蛔鰢?yán)格區(qū)分,兩者都是指請(qǐng)求處理器打斷正常的程序執(zhí)行流程,進(jìn)入特定程序循環(huán)的一種機(jī)制。

3.4.1? 異常種類

ARM體系結(jié)構(gòu)中,存在7種異常處理。當(dāng)異常發(fā)生時(shí),處理器會(huì)把PC設(shè)置為一個(gè)特定的存儲(chǔ)器地址。這一地址放在被稱為向量表(vector table)的特定地址范圍內(nèi)。向量表的入口是一些跳轉(zhuǎn)指令,跳轉(zhuǎn)到專門處理某個(gè)異?;蛑袛嗟?a class="article-link" target="_blank" href="/baike/499965.html">子程序。

存儲(chǔ)器映射地址0x00000000是為向量表(一組32位字)保留的。在有些處理器中,向量表可以選擇定位在存儲(chǔ)空間的高地址(從偏移量0xffff0000開始)。一些嵌入式操作系統(tǒng),如Linux和Windows CE就要利用這一特性。

表3.4列出了ARM的7種異常。

表3.4? ARM的7種異常

異 常 類 型

處理器模式

執(zhí)行低地址

執(zhí)行高地址

復(fù)位異常(Reset)

特權(quán)模式

0x00000000

0xFFFF0000

未定義指令異常(Undefined interrupt)

未定義指令中止模式

0x00000004

0xFFFF0004

軟中斷異常(Software Abort)

特權(quán)模式

0x00000008

0xFFFF0008

預(yù)取異常(Prefetch Abort)

數(shù)據(jù)訪問中止模式

0x0000000C

0xFFFF000C

數(shù)據(jù)異常(Data Abort)

數(shù)據(jù)訪問中止模式

0x00000010

0xFFFF0010

外部中斷請(qǐng)求IRQ

外部中斷請(qǐng)求模式

0x00000018

0xFFFF0018

快速中斷請(qǐng)求FIQ

快速中斷請(qǐng)求模式

0x0000001C

0xFFFF001C

異常處理向量表如圖3.5所示。

當(dāng)異常發(fā)生時(shí),分組寄存器r14和SPSR用于保存處理器狀態(tài),操作偽指令如下。

R14_<exception_mode> = return link

SPSR_<exception_mode> = CPSR

CPSR[4∶0] = exception mode number

CPSR[5] = 0?? /*進(jìn)入ARM狀態(tài)*/

If <exception_mode> = = reset or FIQ then

??? CPSR[6] = 1????????????????? /*屏蔽快速中斷FIQ*/

??? CPSR[7] = 1????????????????? /*屏蔽外部中斷IRQ*/

??? PC = exception vector address

圖3.5? 異常處理向量表

異常返回時(shí),SPSR內(nèi)容恢復(fù)到CPSR,連接寄存器r14的內(nèi)容恢復(fù)到程序計(jì)數(shù)器PC。

1.復(fù)位異常

當(dāng)處理器的復(fù)位引腳有效時(shí),系統(tǒng)產(chǎn)生復(fù)位異常中斷,程序跳轉(zhuǎn)到復(fù)位異常中斷處理程序處執(zhí)行。復(fù)位異常中斷通常用在下面兩種情況下。

·? 系統(tǒng)上電。

·? 系統(tǒng)復(fù)位。

當(dāng)復(fù)位異常時(shí),系統(tǒng)執(zhí)行下列偽操作。

R14_svc = UNPREDICTABLE value

SPSR_svc = UNPREDICTABLE value

CPSR[4∶0] = 0b10011????????? /*進(jìn)入特權(quán)模式*/

CPSR[5] = 0????????????????? /*處理器進(jìn)入ARM狀態(tài)*/

CPSR[6] = 1????????????????? /*禁止快速中斷*/

CPSR[7] = 1????????????????? /*禁止外設(shè)中斷*/

If high vectors configured then

??? PC = 0xffff0000

Else

??? PC = 0x00000000

?

復(fù)位異常中斷處理程序?qū)⑦M(jìn)行一些初始化工作,內(nèi)容與具體系統(tǒng)相關(guān)。下面是復(fù)位異常中斷處理程序的主要功能。

·? 設(shè)置異常中斷向量表。

·? 初始化數(shù)據(jù)棧和寄存器。

·? 初始化存儲(chǔ)系統(tǒng),如系統(tǒng)中的MMU等。

·? 初始化關(guān)鍵的I/O設(shè)備。

·? 使能中斷。

·? 處理器切換到合適的模式。

·? 初始化C變量,跳轉(zhuǎn)到應(yīng)用程序執(zhí)行。

2.未定義指令異常

當(dāng)ARM處理器執(zhí)行協(xié)處理器指令時(shí),它必須等待一個(gè)外部協(xié)處理器應(yīng)答后,才能真正執(zhí)行這條指令。若協(xié)處理器沒有相應(yīng),則發(fā)生未定義指令異常。

未定義指令異常可用于在沒有物理協(xié)處理器的系統(tǒng)上,對(duì)協(xié)處理器進(jìn)行軟件仿真,或通過(guò)軟件仿真實(shí)現(xiàn)指令集擴(kuò)展。例如,在一個(gè)不包含浮點(diǎn)運(yùn)算的系統(tǒng)中,CPU遇到浮點(diǎn)運(yùn)算指令時(shí),將發(fā)生未定義指令異常中斷,在該未定義指令異常中斷的處理程序中可以通過(guò)其他指令序列仿真浮點(diǎn)運(yùn)算指令。

仿真功能可以通過(guò)下面步驟實(shí)現(xiàn)。

① 將仿真程序入口地址鏈接到向量表中未定義指令異常中斷入口處(0x00000004或0xffff0004),并保存原來(lái)的中斷處理程序。

② 讀取該未定義指令的bits[27∶24],判斷其是否是一條協(xié)處理器指令。如果bits[27∶24]值為0b1110或0b110x,該指令是一條協(xié)處理器指令;否則,由軟件仿真實(shí)現(xiàn)協(xié)處理器功能,可以同過(guò)bits[11∶8]來(lái)判斷要仿真的協(xié)處理器功能(類似于SWI異常實(shí)現(xiàn)機(jī)制)。

③ 如果不仿真該未定義指令,程序跳轉(zhuǎn)到原來(lái)的未定義指令異常中斷的中斷處理程序執(zhí)行。

當(dāng)未定義異常發(fā)生時(shí),系統(tǒng)執(zhí)行下列的偽操作。

r14_und = address of next instruction after the undefined instruction

SPSR_und = CPSR

CPSR[4∶0] = 0b11011?????????????? /*進(jìn)入未定義指令模式*/

CPSR[5] = 0????????????????????? /*處理器進(jìn)入ARM狀態(tài)*/

/*CPSR[6]保持不變*/

CPSR[7] = 1????????????????????? /*禁止外設(shè)中斷*/

If? high vectors configured then

????? PC = 0xffff0004

Else

????? PC = 0x00000004

3.軟中斷SWI

軟中斷異常發(fā)生時(shí),處理器進(jìn)入特權(quán)模式,執(zhí)行一些特權(quán)模式下的操作系統(tǒng)功能。軟中斷異常發(fā)生時(shí),處理器執(zhí)行下列偽操作。

r14_svc = address of next instruction after the SWI instruction

SPSR_und = CPSR

CPSR[4∶0] = 0b10011????????????? /*進(jìn)入特權(quán)模式*/

CPSR[5] = 0???????????????????? /*處理器進(jìn)入ARM狀態(tài)*/

/*CPSR[6]保持不變*/

CPSR[7] = 1???????????????????? /*禁止外設(shè)中斷*/

If? high vectors configured then

????? PC = 0xffff0008

Else

????? PC = 0x00000008

4.預(yù)取指令異常

預(yù)取指令異常使由系統(tǒng)存儲(chǔ)器報(bào)告的。當(dāng)處理器試圖去取一條被標(biāo)記為預(yù)取無(wú)效的指令時(shí),發(fā)生預(yù)取異常。

如果系統(tǒng)中不包含MMU時(shí),指令預(yù)取異常中斷處理程序只是簡(jiǎn)單地報(bào)告錯(cuò)誤并退出。若包含MMU,引起異常的指令的物理地址被存儲(chǔ)到內(nèi)存中。

預(yù)取異常發(fā)生時(shí),處理器執(zhí)行下列偽操作。

r14_svc = address of the aborted instruction + 4

SPSR_und = CPSR

CPSR[4∶0] = 0b10111?????????????? /*進(jìn)入特權(quán)模式*/

CPSR[5] = 0????????????????????? /*處理器進(jìn)入ARM狀態(tài)*/

/*CPSR[6]保持不變*/

CPSR[7] = 1????????????????????? /*禁止外設(shè)中斷*/

If? high vectors configured then

???? PC = 0xffff000C

Else

???? PC = 0x0000000C

5.?dāng)?shù)據(jù)訪問中止異常

數(shù)據(jù)訪問中止異常是由存儲(chǔ)器發(fā)出數(shù)據(jù)中止信號(hào),它由存儲(chǔ)器訪問指令Load/Store產(chǎn)生。當(dāng)數(shù)據(jù)訪問指令的目標(biāo)地址不存在或者該地址不允許當(dāng)前指令訪問時(shí),處理器產(chǎn)生數(shù)據(jù)訪問中止異常。

當(dāng)數(shù)據(jù)訪問中止異常發(fā)生時(shí),處理器執(zhí)行下列偽操作。

r14_abt = address of the aborted instruction + 8

SPSR_abt = CPSR

CPSR[4∶0] = 0b10111

CPSR[5] = 0

/*CPSR[6]保持不變*/

CPSR[7] = 1????????????? /*禁止外設(shè)中斷*/

If? high vectors configured then

???? PC = 0xffff000C10

Else

???? PC = 0x00000010

?

當(dāng)數(shù)據(jù)訪問中止異常發(fā)生時(shí),寄存器的值將根據(jù)以下規(guī)則進(jìn)行修改。

① 返回地址寄存器r14的值只與發(fā)生數(shù)據(jù)異常的指令地址有關(guān),與PC值無(wú)關(guān)。

② 如果指令中沒有指定基址寄存器回寫,則基址寄存器的值不變。

③ 如果指令中指定了基址寄存器回寫,則寄存器的值和具體芯片的Abort Models有關(guān),由芯片的生產(chǎn)商指定。

④ 如果指令只加載一個(gè)通用寄存器的值,則通用寄存器的值不變。

⑤ 如果是批量加載指令,則寄存器中的值是不可預(yù)知的值。

⑥ 如果指令加載協(xié)處理器寄存器的值,則被加載寄存器的值不可預(yù)知。

6.外部中斷IRQ

當(dāng)處理器的外部中斷請(qǐng)求引腳有效,而且CPSR寄存器的I控制位被清除時(shí),處理器產(chǎn)生外部中斷IRQ異常。系統(tǒng)中各外部設(shè)備通常通過(guò)該異常中斷請(qǐng)求處理器服務(wù)。

當(dāng)外部中斷IRQ發(fā)生時(shí),處理器執(zhí)行下列偽操作。

r14_irq = address of next instruction to be executed + 4

SPSR_irq = CPSR

CPSR[4∶0] = 0b10010????????????? /*進(jìn)入特權(quán)模式*/

CPSR[5] = 0???????????????????? /*處理器進(jìn)入ARM狀態(tài)*/

/*CPSR[6]保持不變*/

CPSR[7] = 1???????????????????? /*禁止外設(shè)中斷*/

If? high vectors configured then

???? PC = 0xffff0018

Else

???? PC = 0x00000018

7.快速中斷FIQ

當(dāng)處理器的快速中斷請(qǐng)求引腳有效且CPSR寄存器的F控制位被清除時(shí),處理器產(chǎn)生快速中斷請(qǐng)求FIQ異常。

當(dāng)快速中斷異常發(fā)生時(shí),處理器執(zhí)行下列偽操作。

r14_fiq = address of next instruction to be executed + 4

SPSR_fiq = CPSR

CPSR[4∶0] = 0b10001????????? /*進(jìn)入FIQ模式*/

CPSR[5] = 0

CPSR[6] = 1

CPSR[7] = 1

If? high vectors configured then

???? PC= 0xffff001c

Else

???? PC = 0x0000001c

3.4.2? 異常優(yōu)先級(jí)

每一種異常按表3.5中設(shè)置的優(yōu)先級(jí)得到處理。

表3.5???? 異常優(yōu)先級(jí)

優(yōu)? 先? 級(jí)

異??? 常

最高????????? 1

復(fù)位異常

????????????? 2

數(shù)據(jù)中止

????????????? 3

快速中斷請(qǐng)求

????????????? 4

中斷請(qǐng)求

????????????? 5

預(yù)取指令異常

????????????? 6

軟件中斷

最低????????? 7

未定義指令

異常可以同時(shí)發(fā)生,處理器按表3.5的優(yōu)先級(jí)順序處理異常。例如,復(fù)位異常的優(yōu)先級(jí)最高,處理器上電時(shí)發(fā)生復(fù)位異常。所以當(dāng)產(chǎn)生復(fù)位時(shí),它將優(yōu)先于其他異常得到處理。同樣,當(dāng)一個(gè)數(shù)據(jù)訪問中止異常發(fā)生時(shí),它將優(yōu)先于除復(fù)位異常外的其他所有異常。

優(yōu)先級(jí)最低的2種異常是軟件中斷和未定義指令異常。因?yàn)檎趫?zhí)行的指令不可能既是一條SWI指令,又是一條未定義指令,所以軟件中斷異常SWI和未定義指令異享有相同的優(yōu)先級(jí)。

3.4.3? 處理器模式和異常

每一種異常都會(huì)導(dǎo)致內(nèi)核進(jìn)入一種特定的模式。表3.6顯示了ARM處理器異常及其對(duì)應(yīng)的模式。此外,也可以通過(guò)編程改變CPSR,進(jìn)入任何一種ARM處理器模式。

注意

用戶和系統(tǒng)模式是僅有的不可通過(guò)異常進(jìn)入的兩種模式,也就是說(shuō),要進(jìn)入這兩種模式,必須通過(guò)編程改變CPSR。

表3.6? ARM處理器異常及其對(duì)應(yīng)模式

異??? 常

模??? 式

用??? 途

快速中斷請(qǐng)求

FIQ

進(jìn)行快速中斷請(qǐng)求處理

外部中斷請(qǐng)求

IRQ

進(jìn)行外部中斷請(qǐng)求處理

SWI

SVC

進(jìn)行操作系統(tǒng)的高級(jí)處理

復(fù)位

SVC

進(jìn)行操作系統(tǒng)的高級(jí)處理

預(yù)取指令中止異常

ABORT

虛存和存儲(chǔ)器保護(hù)

數(shù)據(jù)中止異常

ABORT

虛存和存儲(chǔ)器保護(hù)

未定義指令

Undefined

軟件模擬硬件協(xié)處理器

?

3.4.4? 異常響應(yīng)流程

1.判斷處理器狀態(tài)

當(dāng)異常發(fā)生時(shí),處理器自動(dòng)切換到ARM狀態(tài),所以在異常處理函數(shù)中要判斷在異常發(fā)生前處理器是ARM狀態(tài)還是Thumb狀態(tài)。這可以通過(guò)檢測(cè)SPSR的T位來(lái)判斷。

通常情況下,只有在SWI處理函數(shù)中才需要知道異常發(fā)生前處理器的狀態(tài)。所以在Thumb狀態(tài)下,調(diào)用SWI軟中斷異常必須注意以下兩點(diǎn)。

① 發(fā)生異常的指令地址為(lr-2)而不是(lr-4)。

② Thumb狀態(tài)下的指令是16位的,在判斷中斷向量號(hào)時(shí)使用半字加載指令LDRH。

下面的例子顯示了一個(gè)標(biāo)準(zhǔn)的SWI處理函數(shù),在函數(shù)中通過(guò)SPSR的T位判斷異常發(fā)生前的處理器狀態(tài)。

T_bit EQU 0x20??????????????? ; bit 5. SPSR中的ARM/Thumb狀態(tài)位,

:

:

SWIHandler

STMFD sp!, {r0-r3,r12,lr}????? ; 寄存器壓棧,保護(hù)程序現(xiàn)場(chǎng)

MRS r0, spsr???????????????? ; 讀SPSR寄存器,判斷異常發(fā)生前的處理器狀態(tài)

TST r0, #T_bit??????????????? ; 檢測(cè)SPSR的T位,判斷異常發(fā)生前是否為Thumb狀態(tài)

LDRNEH r0,[lr,#-2]??????????? ; 如果是Thumb狀態(tài),使用半字加載指令讀取發(fā)生異常的指令地址

BICNE r0,r0,#0xFF00?????????? ; .提取中斷向量號(hào).

LDREQ r0,[lr,#-4]???????????? ; 如果是ARM狀態(tài),使用字加載指令,讀取發(fā)生異常的指令地址

BICEQ r0,r0,#0xFF000000??????? ; 提取中斷向量號(hào)并將中斷向量號(hào)存入r0

; r0 存儲(chǔ)中斷向量號(hào)

CMP r0, #MaxSWI?????????????? ; 判斷中斷是否超出范圍

LDRLS pc, [pc, r0, LSL#2]????? ; 如果未超出范圍,跳轉(zhuǎn)到軟中斷向量表Switable

B SWIOutOfRange?????????????? ; 如果超出范圍,跳轉(zhuǎn)到軟中斷越界處理程序

switable

DCD do_swi_1

DCD do_swi_2

:

:

do_swi_1

; 1號(hào)軟中斷處理函數(shù)

LDMFD sp!, {r0-r3,r12,pc}^ ; Restore the registers and return.

????????????????????????? ; 恢復(fù)寄存器并返回

do_swi_2 ??????????????? ?? ; 2號(hào)軟中斷處理函數(shù)

:

2.向量表

如前面介紹向量表時(shí)提到的,每一個(gè)異常發(fā)生時(shí)總是從異常向量表開始跳轉(zhuǎn)。最簡(jiǎn)單的一種情況是向量表里面的每一條指令直接跳向?qū)?yīng)的異常處理函數(shù)。其中快速中斷處理函數(shù)FIQ_handler()可以直接從地址0x1C處開始,省下一條跳轉(zhuǎn)指令,如圖3.6所示。

圖3.6? 異常處理向量表

但跳轉(zhuǎn)指令B的跳轉(zhuǎn)范圍為±32MB,但很多情況下不能保證所有的異常處理函數(shù)都定位在向量的32MB范圍內(nèi),需要更大范圍的跳轉(zhuǎn),而且由于向量表空間的限制,只能由一條指令完成。具體實(shí)現(xiàn)方法有下面兩種。

(1)MOV? PC,#imme_value

這種辦法將目標(biāo)地址直接賦值給PC。但這種方法受格式限制不能處理任意立即數(shù)。這個(gè)立即數(shù)由一個(gè)8位數(shù)值循環(huán)右移偶數(shù)位得到。

(2)LDR? PC,[PC+offset]

把目標(biāo)地址先存儲(chǔ)在某一個(gè)合適的地址空間,然后把這個(gè)存儲(chǔ)器單元的32位數(shù)據(jù)傳送給PC來(lái)實(shí)現(xiàn)跳轉(zhuǎn)。

這種方法對(duì)目標(biāo)地址值沒有要求。但是存儲(chǔ)目標(biāo)地址的存儲(chǔ)器單元必須在當(dāng)前指令的±4KB空間范圍內(nèi)。

注意

在計(jì)算指令中引用offset數(shù)值的時(shí)候,要考慮處理器流水線中指令預(yù)取對(duì)PC值的影響。

?

3.4.5? 從異常處理程序中返回

當(dāng)一個(gè)異常處理返回時(shí),一共有3件事情需要處理:通用寄存器的恢復(fù)、狀態(tài)寄存器的恢復(fù)以及PC指針的恢復(fù)。通用寄存器的恢復(fù)采用一般的堆棧操作指令即可,下面重點(diǎn)介紹狀態(tài)寄存器的恢復(fù)以及PC指針的恢復(fù)。

1.恢復(fù)被中斷程序的處理器狀態(tài)

PC和CPSR的恢復(fù)可以通過(guò)一條指令來(lái)實(shí)現(xiàn),下面是3個(gè)例子。

·? MOVS? PC,LR

·? SUBS? PC,LR,#4

·? LDMFD? SP!,{PC}^

這幾條指令是普通的數(shù)據(jù)處理指令,特殊之處在于它們把程序計(jì)數(shù)器寄存器PC作為目標(biāo)寄存器,并且?guī)Я颂厥獾暮缶Y“S”或“^”。其中“S”或“^”的作用就是使指令在執(zhí)行時(shí),同時(shí)完成從SPSR到CPSR的拷貝,達(dá)到恢復(fù)狀態(tài)寄存器的目的。

2.異常的返回地址

異常返回時(shí),另一個(gè)非常重要的問題就是返回地址的確定。前面提到過(guò),處理器進(jìn)入異常時(shí)會(huì)有一個(gè)保存LR的動(dòng)作,但是該保持值并不一定是正確中斷的返回地址。以一個(gè)簡(jiǎn)單的指令執(zhí)行流水狀態(tài)圖來(lái)對(duì)此加以說(shuō)明,如圖3.7所示。

圖3.7 ?3級(jí)流水線示例

在ARM架構(gòu)里,PC值指向當(dāng)前執(zhí)行指令地址加8。也就是說(shuō),當(dāng)執(zhí)行指令A(yù)(地址0x8000)時(shí),PC等于0x8000+8=0x8008,即等于指令C的地址。假設(shè)指令A(yù)是BL指令,則當(dāng)執(zhí)行時(shí),會(huì)把PC值(0x8008)保存到LR寄存器。但是,接下來(lái)處理器會(huì)對(duì)LR進(jìn)行一次自動(dòng)調(diào)整,使LR=LR-0x4。所以,最終保存在LR里面的是圖3.5中所示的B指令地址。所以當(dāng)從BL返回時(shí),LR里面正好是正確的返回地址。

同樣的跳轉(zhuǎn)機(jī)制在所有的LR自動(dòng)保存操作中都存在。當(dāng)進(jìn)入中斷響應(yīng)時(shí),處理器對(duì)保存的LR也進(jìn)行一次自動(dòng)調(diào)整,并且跳轉(zhuǎn)動(dòng)作也是LR=LR-0x04。由此,就可以對(duì)不同異常類型的返回地址依次比較。

假設(shè)在指令B處(地址0x8004)發(fā)生了異常,進(jìn)入異常相應(yīng)后,LR經(jīng)過(guò)跳轉(zhuǎn)保存的地址值應(yīng)該是C的地址0x8008。

(1)軟中斷異常

如果發(fā)生軟中斷異常,即指令B為SWI指令,從SWI中斷返回后下一條執(zhí)行指令就是C,正好是LR寄存器保存的地址,所以只有直接把LR恢復(fù)給PC即可。

(2)IRQ或FIQ異常

如果發(fā)生的是IRQ或FIQ異常,因?yàn)橥獠恐袛嗾?qǐng)求中斷了正在執(zhí)行的指令B,當(dāng)中斷返回后,需要重新回到B指令執(zhí)行,也就是說(shuō),返回地址應(yīng)該是B(0x8004),需要把LR減4送PC。

(3)Data Abort數(shù)據(jù)中止異常

在指令B處進(jìn)入數(shù)據(jù)異常的相應(yīng),但導(dǎo)致數(shù)據(jù)異常的原因卻應(yīng)該是上一條指令A(yù)。當(dāng)中斷處理程序恢復(fù)數(shù)據(jù)異常后,要回到A重新執(zhí)行導(dǎo)致數(shù)據(jù)異常的指令,因此返回地址應(yīng)該是LR加8。

為方便起見,表3.7總結(jié)了各異常和返回地址的關(guān)系

表3.7????? 異常和返回地址

異??? 常

地??? 址

用??? 途

復(fù)位

復(fù)位沒有定義LR

數(shù)據(jù)中止

LR-8

指向?qū)е聰?shù)據(jù)中止異常的指令

FIQ

LR-4

指向發(fā)生異常時(shí)正在執(zhí)行的指令

IRQ

LR-4

指向發(fā)生異常時(shí)正在執(zhí)行的指令

預(yù)取指令中止

LR-4

指向?qū)е骂A(yù)取指令異常的那條指令

SWI

LR

執(zhí)行SWI指令的下一條指令

未定義指令

LR

指向未定義指令的下一條指令

?

3.4.6? 在應(yīng)用程序中安裝異常處理程序

1.使用匯編語(yǔ)言安裝異常處理程序

如果系統(tǒng)啟動(dòng)不依賴于Debug或Debug monitor軟件,可以使用匯編語(yǔ)言在系統(tǒng)啟動(dòng)時(shí)直接安裝異常處理程序。

下面的例子顯示了系統(tǒng)從0x0地址啟動(dòng),直接安裝異常處理程序的方法。

Vector_Init_Block

???? LDR PC, Reset_Addr

???? LDR PC, Undefined_Addr

???? LDR PC, SWI_Addr

???? LDR PC, Prefetch_Addr

???? LDR PC, Abort_Addr

???? NOP???????????????????????? ;保留向量

???? LDR PC, IRQ_Addr

???? LDR PC, FIQ_Addr

Reset_Addr DCD Start_Boot

Undefined_Addr DCD Undefined_Handler

SWI_Addr DCD SWI_Handler

Prefetch_Addr DCD Prefetch_Handler

Abort_Addr DCD Abort_Handler

???? DCD 0?????????????????????? ;保留向量

IRQ_Addr DCD IRQ_Handler

FIQ_Addr DCD FIQ_Handler

?

有些情況下,系統(tǒng)0x0地址不一定是ROM。如果0x0地址為RAM,那么就系統(tǒng)將中斷向量表從ROM復(fù)制RAM,下面的例子顯示了這樣一個(gè)過(guò)程。

MOV R8, #0

ADR R9, Vector_Init_Block

LDMIA R9!,{r0-r7}??????????????? ;復(fù)制中斷向量表 (8 words)

STMIA R8!,{r0-r7}

LDMIA R9!,{r0-r7}??????????????? ;復(fù)制由偽操作 DCD定義的地址

STMIA R8!,{r0-r7}

注意

可以使用Scatter文件定義加載向量表的地址,這樣上述代碼的拷貝工作由C庫(kù)函數(shù)完成。

2.使用C語(yǔ)言安裝異常處理程序

程序中有時(shí)需要在main()函數(shù)中使用C語(yǔ)言安裝中斷向量表。這就要求指令經(jīng)編譯后的解碼能安裝在內(nèi)存的正確位置。

(1)向量表中使用跳轉(zhuǎn)指令的情況

如果在向量表中使用跳轉(zhuǎn)指令,使用下面的步驟完成向量表的安裝。

① 讀取異常處理程序的地址。

② 從異常處理程序地址中減去向量表中的偏移。

③ 為適應(yīng)指令流水線,將上一步得到的地址減8。

④ 將得到的結(jié)果右移2位,得到以字為單位的地址偏移量。

⑤ 將結(jié)果的高8位清零,得到跳轉(zhuǎn)指令的24位偏移量。

⑥ 將上一步得到的結(jié)果和0xea000000(無(wú)條件跳轉(zhuǎn)指令編碼)做邏輯與操作,從而得到要寫到向量表中的跳轉(zhuǎn)指令的正確編碼。

下面的例子顯示了這樣一個(gè)標(biāo)準(zhǔn)過(guò)程。

unsigned Install_Handler (unsigned routine, unsigned *vector)

{ unsigned vec, oldvec;

vec = ((routine - (unsigned)vector - 0x8)>>2);

if ((vec & 0xFF000000))

{

/* diagnose the fault */

prinf ("Installation of Handler failed");

exit (1);

}

vec = 0xEA000000 | vec;

oldvec = *vector;

*vector = vec;

return (oldvec);

}

(2)在向量表中使用加載PC指令

在向量表中使用加載PC指令,按照下面的步驟完成。

① 讀取異常處理程序地址。

② 從異常處理程序地址中減去向量表中的偏移。

③ 為適應(yīng)指令流水線,將上一步得到的地址減8。

④ 保留結(jié)果的后12位。

⑤ 將結(jié)果與0xe59ff000(LDR PC, [PC,#offset])做邏輯或操作,從而得到要寫到向量表中的跳轉(zhuǎn)指令的正確編碼。

⑥ 將異常處理程序的地址放到相應(yīng)的存儲(chǔ)單元。

下面的例子顯示了一個(gè)標(biāo)準(zhǔn)的C語(yǔ)言過(guò)程。

unsigned Install_Handler (unsigned location, unsigned *vector)

{ unsigned vec, oldvec;

vec = ((unsigned)location - (unsigned)vector - 0x8) | 0xe59ff000;

oldvec = *vector;

*vector = vec;

return (oldvec);

}

3.4.7? FIQ和IRQ中斷處理函數(shù)的設(shè)計(jì)

1.中斷分支

ARM內(nèi)核只有兩個(gè)外部中斷輸入信號(hào)nFIQ和nIRQ。但對(duì)于一個(gè)系統(tǒng)來(lái)說(shuō),中斷源可能多達(dá)幾十個(gè)。為此,在系統(tǒng)集成的時(shí)候,一般都會(huì)有一個(gè)異常控制器來(lái)處理異常信號(hào),如圖3.8所示。

圖3.8? 中斷系統(tǒng)

這時(shí)候用戶程序可能存在多個(gè)IRQ/FIQ的中斷處理函數(shù)。為了使從向量表開始的跳轉(zhuǎn)始終能找到正確的處理函數(shù)入口,需要設(shè)置一套處理機(jī)制和方法。

多數(shù)情況下是由軟件來(lái)處理異常分支的,因?yàn)檐浖梢酝ㄟ^(guò)讀取中斷控制器來(lái)獲得中斷源的信息,如圖3.9所示。

有些芯片可能支持特殊的硬件分支功能,這需要查看具體的芯片說(shuō)明。

因?yàn)檐浖撵`活性,可以設(shè)計(jì)出比圖3.9更好的流程控制方法,如圖3.10所示。

Int_vector_table是用戶自己開辟的一塊存儲(chǔ)器空間,里面按次序存放異常處理函數(shù)的地址。IRQ_Handler()從中斷控制器獲取中斷源信息,然后再?gòu)腎nt_vector_table中的對(duì)應(yīng)地址單元得到異常處理函數(shù)的入口地址,完成一次異常響應(yīng)的跳轉(zhuǎn)。這種方法的好處是用戶程序在運(yùn)行過(guò)程中,能夠很方便地動(dòng)態(tài)改變異常服務(wù)內(nèi)容。

圖3.9? 軟件控制中斷分支

圖3.10? 靈活的軟件分支設(shè)計(jì)

?

進(jìn)入異常處理程序后,用戶可以完全按照自己的意愿來(lái)進(jìn)行程序設(shè)計(jì),包括調(diào)用Thumb狀態(tài)的函數(shù)等。但對(duì)于絕大多數(shù)的系統(tǒng)來(lái)說(shuō),有兩個(gè)步驟必須處理,一是現(xiàn)場(chǎng)保護(hù),二是要把中斷控制器中對(duì)應(yīng)的中斷狀態(tài)標(biāo)識(shí)清除,表明該中斷請(qǐng)求已經(jīng)得到響應(yīng),否則,中斷函數(shù)退出以后,又會(huì)被再一次觸發(fā),從而進(jìn)入周而復(fù)始的死循環(huán)。

?

2.ARM編譯器對(duì)中斷處理函數(shù)編寫的擴(kuò)展

考慮到中斷處理函數(shù)在現(xiàn)場(chǎng)保護(hù)和返回地址的處理上與普通函數(shù)的不同之處,不能直接把普通函數(shù)體連接到異常向量表上,需要在上面加上一層封裝,下面是一個(gè)例子。

IRQ_Handler?????????????????????? ;中斷相應(yīng)函數(shù)

??? STMFD??? SP!,{r0-r12,lr}????????? ;保護(hù)現(xiàn)場(chǎng),一般只需要保護(hù){r0-r3,LR}

??? BL?? IrqHandler???????????????? ;進(jìn)入普通處理函數(shù),C或匯編均可

……

??? LDMFD??? sp!,{r0-r12,LR}????????? ;恢復(fù)現(xiàn)場(chǎng)

??? SUBS??? pc,lr,#4???????????????? ;中斷返回,注意返回地址

為了方便使用高級(jí)語(yǔ)言直接編寫異常處理函數(shù),ARM編譯器對(duì)此做了特定的擴(kuò)展,可以使用函數(shù)聲明關(guān)鍵字_irq,這樣編譯出來(lái)的函數(shù)就可以滿足異常響應(yīng)對(duì)現(xiàn)場(chǎng)保護(hù)和恢復(fù)的需要,并且自動(dòng)加入LR減4的處理,符合IQR和FIQ中斷處理的要求。

下面的例子顯示了使用_irq對(duì)中斷處理函數(shù)產(chǎn)生的影響。

C語(yǔ)言源程序如下。

__irq void IRQHandler (void)

{

volatile unsigned int *base = (unsigned int *) 0x80000000;

if (*base == 1)

{

/*調(diào)用C語(yǔ)言中斷處理函數(shù)*/

C_int_handler();

}

/*清楚中斷標(biāo)志*/

*(base+1) = 0;

}

使用armcc編譯出的匯編代碼如下。

IRQHandler PROC

??? STMFD sp!,{r0-r4,r12,lr}

??? MOV r4,#0x80000000

??? LDR r0,[r4,#0]

??? SUB sp,sp,#4

??? CMP r0,#1

??? BLEQ C_int_handler

??? MOV r0,#0

??? STR r0,[r4,#4]

??? ADD sp,sp,#4

??? LDMFD sp!,{r0-r4,r12,lr}

??? SUBS pc,lr,#4

??? ENDP

如果不使用_irq子程序聲明關(guān)鍵字,編譯出的匯編代碼如下。

IRQHandler PROC

??? STMFD sp!,{r4,lr}

??? MOV r4,#0x80000000

??? LDR r0,[r4,#0]

??? CMP r0,#1

??? BLEQ C_int_handler

??? MOV r0,#0

??? STR r0,[r4,#4]

??? LDMFD sp!,{r4,pc}

??? ENDP

3.可重入中斷設(shè)計(jì)

在缺省情況下,ARM中斷是不可重入的。因?yàn)橐坏┻M(jìn)入異常響應(yīng)狀態(tài),ARM自動(dòng)關(guān)閉中斷使能。如果在異常處理過(guò)程中,簡(jiǎn)單地打開中斷使能而發(fā)生中斷嵌套時(shí),顯然新的異常處理將破壞原來(lái)的中斷現(xiàn)場(chǎng)而導(dǎo)致出錯(cuò)。但有時(shí)需要中斷必須是可重入的,因此要通過(guò)程序設(shè)計(jì)來(lái)解決這個(gè)問題。其中有兩個(gè)關(guān)鍵問題。

① 新中斷使能之前,必須要保護(hù)好前一個(gè)中斷的現(xiàn)場(chǎng)信息。比如LR_irq和SPSR_irq等,這一點(diǎn)比較容易做的。

② 中斷處理過(guò)程中對(duì)BL進(jìn)行保護(hù)。

在中斷處理函數(shù)中發(fā)生函數(shù)調(diào)用BL是很常見的,假設(shè)有下面一種情況。

IRQ_Handler:

???? ……

???? BL??? Foo

???? ADD

其中,

Foo:

??? STMFD? SP!,{r0-r3,LR}

??? ……

??? LDMFD? SP!{r0-r3,PC}

上述程序,在IRQ處理函數(shù)IRQ_Handler()中調(diào)用了函數(shù)Foo()。若是在IRQ_Handler()里面中斷可重入的話,可能發(fā)生問題,考察下面的情況:當(dāng)新的中斷請(qǐng)求恰好在“BL? Foo”指令執(zhí)行完成后發(fā)生。這時(shí)候LR_irq寄存器(因在IRQ模式下,所以是LR_irq)的值將調(diào)整為BL指令的下一條指令(ADD)地址,使其能從Foo()正確返回;但是因?yàn)檫@時(shí)候發(fā)生了中斷請(qǐng)求,接下來(lái)要進(jìn)行新中斷的響應(yīng),處理器在新中斷響應(yīng)過(guò)程中也要進(jìn)行LR_irq保存。這次對(duì)LR_irq的操作發(fā)生了沖突,當(dāng)新中斷返回后,往下執(zhí)行STMFD指令,這時(shí)候壓棧的LR已不是原來(lái)的ADD指令地址,從而使子程序Foo()無(wú)法正確返回。

這個(gè)問題無(wú)法通過(guò)增加額外的現(xiàn)場(chǎng)保護(hù)指令來(lái)解決。一個(gè)辦法就是在重新使能中斷之前改變處理器模式,也就是使上面程序的“BL? Foo”指令不要運(yùn)行在IRQ模式下。這樣當(dāng)新的中斷發(fā)生時(shí),就不會(huì)造成LR寄存器的沖突。考慮ARM的所有運(yùn)行模式,采用SYSTEM模式是比較合適的,因?yàn)樗翘貦?quán)模式,不是IRQ模式,與中斷響應(yīng)無(wú)關(guān)。

下面的例子顯示了標(biāo)準(zhǔn)的IRQ/FIQ異常中斷處理程序。

??? PRESERVE8

??? AREA INTERRUPT, CODE, READONLY

??? IMPORT C_irq_handler

IRQ

??? SUB lr, lr, #4??????????????? ;跳轉(zhuǎn)返回地址

STMFD sp!, {lr}????????????????? ;保存返回地址

MRS r14, SPSR??????????????????? ;讀取SPSR

STMFD sp!, {r12, r14}???????????? ;保存寄存器

; 清除中斷源

MSR CPSR_c, #0x1F??????????????? ;切換到SYSTEM模式,

STMFD sp!, {r0-r3, lr}??????????? ;保存lr_USR 和其他使用到的寄存器

BL C_irq_handler???????????????? ;跳轉(zhuǎn)到C中斷處理函數(shù)

LDMFD sp!, {r0-r3, lr}??????????? ;恢復(fù)用戶模式寄存器

MSR CPSR_c, #0x92??????????????? ;切換回irq模式

LDMFD sp!, {r12, r14}

MSR SPSR_cf, r14

LDMFD sp!, {pc}^

END

?

3.4.8? SWI異常處理函數(shù)的設(shè)計(jì)

本小節(jié)主要介紹編寫SWI處理程序時(shí)需要注意的幾個(gè)問題,包括下面內(nèi)容。

·? 判斷SWI中斷號(hào)。

·? 使用匯編語(yǔ)言編寫SWI異常處理函數(shù)。

·? 使用C語(yǔ)言編寫SWI異常處理函數(shù)。

·? 在特權(quán)模式下使用SWI異常中斷處理。

·? 從應(yīng)用程序中調(diào)用SWI。

·? 從應(yīng)用程序中動(dòng)態(tài)調(diào)用SWI。

1.判斷SWI中斷號(hào)

當(dāng)發(fā)生SWI異常,進(jìn)入異常處理程序時(shí),異常處理程序必須提取SWI中斷號(hào),從而得到用戶請(qǐng)求的特定SWI功能。

在SWI指令的編碼格式中,后24位稱為指令的“comment field”。該域保存的24位數(shù),即為SWI指令的中斷號(hào),如圖3.11所示。

圖3.11? SWI指令編碼格式

第一級(jí)的SWI處理函數(shù)通過(guò)LR寄存器內(nèi)容得到SWI指令地址,并從存儲(chǔ)器中得到SWI指令編碼。通常這些工作通過(guò)匯編語(yǔ)言、內(nèi)嵌匯編來(lái)完成。

下面的例子顯示了提取中斷向量號(hào)的標(biāo)準(zhǔn)過(guò)程。

PRESERVE8

AREA TopLevelSwi, CODE, READONLY???????? ;第一級(jí)SWI處理函數(shù).

EXPORT SWI_Handler

SWI_Handler

STMFD sp!,{r0-r12,lr}????????????????? ;保存寄存器

LDR r0,[lr,#-4]??????????????????????? ;計(jì)算SWI指令地址.

BIC r0,r0,#0xff000000????????????????? ;提取指令編碼的后24位

;

; 提取出的中斷號(hào)放r0寄存器,函數(shù)返回

;

LDMFD sp!, {r0-r12,pc}^???????????????? ;恢復(fù)寄存器

END

例子中,使用LR-4得到SWI指令的地址,再通過(guò)“BIC r0, r0, #0xFF000000”指令提取SWI指令中斷號(hào)。

2.匯編語(yǔ)言編寫SWI異常處理函數(shù)

最簡(jiǎn)單的方法是利用得到的中斷向量號(hào),使用跳轉(zhuǎn)表直接跳轉(zhuǎn)到實(shí)現(xiàn)相應(yīng)SWI功能的處理程序。

下面的例子,使用匯編語(yǔ)言實(shí)現(xiàn)了這種跳轉(zhuǎn)。

??? CMP r0,#MaxSWI??????????????? ;中斷向量范圍檢測(cè)

??? LDRLS pc, [pc,r0,LSL #2]

??? B SWIOutOfRange

SWIJumpTable

??? DCD SWInum0

??? DCD SWInum1

; 使用DCD 定義各功能函數(shù)入口地址

SWInum0???????????????????????? ;0號(hào)中斷

??? B EndofSWI

SWInum1???????????????????????? ;1號(hào)中斷

??? B EndofSWI

;

EndofSWI

3.使用C語(yǔ)言編寫SWI異常處理函數(shù)

雖然第一級(jí)SWI處理函數(shù)(完成中斷向量號(hào)的提取)必須用匯編語(yǔ)言完成,但第二級(jí)中斷處理函數(shù)(根據(jù)提取的中斷向量號(hào),跳轉(zhuǎn)到具體處理函數(shù))就可以使用C語(yǔ)言來(lái)完成。

因?yàn)榈谝患?jí)的中斷處理函數(shù)已經(jīng)將中斷號(hào)提取到寄存器r0中,所以根據(jù)AAPCS函數(shù)調(diào)用規(guī)則,可以直接使用BL指令跳轉(zhuǎn)到C語(yǔ)言函數(shù),而且中斷向量號(hào)作為第一個(gè)參數(shù)被傳遞到C函數(shù)。

例如匯編中使用了“BL ?C_SWI_Handler”跳轉(zhuǎn)到C語(yǔ)言的第二級(jí)處理函數(shù),則第二級(jí)的C語(yǔ)言函數(shù)示例如下所示。

void C_SWI_handler (unsigned number)

{

??? switch (number)

???? {

????? case 0 : /* SWI number 0 code */

????? break;

????? case 1 : /* SWI number 1 code */

????? break;

????? ...

????? default : /* Unknown SWI - report error */

???? }

}

另外,如果需要傳遞的參數(shù)多于1個(gè),那么可以使用堆棧,將堆棧指針作為函數(shù)的參數(shù)傳遞給C類型的二級(jí)中斷處理程序,就可以實(shí)現(xiàn)在兩級(jí)中斷之間傳遞多個(gè)參數(shù)。

例如:

MOV r1, sp???????????????? ;將傳遞的第二個(gè)參數(shù)(堆棧指針)放到r1中

BL C_SWI_Handler??????????? ;調(diào)用C函數(shù)

相應(yīng)的C函數(shù)的入口變?yōu)椋?/p>

void C_SWI_handler(unsigned number, unsigned *reg)

同時(shí),C函數(shù)也可以通過(guò)堆棧返回操作的結(jié)果。

?

4.在特權(quán)模式下使用SWI異常處理

在特權(quán)模式下使用SWI異常處理,和IRQ/FIQ中斷嵌套基本類似。當(dāng)執(zhí)行SWI指令后,處理器執(zhí)行下面操作。

① 處理器進(jìn)入特權(quán)模式。

② 將程序狀態(tài)字內(nèi)容CPSR保存到SPSR_svc。

③ 返回地址放入LR_svc。

如果處理器已經(jīng)處于特權(quán)模式,再發(fā)生SWI異常,則LR_svc和SPSR_svc寄存器的值將丟失。

所以在特權(quán)模式下,調(diào)用SWI軟中斷異常,必須先將LR_svc和SPSR_svc寄存器的值壓棧保護(hù)。下面的例子顯示了一個(gè)可以在特權(quán)模式下調(diào)用的SWI處理函數(shù)。

???? ?AREA SWI_Area, CODE, READONLY

??? PRESERVE8

??? EXPORT SWI_Handler

??? IMPORT C_SWI_Handler

????????????????????? ?T_bit EQU 0x20

SWI_Handler

??? STMFD sp!,{r0-r3,r12,lr}????????????? ;寄存器壓棧保護(hù)

?? ?MOV r1, sp????????????????????????? ;堆棧指針放r1作為參數(shù)傳遞.

?? ?MRS r0, spsr???????????????????????? ;讀取spsr.

?? ?STMFD sp!, {r0, r3}?????????????????? ;將spsr壓棧保護(hù)

?? ?;

?? ?;

?? ?LDR r0,[lr,#-4]????????????????????? ;計(jì)算SWI指令地址.

?? ?BIC r0,r0,#0xFF000000???????????????? ;讀取SWI中斷向量號(hào).

?? ?; r0存放中斷向量號(hào)

?? ?; r1 堆棧指針

?? ?BL C_SWI_Handler???????????????????? ;調(diào)用C程序的SWI處理函數(shù).

?? ?LDMFD sp!, {r0, r3}?????????????????? ;從堆棧中讀取spsr.

?? ?MSR spsr_cf, r0????????????????????? ;恢復(fù)spcr

?? ?LDMFD sp!, {r0-r3,r12,pc}^???????????? ;恢復(fù)其他寄存器并返回.

?? ?END

5.從應(yīng)用程序中調(diào)用SWI

可從匯編語(yǔ)言或 C/C++ 中調(diào)用 SWI。

(1)從匯編應(yīng)用程序中調(diào)用SWI

從匯編語(yǔ)言程序中調(diào)用SWI,只要遵循AAPCS標(biāo)準(zhǔn)即可。調(diào)用前,設(shè)定所有必須的值并發(fā)出相關(guān)的 SWI。例如:

MOV r0, #65 ??????; 將軟中斷的子功能號(hào)放到r0中

SWI 0x0

注意

SWI指令和其他所以ARM指令一樣,可以被條件執(zhí)行。

(2)從C應(yīng)用程序中調(diào)用SWI

在C或C++應(yīng)用程序中調(diào)用SWI,要將C語(yǔ)言的子程序用編譯器擴(kuò)展_swi聲明,例如:

__swi(0) void my_swi(int);

……

……

……

my_swi(65);

編譯器擴(kuò)展_swi確保了SWI以內(nèi)聯(lián)方式進(jìn)行編譯,而沒有額外的開銷。但有如下的AAPCS限制。

·? 函數(shù)調(diào)用參數(shù)只能使用r0~r3傳遞。

·? 函數(shù)返回值只能通過(guò)r0~r3傳遞。

向內(nèi)聯(lián)的SWI函數(shù)傳遞參數(shù)和向?qū)嶋H的子函數(shù)傳遞參數(shù)基本類似。但返回值的情況比較復(fù)雜。如果有兩到四個(gè)返回值,則必須告訴編譯程序返回值是以結(jié)構(gòu)形式返回的,并使用__value_in_regs 偽操作聲明。這是因?yàn)榛诮Y(jié)構(gòu)值的函數(shù)通常被處理為一個(gè)void(空)型函數(shù),且第一個(gè)自變量必須為存放結(jié)果結(jié)構(gòu)的地址。

下面的例子顯示了對(duì)編號(hào)為0x0、0x1、0x2和0x3的SWI軟中斷的調(diào)用。其中,SWI0x0和SWI0x1傳遞兩個(gè)整型參數(shù)并返回一個(gè)單一結(jié)果;SWI0x2傳遞4個(gè)參數(shù)并返回一個(gè)單一結(jié)果;而SWI0x3傳遞4個(gè)參數(shù)并通過(guò)結(jié)構(gòu)體返回4個(gè)結(jié)果。

#include <stdio.h>

#include "swi.h"

unsigned *swi_vec = (unsigned *)0x08;

extern void SWI_Handler(void);

int main( void )

{

int result1, result2;

struct four_results res_3;

Install_Handler( (unsigned) SWI_Handler, swi_vec );

printf("result1 = multiply_two(2,4) = %dn", result1 = multiply_two(2,4));

printf("result2 = multiply_two(3,6) = %dn", result2 = multiply_two(3,6));

printf("add_two( result1, result2 ) = %dn", add_two( result1, result2 ));

printf("add_multiply_two(2,4,3,6) = %dn", add_multiply_two(2,4,3,6));

res_3 = many_operations( 12, 4, 3, 1 );

printf("res_3.a = %dn", res_3.a );

printf("res_3.b = %dn", res_3.b );

printf("res_3.c = %dn", res_3.c );

printf("res_3.d = %dn", res_3.d );

return 0;

}

__swi(0) int multiply_two(int, int);

__swi(1) int add_two(int, int);

__swi(2) int add_multiply_two(int, int, int, int);

struct four_results

{

int a;

int b;

int c;

int d;

};

__swi(3) __value_in_regs struct four_results many_operations(int, int, int, int);

(3)應(yīng)用程序中動(dòng)態(tài)調(diào)用SWI

在某些情形下,需要調(diào)用直到運(yùn)行時(shí)才會(huì)知道其編號(hào)的 SWI。例如,當(dāng)有很多相關(guān)操作可在同一目標(biāo)上執(zhí)行,并且每一個(gè)操作都有其自己的 SWI 時(shí),就會(huì)發(fā)生這種情況。在此情況下,上一小節(jié)的方法不適用。

解決的方法有兩種。

·? 在運(yùn)行時(shí)得到SWI功能號(hào),然后構(gòu)造出相應(yīng)的SWI指令的編碼,將該編碼保存在某個(gè)存儲(chǔ)單元中,將PC指針指向該單元,執(zhí)行指令。

·? 使用一個(gè)通用的SWI異常中斷處理程序,將運(yùn)行時(shí)需要調(diào)用的SWI功能號(hào)作為參數(shù)傳遞給該通用的SWI異常處理程序,通用的SWI異常中斷處理程序根據(jù)參數(shù)值調(diào)用相應(yīng)的SWI處理程序完成需要的操作。

通過(guò)匯編語(yǔ)言可以實(shí)現(xiàn)第二種解決辦法:通過(guò)寄存器(通常為r0或r12)傳遞所需要的操作數(shù),這樣可以重新編寫SWI處理程序,對(duì)相應(yīng)寄存器中的值進(jìn)行處理。

但有些情況下,為了節(jié)省程序開銷,需要直接使用SWI中斷號(hào)對(duì)程序調(diào)用。例如,操作系統(tǒng)可能會(huì)使用單一的一條SWI指令并用寄存器來(lái)傳遞所需運(yùn)算的編號(hào)。這使得其他SWI空間可用于特定應(yīng)用程序的SWI。在一個(gè)特定的應(yīng)用程序中,如果從指令中提取SWI編號(hào)的開銷太大,就可使用這個(gè)方法。ARM(0x123456)和Thumb(0xAB)半主機(jī)方式的SWI就是這樣實(shí)現(xiàn)的。

?

下面的例子顯示了如何使用_swi將C函數(shù)調(diào)用映射到半主機(jī)方式的SWI。

#ifdef __thumb

/* Thumb 狀態(tài)的Semihosting軟中斷處理*/

#define SemiSWI 0xAB

#else

/* ARM狀態(tài)下的Semihosting的軟中斷處理*/

#define SemiSWI 0x123456

#endif

/* 使用Semihosting軟中斷輸出一個(gè)字符*/

__swi(SemiSWI) void Semihosting(unsigned op, char *c);

#define WriteC(c) Semihosting (0x3,c)

void write_a_character(int ch)

{

char tempch = ch;

WriteC( &tempch );

}

編譯程序含有一個(gè)機(jī)制,用以支持使用r12來(lái)傳遞所需運(yùn)算的值。根據(jù)AAPCS標(biāo)準(zhǔn),r12為IP寄存器,并且專用于函數(shù)調(diào)用。其他時(shí)間內(nèi)可將其用作暫存寄存器。如前面所述,通用SWI參數(shù)和返回值通過(guò)r0~r3寄存器傳遞。而r12可用于傳遞通用SWI調(diào)用的中斷功能編號(hào)。

下面的例子顯示了通用SWI的C語(yǔ)言程序框架。

__swi_indirect(0x80)

unsigned SWI_ManipulateObject(unsigned operationNumber,

unsigned object,unsigned parameter);

unsigned DoSelectedManipulation(unsigned object,

unsigned parameter, unsigned operation)

{

return SWI_ManipulateObject(operation, object, parameter);

}

生成的匯編代碼如下。

DoSelectedManipulation PROC

STMFD sp!,{r3,lr}

MOV r12,r2

SWI 0x80

LDMFD sp!,{r3,pc}

ENDP

Arm

Arm

ARM公司是一家知識(shí)產(chǎn)權(quán)(IP)供應(yīng)商,主要為國(guó)際上其他的電子公司提供高性能RISC處理器、外設(shè)和系統(tǒng)芯片技術(shù)授權(quán)。目前,ARM公司的處理器內(nèi)核已經(jīng)成為便攜通訊、手持計(jì)算設(shè)備、多媒體數(shù)字消費(fèi)品等方案的RISC標(biāo)準(zhǔn)。公司1990年11月由Acorn、Apple和VLSI合并而成。

ARM公司是一家知識(shí)產(chǎn)權(quán)(IP)供應(yīng)商,主要為國(guó)際上其他的電子公司提供高性能RISC處理器、外設(shè)和系統(tǒng)芯片技術(shù)授權(quán)。目前,ARM公司的處理器內(nèi)核已經(jīng)成為便攜通訊、手持計(jì)算設(shè)備、多媒體數(shù)字消費(fèi)品等方案的RISC標(biāo)準(zhǔn)。公司1990年11月由Acorn、Apple和VLSI合并而成。收起

查看更多

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

華清遠(yuǎn)見(www.farsight.com.cn)是國(guó)內(nèi)領(lǐng)先嵌入師培訓(xùn)機(jī)構(gòu),2004年注冊(cè)于中國(guó)北京海淀高科技園區(qū),除北京總部外,上海、深圳、成都、南京、武漢、西安、廣州均有直營(yíng)分公司。華清遠(yuǎn)見除提供嵌入式相關(guān)的長(zhǎng)期就業(yè)培訓(xùn)、短期高端培訓(xùn)、師資培訓(xùn)及企業(yè)員工內(nèi)訓(xùn)等業(yè)務(wù)外,其下屬研發(fā)中心還負(fù)責(zé)嵌入式、Android及物聯(lián)網(wǎng)方向的教學(xué)實(shí)驗(yàn)平臺(tái)的研發(fā)及培訓(xùn)教材的出版,截止目前為止已公開出版70余本嵌入式/移動(dòng)開發(fā)/物聯(lián)網(wǎng)相關(guān)圖書。企業(yè)理念:專業(yè)始于專注 卓識(shí)源于遠(yuǎn)見。企業(yè)價(jià)值觀:做良心教育、做專業(yè)教育,更要做受人尊敬的職業(yè)教育。