1. 分析指令集

  • 经过分类,指令共包含R型指令和I型指令
  • 列出其对应的32位机器码,寻找共性差异

R型指令:

Type Op Rs Rt Rd Shamt Func 解释
add 000000 (5) (5) (5) 00000 100000 相加(rs+rt->rd)
sub 000000 (5) (5) (5) 00000 100010 相减(rs-rt->rd)

I型指令:

Type Op Rs Rt Immediate 解释
ori 001101 (5) (5) (16) 或运算(rs|immediate->rt)
lui 001111 00000 (5) (16) 立即数加载至高16位({immediate||{16{1’b0}}}->rt)
Type Op Rs Rt Offset 解释
lw 100011 (5) (5) (16) 加载字(rs+offset在memory中data->rt)
sw 101011 (5) (5) (16) 保存字(rt->rs+offset在memory中的data)
beq 000100 (5) (5) (16) rs与rt相等则PC偏移offset*4

J型指令

type Op instr_index 解释
jal 000011 (26) 跳转至index并且PC+4 -> $ra
type Op rs 0 0 func 解释
jr 000000 (5) {10{1’b0}} {5{1’b0}} 001000 跳转至$rs中的地址

2. 阶段分析

alt text
F阶段PC值已经确定,进行的是根据PC访存相应的Instruction操作。此时指令已经确定好了
D阶段是将instruction转换成对应的操作数、产生控制信号。
E阶段是将操作数转换成计算结果。
M阶段是方寸数据内存。
W阶段是写入GRF。

3.命名规则

采用首字母大写命名法,每个单词首字母大写。

4. PC设计

端口设计:

方向 name 位宽
input PcOp [3:0]
input BeqPc [31:0]
input JalPc [31:0]
input JrPc [31:0]
input reset 1
input clk 1
output Pc_F [31:0]

转移设计:

PcOp 解释
0000 Pc_F <= Pc_F + 4
0001 Pc_F <= BeqPc
0010 Pc_F <= JalPc
0011 Pc_F <= JrPc

5. CU控制信号分析

端口设计:

type name 位宽 解释
input Op [5:0] 机器码高6位
input Func [5:0] 机器码低6位
output RegDst [1:0] GRF被写入寄存器是rt还是rd。0是rt,1是rd,10是$ra
output AluSrc [1:0] ALU第二个运算值是rt还是立即数。0是rt,1是立即数
output MemToReg [1:0] GRF写入值是ALUans还是DMans。0是ALUans,1是DMans,10是PC + 4
output RegWrite 1 是否写入GRF
output MemWrite 1 是否写入RAM
output PcSel [3:0] 当前指令是否是beq\jal\jr
output ExtOp [7:0] 扩展操作类型类型,详见Extender
output AluOp [7:0] ALU运算类型,详见ALU
output InstrType [7:0] 指令类型
output TNew_D [3:0] 从D级开始,经过多少周期该指令产生运算结果
output TUse1_D,TUse2_D [3:0] 从D级开始,经过多少周期要用到运算结果
  • 内部电路采用最小项表达式判断法,先判断Op,再判断Func

每种指令所需控制信号:

RegDst AluSrc MemToReg RegWrite MemWrite PcSel ExtOp AluOp TNew TUse1 TUse2
add 01 00 00 1 0 0000 ADD 2 1 1
sub 01 00 00 1 0 0000 SUB 2 1 1
ori 00 01 00 1 0 0000 0000 OR 2 1 10
lui 00 01 00 1 0 0000 0010 ADD 2 10 10
lw 00 01 01 1 0 0000 0001 ADD 3 1 10
sw 11 01 0 1 0000 0001 ADD 0 1 2
beq 11 00 0 0 0001 0011 EQUAL 0 0 0
jal 10 10 1 0 0010 0100 0 10 10
jr 11 00 0 0 0011 ADD 0 0 10

6. 流水线寄存器存储信息分析

F级:

name 位宽
Pc_F [31:0]
Instruction_F [31:0]

D级:

name 位宽
Pc_D [31:0]
RD1_D [31:0]
RD2_D [31:0]
WR_D [4:0]
ExtAns_D [31:0]
MemToReg_D [1:0]
RegWrite_D 1
AluSrc_D [1:0]
MemWrite_D 1
AluOp_D [7:0]
InstrType_D [7:0]
TNew_D [7:0]
Addr1_D [4:0]
Addr2_D [4:0]

E级:

name 位宽
Pc_E [31:0]
AluAns_E [31:0]
WR_E [4:0]
RD2_E [31:0]
MemToReg_E [1:0]
RegWrite_E 1
MemWrite_E 1
InstrType_E [7:0]
TNew_E [7:0]
Addr2_E [4:0]

