ARM微处理器的编程模型之:异常中断处理
c。 ③ 返回地址放入LR_svc。 如果处理器已经处于特权模式,再发生SWI异常,则LR_svc和SPSR_svc寄存器的值将丢失。 所以在特权模式下,调用SWI软中断异常,必须先将LR_svc和SPSR_svc寄存器的值压栈保护。下面的例子显示了一个可以在特权模式下调用的SWI处理函数。 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} ;寄存器压栈保护 MOV r1, sp ;堆栈指针放r1作为参数传递. MRS r0, spsr ;读取spsr. STMFD sp!, {r0, r3} ;将spsr压栈保护 ; ; LDR r0,[lr,#-4] ;计算SWI指令地址. BIC r0,r0,#0xFF000000 ;读取SWI中断向量号. ; r0存放中断向量号 ; r1 堆栈指针 BL C_SWI_Handler ;调用C程序的SWI处理函数. LDMFD sp!, {r0, r3} ;从堆栈中读取spsr. MSR spsr_cf, r0 ;恢复spcr LDMFD sp!, {r0-r3,r12,pc}^ ;恢复其他寄存器并返回. END 可从汇编语言或 C/C++ 中调用 SWI。 (1)从汇编应用程序中调用SWI 从汇编语言程序中调用SWI,只要遵循AAPCS标准即可。调用前,设定所有必须的值并发出相关的 SWI。例如: MOV r0, #65 ; 将软中断的子功能号放到r0中 SWI 0x0 注意 SWI指令和其他所以ARM指令一样,可以被条件执行。 (2)从C应用程序中调用SWI 在C或C++应用程序中调用SWI,要将C语言的子程序用编译器扩展_swi声明,例如: __swi(0) void my_swi(int); …… …… …… my_swi(65); 编译器扩展_swi确保了SWI以内联方式进行编译,而没有额外的开销。但有如下的AAPCS限制。 · 函数调用参数只能使用r0~r3传递。 · 函数返回值只能通过r0~r3传递。 向内联的SWI函数传递参数和向实际的子函数传递参数基本类似。但返回值的情况比较复杂。如果有两到四个返回值,则必须告诉编译程序返回值是以结构形式返回的,并使用__value_in_regs 伪操作声明。这是因为基于结构值的函数通常被处理为一个void(空)型函数,且第一个自变量必须为存放结果结构的地址。 下面的例子显示了对编号为0x0、0x1、0x2和0x3的SWI软中断的调用。其中,SWI0x0和SWI0x1传递两个整型参数并返回一个单一结果;SWI0x2传递4个参数并返回一个单一结果;而SWI0x3传递4个参数并通过结构体返回4个结果。 #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) = %d\n, result1 = multiply_two(2,4)); printf(result2 = multiply_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; } __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)应用程序中动态调用SWI 在某些情形下,需要调用直到运行时才会知道其编号的 SWI。例如,当有很多相关操作可在同一目标上执行,并且每一个操作都有其自己的 SWI 时,就会发生这种情况。在此情况下,上一小节的方法不适用。 解决的方法有两种。 · 在运行时得到SWI功能号,然后构造出相应的SWI指令的编码,将该编码保存在某个存储单元中,将PC指针指向该单元,执行指令。 · 使用一个通用的SWI异常中断处理程序,将运行时需要调用的SWI功能号作为参数传递给该通用的SWI异常处理程序,通用的SWI异常中断处理程序根据参数值调用相应的SWI处理程序完成需要的操作。 通过汇编语言可以实现第二种解决办法:通过寄存器(通常为r0或r12)传递所需要的操作数,这样可以重新编写SWI处理程序,对相应寄存器中的值进行处理。 但有些情况下,为了节省程序开销,需要直接使用SWI中断号对程序调用。例如,操作系统可能会使用单一的一条SWI指令并用寄存器来传递所需运算的编号。这使得其5.从应用程序中调用SWI
微处理器 异常中断处理 ARM 复位异常 数据异常 相关文章:
- 用8位微处理器实现数字低通滤波器设计(05-15)
- 如何构造嵌入式Linux系统(05-23)
- 基于嵌入式Linux的便携式RFID信息采集与处理系统(07-01)
- SPARC微处理器综述(05-29)
- Motorola32位嵌入式微处理器MPC860的开发应用(06-02)
- 基于ARM和uClinux的家庭网关系统(09-14)