Cortex-A7中断系统之start.S文件编写中的汇编指令

    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 */

LR 寄存器是 Link Register 的简写,它是 ARM 处理器中的一个寄存器,它用来保存函数调用时的返回地址,也就是调用函数的下一条指令的地址。当处理器执行 BL(Branch with Link,带链接的分支)指令时,它会将当前的 PC 寄存器的值(也就是 BL 指令的下一条指令的地址)保存到 LR 寄存器中,然后跳转到目标函数去执行。当函数执行完毕后,处理器可以通过读取 LR 寄存器的值,跳回到调用函数的下一条指令继续执行。这样就实现了函数调用和返回的功能。

  • 在第一行代码中,PUSH {LR} 指令是用来在进入一个函数前,将 LR 寄存器的值压入到栈中,以便在函数返回时恢复 LR 寄存器的值。这里的 LR 寄存器是 SVC 模式下的 LR 寄存器,SVC 模式是一种特权级别的系统模式,它可以执行一些特权级指令和访问一些特权级资源。SVC 模式有自己独立的 LR 寄存器,不同于其他模式下的 LR 寄存器。
  • 在第三行代码中,BLX R2 指令是用来调用 C 语言中断处理函数 system_irqhandler 的,它会将当前的 PC 寄存器的值保存到 LR 寄存器中,然后跳转到 R2 寄存器中保存的地址去执行。这里的 LR 寄存器也是 SVC 模式下的 LR 寄存器,它保存了 C 语言中断处理函数返回后要继续执行的地址。
  • 在第五行代码中,POP {LR} 指令是用来在退出一个函数后,将栈顶的值弹出到 LR 寄存器中,以恢复之前保存在栈中的 LR 寄存器的值。这里的 LR 寄存器还是 SVC 模式下的 LR 寄存器,它恢复了 C 语言中断处理函数调用前保存在栈中的地址。
130 push {lr} /* 保存 SVC 模式的 lr 寄存器 */
131 ldr r2, =system_irqhandler /* 加载 C 语言中断处理函数到 r2 寄存器中*/
132 blx r2 /* 运行 C 语言中断处理函数,带有一个参数 */
133
134 pop {lr} /* 执行完 C 语言中断服务函数,lr 出栈 */
135 cps #0x12 /* 进入 IRQ 模式 */
136 pop {r0, r1} 
137 str r0, [r1, #0X10] /* 中断执行完成,写 EOIR */
138
139 pop {r0} 
140 msr spsr_cxsf, r0 /* 恢复 spsr */
141
142 pop {r0-r3, r12} /* r0-r3,r12 出栈 */
143 pop {lr} /* lr 出栈 */
144 subs pc, lr, #4 /* 将 lr-4 赋给 pc */

第 143 行的 POP {LR} 指令是用来将栈顶的值弹出到 LR 寄存器中的,这里的 LR 寄存器是 IRQ 模式下的 LR 寄存器,它保存了中断发生时的返回地址。这个指令是为了在中断处理完成后,恢复中断前的执行流程。

可能会觉得第 134 行和第 143 行都是 POP {LR} 指令,为什么要重复执行呢?其实,这两个指令是在不同的模式下执行的,它们操作的是不同的 LR 寄存器。第 134 行是在 SVC 模式下执行的,它操作的是 SVC 模式下的 LR 寄存器,它保存了 C 语言中断处理函数调用前的地址。第 143 行是在 IRQ 模式下执行的,它操作的是 IRQ 模式下的 LR 寄存器,它保存了中断发生时的地址。这两个 LR 寄存器都是独立的,不会相互影响。

subs pc, lr, #4 /* 将 lr-4 赋给 pc */

这条指令的作用是将 LR 寄存器的值减去 4,并将结果保存到 PC 寄存器中,也就是 PC = LR - 4。这样就实现了从中断处理函数返回到中断发生时的执行流程。为什么要减去 4 呢?这是因为 ARM 处理器在进入 IRQ 模式时,会自动将 PC 寄存器的值加上 4,并保存到 LR 寄存器中。这样做是为了保证 LR 寄存器保存了正确的返回地址,因为 PC 寄存器在执行一条指令时,其实已经指向了下一条指令的地址。所以,在从 IRQ 模式返回时,要将 LR 寄存器的值减去 4,才能恢复到正确的 PC 寄存器的值。

 str r0, [r1, #0X10] /* 中断执行完成,写 EOIR

这条指令的意思是:

  • STR(Store Register,存储寄存器)指令是用来将一个源寄存器的值存储到一个目标地址中,目标地址可以由一个基址寄存器和一个偏移量组成。STR 指令可以用来在函数调用后恢复一些寄存器的值,或者将一些数据写入到内存中。
  • 这条指令中的 STR 指令后面跟着两个寄存器和一个立即数,分别是 R0、R1 和 #0X10。这些参数的含义是:
    • R0 是源寄存器,要存储到存储器中的数据就保存在此寄存器中。
    • R1 是基址寄存器,它保存了目标地址的基址部分。
    • #0X10 是偏移量,它表示目标地址相对于基址的偏移量,单位是字节。
  • 这条指令的作用是将 R0 寄存器的值存储到 R1 寄存器的值加上 #0X10 这个偏移量所得到的地址中,也就是 [R1, #0X10] 这个地址中。这个地址对应了一个内存单元,它可以保存 4 个字节(32 位)的数据。

 MCR{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2> 

MCR 指令是用来将 ARM 寄存器的数据写入到 CP15 协处理器寄存器中的。CP15 协处理器是用来控制和配置 ARM 处理器的一些特性,比如缓存、内存管理等。MCR 指令的格式如下:

MCR{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2>

其中,各个参数的含义是:

  • cond 是指令执行的条件码,如果忽略的话就表示无条件执行。
  • opc1 是协处理器要执行的操作码。
  • Rt 是 ARM 源寄存器,要写入到 CP15 寄存器的数据就保存在此寄存器中。
  • CRn 是 CP15 协处理器的目标寄存器。
  • CRm 是协处理器中附加的目标寄存器或者源操作数寄存器,如果不需要附加信息就将 CRm 设置为 C0,否则结果不可预测。
  • opc2 是可选的协处理器特定操作码,当不需要的时候要设置为 0。

举例说明:

假如我们要将 ARM 寄存器 R0 的值写入到 CP15 协处理器的 C1 寄存器中,C1 寄存器是用来控制 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

dsb和isb指令分别执行数据同步屏障和指令同步屏障,这是为了保证之前的内存操作完成,并刷新指令缓存。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值