RooKie_Z P6 Verilog流水线CPU设计文档

RooKie_Z P6 Verilog流水线CPU设计文档

写在前面

这是RooKie_Z的P6流水线CPU设计文档,在课上测试中本CPU取得了 满分💯的成绩。

总体设计概述

本次要求实现的指令集为add, sub, and, or, slt, sltu, lui,addi, andi, ori,lb, lh, lw, sb, sh, sw,mult, multu, div, divu, mfhi, mflo, mthi, mtlo,beq, bne, jal, jr,可以看到,除了一部分位移指令和异常相关的指令,指令集内各类型指令均有覆盖。由于P5架构较为完备,大部分指令已于P5课下实现,故本次设计仅添加乘除单元MDU,并结合课程组所给tb对数据通路稍作修改,并未进行大的重构。

数据通路

添加转发后的数据通路


关键模块介绍

总体而言,在总体架构不作大的修改的前提下,修改了一部分控制信号,同时添加了流水线各级寄存器和虚拟的阻塞控制单元,对于每一级流水线都设计了相应的译码器。

命名规则

  • 对于各模块文件,均采用对于元件的文件命名,均为流水线层级_元件英文简称,例如D_GRF.vE_ALU.v等,实例化时命名为大写首字母小写英文名,例如AluGrf
  • 对于流水线寄存器文件命名为两边的流水线层级_REG,例如FD_REG.vDE_REG.v,实例化时命名为大写英文层级,例如FD
  • 每一级的控制信号和临时的wire均以本级的名称开头,如E_ALUOpM_DMOp
  • 在流水线中参与流水的信息遵从以下约定(以D级为例)
    • PCInstr命名以流水线层级开头,如D_PCD_Instr
    • 寄存器地址分别为D_rs_addrD_rt_addr,读出数据为D_rsD_rt
    • 转发得到的寄存器数据(直接读取也视为一种转发)记作D_FWD_rs_dataD_FWD_rt_data
    • 即将写入的寄存器地址为E_A3,即将写入的数据记作E_WD,选择信号为E_WDSel

F级(取指)

PC(程序计数器)

信号名称 方向 功能描述
NPC[31:0] I 待写入PC的指令地址
clk I 时钟信号
reset I 同步复位信号
PC_WE I PC的写使能
PC O 当前指令地址

然后与mips_txt.v交互获得当前指令

1
2
3
4
5
6
7
8
9
10
11
12
F_PC _pc(
.clk(clk),
.reset(reset),

.PC_WE(PC_WE),
.NPC(NPC),

.PC(F_PC)
);

assign i_inst_addr = F_PC;
assign F_Instr = i_inst_rdata;

FD_REG(F/D级流水线寄存器)

信号名称 方向 功能描述
clk I 时钟信号
reset I 同步复位信号
flush I 寄存器刷新信号(阻塞时使用)
F_PC I F级PC的指令地址
F_Instr[31:0] I 时钟信号
D_PC O D级PC的指令地址
D_Instr[31:0] O 32位的指令值

D级(译码)

  • 本级需要处理来自E, M, W级的转发,其中W级为寄存器内部转发,另外两个分别是D_FWD_rs,D_FWD_rt,在CMPNPC中需要用
  • 本级的输入是来自F级的PCInstr,输出是D_rsD_rtD_Ext_OutD_PCD_Instr,这些参与流水,还有输出到F级的NPC
  • 本级元件较多,是最复杂的一级

D_GRF

端口说明
信号名称 方向 功能描述
A1[4:0] I 5位地址输入信号,将其储存的数据读出到RD1
A2[4:0] I 5位地址输入信号,将其储存的数据读出到RD2
A3[4:0] I 5位地址输入信号,将其作为写入数据的目标寄存器
RD1[31:0] O 输出A1指定的寄存器中的32位数据
RD2[31:0] O 输出A2指定的寄存器中的32位数据
WD[31:0] I 32位数据输入信号
clk I 时钟信号
reset I 同步复位信号,将32个寄存器中的数据清零;1:复位;0:无效
  • 这次删去了WE写使能信号,因为如果我们不写寄存器,可以把A3设为0,就相当于不写寄存器了

Ps :这是我灵光一现想到的办法,受了P4课上访存指令的启发,如果有指令要在读出之后针对数据判断是否写入GRF,那么WE信号不仅要一直参与流水,还要用于控制每级的转发与阻塞,利用0寄存器的特点就可以规避这一切的麻烦!!!

控制信号说明

1. D_A3

直接给出待写入寄存器的地址,弃用了在P4中利用A3Sel进行选择的设计,这是因为P5采用分布式译码,每一级都需要A3的信息,因此在CTRL里面直接集成了

2. D_WDSel

控制信号值 功能
WDSel_DMout 选择写入寄存器的数据来自DM
WDSel_ALUout 选择写入寄存器的数据来自ALU运算结果
WDSel_PC8 选择写入寄存器的数据为当前流水线层级中的PC+8

D_EXT

16位二进制数进行零扩展符号扩展到32位

控制信号说明
控制信号值 功能
EXT_unsigned 零扩展
EXT_signed 符号扩展

D_CMP(分支比较)

参考P3中CPU内BranchDefine子电路生成的CMP模块,来生成jump信号,判断分支是否跳转,link是否写入

目前实现了beq, bne, bgtz, bltz等指令

代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
`timescale 1ns / 1ps
`include "signal_def.v"

module CMP(
input [31:0] rs,
input [31:0] rt,
input [2:0] CMPOp,
output reg jump
);

wire eq = (rs == rt);
wire ne = !eq;
wire ltz = ($signed(rs) < 0);
wire gtz = ($signed(rs) > 0);
wire eqz = (rs == 0);

always @(*) begin
case (CMPOp)
`CMP_beq: begin
jump = eq ? 1 : 0;
end
`CMP_bne: begin
jump = ne ? 1 : 0;
end
`CMP_bltz: begin
jump = ltz ? 1 : 0;
end
`CMP_bgtz: begin
jump = gtz ? 1 : 0;
end
default: jump = 1'b0;
endcase
end
endmodule

端口说明
端口名称 方向 功能描述
rs[31:0] I 转发后$rs寄存器的值
rt[31:0] I 转发后$rt寄存器的值
CMPOp[2:0] I 控制信号
jump O 指示分支是否跳转

D_NPC(次地址计算)

有了CMP之后,NPC的功能也更加简洁,只需根据NPCOpjump信号输出NPC信号的值就行

