9中CPU模式中关于寄存器的图示,正点原子的指南和 官方文档的不太一样
来自 ARM Cortex-A(armV7)编程手册V4.0
来自正点原子的开发指南
官方的寄存器里面SVC模式和IRQ模式是共用SP和LR寄存器的,正点原子给的图示分开的,是这两个图对应的芯片不同吗?
我用的开发板是ALIENTEK I.MX6U ALPHA V2.2
这里好像有点影响IRQ中断的编写
- IRQ_Handler:
- push {lr} /* 保存lr地址 */
- push {r0-r3, r12} /* 保存r0-r3,r12寄存器 */
- mrs r0, spsr /* 读取spsr寄存器 */
- push {r0} /* 保存spsr寄存器 */
- mrc p15, 4, r1, c15, c0, 0 /* 从CP15的C0寄存器内的值到R1寄存器中
- * 参考文档ARM Cortex-A(armV7)编程手册V4.0.pdf P49
- * Cortex-A7 Technical ReferenceManua.pdf P68 P138
- */
- add r1, r1, #0X2000 /* GIC基地址加0X2000,也就是GIC的CPU接口端基地址 */
- ldr r0, [r1, #0XC] /* GIC的CPU接口端基地址加0X0C就是GICC_IAR寄存器,
- * GICC_IAR寄存器保存这当前发生中断的中断号,我们要根据
- * 这个中断号来绝对调用哪个中断服务函数
- */
- push {r0, r1} /* 保存r0,r1 */
-
- cps #0x13 /* 进入SVC模式,允许其他中断再次进去 */
-
- push {lr} /* 保存SVC模式的lr寄存器 */
- ldr r2, =system_irqhandler /* 加载C语言中断处理函数到r2寄存器中*/
- blx r2 /* 运行C语言中断处理函数,带有一个参数,保存在R0寄存器中 */
- pop {lr} /* 执行完C语言中断服务函数,lr出栈 */
- cps #0x12 /* 进入IRQ模式 */
- pop {r0, r1}
- str r0, [r1, #0X10] /* 中断执行完成,写EOIR */
- pop {r0}
- msr spsr_cxsf, r0 /* 恢复spsr */
- pop {r0-r3, r12} /* r0-r3,r12出栈 */
- pop {lr} /* lr出栈 */
- subs pc, lr, #4 /* 将lr-4赋给pc */
复制代码 cps #0x13 /* 进入SVC模式,允许其他中断再次进去 */
push {lr} /* 保存SVC模式的lr寄存器 */
影响这两句代码:
如果SVC和IRQ共用lr寄存器,那如果cps #0x13执行之后,立马来了个IRQ中断,那么lr寄存器肯定会被破坏,然后中断返回之后我们再push{lr}就保存的是错误的数据。
当然如果SVC和IRQ共用lr寄存器也就没必要在这里保存lr寄存器了。
还有sp指针也是,如果共用的话:
- /* 复位中断 */
- Reset_Handler:
- cpsid i /* 关闭全局中断 */
- /* 关闭I,DCache和MMU
- * 采取读-改-写的方式。
- */
- mrc p15, 0, r0, c1, c0, 0 /* 读取CP15的C1寄存器到R0中 */
- bic r0, r0, #(0x1 << 12) /* 清除C1寄存器的bit12位(I位),关闭I Cache */
- bic r0, r0, #(0x1 << 2) /* 清除C1寄存器的bit2(C位),关闭D Cache */
- bic r0, r0, #0x2 /* 清除C1寄存器的bit1(A位),关闭对齐 */
- bic r0, r0, #(0x1 << 11) /* 清除C1寄存器的bit11(Z位),关闭分支预测 */
- bic r0, r0, #0x1 /* 清除C1寄存器的bit0(M位),关闭MMU */
- mcr p15, 0, r0, c1, c0, 0 /* 将r0寄存器中的值写入到CP15的C1寄存器中 */
-
- #if 0
- /* 汇编版本设置中断向量表偏移 */
- ldr r0, =0X87800000
- dsb
- isb
- mcr p15, 0, r0, c12, c0, 0
- dsb
- isb
- #endif
-
- /* 设置各个模式下的栈指针,
- * 注意:IMX6UL的堆栈是向下增长的!
- * 堆栈指针地址一定要是4字节地址对齐的!!!
- * DDR范围:0X80000000~0X9FFFFFFF
- */
- /* 进入IRQ模式 */
- mrs r0, cpsr
- bic r0, r0, #0x1f /* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 */
- orr r0, r0, #0x12 /* r0或上0x13,表示使用IRQ模式 */
- msr cpsr, r0 /* 将r0 的数据写入到cpsr_c中 */
- ldr sp, =0x80600000 /* 设置IRQ模式下的栈首地址为0X80600000,大小为2MB */
- /* 进入SYS模式 */
- mrs r0, cpsr
- bic r0, r0, #0x1f /* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 */
- orr r0, r0, #0x1f /* r0或上0x13,表示使用SYS模式 */
- msr cpsr, r0 /* 将r0 的数据写入到cpsr_c中 */
- ldr sp, =0x80400000 /* 设置SYS模式下的栈首地址为0X80400000,大小为2MB */
- /* 进入SVC模式 */
- mrs r0, cpsr
- bic r0, r0, #0x1f /* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 */
- orr r0, r0, #0x13 /* r0或上0x13,表示使用SVC模式 */
- msr cpsr, r0 /* 将r0 的数据写入到cpsr_c中 */
- ldr sp, =0X80200000 /* 设置SVC模式下的栈首地址为0X80200000,大小为2MB */
- cpsie i /* 打开全局中断 */
- #if 0
- /* 使能IRQ中断 */
- mrs r0, cpsr /* 读取cpsr寄存器值到r0中 */
- bic r0, r0, #0x80 /* 将r0寄存器中bit7清零,也就是CPSR中的I位清零,表示允许IRQ中断 */
- msr cpsr, r0 /* 将r0重新写入到cpsr中 */
- #endif
- b main /* 跳转到main函数 */
复制代码 这里初始化SVC模式的SP和初始化IRQ模式的SP不是就重复了吗?
|