裸机开发(2) Cortex-A7简介 常用ARM汇编指令

目录

  • 1.Cortex-A处理器运行模型
  • 2.Cortex-A寄存器组
    • 2.1.寄存器组简介
    • 2.2.通用寄存器
    • 2.3.程序状态寄存器
  • 3.GUN汇编语法
  • 4.ARM常用汇编指令

1.Cortex-A处理器运行模型

ARM的A系列处理器有9种运行模型:User、FIQ、IRQ、Supervisor(SVC)、Abort、Undef,Monitor,Hyp和System,其中User是非特权模式,其余6中都是特权模式。这9个运行模式可以通过软件、中断或者异常来进行切换。大多数的程序都运行在User模式,是不能访问系统所有资源的,要想访问这些受限的资源就必须进行模式切换。但用户模式不能直接进行切换,需要借助异常来完成模式切换,当要切换模式的时候,应用程序可以产生异常,在异常的处理过程中完成处理器模式切换。当中断或者异常发生以后,处理器就会进入到相应的异常模式种,每一种模式都有一组寄存器供异常处理程序使用,目的是为了保证在进入异常模式以后,用户模式下的寄存器不会被破坏。
STM32只有特权模式和非特权模式,但Cortex-A 就有 9 种运行模式。
裸机开发(2) Cortex-A7简介 常用ARM汇编指令_第1张图片

2.Cortex-A寄存器组

2.1.寄存器组简介

ARM架构有16个32位的通用寄存器,R0~R14可以用作通用的数据存储,R15是程序计数器PC,用来保存将要执行的指令。另外还有“当前程序状态寄存器CPSR”和“备份程序状态寄存器SPSR”,SPSR是CPSR寄存器的备份。

裸机开发(2) Cortex-A7简介 常用ARM汇编指令_第2张图片
Cortex-A7 9种模式对应的寄存器如下图,蓝色背景的是各个模式所独有的寄存器。在所有的模式中,低寄存器组(R0 ~ R7)共享同一组物理寄存器,但一些高寄存器组在不同的模式有自己独有的寄存器。
裸机开发(2) Cortex-A7简介 常用ARM汇编指令_第3张图片

2.2.通用寄存器

R0~R15 通用寄存器,可以分为以下三类:
①、未备份寄存器,即R0~R7。
②、备份寄存器,即R8~R14。
③、程序计数器PC,即R15。

  1. 未备份寄存器
    R0 ~ R7。在所有的处理器模式下这8个寄存器都是同一个物理寄存器;在不同的模式下这8个寄存器中的数据就会被破坏。
  2. 备份寄存器
    R8 ~ R12有两种物理寄存器,在快速中断模式下(FIQ)它们对应着Rx_irq(x=8 ~ 12)物理寄存器,其他模式下对应着Rx(8 ~ 12)物理寄存器。因为FIQ模式下的R8 ~ R12是独立的,因此中断处理程序可以不用执行保存和恢复中断现场的指令,从而加速中断的执行过程。
    R13共有8个物理寄存器,一个是用户模式(User)和系统模式(Sys)共用的,剩下7个分别对应7种不同的模式。R13也叫做SP,用来做为栈指针应用程序会初始化R13,使其指向该模式专用的栈地址,这就是常说的初始化SP指针。
    R14共有7个物理寄存器,其中一个是用户模式(User)、系统模式(Sys)和超级监视模式(Hyp)所共用的,剩下的6个分别对应6种不同的模式。R14也称为连接寄存器(LR),其在 ARM中主要用作如下两种用途:
    ①、每种模式使用R14(LR)存放当前子程序的返回地址,如果使用BL或者BLX来调用子函数,R14(LR)被设置成该子函数的返回地址,在子函数中,将R14(LR)中的值赋给R15(PC)即可完成子函数返回。两种方法代码如下:
方法1.在子函数中编写:
MOV PC, LR //寄存器 LR 中的值赋值给 PC,实现跳转

