6.2.1 異常中斷處理程序的方法種類及其介紹
在 SWI 指令中包括一個(gè) 24 位的立即數(shù),該立即數(shù)指示了用戶請(qǐng)求的特定的 SWI 功能。在
SWI
異常中斷處理程序要讀取該 24 位的立即數(shù),這涉及到 SWI異常模式下對(duì)寄存器 LR的讀
取,并且要從存儲(chǔ)器讀取該 SWI 指令。這樣需要使用匯編程序來(lái)實(shí)現(xiàn)。通常 SWI異常中斷處
理程序分為兩級(jí):第 1 級(jí) SWI
異常中斷處理程序?yàn)閰R編,用于確定 SWI 指令中的 24 位的立
即數(shù);第 2級(jí) SWI 異常中斷處理程序具體實(shí)現(xiàn) SWI 的各個(gè)功能,它可以是匯編程序,也可以
時(shí) C 程序,下面我們分別介紹這兩級(jí)。
● SWI 異常中斷調(diào)用
① 在特權(quán)模式下調(diào)用 SWI
執(zhí)行 SWI 指令后,系統(tǒng)將會(huì)把 CPSR 寄存器的內(nèi)容保存到寄存器 SPSR_SVC 中,
將返回地址保存到寄存器 LR_svc 中。這樣如果執(zhí)行 SWI 指令時(shí),系統(tǒng)已經(jīng)處于
特權(quán)模式下,這時(shí)寄存器 SPSR_svc 和寄存器 LR_svc 中的內(nèi)容就會(huì)被破壞。因
此如果在特權(quán)模式下調(diào)用 SWI 功能,比如在一個(gè) SWI 異常中斷處理程序中執(zhí)行
SWI指令,就必須將原始的寄存器SPSR_svc和寄存器LR_svc值保存在數(shù)據(jù)棧中。
程序6.1說(shuō)明在SWI中斷處理程序中如何保存寄存器SPSR_svc和寄存器LR_svc
值。
程序 6.1 在SWI 中斷處理程序中保存寄存器 SPSR_svc 和寄存器 LR_svc 值
;保存寄存器,包括寄存器 lr_svc
STMFD sp!(r0-r3,r12,lr)
;保存 SPSR_svc
MOV r1,sp
MRS r0,spsr
STMFD sp!,(r0)
;讀取SWI指令
LDR r0,(lr,#4)
;計(jì)算其中的 24 位立即數(shù),并將其放入寄存器 R0 中
BIC r0,r0.#0xff000000
;調(diào)用C_SWI_Handler 完成相應(yīng)的 SWI 功能
BL C_SWI_Handler
;恢復(fù)SPSR_svc 的值
LDMFD sp!,(r0)
MSB spsr_cf,r0
;恢復(fù)其他寄存器,包括寄存器 LR_svc
LDMFD sp!,(r0-r3,r12,pc)^
② 從應(yīng)用程序中調(diào)用 SWI
這里分兩種情況考慮從應(yīng)用程序中調(diào)用特定的 SWI 功能:一種考慮使用匯編指
令調(diào)用特定的 SWI 功能;一種考慮從 C 語(yǔ)言程序中調(diào)用特定的 SWI 功能。
使用匯編指令調(diào)用特定的 SWI 功能比較簡(jiǎn)單,將需要的參數(shù)按照 ATPCS 的要求
放在相應(yīng)的寄存器中,然后在指令 SWI 中指定相應(yīng) 24 位立即數(shù)即可。下面的例
子中,SWI 中斷處理程序需要的參數(shù)放在寄存器 R0 中,這里該參數(shù)為 100,然
后調(diào)用功能號(hào)為 0x0 的SWI 功能調(diào)用。
MOV R0,#100
SWI 0x0
從 C 語(yǔ)言程序中調(diào)用特定的 SWI 功能比較復(fù)雜,因?yàn)檫@時(shí)需要將一個(gè) C 程序的
子程序調(diào)用映射到一個(gè) SWI 異常中斷處理程序。這些被映射的 C 語(yǔ)言子程序使
用編譯器偽操作__SWI 來(lái)聲明。如果該子程序需要的參數(shù)和返回的結(jié)果只使用寄
存器 R0~R3,則該 SWI 可以被編譯成 inline 的,不需要使用子程序調(diào)用過(guò)程。
否則必須告訴編譯器通過(guò)結(jié)構(gòu)數(shù)據(jù)類型來(lái)返回參數(shù),這時(shí)需要使用編譯器偽操
作_value_in_reg 聲明該C 語(yǔ)言子程序。
下面通過(guò)一個(gè)完整的例子來(lái)說(shuō)明如何從 C 程序中調(diào)用特定的 SWI 功能,該例子
是 ARM 公司的 ADS1.2 中所帶的。該例子提供的 4 個(gè)SWI 功能調(diào)用,功能號(hào)分別
為 0x0,0x1,0x2,0x3。其中 SWI 0x0及 SWI 0x1 使用兩個(gè)整形的輸入?yún)?shù),并返
回一個(gè)結(jié)果值,SWI 0x2使用 4 個(gè)輸入?yún)?shù),并返回一個(gè)結(jié)果值;SWI 0x3 使用
4 個(gè)輸入?yún)?shù),并返回 4個(gè)結(jié)果值。
整個(gè) SWI 異常中斷處理程序分為兩級(jí)結(jié)構(gòu)。第 1 級(jí)的 SWI 異常中斷處理程序是
匯編程序 SWI_HANDLER,它讀取 SWI 指令中的 24 位立即數(shù),然后調(diào)用第 2 個(gè)級(jí)
SWI 異常中斷處理程序 C_SWI_HANDLER來(lái)實(shí)現(xiàn)具體的 SWI 功能。第 2 級(jí)SWI異常
中谷底你處理程序 C_SWI_HANDLER 為 C 語(yǔ)言程序。其中實(shí)現(xiàn)了功能號(hào)分別為
0x0,0x1,0x2,0x3的 SWI功能調(diào)用。
主程序中的子程序 multiply_two()對(duì)應(yīng)著 SWI 0x0;add_two()對(duì)應(yīng)著
0x1;add_multiply_two()對(duì)應(yīng)著 0x2;many_operations()對(duì)應(yīng)著 SWI 0x3。
Many_operations()返回 4 個(gè)結(jié)果,使用編譯器偽操作_valuc_in_reg 聲明。4
個(gè)子程序都使用編譯器偽操作__SWI來(lái)聲明。主程序使用 lnstall_Handler()來(lái)
安裝該 SWI異常中斷處理程序,lnstall_Handler()在前面已經(jīng)有詳細(xì)的介紹。
整個(gè)代碼如程序 6.2 所示。
程序 6.2 從C 程序中調(diào)用特定的 SWI功能
__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);
#include
#include “swi.h”
Unsigned *swi_vec=(unsigned *)0x08;
Unsigned install_Handler(unsigned routine, unsigned *vector)
{
Unsigned vec,old_vec;
Vec=(routine –(unsigned)vector-8)>>2;
If (vec & 0xff000000)
{
print(“Handler greter than 32Mbytes from vector”);
vec=0xea000000 |vec;
Old_vec=*vector;
*vector=vec;
Return(old_vec);
}
Int result1,result2;
Struct fcur_results result3;
Install_Handler ((unsigned) SWI_Handler,swi_vec);
Printf(“result1=mutiply_two (2,4)=%dn”,
Result1=multiply_two(2,4));
Printf(“result2=mutiply_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;
}
;第1 級(jí)SWI 異常中斷處理程序 SWI_Handler
;SWI_Handler 在前面已有詳細(xì)介紹
AREA SWI_Area, CODE,PEADONLY
EXPORT SWI_Handler
IMPORT C_SWI_Handler
T_bit EQU 0x2c
SWI_Handler
STMED sp!(r0-r3,r12,lr)
MOV r1,sp
MRS r0,spsr
STMFD sp!,(r0)
TST r0,#T_bit
LDRNEH r0(lr,#-2)
BTCNE r0,r0,#0xff00
LDREQ r0,(lr,#-4)
BICEQ r0,r0,#0xff000000
BL C_SWI_Handler
LDMFD sp!,(r0)
MSR spsr cf,r0
LDMFD sp!,(r0-r3,r12,pc)^
END
Void C_SWI_Handler (int swi_num,int *regs)
{
Switch (swi_num)
{
//對(duì)應(yīng)于SWI 0x0
case 0:
regs[0]=regs[0]*regs[1];
break;
//對(duì)應(yīng)于SWI 0x1
case 1:
regs[0]=regs[0]+ regs[1];
break;
//對(duì)應(yīng)于SWI 0x2
case 2:
regs[0]=(regs[0]*regs[1]) +(regs[2]*regs[3]);
break;
//對(duì)應(yīng)于SWI 0x3
case 3:
{int w,x,y,z;
w=regs[0];
x=regs[1];
y=regs[2];
z=regs[3];
regs[0]=w+x+y+z;
regs[1]=w-x-y-z;
regs[2]=w*x*y*z;
regs[3]=(w+x)*(y-z);
}
Break;
}
}
③ 從應(yīng)用程序中動(dòng)態(tài)調(diào)用 SWI
在有些情況下,直到運(yùn)行時(shí)才能夠確定需要調(diào)用的 SWI 功能號(hào)。這時(shí),有兩種
方法處理這種情況。
第 1 種方法是在運(yùn)行時(shí)得到 SWI 功能號(hào),然后構(gòu)造出相應(yīng)的 SWI 指令的編碼,
把這個(gè)指令的編碼保存在一個(gè)存儲(chǔ)器單元中,執(zhí)行該指令即可。
第 2 種方法使用一個(gè)通用的 SWI 異常中斷處理程序,將運(yùn)行時(shí)需要調(diào)用的 SWI
功能號(hào)作為參數(shù)傳遞給該通用的 SWI 異常中斷處理程序,通用的 SWI 異常中斷
處理程序根據(jù)參數(shù)值調(diào)用相應(yīng)的 SWI 處理程序完成需要的操作。
在匯編程序中很容易實(shí)現(xiàn)第 2 中方法。在執(zhí)行 SWI 指令之前先將需要調(diào)用的 SWI
功能號(hào)放在一個(gè)寄存器。在通用的 SWI 異常中斷處理程序讀取該寄存器值,決
定需要執(zhí)行的操作,但有些 SWI 處理程序需要 SWI 指令的 24位立即數(shù),因而上
述兩種方法常常組合使用。
在操作系統(tǒng)中通常使用一個(gè) SWI 功能號(hào)和一個(gè)寄存器來(lái)提供很多的 SWI 功能調(diào)
用。這樣可以將其他的 SWI 功能號(hào)留給用戶使用。在 DOS 系統(tǒng)中,DOS 提供功能
調(diào)用是 INT 21H ,這時(shí)通過(guò)指定寄存器 AX 的值,可以實(shí)現(xiàn)很多不同的功能調(diào)用。
ARM 體系中semihost 的實(shí)現(xiàn)也是一個(gè)例子。ARM 程序使用 SWI 0x123456 來(lái)實(shí)現(xiàn)
semilhost 功能調(diào)用;Thunb 程序使用SWI 0xAB 來(lái)實(shí)現(xiàn) semihost 功能調(diào)用。在
下面的例子中,將子程序 WRITEC (unsigned op,char *c)映射到 semihost
功能調(diào)用,具體 semihost SWI 的子功能號(hào)通過(guò)參數(shù) op 傳遞。
程序 6.3 從應(yīng)用程序中動(dòng)態(tài)調(diào)用 SWI 功能
#ifdef_thumb
#else
#define semiSWI 0x123456
#endif
__swi (semiSWI) void semibosting (unsigned op,char *c);
Void write_a_character (int ch)
{
char tempth=ch;
writec (&tempch);
}
2.FIQ 和IRQ 異常中斷處理程序
ARM 提供的FIQ和 IRQ 異常中斷用于外部設(shè)備向 CPU 請(qǐng)求中斷服務(wù)。這兩個(gè)異常中斷的引腳
都是低電平有效的。當(dāng)前程序狀態(tài)寄存器 CPSR 的 1 控制位可以屏蔽這兩個(gè)異常中斷請(qǐng)求;
當(dāng)程序狀態(tài)寄存器 CPSR由 1 控制位位 0 時(shí),CPU正常響應(yīng) FIQ 和IRQ 異常中斷請(qǐng)求。
FIQ 異常中斷為快速異常中斷,它比 IRQ 異常中斷優(yōu)先級(jí)高,這主要表現(xiàn)在下面的兩個(gè)方
面:
● 當(dāng) FIQ 和IRQ 異常中斷同時(shí)產(chǎn)生時(shí),CPU 先處理 FIQ 異常中斷。
● 在 FIQ 異常中斷處理程序中 IRQ 異常中斷被禁止。
由于 FIQ 異常中斷通常用于系統(tǒng)對(duì)于響應(yīng)時(shí)間要求比較苛刻的任務(wù),ARM 體系在設(shè)計(jì)上有
一些特別的安排,以盡量減少 FIQ 異常中斷響應(yīng)時(shí)間。FIQ 異常中斷的中斷向量為 0x1c,位
于中斷向量表的最后。這樣 FIQ 異常中斷處理程序可以直接放在地址 0x1c 開(kāi)始的存儲(chǔ)單元,
這種安排省掉了中斷向量表的跳轉(zhuǎn)指令,從而也就節(jié)省了中斷響應(yīng)時(shí)間。當(dāng)系統(tǒng)中存在
cache 時(shí),可以把 FIQ 異常中斷向量以及處理程序一起鎖在 cache 中,從而大大地提高了
FIQ 異常中斷響應(yīng)時(shí)間。除此之外,與其他的異常模式相比,F(xiàn)IQ 異常中斷還有額外的 5 個(gè)
物理寄存器,這樣在進(jìn)入 FIQ 處理程序時(shí)可以保存這 5 個(gè)寄存器,從而也提高了 FIQ 異常中
斷的執(zhí)行速度。
在有些 IRQ/FIQ 異常中斷處理程序中,允許新的 IRQ/FIQ 異常中斷,這時(shí)將需要一些特
別的操作保證“老的”異常中斷的寄存器不會(huì)“新的”異常中斷破壞,這種 IRQ/FIQ 異常中
斷處理程序稱為可重入的異常中斷處理程序。否則稱為不可重入的異常中斷處理程序。
① 不可重入的 IRQ/FIQ 異常中斷處理程序
對(duì)于 C 語(yǔ)言不可重入的 IRQ/FIQ 異常中斷處理程序可以使用關(guān)鍵詞_irq來(lái)說(shuō)明。關(guān)鍵詞
_irq 可以實(shí)現(xiàn)下面的操作:
● 保存 APCS 規(guī)定的被破壞的寄存器。
● 保存其他中斷處理程序中用到的寄存器。
● 同時(shí)將(LD-4)賦予程序計(jì)數(shù)器 pc 實(shí)現(xiàn)中斷處理程序的返回,并且恢復(fù) CPSR 寄
存器的內(nèi)容。
當(dāng) IRQ/FIQ異常中斷處理程序調(diào)用了子程序時(shí),關(guān)鍵詞_irq可以使 IRQ/FIQ 異常中斷
處理程序返回時(shí)從其數(shù)據(jù)棧中讀取 LR_irq 值,并通過(guò) SUBS PC,LR,#4 實(shí)現(xiàn)返回。程序
6.4 說(shuō)明的關(guān)鍵詞_irq 的作用,其中列出了 C 語(yǔ)言程序及其對(duì)應(yīng)的匯編程序,兩個(gè) C
語(yǔ)言程序中,第 1 個(gè)使用關(guān)鍵詞_irq 聲明,第2個(gè)沒(méi)有使用關(guān)鍵詞_irq聲明。
程序 6.4 關(guān)鍵詞_irq 的作用
;第1 個(gè)程序使用關(guān)鍵詞_irq 聲明
_irq void IRQHandler (void)
{
Volatile unsigned int *base=(unsigned int *)0x8000000;
If (*base 1)
{
//調(diào)用相應(yīng)的 C 語(yǔ)言處理程序
C_int_Handler ();
}
//清除中斷標(biāo)志
*(base=1)=0;
}
;第1 個(gè)C 語(yǔ)言程序?qū)?yīng)的匯編程序
IRQHandler PROC
STMFD sp!,(r0-r4,r12,lr)
MOV r4,#0x8000000
LDR r0,(r4,#0)
SUB sp,sp,#4
CMP r0,#1
BLEQ Q_int_handler
MOV r0,#0
STR r0,(r4,#4)
ADD sp,sp,#4
LDMFD sp!,(r0-r4,r12,lr)
SUBS pc,lr,#4
ENDP
BXPORT IRQHandler
//第2 個(gè)程序沒(méi)有使用關(guān)鍵詞_irq 聲明
_irq void IRQHandler (void)
{
Volatile unsigned int *base=(unsigned int *) 0x80000;
If(*base 1)
{
//調(diào)用相應(yīng)的 C 語(yǔ)言處理程序
C_int_handler();
}
//清除中斷標(biāo)志
*(base+1)=0;
}
;第1 個(gè)C 語(yǔ)言程序?qū)?yīng)的匯編程序
IRQHandler PROC
STMFD sp!(r4,lr)
MOV r4,#0x8000000
LDR r0,(r4,#0)
CMP r0,#1
SLEQ C_int_handler
MOV r0,#0
STR r0,(r4,#4)
LDMFD sp!(r4,pc)
ENDP
② 可重入的 IRQ/FIQ 異常中斷處理程序
如果在可重入的 IRQ/FIQ 異常中斷處理程序中調(diào)用了子程序,子程序的返回地址被保存
到寄存器的 LR_irq 中,這時(shí)如果發(fā)生了 IRQ/FIQ異常中斷,這個(gè) LR_irq寄存器的值將
被破壞,那么被調(diào)用的子程序?qū)⒉荒苷_的返回。因此,對(duì)于可重入的 IRQ/FIQ異常中
斷處理程序一些需要特別的操作。下面列出了在可重入的 IRQ/FIQ 異常中斷處理程序中
需要的操作。這時(shí),第1 級(jí)中斷處理程序不能使用 C 語(yǔ)言,因?yàn)槠渲幸恍┎僮鞑荒芡ㄟ^(guò)
C 語(yǔ)言實(shí)現(xiàn):
● 將返回地址保存到 IRQ的數(shù)據(jù)棧中。
● 保存工作寄存器和 SPSR_irq。
● 清除中斷標(biāo)志位。
● 將處理器切換到系統(tǒng)模式,重新使能中斷(IRQ/FIQ)。
● 保存用戶模式的 LR 寄存器和被調(diào)用者的不保存的寄存器。
● 調(diào)用 C 語(yǔ)言的 IRQ/FIQ異常中斷處理程序。
● 當(dāng) C 語(yǔ)言的 IRQ/FIQ 異常中斷程序返回后,恢復(fù)用戶模式的寄存器,并禁止中斷
(IRQ/FIQ)。
● 切換到 IRQ模式,禁止中斷。
● 恢復(fù)工作組寄存器和寄存器 LR_irq。
● 從 IRQ 異常中斷處理程序中返回。
下面程序 6.5 演示了這些操作的過(guò)程。
程序6.5 可重入的 IRQ/FIQ 異常中斷處理程序
AREA INTERRUPT ,CODE,PEADONJY
;引入C語(yǔ)言的 IRQ中斷處理程序 C_irq_handler
IMPORT C_irq_handler
IRQ
;保存返回 IRQ 處理程序地址
SUB lr,lr,#4
STMFD sp! ,(lr)
保存 SPSR_irq,及其他工作寄存器
MRS r14,SPSR
STMFD sp!,lr12,r14
;
;在這里添加指令,清除中斷標(biāo)志位
;添加指令重新使能中斷
;
;切換到系統(tǒng)模式,并使能中斷
MSR CPSR_C,#0x1f
;保存用戶模式的 LR_usr 及被調(diào)用者不保存寄存器
STMFD sp!,(r0-r3,lr)
;跳轉(zhuǎn)到C 語(yǔ)言的中斷處理程序
BL C_irq_handler
;恢復(fù)用戶模式的寄存器
LDMFD sp!,(r0-r3,lr)
;切換到IRQ 模式,禁止 IRQ 中斷,F(xiàn)IQ 中斷允許
MSR CPSP_c,#0x92
;恢復(fù)工作寄存器和 SPSR_irq
LDMFD sp!,(pc)^
END
6.2.2 復(fù)位中的異常中斷處理程序
復(fù)位異常中斷處理程序在系統(tǒng)加電或復(fù)位時(shí)執(zhí)行,它將進(jìn)行一些初始化的工作,具體內(nèi)
容與復(fù)位系統(tǒng)相關(guān),然后程序控制權(quán)交給應(yīng)用程序,因而復(fù)位異常中斷處理程序不需要返回。
下面時(shí)通常在復(fù)位異常中斷處理程序進(jìn)行的一些處理:
● 設(shè)置異常中斷向量表。
● 初始化數(shù)據(jù)棧和寄存器。
● 初始化存儲(chǔ)系統(tǒng),如系統(tǒng)中的 MMU等。
● 初始化一些關(guān)鍵的 I/O設(shè)備。
● 使用中斷。
● 將處理器切換到會(huì)話模式。
● 初始化 C 語(yǔ)言環(huán)境變量,條狀到應(yīng)用程序執(zhí)行。
6.2.3 C 語(yǔ)言程序中的異常中斷處理程序
在程序運(yùn)行過(guò)程中,也可以在 C 語(yǔ)言程序中安裝異常中斷處理程序。這時(shí)需要把相應(yīng)的跳
轉(zhuǎn)指令或者數(shù)據(jù)讀取指令的編碼寫到中斷向量表的響應(yīng)位置。下面分別討論這兩種情況下安
裝異常中斷處理程序的方法。
1.中斷向量表中使用跳轉(zhuǎn)指令的情況
當(dāng)中斷向量表中使用跳轉(zhuǎn)指令時(shí),在 C 程序中安裝異常中斷處理程序的操作如下:
(1) 讀取中斷處理程序的地址。
(2 ) 從上一步得到的地址中減去該異常中斷對(duì)應(yīng)的中斷向量的地址。
(3) 從上一步得到的地址中減去 8,以允許指令的預(yù)取。
(4 ) 將上一步得到的地址右移 2 位,得到以字(32位)為單位的偏移量。
(5) 確保上一步得到的地址高 8 位為0,因?yàn)樘D(zhuǎn)指令只允許 24位的偏移量。
(6) 將上一步得到的地址與數(shù)據(jù) 0xea000000 作邏輯或,從而得到將要寫到中斷向
量表的跳轉(zhuǎn)指令的編碼。
以上具體操作通過(guò)程序 6.6 實(shí)現(xiàn)下面的 C 程序。其中參數(shù) routine 是中斷處理程序
的地址,vector 為中斷向量的地址。
程序 6.6 使用跳轉(zhuǎn)指令的中斷向量表
Unsigned install_handler (unsigned routine ,unsigned *vector)
{ unsigned vec, oldvec;
vec=((routine-(unsigned)vector-0x8)>>2);
If (vec & 0xff000000)
{
Printf(“Installation of handler failed” )
exit (2);
}
vec=0xea000000|vec;
oldvec=^vector;
*vector=vec;
return (oldvec);
}
2. 中斷向量表中使用數(shù)據(jù)讀取指令的情況
當(dāng)中斷向量表中使用數(shù)據(jù)讀取指令時(shí),在 C 程序中安裝異常中斷處理程序的操作序列如下
所示:
(1) 讀取中斷處理程序的地址。
(2) 從上一步得到的地址中減去該異常中斷對(duì)應(yīng)的中斷向量的地址。
(3) 從上一步得到的地址中減去 8,允許指令預(yù)取。
(4) 將上一步得到的地址與數(shù)據(jù) 0xe59f000 作邏輯或,從而得到將要寫到中斷向量
表中的數(shù)據(jù)讀取指令的編碼。
(5) 將中斷處理程序的地址放到相應(yīng)的存儲(chǔ)單元。
程序 6.7中的 C 程序?qū)崿F(xiàn)了上面的操作序列。其中參數(shù) location 是一個(gè)存儲(chǔ)單元,其中
保存了中斷處理程序的地址;vector 為中斷向量的地址。
程序6.7 數(shù)據(jù)讀取指令的中斷向量表
Unsigned Install_Handler (unsigned location ,unsigned *vector)
{ unsigned vec ,oldvec;
Vec=((unsigned)location-(unsigned)vector-0x8) | (0xe59ff0000 oldvec -
*vector;
*vector=vec;
Return (oldvec);
}
下面的語(yǔ)句調(diào)用上面的代碼,在 C 程序中安裝中斷處理程序。
Unsigned *irqvec=(unsigned *)0x18;
Install_Handler ((unsigned)IRQHandler,irqvec);
6.3 其它種類的異常中斷
1.?dāng)?shù)據(jù)訪問(wèn)中止異常中斷處理程序
如果系統(tǒng)不包含 MMU,數(shù)據(jù)訪問(wèn)中止異常中斷處理程序只是簡(jiǎn)單地報(bào)告錯(cuò)誤,然后退出。如
果系統(tǒng)中包含 MMU,數(shù)據(jù)訪問(wèn)中止異常中斷處理程序要處理該數(shù)據(jù)訪問(wèn)中止。當(dāng)發(fā)生數(shù)據(jù)訪
問(wèn)中止異常中斷的指令時(shí)。LR_abt 寄存器已經(jīng)被更新,它指向引起數(shù)據(jù)訪問(wèn)中止異常中斷
的指令后面第 2 條指令。此時(shí)要返回到引起數(shù)據(jù)訪問(wèn)中止異常中斷的指令。即(LR_abt)處。
下面3 種情況可能引起數(shù)據(jù)訪問(wèn)中止異常中斷。
① LDR/STR 指令
對(duì)于 ARM 數(shù)據(jù)訪問(wèn)中止異常中斷發(fā)生時(shí),LR_abt 寄存器已經(jīng)被更新,它指向引起數(shù)據(jù)訪問(wèn)
中止異常中斷的指令后面第 2 條指令,此時(shí)要返回到引起數(shù)據(jù)訪問(wèn)中止異常中斷的指令。
對(duì)于 ARM9、ARM10、strongARM 處理器,數(shù)據(jù)訪問(wèn)中止異常中斷發(fā)生后,處理器將程序計(jì)數(shù)
器設(shè)置稱引起數(shù)據(jù)訪問(wèn)中止異常中斷的指令的地址,不需要用戶來(lái)完成這種程序計(jì)數(shù)器的設(shè)
置操作。
② SWAP 指令
SWAP 指令執(zhí)行時(shí),未更新及存取 LR_abt.
③ LDM/STM 指令
對(duì)于 ARM6及 ARM7 處理器,如果寫回機(jī)制使能的話,基址寄存器將被更新。對(duì)于 ARM9、ARM10
及 strongARM 處理器,如果寫回機(jī)制使能的話,數(shù)據(jù)訪問(wèn)中止異常中斷發(fā)生時(shí),處理器將恢
復(fù)基址寄存器的值。
3.指令預(yù)取中止異常中斷處理程序
如果系統(tǒng)不包含 MMC,指令預(yù)取中止異常中斷處理程序只是簡(jiǎn)單地報(bào)告錯(cuò)誤,然后退出。
如果系統(tǒng)中包含 MMU,則發(fā)生錯(cuò)誤的指令觸發(fā)虛擬地址失效,在該失效處理程序中重新
讀取該指令。指令預(yù)取中止異常中斷是有錯(cuò)的指令執(zhí)行時(shí)被觸發(fā)是,這時(shí) LR_abt 寄存
器還沒(méi)有被更新,它指向該指令的下面一條指令。因?yàn)樵撚袉?wèn)題的指令要被重新讀取,
因而應(yīng)該返回到該有問(wèn)題的指令,即返回到(LR_abt-4)處。
4.未定義指令異常中斷
當(dāng) CPU 不認(rèn)識(shí)當(dāng)前指令時(shí),它將該指令發(fā)送到協(xié)處理器。如果所以的協(xié)處理器都不認(rèn)識(shí)
該指令,這時(shí)將產(chǎn)生未定義指令異常中斷。在未定義指令異常中斷進(jìn)行響應(yīng)的處理???wbr />
以看出這種機(jī)制可以用來(lái)通過(guò)軟件仿真系統(tǒng)中一些部件的功能。比如,如果系統(tǒng)中不包
含浮點(diǎn)運(yùn)算部件,CPU 遇到浮點(diǎn)運(yùn)算指令時(shí)。將發(fā)生未定義指令異常中斷,在該未定義
指令異常中斷的處理程序中可以通過(guò)其他指令序列仿真該浮點(diǎn)運(yùn)算指令。
這種仿真的處理過(guò)程類似有 SWI異常中斷的功能調(diào)用。在 SWI 異常中斷的功能調(diào)用中
通過(guò)讀取 SWI 指令中的 24 位的立即數(shù)。判斷具體請(qǐng)求的 SWI 功能。這種仿真機(jī)制的操
作過(guò)程如下:
① 將仿真程序設(shè)置成未定義指令異常中斷的中斷處理程序(鏈接到未定義指令異常中
斷的中斷處理程序鏈中),并保存原來(lái)的中斷處理程序。這是通過(guò)修改中斷向量表
中未定義指令異常中斷對(duì)應(yīng)的中斷向量來(lái)實(shí)現(xiàn)的。
② 讀取該未定義的位[27:24],判斷該未定義指令是否是一個(gè)協(xié)處理器指令。當(dāng)位
[27:24]為 0b1110 或 0b110x 時(shí),該未定義指令時(shí)一個(gè)協(xié)處理器指令。接著讀取該
未定義的指令的位[11:8],如果位[11:8]指定通過(guò)仿真程序?qū)崿F(xiàn)該未定義指令,則
相應(yīng)的調(diào)用仿真程序?qū)崿F(xiàn)該指令的功能,后來(lái)返回到用戶程序。
③ 如果不仿真該未定義指令,程序跳轉(zhuǎn)到原來(lái)的未定義指令異常中斷的中斷處理程序
執(zhí)行。
Thumb 指令集中不包含協(xié)處理器指令,因而不需要這種仿真機(jī)制。
評(píng)論