64 位内存中的 32 位固定指令长度 space
32-bit fixed instruction length in 64-bit memory space
我目前正在阅读 ARM 的 AArch64 架构。他们使用类似 RISC 的指令集,指令长度固定为 32 位,同时在 64 位地址上运行。我对 ISA 的话题还很陌生,所以我的问题是:当指令中只有 32 位长度时,如何使用 64 位长地址进行操作?
您可以使用 4 位 CPU 对 4096 位值进行运算,只是执行速度不会非常快。任何带有 "bignum" type 的编程语言都将以这种方式工作,但通常不会达到同样的极端。
32 位 CPU 可以对 64 位值进行操作的方式是因为硬件或软件允许,没有其他原因。
在我们拥有 64 位 CPU 之前,我们并不是不能操作 64 位整数值。即使是旧的 Intel 80386 也可以支持 64 位操作,它是在 1985 年发布的。
32 位是以字节为单位的指令长度,而不是操作数大小或地址大小。
ARM 32 位(与所有其他使用 32 位固定宽度指令字的 32 位 RISC 一样)也无法将 32 位地址作为立即数放入单个指令中:会有操作码没有空间说明它是什么指令。
一条指令的宽度限制了您可以拥有的数量个寄存器。每条指令有 3 个寄存器(dst、src1、src2),AArch64 从 16 个增加到 32 个寄存器意味着每条指令需要 3 * log2(32) = 3* 5
= 15 位来编码寄存器。对于只有 2 个或 1 个寄存器的指令,或更少。 (例如 mov-immediate 或 add-immediate)。 space 的其余部分用于可能的操作码数量和立即数的大小。
为了将地址放入寄存器,ARM 编译器通常会从附近的常量池中加载它(使用 PC 相对寻址模式)。
另一个选项是大多数 RISC CPU 所做的:使用 2 指令序列将 16 位立即数放入寄存器的上半部分,然后将 16 位立即数放入寄存器的下半部分。 (或者使用静态地址的下半部分作为 load/store 指令的位移,该指令使用寄存器 + 16 位偏移等寻址模式。)
MIPS 是非常简单的 RISC 的一个很好的例子,参见 it's ISA with binary encoding。它的 lui reg, imm16
将 imm16 <<16
放入寄存器。 (立即加载上层)。然后 lw dst, imm16(base_reg)
就像我在上一段中所说的那样是一个负载。
即使在 64 位代码中,大多数数字仍然很小,因此不需要更宽的立即操作数(地址除外)。例如x86 仍然为 add r64, imm
选择 32 位或 8 位立即数操作数。在很多情况下,当立即数在 -128
和 +127
之间时,作为可变长度 ISA 的 x86 可以节省 space。
我目前正在阅读 ARM 的 AArch64 架构。他们使用类似 RISC 的指令集,指令长度固定为 32 位,同时在 64 位地址上运行。我对 ISA 的话题还很陌生,所以我的问题是:当指令中只有 32 位长度时,如何使用 64 位长地址进行操作?
您可以使用 4 位 CPU 对 4096 位值进行运算,只是执行速度不会非常快。任何带有 "bignum" type 的编程语言都将以这种方式工作,但通常不会达到同样的极端。
32 位 CPU 可以对 64 位值进行操作的方式是因为硬件或软件允许,没有其他原因。
在我们拥有 64 位 CPU 之前,我们并不是不能操作 64 位整数值。即使是旧的 Intel 80386 也可以支持 64 位操作,它是在 1985 年发布的。
32 位是以字节为单位的指令长度,而不是操作数大小或地址大小。
ARM 32 位(与所有其他使用 32 位固定宽度指令字的 32 位 RISC 一样)也无法将 32 位地址作为立即数放入单个指令中:会有操作码没有空间说明它是什么指令。
一条指令的宽度限制了您可以拥有的数量个寄存器。每条指令有 3 个寄存器(dst、src1、src2),AArch64 从 16 个增加到 32 个寄存器意味着每条指令需要 3 * log2(32) = 3* 5
= 15 位来编码寄存器。对于只有 2 个或 1 个寄存器的指令,或更少。 (例如 mov-immediate 或 add-immediate)。 space 的其余部分用于可能的操作码数量和立即数的大小。
为了将地址放入寄存器,ARM 编译器通常会从附近的常量池中加载它(使用 PC 相对寻址模式)。
另一个选项是大多数 RISC CPU 所做的:使用 2 指令序列将 16 位立即数放入寄存器的上半部分,然后将 16 位立即数放入寄存器的下半部分。 (或者使用静态地址的下半部分作为 load/store 指令的位移,该指令使用寄存器 + 16 位偏移等寻址模式。)
MIPS 是非常简单的 RISC 的一个很好的例子,参见 it's ISA with binary encoding。它的 lui reg, imm16
将 imm16 <<16
放入寄存器。 (立即加载上层)。然后 lw dst, imm16(base_reg)
就像我在上一段中所说的那样是一个负载。
即使在 64 位代码中,大多数数字仍然很小,因此不需要更宽的立即操作数(地址除外)。例如x86 仍然为 add r64, imm
选择 32 位或 8 位立即数操作数。在很多情况下,当立即数在 -128
和 +127
之间时,作为可变长度 ISA 的 x86 可以节省 space。