CO_P5
CPU 设计文档
一、指令类型
- 解读:将指令按类型分类,并对指令按照功能划分
R类型指令
R类型指令 | Op(31~26) | Rs(25~21) | Rt(20~16) | Rd(15~11) | Shamt(10~6) | Func(5~0) |
---|---|---|---|---|---|---|
Add | 000000 | Rs | Rt | Rd | XXXXX | 100000 |
Sub | 000000 | Rs | Rt | Rd | XXXXX | 100010 |
Jr | 000000 | Rs | 00000 | 00000 | 00000 | 001000 |
add:
sub:
jr:
I类型指令
I类型指令 | Op(31~26) | Rs(25~21) | Rt(20~16) | immediate or address |
---|---|---|---|---|
Ori | 001101 | Rs | Rt | imm16 |
Lui | 001111 | 00000 | Rt | imm16 |
Lw | 100011 | Rs | Rt | imm16 |
Sw | 101011 | Rs | Rt | imm16 |
Beq | 000100 | Rs | Rt | imm16 |
ori:
lui:
lw:
sw:
beq:
J类型指令
J类型指令 | Op(31~26) | 26 address |
---|---|---|
j | 000010 | target |
jal | 000011 | target |
jal:
二、主要模块
mips(顶层模块)
端口 | 方向 | 描述 |
---|---|---|
clk | I | 时钟信号,控制所有需clk信号输入的模块 |
reset | I | 同步复位信号,控制所有需reset信号输入的模块 |
Conroller(控制器)
控制信号类型及含义
Branch
>
- `Branch_normal : 0,PC输入选择加法器Add输出(PC+4)
- `Branch_Beq 1: 若Zero=1,PC输入选择加法器Nadd
- `Branch_Jal 2: PC输入选择Jal_Adr
`Branch_Jr 3: PC输入选择Rdata1
RegDst`RegDst_Rd: 选择Rd
- `RegDst_Rt: 选择Rt
- `RegDst_31:选择31(jal指令)
RegWirte1: 表示寄存器堆可写入
MemtoReg
>
- `MemtoReg_ALU: 选择 ALU 输出
- `MemtoReg_shift: 选择shift输出
- `MemtoReg_DM: 选择数据存储器DM输出
- `MemtoReg_Adder:选择Adder(地址加法器)输出
ALUSrc
>
- `ALUSrc_ReadData2: 选择寄存器堆的 Read data2 输出
- `ALUSrc_SiExt: 选择Signext输入
- `ALUSrc_ZeExt:选择zero_ext输入
ALUOper
>
- `ALU_add: ALU运算类型 —— +
- `ALU_sub: ALU运算类型 —— -
- `ALU_or: ALU运算类型 —— |
MemRead
>
- 0:表示DM不可写入
- 1:表示DM可写入
MemWrite
>
- 0:表示DM不可写入
- 1:表示DM可写入
shiftSrc
>
- `shiftSrc_shamt: shamt(shift)选择shamt输入
- `shiftSrc_0x10:shamt(shift) 选择0x10输入
- `shiftSrc_0:shamt(shift) 选择0输入
(in.shift根据ALUSrc决定)
Tnew,rs_Tuse,rt_Tuse:根据指令输出
>
- Tnew: 表示位于E级寄存器的指令经过Tnew个时钟周期可以算出结果并且存储到下一级流水级寄存器中。
- rs_Tuse,rt_Tuse:表示该指令位于 D 级的时候,再经过多少个时钟周期就必须要使用Rs,Rt地址对应的数据。
Controller (指令实现控制信号的转换)
- x表示指令实现与该输入无关
指令 | Opcode | Branch | RegDst | RegWrite | MemtoReg | ALUSrc | ALUOp | MemWrite | MemCate | shiftSrc | Tnew | rs_Tuse | rt_Tuse |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Add/Sub | 000000 | 0 | 0 | 1 | 0 | 0 | 2 | 0 | x | x | 1 | 1 | 1 |
Lw | 100011 | 0 | 1 | 1 | 2 | 2 | 0 | 0 | x | x | 2 | 1 | 5 |
Sw | 101011 | 0 | x | 0 | x | 2 | 0 | 1 | 0 | x | 0 | 1 | 2 |
Beq | 000100 | 1 | x | 0 | x | 0 | 1 | 0 | x | x | 0 | 0 | 0 |
Ori | 001101 | 0 | 1 | 1 | 0 | 1 | 3 | 0 | x | x | 1 | 1 | 5 |
Lui | 001111 | 0 | 1 | 1 | 1 | x | x | 0 | x | 1 | 0 | 5 | 5 |
Nop | 000000 | 0 | x | 0 | x | x | x | 0 | x | 0 | 0 | 5 | 5 |
Jal | 000011 | 2 | 2 | 1 | 3 | x | x | 0 | x | x | 0 | 5 | 5 |
Jr | 000000 | 3 | x | 0 | x | x | x | 0 | x | x | 0 | 0 | 5 |
IFU (取指令单元)
端口 | 方向 | 描述 |
---|---|---|
Clk | I | 时钟信号 |
Reset | I | 指令存储器(im_reg)所有地址的存储值清零 1: 复位 0:无效 |
enable_PC | I | 写使能信号, 1: 可写入数据 0: 不可写入数据(不可更改) |
Branch | I | PC值分支跳转指令判断(4位) |
Zero | I | beq指令判断PC是否跳转条件(1位) |
index | I | 跳转指令的target中间值(26位) |
immSiExt | I | 16位立即数有符号扩展输入(32位) |
D_pc | I | D级指令所对应的PC地址(32位) |
ReadData1 | O | GRF(寄存器堆)中Read register1地址对应寄存器的输出 |
pc | O | PC当前值(32位) |
instr | O | PC地址对应IM(指令存储器)的指令输出(32位) |
IF_ID(D级寄存器)
端口 | 方向 | 描述 |
---|---|---|
clk | I | 时钟信号 |
reset | I | 寄存器存储值清零 1: 复位 0:无效 |
enable_D | I | 写使能信号, 1: 可写入数据 0: 不可写入数据(不可更改) |
F_pc | I | F级指令对应的PC地址(32位) |
F_instr | I | F级指令PC地址对应的指令(32位) |
D_pc | O | D级指令对应的PC地址(32位) |
D_instr | O | D级指令PC地址对应的指令(32位) |
Stall (暂停信号控制器)
端口 | 方向 | 描述 |
---|---|---|
rs_Tuse | I | D级指令对应的rs_Tuse(4位) |
rt_Tuse | I | D级指令对应的rt_Tuse(4位) |
E_Tnew | I | E级指令对应的Tnew(4位) |
M_Tnew | I | M级指令对应的Tnew(4位) |
W_Tnew | I | W级指令对应的Tnew(4位) |
Rs | I | D级指令对应的Rs(5位) |
Rt | I | D级指令对应的Rt(5位) |
E_WriteRes | I | E级指令执行写入GRF操作时的地址(5位) |
M_WriteRes | I | M级指令执行写入GRF操作时的地址(5位) |
W_WriteRes | I | W级指令执行写入GRF操作时的地址(5位) |
E_RegWrite | I | E级指令是否执行写入GRF操作, 1: 写入 0: 不写入 |
M_RegWrite | I | M级指令是否执行写入GRF操作, 1: 写入 0: 不写入 |
W_RegWrite | I | W级指令是否执行写入GRF操作, 1: 写入 0: 不写入 |
enable_PC | O | IFU模块中的PC寄存器写使能信号, 1: 可写入数据 0: 不可写入数据(不可更改) |
enable_D | O | D级寄存器写使能信号, 1: 可写入数据 0: 不可写入数据(不可更改) |
enable_PC | O | IFU模块中的PC寄存器写使能信号, 1: 可写入数据 0: 不可写入数据(不可更改) |
reset_E | O | E级寄存器存储值清零 1: 复位 0:无效 |
shift(移位器)
端口 | 方向 | 描述 |
---|---|---|
input | I | 操作数 |
shamt | I | 偏移量(5位) |
output | I | 操作数移位后输出 |
CMP(比较器)
端口 | 方向 | 描述 |
---|---|---|
ReadData1 | I | 操作数1 |
ReadData2 | I | 操作数2 |
Zero | O | 比较ReadData1和ReadData2, 1: 相等 0: 不相等 |
GRF(寄存器堆)
端口 | 方向 | 描述 |
---|---|---|
Clk | I | 时钟信号 |
Reset | I | 复位信号,将寄存器的值全部清零 1: 复位 0:无效 |
WE | I | 写使能信号 1: 可写入数据 0: 不可写入数据 |
ReadRes1 | I | 读出地址输入(5位),读出到Read Data1 |
ReadRes2 | I | 读出地址输入(5位),读出到Read Data2 |
WriteRes | I | 写入地址输入(5位) |
WriteData | I | 写入数据(32位) |
WPC | I | 输入当前pc地址 |
ReadData1 | O | Read register1地址对应寄存器的输出 |
ReadData2 | O | Read register2地址对应寄存器的输出 |
ID_EX (E级寄存器)
端口 | 方向 | 描述 |
---|---|---|
clk | I | 时钟信号 |
reset | I | 复位信号,将寄存器的值全部清零 1: 复位 0:无效 |
D_pc | I | D级指令对应的pc地址 |
reset_E | I | E级寄存器的复位信号,将寄存器的值全部清零 1: 复位 0:无效 |
D_ReadRes1 | I | D级指令对应的Rs,GRF读出地址(5位) |
D_ReadRes2 | I | D级指令对应的Rt,GRF读出地址(5位) |
D_ReadData1 | I | D级指令D_ReadRes1地址对应寄存器的输出(32位) |
D_ReadData2 | I | D级指令D_ReadRes2地址对应寄存器的输出(32位) |
D_WriteRes | I | D级指令写入GRF的地址(5位) |
D_WriteData | I | D级指令写入GRF的数据(32位) |
D_ExtShift | I | D级指令的extend和shift模块输出(32位) |
D_MemtoReg | I | D级指令存入GRF的数据类型(4位) |
D_MemWrite | I | D级指令是否写入DM 1: 可写入 0:不可写入 |
D_MemCate | I | D级指令写入DM的指令类型(4位) |
D_ALUOper | I | D级指令运算类型(4位) |
D_RegWrite | I | D级指令是否可写入GRF 1: 可写入 0:不可写入 |
D_ALUSrc | I | D级指令ALU模块的B端口输入数据类型(4位) |
D_Tnew | I | D级指令对应的Tnew(4位) |
E_pc | I | E级指令对应的pc地址 |
E_ReadRes1 | I | E级指令对应的Rs,GRF读出地址(5位) |
E_ReadRes2 | I | E级指令对应的Rt,GRF读出地址(5位) |
E_ReadData1 | I | E级指令D_ReadRes1地址对应寄存器的输出(32位) |
E_ReadData2 | I | E级指令D_ReadRes2地址对应寄存器的输出(32位) |
E_WriteRes | IE级指令写入GRF的地址(5位) | |
E_WriteData | I | E级指令写入GRF的数据(32位) |
E_ExtShift | I | E级指令的extend和shift模块输出(32位) |
E_MemtoReg | I | E级指令存入GRF的数据类型(4位) |
E_MemWrite | I | E级指令是否写入DM 1: 可写入 0:不可写入 |
E_MemCate | I | E级指令写入DM的指令类型(4位) |
E_ALUOper | I | E级指令运算类型(4位) |
E_RegWrite | I | E级指令是否可写入GRF 1: 可写入 0:不可写入 |
E_ALUSrc | I | E级指令ALU模块的B端口输入数据类型(4位) |
E_Tnew | I | E级指令对应的Tnew(4位) |
ALU(算数逻辑单位)
端口 | 方向 | 描述 |
---|---|---|
A | I | 操作数1(32位) |
B | I | 操作数2(32位) |
ALUOper | I | ALU功能选择(4位) |
Result | O | 结果输出(32位) |
EX_MEM(M级寄存器)
端口 | 方向 | 描述 |
---|---|---|
clk | I | 时钟信号 |
reset | I | 复位信号,将寄存器的值全部清零 1: 复位 0:无效 |
ALU_out | I | D级指令ALU的输出结果(32位) |
E_pc | I | E级指令对应的pc地址 |
E_ReadRes1 | I | E级指令对应的Rs,GRF读出地址(5位) |
E_ReadRes2 | I | E级指令对应的Rt,GRF读出地址(5位) |
E_ReadData2 | I | E级指令D_ReadRes2地址对应寄存器的输出,需转发(32位) |
E_WriteRes | I | E级指令写入GRF的地址(5位) |
E_WriteData | I | E级指令写入GRF的数据(32位) |
E_MemtoReg | I | E级指令存入GRF的数据类型(4位) |
E_MemWrite | I | E级指令是否写入DM 1: 可写入 0:不可写入 |
E_MemAddress | I | E级指令写入DM的地址(32位) |
E_MemCate | I | E级指令写入DM的指令类型(4位) |
E_RegWrite | I | E级指令是否可写入GRF 1: 可写入 0:不可写入 |
E_Tnew | I | E级指令对应的Tnew(4位) |
M_pc | O | M级指令对应的pc地址 |
M_ReadRes1 | O | M级指令对应的Rs,GRF读出地址(5位) |
M_ReadRes2 | O | M级指令对应的Rt,GRF读出地址(5位) |
M_ReadData2 | O | M级指令D_ReadRes2地址对应寄存器的输出(32位) |
M_WriteRes | O | M级指令写入GRF的地址(5位) |
M_WriteData | O | M级指令写入GRF的数据(32位) |
M_MemtoReg | O | M级指令存入GRF的数据类型(4位) |
M_MemWrite | O | M级指令是否写入DM 1: 可写入 0:不可写入 |
M_MemAddress | O | M级指令写入DM的地址(32位) |
M_MemCate | O | M级指令写入DM的指令类型(4位) |
M_RegWrite | O | M级指令是否可写入GRF 1: 可写入 0:不可写入 |
M_Tnew | O | M级指令对应的Tnew(4位) |
DM(数据存储器)
端口 | 方向 | 描述 |
---|---|---|
Clk | I | 时钟信号 |
pc | O | M级指令的PC当前值(32位) |
Reset | I | 数据存储器(RAM)所有地址的存储值清零 1: 复位 0:无效 |
MemWrite | I | 写使能信号, 1: 可写入数据 0: 不可写入数据 |
MemCate | I | 判断向数据储存器写入数据的操作指令类型(4位) |
Address | I | 读写地址(12位) |
WriteData | I | 写入数据(32位) |
ReadData_DM | O | Address地址对应数据储存器(RAM)的储存值输出 |
MEM_WB
端口 | 方向 | 描述 |
---|---|---|
clk | I | 时钟信号 |
reset | I | 复位信号,将寄存器的值全部清零 1: 复位 0:无效 |
M_pc | I | M级指令对应的pc地址 |
M_WriteRes | I | M级指令写入GRF的地址(5位) |
M_WriteData | I | M级指令写入GRF的数据(32位) |
M_MemtoReg | I | M级指令存入GRF的数据类型(4位) |
M_MemWrite | I | M级指令是否写入DM 1: 可写入 0:不可写入 |
M_RegWrite | I | M级指令是否可写入GRF 1: 可写入 0:不可写入 |
M_Tnew | I | M级指令对应的Tnew(4位) |
ReadData_DM | I | M级指令Address地址对应数据储存器(RAM)的储存值输出 |
W_pc | O | W级指令对应的pc地址 |
W_WriteRes | O | W级指令写入GRF的地址(5位) |
W_WriteData | O | W级指令写入GRF的数据(32位) |
W_MemtoReg | O | W级指令存入GRF的数据类型(4位) |
W_MemWrite | O | W级指令是否写入DM 1: 可写入 0:不可写入 |
W_RegWrite | O | W级指令是否可写入GRF 1: 可写入 0:不可写入 |
W_Tnew | O | W级指令对应的Tnew(4位) |
三、数据通路
指令 | A | B | PC | IM Adr | Reg1 | Reg2 | Wreg | Wdata | A | B | DM Adr | DM Wdata | Sign-ext | A | B | shift | ext | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Adder: | ALU: | Nadder: | / | |||||||||||||||
R型指令与访存 | PC | 4 | Adder | PC | Rs | Rt | Rd | ALU | Rdata1 | Rdata2 | / | / | / | / | / | /! | / | |
Lw | PC | 4 | Adder | PC | Rs | / | Rt | DM | Rdata1 | Sign_ext | ALU | / | imm16 | / | / | / | / | |
Sw | PC | 4 | Adder | PC | Rs | Rt | / | / | Rdata1 | Sign_ext | ALU | Rdata2 | imm16 | / | / | / | / | |
Beq | PC | 4 | Adder/Nadder | PC | Rs | Rt | / | / | Rdata1 | Rdata2 | / | / | imm16 | Adder | Sign-imm16(左移2) | / | / | |
Ori | PC | 4 | Adder | PC | Rs | / | Rt | ALU | Rdata1 | zero_ext | / | / | / | / | / | / | imm16 | |
Lui | PC | 4 | Adder | PC | / | / | Rt | shift | / | / | / | / | / | / | / | imm16 | / | / |
Nop | PC | 4 | Adder | PC | / | Rt | Rd | shift | / | / | / | / | / | / | / | Rdata2 | / | |
jal | PC | 4 | Jal_Adr | PC | / | / | 31 | Adder | / | / | / | / | / | / | / | / | / | |
jr | / | / | Rdata1 | PC | Rs | / | / | / | / | / | / | / | / | / | / | / | / |
四、测试
1 | ori $s0,$0,0 |
- Mars导出的机械码(储存在code.txt中的文件):
1 | 34100000 |
利用$readmemh指令读取code.txt中的机械码指令并储存在IFU_mips模块的指令存储器im_reg(4096个32位寄存器)当中,运行mips顶层模块,通过$display指令检测存入寄存器堆(GRF)和数据存储器(DM)时的pc地址,相应数据以及存入的寄存器或数据存储器地址,将结果与Mars对拍运行时的数据做比对,以此检测Verilog代码编写的单周期CPU是否正确。
五、思考题
Q1
若发生流水线冒险行为,则需要进行暂停操作,从而保证提前分支判断时进行比较的数据是已更新后的数据(可以在通过转发减少暂停,提高效率,但无法减少产生新数据所需的暂停),这样就导致提前分支判断所需的周期数与未提前分支判断时所需的周期数相同,未提高效率。
下列例子可见:
在执行beq指令时,add指令对beq指令的比较数据进行修改,其Tnew = 1,后者Tuse = 0,则此时需要暂停一个周期,才能将add指令于E级算出的结果转发至D级(beq指令所处级数),未提前分支判断时当beq指令流水至E级时也可进行分支判断,此时两者效率相同。
1 | ori $t0,123 |
Q2
因为延迟槽(为保证F级指令不被作废)的存在,从而导致jal指令的下一条指令为延迟槽,而延迟槽指令在jal指令在实现跳转过程中已经进入F级流水寄存器中(被执行),故通过jr指令链接调回原指令的下一条指令时,应是延迟槽指令的下一条指令,其对应的PC地址为jal指令对应的PC地址PC_jal + 8;
Q3
因为如果转发数据源自功能部件(DM,ALU),则导致在该时钟周期内,既要包含功能部件的运行时间,也要包含需要转发数据的部件的运行时间,从而延长了时钟周期,导致违背了流水线寄存器初始的设计理念
Q4
因为在某一个时钟周期内,可能某一个寄存器文件需要在 D 级和 W 级同时被使用(读写)时并且读和写的寄存器为同一个寄存器时,需要保证当读寄存器时的地址与同周期写寄存器的地址相同时,我们将读取的内容改为写寄存器的内容,而不是该地址可以索引到的寄存器文件中的值。
我们在设计GRF时保证其能同时进行读和写操作,并且对同一寄存器文件进行操作,以及将W级需要写入GRF的数据转发回GRF的写入数据端口,从而实现内部转发。
Q5
需求者:NPC模块,CMP模块,ALU模块,DM模块,GRF模块。
供给者:D级,E级,M级,W级流水线寄存器,GRF可看做最后一级流水线寄存器(其也可转发)
转发数据通路:
NPC_ReadData1 | CMP_ReadData1 | CMP_ReadData2 | ALU_A | ALU_B | DM_WriteData | GRF_WriteData |
---|---|---|---|---|---|---|
D E M W GRF | E M W | E M W | M W | M W | W | W |
Q6
算术/逻辑运算指令:
对ALU运算类型进行添加
对ALU模块的输入端口进行添加或修改
添加新的模块,如shift模块,完成移位操作
考虑是否需要增加转发数据传输指令:
需考虑寄存器与寄存器之间的数据传输,考虑是否要增加转发,以及其控制信号的设置
程序控制指令:
增加新的提前分支判断模块,为条件判断提供依据
添加新的NPC模块的输入端口来源
考虑是否需要增加转发浮点运算指令:
暂不考虑
Q7
译码方式:
集中式译码
译码器架构:
通过指令对应的控制信号的取值的方式,逐个对每一条指令编写其控制信号。译码器存放在D级,每一条指令进入D级,将指令输入译码器,产生控制信号,再将该控制信号输入E级流水级寄存器中,进入下一级(E级),在存入下一级流水级寄存器之前,对控制信号进行筛选,判断后面的流水级是否需要该控制信号,筛选出有需要的控制信号进行流水。
优势:
>
- 可以统一对指令的每一条控制信号进行管理,避免使用分布式译码导致控制信号分布在各流水级,导致控制信号的分散,不利于统一编写,导致遗漏。
- 资源利用率高,使用一个控制器(译码器)
不足:
相较于分布式译码,集中式译码的结构简洁性,项目维护性,代码可读性低,后者仅仅一个译码器,同时需要流水控制信号,结构不如每一流水级都有本流水级控制器简洁;后者需要检查每一级流水级寄存器的控制信号,来判断并修改该流水级所用控制信号,不利于维护;代码可读性差。