单周期CPU
单周期CPU
以MIPS为参考,logisim为仿真模拟器,设计一个支持addu、subu、or、andi、lui、beq、j、jal、jr、sb、sh、sw、lb、lh及lw指令的单周期CPU,共支持32条指令。若无特殊说明,涉及时钟的部件均为上升沿触发。
理论
单周期CPU的时钟周期
单周期CPU意味着一条指令涉及的所有操作均在一个时钟周期内完成,而不同指令执行从开始到结束所需的时间往往是不一样的,为了保证一个程序的所有指令能够顺利地执行,单周期CPU的时钟周期取时间最大者。由于设计方式、材料等方面的不同,CPU寄存器的访问时间是最快的,而内存的访问时间相当慢。在所有的指令中,访存指令(如lw,sw)的执行时间往往是最长的,为了提高效率,人们设计出了Cache这一结构(这是后话)。当然,由于时钟周期是不变的,单周期CPU的效率是很低的,现如今多采用流水线CPU。
CPU运行机制(简化)
CPU中的程序计数器(Program Counter)——PC存储着指令地址,通过这些地址,获得指令寄存器(Instruction Register)中对应的指令。指令通过译码器,得到控制各个逻辑单元的控制信号。一般而言,部分编码信号及数据在算术逻辑单元(Arithmetic and Logic Unit)进行运算,运算的结果或成为最终的结果写回CPU寄存器,或成为与内存进行交换时的地址和数据。若指令对内存进行访问,写操作时,ALU结果写入内存中;读操作时,将内存中对应地址的数据写回CPU寄存器。上述操作即为单周期CPU在一个时钟周期内的相关操作。下一个时钟周期,PC+4,获得新的指令地址,执行下一条指令。
实现
将所有操作大致分为取地址、取指令、译码、运算、访存及写回六个阶段。
顶层模块展示:

取地址
在MIPS中,指令的入口为\(12288_{(10)}\),亦即\(3000_{16}\)。当前Address+4即为下一条指令的地址。我们需要:当下一个时钟上升沿到来时,PC+4;当(异步)复位信号——Reset到来时,PC恢复至0x3000的状态。考虑到要实现的指令中有条件跳转指令(beq)及无条件跳转指令(j、jal、jr),因此,PC结构的输入是多样的,同时我们需要一个地址选择信号PCSrc(PCSource)。jal指令将PC+4写入$31号寄存器,执行jr指令时将$31号寄存器的内容作为新的PC。

此处无PCSrc,而是对Branch信号和Jump信号译码,实现对地址的选择。
取指令
此处的ROM最多存储32条指令,故需要五位的二进制数才能对所有指令进行选择。而之所以选择2-6位的数据,是因为此处为PC+4,PC的低两位(二进制)恒为00。
译码
MIPS中,一条指令为32位的二进制数,其组成有如下几种情况:
| OP(31-26) | RS(25-21) | RT(20-16) | RD(15-11) | shamt(10-6) | Func(5-0) |
|---|
| OP(31-26) | RS(25-21) | RT(20-16) | Imm16(15-0) |
|---|
| OP(31-26) | base(25-21) | RT(20-16) | imm16(15-0) |
|---|
| OP(31-26) | instr_index(25-0) |
|---|
指令经过分线器后,RD、RS及RT被传至GRF作为源寄存器和目的寄存器的地址,而OP和Func传至控制单元进行译码,imm16和imm26被传至其他逻辑单元。
控制信号与指令间的关系如下:
| ADDU | SUBU | OR | LUI | ANDI | BEQ | J | JAL | JR | LB/LH/LW | SB/SH/SW | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| RegDst | 1 | 1 | 1 | 0 | 0 | x | x | 2 | x | 0 | x |
| RegWrite | 1 | 1 | 1 | 1 | 1 | x | x | 1 | x | 1 | x |
| ALUSrc | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 1 |
| ALUOP | 0 | 1 | 2 | 3 | 4 | 1 | x | x | x | 0 | 0 |
| MemWrite | x | x | x | x | x | x | x | x | x | 0 | 1 |
| MemToReg | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| EXTOP | x | x | x | 0 | 0 | x | x | x | x | 1 | 1 |
其中对于‘x’和'0'的判定见仁见智。
除此之外,为了实现LB/LH/LW及SB/SH/SW指令,还需要添加控制位宽的信号。
运算
运算阶段没有太多要说明的地方,需要注意的是ALUOP控制信号和多选器输入间的关系,具体的对应情况由个人决定。此处BEQ指令引入了ZERO信号,目的是与Branch信号一同作用判断是否需要跳转。

访存
读指令
读取的数据的位宽受BWidth信号控制,而具体选择哪部分的数据受地址的低1/2位影响。
写指令
其具体机制与读指令类似,但稍显复杂。由于logisim的特性,我们需要先将给定地址的数据读取出来,然后用\(GPR[RT]_{x:0}\)代替指定字段的内容,再写入。

写回
RegWrite信号控制是否将数据写回CPU寄存器中(事实上,在此ALU结果和内存数据一直都有存在,所以需要由RegWrite决定是否写回)。而MemToReg信号决定写回的数据是ALU结果还是内存数据。
一些话
不保证图示的正确性,仅供参考。

浙公网安备 33010602011771号