多周期 CPU 相比单周期 CPU 以及流水线 CPU 实现来说其实写起来要麻烦那么一些,但是相对于流水线 CPU 和单周期 CPU 而言,多周期 CPU 除了能提升主频之外似乎并没有什么卵用,流水线 CPU 反而更有用一些。不过我的课题是多周期 CPU 那么就开始吧。
多周期 CPU不同于单周期 CPU,多周期 CPU 指的是将整个 CPU 的执行过程分成几个阶段,每个阶段用一个时钟去完 成,然后开始下一条指令的执行,而每种指令执行时所用的时钟数不尽相同,这就是所谓的多周期CPU。
CPU在处理指令时,一般需要经过以下几个阶段:
(1) 取指令(IF):根据程序计数器 PC 中的指令地址,从存储器中取出一条指令,同时,PC 根据指令字长度自动递增产生下一条指令所需要的指令地址,但遇到“地址转移”指令 时,则控制器把“转移地址”送入 PC,当然得到的“地址”需要做些变换才送入 PC。
(2) 指令译码(ID):对取指令操作中得到的指令进行分析并译码,确定这条指令需要完成的操作,从而产生相应的操作控制信号,用于驱动执行状态中的各种操作。
(3) 指令执行(EXE):根据指令译码得到的操作控制信号,具体地执行指令动作,然后转移到结果写回状态。
(4) 存储器访问(MEM):所有需要访问存储器的操作都将在这个步骤中执行,该步骤给出存储器的数据地址,把数据写入到存储器中数据地址所指定的存储单元或者从存储器中得 到数据地址单元中的数据。
(5) 结果写回(WB):指令执行的结果或者访问存储器中得到的数据写回相应的目的寄存器中。
这也就意味着一条 CPU 指令最长需要 5 个时钟周期才能执行完毕,至于具体需要多少周期则根据指令的不同而不同。
MIPS 指令集的设计为定长简单指令集,这为 CPU 的实现带来了极大的方便。
指令集MIPS 指令分为三种:R、I 和 J,三种指令有不同的存储方式:
其中,
op:操作码;
rs:第1个源操作数寄存器,寄存器地址(编号)是00000~11111,00~1F;
rt:第2个源操作数寄存器,或目的操作数寄存器,寄存器地址(同上);
rd:目的操作数寄存器,寄存器地址(同上);
sa:位移量(shift amt),移位指令用于指定移多少位;
funct:功能码,在寄存器类型指令中(R类型)用来指定指令的功能;
immediate:16位立即数,用作无符号的逻辑操作数、有符号的算术操作数、数据加载(Load)/数据保存(Store)指令的数据地址字节偏移量和分支指令中相对程序计数器(PC)的有符号偏移量;
address:地址。
在执行指令的过程中,需要在不同的时钟周期之间进行状态转移:
本简易 CPU 姑且只实现以下指令:
OpCode 指令 功能000000 add rd, rs, rt 带符号加法运算
000001 sub rd, rs, rt 带符号减法运算
000010 addiu rt, rs, immediate 无符号加法运算
010000 and rd, rs, rt 与运算
010001 andi rt, rs, immediate 对立即数做 0 扩展后进行与运算
010010 ori rt, rs, immediate 对立即数做 0 扩展后做或运算
010011 xori rt, rs, immediate 对立即数做 0 扩展后做异或运算
011000 sll rd, rt, sa 左移指令
100110 slti rt, rs, immediate 比较指令
100111 slt rd, rs, rt 比较指令
110000 sw rt, immediate(rs) 存数指令
110001 lw rt, immediate(rs) 读数指令
110100 beq rs, rt, immediate 分支指令,相等时跳转
110101 bne rs, rt, immediate 分支指令,不等时跳转
110110 bltz rs, immediate 分支指令,小于 0 时跳转
111000 j addr 跳转指令
111001 jr rs 跳转指令
111010 jal addr 调用子程序指令
111111 halt 停机指令
控制单元
一个简易的多周期 CPU 的数据通路图如下: