MRRC(Move to two ARM registers from Coprocessor)是ARM架构中用于协处理器数据传输的关键指令。它允许协处理器将数据同时传输到两个ARM通用寄存器,这种双寄存器传输机制特别适合处理64位数据类型的场景。
MRRC指令的二进制编码格式如下:
code复制31-28 | 27-20 | 19-16 | 15-12 | 11-8 | 7-4 | 3-0
cond | 11000101 | Rn | Rd | coproc | opcode | CRm
其中各字段含义:
标准语法格式为:
assembly复制MRRC{cond} coproc, opcode, Rd, Rn, CRm ; 条件执行版本
MRRC2 coproc, opcode, Rd, Rn, CRm ; 无条件执行版本
关键提示:MRRC2是ARMv6引入的变体,其固定将cond字段设为0b1111,为协处理器设计提供了额外的操作码空间。这种指令只能无条件执行。
双精度浮点传输是最典型的应用案例。假设我们需要将协处理器p10中的双精度浮点数(存储在寄存器c5中)传输到ARM寄存器:
assembly复制MRRC p10, 3, R2, R3, c5 ; 将p10的c5中数据传送到R2(低32位)和R3(高32位)
硬件加速器交互示例:
assembly复制; 加密协处理器数据获取
MRRC p5, 1, R0, R1, c2 ; 从加密引擎获取128位密钥的前64位
MRRC p5, 1, R2, R3, c3 ; 获取密钥的后64位
当出现以下情况时会触发Undefined Instruction异常:
重要限制条件:
实测中发现的一个典型问题:
assembly复制MRRC p7, 0, R8, R8, c0 ; 错误!同一寄存器用于双目标
这种编码在某些处理器上会导致数据损坏,应绝对避免。
MRS(Move PSR to general-purpose register)是ARM架构中唯一用于读取状态寄存器的指令,它允许将CPSR或当前模式的SPSR复制到通用寄存器。
MRS指令编码格式:
code复制31-28 | 27-23 | 22 | 21-16 | 15-12 | 11-0
cond | 00010R0 | SBZ | Rd | 000000000000
其中关键位:
语法格式:
assembly复制MRS{cond} Rd, CPSR ; 读取当前程序状态寄存器
MRS{cond} Rd, SPSR ; 读取保存的程序状态寄存器
标准的三步修改法:
assembly复制MRS R0, CPSR ; 读取当前状态
BIC R0, R0, #0x1F ; 清除模式位
ORR R0, R0, #0x13 ; 设置为Supervisor模式
MSR CPSR_c, R0 ; 写回控制字段
在可能发生嵌套异常的代码中:
assembly复制IRQ_Handler:
MRS R0, SPSR ; 保存进入时的状态
STMFD SP!, {R0-R3} ; 保存寄存器
... ; 处理代码
LDMFD SP!, {R0-R3} ; 恢复寄存器
MSR SPSR_cxsf, R0 ; 恢复SPSR
MOVS PC, LR ; 异常返回
用户模式限制:
版本差异:
实测中发现的一个典型错误:
assembly复制MRS R15, CPSR ; 错误!R15作为目标寄存器
这会导致不可预测的行为,因为PC的特殊性会干扰状态传输。
结合使用MRRC和MRS可以实现安全的浮点运算环境切换:
assembly复制SaveFPState:
MRS R0, CPSR
ORR R1, R0, #0xC0 ; 禁用IRQ和FIQ
MSR CPSR_c, R1
MRRC p10, 1, R2, R3, c1 ; 保存浮点状态寄存器
STM R12!, {R2-R3}
... ; 保存其他浮点寄存器
MSR CPSR_c, R0 ; 恢复原始状态
在加密操作中典型的工作流:
assembly复制StartAES:
MRS R0, CPSR
CPSID if ; 禁用中断
MRRC p5, 0, R1, R2, c0 ; 获取输入数据
... ; 设置加密参数
MCR p5, 0, R7, c4, c0, 0 ; 启动加密
PollComplete:
MRRC p5, 1, R3, R4, c1 ; 读取状态寄存器
TST R3, #0x80000000
BEQ PollComplete
MRRC p5, 0, R5, R6, c2 ; 获取结果数据
MSR CPSR_c, R0 ; 恢复中断状态
通过实测发现,连续的MRRC指令最好间隔至少2个NOP:
assembly复制MRRC p9, 0, R0, R1, c0
NOP
NOP
MRRC p9, 0, R2, R3, c1 ; 比直接连续执行稳定
当需要原子读取所有状态位时:
assembly复制 MRS R0, CPSR
MRS R1, SPSR ; 这两条指令间可能被中断
; 更安全的做法:
CPSID if ; 先禁用中断
MRS R0, CPSR
MRS R1, SPSR
CPSIE if ; 再启用中断
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| MRRC触发Undef异常 | 协处理器不存在 | 检查CP15的协处理器访问控制寄存器 |
| MRS读取值异常 | 在User模式读SPSR | 添加模式检查代码 |
| 双寄存器数据错位 | 协处理器端序设置错误 | 检查CP15的EE位配置 |
| 状态修改无效 | 未正确设置field_mask | 确保MSR指令指定了_c后缀 |
| 架构版本 | MRRC支持 | MRRC2支持 | 注意事项 |
|---|---|---|---|
| ARMv5TE | ✓ | ✗ | 不包括ARMv5TExP |
| ARMv6 | ✓ | ✓ | 新增条件执行扩展 |
| ARMv7 | ✓ | ✓ | 增加Thumb-2支持 |
关键变化点:
一个典型的版本检测代码:
assembly复制CheckArch:
MRS R0, CPSR
AND R1, R0, #0x00000020 ; 检查T位
CMP R1, #0
BNE ThumbMode
... ; ARM模式处理
在实际开发中,我发现较新的Cortex处理器对MRRC的延迟要求更低,但在早期的ARM9处理器上,不遵守推荐的指令间隔会导致数据损坏。这种差异在移植代码时需要特别注意。