方法2.在子函数入口将LR入栈:
PUSH {LR} //将LR寄存器压栈
在子函数的最后面出栈:
POP{PC}  @将上面压栈的 LR 寄存器数据出栈给 PC 寄存器

②、当异常发生后,该异常模式对应的R14寄存器被设置成该异常模式将要返回的地址,R14也可以当作普通寄存器使用。

  1. 程序计数器R15
    程序计数器R15也叫PC,因为ARM的流水线机制,R15保存着当前执行的指令地址值加8个字节。ARM处理器3级流水线:取指->译码->执行,这三级流水线循环执行,比如当前正在执行第一条指令的同时也对第二条指令进行译码,第三条指令也同时被取出存放在 R15(PC)中,也就是R15(PC)总是指向当前正在执行的指令地址再加上2条指令的地址。对于32位的ARM处理器,每条指令是4个字节,因此R15(PC)值 = 当前执行的程序位置+8个字节。

2.3.程序状态寄存器

CPSR是当前程序状态寄存器,被所有模式共用,该寄存器包含了条件标志位、中断禁止位、当前处理器模式标志等一些状态位以及一些控制位。所有的处理器模式都共用一个CPSR会导致冲突,为此除了User和Sys两个模式,其他7个模式都各配备了一个专用的物理状态寄存器,叫做SPSR(备份程序状态寄存器)。当特定的异常中断发生时,SPSR寄存器用来保存当前程序状态寄存器(CPSR)的值,当异常退出以后可以用SPSR中保存的值来恢复CPSR。因为User和Sys不是异常模式,所以并没有配备SPSR,因此不能在User和Sys模式下访问SPSR,会导致不可预知的结果。SPSR和CPSR的寄存器结构相同。

CPSR寄存器:
在这里插入图片描述

  1. N(bit31):当两个补码表示有符号整数运算时,N=1表示运算结果为负,N=0表示结果为正。
  2. Z(bit30):Z=1表示运算结果为零,Z=0 表示不为零,对于CMP指令Z=1表示进行比较的两数相等。
  3. C(bit29):加法指令中当结果产生了进位,C=1;减法指令中当运算发生借位,则C=0。
  4. V(bit28):对于加/减法运算指令,V=1表示符号位溢出。
  5. Q(bit27):仅ARM v5TE_J架构支持,表示饱和状态,Q=1表示累积饱和,Q=0表示累积不饱和。
  6. IT[1:0] (bit26:25):和IT[7:2] (bit15:bit10)一起组成IT[7:0],作为IF-THEN指令执行状态。
  7. J(bit24):仅ARM_v5TE-J架构支持,J=1表示处于Jazelle 状态,此位通常和T(bit5)位一起表示当前所使用的指令集:
J T 描述
0 0 ARM
0 1 Thumb
1 1 ThumbEE
1 0 Jazelle
  1. GE[3:0] (bit19:16):SIMD指令有效,大于或等于。
  2. IT[7:2] (bit15:10):参考 IT[1:0]。
  3. E(bit9):大小端控制位,E=1表示大端模式,E=0表示小端模式。
  4. A(bit8):禁止异步中断位,A=1表示禁止异步中断。
  5. I(bit7):I=1禁止IRQ,I=0使能 IRQ。
  6. F(bit6):F=1禁止FIQ,F=0使能FIQ。
  7. T(bit5):参考J(bit24)。
  8. M[4:0]:处理器模式控制位,含义如表所示:
M[4:0] 处理器模式
10000 User模式
10001 FIQ模式
10010 IRQ模式
10011 Supervisor(SVC)模式
10110 Monitor(MON)模式
10111 Abort(ABT)模式
11010 Hyp(HYP)模式
11011 Undef(UND)模式
11111 System(SYS)模式

3.GUN汇编语法

在Cortex-A芯片上电后,需要用户写程序,使用汇编语言初始化SP指针,使其指向栈顶,并且需要初始化DDR等操作(因为芯片可能没有向用户开放的ram),最后再进入C语言的main。由于我们编写的是ARM汇编,使用GCC交叉编译器编译,所以汇编代码要符合GNU语法,GNU语法的格式是:label:instruction @ comment。

