【ARM】v8架构programmer guide(4)_ARMv8的寄存器

目录

4.4Endianness(端序或字节序)

4.5 改变execution state

4.5.1 Registers at AArch32

4.5.2 PSTATE at AArch32

4.6 NEON 和浮点数寄存器

4.6.1 AArch64中浮点寄存器的组织结构

4.6.2 标量寄存器大小

4.6.3 向量寄存器大小

4.6.4 NEON在AArch32执行状态


4.4Endianness(端序或字节序)

在计算机体系结构中,有两种基本的内存中字节的视图,即小端序(Little-Endian, LE)和大端序(Big-Endian, BE):

  1. 大端序(Big-Endian, BE):在大端序的机器上,一个对象(如整数或浮点数)的内存中最高有效字节(Most Significant Byte, MSB)存储在最低的地址上,即最接近于零的地址。这意味着当你查看内存时,首先是最重要的字节。

  2. 小端序(Little-Endian, LE):在小端序的机器上,对象的最低有效字节(Least Significant Byte, LSB)存储在最低的地址上。这意味着内存中首先出现的是最不重要的字节。

  3. 字节序(Byte-Ordering):有时也使用“字节序”这个词来代替“端序”(endianness),表达的是相同的概念。

  4. 影响:字节序的选择会影响多字节数据类型在内存中的存储方式,这在数据传输和处理时尤为重要,尤其是在不同架构的系统之间进行通信时。

  5. 示例:假设有一个32位的整数0x12345678,在大端序系统中,它在内存中的存储顺序将是:

    • 地址0x00: 0x12
    • 地址0x01: 0x34
    • 地址0x02: 0x56
    • 地址0x03: 0x78

    而在小端序系统中,存储顺序将是:

    • 地址0x00: 0x78
    • 地址0x01: 0x56
    • 地址0x02: 0x34
    • 地址0x03: 0x12
  6. 系统设计:不同的系统设计选择不同的字节序,这取决于历史原因、特定的系统需求或性能考虑。

  7. 兼容性:了解系统的字节序对于编写能够在不同架构之间正确交换数据的软件非常重要。

4.5 改变execution state

我们从异常级别的角度描述了在AArch64和AArch32之间切换执行状态。现在我们从寄存器的角度来考虑这种切换:

当从使用AArch32的异常级别进入使用AArch64的异常级别时:

  • 在使用AArch32执行的任何较低异常级别上可访问的寄存器的高32位值是未知的
  • 在AArch32执行期间不可访问的寄存器保留着在AArch32执行之前的状态。
  • 在异常进入EL3时,如果EL2一直在使用AArch32,则ELR_EL2的高32位值是未知的
  • 与AArch64栈指针(SPs)和异常链接寄存器(ELRs)相关联的异常级别,在AArch32执行期间不可访问,在该异常级别上,保留着它们在AArch32执行之前的状态。这适用于以下寄存器:
    • SP_EL0。
    • SP_EL1。
    • SP_EL2。
    • ELR_EL1。

通常,应用程序程序员只为AArch32或AArch64编写应用程序。只有操作系统(OS)必须考虑这两种执行状态以及它们之间的切换。这意味着操作系统需要能够处理两种架构的上下文切换,确保在切换执行状态时,应用程序和系统能够正确地保存和恢复状态。

4.5.1 Registers at AArch32

AArch32与ARMv7在功能上几乎相同,这意味着AArch32必须匹配ARMv7的特权级别。同样,AArch32只处理ARMv7的32位通用寄存器。因此,ARMv8架构及其在AArch32执行状态下提供的视图之间必须存在某种对应关系。

请记住,在ARMv7架构中有十六个32位通用寄存器(R0-R15)供软件使用。其中十五个(R0-R14)可以用于通用数据存储。剩下的一个寄存器,R15,是程序计数器(PC),当核心执行指令时,其值会改变。软件还可以访问当前程序状态寄存器(CPSR),以及之前执行模式中CPSR的保存副本,即保存程序状态寄存器(SPSR)。在触发异常时,CPSR的值会被复制到异常目标模式的SPSR。

