嵌入式裸机开发-Cortex-A7结构及指令


Cortex-A7 MPcore 处理器支持 1~4 核,性能强,功耗低。

Cortex-A 处理器运行模式

运行模式

Cortex-A7 处理器有 9 种处理模式:

大多数的程序都运行在用户模式,用户模式下是不能访问系统所有资源的,有些资源是受限的,要想访问这些受限的资源就必须进行模式切换。但是用户模式是不能直接进行切换的,用户模式下需要借助异常来完成模式切换,当要切换模式的时候,应用程序可以产生异常,在异常的处理过程中完成处理器模式切换。

中断或者异常发生以后,处理器就会进入到相应的异常模式种,每一种模式都有一组寄存器供异常处理程序使用,这样的目的是为了保证在进入异常模式以后,用户模式下的寄存器不会被破坏

寄存器

以下为9种模式所对应的寄存器:
在这里插入图片描述
浅色字体的是与 User 模式所共有的寄存器,蓝绿色背景的是各个模式所独有的寄存器。
①、 34 个通用寄存器,包括 R15 程序计数器(PC),这些寄存器都是 32 位的。
②、 8 个状态寄存器,包括 CPSR 和 SPSR。
③、 Hyp 模式下独有一个 ELR_Hyp 寄存器

16 个 32 位的通用寄存器(R0~ R15)供软件使用,前 15 个(R0~R14)可以用作通用的数据存储。
R0~R7 是未备份寄存器
在不同的模式下,这 8 个寄存器都是同一个物理寄存器,所以数据就会被破坏。
R8~R12是备份寄存器
有两种物理寄存器,其中FIQ 模式下中断处理程序可以使用 R8~R12寄存器,因为 FIQ 模式下的 R8 ~R12 是独立的,因此中断处理程序可以不用执行保存和恢复中断现场的指令,从而加速中断的执行过程。

R13 是堆栈指针SP
有 8 个物理寄存器。

R14 是链接寄存器
有 7 个物理寄存器。
①、每种处理器模式使用 R14(LR)来存放当前子程序的返回地址。
②、当异常发生以后,该异常模式对应的 R14 寄存器被设置成该异常模式将要返回的地址,R14 也可以当作普通寄存器使用。

R15 是程序计数器 PC
ARM 处理器 3 级流水线:取址->译码->执行
PC负责取址,总是指向当前正在执行的指令地址再加上 2 条指令的地址(32位处理器,一条指令=4字节)。

R15 (PC)= 当前执行的程序位置 + 8 个字节

当前程序状态寄存器 CPSR备份程序状态寄存器 SPSR,SPSR 寄存器就是 CPSR 寄存器的备份。
当特定的异常中断发生时, SPSR 寄存器用来保存当前程序状态寄存器(CPSR)的值,当异常退出以后可以用SPSR 中保存的值来恢复 CPSR(实际操作就是用汇编还可以CPSR入栈进一步保存~)。

模式切换

所有的处理器模式都共用一个 CPSR 物理寄存器,因此 CPSR 可以在任何模式下被访问。所有的处理器模式都共用一个 CPSR 必然会导致冲突,为此,除了 User 和 Sys 这两个模式以外,其他 7 个模式每个都配备了一个专用的物理状态寄存器,叫做 SPSR(备份程序状态寄存器),当特定的异常中断发生时, SPSR 寄存器用来保存当前程序状态寄存器(CPSR)的值,当异常退出以后可以用 SPSR 中保存的值来恢复 CPSR。

SPSR 和CPSR 的寄存器结构相同,如图所示:

