0 参考资料
Cortex M3权威指南(中文).pdf(可以参考ARM指令集用法)
1 前言
tx_thread_irq_nesting_start.s是用来实现Cortex-A7 IRQ嵌套中断的开始函数实现的汇编文件。
2 源码分析
源码如下:
c
1 IRQ_DISABLE = 0x80 // IRQ disable bit
2 MODE_MASK = 0x1F // Mode mask
3 SYS_MODE_BITS = 0x1F // System mode bits
4 .global _tx_thread_irq_nesting_start
5 .type _tx_thread_irq_nesting_start,function
6 _tx_thread_irq_nesting_start:
7 MOV r3,lr // Save ISR return address
8 MRS r0, CPSR // Pickup the CPSR
9 BIC r0, r0, #MODE_MASK // Clear the mode bits
10 ORR r0, r0, #SYS_MODE_BITS // Build system mode CPSR
11 MSR CPSR_c, r0 // Enter system mode
12 STMDB sp!, {r1, lr} // Push the system mode lr on the system mode stack
13 // and push r1 just to keep 8-byte alignment
14 BIC r0, r0, #IRQ_DISABLE // Build enable IRQ CPSR
15 MSR CPSR_c, r0 // Enter system mode
16 #ifdef __THUMB_INTERWORK
17 BX r3 // Return to caller
18 #else
19 MOV pc, r3 // Return to caller
20 #endif
代码逐行分析:
c
1 IRQ_DISABLE = 0x80 // IRQ disable bit
2 MODE_MASK = 0x1F // Mode mask
3 SYS_MODE_BITS = 0x1F // System mode bits
说明:
汇编中可以使用EQU或=指令来定义宏常量,编译器会将这些定义的符号替换为它们所指定的值。
c
4 .global _tx_thread_irq_nesting_start
说明:
.global 用于定义全局符号,以便于被其他文件引用;.local 用于定义局部符号, 仅在当前文件使用。
c
5 .type _tx_thread_irq_nesting_start,function
说明:
.type用于设置符号的type属性,可选值为function或object(函数或对象(如全局变量))
这里设置_tx_thread_irq_nesting_start的属性为函数,可以供其它文件调用。
c
6 _tx_thread_irq_nesting_start:
指示_tx_thread_irq_nesting_start函数入口。
c
7 MOV r3,lr
功能:
将lr(程序链接寄存器(用来保存子程序返回地址))的值保存到寄存器R3。
c
8 MRS r0, CPSR
功能:
将CPSR寄存器的值保存到R0寄存器,特殊的寄存器如CPSR和SPSR必须通过该指令读取。
c
9 BIC r0, r0, #MODE_MASK
清空模式选择位,将R0寄存器的低5bit(0x1F)清空。
1、指令格式
bic{条件}{S} Rd,Rn,operand
2、指令说明
该指令的效果是,根据operand哪个位为1,清除Rn对应的位,然后将结果存入Rd。
CPSR寄存器低5位为处理器模式选择位,定义如下:
c
10 ORR r0, r0, #SYS_MODE_BITS
构造模式选择位,将R0寄存器的低5bit(0x1F)全部置1,配置为系统模式。
ORR指令是逻辑"或"指令。
1、指令格式
orr{条件}{S} Rd,Rn,operand
2、指令说明
orr指令,将Rn的值与操作数operand按位逻辑"或",结果存放到目的寄存器Rd 中。
或者说,根据operand哪个位为1,将Rn对应的位设置为1,然后将结果存入Rd。
c
11 MSR CPSR_c, r0
将R0寄存器的值存入CPSR寄存器,进入系统模式。
功能:将R0寄存器的值保存到CPSR寄存器,特殊的寄存器如CPSR和SPSR必须通过该指令写入。
c
12 STMDB sp!, {r1, lr}
在系统模式下将lr、r1依次压栈,保证8字节对齐。
STMDB指令用于将寄存器压栈。
举例:
指令:stmdb sp!,{r0-r12,lr}
含义:sp = sp - 4,先压lr,sp =lr(即将lr中的内容放入sp所指的内存地址)。sp = sp - 4,再压r12,sp = r12。sp = sp - 4,再压r11,sp = r11...sp = sp - 4,最后压r0,sp = r0。
c
14 BIC r0, r0, #IRQ_DISABLE
构造CPSR寄存器内容,也就是将IRQ使能位置0,使能IRQ。
相关寄存器描述如下:
c
15 MSR CPSR_c, r0
将R0寄存器的值写入CPSR寄存器,进入使能IRQ的系统模式。
c
17 BX r3
执行结束,返回父函数。
如果编译器生成的代码使用Thumb指令集,则执行该语句。
BX指令:带状态切换的跳转指令
BX 指令跳转到指令中所指定的目标地址, 目标地址处的指令既可以是ARM 指令,也可以是Thumb指令。因为 BX 指令会根据 Rm的最低两位切换处理器的状态(ARM指令是4字节对齐,最低两位可以用作状态指示,如果最低两位是0,表示切换到ARM状态;Thumb指令是2字节对齐,最低一位可以用作指示,如果最低一位是1,表示切换到Thumb状态)
c
19 MOV pc, r3
将r3寄存器的值写入PC,返回父函数。
如果编译器生成的代码使用ARM指令集,则执行该语句。
3 总结
tx_thread_irq_nesting_start.s的主要功能就是在进入IRQ时,将模式切换到系统模式然后使能IRQ(硬件进入IRQ会自动失能IRQ),使得IRQ能够被嵌套。
这里有个关键操作,在系统模式下需要将进入中断前的LR压入系统模式栈区,以便后面退出中断时LR值恢复被中断打断,避免系统模式下进入子函数(使用BL指令会修改LR的值)后LR被修改无法返回父函数。