访问哪些寄存器以及在何处访问,取决于软件正在执行的处理器模式以及寄存器本身。这称为寄存器银行(banking),下图中的阴影寄存器就是banking的。它们使用物理上不同的存储空间,并且通常只有在进程在特定模式下执行时才能访问。

寄存器bank是一种机制,允许不同模式或异常级别拥有自己的寄存器集,从而在不同上下文之间提供隔离。这种隔离确保了操作系统和应用程序的稳定性和安全性,因为每个模式都可以维护自己的执行状态,而不会影响其他模式的状态。在AArch32执行状态下,这种机制允许软件与ARMv7架构保持兼容性,同时在ARMv8架构上运行。

在ARMv7中,寄存器bank(banking)被用来减少异常处理的延迟。然而,这也意味着在任何给定时间,可能的寄存器中少于一半可以被使用。相比之下,AArch64执行状态拥有31个64位通用寄存器,这些寄存器在所有异常级别上始终可访问。

在AArch64和AArch32之间的执行状态改变意味着AArch64寄存器必须映射到AArch32(ARMv7)寄存器集上。这种映射在下图中展示。

当在AArch32下执行时,AArch64寄存器的高32位是不可访问的。如果处理器在AArch32状态下运行,它使用32位的W寄存器,这些寄存器等同于32位ARMv7寄存器。

AArch32将银行化的寄存器映射到在AArch64状态下原本不可访问的寄存器。这种映射确保了两种执行状态之间的兼容性和过渡,允许操作系统和应用程序根据需要在AArch64和AArch32之间切换,同时保持数据和上下文的一致性。这种设计也简化了从ARMv7到ARMv8的迁移过程,因为它允许现有软件在新的64位架构上运行,尽管可能需要一些调整以利用AArch64的全部功能。

在AArch32中,SPSR(Saved Program Status Register)和ELR_Hyp(Exception Link Register for Hypervisor)是额外的寄存器,只能通过系统指令访问。它们没有映射到AArch64架构的通用寄存器空间中。以下是AArch32和AArch64之间的一些寄存器映射关系:

  • SPSR_svc(服务程序状态寄存器)映射到SPSR_EL1。
  • SPSR_hyp(虚拟机监视器程序状态寄存器)映射到SPSR_EL2。
  • ELR_hyp(虚拟机监视器异常链接寄存器)映射到ELR_EL2。

以下是仅在AArch32执行期间使用的寄存器。然而,由于在AArch64的EL1上执行,尽管在该异常级别上执行AArch64时它们不可访问,但它们仍然保留其状态:

  • SPSR_abt(异常服务程序状态寄存器)。
  • SPSR_und(未定义服务程序状态寄存器)。
  • SPSR_irq(中断服务程序状态寄存器)。
  • SPSR_fiq(快速中断服务程序状态寄存器)。

SPSR寄存器仅在AArch64的更高异常级别上执行时用于上下文切换,并且在这些级别上可访问。

再次强调,如果从AArch32的异常级别触发异常到AArch64的异常级别,AArch64的ELR_ELn的高32位将全部为零。这意味着在进行状态转换时,AArch64的异常链接寄存器的高32位不会被AArch32状态中的相应寄存器值所影响,而是被清零,以确保在AArch64环境中以一致的64位状态进行处理。

4.5.2 PSTATE at AArch32

在AArch64中,传统CPSR(Current Program Status Register)的不同组件被呈现为处理器状态(Processor State, PSTATE)字段,这些字段可以独立访问。而在AArch32中,有额外的字段对应于ARMv7 CPSR的位。

4.6 NEON 和浮点数寄存器

ARMv8除了拥有通用寄存器外,还有32个128位的浮点寄存器,标记为V0至V31。这些寄存器用于以下目的:

  • 存储标量浮点指令的浮点操作数。
  • 存储NEON(ARM的高级SIMD(单指令多数据))操作的标量和向量操作数。

