我试图了解现代CPU的工作原理。我专注于RISC-V。分支的类型很少:BEQ
BNE
BLT
BGE
BLTU
BGEU
我使用venus模拟器对此进行了测试,并且我也尝试对其进行模拟,到目前为止,它仍然可以正常工作,但是我不明白分支的计算方式。
根据我的阅读,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和有符号比较-反对零条件,所有这些条件都可以快速进行测试,而无需进位传播或任何其他级联位。这很重要,因为它在与解码相同的阶段检查了分支条件,从而减少了分支等待时间。 (因此1个分支延迟插槽隐藏了延迟。)
为什么使用仅输出零的ALU?这使得除完全相等之外的其他比较无法使用。
您需要其他输出来从减法结果中确定GT / GE / LE / LT(及其无符号等效项)。
对于无符号条件,您所需要做的只是零和一个进位/借位(无符号溢出)标志。
结果本身的符号位不足以用于带符号的条件,因为可能发生带符号的溢出:(-1) - (-2)
= +1
:-1 > -2
(符号位清除)但(8位环绕)0x80 - 0x7F = +1
(符号位也清除),但-128 < 127
。仅当与零比较时,数字的符号位才有用。
如果扩大结果(通过对输入进行符号扩展并再做一点加法/加法运算),则将导致有符号溢出成为不可能,因此第33位是直接小于符号的结果。
您还可以从signed_overflow XOR signbit
获得小于符号的结果,而不是实际上加宽+添加。如果RISC-V具有任何用于软件检查签名整数溢出的体系结构方式,则您可能还希望ALU输出用于签名溢出。
可以通过查看进位和从MSB(符号位)中执行进位来计算符号溢出。如果这些不同,则您溢出。即SF =这两个进位的XOR。另请参见http://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt,以详细了解2位和4位示例的无符号进位与有符号溢出。
在具有FLAGS寄存器的CPU(例如x86和ARM)中,这些ALU输出实际上进入带有命名位的特殊寄存器中。您可以查看x86 manual for conditional-jump instructions来查看诸如l
(小于符号)或b
(以下未签名)之类的条件名称如何映射到这些标志:
签署条件:jl
(又名RISC-V blt
):如果小于(SF≠ OF
)则跳转。从减法/ cmp中得出的输出符号位不等于溢出标志jle
:小于或等于(ZF=1 or SF≠ OF
)时跳转。jge
(又名RISC-V bge
):如果大于或等于(SF=OF
),则跳转。jg
(又名RISC-V bgt
):如果较大,则跳短(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-V bltu
):如果低于(CF=1
),则跳转。那只是测试进位标志。jae
(又名RISC-V bgeu
):如果大于或等于(CF=0
),则跳短。ja
(又名RISC-V bgtu
):如果高于(CF=0 and ZF=0
),则跳短。
(请注意,x86减法设置CF =借位输出,因此1 - 2
设置CF = 1。其他一些ISA(例如ARM)会反转进位标志以进行减法。在实现RISC-V时,这将全部在CPU内部,而不是体系结构对软件可见)。
我不知道RISC-V是否实际上具有所有这些不同的分支条件,但是x86确实具有。
实现有符号或无符号比较器可能比进行减法更简单。
但是,如果您已经有一个加/减ALU并希望使用它,那么您可能只希望它生成“进位”和“小于符号”输出以及零。
这样,您就不需要单独的符号标志输出,也不需要获取整数结果的MSB。这只是ALU内部一个额外的XOR门,可以将这两件事结合在一起。
关于cpu - RISCV:如何计算分支指令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57452447/