您的位置 首页 ADAS

异常中断处理程序

6.2.1异常中断处理程序的方法种类及其介绍1.SWI异常中断处理程序的实现在SWI指令中包括一个24位的立即数,该立即数指示了…

6.2.1 反常间断处理程序的办法品种及其介绍

1.SWI 反常间断处理程序的完结
在 SWI 指令中包括一个 24 位的当即数,该当即数指示了用户恳求的特定的 SWI 功用。在
SWI 反常间断处理程序要读取该 24 位的当即数,这涉及到 SWI反常形式下对存放器 LR的读
取,而且要从存储器读取该 SWI 指令。这样需求运用汇编程序来完结。一般 SWI反常间断处
理程序分为两级:第 1 级 SWI 反常间断处理程序为汇编,用于确认 SWI 指令中的 24 位的立
即数;第 2级 SWI 反常间断处理程序详细完结 SWI 的各个功用,它可所以汇编程序,也能够
时 C 程序,下面咱们别离介绍这两级。
● SWI 反常间断调用
① 在特权形式下调用 SWI
履行 SWI 指令后,体系将会把 CPSR 存放器的内容保存到存放器 SPSR_SVC 中,
将回来地址保存到存放器 LR_svc 中。这样假如履行 SWI 指令时,体系现已处于
特权形式下,这时存放器 SPSR_svc 和存放器 LR_svc 中的内容就会被损坏。因
此假如在特权形式下调用 SWI 功用,比方在一个 SWI 反常间断处理程序中履行
SWI指令,就有必要将原始的存放器SPSR_svc和存放器LR_svc值保存在数据栈中。
程序6.1阐明在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)
;核算其间的 24 位当即数,并将其放入存放器 R0 中
BIC r0,r0.#0xff000000
;调用C_SWI_Handler 完结相应的 SWI 功用
BL C_SWI_Handler
;康复SPSR_svc 的值
LDMFD sp!,(r0)
MSB spsr_cf,r0
;康复其他存放器,包括存放器 LR_svc
LDMFD sp!,(r0-r3,r12,pc)^
② 从应用程序中调用 SWI
这儿分两种状况考虑从应用程序中调用特定的 SWI 功用:一种考虑运用汇编指
令调用特定的 SWI 功用;一种考虑从 C 言语程序中调用特定的 SWI 功用。
运用汇编指令调用特定的 SWI 功用比较简略,将需求的参数依照 ATPCS 的要求
放在相应的存放器中,然后在指令 SWI 中指定相应 24 位当即数即可。下面的例
子中,SWI 间断处理程序需求的参数放在存放器 R0 中,这儿该参数为 100,然
后调用功用号为 0x0 的SWI 功用调用。
MOV R0,#100
SWI 0x0
从 C 言语程序中调用特定的 SWI 功用比较复杂,由于这时需求将一个 C 程序的
子程序调用映射到一个 SWI 反常间断处理程序。这些被映射的 C 言语子程序使
用编译器伪操作__SWI 来声明。假如该子程序需求的参数和回来的成果只运用寄
存器 R0~R3,则该 SWI 能够被编译成 inline 的,不需求运用子程序调用进程。
不然有必要告知编译器经过结构数据类型来回来参数,这时需求运用编译器伪操
作_value_in_reg 声明该C 言语子程序。
下面经过一个完好的比方来阐明怎么从 C 程序中调用特定的 SWI 功用,该比方
是 ARM 公司的 ADS1.2 中所带的。该比方供给的 4 个SWI 功用调用,功用号别离
为 0x0,0x1,0x2,0x3。其间 SWI 0x0及 SWI 0x1 运用两个整形的输入参数,并返
回一个成果值,SWI 0x2运用 4 个输入参数,并回来一个成果值;SWI 0x3 运用
4 个输入参数,并回来 4个成果值。
整个 SWI 反常间断处理程序分为两级结构。第 1 级的 SWI 反常间断处理程序是
汇编程序 SWI_HANDLER,它读取 SWI 指令中的 24 位当即数,然后调用第 2 个级
SWI 反常间断处理程序 C_SWI_HANDLER来完结详细的 SWI 功用。第 2 级SWI反常
中谷底你处理程序 C_SWI_HANDLER 为 C 言语程序。其间完结了功用号别离为
0x0,0x1,0x2,0x3的 SWI功用调用。
主程序中的子程序 multiply_two()对应着 SWI 0x0;add_two()对应着
0x1;add_multiply_two()对应着 0x2;many_operations()对应着 SWI 0x3。
Many_operations()回来 4 个成果,运用编译器伪操作_valuc_in_reg 声明。4
个子程序都运用编译器伪操作__SWI来声明。主程序运用 lnstall_Handler()来
装置该 SWI反常间断处理程序,lnstall_Handler()在前面现已有详细的介绍。
整个代码如程序 6.2 所示。
程序 6.2 从C 程序中调用特定的 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)=%d\n”,
Result1=multiply_two(2,4));
Printf(“result2=mutiply_two (3,6)=%d\n”,
Result2=multiply_two(3,6));
Printf(“add_two(result1,result2 ) =%d\n, add_two(result1,result2));
Printf(‘add_multiply_two(2,4,3,6)=&d\n”,add_multiply_two(2,4,3,6));
Res_3=many_operations(12,4,3,1);
Printf(“res_3.a=&d\n”,res_3.a);
Printf(“res_3.b=&d\n”,res_3.b);
Printf(“res_3.c=&d\n”,res_3.c);
Printf(“res_3.d=&d\n”,res_3.d);
Return 0;
}
;第1 级SWI 反常间断处理程序 SWI_Handler
;SWI_Handler 在前面已有详细介绍
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)
{
//对应于SWI 0x0
case 0:
regs[0]=regs[0]*regs[1];
break;
//对应于SWI 0x1
case 1:
regs[0]=regs[0]+ regs[1];
break;
//对应于SWI 0x2
case 2:
regs[0]=(regs[0]*regs[1]) +(regs[2]*regs[3]);
break;
//对应于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;
}
}
③ 从应用程序中动态调用 SWI
在有些状况下,直到运转时才能够确认需求调用的 SWI 功用号。这时,有两种
办法处理这种状况。
第 1 种办法是在运转时得到 SWI 功用号,然后构造出相应的 SWI 指令的编码,
把这个指令的编码保存在一个存储器单元中,履行该指令即可。
第 2 种办法运用一个通用的 SWI 反常间断处理程序,将运转时需求调用的 SWI
功用号作为参数传递给该通用的 SWI 反常间断处理程序,通用的 SWI 反常间断
处理程序依据参数值调用相应的 SWI 处理程序完结需求的操作。
在汇编程序中很简略完结第 2 中办法。在履行 SWI 指令之前先将需求调用的 SWI
功用号放在一个存放器。在通用的 SWI 反常间断处理程序读取该存放器值,决
定需求履行的操作,但有些 SWI 处理程序需求 SWI 指令的 24位当即数,因此上
述两种办法常常组合运用。
在操作体系中一般运用一个 SWI 功用号和一个存放器来供给许多的 SWI 功用调
用。这样能够将其他的 SWI 功用号留给用户运用。在 DOS 体系中,DOS 供给功用
调用是 INT 21H ,这时经过指定存放器 AX 的值,能够完结许多不同的功用调用。
ARM 体系中semihost 的完结也是一个比方。ARM 程序运用 SWI 0x123456 来完结
semilhost 功用调用;Thunb 程序运用SWI 0xAB 来完结 semihost 功用调用。在
下面的比方中,将子程序 WRITEC (unsigned op,char *c)映射到 semihost
功用调用,详细 semihost SWI 的子功用号经过参数 op 传递。
程序 6.3 从应用程序中动态调用 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 反常间断用于外部设备向 CPU 恳求间断服务。这两个反常间断的引脚
都是低电平有用的。当时程序状况存放器 CPSR 的 1 操控位能够屏蔽这两个反常间断恳求;
当程序状况存放器 CPSR由 1 操控位位 0 时,CPU正常呼应 FIQ 和IRQ 反常间断恳求。
FIQ 反常间断为快速反常间断,它比 IRQ 反常间断优先级高,这首要体现鄙人面的两个方
面:
● 当 FIQ 和IRQ 反常间断一同产生时,CPU 先处理 FIQ 反常间断。
● 在 FIQ 反常间断处理程序中 IRQ 反常间断被制止。
由于 FIQ 反常间断一般用于体系关于呼应时刻要求比较严苛的使命,ARM 体系在规划上有
一些特其他组织,以尽量削减 FIQ 反常间断呼应时刻。FIQ 反常间断的间断向量为 0x1c,位
于间断向量表的最终。这样 FIQ 反常间断处理程序能够直接放在地址 0x1c 开端的存储单元,
这种组织省掉了间断向量表的跳转指令,然后也就节省了间断呼应时刻。当体系中存在
cache 时,能够把 FIQ 反常间断向量以及处理程序一同锁在 cache 中,然后大大地提高了
FIQ 反常间断呼应时刻。除此之外,与其他的反常形式比较,FIQ 反常间断还有额定的 5 个
物理存放器,这样在进入 FIQ 处理程序时能够保存这 5 个存放器,然后也提高了 FIQ 反常中
断的履行速度。
在有些 IRQ/FIQ 反常间断处理程序中,答应新的 IRQ/FIQ 反常间断,这时将需求一些特
其他操作保证“老的”反常间断的存放器不会“新的”反常间断损坏,这种 IRQ/FIQ 反常中
断处理程序称为可重入的反常间断处理程序。不然称为不行重入的反常间断处理程序。
① 不行重入的 IRQ/FIQ 反常间断处理程序
关于 C 言语不行重入的 IRQ/FIQ 反常间断处理程序能够运用要害词_irq来阐明。要害词
_irq 能够完结下面的操作:
● 保存 APCS 规则的被损坏的存放器。
● 保存其他间断处理程序中用到的存放器。
● 一同将(LD-4)赋予程序计数器 pc 完结间断处理程序的回来,而且康复 CPSR 寄
存器的内容。
当 IRQ/FIQ反常间断处理程序调用了子程序时,要害词_irq能够使 IRQ/FIQ 反常间断
处理程序回来时从其数据栈中读取 LR_irq 值,并经过 SUBS PC,LR,#4 完结回来。程序
6.4 阐明的要害词_irq 的效果,其间列出了 C 言语程序及其对应的汇编程序,两个 C
言语程序中,第 1 个运用要害词_irq 声明,第2个没有运用要害词_irq声明。
程序 6.4 要害词_irq 的效果
;第1 个程序运用要害词_irq 声明
_irq void IRQHandler (void)
{
Volatile unsigned int *base=(unsigned int *)0x8000000;
If (*base 1)
{
//调用相应的 C 言语处理程序
C_int_Handler ();
}
//铲除间断标志
*(base=1)=0;
}
;第1 个C 言语程序对应的汇编程序
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 个程序没有运用要害词_irq 声明
_irq void IRQHandler (void)
{
Volatile unsigned int *base=(unsigned int *) 0x80000;
If(*base 1)
{
//调用相应的 C 言语处理程序
C_int_handler();
}
//铲除间断标志
*(base+1)=0;
}
;第1 个C 言语程序对应的汇编程序
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 反常间断处理程序中调用了子程序,子程序的回来地址被保存
到存放器的 LR_irq 中,这时假如产生了 IRQ/FIQ反常间断,这个 LR_irq存放器的值将
被损坏,那么被调用的子程序将不能正确的回来。因此,关于可重入的 IRQ/FIQ反常中
断处理程序一些需求特其他操作。下面列出了在可重入的 IRQ/FIQ 反常间断处理程序中
需求的操作。这时,第1 级间断处理程序不能运用 C 言语,由于其间一些操作不能经过
C 言语完结:
● 将回来地址保存到 IRQ的数据栈中。
● 保存作业存放器和 SPSR_irq。
● 铲除间断标志位。
● 将处理器切换到体系形式,从头使能间断(IRQ/FIQ)。
● 保存用户形式的 LR 存放器和被调用者的不保存的存放器。
● 调用 C 言语的 IRQ/FIQ反常间断处理程序。
● 当 C 言语的 IRQ/FIQ 反常间断程序回来后,康复用户形式的存放器,并制止间断
(IRQ/FIQ)。
● 切换到 IRQ形式,制止间断。
● 康复作业组存放器和存放器 LR_irq。
● 从 IRQ 反常间断处理程序中回来。
下面程序 6.5 演示了这些操作的进程。
程序6.5 可重入的 IRQ/FIQ 反常间断处理程序
AREA INTERRUPT ,CODE,PEADONJY
;引进C言语的 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
;
;在这儿增加指令,铲除间断标志位
;增加指令从头使能间断
;
;切换到体系形式,并使能间断
MSR CPSR_C,#0x1f
;保存用户形式的 LR_usr 及被调用者不保存存放器
STMFD sp!,(r0-r3,lr)
;跳转到C 言语的间断处理程序
BL C_irq_handler
;康复用户形式的存放器
LDMFD sp!,(r0-r3,lr)
;切换到IRQ 形式,制止 IRQ 间断,FIQ 间断答应
MSR CPSP_c,#0x92
;康复作业存放器和 SPSR_irq
LDMFD sp!,(pc)^
END
6.2.2 复位中的反常间断处理程序
复位反常间断处理程序在体系加电或复位时履行,它将进行一些初始化的作业,详细内
容与复位体系相关,然后程序操控权交给应用程序,因此复位反常间断处理程序不需求回来。
下面时一般在复位反常间断处理程序进行的一些处理:
● 设置反常间断向量表。
● 初始化数据栈和存放器。
● 初始化存储体系,如体系中的 MMU等。
● 初始化一些要害的 I/O设备。
● 运用间断。
● 将处理器切换到会话形式。
● 初始化 C 言语环境变量,条状到应用程序履行。
6.2.3 C 言语程序中的反常间断处理程序
在程序运转进程中,也能够在 C 言语程序中装置反常间断处理程序。这时需求把相应的跳
转指令或许数据读取指令的编码写到间断向量表的呼应方位。下面别离评论这两种状况下安
装反常间断处理程序的办法。
1.间断向量表中运用跳转指令的状况
当间断向量表中运用跳转指令时,在 C 程序中装置反常间断处理程序的操作如下:
(1) 读取间断处理程序的地址。
(2 ) 从上一步得到的地址中减去该反常间断对应的间断向量的地址。
(3) 从上一步得到的地址中减去 8,以答应指令的预取。
(4 ) 将上一步得到的地址右移 2 位,得到以字(32位)为单位的偏移量。
(5) 保证上一步得到的地址高 8 位为0,由于跳转指令只答应 24位的偏移量。
(6) 将上一步得到的地址与数据 0xea000000 作逻辑或,然后得到即将写到间断向
量表的跳转指令的编码。
以上详细操作通进程序 6.6 完结下面的 C 程序。其间参数 routine 是间断处理程序
的地址,vector 为间断向量的地址。
程序 6.6 运用跳转指令的间断向量表
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. 间断向量表中运用数据读取指令的状况
当间断向量表中运用数据读取指令时,在 C 程序中装置反常间断处理程序的操作序列如下
所示:
(1) 读取间断处理程序的地址。
(2) 从上一步得到的地址中减去该反常间断对应的间断向量的地址。
(3) 从上一步得到的地址中减去 8,答应指令预取。
(4) 将上一步得到的地址与数据 0xe59f000 作逻辑或,然后得到即将写到间断向量
表中的数据读取指令的编码。
(5) 将间断处理程序的地址放到相应的存储单元。
程序 6.7中的 C 程序完结了上面的操作序列。其间参数 location 是一个存储单元,其间
保存了间断处理程序的地址;vector 为间断向量的地址。
程序6.7 数据读取指令的间断向量表
Unsigned Install_Handler (unsigned location ,unsigned *vector)
{ unsigned vec ,oldvec;
Vec=((unsigned)location-(unsigned)vector-0x8) | (0xe59ff0000 oldvec
*vector;
*vector=vec;
Return (oldvec);
}
下面的句子调用上面的代码,在 C 程序中装置间断处理程序。
Unsigned *irqvec=(unsigned *)0x18;
Install_Handler ((unsigned)IRQHandler,irqvec);
6.3 其它品种的反常间断
1.数据拜访间断反常间断处理程序
假如体系不包括 MMU,数据拜访间断反常间断处理程序仅仅简略地陈述过错,然后退出。如
果体系中包括 MMU,数据拜访间断反常间断处理程序要处理该数据拜访间断。当产生数据访
问间断反常间断的指令时。LR_abt 存放器现已被更新,它指向引起数据拜访间断反常间断
的指令后边第 2 条指令。此刻要回来到引起数据拜访间断反常间断的指令。即(LR_abt)处。
下面3 种状况或许引起数据拜访间断反常间断。
① LDR/STR 指令
关于 ARM 数据拜访间断反常间断产生时,LR_abt 存放器现已被更新,它指向引起数据拜访
间断反常间断的指令后边第 2 条指令,此刻要回来到引起数据拜访间断反常间断的指令。
关于 ARM9、ARM10、strongARM 处理器,数据拜访间断反常间断产生后,处理器将程序计数
器设置称引起数据拜访间断反常间断的指令的地址,不需求用户来完结这种程序计数器的设
置操作。
② SWAP 指令
SWAP 指令履行时,未更新及存取 LR_abt.
③ LDM/STM 指令
关于 ARM6及 ARM7 处理器,假如写回机制使能的话,基址存放器将被更新。关于 ARM9、ARM10
及 strongARM 处理器,假如写回机制使能的话,数据拜访间断反常间断产生时,处理器将恢
复基址存放器的值。
3.指令预取间断反常间断处理程序
假如体系不包括 MMC,指令预取间断反常间断处理程序仅仅简略地陈述过错,然后退出。
假如体系中包括 MMU,则产生过错的指令触发虚拟地址失效,在该失效处理程序中从头
读取该指令。指令预取间断反常间断是有错的指令履行时被触发是,这时 LR_abt 存放
器还没有被更新,它指向该指令的下面一条指令。由于该有问题的指令要被从头读取,
因此应该回来到该有问题的指令,即回来到(LR_abt-4)处。
4.未定义指令反常间断
当 CPU 不知道当时指令时,它将该指令发送到协处理器。假如所以的协处理器都不知道
该指令,这时将产生未定义指令反常间断。在未定义指令反常间断进行呼应的处理。可
以看出这种机制能够用来经过软件仿真体系中一些部件的功用。比方,假如体系中不包
含浮点运算部件,CPU 遇到浮点运算指令时。将产生未定义指令反常间断,在该未定义
指令反常间断的处理程序中能够经过其他指令序列仿真该浮点运算指令。
这种仿真的处理进程相似有 SWI反常间断的功用调用。在 SWI 反常间断的功用调用中
经过读取 SWI 指令中的 24 位的当即数。判别详细恳求的 SWI 功用。这种仿真机制的操
作进程如下:
① 将仿真程序设置成未定义指令反常间断的间断处理程序(链接到未定义指令反常中
断的间断处理程序链中),并保存本来的间断处理程序。这是经过修正间断向量表
中未定义指令反常间断对应的间断向量来完结的。
② 读取该未定义的位[27:24],判别该未定义指令是否是一个协处理器指令。当位
[27:24]为 0b1110 或 0b110x 时,该未定义指令时一个协处理器指令。接着读取该
未定义的指令的位[11:8],假如位[11:8]指定经过仿真程序完结该未定义指令,则
相应的调用仿真程序完结该指令的功用,后来回来到用户程序。
③ 假如不仿真该未定义指令,程序跳转到本来的未定义指令反常间断的间断处理程序
履行。
Thumb 指令会集不包括协处理器指令,因此不需求这种仿真机制。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qiche/adas/262727.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部