历史上的今天
今天是:2024年11月26日(星期二)
2021年11月26日 | ARM基础学习-SWI异常中断处理
2021-11-26 来源:eefocus
在ARM处理器中,我们常常使用SWI指令来产生一个软中断。软中断指令SWI指令中包含了一个24位的立即数,这个立即数指示了用户请求的特定的SWI功能,即这个立即数表示的是SWI指令所想要触发中断的中断号。
所以,当SWI指令触发了一次异常后进入异常处理的程序时,异常程序必须要从SWI指令中提取出来中断号,即提出出来SWI指令中低24位的值,从而得到用户请求的特定的SWI功能。
SWI异常处理程序
通常情况下,SWI异常中断处理函数分为两级,第一级的SWI处理函数用于从SWI指令中提取24位的立即数即中断号,通第一级函数通过汇编语言、内嵌汇编来完成。第二级SWI异常中断处理程序实现各个SWI的具体功能,第二级程序可以是汇编程序,也可以是C程序。
第一级SWI异常处理程序通过LR寄存器内容得到SWI指令地址,LR寄存器中保存的是该SWI指令的下一条指令的地址,并从存储器中得到SWI指令编码,从而提取出来24位中断号。下面的例子显示了提取中断向量号的标准过程。
.SWI_Handler:
STMFD sp!,{r0-r12,lr} ;保存寄存器
LDR r0,[lr,#-4] ;计算SWI指令地址
BIC r0,r0,#0xff000000 ;提取指令编码的后24位
;
; 提取出的中断号放r0寄存器,函数返回
;
LDMFD sp!, {r0-r12,pc}^ ;恢复寄存器
第二级中断处理函数(根据提取的中断向量号,跳转到具体处理函数)却可以使用C语言来完成。因为第一级的中断处理函数已经将中断号提取到寄存器r0中,所以根据AAPCS函数调用规则,可以直接使用BL指令跳转到C语言函数,而且中断向量号作为第一个参数被传递到C函数。
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 */
}
}
另外,如果需要传递的参数多于1个,那么可以使用堆栈,将堆栈指针作为函数的参数传递给C类型的二级中断处理程序,就可以实现在两级中断之间传递多个参数。
例如:
MOV r1, sp ;将传递的第二个参数(堆栈指针)放到r1中
BL C_SWI_Handler ;调用C函数
相应的C函数的入口变为:
void C_SWI_handler(unsigned number, unsigned *reg)
在2级中断处理程序,可以通过下面的操作数读取参数,这些参数是在SWI异常中断产生时各寄存器的值,这些寄存器保存在SWI异常中断的数据栈中:
value_in_reg_0 =reg [0];
value_in_reg_1 =reg [1];
value_in_reg_2 =reg [2];
value_in_reg_3= reg [3];
SWI异常中断调用
(1) 在特权模式下调用SWI
比如在中断模式下调用SWI,系统此时已经属于特权模式,这是在调用SWI会破坏SPSR_svc和寄存器LR_svc,所以在调用SWI前保存SPSR_svc和寄存器LR_svc在数据栈中:
STMFD sp!,{r0-r3,r12,lr}
MOV r1,sp;
MRS r0,spsr;
STMFD sp!,[r0];
...
SWI
...
LDMFD sp!,{r0};
MSR spsr_cf,r0;
LDMFD sp!, {r0-r3,r12,pc}^ ;
(2)应用程序中调用SWI
最简单的是用汇编:
MOV r0,#100;
SWI 0x0;
C语言调用SWI比较复杂,因为这时需要将一个C程序的子程序调用映射到一个SWI异常中断程序,这些被映射的C语言子程序使用编译器伪操作_SWI来声明,如果该子程序需要的参数和返回结果只使用R0~R3寄存器,则该SWI可以编译成inline,不需要使用子程序调用过程,否则编译器需要用数据结构来返回参数,这时需要用伪操作_value_in_reg声明该C语言程序;
需要安装异常中断处理程序到向量表中相对位置;
详细参考ARM体系结构与编程P-272;
下一篇:ARM基础学习-异常中断处理
史海拾趣
|
我写了个1602+1302的程序,在调试的时候,总是不能显示第一个字母, 不如说我要写TIME,它就只会显示IME, 中间再写 ,write_com(写命令), 然后后面接着写东西的话,第一个字母也是不显示,但是闪过之后又显示, 然后又不显示,就这样循环, ...… 查看全部问答> |
|
我编完程序,在ADS1.2中编译时,在2410init.s中有2个错误。error 1, unkonwn opcode: AREA Init,CODE,READONLY,程序接下来是ENTRY ,报错,error 2 ,A label was found which was in no AREA,请教大家,这是怎么回事?… 查看全部问答> |
|
已打过07年全年补丁.目前能支持2G SD卡.看了网上支持大容量SD卡的文章. [url=http://www.cnblogs.com/wogoyixikexie/archive/2009/05/06/1450503.html][/url] 测试了后连普通的2G SD卡也检测不到. 修改前sdbus.dll大小为49K, 在platform->setti ...… 查看全部问答> |
|
TI Stellaris学习笔记(使用openocd(基于mingw)调试LM3S811开发板环境的搭建) LM3S811开发板学习笔记---使用openocd(基于mingw)调试LM3S811开发板环境的搭建收到网站的LM3S811开发板,不能放那浪费了。因本人在linux环境下开发的较多,对keil和iar等环境也不是很熟悉而且他们是商业软件,使用D版毕竟不太好,这里就以如何使用 ...… 查看全部问答> |
|
主要应用案例: 3700系列产品可以用于电源(PC、网络、电信)老化测试。类似的使用案例包括环境应力筛选(ESS)以及高加速应力筛选(HALT)。 应用实例: 典型应用通常包括在大型高温老化试验箱内的大量电源(50~100个)。测量时将对试验箱内 ...… 查看全部问答> |




