RISC 访问地址大于最大整数寄存器
RISC access address greater than largest integer register
假设您是 运行 32 位 RISC 系统。您将使用什么指令来访问 64 位内存地址?
在CISC指令集中,您可以使用多字指令简单地传递额外的字。例如:
1a) JMP
1b) loAddress
1c) hiAddress
鉴于 RISC 指令每条只有一个字,您将如何访问多字地址?
假设 ALU 是 32 位的并且有一个进位标志。
此外,在 CISC 系统(例如 8080)中,loAddress 和 hiAddress 字都将存储在程序存储器中。 IE。 JMP
指令知道查看程序存储器中的下一项以检索 loAddress
,然后查看下一项以检索 hiAddress
。 RISC 会发生什么?
即使在 CISC 上,你描述的情况也很不寻常。 不是因为是CISC,而是因为使用了比寄存器更宽的地址。这通常只在 8 位 CPU 中出现。 (尽管 x86 分段也符合条件,间接远跳采用指向 m16:32
段/偏移对的指针。或者在 16 位模式下,m16:16
。作为小端,偏移在前。 ) 在 64 位模式之外,jmp ptr16:32
也是可编码的,绝对 segment:offset 作为指令流的一部分。)
通常当你想设计一个CPU更大的地址space时,你也会使寄存器更宽,这样你就可以有效地处理地址。当您想通过使用大部分 8 位寄存器/ALU 来节省晶体管时,它只是在非常低端,但不能将您的地址 space 限制为 256 字节,您可以在其中找到这种设计。
即使地址大小与字长相符,这里也确实存在问题。 构造任意32位(或64位)常量是不同ISA以不同方式解决的问题。 ARM 通常使用来自附近 "literal pool" 的 PC 相关负载,而其他人通常使用 lui
或等效设置高 16 位并将其余部分置零,然后使用 16 位 ori
即时。 (ARM 有一些巧妙的技巧,通过使用 shifted/rotated 立即数来编码仅设置了几个位的立即数。)
一般在RISC上,如果你需要跳远,你可能需要使用多条指令在一个寄存器中构造地址。然后使用跳转到寄存器说明。
MIPS 分支指令很有趣:它有相对分支,在相当大的范围内向程序计数器添加一个带符号的位移,以及用新地址替换PC 低28 位的绝对跳转指令。 (由26位立即数左移构造,因为MIPS要求指令对齐所以低2位不需要存储。)How to Calculate Jump Target Address and Branch Target Address?。但是当目标无法从当前位置到达时,您需要 jr
和寄存器中的地址。
x86-64也缺少64位相对跳转指令。如果您需要跳转超过 +-2GiB 的距离(而不是 far
,就像在新的 CS 段中一样),您需要间接跳转。正常的 jump/branch 指令仍然使用 rel8
或 rel32
位移,以保持机器代码紧凑。唯一可以采用 64 位立即数的指令是 mov
-to-register。正常的代码模型假定同一库或 executable 中的所有代码彼此之间的距离在 2GiB 以内,因此链接器将能够填充 32 位位移。
8 位 RISC
据我所知,程序计数器比寄存器宽的唯一 RISC ISA 是 AVR,它是一种带有 8 位寄存器的微控制器。 它可以把成对的寄存器当作16位地址,它的PC是16位的。它 IJMP
(indirect jump) instruction 设置 PC = Z(其中 Z
是一对 8 位寄存器)。在具有 22 位程序计数器而不是 16 位程序计数器的 AVR 上,它将 PC(21:16)
.
归零
EIJMP(扩展间接跳转)从I/Ospace取EIND寄存器为PC的高位,低位仍然来自Z
。
AVR指令几乎都是2字节长,但有些版本a 4-byte jmp
instruction需要一个0..4M的绝对地址作为跳转目标。
32位寄存器的主流RISC机器也有32位程序计数器和虚拟地址-spaces。 (拥有超过 4GiB 的物理内存是可能的,但您无法在一个进程中同时映射所有内存)。
他们中的大多数在他们的设计中都是以字为导向的,所以他们所需要的只是 jr reg
(MIPS) 或任何等效于分支到任何可能地址的东西,因为它适合一个寄存器。这是 RISC 字面上所代表的降低的 复杂性 的一部分。
在像 MIPS、SPARC 或 PowerPC 这样的普通 RISC 上,64 位地址仅在 64 位 ISA 扩展中可用,其中有 64 位整数寄存器.因此,您将使用像 MIPS ld , 0()
这样的指令来使用 </code> 作为 64 位基地址来执行 64 位(双字)加载。看到这个 <a href="https://www.cs.cmu.edu/afs/cs/academic/class/15740-f97/public/doc/mips-isa.pdf" rel="nofollow noreferrer">MIPS-IV ISA manual</a>。 (MIPS-III 添加了 64 位扩展,带有 <code>ld
和 daddu
等指令。显然 MIPS-I 留下了很多未使用的操作码编码 space,因此有足够的空间新的操作码来完成完整的 64 位 ALU 操作。)
一些 32 位 CPU 添加了扩展以支持大 物理 地址而不增加虚拟地址 space。例如,x86 的 PAE 定义了一种新的 page-table 格式,具有 36 位物理地址。但即使使用分段,单个进程也不能同时处理超过 4GiB 的虚拟内存。 (x86 段基址+偏移发生在之前 virt->phys 转换,创建一个 32 位线性地址。因此它对于线程本地存储仍然有用,例如 [fs:0]
一个不同的线性地址,具体取决于该线程的 fs
段基数。)
32 位 RISC ISA 上的扩展寻址
保罗克莱顿评论:
PA-RISC had "space registers" which provided extended addressing. 32-bit PowerPC had segment registers which were selected based on the most significant 4 bits of the effective address from a 16-entry table (providing a 52-bit virtual address space). For PA-RISC "SRs 5 through 7 can be modified only by code executing at the most privileged level." For PowerPC, any segment register change required privilege.
很明显,一些 RISC ISA 在进入完全 64 位之前确实扩展了它们的寻址。但我不知道细节,也不打算花时间研究这个。欢迎其他答案!
Given that RISC instructions are only one word each
这不是真的。大多数现代 RISC 架构都有可变宽度指令集,或者至少有一个特殊的可变宽度模式(RISC-V 中的 ForwardCom, SuperH, MIPS16e, thumb2 in ARM, C instruction set...),尽管它们主要用于 compacting 目的是增加 代码密度 。这仍然意味着您实际上可以让您的 RISC 架构使用多字指令
即便如此,它也无济于事,除非您可以使用比 64 位更宽的指令(太大而不实用)。只有两个 32 位字,您仍然会被限制在基地址周围的一些 偏移量 而不是完整的 64 位地址 space。但这应该不是问题,因为几乎没有一个程序可以利用庞大的 64 位地址 space。这就是为什么在 x86-64 中没有指令接收 64 位立即地址,因为 32 位偏移量已经足够了。所以你可以这样做:在大多数情况下使用一个小的立即偏移量,并在你需要完整的 64 位地址时使用一个 2 寄存器对
正如 Peter 所说,比字长宽的地址主要只出现在 8 位微控制器中。除了AVR,它也被用在8位PIC where the program counter is 13 or 14-bit long. Instructions generally contain only the low bits of the address, the high bits will be taken from the PC or PCLATH register. If you don't want to use an offset like above then replacing the low bits directly like this is an alternative way. Obviously you still need a separate register for the high bits. But if you don't care about orthogonality然后只用一个专用的大寄存器来寻址,就像在8051、6502或其他更老的CISC架构
还有很多其他方法可以支持比我在此处描述的寄存器大小更宽的地址范围 How can 8-bit processor support more than 256 bytes of RAM?. One of them is to limit virtual address to the register size only (like ARM LPAE or x86 PAE), while allowing physical address to be 64-bit wide. The pages will be mapped in the TLB and you don't need to use 2 registers to address. If you want to access more than 4GB of memory in this mode just use some API similar to Windows AWE,或者使用多个进程(就像 Adobe Premiere CS4 所做的那样)
假设您是 运行 32 位 RISC 系统。您将使用什么指令来访问 64 位内存地址?
在CISC指令集中,您可以使用多字指令简单地传递额外的字。例如:
1a) JMP
1b) loAddress
1c) hiAddress
鉴于 RISC 指令每条只有一个字,您将如何访问多字地址?
假设 ALU 是 32 位的并且有一个进位标志。
此外,在 CISC 系统(例如 8080)中,loAddress 和 hiAddress 字都将存储在程序存储器中。 IE。 JMP
指令知道查看程序存储器中的下一项以检索 loAddress
,然后查看下一项以检索 hiAddress
。 RISC 会发生什么?
即使在 CISC 上,你描述的情况也很不寻常。 不是因为是CISC,而是因为使用了比寄存器更宽的地址。这通常只在 8 位 CPU 中出现。 (尽管 x86 分段也符合条件,间接远跳采用指向 m16:32
段/偏移对的指针。或者在 16 位模式下,m16:16
。作为小端,偏移在前。 ) 在 64 位模式之外,jmp ptr16:32
也是可编码的,绝对 segment:offset 作为指令流的一部分。)
通常当你想设计一个CPU更大的地址space时,你也会使寄存器更宽,这样你就可以有效地处理地址。当您想通过使用大部分 8 位寄存器/ALU 来节省晶体管时,它只是在非常低端,但不能将您的地址 space 限制为 256 字节,您可以在其中找到这种设计。
即使地址大小与字长相符,这里也确实存在问题。 构造任意32位(或64位)常量是不同ISA以不同方式解决的问题。 ARM 通常使用来自附近 "literal pool" 的 PC 相关负载,而其他人通常使用 lui
或等效设置高 16 位并将其余部分置零,然后使用 16 位 ori
即时。 (ARM 有一些巧妙的技巧,通过使用 shifted/rotated 立即数来编码仅设置了几个位的立即数。)
一般在RISC上,如果你需要跳远,你可能需要使用多条指令在一个寄存器中构造地址。然后使用跳转到寄存器说明。
MIPS 分支指令很有趣:它有相对分支,在相当大的范围内向程序计数器添加一个带符号的位移,以及用新地址替换PC 低28 位的绝对跳转指令。 (由26位立即数左移构造,因为MIPS要求指令对齐所以低2位不需要存储。)How to Calculate Jump Target Address and Branch Target Address?。但是当目标无法从当前位置到达时,您需要 jr
和寄存器中的地址。
x86-64也缺少64位相对跳转指令。如果您需要跳转超过 +-2GiB 的距离(而不是 far
,就像在新的 CS 段中一样),您需要间接跳转。正常的 jump/branch 指令仍然使用 rel8
或 rel32
位移,以保持机器代码紧凑。唯一可以采用 64 位立即数的指令是 mov
-to-register。正常的代码模型假定同一库或 executable 中的所有代码彼此之间的距离在 2GiB 以内,因此链接器将能够填充 32 位位移。
8 位 RISC
据我所知,程序计数器比寄存器宽的唯一 RISC ISA 是 AVR,它是一种带有 8 位寄存器的微控制器。 它可以把成对的寄存器当作16位地址,它的PC是16位的。它 IJMP
(indirect jump) instruction 设置 PC = Z(其中 Z
是一对 8 位寄存器)。在具有 22 位程序计数器而不是 16 位程序计数器的 AVR 上,它将 PC(21:16)
.
EIJMP(扩展间接跳转)从I/Ospace取EIND寄存器为PC的高位,低位仍然来自Z
。
AVR指令几乎都是2字节长,但有些版本a 4-byte jmp
instruction需要一个0..4M的绝对地址作为跳转目标。
32位寄存器的主流RISC机器也有32位程序计数器和虚拟地址-spaces。 (拥有超过 4GiB 的物理内存是可能的,但您无法在一个进程中同时映射所有内存)。
他们中的大多数在他们的设计中都是以字为导向的,所以他们所需要的只是 jr reg
(MIPS) 或任何等效于分支到任何可能地址的东西,因为它适合一个寄存器。这是 RISC 字面上所代表的降低的 复杂性 的一部分。
在像 MIPS、SPARC 或 PowerPC 这样的普通 RISC 上,64 位地址仅在 64 位 ISA 扩展中可用,其中有 64 位整数寄存器.因此,您将使用像 MIPS ld , 0()
这样的指令来使用 </code> 作为 64 位基地址来执行 64 位(双字)加载。看到这个 <a href="https://www.cs.cmu.edu/afs/cs/academic/class/15740-f97/public/doc/mips-isa.pdf" rel="nofollow noreferrer">MIPS-IV ISA manual</a>。 (MIPS-III 添加了 64 位扩展,带有 <code>ld
和 daddu
等指令。显然 MIPS-I 留下了很多未使用的操作码编码 space,因此有足够的空间新的操作码来完成完整的 64 位 ALU 操作。)
一些 32 位 CPU 添加了扩展以支持大 物理 地址而不增加虚拟地址 space。例如,x86 的 PAE 定义了一种新的 page-table 格式,具有 36 位物理地址。但即使使用分段,单个进程也不能同时处理超过 4GiB 的虚拟内存。 (x86 段基址+偏移发生在之前 virt->phys 转换,创建一个 32 位线性地址。因此它对于线程本地存储仍然有用,例如 [fs:0]
一个不同的线性地址,具体取决于该线程的 fs
段基数。)
32 位 RISC ISA 上的扩展寻址
保罗克莱顿评论:
PA-RISC had "space registers" which provided extended addressing. 32-bit PowerPC had segment registers which were selected based on the most significant 4 bits of the effective address from a 16-entry table (providing a 52-bit virtual address space). For PA-RISC "SRs 5 through 7 can be modified only by code executing at the most privileged level." For PowerPC, any segment register change required privilege.
很明显,一些 RISC ISA 在进入完全 64 位之前确实扩展了它们的寻址。但我不知道细节,也不打算花时间研究这个。欢迎其他答案!
Given that RISC instructions are only one word each
这不是真的。大多数现代 RISC 架构都有可变宽度指令集,或者至少有一个特殊的可变宽度模式(RISC-V 中的 ForwardCom, SuperH, MIPS16e, thumb2 in ARM, C instruction set...),尽管它们主要用于 compacting 目的是增加 代码密度 。这仍然意味着您实际上可以让您的 RISC 架构使用多字指令
即便如此,它也无济于事,除非您可以使用比 64 位更宽的指令(太大而不实用)。只有两个 32 位字,您仍然会被限制在基地址周围的一些 偏移量 而不是完整的 64 位地址 space。但这应该不是问题,因为几乎没有一个程序可以利用庞大的 64 位地址 space。这就是为什么在 x86-64 中没有指令接收 64 位立即地址,因为 32 位偏移量已经足够了。所以你可以这样做:在大多数情况下使用一个小的立即偏移量,并在你需要完整的 64 位地址时使用一个 2 寄存器对
正如 Peter 所说,比字长宽的地址主要只出现在 8 位微控制器中。除了AVR,它也被用在8位PIC where the program counter is 13 or 14-bit long. Instructions generally contain only the low bits of the address, the high bits will be taken from the PC or PCLATH register. If you don't want to use an offset like above then replacing the low bits directly like this is an alternative way. Obviously you still need a separate register for the high bits. But if you don't care about orthogonality然后只用一个专用的大寄存器来寻址,就像在8051、6502或其他更老的CISC架构
还有很多其他方法可以支持比我在此处描述的寄存器大小更宽的地址范围 How can 8-bit processor support more than 256 bytes of RAM?. One of them is to limit virtual address to the register size only (like ARM LPAE or x86 PAE), while allowing physical address to be 64-bit wide. The pages will be mapped in the TLB and you don't need to use 2 registers to address. If you want to access more than 4GB of memory in this mode just use some API similar to Windows AWE,或者使用多个进程(就像 Adobe Premiere CS4 所做的那样)