实际上NPC横跨了F级和D级两级,因为同时会输入F_PCD_PC,前者正常跳转F_PC+4用,后者则用于流水PC值,后面转发PC+8的时候用

这次我们弃用了P4中直接输出PC+4的设计,转而让PC信号参与流水,在需要转发时计算PC+8

端口说明
端口名称 方向 功能描述
F_PC[31:0] I 32位输入当前F级地址
D_PC[31:0] I 32位输入当前D级地址
imm[31:0] I 32位立即数
jump I 指示b类型指令是否跳转
NPCOp[2:0] I 控制信号
RD1_rs[31:0] I $ra寄存器保存的32位地址
NPC[31:0] O 32位输出次地址
控制信号说明
控制信号值 功能
NPC_pc4 NPC = F_PC+4
NPC_b 执行beq等b类指令
NPC_jal 执行jjal指令
NPC_jalr 执行jalrjr指令

DE_REG(D/E级流水线寄存器)

  • 输入D_PC,D_Instr,D_Ext_Out,此外上一级的$rs$rt的值也要参与流水,即D_FWD_rs,D_FWD_rt需要参与流水,这是由于指令序列sw, nop, add的存在,sw在M级需要使用$rt的数据,但是在E级不会再进行转发(因为在D级已经转发过了),因此需要让正确的$rt值参与流水

  • 输出E_PC,E_Instr,E_Ext_Out,E_rs,E_rtALU需要这些信息

信号名称 方向 功能描述
clk I 时钟信号
reset I 同步复位信号
flush I 寄存器刷新信号(阻塞时使用)
D_PC[31:0] I D级PC的指令地址
D_Instr[31:0] I 32位的指令值
D_Ext_Out[31:0] I 16位立即数经EXT扩展的结果
D_rs[31:0] I 32位的寄存器数据
D_rt[31:0] I 32位的寄存器数据
E_PC[31:0] O E级PC的指令地址
E_Instr[31:0] O 32位的指令值
E_Ext_Out[31:0] O 16位立即数经EXT扩展的结果
E_rs[31:0] O 32位的寄存器数据
E_rt[31:0] O 32位的寄存器数据

E_ALU

  • 相比于P4,ALU做了很大的变动,添加了ALUSrcA信号选择A运算数的来源,这是为了便于扩展sllsllv类指令的原因取消了shamt信号,shamt信号从ALUSrcB中选择进入ALU
端口说明
信号名称 方向 功能描述
A[31:0] I 32位输入运算数A
B[31:0] I 32位输入运算数B
ALUOp[4:0] I 控制信号
ALUOut[31:0] O 32位输出运算结果
控制信号说明
1. ALUOp

具体见代码,已实现绝大多数计算功能。

