【问题标题】:RISC access address greater than largest integer registerRISC访问地址大于最大整数寄存器
【发布时间】:2018-06-07 18:59:17
【问题描述】:

假设您正在运行 32 位 RISC 系统。您会使用什么指令来访问 64 位内存地址?

在 CISC 指令集中,您可以使用多字指令简单地传递额外的字。例如:

1a) JMP
1b) loAddress
1c) hiAddress

鉴于每条 RISC 指令只有一个字,您将如何访问多字地址?

假设 ALU 是 32 位的并且有一个进位标志。

此外,在 CISC 系统(例如 8080)中,loAddress 和 hiAddress 字都将存储在程序存储器中。 IE。 JMP 指令知道查看程序存储器中的下一项以检索loAddress,然后查看其后的项以检索hiAddress。 RISC 会发生什么?

【问题讨论】:

  • 如果您的寄存器只有 32 位,那么您可能需要使用寄存器对的专门指令。或者,您可以以特定于架构的方式选择内存库,例如写入控制寄存器。再说一次,您的示例使用了 JMP,这意味着至少您的 PC 是 64 位的,所以也许您确实有 64 位寄存器,您可以在其中简单地使用间接跳转。
  • 另外你的标题对我来说没有多大意义,你的地址显然不大于地址空间。
  • 关于JMP,我在想8位8080中的JMP命令。它的作用是将hiAddress(一个字节)加载到一个寄存器中,loAddress(一个字节)到另一个。
  • 我更新了标题。另外,我问的是一般意义上的问题,因为我比 RISC 更熟悉 CISC 指令。
  • @downvoter,对否决票的解释会很好。我非常愿意接受改进问题所需的任何建议

标签: assembly cpu-architecture memory-address addressing-mode risc


【解决方案1】:

即使在 CISC 上,您所描述的也很不寻常。 不是因为是 CISC,而是因为使用的地址比寄存器宽。这通常只存在于 8 位 CPU 中。 (虽然 x86 分段也符合条件,间接远跳转采用指向 m16:32 段/偏移对的指针。或者在 16 位模式下,m16:16。作为 little-endian,偏移是第一位的。) 64-位模式,jmp ptr16:32 也是可编码的,绝对段:偏移量作为指令流的一部分。)

通常,当您想要设计具有更大地址空间的 CPU 时,您也会使寄存器更宽,以便您可以有效地处理地址。只有当您想通过主要使用 8 位寄存器/ALU 来节省晶体管,但又不能将地址空间限制为 256 字节时,它才处于非常低端,您会发现这种设计。


即使地址大小与字长匹配,这里也存在一个真正的问题。 构造任意 32 位(或 64 位)常量是不同 ISA 解决方法不同的问题。 ARM 经常使用来自附近“文字池”的 PC 相对加载,而其他人经常使用 lui 或等效项来设置高 16 位并将其余部分归零,然后将 ori 与 16 位立即数一起使用。 (ARM 有一些巧妙的技巧可以通过使用移位/旋转的立即数对只设置几位的立即数进行编码。)

一般而言,在 RISC 上,如果您需要跳转很远,您可能需要使用多条指令在寄存器中构造地址。然后使用跳转到寄存器指令。

MIPS 分支指令很有趣:它具有向程序计数器添加一个相当大范围的有符号位移的相对分支,以及将 PC 的低 28 位替换为新地址的绝对跳转指令。 (由 26 位立即左移构造,因为 MIPS 需要对齐指令,因此不需要存储低 2 位。)How to Calculate Jump Target Address and Branch Target Address?。但是当目标无法从当前位置到达时,您需要jr 和寄存器中的地址。

x86-64 也缺少 64 位相对跳转指令。如果您需要跳得比 +-2GiB 远(不是 far 就像在新的 CS 段中那样),您需要间接跳转。正常的跳转/分支指令仍然使用rel8rel32 位移,保持机器代码紧凑。唯一可以采用 64 位立即数的指令是 mov-to-register。普通代码模型假设同一个库或可执行文件中的所有代码彼此之间的距离在 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/O 空间为 PC 的高位获取 EIND 寄存器,而低位仍然来自Z

AVR 指令几乎都是 2 个字节长,但有些版本有 a 4-byte jmp instruction,它使用 0..4M 的绝对地址作为跳转目标。


具有 32 位寄存器的主流 RISC 机器也具有 32 位程序计数器和虚拟地址空间。 (拥有超过 4GiB 的物理内存是可能的,但您不能在一个进程中同时映射所有内存)。

他们中的大多数在他们的设计中都是面向字的,所以他们只需要jr reg (MIPS) 或任何相当于分支到任何可能地址的东西,因为它适合一个寄存器。这是 RISC 字面意思所代表的降低复杂性的一部分。


在 MIPS、SPARC 或 PowerPC 等普通 RISC 上,64 位地址仅在 64 位 ISA 扩展中可用,其中您有 64 位整数寄存器。因此,您可以使用诸如 MIPS ld $2, 0($3) 之类的指令来使用 $3 作为 64 位基地址来执行 64 位(双字)加载。请参阅此MIPS-IV ISA manual。 (MIPS-III 添加了 64 位扩展,带有类似 lddaddu 的指令。显然 MIPS-I 留下了很多未使用的操作码编码空间,因此有足够的空间让新操作码完成完整的 64 位ALU 运算。)

一些 32 位 CPU 添加了扩展以支持大型 物理 地址,而不会增加虚拟地址空间。例如,x86 的 PAE 定义了一种具有 36 位物理地址的新页表格式。但即使有分段,单个进程一次也不能处理超过 4GiB 的虚拟内存。 (x86 段基址+偏移发生在 virt->phys 转换之前,创建一个 32 位线性地址。因此它对于线程本地存储仍然有用,例如 [fs:0] 是不同的线性地址,具体取决于在该线程的fs 段基础上。)


