🗒️A64指令集学习
2024-9-29
| 2024-11-5
字数 2025阅读时长 6 分钟
type
status
date
slug
summary
tags
category
icon
password
URL
参考文档:Armv8-A Instruction Set Architecture.pdf

一、前言

Armv8-A 中的指令集 Armv8-A 支持三种指令集:A32、T32 和 A64。
在AArch64执行状态下执行时使用A64指令集。它是一个固定长度的32位指令集。名称中的 “64”指的是 AArch64 执行状态对该指令的使用。它不是指内存中指令的大小。
A32 和 T32 指令集也分别称为“ARM”和“Thumb”。这些指令集在 AArch32 执行状态下执行时使用。在本指南中,我们不介绍 A32 和 T32 指令集。
每个版本的 Arm 架构都有自己的 Arm 架构参考手册(Arm ARM),可以在 Arm 开发者网站上找到。每个Arm ARM都提供了每条指令的详细说明,包括:
  • 编码——指令在内存中的表示。
  • 参数 - 指令的输入。
  • 伪代码 - 指令的作用,以 Arm 伪代码语言表示。
  • 限制 - 当指令不能使用时,或者它可以触发的异常。
A64 的指令描述也以 XML 和 HTML 形式提供。如果您需要经常参考说明,则 XML 和 HTML 格式
非常有用。 XML 和 HTML 格式可以在 Arm 开发者网站上找到。

1.1 指令概况

指令基本格式
<Opcode>{<Cond>}<S> <Rd>, <Rn> {,<Opcode2>}
  • 其中尖括号是必须的,花括号是可选的
  • A32 Rd => {R0R14}
  • A64 Rd =>Xt => {X0X30}

1.2 指令分类

