为什么 RISC-V SB 和 UJ 指令类型以这种方式编码?

jwk*_*koo 11 assembly encoding instruction-set machine-code riscv

我正在读一本书“计算机组织和设计 RISC-V 版”,我遇到了 SB 和 UJ 指令类型的编码。

我上面提到的那些类型具有奇怪的编码立即字段。

SB 类型将立即数字段分成两部分。这是有道理的,因为所有指令编码都必须相似。但我不明白为什么下面的直接字段以这种方式编码。

imm[12, 10:5], imm[4:1, 11]
Run Code Online (Sandbox Code Playgroud)

代替

imm[11:5], imm[4:0]
Run Code Online (Sandbox Code Playgroud)

UJ 类型也有这个奇怪的编码立即字段

imm[20,10:1,11,19:12]
Run Code Online (Sandbox Code Playgroud)

代替

imm[19:0]
Run Code Online (Sandbox Code Playgroud)

谁能解释一下?

Eri*_*idt 8

所选择的编码与其他编码非常吻合,以牺牲必须生成指令的软件、必须解码指令的软件以及学习或使用 RISC V 的程序员为代价来简化硬件;)。

S 格式将立即数分解为imm[11:5]imm[4:0]。这个立即数被分解的原因是为了保持其他字段,即寄存器字段rs2rs1,与 R 类型指令中的两个源寄存器字段处于相同的位置。(与 MIPS 相比,它的功能类似但不完全,这消除了寄存器名称宽度(例如 5 位宽)多路复用器和一些额外的布线,以及控制信号。)

S 格式允许 12 位立即数。

而分支的 (S)B-Type 使用 13 位立即数,尽管 13 位立即数的最后一个(最低有效位)始终为零,因此不会存储!因此,它实际上需要像 S-Format 一样编码 12 位,但因为它们在实际使用中被移位(左移 1,例如 *2),与 S- 相比,所有位基本上都偏离 1 位位置立即格式化。(移位不难也不慢,但会消耗硅片空间。通常,通过简单地将输入位连接到偏移输出位位置,而不是使用我们在 ALU 中看到的专用移位器,即可完成这种恒定量的移位;然而,这仍然是直接的和数据路径大小的布线,所以大约有 12 到 32+ 条额外的电线。)

为了不必须转移(尽可能的)的立即数的部分存储,并以线很好地与在S-格式立即,在未存储的LSB位置(从S-格式)被用于存储 SB 格式立即数的第 11 位。这样,位10:1个排队正好与S-格式立竿见影。

但是为什么不直接将分支的第 12 位放在那里,这样可以使多一位与 S 格式保持对齐(即 11:1)?因为指令的立即数中编码的最高位用于将立即数符号扩展为 32 位(对于 RV32,或 64 位对于 RV64,128 位对于 RV128,很多线!)。因此,通过将符号位保持在与 S 格式 12 位立即数相同的位置,可以共享相同的符号扩展硬件(具有相同的上述优点和缺点;-)。因此,选择将第 11 位(SB 类型立即数的下一个最高有效位)存储在 0 位位置(相对于 S 格式)。

SB(已经给定 S)的成本只有两根左右(1 位)线和一个 1 位多路复用器和一个 1 位控制信号——与替代方案相比,这是最低的。

请参阅以下演示文稿,幻灯片 46,标题为“RISC-V 立即编码”,副标题为:“为什么如此令人困惑?!?!”

UJ-Type 做类似的事情,将符号位保持在与其他指令的符号位相同的位位置,同时将尽可能多的其他位与其他格式对齐。

请参阅同一演示文稿的幻灯片 60。


phu*_*clv 5

官方RISC-V 规范很好解释了指令集中的每个设计选择,以及为什么以这种特定方式完成某些操作。如有疑问,您只需看一下即可

因此,指令编码的基本原理在第 2.2 章 -基本指令格式中进行了描述。这一切都是为了使指令解码更简单、更快

  • 不同指令格式之间共享解码单元
  • 将立即位放在特定位置,以消除硬件移位器的需要并减少解码时的扇出

RISC-V ISA 在所有格式中将源 (rs1rs2) 和目标 ( rd) 寄存器保持在同一位置,以简化解码。除了 CSR 指令(第 9 章)中使用的 5 位立即数之外,立即数始终是符号扩展的,并且通常被打包到指令中最左边的可用位,并进行分配以降低硬件复杂性。特别是,所有立即数的符号位始终位于指令的位 31 中,以加速符号扩展电路。


解码寄存器说明符通常位于实现中的关键路径上,因此选择指令格式以将所有寄存器说明符保持在所有格式中的相同位置,但代价是必须跨格式移动立即位(与 RISC-IV 共享的属性)又名 SPUR [11])。

查看指令编码,您会发现每个rs1,rs2以及rd任何需要它们的指令格式都只需要一个解码器,并且位 31 始终是立即数中的符号位,无论其长度如何,以实现快速符号扩展

RISC-V指令编码

现在关注立即数,您还会看到它们以“奇怪”的顺序排列,但它们也允许在格式之间共享解码器。例如,在所有格式中,位 10:1 始终位于同一位置。与 U/J 中的位 19:12 和 S/B 中的位 4:1 相同。这两对实际上几乎相同,只是 J 和 B 中的立即数左移一位。通过这种方式交错位,大部分移位工作都留给了汇编器,从而进一步简化了硬件

2.3 立即编码变体

S 和 B 格式之间的唯一区别在于,B 格式中使用 12 位立即数字段来编码 2 的倍数的分支偏移量。中间位 (imm[10:1]) 和符号位保留在固定位置,而 S 格式中的最低位 (inst[ 7])以B格式对高位进行编码。

类似地,U 和 J 格式之间的唯一区别在于,20 位立即数左移 12 位以形成 U 立即数,左移 1 位以形成 J 立即数。U 和 J 格式立即数中指令位的位置被选择为最大化与其他格式以及彼此之间的重叠。


符号扩展是立即数上最关键的操作之一(特别是对于 XLEN>32),并且在 RISC-V 中,所有立即数的符号位始终保存在指令的第 31 位中,以允许符号扩展与指令译码。

尽管更复杂的实现可能具有用于分支和跳转计算的单独加法器,因此不会受益于在指令类型之间保持立即位的位置不变,但我们希望降低最简单实现的硬件成本。通过旋转 B 和 J 立即数的指令编码中的位,而不是使用动态硬件多路复用器将立即数乘以 2,我们将指令信号扇出和立即多路复用器成本减少了大约 2 倍。加扰的立即数编码将增加可忽略不计的时间静态或提前编译。对于指令的动态生成,存在一些小的额外开销,但最常见的短前向分支具有简单的立即编码。

如果你有兴趣可以在官方github页面找到更多讨论