M级:

name 位宽
Pc_M [31:0]
AluAns_M [31:0]
WR_M [4:0]
DmAns_M [31:0]
MemToReg_M 1
RegWrite_M 1
InstrType_M [7:0]
TNew_M [7:0]

W级:

name 位宽
Pc_W [31:0]
AluAns_W [31:0]
WR_W [4:0]
DmAns_W [31:0]
MemToReg_W [1:0]
RegWrite_W 1
InstrType_W [7:0]
TNew_W [7:0]

7. 流水线转发数据

E级:

instruction Data_E
add 0
sub 0
ori 0
lui 0
beq 0
jal Pc_E + 8
jr 0
lw 0
sw 0

M级:

instruction Data_M
add AluAns_M
sub AluAns_M
ori AluAns_M
lui AluAns_M
beq 0
jal Pc_M + 8
jr 0
lw 0
sw 0

W级:

instruction Data_W
add AluAns_W
sub AluAns_W
ori AluAns_W
lui AluAns_W
beq 0
jal Pc_W + 8
jr 0
lw DmAns_W
sw 0

8. 测试方案

1. 数据通路测试:先不考虑转发和阻塞,单纯检验数据通路是否正确,为了避免冒险情况,相邻两个指令之间间隔三个nop指令。

2. 转发阻塞测试:测试连续访存的指令,跳转指令,与MARS行为对应。

9. 思考题

  1. 原因:我们跳转指令的判断在D级进行,但实际上是在D级的最后进行的。在此之前,我们需要完成指令译码、产生控制信号、阻塞判断、GRF读取、转发判断等操作,之后再依据跳转指令类型决定后续操作(beq:判断两个寄存器值是否相等;jal:立即数位扩展;jr:$rs寄存器的值)。这些前置步骤会消耗一定的时间,导致最后剩余给跳转判断的时间很紧张,容易产生数据冒险,使跳转判断不准确,因此并非总能提高效率。并且由于在D级就要使用数据,所以Tuse=0,这使得如果要使用的数据还未被算出,则要阻塞很长时间,导致指令效率下降。
    例子:
1
2
3
4
5
lui $t0 1
sw $t0 0($0)
lw $t1 0($0)
beq $t1 $0 label
label:
  1. 因为jal本意是PC跳转到标签处,并把当前指令的下一条要执行的指令存入$ra,当没有延迟槽的时候,当前指令的下一条指令就是PC + 4。而有延迟槽时,jal指令并不会立即跳转,而是会先执行PC + 4这条指令再跳转,因此真正的下一条要执行的指令是PC + 8。这样可以多执行一条指令,又不耽误之后的指令执行,提高指令执行效率。
  2. 因为功能部件产生转发数据是需要时间的,如果我们使用功能部件产生的数据转发,那么之后我们还要用转发的数据再进行一些操作,这些操作挤占在一个时钟周期内反而会降低效率。如果我们使用流水寄存器的数据,我们可以在周期刚开始就获得转发数据,从而有充足的时间去进行后续操作。
  3. 因为W级的数据会写入GRF,同时D级数据也会读取GRF。如果被写入数据和被读取数据是同一个,那么被读取的数据应该是写入的结果而不是原来的结果。此时可以用GRF内部转发解决问题。实现方式为:判断该寄存器是不是$0,如果是则为0,如果不是,判断写入寄存器和读取寄存器是否是同一个,如果是,则读取写入结果,否则读取原来寄存器的值。
  4. 转发数据的需求者可能来自于D,E,M级,转发供给者可能来自于E,M,W级。转发数据通路有:D级接受E,M,W级的转发,E级接受M,W的转发,M级接受W级的转发。
  5. 可能扩展ALU的运算类型,控制信号的类型,寄存器传递的控制信号的种类,阻塞条件等。
  6. 我采用集中式译码器,在D级集中产生控制信号,并随着流水线传递控制信号。这种架构的好处是只需要一个译码器,只需要产生一次控制信号,进行一次状态判断。不足之处是流水线寄存器需要传递较多控制信号,操作量比较大,且修改需要一并修改后面的流水线寄存器。
  7. 测试方案分为数据通路测试和转发阻塞测试。数据通路测试不涉及转发阻塞,单纯用来检测每一条指令能否正常执行,为了避免产生冒险,在编写测试代码的时候,相邻指令之间要相隔3-4个nop指令。测试转发和阻塞数据时,主要针对冒险情况来编写代码,可以列举哪些指令相邻出现需要转发或者阻塞,然后抽样测试,与MARS行为进行对照。