NEON技术允许进行高效的多媒体和浮点运算,这些运算在图形、音频、视频、科学计算和许多其他应用程序中非常重要。这些128位寄存器在NEON指令中可以被当作一个128位的单一寄存器使用,或者在某些操作中被分为较小的寄存器组,例如两个64位寄存器或四个32位寄存器。这些浮点寄存器和NEON技术在ARMv8架构的AArch64执行状态下提供了强大的处理能力,特别是在需要大量数学和逻辑运算的应用程序中。

4.6.1 AArch64中浮点寄存器的组织结构

在NEON和操作标量数据的浮点指令中,浮点寄存器和NEON寄存器的表现类似于主要的通用整数寄存器。因此,只有低位有效位被访问,高位未使用的位在读取时被忽略,在写入时被设置为零。标量浮点和NEON的命名约定如下,其中n是一个0到31的寄存器编号:

  • 当使用标量浮点指令时,只有寄存器的低64位被使用。例如,如果使用S0进行操作,那么只有V0寄存器的低64位被读取或写入。
  • 对于NEON标量操作,可以指定使用寄存器的不同部分,例如使用D0的低64位或D0的高64位(如果指令支持这种操作)。
  • 在某些情况下,可以使用SD前缀来明确指出操作是针对单精度(32位)或双精度(64位)浮点数。

注意,ARMv8架构支持16位浮点数格式,但仅作为需要从该格式转换或转换到该格式的情况。它不支持将16位浮点数用于数据处理操作。

4.6.2 标量寄存器大小

在ARMv8架构中,寄存器的组织方式允许不同宽度的视图,以适应不同精度的操作。以下是一些关键点,解释了如何在不同的NEON和浮点指令中使用这些寄存器:

  • S0作为D0的低半部分:在图4中,S0是D0的低32位,而D0本身是Q0的低64位。这种模式对于S1、D1、Q1等也是类似的。

  • Q寄存器的低64位:每个Q寄存器的低64位可以被视为D0-D31,这是32个64位宽的寄存器,用于浮点和NEON操作。

  • Q寄存器的低32位:每个Q寄存器的低32位可以被视为S0-S31,这是32个32位宽的寄存器,同样用于浮点和NEON操作。

  • S寄存器的低16位:每个S寄存器的低16位可以被视为H0-H31,这是32个16位宽的寄存器,用于浮点和NEON操作。

  • H寄存器的低8位:每个H寄存器的低8位可以被视为B0-B31,这是32个8位宽的寄存器,仅用于NEON操作。

这种设计简化了编译器自动向量化高级代码的问题,因为它提供了一种自然的映射,使得标量代码更容易转换为NEON SIMD指令。例如,如果编译器识别到一个循环可以并行化,它可以将32个标量操作映射到NEON的128位寄存器上,每个寄存器可以容纳多个数据元素,从而实现更高效的数据处理。

此外,这种设计还允许程序员在编写汇编代码或低级代码时有更多的灵活性,因为他们可以选择适当的寄存器大小来匹配他们的数据类型和操作需求。这种灵活性对于优化性能和资源使用非常关键。

注意:

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

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

4.6.3 向量寄存器大小

向量可以是64位宽,包含一个或多个元素,也可以是128位宽,包含两个或多个元素。

4.6.4 NEON在AArch32执行状态

在AArch32中,较小的寄存器被打包进较大的寄存器中(例如,D0和D1组合成Q1)。这引入了一些棘手的循环携带依赖性,这可能会降低编译器向量化循环结构的能力。

在AArch32中,浮点和高级SIMD(NEON)寄存器被映射到AArch64的FP(浮点)和SIMD寄存器。这样做的目的是允许系统软件的更高层次,例如操作系统(OS)或虚拟机监视器(Hypervisor),来解释(并在必要时修改)应用程序或虚拟机的浮点和NEON寄存器。

AArch64的V16-V31浮点和NEON寄存器在AArch32中是不可见的。与通用寄存器一样,在AArch32执行异常级别期间,这些寄存器保留着之前使用AArch64执行时的状态。

  • 11
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值