多周期CPU仿真

经过单周期CPU的洗礼,我们接下来要做的就是多周期CPU了。因为有很多单周期的代码可以复用,所以多周期写起来没有那么困难。

多周期CPU原理

多周期CPU就是指一条指令在多个时钟周期内完成,本身并不涉及多级流水线的设计,所以执行指令的性能反而不如单周期CPU。不过每一条指令在不同的时钟周期完成不同的阶段,因此执行指令的流程会更容易理解。每一条指令最多包含以下五个阶段:
1. 取指令:sIF状态,读取下一条指令地址 。
2. 指令译码:sID状态,读取下一条指令。
3. 指令执行:sEXE状态,执行运算。
4. 存储器访问:sMEM状态,读写数据存储器。
5. 写回:sWB状态,写入寄存器。

多周期CPU设计

多周期CPU和单周期CPU基本框架差不多,直接复用代码并稍作调整。然后因为每一条指令需要多个时钟周期执行,所以需要记录当前阶段(即状态)以及保存各阶段数据,其中指令的读取、状态的转移、寄存器的写入和数据寄存器的刷新均由时钟信号触发,如何分配上升沿和下降沿触发是多周期CPU设计的难点。

我的设计是由状态驱动指令的执行,即所有控制信号都由当前的状态和指令操作码共同确定,这就需要严格保证在每一个阶段先转移状态再执行指令。具体来说就是在每个时钟周期的上升沿触发状态转移,然后在下降沿读指令、写寄存器、刷新数据寄存器。因为上升沿只触发状态转移,所以状态转移不会与其它任何时序逻辑发生冲突,从而保证在下降沿当前状态可以确定当前阶段。虽然下降沿同时执行各种操作,但它们互不干扰,这是因为时序逻辑模块的触发不会影响整个CPU,影响的范围从当前时序逻辑模块的输出到下一个时序逻辑模块的输入为止。那么根据当前阶段就可以保证对应时序逻辑模块的触发的正确性,至于其它时序逻辑模块的触发则有可能是正确的,也有可能是不正确的。对于读操作,不正确的触发不会对程序的运行造成实质性的影响;对于写操作,不正确的触发会导致错误,因此必须通过控制信号禁止在正确的阶段以外进行写操作。

经过测试发现有两个特殊情况:
1. lw指令在写回阶段的下降沿要先刷新总线数据寄存器,再写寄存器,因此无法保证触发的先后顺序。
2. jal指令要在指令译码阶段下降沿先刷新指令寄存器,再写寄存器,同样无法保证触发的先后顺序。

我将指令寄存器的刷新调整为上升沿触发,这样不但可以同时解决这两个问题,而且不会对状态转移造成干扰。首先,对于第二个问题,在指令译码阶段上升沿刷新指令寄存器,在下降沿写寄存器,可以保证触发的先后顺序。然后,对于第一个问题,实际上在指令译码阶段下降沿会不正确地触发数据寄存器的刷新,从而提前完成指令执行阶段,并且对于在指令译码阶段之后的所有读操作都将提前一个时钟周期完成。因为lw指令除了写寄存器以外均为读操作,所以在访问寄存器阶段下降沿就会提前刷新总线数据寄存器,那么在写回阶段下降沿就可以保证写寄存器的正确性。最后,虽然指令寄存器的刷新和状态转移都是上升沿触发,但两者其实并不需要保证触发的先后顺序,因为两者的输出均作为控制单元的输入,而控制单元为组合逻辑电路,所以无论哪一个先触发都可以保证在指令译码下降沿之前确定控制信号。

使用工具

vivado软件和verilog语言

多周期CPU实现

多周期CPU的实现和单周期CPU差不多,除了加入数据寄存器模块和调整时序逻辑以外,唯一需要注意的是单周期CPU仿真初始时钟信号应为1,多周期CPU仿真初始时钟信号应为0,因为单周期CPU在执行第一条指令时不需要取指令(上升沿),多周期CPU在执行第一条指令时也不需要取指令(下降沿)。

猜你喜欢

转载自blog.csdn.net/Fast_G/article/details/80739389
今日推荐