单周期 CPU 的基础知识
CPU 本质上就是一个数字逻辑电路,所以我们设计 CPU 的时候实际上就是在设计电路。我们在使用 Verilog 的时候,实际上是在利用 Verilog 硬件描述语言来设计 CPU 的逻辑电路结构。因此,我们需要:
- 先进行电路设计
- 再进行 Verilog 的代码编写
只有当我们的电路被清晰的分解为结构图中各个模块与模块之间的连接、模块内部的数据通路和状态机、数据通路中的电路逻辑以及状态机中的状态转换图,那么接下来的 Verilog 代码设计就是一个简单的「翻译」而已。
单周期 CPU
单周期 CPU(Single Cycle Processor)是指一条指令在一个时钟周期内完成并开始下一条指令的执行。由时钟的「上升沿」和「下降沿」控制相关操作。两个相邻的「上升沿」或「下降沿」之间的时间间隔就是 CPU 的「时钟周期」。
CPU 执行指令的实际过程
一个 CPU 执行指令的基本流程是这样的:
步骤 | 行为 | |
---|---|---|
1 | 取指令 | CPU 根据 PC(程序计数器 - Program Counter)中的指令地址,在指令存储器中获取相应的指令,之后 PC 的值会自动改变移动到下一条指令的地址 |
2 | 指令译码 | 对获取的指令进行分析,确定这个指令要完成什么操作,改变相应的控制信号 |
3 | 指令执行 | 相关组件获取控制信号,执行相应操作,并将结果反馈 |
4 | 存储器访问 | 如果指令设计读取、存储内存,则需要对存储器中相应地址进行读取或者写入 |
5 | 结果写回 | 将得到的数据(访问存储器或者修改其它寄存器的值获得)写回相应的寄存器 |
6 | 循环 1-5 | ... |
MIPS32 指令集子集
根据 MIPS32 指令集的设计,我们需要实现的指令有以下三种类型:
所有的指令长度均为 32 比特。
根据实验要求,我们本次需要设计的指令共有这样几个:LUI、ADDIU、ADD、LW、SW、BEQ、J 以及一个抽签得到的指令(我的是 SUBU)。这些指令具体是这样的:
由 ALU 负责的指令
LUI
:将 16 位立即数 imm 写入寄存器 rt 的高 16 位,寄存器 rt 的低 16 位置 0ADDIU
:将寄存器 rs 的值与有符号扩展至 32 位的立即数 imm 相加,结果写入 rt 寄存器中ADD
:将寄存器 rs 的值与寄存器 rt 的值相加,结果写入寄存器 rd 中。如果产生溢出,则触发整型溢出例外(IntegerOverflow)
访存指令
LW
:将 base 寄存器的值加上符号扩展后的立即数 offset 得到访存的虚地址,据此虚地址从存储器中读取连续 4 个字节的值并进行符号扩展,写入到 rt 寄存器中(不对错误进行处理)SW
:将 base 寄存器的值加上符号扩展后的立即数 offset 得到访存的虚地址,据此虚地址将 rt 寄存器存入存储器中(不对错误进行处理)
转移指令(无条件或条件跳转)
BEQ
:如果寄存器 rs 的值等于寄存器 rt 的值则转移,否则顺序执行。转移目标由立即数 offset 左移 2 位并进行有符号扩展的值加上该分支指令对应的延迟槽指令的 PC 计算得到J
:无条件跳转。跳转目标由该分支指令对应的延迟槽指令的 PC 最高 4 位与立即数instr_index
左移 2 位后的值拼接得到
我小组三人随机抽到的指令
SUBU
:将寄存器 rs 的值与寄存器 rt 的值相减,结果写入 rd 寄存器中SRLV
:由寄存器 rs 中的值指定移位量,对寄存器 rt 的值进行逻辑右移,结果写入寄存器 rd 中ORI
:寄存器 rs 中的值与 0 扩展至 32 位的立即数 imm 按位逻辑或,结果写入寄存器 rt 中
CPU 组成中的主要元件
- 指令存储器(Instruction Memory)
- 数据存储器(Data Memory)
- 寄存器堆(Register File)
- 指令寄存器(Instruction Register)
- 程序计数器(Program Counter)
- 控制单元(Control Unit)
多周期、流水线 CPU
在流水线 CPU 中,为了将指令更有效地执行,我们会将 CPU 的取值、译码、执行的过程按照流水线的方式进行组织,从而提高 CPU 的执行、运算效率。在之后的实验中,我们会通过这种方式进行 CPU 指令的执行与实现。