32 位 RISC ISA 上的扩展寻址

Paul Clayton cmets:

PA-RISC 具有提供扩展寻址的“空间寄存器”。 32 位 PowerPC 具有根据 16 项表中有效地址的最高有效 4 位选择的段寄存器(提供 52 位虚拟地址空间)。对于 PA-RISC,“SR 5 到 7 只能通过在最高特权级别执行的代码进行修改。”对于 PowerPC,任何段寄存器更改都需要特权。

显然,一些 RISC ISA 在完全 64 位之前确实扩展了它们的寻址。但我不知道细节,也不打算花时间研究这个。欢迎其他答案!

【讨论】:

  • 感谢您的回答。我不熟悉 AVR 的 ISA。 Z寄存器如何设置?例如说保持值 65535 (两个字节上的 0xFFFF )。是否有单独的指令来设置对中的每个成员,或者有一个特殊的指令来同时设置两者?
  • 谷歌搜索得到LD ZH, hiByteLD ZL, loByte
  • @JetBlue:AVR 的文档页面有一个目录。我环顾了一下,LDI (load-immediate) 显示了设置 Z 的示例:clr r31 (zhigh = 0) / ldi r30, $F0 (zlow = 0xF0) / lpm (从程序存储器加载常量,使用 Z 作为指针)。所以 Z 是 r31:r30。一些指令可以对整个单词进行操作,例如adiw ZH:ZL, 63。所以这很像 8080 如何将一对 8 位 reg 用于一些 16 位操作,并用作指针。
  • @JetBlue:在考虑了您真正要问的内容后,我添加了更多内容。即使是完整的 32 位地址,在 32 位指令字中也是一个问题!
  • PA-RISC 具有提供扩展寻址的“空间寄存器”。 32 位 PowerPC 具有根据 16 项表中有效地址的最高有效 4 位选择的段寄存器(提供 52 位虚拟地址空间)。对于 PA-RISC,“SR 5 到 7 只能通过在最高特权级别执行的代码进行修改。”对于 PowerPC,任何段寄存器更改都需要特权。
【解决方案2】:

鉴于 RISC 指令每个只有一个字

这不是真的。大多数现代 RISC 架构都有一个可变宽度指令集,或者至少有一个特殊的可变宽度模式(ForwardComSuperHMIPS16ethumb2 在 ARM 中,C instruction set 在 RISC-V... ) 尽管它们主要用于压缩目的以增加代码密度。这仍然意味着您实际上可以使您的 RISC 架构使用多字指令

即使那样,它也无济于事,除非您可以使用超过 64 位的指令(这些指令太大而无法实用)。只有两个 32 位字,您仍将受限于基地址周围的一些 偏移,而不是完整的 64 位地址空间。但这应该不是问题,因为几乎没有单个程序可以利用巨大的 64 位地址空间。这就是为什么在 x86-64 中没有指令接收 64 位立即地址的原因,因为 32 位偏移已经足够了。所以你也可以这样做:在大多数情况下使用一个小的立即偏移量,当你需要完整的 64 位地址时使用一个 2 寄存器对

正如 Peter 所说,比字长更宽的地址主要只出现在 8 位微控制器中。除了 AVR,它还用于 8 位 PIC,其中程序计数器为 13 位或 14 位长。指令一般只包含地址的低位,高位将取自 PC 或 PCLATH 寄存器。如果您不想使用像上面这样的偏移量,那么像这样直接替换低位是另一种方法。显然,您仍然需要一个单独的寄存器来存放高位。但是,如果您不关心 orthogonality,那么只需使用专用的大寄存器进行寻址,例如在 8051、6502 或其他较旧的 CISC 架构中

还有许多其他方法可以支持比寄存器大小更宽的地址范围,正如我在此处 How can 8-bit processor support more than 256 bytes of RAM? 所描述的那样。其中之一是将虚拟地址限制为仅寄存器大小(如 ARM LPAE 或 x86 PAE),同时允许物理地址为 64 位宽。这些页面将在 TLB 中映射,您无需使用 2 个寄存器来寻址。如果您想在此模式下访问超过 4GB 的内存,只需使用类似于 Windows AWE 的一些 API,或使用多个进程(如 Adob​​e Premiere CS4 所做的那样)

【讨论】:

  • 我不认为 ForwardCom 声称自己是 RISC。这个想法是一个 ISA,它可以轻松解码和流水线,同时仍然保持 CISC 的代码密度优势(以字节为单位和每条指令的工作量)。亮点的第一个要点是它既不是 RISC 也不是 CISC。因此,它绝对不属于您在 RISC ISA 列表中的第一个条目!但无论如何,所有这些紧凑的可变长度编码之所以存在,主要是因为 RISC 市场转向嵌入式/微控制器,其中代码大小很重要,而短而窄的管道使可变长度解码变得便宜。
  • 因此,RISC 的可变长度编码基本上是一种非 RISC 功能,现实世界中的原始纯 RISC CPU 添加了该功能,因为 RISC 纯度不直接销售芯片。 (ARM32 是其他非 RISC 功能的一个很好的例子,例如带有寄存器位图的微编码推送/弹出。)请注意,AArch64(AFAIK)没有可变长度模式;你只能在 32 位模式下运行 Thumb 代码(在完全支持 32 位模式的芯片上;一些 Apple 放弃了 IIRC。)所以对于相对较高的性能,固定长度仍然是选择~经过多年的拇指经验,2010 年。
猜你喜欢
  • 2011-05-27
  • 2020-08-27
  • 2011-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-22
  • 1970-01-01
  • 2010-11-18
相关资源
最近更新 更多