控制信号值 功能
ALU_add 执行加法运算
ALU_sub 执行减法运算
ALU_or 执行逻辑或运算
ALU_lui 执行lui指令
2. ALUSrcA
控制信号值 功能
SrcA_rt 对于sllsllv等移位指令,选择$rt的值
SrcA_rs 对于其他大部分运算指令,采用 $rs的值
3. ALUSrcB
控制信号值 功能
SrcB_rt 选择处理完转发后$rt寄存器中的值进行运算
SrcB_imm 选择立即数进行运算
SrcB_shamt 使用{27'b0, E_ALUshamt}得到32为扩展移位数
SrcB_rs 考虑到sllv指令要求可变的位移数,这里可以选择{27'b0, E_FWD_rs_data[4:0]},即$rs寄存器中的数据作为移位数

E_MDU(乘除单元)

端口说明
信号名称 方向 功能描述
clk I 时钟信号
reset I 复位信号
MDUOp[2:0] I 控制信号
D1[31:0] I 32位输入运算数A
D1[31:0] I 32位输入运算数B
Start I 开始运算的指示信号
Busy O 是否处于运算过程中
HI[31:0] O 32位HI寄存器值结果
LO[31:0] O 32位LO寄存器值结果
控制信号说明
1. MDUOp
控制信号值 功能
MDU_mult 乘法运算
MDU_div 除法运算
MDU_multu 无符号乘法运算
MDU_divu 无符号除法运算
MDU_mfhi mfhi指令
MDU_mflo mflo指令
MDU_mthi mthi指令,把D1的值赋给HI寄存器中
MDU_mtlo mtlo指令,把D1的值赋给LO寄存器中

EM_REG(E/M级流水线寄存器)

信号名称 方向 功能描述
clk I 时钟信号
reset I 同步复位信号
flush I 寄存器刷新信号(阻塞时使用)
E_PC[31:0] I E级PC的指令地址
E_Instr[31:0] I 32位的指令值
E_Ext_Out[31:0] I 16位立即数经EXT扩展的结果
E_rt[31:0] I 32位的寄存器数据
E_ALU_Out[31:0] I 32位的ALU运算结果
E_MDU_Out[31:0] I 32位的MDU运算结果
M_PC[31:0] O M级PC的指令地址
M_Instr[31:0] O 32位的指令值
M_Ext_Out[31:0] O 16位立即数经EXT扩展的结果
M_ALU_Out[31:0] O 32位的ALU运算结果
M_MDU_Out[31:0] O 32位的MDU运算结果
M_rt[31:0] O 32位的寄存器数据

M级(储存)

  • 输入E_PC,E_Instr,此外上一级的ALUOut参与流水,即E_ALU_Out,E_Ext_Out需要参与流水,这是因为ALUOut可能是待写入或读取的内存地址另外,上一级的rt值需要参与流水,因此还需要输入E_FWD_rt这是因为sw指令会向内存中写入$rt的数据
  • 输出M_PC,M_Instr,M_ALU_Out,M_DM_Out,M_MDU_Out

M_DM(数据储存器)

  • DM已经不需要自行实现,调用mips_txt.v中的接口即可

  • 利用BE模块处理待写入数据,使其支持按半字、字节、字储存

  • 利用DE模块处理DM返回的数据,使其可以按照不同要求存入寄存器

M_BE
信号名称 方向 功能描述
BEOp[1:0] 输入 控制信号
Addr[31:0] 输入 地址信息,用于处理半字、字节
rt_data[31:0] 输入 读取的寄存器数据,待处理
DMWr 输入 写使能
m_data_byteen[3:0] 输出 控制写入半字、字节的位置位置
m_data_wdata[31:0] 输出 待写入数据
M_DE
信号名称 方向 功能描述
DEOp[1:0] 输入 控制信号
Addr[31:0] 输入 地址信息,用于处理半字、字节
m_data_rdata[31:0] 输入 mips_txt.v返回的DM中的数据
DMout[31:0] 输出 处理之后的正确的读取数据
与接口进行交互
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 与DM交互
M_BE _be(
.BEOp(M_BEOp),
.Addr(M_ALU_Out),
.WD(M_FWD_rt_data),
.m_data_byteen(m_data_byteen),
.m_data_wdata(m_data_wdata)
);

assign m_inst_addr = M_PC;
assign m_data_addr = M_ALU_OUt;

wire [31:0] M_DM_Out;
M_DE _de(
.DEOp(M_DEOp),
.Addr(M_ALU_Out),
.m_data_rdata(m_data_rdata),
.DMRD(M_DM_out)
);

// 正确输出GRF读写信息
assign w_grf_addr = W_A3;
assign w_grf_wdata = W_WD;
assign w_grf_we = W_GRFWE;
assign w_inst_addr = W_PC;

W级(回写)

MW_REG(M/W级流水线寄存器)

信号名称 方向 功能描述
clk I 时钟信号
reset I 同步复位信号
flush I 寄存器刷新信号(阻塞时使用)
M_PC[31:0] I M级PC的指令地址
M_Instr[31:0] I 32位的指令值
M_DM_Out[31:0] I 从内存中读取的值
M_ALU_Out[31:0] I 32位的ALU运算结果
W_PC[31:0] O W级PC的指令地址
W_Instr[31:0] O 32位的指令值
W_DM_Out[31:0] O 从内存中读取的值
W_ALU_Out[31:0] O 32位的ALU运算结果

数据通路分析

指令 opcode funct NPCOp A3Sel WDSel EXTOp GRFWE ALUSRCB ALUOp DMWr DMOp
add 000000 100000 NPC_PC4 A3Sel_rd WDSel_ALUout X 1 SrcB_rt ALU_add 0 X
sub 000000 100010 NPC_PC4 A3Sel_rd WDSel_ALUout X 1 SrcB_rt ALU_sub 0 X
ori 001101 X NPC_PC4 A3Sel_rt WDSel_ALUout EXT_unsigned 1 SrcB_imm ALU_or 0 X
lw 100011 X NPC_PC4 A3Sel_rt WDSel_DMout EXT_signed 1 SrcB_imm ALU_add 0 DM_w
sw 101011 X NPC_PC4 X WDSel_DMout EXT_signed 0 SrcB_imm ALU_add 1 DM_w
beq 000100 X NPC_branch X X X 0 X X 0 X
lui 001111 X NPC_PC4 A3Sel_rt WDSel_ALUout X 1 SrcB_imm ALU_lui 0 X
jal 000011 X NPC_jal A3Sel_ra WDSel_PC8 X 1 X X 0 X
jr 000000 001000 NPC_jalr X X X 0 X X X X

本CPU采用分布式译码,在每一级均设有译码器,解码出各级所需信息


冲突处理方法

转发(Forwarding)

对于转发,我们直接采用 AT 法 + 暴力转发,首先要搞明白转发到哪,转发什么。 对于每一个流水线层级,我们要能够确定当前这一级正在执行的指令要写什么数据,向哪里写,因此就要维护 GRFWD (解决转发啥)和 GRFA3 (解决转发到哪)这两个值,我们转发需要去关注的也就是这两个数据,这些信号都可以从 Control 里面译码读出来 简单来说就是,我们需要在每一级都知道本级需要从哪读数据,要写到哪,要写啥,现在不知道没事,总之在这条指令从流水线消失之前,我们肯定知道,并且可以根据这些再经过判断做转发。

在每一个需要用转发数据的地方,我们去比较要用的数据的 GPR 地址和前面正在维护的要写的 GRFA3 的地址,如果相同,那就意味着我们要写的寄存器已经被用了,但是这时前面获得的值显然是错误的,这时候直接转发过去就好了

这里还要考虑优先级的问题,流水线寄存器生成的WD越靠近这条指令,得到的数据就越新,我们就越倾向于优先使用这些数据

利用 AT 法,如果不阻塞就意味着一定能够在使用该寄存器的值之前获得正确的值,如果我们要用的时候,这个正确的值还没有算出来,那肯定不行,这时候我们就阻塞,如果能算出来,那么之前转发的错误的值不用去管它,最后总能得到一个正确的值去覆盖原先错误的值

如果我们还不知道要写的值是啥,那这个时候 GRFA3 就给正确的地址, GRFWD 就给 32'bz ,这时还不能做转发,但是如果写的阻塞模块正确,这个值就不可能被转发,因为这种情况如果出现就已经被阻塞在 D 级了

综合考量各种指令序列,我们得到了转发的旁路:

  1. D级需求: E->D(如序列jal-add), M->D(如序列jal-nop-add)(W->D隐藏于GRF的内部转发中);
  2. E级需求: M->E(如序列add-add), W->E(如序列add-nop-add)
  3. M级需求: W->M(如序列add-sw)

具体设计见前文图片

代码实现

W to D:

1
2
3
4
5
// 寄存器内部转发
assign RD1 = (A1 == 5'b00000) ? 32'h0000_0000 :
(A3 == A1 && A1 != 5'b00000) ? WD : grf[A1];
assign RD2 = (A2 == 5'b00000) ? 32'h0000_0000 :
(A3 == A2 && A2 != 5'b00000) ? WD : grf[A2];

D级转发处理

1
2
3
4
5
6
7
8
9
10
//D级写回数据
assign D_FWD_rs_data = (D_rs_addr == 0) ? 0 :
(D_rs_addr == E_A3) ? E_WD :
(D_rs_addr == M_A3) ? M_WD :
D_rs;

assign D_FWD_rt_data = (D_rt_addr == 0) ? 0 :
(D_rt_addr == E_A3) ? E_WD :
(D_rt_addr == M_A3) ? M_WD :
D_rt;

E级转发处理

1
2
3
4
5
6
7
8
9
10
//转发
assign E_FWD_rs_data = (E_rs_addr == 0) ? 0 :
(E_rs_addr == M_A3) ? M_WD :
(E_rs_addr == W_A3) ? W_WD :
E_rs;

assign E_FWD_rt_data = (E_rt_addr == 0) ? 0 :
(E_rt_addr == M_A3) ? M_WD :
(E_rt_addr == W_A3) ? W_WD :
E_rt;

M级转发处理

1
2
3
4
5
6
7
8
//转发
assign M_FWD_rt_data = (M_rt_addr == 0) ? 0 :
(M_rt_addr == W_A3) ? W_WD :
M_rt;

assign M_WD = (M_WDSel == `WDSel_PC8) ? M_PC + 8 :
(M_WDSel == `WDSel_ALUout) ? M_ALU_Out :
32'bz;

阻塞(Stall)

对于阻塞的处理,直接采用教程中的AT方法,设计一个 Stall 模块,专门负责处理阻塞时流水线寄存器的 flushWE 信号就行

只在 D 级进行阻塞,阻塞控制器接受当前 D,E,M 级的指令输入,处理分析指令类别,算出当前D的Tuse,和E、M的Tnew,再进行相应的计算

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//阻塞逻辑

wire E_stall_rs = ((E_A3 == D_rs_ad) && (D_rs_ad != 0)) && (E_Tnew > D_Tuse_rs);
wire E_stall_rt = ((E_A3 == D_rt_ad) && (D_rt_ad != 0)) && (E_Tnew > D_Tuse_rt);

wire M_stall_rs = ((M_A3 == D_rs_ad) && (D_rs_ad != 0)) && (M_Tnew > D_Tuse_rs);
wire M_stall_rt = ((M_A3 == D_rt_ad) && (D_rt_ad != 0)) && (M_Tnew > D_Tuse_rt);

assign Stall = E_stall_rs | E_stall_rt | M_stall_rs | M_stall_rt;



//清空当前指令信号,即插入nop
wire FD_Flush, DE_Flush, EM_Flush, MW_Flush;

assign FD_WE = !Stall; //不再进新指令
assign DE_WE = 1'b1;
assign EM_WE = 1'b1;
assign MW_WE = 1'b1;

assign PC_WE = !Stall;

assign FD_Flush = 1'b0;
assign DE_Flush = Stall; //阻塞到D级,清空DE寄存器
assign EM_Flush = 1'b0;
assign MW_Flush = 1'b0;

测试方案

指令集:add, sub, and, or, slt, sltu, lui, addi, andi, ori, lb, lh, lw, sb, sh, sw, mult, multu, div, divu, mfhi, mflo, mthi, mtlo, beq, bne, jal, jr

测试目标

  • 单计算指令行为
  • 单存取指令行为
  • 单跳转指令行为
  • 计算/存取指令数据冲突阻塞转发行为
  • 跳转指令与计算/存取指令数据冲突阻塞转发行为
  • 新增存储指令行为
  • 单指令乘除指令行为以及 Busy 信号表现
  • 乘除指令阻塞行为
  • 计算指令/乘除指令的数据冲突阻塞转发行为

具体实现分为两部分

功能性测试

采用课下提供的P6_L0_weak.txt测试每条指令的功能,对于未进行测试的指令,进行手动测试

首先在P5的测试工具基础上进行简单的修改,由于指令类型相似,因此仅在P5的基础上添加了mfhi,mflo,mthi,mtlo,div,divu,mult,multu指令然后进行大范围的随机生成测试

我的测试方法是利用随机生成数据进行大范围测试,对于随机数据无法覆盖的点,通过手动构造特殊样例进行测试

对于更多情况,手动构造数据处理

单条指令功能测试:

ori测试:

1
2
3
4
ori $t0, $t0, 1
ori $t1, $t1, 0
ori $t3, $t3, 0x7fff
ori $t4, $t3, 0xffff

add测试:

1
2
3
4
ori $t0, $t0, 2
ori $t1, $t1, 0xffff
add $t2, $t0, $t0
add $t3, $t1, $t1

sub测试:

1
2
3
4
5
6
ori $t0, $t0, 2
ori $t1, $t1, 0xffff
sub $t2, $t0, $t0
sub $t3, $t1, $t1
sub $t4, $t1, $t0
sub $t4, $t0, $t1

lui测试:

1
2
lui $t0, 0x7fff
ori $t0, $t0, 0x777f

beq测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#三次跳转
ori $t3, $t4, 1
beq $3, $t0, A
ori $t1, $t1, 0xffff
A:
beq $0, $t0, B
lui $t1, 0xffff
C:
ori $t1, $t1, 1
lui $t0, 1
B:
beq $t0, $0, C
lui $t2, 0xffff
//后跳
beq $t3, $t0, A
ori $t1, $t1, 0xffff
ori $t2, $t2, 0xffff
A:
lui $t1, 0xffff
//不跳
beq $3, $t0, A
nop
A:
beq $0, $t0, B
nop
C:
lui $t0, 1
B:
beq $t0, $0, C
nop
//前跳
beq $3, $t0, A
nop
B:
lui $t0, 1
A:
beq $0, $t0, B
nop

j,jal,jr测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
jal A
ori $s1, $s1, 0x1111
add $ra, $ra, $t2
ori $s1, $s1, 0x2222
A:
lui $t1, 200

jal A
ori $t0, $t0, 0x1111
sub $t1, $t1, $t0
ori $t2, $t2, 0x1111
beq $t2, $t2, B
nop
A:
jr $ra
add $t3, $t0, $t0
B:

sw,lw测试:

1
2
3
4
5
6
7
8
9
ori $t0, $t0, 4 #t0 = 4
add $t1, $t0, $t0 # t1 = 8
sub $t2, $t0, $t1 # t2 = -4
add $t3, $t2, $t2 #t3 = -8
sub $t4, $t0, $t3 #t4 = c
sw $t4, 16($t4) # add = 1c
sw $t3, -4($t1) # add = 4
lw $t5, 16($t4)
lw $t6, -4($t1)

之后对于各种边界情况和转发阻塞情况,进行覆盖测试:

提供一组超强测样例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
.text
init_1:j init_44
lui $0, 58479
init_2:j init_61
lui $26, 40699
init_3:nop
j init_26
ori $29, 12340
init_4:j init_21
lui $9, 18793
init_5:nop
j init_9
ori $13, 19610
init_6:j init_38
ori $28, 17819
init_7:nop
j init_37
ori $27, 17810
init_8:j init_48
ori $14, 1324
init_9:j init_8
lui $14, 20958
init_10:j init_31
lui $4, 28505
init_11:nop
j init_13
ori $23, 24263
init_12:j init_16
ori $12, 2525
init_13:j init_62
lui $24, 49213
init_14:j init_59
ori $6, 27235
init_15:j init_52
ori $16, 28030
init_16:j init_5
lui $13, 39021
init_17:j init_23
lui $20, 45636
init_18:nop
j init_57
ori $7, 34738
init_19:j init_56
lui $22, 48232
init_20:j init_7
lui $27, 21269
init_21:nop
j init_24
ori $9, 60940
init_22:j init_47
lui $19, 24579
init_23:j init_53
ori $20, 23617
init_24:j init_27
lui $10, 4700
init_25:nop
j init_60
ori $5, 25135
init_26:j init_34
lui $30, 14559
init_27:j init_29
ori $10, 45253
init_28:j init_12
lui $12, 55820
init_29:j init_36
lui $11, 49875
init_30:j init_25
lui $5, 35220
init_31:j init_30
ori $4, 7615
init_32:j begin
lui $31, 60984
init_33:j init_43
ori $2, 18084
init_34:j init_63
ori $30, 41019
init_35:j init_15
lui $16, 54272
init_36:nop
j init_28
ori $11, 2111
init_37:j init_6
lui $28, 33755
init_38:j init_3
lui $29, 26291
init_39:nop
j init_2
ori $25, 48740
init_40:j init_42
lui $1, 43965
init_41:nop
j init_19
ori $21, 27953
init_42:nop
j init_50
ori $1, 18337
init_43:j init_54
lui $3, 36555
init_44:j init_40
ori $0, 39840
init_45:j init_22
ori $18, 28396
init_46:j init_4
ori $8, 13173
init_47:nop
j init_17
ori $19, 60189
init_48:j init_49
lui $15, 28446
init_49:nop
j init_35
ori $15, 43996
init_50:j init_33
lui $2, 50534
init_51:j init_45
lui $18, 47692
init_52:j init_58
lui $17, 18098
init_53:j init_41
lui $21, 23125
init_54:nop
j init_10
ori $3, 34935
init_55:j init_39
lui $25, 37200
init_56:j init_64
ori $22, 41245
init_57:j init_46
lui $8, 16690
init_58:nop
j init_51
ori $17, 23659
init_59:j init_18
lui $7, 16431
init_60:j init_14
lui $6, 20586
init_61:j init_20
ori $26, 21724
init_62:j init_55
ori $24, 64211
init_63:j init_32
lui $31, 32491
init_64:j init_11
lui $23, 36591
begin:
ori $11, $11, 39941
sw $11, 0($0)
ori $22, $22, 13378
nop
sw $22, 4($0)
addu $8, $31, $16
nop
nop
sw $8, 8($0)
subu $20, $16, $6
sw $20, 12($0)
addu $9, $15, $7
nop
sw $9, 16($0)
addu $19, $23, $27
nop
nop
sw $19, 20($0)
subu $5, $1, $31
sw $5, 24($0)
addu $22, $6, $26
nop
sw $22, 28($0)
addu $10, $4, $18
nop
nop
sw $10, 32($0)
subu $19, $3, $0
sw $19, 36($0)
subu $22, $24, $1
nop
sw $22, 40($0)
subu $19, $10, $14
nop
nop
sw $19, 44($0)
subu $0, $19, $15
sw $0, 48($0)
ori $21, $21, 728
nop
sw $21, 52($0)
subu $13, $29, $4
nop
nop
sw $13, 56($0)
addu $11, $3, $1
sw $11, 60($0)
addu $27, $19, $11
nop
sw $27, 64($0)
addu $27, $16, $28
nop
nop
sw $27, 68($0)
ori $25, $25, 7272
sw $25, 72($0)
ori $31, $31, 65375
nop
sw $31, 76($0)
ori $13, $13, 65318
nop
nop
sw $13, 80($0)
ori $5, $5, 27677
sw $5, 84($0)
ori $13, $13, 30209
nop
sw $13, 88($0)
subu $16, $28, $20
nop
nop
sw $16, 92($0)
addu $6, $16, $21
sw $6, 96($0)
subu $22, $11, $31
nop
sw $22, 100($0)
subu $25, $23, $19
nop
nop
sw $25, 104($0)
ori $0, $0, 8927
sw $0, 108($0)
ori $24, $24, 21563
nop
sw $24, 112($0)
addu $13, $16, $11
nop
nop
sw $13, 116($0)
subu $14, $12, $27
sw $14, 120($0)
addu $15, $24, $27
nop
sw $15, 124($0)
subu $20, $1, $24
nop
nop
sw $20, 128($0)
subu $13, $28, $15
sw $13, 132($0)
ori $28, $28, 56842
nop
sw $28, 136($0)
addu $31, $6, $23
nop
nop
sw $31, 140($0)
ori $10, $10, 11112
sw $10, 144($0)
addu $21, $23, $9
nop
sw $21, 148($0)
subu $22, $16, $29
nop
nop
sw $22, 152($0)
addu $16, $1, $31
sw $16, 156($0)
subu $12, $15, $28
nop
sw $12, 160($0)
addu $6, $10, $22
nop
nop
sw $6, 164($0)
ori $12, $12, 14691
sw $12, 168($0)
ori $16, $16, 34145
nop
sw $16, 172($0)
ori $11, $11, 18551
nop
nop
sw $11, 176($0)
sw $sp, 180($0)
sw $ra, 184($0)
sw $at, 188($0)
ori $sp, $0, 4060
ori $1, $0, 32
jal foo1
nop
lui $1, 0
ori $1, 0
beq $1, $0, skip_manual1
nop
j dl
nop
skip_manual1:
lui $1, 10994
lui $2, 10994
beq $1, $2, skip_manual2
nop
j dl
nop
skip_manual2:
lui $3, 10995
nop
nop
beq $1, $3, dl
addu $4, $4, $3
lui $1, 0x6183
addu $2, $2, $1
lui $5, 0x8124
addu $4, $5, $1
subu $6, $6, $5
jal skip_manual3
nop
sw $0, 4($0)
skip_manual3:
sw $7, -0x3000($ra)
lw $ra, -0x3000($ra)
ori $ra, $0, 0
jal skip_manual4
nop
sw $0, 8($0)
skip_manual4:
beq $ra, $0, dl
nop
ori $ra, $0, 0
jal skip_manual5
nop
sw $ra, 12($0)
skip_manual5:
nop
beq $ra, $0, dl
nop
ori $4, $0, 4
ori $5, $0, 5
ori $1, $0, 1
addu $4, $4, $1
nop
nop
beq $4, $5, skip_manual6
nop
sw $0, 16($0)
skip_manual6:
ori $1, $0, 1
ori $2, $0, 2
ori $3, $0, 3
ori $4, $0, 4
ori $5, $0, 6
ori $6, $0, 5
subu $5, $5, $1
addu $6, $2, $1
beq $5, $6, dl
nop
jal skip_manual8
nop
skip_manual8:
addu $3, $3, $ra
subu $4, $4, $ra
jal foo
nop
jal fooo
nop
jal foooo
nop
jal fooooo
nop
sw $0, 192($0)
sw $1, 196($0)
sw $2, 200($0)
sw $3, 204($0)
sw $4, 208($0)
sw $5, 212($0)
sw $6, 216($0)
sw $7, 220($0)
sw $8, 224($0)
sw $9, 228($0)
sw $10, 232($0)
sw $11, 236($0)
sw $12, 240($0)
sw $13, 244($0)
sw $14, 248($0)
sw $15, 252($0)
sw $16, 256($0)
sw $17, 260($0)
sw $18, 264($0)
sw $19, 268($0)
sw $20, 272($0)
sw $21, 276($0)
sw $22, 280($0)
sw $23, 284($0)
sw $24, 288($0)
sw $25, 292($0)
sw $26, 296($0)
sw $27, 300($0)
sw $28, 304($0)
sw $29, 308($0)
sw $30, 312($0)
sw $31, 316($0)
lui $31, 63605
jal tag_0
nop
ori $ra, $0, 2
tag_0:sw $ra, 320($0)
addu $14, $13, $7
jal tag_1
nop
ori $ra, $0, 2
tag_1:sw $ra, 324($0)
lw $25, 12($0)
jal tag_2
nop
ori $ra, $0, 2
tag_2:sw $ra, 328($0)
lui $29, 14949
nop
jal tag_3
nop
ori $ra, $0, 2
tag_3:sw $ra, 332($0)
addu $10, $24, $1
nop
jal tag_4
nop
ori $ra, $0, 2
tag_4:sw $ra, 336($0)
lw $12, 164($0)
nop
jal tag_5
nop
ori $ra, $0, 2
tag_5:sw $ra, 340($0)
lui $31, 58593
nop
nop
jal tag_6
nop
ori $ra, $0, 2
tag_6:sw $ra, 344($0)
addu $1, $7, $12
nop
nop
jal tag_7
nop
ori $ra, $0, 2
tag_7:sw $ra, 348($0)
lw $20, 256($0)
nop
nop
jal tag_8
nop
ori $ra, $0, 2
tag_8:sw $ra, 352($0)
lui $17, 19367
jal tag_9
nop
ori $ra, $0, 2
tag_9:sw $ra, 356($0)
addu $8, $11, $11
jal tag_10
nop
ori $ra, $0, 2
tag_10:sw $ra, 360($0)
lw $1, 132($0)
jal tag_11
nop
ori $ra, $0, 2
tag_11:sw $ra, 364($0)
lui $18, 56313
nop
jal tag_12
nop
ori $ra, $0, 2
tag_12:sw $ra, 368($0)
addu $23, $25, $24
nop
jal tag_13
nop
ori $ra, $0, 2
tag_13:sw $ra, 372($0)
lw $20, 368($0)
nop
jal tag_14
nop
ori $ra, $0, 2
tag_14:sw $ra, 376($0)
lui $21, 22951
nop
nop
jal tag_15
nop
ori $ra, $0, 2
tag_15:sw $ra, 380($0)
addu $8, $10, $1
nop
nop
jal tag_16
nop
ori $ra, $0, 2
tag_16:sw $ra, 384($0)
lw $4, 88($0)
nop
nop
jal tag_17
nop
ori $ra, $0, 2
tag_17:sw $ra, 388($0)
ori $4, $0, 12
jal skip_manual7
nop
skip_manual7:
addu $ra, $ra, $4
jr $ra
ori $4, $0, 8
addu $ra, $ra, $4
nop
jr $ra
nop
dl:addu $ra, $0, $0
beq $0, $0, dl
nop
foo: jr $ra
ori $ra, $ra, 0xff
fooo: ori $6, $ra, 0xa
jr $ra
nop
foooo: jr $ra
ori $t8, $ra, 0xff
fooooo: ori $t9, $ra, 0xa
jr $ra
nop
foo1:
sw $a0, 0($sp)
sw $ra, 16($sp)
sw $a1, 4($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 84
ori $s2, $0, 220
lw $t0, -40($s1)
lw $t1, -88($s2)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 11072
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 30986
ori $a2, $a1, 0xf0
nop
beq $a2, $a1, skip1
nop
jal foo2
subu $sp, $sp, $1
skip1: lw $a3, 16($sp)
addu $sp, $sp, $1
nop
jr $a3
nop
foo2:
sw $a0, 0($sp)
sw $a1, 4($sp)
sw $ra, 16($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 152
ori $s2, $0, 54
lw $t1, 326($s2)
lw $t0, 160($s1)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 21109
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 60683
ori $a2, $a1, 0xf0
beq $a2, $a1, skip2
nop
jal foo3
subu $sp, $sp, $1
skip2: lw $a3, 16($sp)
jr $a3
addu $sp, $sp, $1
foo3:
sw $ra, 16($sp)
sw $a0, 0($sp)
sw $a1, 4($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 139
ori $s2, $0, 302
lw $t0, -35($s1)
lw $t1, -34($s2)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 29202
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 43269
ori $a2, $a1, 0xf0
nop
beq $a2, $a1, skip3
nop
jal foo13
subu $sp, $sp, $1
skip3: lw $a3, 16($sp)
addu $sp, $sp, $1
jr $a3
nop
foo4:
sw $a0, 0($sp)
sw $ra, 16($sp)
sw $a1, 4($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 297
ori $s2, $0, 96
lw $t1, 104($s2)
lw $t0, -197($s1)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 14171
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 18179
ori $a2, $a1, 0xf0
beq $a2, $a1, skip4
nop
jal foo11
subu $sp, $sp, $1
skip4: lw $a3, 16($sp)
addu $sp, $sp, $1
nop
jr $a3
nop
foo5:
sw $a0, 0($sp)
sw $a1, 4($sp)
sw $ra, 16($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 106
ori $s2, $0, 190
lw $t0, -26($s1)
lw $t1, -82($s2)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 49045
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 36619
ori $a2, $a1, 0xf0
nop
beq $a2, $a1, skip5
nop
jal foo1
subu $sp, $sp, $1
skip5: lw $a3, 16($sp)
jr $a3
addu $sp, $sp, $1
foo6:
sw $ra, 16($sp)
sw $a0, 0($sp)
sw $a1, 4($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 345
ori $s2, $0, 52
lw $t1, -32($s2)
lw $t0, 15($s1)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 25874
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 45316
ori $a2, $a1, 0xf0
beq $a2, $a1, skip6
nop
jal foo4
subu $sp, $sp, $1
skip6: lw $a3, 16($sp)
addu $sp, $sp, $1
jr $a3
nop
foo7:
sw $a0, 0($sp)
sw $ra, 16($sp)
sw $a1, 4($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 319
ori $s2, $0, 212
lw $t0, -167($s1)
lw $t1, 120($s2)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 44079
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 38407
ori $a2, $a1, 0xf0
nop
beq $a2, $a1, skip7
nop
jal foo10
subu $sp, $sp, $1
skip7: lw $a3, 16($sp)
addu $sp, $sp, $1
nop
jr $a3
nop
foo8:
sw $a0, 0($sp)
sw $a1, 4($sp)
sw $ra, 16($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 366
ori $s2, $0, 244
lw $t1, -116($s2)
lw $t0, -290($s1)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 20552
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 22025
ori $a2, $a1, 0xf0
beq $a2, $a1, skip8
nop
jal foo5
subu $sp, $sp, $1
skip8: lw $a3, 16($sp)
jr $a3
addu $sp, $sp, $1
foo9:
sw $ra, 16($sp)
sw $a0, 0($sp)
sw $a1, 4($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 223
ori $s2, $0, 283
lw $t0, 13($s1)
lw $t1, -27($s2)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 28872
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 52993
ori $a2, $a1, 0xf0
nop
beq $a2, $a1, skip9
nop
jal foo15
subu $sp, $sp, $1
skip9: lw $a3, 16($sp)
addu $sp, $sp, $1
jr $a3
nop
foo10:
sw $a0, 0($sp)
sw $ra, 16($sp)
sw $a1, 4($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 228
ori $s2, $0, 255
lw $t1, -155($s2)
lw $t0, 12($s1)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 56866
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 21770
ori $a2, $a1, 0xf0
beq $a2, $a1, skip10
nop
jal foo12
subu $sp, $sp, $1
skip10: lw $a3, 16($sp)
addu $sp, $sp, $1
nop
jr $a3
nop
foo11:
sw $a0, 0($sp)
sw $a1, 4($sp)
sw $ra, 16($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 54
ori $s2, $0, 306
lw $t0, 278($s1)
lw $t1, -238($s2)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 34513
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 36103
ori $a2, $a1, 0xf0
nop
beq $a2, $a1, skip11
nop
jal foo8
subu $sp, $sp, $1
skip11: lw $a3, 16($sp)
jr $a3
addu $sp, $sp, $1
foo12:
sw $ra, 16($sp)
sw $a0, 0($sp)
sw $a1, 4($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 248
ori $s2, $0, 72
lw $t1, 152($s2)
lw $t0, 76($s1)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 1104
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 24322
ori $a2, $a1, 0xf0
beq $a2, $a1, skip12
nop
jal foo9
subu $sp, $sp, $1
skip12: lw $a3, 16($sp)
addu $sp, $sp, $1
jr $a3
nop
foo13:
sw $a0, 0($sp)
sw $ra, 16($sp)
sw $a1, 4($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 386
ori $s2, $0, 194
lw $t0, -82($s1)
lw $t1, -142($s2)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 18477
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 2816
ori $a2, $a1, 0xf0
nop
beq $a2, $a1, skip13
nop
jal foo7
subu $sp, $sp, $1
skip13: lw $a3, 16($sp)
addu $sp, $sp, $1
nop
jr $a3
nop
foo14:
sw $a0, 0($sp)
sw $a1, 4($sp)
sw $ra, 16($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 184
ori $s2, $0, 255
lw $t1, 13($s2)
lw $t0, -88($s1)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 26871
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 23821
ori $a2, $a1, 0xf0
beq $a2, $a1, skip14
nop
jal foo16
subu $sp, $sp, $1
skip14: lw $a3, 16($sp)
jr $a3
addu $sp, $sp, $1
foo15:
sw $ra, 16($sp)
sw $a0, 0($sp)
sw $a1, 4($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 264
ori $s2, $0, 366
lw $t0, -212($s1)
lw $t1, -2($s2)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 36680
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 1289
ori $a2, $a1, 0xf0
nop
beq $a2, $a1, skip15
nop
jal foo14
subu $sp, $sp, $1
skip15: lw $a3, 16($sp)
addu $sp, $sp, $1
jr $a3
nop
foo16:
sw $a0, 0($sp)
sw $ra, 16($sp)
sw $a1, 4($sp)
sw $a2, 8($sp)
sw $a3, 12($sp)
sw $t0, 20($sp)
sw $t1, 24($sp)
sw $t2, 28($sp)
ori $s1, $0, 39
ori $s2, $0, 301
lw $t1, -17($s2)
lw $t0, 317($s1)
addu $a3, $t0, $t1
addu $a0, $a0, $t0
addu $a1, $a1, $t1
addu $t2, $a0, $a1
ori $a0, $t2, 706
addu $t2, $t2, $t2
addu $t2, $t2, $t2
ori $a1, $t2, 2561
ori $a2, $a1, 0xf0
beq $a2, $a1, skip16
nop
jal foo6
subu $sp, $sp, $1
skip16: lw $a3, 16($sp)
addu $sp, $sp, $1
nop
jr $a3
nop

对拍输出一致或许对吧……


思考题

  1. 为什么需要有单独的乘除法部件而不是整合进 ALU?为何需要有独立的 HI、LO 寄存器?

    因为乘法除法需要在多个周期内执行,且只用HI,LO寄存器。所以用单独的HI,LO寄存器可以减少阻塞周期,提高效率,因为在乘除法部件工作时ALU模块还可以进行其他指令的工作,做到高效率执行。

    并且HI,LO寄存器不属于通用寄存器,和其他通用寄存器的用法不一致,不能通过非乘除法指令修改和访问,因此不需要置于GRF中,内置在MDU中即可。

  2. 真实的流水线 CPU 是如何使用实现乘除法的?请查阅相关资料进行简单说明。

    乘法实现:

    首先CPU会初始化三个通用寄存器用来存放被乘数,乘数,部分积。
    部分积寄存器初始化为0。
    判断乘数寄存器的低位是0|1,如果为0则将乘数寄存器右移一位,同时将部分积寄存器也右移一位。
    在位移时遵循计算机位移规则,乘数寄存器低位溢出的一位丢弃,部分积寄存器低位溢出的一位填充到乘数寄存器的高位。
    同时部分积寄存器高位补0。如果为1则将部分积寄存器加上被乘数寄存器,再进行移位操作。
    当所有乘数位处理完成后部分积寄存器做高位,乘数寄存器做低位就是最终乘法结果。

    还有另一种乘法的方式:

    只需两个寄存器,A[31:0],B[63:0],A初始化为被乘数,B初始化为乘数。
    每一次取B的最低位,为1则将A[31:0]+B[63:32] -> B[63:32],为0则不操作。
    每次将B >> 1,然后高位补0。

    除法实现:

    与乘法的操作基本相反,首先CPU会初始化三个寄存器,用来存放被除数,除数,部分商。余数(被除数与除数比较的结果)放到被除数的有效高位上。CPU做除法时和做除法时是相反的,乘法是右移,除法是左移,乘法做的是加法,除法做的是减法。首先CPU会把被除数bit位与除数bit位对齐,然后再让对齐的被除数与除数比较(双符号位判断)。比如01-10=11(前面的1是符号位) 1-2=-1 计算机通过符号位和后一位的bit位来判断大于和小于,那么01-10=11 就说明01小于10,如果得数为01就代表大于,如果得数为00代表等于。如果得数大于或等于则将比较的结果放到被除数的有效高位上然后再商寄存器上商:1 并向后多看一位(上商就是将商的最低位左移1位腾出商寄存器最低位上新的商)如果得数小于则上商:0 并向后多看一位然后循环做以上操作当所有的被除数都处理完后,商做结果被除数里面的值就是余数。

  3. 请结合自己的实现分析,你是如何处理 Busy 信号带来的周期阻塞的?

    对于stall信号,我增加了如果Start或者Busy信号有效,且D级时mfhi,mflo,mthi,mtlo时进行阻塞。

  4. 请问采用字节使能信号的方式处理写指令有什么好处?(提示:从清晰性、统一性等角度考虑)

    清晰性方面,按字节使能相当于onehot编码,1为写入,0为不写入,直观清楚。

    统一性方面,对于各种处理内存指令只需设置好字节使能信号就可以控制数据的写入,不用通过取出该字的数据后再次拼接,对各种指令的操作表现的一样。

  5. 请思考,我们在按字节读和按字节写时,实际从 DM 获得的数据和向 DM 写入的数据是否是一字节?在什么情况下我们按字节读和按字节写的效率会高于按字读和按字写呢?

    在按字节读和按字节写时,实际从 DM 获得的数据和向 DM 写入的数据是同一节,因为读写所使用的地址都来自上一级的ALUresult,但是对应的字节不能保证一样,因为写入的和读出的有特定的模块控制。

    在有sb,sh这种不是对于完整字节操作的指令来说, 按字节的读写效率会更高,如果按字处理,需要先从内存中读出该字节的所存储的数据,接下来根据需要进行拼接,最后组成完整的字节存入地址中,从内存中读出所消耗的组合逻辑延迟会降低效率,以字节读写就会消除这方面的影响。

  6. 为了对抗复杂性你采取了哪些抽象和规范手段?这些手段在译码和处理数据冲突的时候有什么样的特点与帮助?

    主要采用了指令分类的方法,P6 完全沿用了 P5 的分类方法,新增的指令对应的特点都没有脱离这些分类,因此对于每条指令而言,只需译码后将其加入对应的分类,数据通路部分和 P5 完全类似,转发部分完全不用改,暂停部分只需添加一个因乘除块而导致的暂停。

  7. 在本实验中你遇到了哪些不同指令类型组合产生的冲突?你又是如何解决的?相应的测试样例是什么样的?

    冲突方面,主要是数据冒险和控制冒险,分别通过暂停转发以及比较前移+延迟槽解决。

    具体而言:

    R类型Rd(写),后续指令Rs或Rt(读)

    使用旁路转发,以add为例

    1
    2
    3
    add $t0,$t1,$t2 add $a0,$t0,$t1 M到E级转发 
    add $t0,$t1,$t2 nop add $a0,$t0,$t1 M到D级转发
    add $t0,$t1,$t2 nop nop add $a0,$t0,$t1 WB向D级转发

    load指令Rt(写),隔条指令Rs或Rt(读)

    1
    2
    3
    lw $t0,0($0) add $t0,$t0,$t0 stall一个周期,WB向E级转发 
    lw $t0,0($0) nop add $t0,$t0,$t0 WB向E级转发
    lw $t0,0($0) nop nop add $t0,$t0,$t0 WB向D级转发

    mult、multu、div、divu和mfhi、mflo、mthi、mtlo

    如果E级的Busy或Start信号有效,如果是其他非乘除法相关指令,不会阻塞,使用ALU即可,如果是乘除法相关指令,如果是mfhi、mflo、mthi、mtlo,将它们阻塞在D级,直到乘除法结束;如果是mult、multu、div、divu,清空乘除法模块中的操作,将D级流水到E级。

    1
    2
    mult $t1,$t2 mflo $a0 会阻塞直到乘除法结束 
    mult $t1,$t2 div $a0,$a1 mult指令被div指令覆盖
  8. 如果你是手动构造的样例,请说明构造策略,说明你的测试程序如何保证覆盖了所有需要测试的情况;如果你是完全随机生成的测试样例,请思考完全随机的测试程序有何不足之处;如果你在生成测试样例时采用了特殊的策略,比如构造连续数据冒险序列,请你描述一下你使用的策略如何结合了随机性达到强测的效果。

    数据生成器采用了特殊策略:单组数据中除了 0 和 31 号寄存器外,至多涉及 3 个寄存器。一方面,这样产生的代码中,邻近的指令几乎全部都存在数据冒险,可以充分测试转发和暂停;另一方面,当测试数据的组数一定多,几乎涉及了每个寄存器,避免了只测试部分寄存器。此外,所有跳转指令都是特殊构造的,不会进入死循环的同时如果跳转出错可以输出中体现。

    对于一些会产生异常的指令,为防止 MARS 报错,进行了一定的规避,比如除法不会去生成有关0号寄存器的除法,lw,sw保证是4的倍数等等。

RooKie_Z P6 Verilog流水线CPU设计文档

https://rookie-zgy1513.github.io/2025/08/10/P6-CPU/

作者

RooKie_Z

发布于

2025-08-10

更新于

2025-08-16

许可协议

评论