CPU 设计文档 - P5
设计方案
流水线各阶段寄存器设计
D 级 (F/D)
| 寄存器名 | 数据含义 |
|---|---|
| Instruction [31:0] | 指令存储器中读取出的指令. |
| PC [31:0] | 当前指令的地址. |
- 注意:为实现流水线的阻塞,需要传入当前流水线寄存器的值。
E 级 (D/E)
Control 信号
| 寄存器名 | |
|---|---|
| ALUop [3:0] | 指明 ALU 的运算类型. |
| ALUSrc [1:0] | 决定 ALU 输入端 B 数据来源. |
| RegWrite | 寄存器堆写入使能信号. |
| MemtoReg [1:0] | 决定寄存器堆写入端数据来源. |
| MemWrite | DM 写入使能信号. |
| MemRead | DM 读取使能信号. |
| MemtoDM | 决定 DM 写入端数据来源. |
数据传递
| 寄存器名 | |
|---|---|
| Reg [4:0] | 当前指令可能写入的寄存器地址. |
| read1 [31:0] | 当前指令正确对应的寄存器 Reg_1(rs) 的数据. |
| read2 [31:0] | 当前指令正确对应的寄存器 Reg_2(rt) 的数据. |
| Shamt [4:0] | 当前指令 Shamt 字段. |
| Imm [31:0] | 当前指令正确扩展的立即数. |
| Instruction [31:0] | 指令存储器中读取出的指令. |
| PC [31:0] | 当前指令的地址. |
M 级 (E/M)
A-T 模型
| 寄存器名 | |
|---|---|
| Tnew [1:0] | 产出数据的供给时间(经过多少个时钟周期可以算出结果并且存储到流水级寄存器里). |
Control 信号
| 寄存器名 | |
|---|---|
| RegWrite | 寄存器堆写入使能信号. |
| MemtoReg [1:0] | 决定寄存器堆写入端数据来源. |
| MemWrite | DM 写入使能信号. |
| MemRead | DM 读取使能信号. |
| MemtoDM | 决定 DM 写入端数据来源. |
数据传递
| 寄存器名 | |
|---|---|
| Reg [4:0] | 当前指令可能写入的寄存器地址. |
| rt [31:0] | 当前指令正确对应的寄存器rt的数据. |
| Result [31:0] | ALU 模块的运算结果. |
| Instruction [31:0] | 当前指令的机器码. |
| PC [31:0] | 当前指令的地址. |
W 级 (M/W)
A-T 模型
| 寄存器名 | |
|---|---|
| Tnew [1:0] | 产出数据的供给时间(经过多少个时钟周期可以算出结果并且存储到流水级寄存器里). |
Control 信号
| 寄存器名 | |
|---|---|
| RegWrite | 寄存器堆写入使能信号. |
| MemtoReg [1:0] | 决定寄存器堆写入端数据来源. |
数据传递
| 寄存器名 | |
|---|---|
| Reg [4:0] | 当前指令可能写入的寄存器地址. |
| Result [31:0] | ALU 模块的运算结果. |
| ReadData [31:0] | 使能信号有效时,从 DM 读取到的 32 位数据. |
| PC [31:0] | 当前指令的地址. |
模块设计与功能规定
IFU
端口说明
| 信号名 | 方向 | |
|---|---|---|
| clk | I | 时钟信号. |
| reset | I | 同步复位信号. |
| Branch [2:0] | I | Controller 输出的跳转类型. |
| Judge [1:0] | I | D 级输出的判断值. |
| Imm [31:0] | I | 经过扩展的 32 位立即数. |
| rs [31:0] | I | 寄存器 rs 的值. |
| Instruction [31:0] | O | 当前的 32 位指令码. |
| PC [31:0] | O | 当前指令的地址. |
Controller
端口说明
| 信号名 | 方向 | |
|---|---|---|
| OpCode [5:0] | I | 指令的 OpCode 字段. |
| Func [5:0] | I | 指令的 Func 字段. |
| Ext [1:0] | O | 指明立即数的扩展方式. |
| ALUop [3:0] | O | 指明 ALU 的运算类型. |
| ALUSrc [1:0] | O | 决定 ALU 输入端 B 数据来源. |
| Branch [2:0] | O | 决定跳转类型. |
| RegWrite | O | GRF写入使能信号. |
| RegDst [1:0] | O | 决定 GRF 写入端地址. |
| MemtoReg [1:0] | O | 决定 GRF 写入端数据来源. |
| MemWrite | O | DM写入使能信号. |
| MemRead | O | DM读取使能信号. |
| MemtoDM | O | 决定 DM 写入端数据来源. |
功能规定
Ext (立即数扩展方式)
00 : 16 位立即数 0 扩展为 32 位;
01 : 16 位立即数符号扩展为 32 位;
ALUSrc ( ALU 输入端 B 数据来源)
00 : 选择 GRF 输出 read2(rt寄存器);
01 : 选择 EXT 输出.
Branch (跳转类型)
000 : 不跳转;
001 : 跳转到 Imm 指定的偏移量;
010 : 跳转到 Imm 指定的地址;
011 : 跳转到寄存器 rs 指定的地址.
RegWrite MemWrite MemRead (使能信号)
0 : 无效;
1 : 有效.
RegDst ( GRF 写入端地址)
00 : 选择 rt 字段;
01 : 选择 rd 字段;
10 : 选择寄存器 $ra.
MemtoReg ( GRF 写入端数据来源)
00 : 来自 ALU 输出;
01 : 来自 DM 输出;
10 : 来自 IFU 输出.
MemtoDM ( DM 写入端数据来源)
0 : 寄存器 rt 的值.
Hazard
端口说明
| 信号名 | 方向 | |
|---|---|---|
| D_Instruction [31:0] | I | D 级流水线指令的 32 位指令码. |
| E_Instruction [31:0] | I | E 级流水线指令的 32 位指令码. |
| M_Instruction [31:0] | I | M 级流水线指令的 32 位指令码. |
| E_Reg [4:0] | I | E 级 Reg 信号. |
| E_RegWrite | I | E 级 RegWrite 信号. |
| E_Tnew | I | E 级 Tnew 信号. |
| M_Reg [4:0] | I | M 级 Reg 信号. |
| M_RegWrite | I | M 级 RegWrite 信号. |
| M_Tnew | I | M 级 Tnew 信号. |
| M_MemtoReg [1:0] | I | M 级 MemtoReg 信号. |
| W_Reg [4:0] | I | W 级 Reg 信号. |
| W_RegWrite | I | W 级 RegWrite 信号. |
| D_read1 [31:0] | I | D 级 read1 信号. |
| D_read2 [31:0] | I | D 级 read2 信号. |
| E_read1 [31:0] | I | E 级 read1 信号. |
| E_read2 [31:0] | I | E 级 read2 信号. |
| M_Result [31:0] | I | M 级 Result 信号. |
| M_rtdata [31:0] | I | M 级读取的 rt 寄存器的值. |
| RegData [31:0] | I | W 级 GRF 写入的 32 位数据. |
| nop | O | 阻塞使能信号. |
| ALUdata1 [31:0] | O | 选择的 ALU 第一个操作数 read1 的正确值. |
| ALUdata2 [31:0] | O | 选择的 read2 的正确值. |
| WriteData [31:0] | O | 选择的 DM 写入数据. |
功能规定
- nop 阻塞使能信号,当有效时:
- 冻结 PC 的值;
- 冻结 D 级流水线寄存器的值;
- 将 E 级流水线寄存器清零。
- 五个选择器,实现数据的转发。
GRF
端口说明
| 信号名 | 方向 | |
|---|---|---|
| clk | I | 时钟信号. |
| reset | I | 同步复位信号. |
| reg1 [4:0] | I | 指定寄存器的 5 位地址,将目标寄存器的数据读出到 read1. |
| reg2 [4:0] | I | 指定寄存器的 5 位地址,将目标寄存器的数据读出到 read2. |
| RegWrite | I | GRF 写入使能信号:有效时允许向 GRF 中写入. |
| RegAddr [4:0] | I | GRF 写入目标寄存器的5位地址. |
| RegData [31:0] | I | GRF 写入的 32 位数据. |
| PC [31:0] | I | 当前指令的地址. |
| read1 [31:0] | O | 输出 Reg1 指定的寄存器中的 32 位数据. |
| read2 [31:0] | O | 输出 Reg2 指定的寄存器中的 32 位数据. |
EXT
端口说明
| 信号名 | 方向 | |
|---|---|---|
| Index [25:0] | I | 指令 Instruction 的 [25:0] 位. |
| Ext [1:0] | I | 指明立即数的扩展方式. |
| Imm [31:0] | O | 立即数按要求扩展后的结果. |
ALU
端口说明
| 信号名 | 方向 | |
|---|---|---|
| a [31:0] | I | 进行逻辑运算的第一个 32 位操作数. |
| b [31:0] | I | 进行逻辑运算的第二个 32 位操作数. |
| Shamt [4:0] | I | 当前指令的 Shamt 字段. |
| ALUoperation [3:0] | I | 由 ALU 控制单元输出的,指明 ALU 的运算类型. |
| Result [31:0] | O | 输出逻辑运算后的 32 位结果. |
功能规定
- 根据 ALU 控制单元输出的 ALUoperation 信号对两个 32位数据 A、B 进行算术逻辑运算。
| ALUoperation [3:0] | 功能 |
|---|---|
0000 |
执行+运算 |
0001 |
执行-运算 |
0010 |
执行&运算 |
0011 |
执行\|运算 |
0100 |
执行加载至高位 lui运算 |
0101 |
执行逻辑左移 sll运算 |
0110 |
执行逻辑右移 srl运算 |
0111 |
执行算术右移 sra运算 |
DM
端口说明
| 信号名 | 方向 | |
|---|---|---|
| clk | I | 时钟信号. |
| reset | I | 异步复位信号. |
| MemWrite | I | 写入使能信号. |
| MemRead | I | 读取使能信号. |
| Address [31:0] | I | ALU 输出的 32 位信号,当使能信号有效时作为数据读写的地址. |
| WriteData [31:0] | I | 使能信号有效时,要写入 RAM 中的 32 位数据. |
| PC [31:0] | I | 当前指令的地址. |
| ReadData [31:0] | O | 使能信号有效时,从 RAM 读取到的 32 位数据. |
思考题
1 . 我们使用提前分支判断的方法尽早产生结果来减少因不确定而带来的开销,但实际上这种方法并非总能提高效率,请从流水线冒险的角度思考其原因并给出一个指令序列的例子。
提前分支判断是指将分支判断提前到 D 级,从而若发生跳转,只会影响到 F 级指令。但是,以指令 beq 为例,由于在D级就要对 rs ,rt 寄存器的值进行判断,在 A-T 模型中,该指令 rs_Tuse 与 rt_Tuse 的值均为 0。因此, beq 指令很容易引起阻塞行为,并不完全一定能提高效率。
2 . 因为延迟槽的存在,对于
jal等需要将指令地址写入寄存器的指令,要写回 PC + 8,请思考为什么这样设计?
由于存在延迟槽,因此在执行跳转指令时,不论是否进行跳转,跳转指令的下一条指令(PC + 4)都会被执行。因此对于 jal 等指令,为使得函数返回时能正确执行接下来的指令,应将返回地址记为(PC + 8)。
3 . 我们要求大家所有转发数据都来源于流水寄存器而不能是功能部件(如 DM 、 ALU ),请思考为什么?
流水线 CPU 的效率由最短时钟周期决定,而最短时钟周期由流水线某一级最长数据通路决定。因此,如果数据选择来源于功能部件,将会加长这一数据通路,从而导致时钟周期延长,CPU 效率降低。
4 . 我们为什么要使用 GPR 内部转发?该如何实现?
如果在某一时钟周期内,W 级向 GRF 写入的寄存器与 D 级读取的寄存器相同时会导致冲突。为获得指令期望的数据,我们考虑进行转发,可以直接读到正在写入的数据。
5 . 我们转发时数据的需求者和供给者可能来源于哪些位置?共有哪些转发数据通路?
在本次设计中,为实现已经产生数据的充分利用,我一共设计了五条转发数据通路。数据的需求者包括:D 级 GRF 输出的 read1,read2 信号;E 级 ALU 输入的 a,b(rt branch) 信号;M 级 DM 输入的 WriteData 信号。同时,这些数据的供给者都来自于 E、M、W 级流水线寄存器。具体数据通路,可见 Hazard 功能规定。
6 . 在课上测试时,我们需要你现场实现新的指令,对于这些新的指令,你可能需要在原有的数据通路上做哪些扩展或修改?提示:你可以对指令进行分类,思考每一类指令可能修改或扩展哪些位置。
指令主要可以分为 R 型、I 型、J 型。对于 R 型指令,主要需要增加 ALU 模块的逻辑运算方式,其余行为可以参考其他 R 型指令。对于 I 型指令,注意立即数拓展的控制信号以及相关寄存器 A-T 模型的值。对于 J 型指令,一定注意其中的跳转判断,延迟槽以及地址存入问题。以上都是可能有所修改的地方。
7 . 确定你的译码方式,简要描述你的译码器架构,并思考该架构的优势以及不足。
我选择的是集中译码的方式。其优点明显,整个流水线只需要进行一次译码,便于增删指令,便于集中观察。但是缺点是流水线各级需要传递很多控制信号,需要更多流水线寄存器。