在这里插入图片描述
N(bit31):当两个补码表示的 有符号整数运算的时候, N=1 表示运算对的结果为负数, N=0表示结果为正数。
Z(bit30): Z=1 表示运算结果为零, Z=0 表示运算结果不为零,对于 CMP 指令, Z=1 表示进行比较的两个数大小相等。
C(bit29):在加法指令中,当结果产生了进位,则 C=1,表示无符号数运算发生上溢,其它情况下 C=0。在减法指令中,当运算中发生借位,则 C=0,表示无符号数运算发生下溢,其它情况下 C=1。对于包含移位操作的非加/减法运算指令, C 中包含最后一次溢出的位的数值,对于其它非加/减运算指令, C 位的值通常不受影响。
V(bit28): 对于加/减法运算指令,当操作数和运算结果表示为二进制的补码表示的带符号数时, V=1 表示符号位溢出,通常其他位不影响 V 位。
Q(bit27): 仅 ARM v5TE_J 架构支持,表示饱和状态, Q=1 表示累积饱和, Q=0 表示累积不饱和。
IT【1:0】( bit26:25): 和 IT【7:2】(bit15:bit10)一起组成 IT[7:0],作为 IF-THEN 指令执行状态。
J(bit24): 仅 ARM_v5TE-J 架构支持, J=1 表示处于 Jazelle 状态,此位通常和 T(bit5)位一起表示当前所使用的指令集,如下表所示:

JT描述
00ARM
01Thumb
11ThumbEE
10Jazelle

GE{3:0}(bit19:16): SIMD 指令有效,大于或等于。
IT{7:2}(bit15:10): 参考 IT[1:0]。
E(bit9): 大小端控制位, E=1 表示大端模式, E=0 表示小端模式。
A(bit8): 禁止异步中断位, A=1 表示禁止异步中断。
I(bit7): I=1 禁止 IRQ, I=0 使能 IRQ。
F(bit6): F=1 禁止 FIQ, F=0 使能 FIQ。
T(bit5): 控制指令执行状态,表明本指令是 ARM 指令还是 Thumb 指令,通常和 J(bit24)一起表明指令类型,参考 J(bit24)位。
M[4:0]: 处理器模式控制位,含义如下表所示:
在这里插入图片描述

程序状态寄存器各个位的说明在以后学习中慢慢熟悉。

ARM 汇编基础

Cortex-A 芯片一上电 SP 指针还没初始化, C 环境还没准备
好,所以肯定不能运行 C 代码,必须先用汇编语言设置好 C 环境,比如初始化 DDR、设置 SP指针等等,当汇编把 C 环境设置好了以后才可以运行 C 代码。

GNU 汇编语法

GNU 汇编语法适用于所有的架构,并不是 ARM 独享的, GNU 汇编由一系列的语句组成,每行一条语句,每条语句有三个可选部分,如下:

1.一般结构

label: instruction @ comment

label 即标号,表示地址位置。任何以“:”结尾的标识符都会被识别为一个标号。
instruction 即指令,也就是汇编指令或伪指令。
@符号,表示后面的是注释。
comment 就是注释内容。

代码举例
add:
	MOVS R0, #0X12 @设置 R0=0X12

注意! ARM 中的指令、伪指令、伪操作、寄存器名等可以全部使用大写,也可以全部使用小写,但是不能大小写混用。

2.伪操作

.global _start

_start:
	ldr r0, =0x12 @r0=0x12

.global 是伪操作,表示_start 是一个全局标号。
常见的伪操作有:

.byte 	定义单字节数据,比如.byte 0x12。
.short 	定义双字节数据,比如.short 0x1234。
.long 	定义一个 4 字节数据,比如.long 0x12345678。
.equ 	赋值语句,格式为: .equ 变量名,表达式,比如.equ num,0x12,表示 num=0x12。
.align 	数据字节对齐,比如: .align 4 表示 4 字节对齐。
.end 	表示源文件结束。
.global 定义一个全局符号,格式为: .global symbol,比如:.global _start。

用户可以使用.section 伪操作来定义一个段,汇编系统预定义了一些段名:

.text 表示代码段。
.data 初始化的数据段。
.bss 未初始化的数据段。
.rodata 只读数据段。

3.函数

函数名:
	函数体
	返回语句
如:
Undefined_Handler:
	ldr r0, =Undefined_Handler
	bx r0	@“bx”指令是返回指令,函数返回语句不是必须的

Cortex-A7 常用汇编指令

处理器内部数据传输指令

1、 MOV 指令
用于将数据从一个寄存器拷贝到另外一个寄存器。

MOV R0, R1 	@将寄存器 R1 中的数据传递给 R0,即 R0=R1
MOV R0, #0X12	@将立即数 0X12 传递给 R0 寄存器,即 R0=0X12

