实现了跳转与分支两条指令,跳转是绝对转移,分支是相对转移
如果转移指令在流水线的执行阶段进行转移条件判断,在发生转移时,会导致当前处于取指、译码阶段的指令无效,需要重新取指。也就是说,在流水线执行阶段进行转移判断,并且转移发生,那么会有2条无效指令,导致浪费了两个时钟周期。为了减少损失,规定转移指令后面的指令位置为“延迟槽”,延迟槽中的指令被称为“延迟指令”(“延迟槽指令”)。延迟指令总是被执行,与转移发生与否没有关系。
但是,即使引入延迟槽,在转移发生时仍然会导致已经进入取指阶段的指令无效,也就是说,仍浪费一个时钟周期,要解决这个问题,可以在译码阶段进行转移判断,这样就可以避免浪费时钟周期。OpenMIPS处理器就设计为在译码阶段进行转移判断。
实现思路:为了尽量减少转移指令带来的损失,OpenMIPS在译码阶段进行转移条件的判断,如果满足转移条件,那么修改PC为转移目标地址。
情况一:PC等于PC+4。这属于一般情况,每个时钟周期PC加4,指向下一条指令
情况二:PC保持不变。当流水线暂停的时候,就会发生这种情况,参考第7章中流水线
暂停的实现。
情况三:PC等于转移判断的结果。如果是转移指令,且满足转移条件,那么会将转移目标地址赋给PC。
如果处于译码阶段的指令是转移指令,并且满足转移条件,那么ID模块设置转移发生标志 branch _fag_o为Branch,同时通过 branch_target_address_o接口给出转移目的地址,送到 PC 模块,后者据此修改取指地址。
(2)如果处于译码阶段的指令是转移指令,并且满足转移条件,那么ID模块还会设置next_inst_in_ delayslot_o为InDelaySlot,表示下一条指令是延迟槽指令,其中 InDelaySlot 是一个宏定义。next_inst_in_delayslot_o信号会送入ID/EX模块,并在下一个时钟周期通过ID/EX模块的 is_in_ delayslot_o接口送回到ID 模块,ID 模块可以据此判断当前处于译码阶段的指令是否是延迟槽指令。
(3)如果转移指令需要保存返回地址,那么ID模块还要计算返回地址,并通过 link_addr_o接口输出,该值最终会传递到EX模块,作为要写入目的寄存器的值。
跳转指令
分支指令: