我试图了解现代CPU的工作原理。我专注于RISC-V。有几种类型的分支:
BEQ
BNE
BLT
BGE
BLTU
BGEU
我使用金星模拟器来测试这一点,我也在尝试模拟它,到目前为止它工作得很好,但我不明白,分支是如何计算的。 根据我所读到的内容,ALU 单元只有一个信号输出 -ZERO
(除了其数学输出),只要输出为零,它就会激活。但是,我如何确定是否应该仅基于ZERO
输出来获取分支?它们是如何计算的?
示例代码:
addi t0, zero, 9
addi t1, zero, 10
blt t0, t1, end
end:
分支示例:
BEQ
- 减去 2 个数字,如果ZERO
处于活动状态,则分支
BNE
- 减去 2 个数字,如果ZERO
不活动,则分支
BLT
- 在这里我有点困惑; 我应该减去然后看符号位,还是什么?
BGE
/BGEU
- 以及如何区分这些?我应该使用哪些数学指令?
是的,ZERO 输出为您提供相等/不相等。 您也可以使用 XOR 代替 SUB 进行相等比较,如果它运行得更快(在部分时钟周期中更早准备好)和/或使用更少的功率(更少的晶体管开关)。
有趣的事实:MIPS只有eq/ne和有符号比较零分支条件,所有这些都可以在没有进位传播或任何其他级联位的情况下快速测试。 这很重要,因为它在exec的前半周期检查分支条件,及时转发以获取,将分支延迟降低到1个周期,分支延迟槽隐藏在经典MIPS管道上。 对于其他条件,例如两个寄存器之间的blt
,您需要slt
并在此上进行分支。 RISC-V具有用于两个寄存器之间blt
的真正硬件指令,而MIPS的bltz
仅针对零。
为什么使用只有零输出的 ALU? 这使得它无法用于精确相等以外的比较。
您需要其他输出来从减去结果中确定 GT/GE/LE/LT(及其无符号等效物)。
对于无符号条件,您只需要零和一个携带/借用(无符号溢出)标志。
结果的符号位本身不足以满足有符号条件,因为签名溢出是可能的:(-1) - (-2)
=+1
:-1 > -2
(符号位清除)但(8位环绕)0x80 - 0x7F = +1
(符号位也清除)但-128 < 127
。 数字本身的符号位仅在与零进行比较时才有用。
如果扩大结果(通过符号扩展输入并再执行一位添加/sub),则无法进行签名溢出,因此第 33 位直接成为无符号小于结果。
您还可以从signed_overflow XOR signbit
中获得符号小于结果,而不是实际加宽 + 添加。 如果RISC-V有任何架构方式让软件检查有符号整数溢出,您可能还需要有符号溢出的ALU输出。
可以通过查看 MSB(符号位)的进移和执行来计算有符号溢出。 如果这些不同,则表示您有溢出。 即 SF = 这两个携带的 XOR。 另请参阅 http://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt,详细了解无符号进位与带符号溢出的 2 位和 4 位示例。
在具有 FLAGS 寄存器(例如 x86 和 ARM)的 CPU 中,这些 ALU 输出实际上进入具有命名位的特殊寄存器。 您可以查看 x86 手册以获取条件跳转指令,以了解条件名称(如l
(无符号小于)或b
(下面无符号)如何映射到这些标志:
签署条件:
jl
(又名RISC-Vblt
):如果少则跳(SF≠ OF
)。 这是输出符号位不等于溢出标志,从减法/cmpjle
: 如果小于或等于,则跳跃 (ZF=1 or SF≠ OF
)。jge
(又名RISC-Vbge
):如果大于或等于(SF=OF
)则跳跃。jg
(又名RISC-Vbgt
):如果更大(ZF=0 and SF=OF
)则跳短。
如果您决定让您的 ALU 只生成"符号小于"输出而不是单独的 SF 和 OF 输出,那很好。SF==OF
只是!(SF != OF)
.
(x86 也有一些相同操作码的助记同义词,如jl
=jnge
。 "只有"16 个 FLAGS 谓词,包括单独OF=0
(测试溢出,而不是比较结果)和奇偶校验标志。 您只关心实际的有符号/无符号比较条件。
如果你仔细考虑一些示例案例,比如测试那个INT_MAX > INT_MIN
你就会明白为什么这些条件是有意义的,就像我上面展示的 8 位数字的例子一样。
无符号:
jb
(又名RISC-Vbltu
):如果低于(CF=1
)则跳跃。这只是测试携带标志。jae
(又名RISC-Vbgeu
):如果高于或等于(CF=0
),则跳短。ja
(又名RISC-Vbgtu
) : 如果高于 (CF=0 and ZF=0
),则跳短。
(请注意,x86 减去设置 CF = 借用输出,因此1 - 2
设置 CF=1。 其他一些 ISA(例如 ARM)反转了减法的进位标志。 在实现RISC-V时,这将全部是CPU内部的,在架构上对软件不可见。
我不知道RISC-V是否真的具有所有这些不同的分支条件,但x86确实如此。
实现有符号或无符号比较器的方法可能比做减法更简单。
但是,如果您已经有一个加/减 ALU 并希望捎带它,那么您可能只希望它生成进位和无符号小于输出以及零。
这样,您就不需要单独的符号标志输出,也不需要获取整数结果的 MSB。 它只是ALU内部的一个额外的XOR门,可以将这两件事结合起来。
您不必做减法来比较两个(有符号或无符号)数字。 例如,您可以使用级联 7485 芯片。 使用此芯片,您可以执行所有 Branch 计算,而无需进行任何减法。