关于指令译码级(ID stage)的设计决策

ID级的任务是对指令译码,根据不同的指令产生相应的控制信号,控制CPU内的其他部件按要求工作。
要设计ID级,首先要确定CPU支持的指令,然后根据指令,编制控制信号表,依照控制信号表进行硬件设计工作。ID级需要考虑跳转、中断、异常、分支预测的复杂任务,这些问题都需要在设计前提前确定。虽然第一阶段我的CPU不一定对复杂的功能进行支持,但是为了在以后进行扩展时不对系统进行大的改动,这些部分确实需要仔细考虑。其中一些问题是相互关联的,如果不提前考虑好,以后改动起来会比较麻烦。

分支预测还是延时槽?

这是首先要解决的问题。我最初的设想,是沿用早期RISC处理器的延时槽,认为其硬件实现简单,即便软件上需要一些优化措施,也可暂不实施,以空指令填充延时槽。但是现代处理器纷纷抛弃指令延时槽是有原因的(相关讨论),而我在设计过程中所遇到的问题合这些历史一样,这使我不得不重新权衡二者之间的利弊。

延时槽真的会简化硬件设计吗?

初步看,延时槽确实可以简化流水线的结构,尤其是取指阶段。但是引入延时槽会使得中断和异常的设计变得复杂。一旦引入延时槽,就需要分析发生中断或异常时,各级指令是否是延时槽中的指令。这是因为从中断或异常返回时要确定的返回地址与当前指令是否是延时槽中的指令有关。延时槽改变了流水线中原本的顺序结构,如果发生异常的指令是延时槽中的指令,按照处理异常的惯例,需要在异常处理完毕后返回发生异常的指令,这时候,若不做特殊处理,处理器就会丢弃异常指令前的一个跳转指令的跳转,使得处理器执行发生错误。这种由延时槽引入的复杂性,对于中断来说好处理一些,毕竟中断时来自外部设备,总可以让外部设备先等一等,等到CPU状态稳定一些在处理中断。但对于异常来说就没有那么幸运了,异常可以发生在CPU的任何一个阶段:取指阶段有缺页异常,译码阶段有为实现的指令异常,EXE级有溢出异常,WB级有缺页异常。单独分析这些阶段与延时槽的关系,显得得不偿失。

分支预测比延时槽复杂多少?

静态分支预测和简单的动态分支预测并不复杂。拿静态分支预测来说,我若总是预测跳转不发生,即总是预取跳转后的下一条指令,只需要在指令预取阶段增加一套流水线废弃机制,当ID级对跳转指令译码完毕时,即可判断当前预取的指令是否是正确的跳转目标,如果不是,废弃当前指令即可。这样做虽然性能差一点,但是对于我这样一个只有5级流水线的CPU来说,性能损失并不大,而且即使使用延时槽,我也没有打算完整的进行编译器的优化(lcc目前并不支持延时槽的优化,这个需要我手工完成)。但是使用静态分支预测,可以保证后续流水线中的有效指令均是正确的执行顺序,在分析异常时,不用再考虑跳转的影响,异常和中断处理就会大大简化。

我的设计决策

正如CPU设计的主流,我也倾向于使用分支预测替代延时槽。我设计这个CPU的目的一是用于教学实践,二是用于学术研究,显然研究各种分支预测方法的效率对比是很有价值的。一旦选择了分支预测这条设计路线,以后在这个平台上实现不同的分支预测方法会很方便。因此我选择分支预测,并不是因为性能,更多的是为了方便以后的设计。目前我决定采用静态分支预测,总是预测跳转不发生,即总是与去跳转后的下一条指令,然后在ID级进行跳转结果的比对,如果跳转后的预取不正确,就废弃预取的指令。以后的路线包括增加饱和计数器和二级分支预测器等动态指令预取。这样我在实现各种异常的时候就会轻松很多。

动态分支预测与自修改代码

如果实现了动态分支预测,还需要实现与自修改代码配合的机制。饱和计数器等动态分支预测器,往往采用指令的地址作为标签,因此可以在IF级就能知道某个指令是否是跳转指令和预测的跳转目标,但这与自修改代码有一定的冲突。试想某一条跳转指令已经存储在分支预测器中,这时如果发生自修改代码的情况,这一地址的指令被修改为其他的指令。而由于分支预测器是用地址作为标签的,与cache一样存在自修改代码的同步问题。这个问题在Intel的X86处理器手册上我没有找到相关的表述,倒是在analog devices的一个DSP的手册里看到了相关的描述(Tuning Dynamic Branch Prediction on ADSP-BF70x Processors)。

Finally, it is good programming practice to reset the BP if self-modifying code is used. This will clear invalid branch entries associated with previous execution from the affected memory space from the BP table and result in correct operation. For a detailed description of the procedure for clearing the BP table, see the ADSPBF70x Blackfin+ Processor Programming Reference.

我猜想X86处理器的分支预测器应该和其cache一样,有相关的硬件处理这个问题。

与cache的同步机制不同,分支预测器的同步机制逻辑较为简单,可以不涉及系统总线的监听。因为分支预测器内只记录跳转指令的地址,对分支预测器的同步只需要保证预取的地址正确即可,地址内的指令有cache的同步机制保证。因此,在每次执行到分支预测器中记录的地址时,ID级要检查该地址包含的指令是否是跳转指令,如果是跳转指令则分支预测器内的记录不动,依照跳转指令执行的结果相应的更新分支预测器内该记录的状态即可。如果该指令在分支预测器内但不是跳转指令,说明发生了自修改代码,此时应使分支预测器内的条目失效,并根据分支预测的结果判断是否将预取的指令废弃,若分支预测的结果是跳转,则需要将IF级预取的指令废弃并修改NextPC为PC+4,否则预取的仍是正确的指令,仅将分支预测器内的条目作废即可。

Cache同步机制的设计实现和测试 组相联cache设计、实现与测试
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×