【ARMv8 SIMD和浮点指令编程】寄存器

ARMv8 用于描述整体架构,包括 32 位执行和 64 位执行。它使用 64 位位宽寄存器,同时保持向后兼容 v7。

【ARMv8 SIMD和浮点指令编程】寄存器

二、通用寄存器

AArch64 执行状态提供了 31 × 64 位通用寄存器,在任何时候和所有异常级别都可以访问。每个寄存器是 64 位宽的,它们通常被称为寄存器 X0~X30。

【ARMv8 SIMD和浮点指令编程】寄存器
32 位 W 寄存器对应的 64 位 X 寄存器的下半部分。即 W0 映射到 X0 的下半部分,W1 映射到 X1 的下半部分。

从 W 寄存器读取时,忽略对应的 X 寄存器中较高的 32 位,并保持不变。写入 W 寄存器将 X 寄存器的高 32 位设置为零。也就是说,将 0xFFFFFFFF 写入 W0 会将 X0 设置为 0x00000000FFFFFFFF。

三、特殊寄存器

【ARMv8 SIMD和浮点指令编程】寄存器
标志 描述
N 负数标志位。结果为负数则 N=1,否则 N=0
Z 零标志位。如果结果为零,则 Z=1,否则 Z=0
C 进位标志位。如果结果有进位,则 C=1,否则 C=0
V 溢出标志位。如果结果有溢出,则 V=1,否则 V=0
SS 软件单步调试。该位为1,表示在异常处理时使能了软件单步功能。
IL 非法执行状态位。在异常处理之前立即显示 PSTATE.IL 的值。
D 进程状态调试掩码。指示来自观察点、断点和软件单步调试事件的调试异常是否被屏蔽,这些事件的目标是发生的异常所在异常级别。
A SError(系统错误)掩码。
I IRQ 掩码位。
F FIQ 掩码位。
M[4] 异常发生所处的执行状态。取值为 0 表示 AArch64
M[3:0] 异常发生时所处的模式或异常级别。

处理器状态 PSTATE

AArch64 没有直接等效于 ARMv7 当前程序状态寄存器(CPSR)。在 AArch64 中,传统 CPSR 的组件是作为字段提供的,可以独立访问。这些状态统称为处理器状态(PSTATE)。

AArch64 的处理器状态或 PSTATE 字段有以下定义:

名称 描述
N 负数标志位。
Z 零标志位。
C 进位标志位。
V 溢出标志位。
D 进程状态调试掩码。
A SError(系统错误)掩码。
I IRQ 掩码位。
F FIQ 掩码位。
SS 软件单步调试。
IL 非法执行状态位。
EL (2) 异常级别。
nRW 执行状态:0 = 64-bit,1 = 32-bit
SP 栈指针选择:0 = SP_EL0,1 = SP_ELn

在 AArch64 中,通过执行 ERET 指令从异常中返回,这将导致 SPSR_ELn 被复制到 PSTATE。这将恢复 ALU 标志、执行状态、异常级别和处理器分支。从这里开始,从 ELR_ELn 中的地址继续执行。

PSTATE.{N, Z, C, V} 字段可以在 EL0 访问。所有其他的 PSTATE 字段可以在 EL1 或更高的值访问,并且在 EL0 是未定义的。

四、系统寄存器

在 AArch64 中,系统配置通过系统寄存器控制,并使用 MSR 和 MRS 指令访问。这与 ARMv7-A 不同,在 ARMv7-A 中,这些寄存器通常是通过协处理器 15(CP15)操作访问的。寄存器的名称告诉你可以访问它的最低异常级别。例如:

  1. TTBR0_EL1 可通过 EL1、EL2、EL3 访问。
  2. TTBR0_EL2 可从 EL2 和 EL3 访问。

具有 _ELn 后缀的寄存器在某些或所有级别中具有单独的存储副本,尽管通常不是 EL0。很少有系统寄存器可以从 EL0 访问,尽管缓存类型寄存器(CTR_EL0)是一个可以访问的例子。

访问系统寄存器的代码采用以下形式:

以前版本的 ARM 架构使用协处理器进行系统配置。但是 AArch64 不支持。下表显示了每个寄存器的独立副本的异常级别。例如,ACTLR(辅助控制寄存器)以 ACTLR_EL1、ACTLR_EL2 和 ACTLR_EL3 的形式存在。

名称 寄存器 描述 允许的 n 值
ACTLR_ELn 辅助控制寄存器 控制特定于处理器的特性。 1, 2, 3
CCSIDR_ELn 当前缓存大小 ID 寄存器 提供有关当前选定缓存的体系结构信息。 1
CLIDR_ELn 缓存级 ID 寄存器 缓存的类型,或在每个级别实现的缓存。 1, 2, 3
CNTFRQ_ELn 计数型计时器的频率寄存器 上报系统计时器的频率。 0
CNTPCT_ELn 计数型计时器的物理计数寄存器 保存 64 位的当前计数值。 0
CNTKCTL_ELn 计数型计时器的内核控制寄存器 控制从虚拟计数器生成事件流。还控制从 EL0 到物理计数器、虚拟计数器、EL1 物理计时器和虚拟计时器的访问。 1
CNTP_CVAL_ELn 计数型计时器的物理计时器比较值寄存器 保存 EL1 物理计时器的比较值。 0
CPACR_ELn 协处理器访问控制寄存器 控制对 Trace、浮点和 NEON 功能的访问。 1
CSSELR_ELn 缓存大小选择寄存器 通过指定所需的缓存级别和缓存类型(指令缓存或数据缓存),选择当前的缓存大小 ID 寄存器 CCSIDR_EL1。 1
CNTP_CTL_ELn 计数型计时器的物理控制寄存器 控制寄存器的 EL1 物理计时器。 0
CTR_ELn 缓存类型寄存器 关于集成缓存架构的信息。 0
DCZID_ELn 数据缓存零 ID 寄存器 由 DCZVA(Data Cache 0 by Virtual Address)系统指令写入的字节值为 0 的块大小。 0
ELR_ELn 异常链接寄存器 保存导致异常指令的地址。 1, 2, 3
ESR_ELn 异常诊断(Syndrome)寄存器 包括有关异常原因的信息。 1, 2, 3
FAR_ELn 故障地址寄存器 保存虚拟故障地址。 1, 2, 3
FPCR 浮点控制寄存器 控制浮点扩展行为。这个寄存器中的字段映射到 AArch32 FPSCR 中的等效字段。
FPSR 浮点状态寄存器 提供浮点系统状态信息。这个寄存器中的字段映射到 AArch32 FPSCR 中的等效字段。
HCR_ELn Hypervisor 配置寄存器 控制虚拟化设置和捕获 EL2 的异常。 2
MAIR_ELn 内存属性间接寄存器 提供与 ELn 的阶段 1 转换的长描述格式转换表项中可能值对应的内存属性编码。 1, 2, 3
MIDR_ELn 主 ID 寄存器 运行代码的处理器类型(部件号和版本号)。 1
MPIDR_ELn 多处理器亲和性寄存器 多核或集群系统中的处理器和集群 ID。 1
SCR_ELn 安全配置寄存器 控制 EL3 的安全状态和异常捕获。 3
SCTLR_ELn 系统控制寄存器 控制架构特性,例如 MMU、缓存和对齐检查。 0, 1, 2, 3
SPSR_ELn 保存程序状态寄存器 当此模式或异常级别发生异常时,保持已保存的处理器状态。 abt, fiq, irq, und, 1,2, 3
TCR_ELn 转换控制寄存器 确定哪个转换表基址寄存器定义了从 ELn 访问内存的阶段 1 转换所需的转换表遍历的基地址。还控制转换表格式并保存可缓存性和可共享性信息。 1, 2, 3
TPIDR_ELn 用户读/写线程 ID 寄存器 提供在 ELn 处执行的软件可以存储线程标识信息的位置,以用于 OS 管理。 0, 1, 2, 3
TPIDRRO_ELn 用户仅允许读线程 ID 寄存器 提供在 EL1 或更高版本执行的软件可以存储线程标识信息的位置。出于 OS 管理目的,此信息对在 EL0 处执行的软件可见。 0
TTBR0_ELn 转换表基址寄存器 0 保存转换表 0 的基地址,以及有关它占用的内存的信息。这是 ELn 内存访问阶段 1 转换的转换表之一。 1, 2, 3
TTBR1_ELn 转换表基址寄存器 1 保存转换表 1 的基地址,以及有关它占用的内存的信息。这是 EL0 和 EL1 内存访问的阶段 1 转换的转换表之一。 1
VBAR_ELn 基于向量的地址寄存器 保存被带到 ELn 的任何异常的异常基地址。 1, 2, 3
VTCR_ELn 虚拟化转换控制寄存器 控制从非安全 EL0 和 EL1 进行内存访问的第 2 阶段转换所需的转换表遍历。还保存访问的可缓存性和可共享性信息。 2
VTTBR_ELn 虚拟化转换表基址寄存器 保存从非安全 EL0 和 EL1 进行内存访问的阶段 2 转换的转换表的基地址。 2

