跳转至

流水线 CPU 的设计和实现

流水线 CPU 的设计和实现较为复杂,下面的描述可能较为粗略。如果想看非常具体的描述讲解,则请同学们仔细听老师上课讲解,同时也可以去看计算机组成与设计 硬件/软件接口(RISC-V,第 5 版,学校书店有)这本书第 4 章的相关内容,上面有非常详细的流水线 CPU 的设计(以及习题)。

下面还是以 addi 为例,重新回顾流水线 CPU 的设计方法。

流水线 CPU 中的大部分的控制信号是由 ID 段生成,一段一段传到后续阶段进行处理的。因此,在设计的时候,我们可以从 WB 阶段开始,倒着考虑。这样可以保证在设计信号的时候不会漏下信号。

老师上课讲以及书上都是正着的方式,这个可能会好理解一些,因为这是指令执行的时间顺序。我们在这里默认大家都已经对流水线有了一定的了解,如果还不太清楚流水线的工作原理的话,请先听老师讲解或看书学习。

WB 阶段

对于 addi 指令的 WB 阶段,需要做的是将 alu 计算得到的 result 写回寄存器中,因此 WB 阶段需要的信号如下:

  • rf_wen = 1: 表示是否写寄存器(ID 段在解析指令后给出)
  • rf_wdata = alu_result: 写寄存器的数据(EXE 段计算后得出)
  • rf_waddr = rd: 写寄存器的编号(ID 段在解析指令后给出)

具体实现方式可以是将 mem_wb_reg 的对应信号直接引到 regfile 的写端口上。

MEM 阶段

对于 addi 指令的 MEM 阶段,不需要做任何事情,因此需要的信号如下:

  • mem_en = 0: 表示是否有内存操作(ID 段在解析指令后给出)

EXE 阶段

对于 addi 指令的 EXE 阶段,需要生成立即数,同时在 ALU 中进行加法运算,因此需要的信号如下:

  • rf_rdata_a/rf_rdata_b: 表示寄存器读取 rs1,rs2 地址的结果(ID 段在读取寄存器后给出)
  • inst: 指令,用于生成立即数(IF 段在读取 SRAM 后给出)
  • imm_type = I: 立即数种类(ID 段在解析指令后给出)
  • alu_op = ADD: alu 运算的种类(ID 段在解析指令后给出)
  • use_rs2 = false: 表示第二个 operand 是立即数还是 rs2 的读取结果(ID 段在解析指令后给出)

同时需要给出 rf_wdata = alu_result,以供 WB 阶段使用

ID 阶段

这个阶段对于所有指令都需要生成对应的控制信号,同时完成寄存器的读取。对于 addi 指令,需要的信号和对应的值如下:

  • inst = inst
  • rf_raddr_a = rs1 segment of instruction
  • rf_raddr_b = rs2 segment of instruction
  • imm_type = I
  • alu_op = ADD
  • use_rs2 = false
  • mem_en = 0
  • rf_wen = 1
  • rf_waddr = rd segment of instruction

这些信号的含义在上面已经介绍过了,因此在这里不再重新说明。

注意到需要进行可能的冲突处理,因此,若位于 EXE/MEM/WB 阶段的指令要写寄存器,且 ID 阶段的指令需要读这个寄存器,我们则不应该让 ID 阶段的指令进入下一阶段 (EXE)。否则这里将会读到错误(旧)的寄存器数据。

为此我们需要插入气泡。这里给出一个较为简单的气泡实现方案:使用指令addi zero, zero, 0填充流水线(输出的 inst 为32'h00000013,再生成对应的控制信号) 即可。当然,你可以换成任意一个既不写寄存器也不访问内存的指令来填充。注意 zero 寄存器的特殊处理。

IF 阶段

这个阶段对于所有指令都需要进行 SRAM 的读取,从而获取对应的指令。

这里的实现相当于在实验 5 中实现的 wishbone master 的一部分。你需要根据拿到的 pc,访问内存,获取到对应的指令。如果忘记了 wishbone master 的实现方法,请重新回顾 lab5 的相关内容。

注意到 wishbone 请求无法在一个周期内完成,因此需要向流水线中插入气泡。

在 IF 阶段还要完成 pc 的更新,由于这里只介绍 addi 指令的实现,因此直接让pc <= pc + 4即可。但由于还有其他的指令会修改 pc,因此我建议大家将 pc_mux 实现成一个单独的模块,通过控制信号控制 pc 的更新。

最后,在实现这些模块之后,在 top 中完成连线即可。

这样我们就完成了一个能执行 addi 指令的流水线 CPU 了。

总结

addi 指令需要的流水线信号如下表:

信号名 生成阶段 最后使用阶段 含义
inst 指令 IF EXE 指令编码
rf_raddr_a rs1 ID ID 读取寄存器编号
rf_raddr_b rs2 ID ID 读取寄存器编号
rf_rdata_a ?? ID EXE 读取寄存器结果
rf_rdata_b ?? ID EXE 读取寄存器结果
imm_type I ID EXE 立即数种类
alu_op ADD ID EXE ALU 操作
use_rs2 0 ID EXE 使用立即数/rs2
mem_en 0 ID MEM 是否在 MEM 段访存
rf_wen 1 ID WB 是否写寄存器
rf_waddr rd ID WB 写寄存器编号
rf_wdata result EXE WB 写寄存器数据

以上仅是一种对于 addi 指令可行的设计,同学们在实现时可以按照需要,自己设计对应的流水线信号。同时也可以自己调整功能所在的流水线段。


最后更新: 2022年10月24日
作者:Jiajie Chen (39.13%), cuibst (1.09%), 崔轶锴 (59.78%)