首先看下ARM状态下不同模式下的的寄存器,共37个,31个通用的。
好,问题来了:在快速中断模式下的R8_fiq与其他模式下的R8是不同的寄存器,但是在汇编代码中不会区别寄存器名字。
例如MOV R8,#0x1,该命令在快速中断模式下运行,与处快速中断之外的模式下执行,显然访问的是不同的R8寄存器,但是这个访问不同寄存器的过程是编译器做的,还是CPU做的?
通过请教高手得出结论如下:
名词:r*_fiq (*=8~14)
在Linux内核里,如果要用到快速中断,需要初始化快速中断,首先先设置r*_fiq,然后使能快速中断。系统在同一时刻只能支持一个fiq,允许程序员在系统运行的过程中改变fiq的目标。
下面是摘抄Linux内核里设置r*_fiq的代码:
Linux3.2 arch/arm/kernel/fiqasm.S line25:
ENTRY(__set_fiq_regs)
mov r2, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE
mrs r1, cpsr
msr cpsr_c, r2 @ select FIQ mode
mov r0, r0 @ avoid hazard prior to ARMv4
ldmia r0!, {r8 - r12}
ldr sp, [r0], #4
ldr lr, [r0]
msr cpsr_c, r1 @ return to SVC mode
mov r0, r0 @ avoid hazard prior to ARMv4
mov pc, lr
ENDPROC(__set_fiq_regs)
系统程序员预先初始化一个数组,填上需要放到r8-r14的值,然后调用该函数,参
数为该数组的指针。这个函数主要做的工作是保存cpsr,将当前模式切换成FIQ
模式,将r0指向的内存里的值放到r8-r14(r*_fiq),切换回以前的管理模式,
函数返回。
程序里使用ldmia和ldr指令往r*_fiq寄存器里存储数据。根据ARM指令手册,
ldmia指令操作的register_list(位图)只有16位,下图为LDMIA指令的二进制码,后16位是寄存器列表。
也就是说ldmia指令只能访问r0-r15,不能在指令码里指定更多的寄存器编号。如果想要在指令二进制码里就指明不同模式下的同名寄存器(如指明快速中断模式下的r8_fiq),那就需要不止16位的寄存器编号。
LDR指令也类似,指令码里指明寄存器编号的位段只有4位,也只能访问r0-r15。
从这里我们可以看出编译器并不知道r*_fiq的存在,只能当r*处理。真正区分
fiq寄存器和通用寄存器,需要CPU根据cpsr寄存器的标志位来判断。
下图是CPSR寄存器,后五位组合为不同模式位。