五、NEON 和浮点寄存器

除了通用寄存器,ARMv8 还有 32 个 128 位浮点寄存器,标记为 V0-V31。 32 个寄存器用于保存标量浮点指令的浮点操作数以及 NEON 操作的标量和向量操作数。

AArch64 中的浮点寄存器组织

在对标量数据进行操作的 NEON 和浮点指令中,浮点和 NEON 寄存器的行为类似于主要的通用整数寄存器。因此,仅访问低位,读取时忽略未使用的高位,写入时设置为零。标量浮点和 NEON 名称的限定名称表示有效位数如下,其中 n 是寄存器编号 0-31。

不同大小的浮点数的操作数名称表

精度 大小(bits) 名称
Half(半) 16 Hn
Single(单) 32 Sn
Double(双) 64 Dn

【ARMv8 SIMD和浮点指令编程】寄存器
图中 S0 为 D0 的下半部分,D0 为 Q0 的下半部分。S1 是 D1 的下半部分,D1 是 Q1 的下半部分,以此类推。这消除了编译器在自动向量化高级代码时存在的许多问题。
  1. 每个 Q 寄存器的底部 64 位也可以被视为 D0-D31, 32 位浮点和 NEON 使用的 64 位寄存器。

  2. 每个 Q 寄存器的底部 32 位也可以被视为 S0-S31, 32 位浮点和 NEON 使用的32 位宽寄存器。

  3. 每个 S 寄存器的底部 16 位也可以被视为 H0-H31, 32 个 16 位宽寄存器用于浮点和 NEON 使用。

  4. 每个 H 寄存器的底部 8 位也可以被视为 B0-B31, 32 个 8 位宽寄存器用于 NEON。

在每种情况下,仅使用每个寄存器组的低位。其余的寄存器空间读取时忽略,写入时填充零。

这种映射的结果是,如果在 AArch64 中执行的程序正在解释来自 AArch32 的 D 或 S 寄存器。那么,在使用 D 或 S 寄存器之前,程序必须将它们从 V 寄存器中解包。

对于标量 ADD 指令:

例如,如果大小为 32 位,则指令为:

不同尺寸标量操作数的名称见下表

字大小 大小(bits) 名称
Byte 8 Bn
Halfword 16 Hn
Word 32 Sn
Doubleword 64 Dn
Quadword 128 Qn

向量寄存器大小

向量可以是 64 位宽,包含一个或多个元素,也可以是 128 位宽,包含两个或多个元素,如图所示:

【ARMv8 SIMD和浮点指令编程】寄存器
参考资料

《ARMv8-A-Programmer-Guide》

来源:TYYJ-洪伟

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年7月25日
下一篇 2022年7月25日

相关推荐