类型
Note
跳转指令
条件跳转、无条件跳转(#immregister)指令
异常产生指令
系统调用类指令(SVCHVCSMC
系统寄存器指令
读写系统寄存器,如 :MRSMSR指令 可操作PSTATE的位段寄存器
数据处理指令
包括各种算数运算、逻辑运算、位操作、移位(shift)指令
load/store内存访问指令
load/store {批量寄存器、单个寄存器、一对寄存器、非-暂存、非特权、独占}以及load-Acquirestore-Release指令 (A64没有LDM/STM指令)
协处理指令
A64没有协处理器指令

1.3 指令助记符

整型
W/R
32bit整数
X
64bit整数
加载/存储、符号-0扩展
B
无符号8bit字节
SB
带符号8bit字节
H
无符号16bit半字
SH
带符号16bit半字
W
无符号32bit
SW
带符号32bit
P
Pair(一对)
寄存器宽度改变
H
高位(dst gets top half
N
有限位(dst < src
L
Long dst > src
W
Wide (dst==src1,src1>src2)

1.4 指令条件码

编码
助记符
描述
标记
0000
EQ
运算结果相等为1
Z==1
0001
NE
运算结果不等为0
Z==0
0010
HS/CS
无符号高或者相同进位,发生进位为1
C==1
0011
LO/CC
无符号低清零,发生借位为0
C==0
0100
MI
负数为1
N==1
0101
PL
非负数0
N==0
0110
VS
有符号溢出为1
V==1
0111
VC
没用溢出为0
V==0
1000
HI
无符号 >
C==1 && Z==0
1001
LS
无符号 <=
!(C==1 && Z==0)
1010
GE
带符号 >=
N==V
1011
LT
带符号 <
N!=V
1100
GT
带符号 >
Z==0 && N==V
1101
LE
带符号 <=
!( Z==0 && N==V)
1110
AL
无条件执行
Any
1111
NV

二、跳转指令

通常,处理器按程序顺序执行指令。这意味着处理器按照指令在内存中设置的顺序执行指令。更改此
顺序的一种方法是使用分支指令。分支指令改变程序流程并用于循环、决策和函数调用。
A64指令集还有一些条件分支指令。这些指令会根据先前指令的结果更改其执行方式。

2.1 无条件跳转指令

2.2 条件跳转指令

2.3 举例说明

第一个例子:如果a等于5,则b等于5
使用汇编编写,如下所示
第二个例子:当a不等于0时,b+c赋值给b,a-1赋值给a
使用汇编

三、PC相对寻址

读取PC的方法:PC相对地址指令(ADR, ADRP),以及branch-and-link指令(BL和BLR)会将PC地址存储在LR寄存器
修改PC的方法:使用显示控制流指令:条件分支、无条件分支、异常产生和异常返回指令
相对于A32的操作PC的MOV指令,A64已经不支持

3.1 ADR指令

使用格式:ADR register exper
编译时,首先会计算出当前PC到exper的偏移量#offset_to_exper
然后会用ADD或者SUB指令,来替换这个指令;例如等效于:ADD register,PC,#offset_to_exper
register就是exper的地址

3.2 ADRP指令

使用格式:ADRP register exper
编译时,会计算出当前PC到exper的偏移量#offset_to_exper
pc的低12位清零,然后加上偏移量给register,得到的地址时含有label的4kb对齐的内存区域的base地址

3.3 实例

  1. 本代码取自warm项目开机汇编代码的head.S的部分
notion image
解释:
  • 第365行:读取init_idmap_pd_dir的地址并写入到x0寄存器
  • 第366行:读取init_idmap_pd_end的地址并写入x1寄存器
  • 第372行:读取init_pd_dir的地址并写入x0寄存器
备注:这部分的地址在vmlinux.lds.S中被定义
notion image

四、系统操作指令

4.1 cache操作指令DC/IC

分为DC/IC指令,两者的区别在于DC为操作D-cache的指令,IC为操作I-cache的指令
这部分详看Armv8-A.pdf中的第D4.4.8 A64 Cache maintenance instructions部分
这部分还没有看,到后面专门学cache后来补充这部分内容,暂时设为TODO

4.2 地址翻译指令AT

notion image
以AT S1E1R为例
notion image
就是说给一个EL1或者EL2权限的虚拟地址,执行此AT指令后,就可以在PAR_EL1寄存器中读到翻译后的地址
下面请看这段c代码
notion image
notion image
notion image
read_sys_reg_par函数其实就是用的MRS指令读取PAR_EL1寄存器

4.3 TLBI指令

TLBI指令用于使 TLBs 中的条目无效。此指令的语法为:
TLBI < type >< level >{IS|OS} {, < xt >}
其中,
< type >,哪些条目无效
All - 所有条目
VA - 匹配在 Xt 的 VA 和 ASID 的条目 [ Entry matching VA and ASID in Xt ]
VAA - 匹配在 Xt 中的 VA ,任何 ASID 的条目
ASID - 匹配在 Xt 中的 ASID 的任何条目
...
< level >,要操作的地址空间
E1 = EL0/1虚拟地址空间
E2 = EL2虚拟地址空间
E3 = EL3虚拟地址空间
< IS|OS >,无论一个操作是内部可共享(IS)还是外部可共享(OS)
当 IS 添加到操作时,它将广播到内部共享域中的其他核心
当 OS 添加到操作时,它将广播到外部共享域的其他核心(在Armv8.4-A中添加)
< Xt >,操作哪个地址或ASID
仅用于按地址或ASID进行的操作
关于TLB的介绍,后面在学习到TLB章节时详细描述,本节仅描述此指令的功能以及用法
以linux内核api flush_tlb_all函数为例
notion image
notion image
最终调用的指令位tlbi vmalle1is
notion image

五、异常产生和返回指令

指令
解释
SVC
SVC系统调用,目标异常等级为EL1
HVC
HVC系统调用,目标异常等级为EL2
SMC
SMC系统调用,目标异常等级为EL3
ERET
异常返回,使用当前的SPSR_ELxELR_ELx

六、系统存储器指令

指令
解释
MRS
R <- S: 通用寄存器 <= 系统寄存器
MSR
S <- R: 系统寄存器 <= 通用寄存器

七、数据运算指令

算数运算
逻辑运算
数据传输
地址生成
位段移动
移位运算
ADDS
ANDS
MOV
ADRP
BFM
ASR
SUBS
EOR
MOVZ
ADR
SBFM
LSL
CMP
ORR
MOVK
UBFM
LSR
SBC
MOVI
BFI
ROR
RSB
TST
BFXIL
RSC
SBFIZ
CMN
SBFX
MADD
UBFIZ
MSUB
MUL
SMADDL
SDIV
UDIV

7.1 算术运算指令

指令
解释
ADDS
加法指令,若S存在,则更新条件位flag
ADCS
带进位的加法,若S存在,则更新条件位flag
SUBS
减法指令,若S存在,则更新条件位flag
SBC
将操作数 1 减去操作数 2,再减去 标志位C的取反值 ,结果送到目的寄存器Xt/Wt
RSB
逆向减法,操作数 2 –操作数 1,结果 Rd
RSC
带借位的逆向减法指令,将操作数 2 减去操作数 1,再减去 标志位C的取反值 ,结果送目标寄存器Xt/Wt
CMP
比较相等指令
CMN
比较不等指令
NEG
取负数运算,NEG X1X2 // X1 = X2按位取反+1(负数=正数补码+1
MADD
乘加运算
MSUB
乘减运算
MUL
乘法运算
SMADDL
有符号乘加运算
SDIV
有符号除法运算
UDIV
无符号除法运算

7.2 逻辑运算指令

指令
解释
ANDS
按位与运算,如果S存在,则更新条件位标记
EOR
按位异或运算
ORR
按位或运算
TST
例如:TST W0, #0X40 //指令用来测试W0[3]是否为1,相当于:ANDS WZR,W0#0X40
不再多介绍,这部分遇到了直接查

八、load/store指令

对齐偏移
非对齐偏移
PC-相对寻址
访问一对
非暂存
非特权
独占
AcquireRelease
LDR
LDUR
LDR
LDP
LDNP
LDTR
LDXR
LDAR
LDRB
LDURB
LDRSW
LDRSW
STNP
LDTRB
LDXRB
LDARB
LDRSB
LDURSB
STP
LDTRSB
LDXRH
LDARH
LDRH
LDURH
LDTRH
LDXP
STLR
LDRSH
LDURSH
LDTRSH
STXR
STLRB
LDRSW
LDURSW
LDTRSW
STXRB
STLRH
STR
STUR
STTR
STXRH
LDAXR
STRB
STURB
STTRB
STXP
LDAXRB
STRH
STURH
STTRH
LDAXRH
LDAXP
STLXR
STLXRB
STLXRH
STLXP

8.1 Load/Store (Scaled Offset)

所谓Scaled Unscaled其实就是可以见到理解为对齐和非对齐,本质就是是否乘以一个常量,因为scaled的总是可以乘以一个常量来达到对齐,而Unscaled就不需要,是多少就多少,更符合人类自然的理解
指令
解释
LDR
Memory地址addr中读取双字/字节/半字/字数据到目标寄存器Xt/Wt中带”S”表示需要符号扩展.
LDRB
LDRSB
LDRH
LDRSH
LDRSW
STR
Xn/Wn中的双字/字节/半字数据写入到Memory地址addr
STRB
STRH
 

8.2 Load/Store (Unscaled Offset)

指令
解释
LDUR
Memory地址addr中读取双字/字节/半字/字数据到目标寄存器Xt/Wt中带”S”表示需要符号扩展.立即数偏移 #simm9 = { -256 ~ +256 } 的任意整数,不需要对齐规则.
LDURB
LDURSB
LDURH
LDURSH
LDURSW
STUR
Xn/Wn中的双字/字节/半字数据写入到Memory地址addr中立即数偏移 #simm9 = { -256 ~ +256 } 的任意整数,不需要对齐规则.
STURB
STURH

8.3 Load/Store PC-relative(PC相对寻址)

指令
解释
LDR
Memory地址addr中读取双字/字数据到目标寄存器Xt/Wt中带”S”表示需要符号扩展.
LDRSW

8.4 Load/Store Pair(一对)

指令
解释
LDP
Memory地址addr处读取两个双字/字数据到目标寄存器Xt1Xt2带”S”表示需要符号扩展.
LDRSW
STP
Xt1Xt2两个双字/字数据写到Memory地址addr

8.5 Load/Store Non-temporal(非暂存) Pair

所谓Non-temporal就是就是用于你确定知道该地址只加载一次,不需要触发缓存,避免数据被刷新,优化性能,其它指令都默认会写Cache
指令
解释
LDNP
Memory地址addr处读取两个双字/字数据到目标寄存器Xt1Xt2, 标注非暂存访问,不更新cache带”S”表示需要符号扩展.
STNP
Xt1Xt2两个双字/字数据写到Memory地址addr中,标注非暂存访问,不更新cache

8.6 Load/Store Unprivileged(非特权)

所谓Unprivileged就是说EL0/EL1的内存有不同的权限控制,这条指令以EL0的权限存取,用于模拟EL0的行为,该指令应用于EL1和EL0之间的交互.
指令
解释
LDTR
Memory地址addr中读取双字/字节/半字/字数据到目标寄存器Xt/Wt中,当执行在EL1的时候使用EL0的权限带”S”表示需要符号扩展
LDTRB
LDTRSB
LDTRH
LDTRSH
LDTRSW
STTR
Xn/Wn中的双字/字节/半字数据写入到Memory地址addr中,当执行在EL1的时候使用EL0的权限
STTRB
STTRH

8.7 Load/Store Exclusive(独占)

在多核CPU下,对一个地址的访问可能引起冲突,这个指令解决了冲突,保证原子性(所谓原子操作简单理解就是不能被中断的操作),是解决多个CPU访问同一内存地址导致冲突的一种机制。
比如2个CPU同时写,其中一条的Ws就会返回失败值。通常用于锁,比如spinlock,可以参考代码:arch/arm64/include/asm/spinlock.h
指令
解释
LDXR
Memory地址addr中读取双字/字节/半字数据到目标寄存器Xt/Wt中,标记物理地址是独占访问的
LDXRB
LDXRH
LDXP
Memory地址addr中读取一对双字数据到目标寄存器Xt1Xt2中,标记物理地址是独占访问的
STXR
Xn/Wn中的双字/字节/半字数据写入到Memory地址addr中,返回是否独占访问成功状态(Ws
STXRB
STXRH
STXP
Xt1Xt2一对双字字数据写入到Memory地址addr中,返回是否独占访问成功状态

8.8 Load-Acquire/Store-Release

指令
解释
Non-exclusive(非独占)
LDAR
Memory地址addr中读取一个双字/字节/半字数据到目标寄存器Xt/Wt中,标记物理地址为非独占访问
LDARB
LDARH
STLR
把一个双字/字节/半字数据Xt/Wt写到Memory地址addr中,返回是否独占访问成功状态
STLRB
STLRH
Exclusive(独占)
LDAXR
Memory地址addr中读取一个双字/字节/半字数据到目标寄存器Xt/Wt中,标记物理地址为独占访问 LDAXP Pair 访问
LDAXRB
LDAXRH
LDAXP
STLXR
把一个双字/字节/半字数据Xt/Wt写到Memory地址addr中,返回是否独占访问成功状态 STLXP Pair 访问
STLXRB
STLXRH
STLXP

九、内存屏蔽指令

指令
翻译
解释
DMB
数据内存屏障指令
保证该指令前的所有内存访问结束,而该指令之后引起的内存访问只能在该指令执行结束后开始,其它数据处理指令等可以越过DMB屏障乱序执行
DSB
数据同步屏障指令
DSBDMB管得更宽,DSB屏障之后的所有得指令不可越过屏障乱序执行
ISB
指令同步屏障指令
ISBDSB管的更宽,ISB屏障之前的指令保证执行完,屏障之后的指令直接flush掉再重新从Memroy中取指
在第4.2 地址翻译指令AT的案例中也使用了dsb的内存屏蔽指令
 
  • arm
  • ARMv8 寄存器高通平台Logfs分区Uefilog乱码乱序问题
    Loading...