【问题标题】:RISC-V: Immediate Encoding VariantsRISC-V:立即编码变体
【发布时间】:2017-01-18 12:29:37
【问题描述】:

在 RISC-V 指令集手册,用户级 ISA 中,我无法理解第 11 页第 2.3 节立即编码变体。

指令格式有 R、I、S 和 U 四种类型,然后是 S 和 U 类型的变体,它们是 SB 和 UJ,我想是指分支和跳转,如图 2.3 所示。然后是RISC-V指令产生的立即数类型,如图2.4所示。

所以我的问题是,为什么需要 SB 和 UJ?为什么要以这种方式洗牌立即位?说“RISC-V指令产生的立即数”是什么意思?以及它们是如何以这种方式生产的?

【问题讨论】:

    标签: cpu-architecture riscv machine-code instruction-set immediate-operand


    【解决方案1】:

    选择RISC-V指令编码简化解码器

    2.2 基本指令格式

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

    2.3 立即编码变体

    S 和 B 格式之间的唯一区别是 12 位立即数字段用于在 B 格式中以 2 的倍数对分支偏移进行编码。不是像传统那样在硬件中将指令编码立即数中的所有位左移一位,中间位 (imm[10:1]) 和符号位保持在固定位置,而 S 格式的最低位 (inst[ 7]) 以B格式编码一个高位。

    同样,U 和 J 格式之间的唯一区别是 20 位立即数左移 12 位形成 U 立即数,并左移 1 位形成 J 立即数。选择 U 和 J 格式立即数中指令位的位置,以最大限度地与其他格式和彼此重叠。

    https://riscv.org/technical/specifications/

    在 RISC-V 规范中也解释了 SB/UL 格式中立即数改组的原因

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

    【讨论】:

      【解决方案2】:

      为了加快解码速度,基本 RISC-V ISA 将最重要的字段放在每条指令的相同位置。如您在指令格式表中所见,

      • 主要操作码始终位于 0-6 位。
      • 目标寄存器(如果存在)始终位于第 7-11 位。
      • 第一个源寄存器(如果存在)始终位于第 15-19 位。
      • 第二个源寄存器(如果存在)始终位于第 20-24 位。

      其他位用于指令的次要操作码或其他数据(funct3 在位 12-14 和 funct7 在位 25-31)和立即数。立即数可以使用多少位取决于指令中存在多少寄存器号:

      • 具有一个目标和两个源寄存器(R 类型)的指令没有立即数,例如添加两个寄存器 (ADD);
      • 具有一个目标和一个源寄存器(I 类型)的指令有 12 位用于立即数,例如添加一个带有立即数的寄存器 (ADDI);
      • 具有两个源寄存器且没有目标寄存器(S 类型)的指令,例如存储指令,也有 12 位用于立即数,但它们必须位于不同的位置,因为寄存器编号也在不同的位置地点;
      • 最后,只有目标寄存器且没有次要操作码(U 型)的指令,例如LUI,可以使用 20 位作为立即数(主要操作码和目标寄存器号共需要 12 位)。

      现在从另一个角度考虑将使用这些立即值的指令。最简单的用户,I-immediate 和 S-immediate,只需要一个符号扩展的 12 位值。 U 立即数指令需要 32 位值的高 20 位立即数。最后,分支/跳转指令需要在值的低位进行符号扩展立即数,但最低位始终为零,因为 RISC-V 指令始终与偶数地址对齐。

      但是为什么直接位被打乱了?这次想想解码立即场的物理电路。由于它是硬件实现,因此这些位将被并行解码;输出立即数中的每个位都有一个multiplexer 来选择它来自哪个输入位。多路复用器越大,成本越高,速度越慢。

      因此,指令编码中立即位的“洗牌”是为了使每个输出立即位具有尽可能少的输入指令位选项。例如,立即数位 1 只能来自指令位 8(S-立即数或 B-立即数)、21(I-立即数或 J-立即数)或常量 0(没有立即数的 U-立即数或 R-类型指令) )。立即数位 0 可以来自指令位 7(S-立即数)、20(I-立即数)或常数零。立即位 5 只能来自指令位 25 或常数零。以此类推。

      指令位 31 是一种特殊情况:对于 RV-64,立即数的位 32-63 始终是指令位 31 的副本。这种高扇出会增加延迟,如果还需要多路复用器,所以它只有一个选项(除了常数零,稍后可以通过忽略整个立即数在管道中处理)。

      值得注意的是,只需要主要操作码(位 0-6)就知道如何解码立即数,因此立即数解码可以与解码其余指令并行进行。


      所以,回答问题:

      • SB 类型将分支范围扩大了一倍,因为指令始终与偶数地址对齐;
      • UJ-type与U-type的整体指令格式相同,但立即数在低位而不是高位;
      • 通过减少每个输出立即位的选择数量,对立即位进行混洗以降低解码立即值的成本;
      • “RISC-V 指令产生的立即数”表显示了可以从 RISC-V 指令解码的不同类型的立即数,以及指令中每个位的来源;
      • 对于每个输出立即位,它们是通过使用主要操作码(位 0-6)选择输入指令位来生成的。

      【讨论】:

      • “最后,分支/跳转指令需要在值的低位进行符号扩展立即数”,这是为什么呢?
      • “SB-type 使分支范围加倍,因为指令总是与偶数地址对齐”,它是如何使范围加倍的?
      • @akurd 带有一个带符号的 12 位数字,范围从 -2048 到 +2047。在 B 立即数(SB 类型)中,您有一个带符号的 13 位数字,最低位设置为零,范围从 -4096 到 +4094。至于为什么分支/跳转指令需要低位立即数,如果不需要,它们就无法转到它们附近的指令。
      【解决方案3】:

      编码是为了尽量让实际的硬件实现尽可能简单,而不是让读者一眼就能理解。

      实际上,编译器会生成输出,因此用户是否难以理解也没关系。

      在可能的情况下,SB 类型尝试将相同的位用于与类型 S 相同的立即位位置,从而最大限度地降低硬件设计的复杂性。所以 imm[4:1] 和 imm[10:5] 都在同一个地方。立即数的最高位始终位于位置 31,因此您可以使用该位来决定是否需要符号扩展。同样,这使硬件更容易,因为对于多种类型的指令,最高位用于决定符号扩展。

      【讨论】:

        猜你喜欢
        • 2017-03-13
        • 1970-01-01
        • 2021-06-17
        • 2023-04-10
        • 2018-12-15
        • 2022-12-17
        • 1970-01-01
        • 1970-01-01
        • 2021-10-05
        相关资源
        最近更新 更多