2、 MRS 指令
用于将特殊寄存器(如 CPSR 和 SPSR)中的数据传递给通用寄存器。

MRS R0, CPSR 	@将特殊寄存器 CPSR 里面的数据传递给 R0,即 R0=CPSR

3、 MSR 指令
用来将普通寄存器的数据传递给特殊寄存器(如 CPSR 和 SPSR)。

MSR CPSR, R0 	@将 R0 中的数据复制到 CPSR 中,即 CPSR=R0

存储器访问指令

存储器有程序存储器(ROM)数据存储器(RAM)

寄存器独立于RAM,一般寄存器存在于CPU中用于快速计算。寄存器体积大,速度快;存储器体积小,速度慢。

ARM 不能直接访问存储器( RAM 中的数据),但可借助寄存器间接读取。在这里插入图片描述
1、 LDR 指令
用于从存储器加载数据寄存器 Rx 中,也可以将一个立即数加载到寄存器 Rx中, LDR 加载立即数的时候要使用“=”,而不是“#”。

LDR R0, =0X0209C004 	@将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, [R0] 			@读取地址 0X0209C004 中的数据到 R1 寄存器中

1.x ADR指令
和LDR类似,他是将标号的地址存到寄存器中。

ADR LR,_start  @将标号_start的地址存到LR寄存器中

2、 STR 指令
数据写入到存储器

LDR R0, =0X0209C004 	@将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, =0X20000002 	@R1 保存要写入到寄存器的值,即 R1=0X20000002
STR R1, [R0] 			@将 R1 中的值写入到 R0 中所保存的地址中

LDR 和 STR 都是按照进行读取和写入的,指令“LDR/STR”后面加上 B(字节=8位)H(半字=16位)
LDR 和 STR在操作过程中一般只认寄存器传数据。

压栈和出栈指令

进中断,保存 R0~R15 寄存器的操作就叫做现场保护
结束中断,恢复 R0 ~R15 寄存器的操作就叫做恢复现场
栈指针 SP 指向栈顶。
在这里插入图片描述
堆栈是向下增长的,之前认识的也没错,以后就按照下图地址增长记忆。

@注意顺序
PUSH {R0~R3, R12} 			@将 R0~R3 和 R12 入栈,SP-1*5,存数据
STMFD SP!,{R0~R3, R12} 		@R0~R3,R12 入栈

POP {R0~R3,R12} 			@在恢复 R0~R3,R12,出数据,SP+1*5
LDMFD SP!, {R0~R3, R12}		@再恢复 R0~R3, R12

@出栈命令R1指向的地址到寄存器R10_R11
ldmia r1!, {r10-r11} /* copy from source address [r1] */
@入栈命令寄存器R10_R11到R0指向的地址
stmia r0!, {r10-r11} /* copy to target address [r0] */

在这里插入图片描述

跳转指令

有多种跳转操作,比如:
①、直接使用跳转指令 B、 BL、 BX 等。
②、直接向 PC 寄存器里面写入数据。

在这里插入图片描述
1、 B 指令
B 指令会将 PC 寄存器的值设置为跳转目标地址。

 b main 	@跳转到 main 函数

2、 BL 指令
BL 指令会将 PC 寄存器的值设置为跳转目标地址,并将返回地址存到LR中(LR寄存器中的内容要提前入栈保护),完事后在回来。

bl system_irqhandler 	@加载 C 语言中断处理函数到 r2 寄存器中

当通过BL或BLX指令调用子程序时, ** 硬件自动将子程序返回地址保存在LR寄存器中 ** 。在子程序返回时,把LR的值复制到程序计数器PC即可实现子程序返回。如,可以使用MOV PC, LR或者BX LR来完成子程序返回。另外,也可以在在子程序入口处使用下面的指令将LR保存到栈中。

算术运算指令

汇编中也可以进行算术运算在这里插入图片描述

逻辑运算指令

使用汇编语言的时候也可以使用逻辑运算指令,注意:这里每条指令要保证至少两个寄存器。
在这里插入图片描述
关于汇编指令,本文暂时记录于此,后续学习中遇到其他指令,在补充。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值