了解通过汇编指令对寄存器的地址分配

Understanding address assignment to registers via assembly instructions

如果我有一个 CPU/system 具有以下特征...

假设我的汇编指令遵循以下格式...

OPCode (6 bits) + Register (3 bits) + Register (3 bits) + Unused (4 bits)


** Example Instructions (below) **

Assembly: LOAD R1,  R7 (Loads value of address stored in R1 into destination register R7)
Machine: 110000 001 111 0000

Assembly: STORE R1,  R7 (Stores value in R1 into destination address stored in register R7)
Machine: 110001 001 111 0000

这些类型的指令对我来说很有意义,因为所有必需的位都很好地适合 16 位格式,因此适合指令寄存器(它包含 16 位),但是 我很困惑如何由于此指令长度限制,将所需地址放入寄存器开始?

如果这个系统上的地址是 16 位,在我看来我需要超过 16 位来表示将地址值分配给任何给定寄存器的指令before 我什至可以使用类似 LOAD 或 STORE 指令的东西...

OPCode (6bits) + destinationRegister (3 bits) + addressLiteral (16 bits) ???

但是,像这样的东西不适合我的 16 位指令寄存器。我在这里不明白什么?非常感谢任何帮助,谢谢!

我假设这是一个虚构的指令集架构,因为根据这个问题它看起来并不真实。

地址通常使用“立即”式指令从程序中加载,因此需要“op + reg1 + reg2 + padding”形式之外的指令

例如,在 MIPS 中,您可以使用 Load Upper Immediate 和 Load Immediate 通过两条 32 位指令将 32 位值加载到寄存器中。

  • Fixed-length 指令集:

    • LC-3 是一个 8 寄存器机器,具有固定大小的 16 位指令:它允许在某些 16 位指令中有 9 位偏移。 9 位偏移量用作立即数以形成 pc-relative 地址,从该地址加载完整的 16 位值作为数据。因此,诀窍是将完整的 16 位值定位为数据,位于使用它的代码附近的某个位置(例如,在 +/-256 个字内)。

    • MIPS 是一个 32 位指令集,在一个 32 位地址 space。使用两条指令,每条指令都有 16 位立即数,可以组成一个完整的 32 位地址。

    • Hack / nand2tetris 有 16 位指令,并且有一种特殊的加载形式 constants/address,指令形式有一位表示它是否是一个 A-type,这然后允许 15 位常量或地址。

    • MARIE,累加器机器,有16位定长指令,但只有4k内存,所以允许在16位指令中嵌入12位绝对地址。

    • PDP-8,累加器机器,12位地址有12位指令space。指令可以直接引用附近的内存(在与代码相同的128字页内),或零页(lowmem,也是128字)上的任何东西。

  • 可变长度指令集通常允许在指令后面紧跟一个全长,例如 x86、68000 等。处理器将自动在指令的全长中包含此类立即数的大小。

为了获得更多元数据,指令集具有格式,并且指令集中的格式会有所不同以适应不同类型的操作,例如,3 reg,与 2 reg 加 large-ish 立即数。这一切都与指令编码有关,这里的部分想法是为软件提供所需的功能,同时保持硬件实现的可管理性。


在设计 ISA 时,需要考虑很多事情。一件事是位置无关代码,它允许代码在地址space的任何地方加载,甚至可以在不同地址space的不同位置共享;理想情况下,代码将 运行 没有任何 运行 时间重定位,因此代码可以完全不可变。对于可动态加载的共享库 (DLL) 也有一些注意事项。

因此,pc-relative寻址模式非常有用,而且,绝对地址应该限制在数据中,不允许出现在代码中,这与 LC-3、MARIE、PDP-8 不同。

这是正确的,在 RISC-like 机器中 fixed-width 指令的字长与地址和寄存器相同,需要多条指令才能在寄存器中生成任意常量。

你可以做到

  • a PC-relative 在具有它的 ISA 上加载(例如 ARM,当您编写 ldr r0, =0x1234567 之类的内容时,汇编程序可以自动生成附近的“文字池”)
  • add-with-PC
  • PC-relative 像 AArch64 一样缩放偏移 adrp(按页)/add(用页内偏移修复它,或者使用低 12 位作为页内偏移ldr 指令)
  • 或经典的 lui/addi 用于任意 non-address 常量,两个立即数的宽度加起来等于字长(如 MIPS 16+16,或 RISC-V 来自 lui 的高 20 + 来自普通 I-type 指令的低 12)

您通常需要一个指令格式的操作码,该指令格式采用 1 个寄存器,并将其余部分用作立即位,从而为您提供最大值 space。

在你的例子中,6 个操作码位 + 1 个寄存器将占用 9 位,只剩下 7 个立即数位。

所以这不是很多,甚至不足以在 2 条指令中生成一个 16 位常量,即使使用第二个操作码将 ADD 或 OR 放入一个寄存器的底部。除非你想牺牲多个操作码(例如,使用操作码的低位作为额外的立即位),否则不是很好。

因此您可能希望使用 PC-relative 加载作为生成大常量的主要方式。 (所以一个操作码,1 个寄存器,留下 7 位偏移量,可能按比例缩放 2,所以它是 word-aligned)。

或者将整个下一个指令字作为立即数读取的特殊指令。解码可以将此指令视为跳过数据以及加载该数据。 (在一个简单的标量流水线设计中,可能将它从获取阶段拉出来并在管道的其余部分发送一个 NOP。它需要一堆特殊情况,并且如果你的流水线的危险检测仍然在看它,可能会有性能缺陷在用 NOP 替换之前。并在解码阶段的路径指令位中放置一个额外的多路复用器或与门。)我不知道是否有任何真正的 ISA 实际上这样做;一些带有 16 位压缩指令的 32 位 ISA(如 ARM Thumb 模式或 RV32c)有 variable-width 2 或 4 字节的指令,由第一个 2 字节块中的一些 easy-to-decode 位表示.