可以使用“.section”伪操作来定义一个段,可以自定义段名称,也可以使用汇编系统预定义的段名:

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

汇编程序的默认入口标号是_start,也可以在链接脚本中使用ENTRY来指明其它的入口点。下面代码中.global 是伪操作,表示_start 是一个全局标号,类似 C 语言里面的全局变量。

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

还有其他常用伪操作:

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

4.ARM常用汇编指令

处理器内部数据传输命令:

  1. MOV指令,用于将数据从一个寄存器拷贝到另外一个寄存器,或者将一个立即数传递到寄存器。
MOV R0,R1 	  @将寄存器R1中的数据传递给R0,即R0=R1
MOV R0, #0X12 @将立即数0X12传递给R0寄存器,即R0=0X12
  1. MRS指令,用于将特殊寄存器(如CPSR和SPSR)中的数据传递给通用寄存器。
MRS R0, CPSR  @将特殊寄存器CPSR里面的数据传递给R0,即R0=CPSR
  1. MSR指令,和MRS相反,用来将普通寄存器的数据传递给特殊寄存器。
MSR CPSR, R0  @将R0中的数据复制到CPSR中,即CPSR=R0

存储器访问指令:

  1. LDR指令,LDR Rd, [Rn , #offset] ,从存储器Rn+offset的位置读取数据存放到Rd中。
    字节操作是LDRB,半字操作是LDRH。
LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, [R0]        @读取地址 0X0209C004 中的数据到 R1 寄存器中
  1. STR指令,STR Rd, [Rn, #offset] ,将Rd中的数据写入到存储器中的Rn+offset位置。字节操作是STRB,半字操作是STRH。
LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, =0X20000002 @R1 保存要写入到寄存器的值,即 R1=0X20000002
STR R1, [R0]        @将 R1 中的值写入到 R0 中所保存的地址中

压栈和出栈指令:
通常会在A函数中调用B函数,B函数执行完以后再回到A函数继续执行。必须在跳到B函数前保存当前处理器状态(R0 ~ R15寄存器值,即保护现场),B函数执行完后再恢复R0 ~ R15即可(即恢复现场)。保护现场需要进行压栈操作(PUSH指令),恢复现场要进行出栈操作(POP指令)。PUSH和POP是多存储和多加载指令,利用当前的栈指针SP来生成地址,能一次操作多个寄存器。

  1. PUSH < reg list >,将寄存器列表存入栈中,也可写作“STMFD SP!”。
  2. POP < reg list >,从栈中恢复寄存器列表,也可写作“LDMFD SP!”。

跳转指令:

  1. B指令,能将PC寄存器的值设置为跳转目标地址, 执行后ARM处理器就会立即跳转到指定的目标地址,不再返回原地址。
//设置栈顶指针后跳转到C语言
_start:
ldr sp,=0X80200000 @设置栈指针
b main 			   @跳转到 main 函数
  1. BL指令,在跳转之前会在寄存器LR(R14)中保存当前PC寄存器值,所以可以通过将LR 寄存器中的值重新加载到PC中来继续从跳转之前的代码处运行,是子程序调用的常用的方法。
//在汇编中使用bl执行C语言的中断服务函数
push {r0, r1} 		 @保存r0,r1
cps #0x13 			 @进入SVC模式,允许其他中断再次进去
bl system_irqhandler @加载C语言中断处理函数到r2寄存器中
cps #0x12            @进入IRQ模式
pop {r0, r1}
str r0, [r1, #0X10]  @中断执行完成,写EOIR

算术运算指令:
裸机开发(2) Cortex-A7简介 常用ARM汇编指令_第4张图片
逻辑运算指令:
裸机开发(2) Cortex-A7简介 常用ARM汇编指令_第5张图片

参考正点原子嵌入式linux开发指南

你可能感兴趣的:(I.MX6U学习笔记)