CO_P6
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 |
And | 000000 | Rs | Rt | Rd | 00000 | 100100 |
Or | 000000 | Rs | Rt | Rd | 00000 | 100101 |
Mult | 000000 | Rs | Rt | 00000 | 00000 | 011000 |
Multu | 000000 | Rs | Rt | 00000 | 00000 | 011001 |
Div | 000000 | Rs | Rt | 00000 | 00000 | 011010 |
Divu | 000000 | Rs | Rt | 00000 | 00000 | 011011 |
Mfhi | 000000 | 00000 | 00000 | Rd | 00000 | 010000 |
Mflo | 000000 | 00000 | 00000 | Rd | 00000 | 010010 |
Mthi | 000000 | Rs | 00000 | 00000 | 00000 | 010001 |
Mtlo | 000000 | Rs | 00000 | 00000 | 00000 | 010011 |
Slt | 000000 | 00000 | Rt | Rd | 00000 | 101010 |
Sltu | 000000 | 00000 | Rt | Rd | 00000 | 101011 |
Jr | 000000 | Rs | 00000 | 00000 | 00000 | 001000 |
add:
sub:
and:
or:
mult:有符号数
multu:无符号数
div:
divu:
mfhi:
mflo:
mthi:
mtlo:
slt:
sltu:
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 |
Addi | 001000 | Rs | Rt | imm16 |
Andi | 001100 | Rs | Rt | imm16 |
Lb | 100000 | Base | Rt | offset_16 |
Lh | 100001 | Base | Rt | offset_16 |
Lw | 100011 | Rs | Rt | imm16 |
Sb | 101000 | Base | Rt | offset_16 |
Sh | 101001 | Base | Rt | offset_16 |
Sw | 101011 | Rs | Rt | imm16 |
Beq | 000100 | Rs | Rt | imm16 |
Bne | 000101 | Rs | Rt | offset_16 |
ori:
lui:
addi:
andi:
lb:
lh:
lw:
sb:
sh:
sw:
beq:
bne:
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 | lui $t0,7434 |
- Mars导出的机械码(储存在code.txt中的文件):
1 | 3c081d0a |
利用$readmemh指令读取code.txt中的机械码指令并储存在IFU_mips模块的指令存储器im_reg(4096个32位寄存器)当中,运行mips顶层模块,通过$display指令检测存入寄存器堆(GRF)和数据存储器(DM)时的pc地址,相应数据以及存入的寄存器或数据存储器地址,将结果与Mars对拍运行时的数据做比对,以此检测Verilog代码编写的单周期CPU是否正确。
五、思考题
Q1
因为进行乘法和除法运算时存在延迟,而其他运算方式在一个周期内即可完成运算,所有独立出一个乘除法部件使其他运算(乘除运算外)不受乘除运算的影响。
在进行乘除法运算时,其他运算并行运行,当乘除法运算结束后,将计算结果存入HI,LO寄存器即可,之后通过mfhi,mflo指令将HI,LO寄存器中的值取出。故使用独立的HI,LO寄存器是为了存储乘除法运算的结果,并方便取出计算结果。
Q2
在流水线 CPU 中,乘法运算和除法运算的执行是分为几个阶段的。对于乘法运算,至少需要3个阶段:取数、乘法和回写结果。在取数阶段,CPU 从内存中读取两个操作数。在乘法阶段,CPU 执行乘法运算,并将结果存储在一个临时寄存器中。最后,在回写结果阶段,CPU 将临时寄存器中的结果写入目标寄存器中,除法指令类似。
在执行乘除法运算时,CPU 需要遵循特定的指令序列。这些指令序列是预先定义好的,用于控制 CPU 的操作和时序。
CPU 还需要遵循特定的时序规则。这些规则规定了每个阶段的时间长度和操作顺序。例如,取数阶段必须在乘法阶段之前完成,除法阶段必须在回写结果阶段之前完成。
真实的流水线 CPU 是通过多个阶段的协同工作和遵循特定的指令序列和时序规则来实现乘除法运算的。
Q3
当E级为乘除法运算时,Start信号置一,一时钟周期后,Start信号复位,Busy信号根据乘除法运算维持一定周期的高位。
通过计数值cnt的方式来,对于乘法运算,当Start信号处于高位时,将D1,D2,MDOper(运算类型)存入临时变量,同时在下一周期满足条件时,将Busy信号置一,同时赋值cnt为5,同时将计算结果(利用D1,D2,MDOPer的临时变量)存入HI,LO临时变量中,在接下来的时钟周期中,若cnt不为1,则进行自减一,若为1,则将cnt置为0,同时将HI,LO临时寄存器的值存入HI,LO寄存器当中,从而完成周期阻塞。
1 | always @(*) begin |
Q4
清晰性:这种处理方式可以直接从信号(二进制)中看出写入数据存储器中的数据位置,并方便为不同写入DM的指令编码写入数据存储器的使能信号。
统一性:每种写入DM的指令都可使用这种使能信号的编码方式。
Q5
不是
当只写入一字节的数据或者读出一字节的数据时
Q6
模块化,将各个功能部件聚合成一个模块,简化每一个模块的复杂度,尽量使他们彼此独立
使用独立译码器,将指令分析和模块的功能分离,让模块只受译码器给出的信号的控制。
wire型数据统一申明
译码器:使用指令驱动型的译码器,利用宏定义的方式命名控制信号,并对相似指令的控制信号进行统一赋值,并将控制信号统一输出。
模块化和使用独立译码后,只要在进入模块前选择其所要使用的控制信号以及数据即可。例如通过转发以及选择信号控制输入数据,仅需判断当前模块所要考虑的数据冲突。
命名方式:使用关键词以及下划线分隔符的方式选择信号,方便进行模块前的输入信号的辨识判断。
Q7
需向寄存器数据类型的指令与需读出寄存器数据类型的指令之间的冲突,例如add,sub,and,or,mult,multu,div,divu,slt,sltbeq,bne指令需要读出Rs,Rt对应寄存器的数据,mtlo,mthi,jr,sw,sh,sb,ori,lui,andi等需要读出Rs对应寄存器的数据,当lw,lh,lb,jal,运算类型,slt,slt(置位),jal等类型的指令未写入寄存器当中时,其会发生数据冲突。
利用转发和暂停来控制冒险冲突
测试样例:
1 | lui $t0,7434 |
Q8
手动构造:
编写各种类型指令对应的代码,控制利用寄存器的类型,之后将上述代码随机组合。
随机产生的测试程序的不足之处:其并不能确保包含所有冲突与冒险类型,存在缺漏,需要保证数据量足够大,尽可能的覆盖。