一、CPU设计方案综述
(一)总体设计概述
本CPU为Verilog实现的流水线CPU,支持的指令集包含{LB、LBU、LH、LHU、LW、SB、SH、SW、ADD、ADDU、SUB、SUBU、MULT、MULTU、DIV、DIVU SLL、SRL、SRA、SLLV、SRLV、SRAV、AND、OR、XOR、NOR、ADDI、ADDIU、ANDI、ORI、XORI、LUI、SLT、SLTI、SLTIU、SLTU、BEQ、BNE、BLEZ、BGTZ、BLTZ、BGEZ、J、JAL、JALR、JR、MFHI、MFLO、MTHI、MTLO}。为了实现这些功能,CPU主要包含了mips、IM、PC、GRF、Controller、EXT、CMP、NPC、ALU、DM、regFD、regDE、regEM、regMW、Fw_Controller、Mult_Div、Load_select、CP0、Bridge等部件,其中,mips为顶层模块。
将这些部件分为F、D、E、M、W级模块,主要通过F级读取当前指令,进入D级输出各个模块的控制信号从而对各个模块进行相应控制并计算出下一指令地址,继而进入E级进行计算,通过M级、W级进行写入操作从而实现指令的功能。通过Fw_Controller模块,分析传入的各级寄存器编号以及指令类型,输出相应的转发控制信号和暂停控制信号。
(二)关键模块定义
1. PC
表1 PC模块接口
文件 |
模块接口定义 |
PC.v |
module PC( input [31:0] NPC, //下一PC值 input clk, //时钟信号 input reset, //同步复位信号 Input PCEn, //PC使能信号 output reg [31:0] PC //当前PC值 ); |
表2 IFU功能定义
序号 |
功能名称 |
功能描述 |
1 |
同步复位 |
当时钟信号处于上升沿且reset信号有效时,PC被设置为0x0000 3000 |
2 |
读取地址 |
根据PC寄存器中保存的值输出当前地址 |
3 |
冻结地址 |
当PC使能信号失效时,需要暂停,冻结当前地址 |
2. GRF
表3 GRF模块接口
文件 |
模块接口定义 |
GRF.v |
module GRF( input clk,//时钟信号 input reset,//同步复位信号 input RegWrite,//写使能信号 input [4:0] A1,//读寄存器地址1 input [4:0] A2,//读寄存器地址2 input [4:0] A3,//写寄存器地址 input [31:0] WD,//写入数据 input [31:0] PC,//当前地址 output [31:0] RD1,//寄存器地址1的数据 output [31:0] RD2 //寄存器地址2的数据 ); reg[31:0] register[31:0]; |
表4 GRF功能定义
序号 |
功能名称 |
功能描述 |
1 |
同步复位 |
当时钟信号处于上升沿且reset信号有效时,所有寄存器存储的数值清零 |
2 |
读数据 |
读出A1,A2地址对应寄存器中存储的数据到RD1,RD2 |
3 |
写数据 |
当RegWrite有效且时钟上升沿来临,将WD写入A3对应的寄存器中 |
3. Controller
表5 Controller模块接口
文件 |
模块接口定义 |
Controller.v |
module Controller( input [5:0] op,//指令的[31:26]位,表明指令类型 input [5:0] func,//指令的[5:0]位,表明R型指令的控制信号 output reg [1:0]MemtoReg,//GRF写入数据选择信号 output reg MemWrite,//DM写使能信号 output reg Branch,//分支指令判断信号 output reg if_jr,//jr指令判断信号 output reg iF_j,//jal、j指令判断信号 output reg ALUSrc,//ALU输入数据选择信号 output reg [2:0] ALUControl,//ALU控制信号 output reg [1:0]RegDst,//GRF写入寄存器选择信号 output reg RegWrite,//GRF写使能信号 output reg [1:0] ExpandSrc//立即数拓展方式选择信号 ); |
表6 Controller功能定义
序号 |
功能名称 |
功能描述 |
1 |
产生控制信号 |
通过读入的op与func,产生对应指令的控制信号 |
4.ALU
表7 ALU模块接口
文件 |
模块接口定义 |
ALU.v |
module ALU( input [31:0] A,//输入数据1 input [31:0] B,//输入数据2 input [2:0] ALUControl,//ALU控制信号 output reg [31:0] ALUResult,//ALU计算结果 ); |
表8 ALU功能定义
序号 |
功能名称 |
功能描述 |
1 |
加 |
A + B //ALUControl=00 |
2 |
减 |
A - B //ALUControl=01 |
3 |
与 |
A & B //ALUControl=10 |
4 |
或 |
A | B //ALUControl=11 |
5.DM
表9 DM模块接口
文件 |
模块接口定义 |
DM.v |
module DM( input clk,//时钟信号 input reset,//同步复位信号 input MemWrite,//写使能信号 input [31:0] PC,//当前地址 input [31:0] Addr,//写入地址 input [31:0] WD,//写入数据 output [31:0] RD//输出数据 ); |
表10 DM功能定义
序号 |
功能名称 |
功能描述 |
1 |
复位 |
当时钟信号处于上升沿且reset信号有效时,RAM中的数据都被设置为0x0000 0000 |
2 |
写 |
当时钟处于上升沿且写使能信号有效时,根据输入地址,把输入数据写入 |
3 |
读 |
根据输入的地址,输出对应地址的数据 |
6.EXT
表11 EXT模块接口
文件 |
模块接口定义 |
EXT.v |
module EXT( input [15:0] imm16,//输入数据imm16 input [1:0] ExpandSrc,//拓展选择信号 output reg [31:0] EXTResult//输出数据 ); |
表12 EXT功能定义
序号 |
功能名称 |
功能描述 |
1 |
符号拓展 |
当拓展选择信号为00时,将输入数据进行符号拓展 |
2 |
无符号拓展 |
当拓展选择信号为01时,将输入数据进行无符号拓展 |
3 |
转移至高位拓展 |
当拓展选择信号为10时,将输入数据转移至高位 |
7.IM
表13 IM模块接口
文件 |
模块接口定义 |
IM.v |
module IM( input [31:0] PC,//当前地址 output [31:0] instruction//当前地址对应指令 ); |
表14 IM功能定义
序号 |
功能名称 |
功能描述 |
1 |
读 |
根据输入地址,读取当前指令 |
8.CMP
表15 CMP模块接口
文件 |
模块接口定义 |
CMP.v |
module CMP( input [31:0] MFRSD, input [31:0] MFRTD, output reg Zero ); |
表16 CMP功能定义
序号 |
功能名称 |
功能描述 |
1 |
判断是否相等 |
判断输入的两个寄存器中的值是否相等 |
9.NPC
表17 NPC模块接口
文件 |
模块接口定义 |
NPC.v |
module NPC( input [31:0] PC4_F, input [31:0] PC4_D, input [25:0] imm26, input Zero, input Branch, input if_j, input if_jr, input [31:0] MFRSD, output reg[31:0] NPC ); wire [31:0] PC; assign PC = PC4_F - 4; |
表18 NPC功能定义
序号 |
功能名称 |
功能描述 |
1 |
判断下一条指令地址 |
根据输入的各个控制信号,判断下一条指令的地址。 若Branch信号和Zero信号都有效,beq跳转生效 NPC = PC4_D + {{14{imm26[15]}},imm26[15:0],2'b00}; 若if_j信号有效,j或jal跳转生效 NPC = {PC[31:28],imm26[25:0],2'b00}; 若if_jr信号有效,jr跳转生效 NPC = MFRSD; 若以上信号都未生效,NPC=PC+4; |
10.regFD
表19 regFD模块接口
文件 |
模块接口定义 |
regFD.v |
module regFD( input [31:0] Instr_F, input [31:0] PC4_F, input clk, input reset, input stall, output reg [31:0] Instr_D, output reg [31:0] PC4_D ); |
表20 regFD功能定义
序号 |
功能名称 |
功能描述 |
1 |
流水指令及地址 |
将F级读到的指令及地址流水至D级 |
2 |
暂停 |
若暂停信号stall信号生效,FD寄存器中的值冻结 |
3 |
复位 |
若复位信号生效,FD寄存器中的值归0 |
11.regDE
表21 regDE模块接口
文件 |
模块接口定义 |
regDE.v |
module regDE( input clk, input reset, input stall, input [31:0] Instr_D, input [31:0] PC4_D, input RegWrite_D, input [1:0] MemtoReg_D, input MemWrite_D, input [1:0] RegDst_D, input ALUSrc_D, input [2:0] ALUControl_D, input [31:0] RD1_D, input [31:0] RD2_D, input [31:0] EXTResult_D, input [4:0] Rs_D, input [4:0] Rt_D, input [4:0] Rd_D, output reg [31:0] Instr_E, output reg [31:0] PC4_E, output reg RegWrite_E, output reg [1:0] MemtoReg_E, output reg MemWrite_E, output reg [1:0] RegDst_E, output reg ALUSrc_E, output reg [2:0] ALUControl_E, output reg [31:0] RD1_E, output reg [31:0] RD2_E, output reg [31:0] EXTResult_E, output reg [4:0] Rs_E, output reg [4:0] Rt_E, output reg [4:0] Rd_E ); |
表22 regDE功能定义
序号 |
功能名称 |
功能描述 |
1 |
流水指令及地址 |
将D级读到的指令及地址流水至E级 |
2 |
流水控制信号 |
将D级Controller输出的控制信号流水至E级 |
3 |
流水关键数据 |
将部分关键数据如GRF(转发)的数据,EXT拓展结果,指令中Rs,Rt,Rd的编号流水至E级 |
4 |
暂停 |
若暂停信号stall信号生效,FD寄存器中的值归0 |
5 |
复位 |
若复位信号生效,DED寄存器中的值归0 |
12.regEM
表23 regEM模块接口
文件 |
模块接口定义 |
regEM.v |
module regEM( input clk, input reset, input [31:0] Instr_E, input [31:0] PC4_E, input RegWrite_E, input [1:0] MemtoReg_E, input MemWrite_E, input [4:0] A3_E, input [31:0] ALUResult_E, input [31:0] MFRTE, output reg [31:0] Instr_M, output reg [31:0] PC4_M, output reg RegWrite_M, output reg [1:0] MemtoReg_M, output reg MemWrite_M, output reg [31:0] ALUResult_M, output reg [4:0] A3_M, output reg [31:0] MFRTM ); |
表24 regEM功能定义
序号 |
功能名称 |
功能描述 |
1 |
流水指令及地址 |
将E级读到的指令及地址流水至M级 |
2 |
流水控制信号 |
将E级读到的控制信号流水至M级 |
3 |
流水关键数据 |
将部分关键数据如E级Rt转发后的值,ALU计算结果,E级指令所需写寄存器编号流水至M级 |
4 |
复位 |
若复位信号生效,EM寄存器中的值归0 |
13.regMW
表25 regMW模块接口
文件 |
模块接口定义 |
regMW.v |
module regMW( input reset, input clk, input [31:0] Instr_M, input [31:0] PC4_M, input RegWrite_M, input [1:0] MemtoReg_M, input [31:0] ALUResult_M, input [4:0] A3_M, input [31:0] RD_M, output reg [31:0] Instr_W, output reg [31:0] PC4_W, output reg RegWrite_W, output reg [1:0] MemtoReg_W, output reg [31:0] ALUResult_W, output reg [4:0] A3_W, output reg [31:0] RD_W ); |
表26 regMW功能定义
序号 |
功能名称 |
功能描述 |
1 |
流水指令及地址 |
将M级读到的指令及地址流水至W级 |
2 |
流水控制信号 |
将M级读到的控制信号流水至W级 |
3 |
流水关键数据 |
将部分关键数据如M级写入DM的值,M级流水的ALU计算结果,M级指令所需写寄存器编号流水至M级 |
4 |
复位 |
若复位信号生效,MW寄存器中的值归0 |
14.F
表27 F模块接口
文件 |
模块接口定义 |
F.v |
module F( input [31:0] NPC, input clk, input reset, input stall, output [31:0] Instr_F, output [31:0] PC4_F ); wire [31:0] PC; assign PCEn = !stall; |
表28 F功能定义
序号 |
功能名称 |
功能描述 |
1 |
流水指令及地址 |
将根据地址读到的指令及地址及地址流水至D级 |
2 |
暂停 |
若stall信号生效,冻结当前PC |
4 |
复位 |
若复位信号生效,将PC复位至32’h00003000 |
15.D
表29 D模块接口
文件 |
模块接口定义 |
D.v |
module D( input [31:0] Instr_F, input clk, input reset, input [31:0] PC4_F, input RegWrite_W, input [31:0] WD_W, input [31:0] WD_M, input [4:0] A3_W, input [31:0] PC4_W, input [31:0] PC4_E, input [31:0] PC4_M, input [2:0] ForwardRSD, input [2:0] ForwardRTD, input stall, input [31:0]ALUResult_M, output [31:0] Instr_D, output [31:0] PC4_D, output [31:0] NPC, output RegWrite_D, output [1:0] MemtoReg_D, output MemWrite_D, output [1:0] RegDst_D, output ALUSrc_D, output [2:0] ALUControl_D, output [31:0] RD1_D, output [31:0] RD2_D, output [31:0] EXTResult_D, output [4:0] Rs_D, output [4:0] Rt_D, output [4:0] Rd_D ); assign Rs_D=Instr_D[`rs]; assign Rt_D=Instr_D[`rt]; assign Rd_D=Instr_D[`rd]; |
表30 D功能定义
序号 |
功能名称 |
功能描述 |
1 |
流水指令及地址 |
将D级读到的指令及地址流水至E级 |
2 |
流水控制信号 |
将Controller产生的控制信号流水至E级 |
3 |
流水关键数据 |
将部分关键数据流水至E级 |
4 |
计算下一个指令地址 |
通过NPC计算下一条指令地址 |
5 |
复位 |
若复位信号生效,FD寄存器中的值归0 |
6 |
暂停 |
若stall信号生效,使FD寄存器冻结 |
16.E
表31 E模块接口
文件 |
模块接口定义 |
E.v |
module E( input clk, input reset, input [31:0] Instr_D, input [31:0] PC4_D, input RegWrite_D, input [1:0] MemtoReg_D, input MemWrite_D, input [1:0] RegDst_D, input ALUSrc_D, input [2:0] ALUControl_D, input [31:0] RD1_D, input [31:0] RD2_D, input [31:0] EXTResult_D, input [4:0] Rs_D, input [4:0] Rt_D, input [4:0] Rd_D, input [2:0] ForwardRSE, input [2:0] ForwardRTE, input [31:0] WD_M, input [31:0] WD_W, input stall, output [31:0] Instr_E, output [31:0] PC4_E, output RegWrite_E, output [1:0] MemtoReg_E, output MemWrite_E, output [4:0] A3_E, output [31:0] ALUResult_E, output [31:0] MFRTE, output flag_E, output [4:0]Rs_E, output [4:0]Rt_E ); |
表32 E功能定义
序号 |
功能名称 |
功能描述 |
1 |
流水指令及地址 |
将E级读到的指令及地址流水至M级 |
2 |
流水控制信号 |
将E级读到的控制信号流水至M级 |
3 |
流水关键数据 |
将部分关键数据流水至M级 |
4 |
计算指令结果 |
通过ALU计算部分指令的输出 |
5 |
复位 |
若复位信号生效,DE寄存器中的值归0 |
6 |
暂停 |
若stall信号生效,DE寄存器中的值归0 |
17.M
表33 M模块接口
文件 |
模块接口定义 |
M.v |
module E( input clk, input reset, input [31:0] Instr_D, input [31:0] PC4_D, input RegWrite_D, input [1:0] MemtoReg_D, input MemWrite_D, input [1:0] RegDst_D, input ALUSrc_D, input [2:0] ALUControl_D, input [31:0] RD1_D, input [31:0] RD2_D, input [31:0] EXTResult_D, input [4:0] Rs_D, input [4:0] Rt_D, input [4:0] Rd_D, input [2:0] ForwardRSE, input [2:0] ForwardRTE, input [31:0] WD_M, input [31:0] WD_W, input stall, output [31:0] Instr_E, output [31:0] PC4_E, output RegWrite_E, output [1:0] MemtoReg_E, output MemWrite_E, output [4:0] A3_E, output [31:0] ALUResult_E, output [31:0] MFRTE, output flag_E, output [4:0]Rs_E, output [4:0]Rt_E ); |
表34 M功能定义
序号 |
功能名称 |
功能描述 |
1 |
流水指令及地址 |
将M级读到的指令及地址流水至W级 |
2 |
流水控制信号 |
将M级读到的控制信号流水至W级 |
3 |
流水关键数据 |
将部分关键数据流水至M级 |
4 |
复位 |
若复位信号生效,EM寄存器中的值归0,DM中的值归0 |
18.W
表35 W模块接口
文件 |
模块接口定义 |
M.v |
module E( input clk, input reset, input [31:0] Instr_D, input [31:0] PC4_D, input RegWrite_D, input [1:0] MemtoReg_D, input MemWrite_D, input [1:0] RegDst_D, input ALUSrc_D, input [2:0] ALUControl_D, input [31:0] RD1_D, input [31:0] RD2_D, input [31:0] EXTResult_D, input [4:0] Rs_D, input [4:0] Rt_D, input [4:0] Rd_D, input [2:0] ForwardRSE, input [2:0] ForwardRTE, input [31:0] WD_M, input [31:0] WD_W, input stall, output [31:0] Instr_E, output [31:0] PC4_E, output RegWrite_E, output [1:0] MemtoReg_E, output MemWrite_E, output [4:0] A3_E, output [31:0] ALUResult_E, output [31:0] MFRTE, output flag_E, output [4:0]Rs_E, output [4:0]Rt_E ); |
表36 W功能定义
序号 |
功能名称 |
功能描述 |
1 |
写数据 |
将指令所需写数据传入GRF |
2 |
复位 |
若复位信号生效,MW寄存器中的值归0 |
19.Mult_Div
表37 Mult_Div模块接口
文件 |
模块接口定义 |
Mult_Div.v |
module Mult_Div( input clk, input reset, input [31:0] A, input [31:0] B, input start_E, input [3:0]MDOp_E, output reg Busy, output [31:0] HI, output [31:0] LO ); |
表38 Mult_Div功能定义
序号 |
功能名称 |
功能描述 |
1 |
进行乘除计算 |
将指令进行乘除计算并且将相应值保存至HI,LO |
2 |
赋值 |
给HI,LO赋值 |
20.Load_seLect
表39 Load_seLect模块接口
文件 |
模块接口定义 |
Mult_Div.v |
module Load_select( input [31:0] RD_W, input [31:0] Instr_W, input [31:0] ALUResult_W, output reg [31:0] RD_W_real ); |
表40 Load_stlect功能定义
序号 |
功能名称 |
功能描述 |
1 |
取内存值 |
根据当前指令及Addr,取处内存中值的相应位 |
21.CP0
表41 CP0模块接口
文件 |
模块接口定义 |
CP0.v |
module CP0( input [4:0] A1,//rd读 input [4:0] A2,//rd写 input [31:0] DIn, input [31:0] PC, //存入的epc input [4:0] ExcCode, //中断异常类 input [5:0] HWInt, //6个中断 input We, //CP0写使能 input EXLSet, //中断 exl置1 input EXLClr, //eret exl置0 input clk, input reset, input BD, //延迟操指令受害标志 output IntReq, //输出中断请求 output [31:0] EPC, output [31:0] Dout ); |
表42 CP0功能定义
序号 |
功能名称 |
功能描述 |
1 |
同步复位 |
当时钟信号处于上升沿且reset信号有效时,所有寄存器存储的数值清零 |
2 |
读数据 |
mfc0可以将CP0中寄存器存储的数据读出 |
3 |
写数据 |
mtc0可以向CP0寄存器写入数据 |
4 |
判断中断异常 |
判断中断异常的发生,产生中断请求的信号 |
5 |
返回地址 |
eret可以让cpu在处理完异常后返回epc |
22.Bridge
表43 Bridge模块接口
文件 |
模块接口定义 |
Bridge.v |
module Bridge( input [31:0] PrAddr, input PrWE,//timer写使能 input [31:0] PrWD,//写入DEV的数据 input [31:0] DEV0_RD,//DEV0的数据 input [31:0] DEV1_RD,//DEV1的数据 output [31:0] PrRD, //从DEV0/1读取的数据 output [31:0] DEV_Addr,//写入地址 output [31:0] DEV_WD,//写入DEV的数据 output WeDEV0,//DEV0写使能 output WeDEV1 //DEV1写使能 ); |
表44 Bridge功能定义
序号 |
功能名称 |
功能描述 |
1 |
写/读 数据 |
作为CPU与timer的桥梁,向timer中写或读数据 |
23.mips
表45 mips模块接口
文件 |
模块接口定义 |
mips.v |
module mips( input clk, input reset, input interrupt, output [31:0] addr ); |
表46 mips功能定义
序号 |
功能名称 |
功能描述 |
1 |
复位 |
当复位信号有效时,将CPU复位 |
2 |
外部中断 |
当interrupt信号有效时,将CPU中断 |
3 |
输出当前宏观pc |
输出当前宏观pc值 |
(三)重要机制实现方案
①:跳转
NPC模块和CMP模块协同工作支持b指令的跳转
CMP比较Rs和Rt寄存器中的值,以及比较0和Rs寄存器中的值,输出是大于小于等于0,或是否相等,进而通过NPC模块进行跳转。
NPC模块和Controller模快协同支持j,jal,jr,jalr的跳转
Controller模块通过读取指令判断指令是否为j,jal或jr,jalr,进而跳转至所需位置。
②:转发
Fw_Controller与D,E,M级模块协同工作以支持转发(未使用内部转发)
先分析当前级别(D,E,M)的指令是否立刻需要其所需寄存器的值,若需要,则判断所需寄存器编号与该指令前的指令中已产生新值但仍未写回GRF的的写入寄存器编号是否相等,若相等,进行转发。
而判断之前的指令是否已产生新值则需根据指令类型进行分析,在E,M,W级寄存器中通过分析指令的类型来判断当前是否产生新值,若已产生,flag_X(X为级数)为1.
图1 转发控制表
assign flag_E = Instr_E[`op]==`jal||Instr_E[`op]==`jalr;
assign flag_M=cal_r||cal_i||mf||j;
assign flag_W=cal_r||cal_i||mf||j||load;
assign ForwardRSD=(Rs_D==A3_E&&A3_E!=0&&flag_E)? 3'b001:
(Rs_D==A3_M&&A3_M!=0&&flag_M)? 3'b010:
(Rs_D==A3_W&&A3_W!=0&&flag_W)? 3'b011:0;
assign ForwardRTD=(Rt_D==A3_E&&A3_E!=0&&flag_E)? 3'b001:
(Rt_D==A3_M&&A3_M!=0&&flag_M)? 3'b010:
(Rt_D==A3_W&&A3_W!=0&&flag_W)? 3'b011:0;
assign ForwardRSE=(Rs_E==A3_M&&A3_M!=0&&flag_M)? 3'b010:
(Rs_E==A3_W&&A3_W!=0&&flag_W)? 3'b011:0;
assign ForwardRTE=(Rt_E==A3_M&&A3_M!=0&&flag_M)? 3'b010:
(Rt_E==A3_W&&A3_W!=0&&flag_W)? 3'b011:0;
assign ForwardRTM=(Rt_M==A3_W&&A3_W!=0&&flag_W)? 3'b011:0;
assign MFRSD = (ForwardRSD==3'b001)?PC4_E+4:
(ForwardRSD==3'b010)?WD_M:
(ForwardRSD==3'b011)?WD_W:RD1;
assign MFRTD = (ForwardRTD==3'b001)?PC4_E+4:
(ForwardRTD==3'b010)?WD_M:
(ForwardRTD==3'b011)?WD_W:RD2;
assign MFRSE = (ForwardRSE==3'b010)?WD_M:
(ForwardRSE==3'b011)?WD_W:RD1_E;
assign MFRTE = (ForwardRTE==3'b010)?WD_M:
(ForwardRTE==3'b011)?WD_W:RD2_E;
assign WD = (ForwardRTM==3'b011)?WD_W:MFRTM;
③:暂停
Fw_Controller发出控制信号stall控制F,D,E级模块的暂停工作
分析D级指令还要过几个周期才需要使用寄存器的值(Tuse),对于该指令前的指令,分析还需过几个周期才能产生新值(Tnew),若Tnew>Tuse则需暂停。分析完本次实验所有指令的Tuse、Tnew后,对于D中指令以及前面的指令类型进行判断,若有Tnew>Tuse且所用寄存器编号相等,stall信号有效,控制各个流水寄存器进行暂停
图2 暂停控制表
assign stall_b = b_D&&((((Rs_D==A3_E)||(Rt_D==A3_E))&&(cal_r_E||cal_i_E||mf_E||load_E))||(((Rs_D==A3_M)||(Rt_D==A3_M))&&load_M));
assign stall_cal_r=cal_r_D&&((Rs_D==A3_E)||(Rt_D==A3_E))&&load_E;
assign stall_MD=MD_D&&((Rs_D==A3_E)||(Rt_D==A3_E))&&load_E;
assign stall_cal_i=cal_i_D&&Rs_D==A3_E&&load_E;
assign stall_mt=mt_D&&Rs_D==A3_E&&load_E;
assign stall_load=load_D&&Rs_D==A3_E&&load_E;
assign stall_store=store_D&&Rs_D==A3_E&&load_E;
assign stall_j = j_D&&(((Rs_D==A3_E)&&(cal_r_E||cal_i_E||mf_E||load_E))||((Rs_D==A3_M)&&load_M));
assign stall_ALLMD=ALLMD_D&&(Busy||MD_E);
assign stall = stall_b||stall_cal_r||stall_MD||stall_cal_i||stall_mt||stall_load||stall_store||stall_j||stall_ALLMD;
④:异常/异常
异常:根据所可能发生的异常,在cpu中进行判断,若发生异常将ExcCode修改为相应值,传入CP0中进行相应。
中断:向CPU输入HWInt信号,由interrupt、IRQ1、IRQ0组成,若该信号有位为1,则将CPU中断,各流水清空。
二、测试方案
1.转发机制测试
表48 转发情况
用例编号 |
当前指令 |
前序指令 |
冲突寄存器 |
冲突级别 |
1 |
b/jr/jalr |
jal |
rs |
D |
2 |
b/jr/jalr |
cal_r xxx |
rs |
D |
3 |
b/jr/jalr |
cal_i xxx |
rs |
D |
4 |
b/jr/jalr |
jal xxx |
rs |
D |
5 |
b/jr/jalr |
cal_r xxx xxx |
rs |
D |
6 |
b/jr/jalr |
cal_i xxx xxx |
rs |
D |
7 |
b/jr/jalr |
lw xxx xxx |
rs |
D |
8 |
b/jr/jalr |
jal (延迟槽) xxx xxx |
rs |
D |
9 |
b |
jal |
rt |
D |
10 |
b |
cal_r xxx |
rt |
D |
11 |
b |
cal_i xxx |
rt |
D |
12 |
b |
jal xxx |
rt |
D |
13 |
b |
cal_r xxx xxx |
rt |
D |
14 |
b |
cal_i xxx xxx |
rt |
D |
15 |
b |
lw xxx xxx |
rt |
D |
16 |
b |
jal (延迟槽) xxx xxx |
rt |
D |
17 |
cal_r,cal_i,load,store,mf |
cal_r xxx |
rs |
E |
18 |
cal_r,cal_i,load,store,mf |
cal_i xxx |
rs |
E |
19 |
cal_r,cal_i,load,store,mf |
jal xxx |
rs |
E |
20 |
cal_r,cal_i,load,store,mf |
cal_r xxx xxx |
rs |
E |
21 |
cal_r,cal_i,load,store,mf |
cal_i xxx xxx |
rs |
E |
22 |
cal_r,cal_i,load,store,mf |
lw xxx xxx |
rs |
E |
23 |
cal_r,cal_i,load,store,mf |
jal (延迟槽) xxx xxx |
rs |
E |
24 |
cal_r |
cal_r xxx |
rt |
E |
25 |
cal_r |
cal_i xxx |
rt |
E |
26 |
cal_r |
jal xxx |
rt |
E |
27 |
cal_r |
cal_r xxx xxx |
rt |
E |
28 |
cal_r |
cal_i xxx xxx |
rt |
E |
29 |
cal_r |
lw xxx xxx |
rt |
E |
30 |
cal_r |
jal (延迟槽) xxx xxx |
rt |
M |
31 |
store |
cal_r xxx xxx |
rt |
M |
32 |
store |
cal_i xxx xxx |
rt |
M |
33 |
store |
lw xxx xxx |
rt |
M |
34 |
store |
jal (延迟槽) xxx xxx |
rt |
M |
1,9.jal后不接跳转或分支指令,故不需考虑
2,10.
ori $t1,$0,0x1234
addu $t2,$0,$t1
beq $t1,$t2,tag
nop
addu $t3,$t1,$t2
tag:
期望输出:
@00003000: $ 9 <= 00001234
@00003004: $10 <= 00001234
3,11.
ori $t1,$0,0x1234
ori $t2,$0,0x1234
beq $t1,$t2,tag
nop
addu $t3,$t1,$t2
tag:
期望输出:
@00003000: $ 9 <= 00001234
@00003004: $10 <= 00001234
4,12.
ori $t1,$0,0x300c
jal tag1
nop
addu $t1,$t1,$0
tag1:
beq $31,$t1,tag2
nop
addu $t1,$t1,$0
tag2:
期望输出:
@00003000: $ 9 <= 0000300c
@00003004: $31 <= 0000300c
5,13.
ori $t1,$0,0x1234
addu $t2,$0,$t1
nop
beq $t1,$t2,tag
nop
addu $t3,$t1,$t2
tag:
期望输出:
@00003000: $ 9 <= 00001234
@00003004: $10 <= 00001234
6,14.
ori $t1,$0,0x1234
ori $t2,$0,0x1234
nop
beq $t1,$t2,tag
nop
addu $t3,$t1,$t2
期望输出:
@00003000: $ 9 <= 00001234
@00003004: $10 <= 00001234
7.15
ori $t1,0x1234
sw $t1,0($0)
lw $t2,0($0)
nop
nop
beq $t1,$t2,tag
nop
addu $t1,$t1,$0
tag:
期望输出:
@00003000: $ 9 <= 00001234
@00003004: *00000000 <= 00001234
@00003008: $10 <= 00001234
8.16
ori $t1,$0,0x300c
jal tag1
nop
addu $t1,$t1,$0
tag1:
nop
beq $31,$t1,tag2
nop
addu $t1,$t1,$0
tag2:
期望输出:
@00003000: $ 9 <= 0000300c
@00003004: $31 <= 0000300c
17,18,24,25
ori $t1,$0,0x0010
ori $t2,$0,0x0020
ori $t3,$0,0x0004
addu $t4,$t1,$t2
nop
addu $t4,$t4,$t3 //t4=0034
nop
ori $t5,$t4,0x1234
subu $t4,$t4,$t3
nop
sw $t1,0($t4)
addu $t4,$t4,$t3
subu $t4,$t4,$t3
nop
lw $t2,0($t4)
期望输出:
@00003000: $ 9 <= 00001000
@00003004: $10 <= 00002000
@00003008: $11 <= 00000004
@0000300c: $12 <= 00003000
@00003014: $12 <= 00003004
@0000301c: $13 <= 00003234
@00003020: $12 <= 00003000
@00003000: $ 9 <= 00000010
@00003004: $10 <= 00000020
@00003008: $11 <= 00000004
@0000300c: $12 <= 00000030
@00003014: $12 <= 00000034
@0000301c: $13 <= 00001234
@00003020: $12 <= 00000030
@00003028: *00000030 <= 00000010
@0000302c: $12 <= 00000034
@00003030: $12 <= 00000030
@00003038: $10 <= 00000010
19.26
ori $t1,$0,4
jal tag1
nop
addu $t1,$t1,$t1
tag1:
addu $t2,$31,$t1
jal tag2
nop
addu $t1,$t1,$t1
tag2:
ori $t3,$31,0xff00
jal tag3
nop
addu $t1,$t1,$t1
tag3:
期望输出:
@00003000: $ 9 <= 00000004
@00003004: $31 <= 0000300c
@00003010: $10 <= 00003010
@00003014: $31 <= 0000301c
@00003020: $11 <= 0000ff1c
@00003024: $31 <= 0000302c
@00003000: $ 9 <= 00000004
@00003004: $31 <= 0000300c
@00003010: $10 <= 00003010
@00003014: $31 <= 0000301c
@00003020: $11 <= 0000ff1c
@00003024: $31 <= 0000302c
20,21,27,28.
ori $t1,$0,0x0010
ori $t2,$0,0x0020
ori $t3,$0,0x0004
addu $t4,$t1,$t2
nop
nop
addu $t4,$t4,$t3 //t4=0034
nop
nop
ori $t5,$t4,0x1234
subu $t4,$t4,$t3
nop
nop
sw $t1,0($t4)
addu $t4,$t4,$t3
subu $t4,$t4,$t3
nop
nop
lw $t2,0($t4)
期望输出:
@00003000: $ 9 <= 00001000
@00003004: $10 <= 00002000
@00003008: $11 <= 00000004
@0000300c: $12 <= 00003000
@00003014: $12 <= 00003004
@0000301c: $13 <= 00003234
@00003020: $12 <= 00003000
@00003000: $ 9 <= 00000010
@00003004: $10 <= 00000020
@00003008: $11 <= 00000004
@0000300c: $12 <= 00000030
@00003014: $12 <= 00000034
@0000301c: $13 <= 00001234
@00003020: $12 <= 00000030
@00003028: *00000030 <= 00000010
@0000302c: $12 <= 00000034
@00003030: $12 <= 00000030
@00003038: $10 <= 00000010
22,30.
ori $t1,$0,0x1234
sw $t1,0($1)
sw $t1,4($0)
lw $t2,0($0)
nop
nop
addu $t2,$t2,$t2
lw $t3,0($0)
nop
nop
ori $t3,$t3,0xfff0
lw $t4,0($0)
nop
nop
lw $t4,0($t4)
期望输出:
@00003000: $ 9 <= 00001234
@00003004: *00000000 <= 00001234
@00003008: *00000004 <= 00001234
@0000300c: $10 <= 00001234
@00003018: $10 <= 00002468
@0000301c: $11 <= 00001234
@00003028: $11 <= 0000fff4
@0000302c: $12 <= 00001234
@00003038: $12 <= 00000000
31,32,33,34
ori $t1,$0,0x1234
ori $t2,$0,0x0004
addu $t3,$t1,$t2
sw $t1,0($0)
lw $t4,0($0)
sw $t3,4($0)
nop
sw $t4,8($0)
jal tag
nop
addu $t1,$t1,$t1
tag:
nop
sw $31,12($0)
期望输出:
@00003000: $ 9 <= 00001234
@00003004: $10 <= 00000004
@00003008: $11 <= 00001238
@0000300c: *00000000 <= 00001234
@00003010: $12 <= 00001234
@00003014: *00000004 <= 00001238
@0000301c: *00000008 <= 00001234
@00003020: $31 <= 00003028
@00003030: *0000000c <= 00003028
2.暂停机制测试
用例编号 |
当前指令 |
前序指令 |
冲突寄存器 |
1 |
b |
cal_r |
rs/rt |
2 |
b |
cal_i |
rs/rt |
3 |
b |
load |
rs/rt |
4 |
b |
load xxx |
rs/rt |
5 |
cal_r |
load |
rs |
6 |
cal_i |
load |
rs |
7 |
load |
load |
rs |
8 |
store |
load |
rs |
9 |
jr/jalr |
cal_r |
rs |
10 |
jr/jalr |
cal_i |
rs |
11 |
jr/jalr |
load |
rs |
12 |
jr/jalr |
load xxx |
rs |
13 |
b |
mf |
rs/rt |
14 |
jr/jalr |
mf |
rs |
15 |
MD |
load |
rs/rt |
16 |
ALLMD |
busy/MD |
/ |
测试代码:
1.
ori $t1,$0,0x3000
addu $t2,$t1,$zero
beq $t1,$t2,tag
nop
addu $t3,$t1,$t2
tag:
期望输出:
@00003000: $ 9 <= 00003000
@00003004: $10 <= 00003000
2.
ori $t1,$0,0x3000
ori $t2,$0,0x3000
beq $t1,$t2,tag
nop
addu $t3,$t1,$t2
tag:
期望输出:
@00003000: $ 9 <= 00003000
@00003004: $10 <= 00003000
3.
ori $t1,$0,0x3000
sw $t1,0($0)
lw $t2,0($0)
beq $t1,$t2,tag
nop
addu $t3,$t1,$t2
tag:
期望输出:
@00003000: $ 9 <= 00003000
@00003004: *00000000 <= 00003000
@00003008: $10 <= 00003000
4.
ori $t1,$0,0x3000
sw $t1,0($0)
lw $t2,0($0)
nop
beq $t1,$t2,tag
nop
addu $t3,$t1,$t2
tag:
期望输出:
@00003000: $ 9 <= 00003000
@00003004: *00000000 <= 00003000
@00003008: $10 <= 00003000
5.
ori $t1,$0,0x3000
sw $t1,0($0)
lw $t2,0($0)
addu $t3,$t1,$t2
期望输出:
@00003000: $ 9 <= 00003000
@00003004: *00000000 <= 00003000
@00003008: $10 <= 00003000
@0000300c: $11 <= 00006000
6.
ori $t1,$0,0x3000
sw $t1,0($0)
lw $t2,0($0)
ori $t3,$0,0x3000
期望输出:
ori $t1,$0,0x3000
sw $t1,0($0)
lw $t2,0($0)
ori $t3,$t2,0x3000
7.
ori $t1,$0,0x1000
sw $t1,0($0)
sw $t1,0($t1)
lw $t2,0($0)
lw $t3,0($t2)
期望输出:
@00003000: $ 9 <= 00001000
@00003004: *00000000 <= 00001000
@00003008: *00001000 <= 00001000
@0000300c: $10 <= 00001000
@00003010: $11 <= 00001000
8.
ori $t1,$0,0x1000
sw $t1,0($0)
lw $t2,0($0)
sw $t1,0($t2)
期望输出:
@00003000: $ 9 <= 00001000
@00003004: *00000000 <= 00001000
@00003008: $10 <= 00001000
@0000300c: *00001000 <= 00001000
9.
ori $t1,$0,0x3014
addu $t2,$t1,$0
jr $t2
nop
addu $t1,$t1,$0
addu $t1,$t1,$t1
期望输出:
@00003000: $ 9 <= 00003014
@00003004: $10 <= 00003014
@00003014: $ 9 <= 00006028
10.
ori $t1,$0,0x3014
ori $t2,$t1,0x0000
jr $t2
nop
addu $t1,$t1,$0
addu $t1,$t1,$t1
期望输出:
@00003000: $ 9 <= 00003014
@00003004: $10 <= 00003014
@00003014: $ 9 <= 00006028
11.
ori $t1,0x3018
sw $t1,0($0)
lw $t2,0($0)
jr $t2
nop
addu $t1,$t1,$0
addu $t1,$t1,$t1
期望输出:
@00003000: $ 9 <= 00003018
@00003004: *00000000 <= 00003018
@00003008: $10 <= 00003018
@00003018: $ 9 <= 00006030
12.
ori $t1,0x301c
sw $t1,0($0)
lw $t2,0($0)
nop
jr $t2
nop
addu $t1,$t1,$0
addu $t1,$t1,$t1
期望输出:
@00003000: $ 9 <= 0000301c
@00003004: *00000000 <= 0000301c
@00003008: $10 <= 0000301c
@0000301c: $ 9 <= 00006038
13.
addi $t1,$0,2
addi $t2,$t0,1
mult $t1,$t2
mflo $t3
beq $t1,$t3,flag
nop
add $t1,$t1,$t1
flag:
add $t1,$t1,$t1
期望输出:
@00003000: $ 9 <= 00000002
@00003004: $10 <= 00000001
@0000300c: $11 <= 00000002
@0000301c: $ 9 <= 00000004
14.
addi $t1,$0,1
addi $t2,$t0,0x301c
mult $t1,$t2
mflo $t3
jr $t3
nop
add $t1,$t1,$t1
flag:
add $t1,$t1,$t1
期望输出:
@00003000: $ 9 <= 00000001
@00003004: $10 <= 0000301c
@0000300c: $11 <= 0000301c
@0000301c: $ 9 <= 00000002
15.
addi $t1,$0,10
sw $t1,0($0)
lw $t2,0($0)
mult $t1,$t2
mflo $t3
期望输出:
@00003000: $ 9 <= 0000000a
@00003004: *00000000 <= 0000000a
@00003008: $10 <= 0000000a
@00003010: $11 <= 00000064
三、思考题
(一)为什么需要有单独的乘除法部件而不是整合进ALU?为何需要有独立的HI、LO寄存器?
因为MD类指令需要额外设置运算延迟,单独的乘除法部件更容易实现。同时MD指令计算结果为64位,而ALU的结果普遍都是32位,若仍要用ALU计算则要将ALU结果改为64位,那么就需要修改关于独立的HI、LO寄存器,违背了“高内聚,低耦合”的原则。
由于MD指令得到的结果为64位,将其分为两个32位寄存器来存储,对于乘法存储高32位和低32位,对于除法存储低余数和商,有了HI和LO方便获取MD指令计算后所需要的结果,也得以实现mf、mt指令。
(二)参照你对延迟槽的理解,试解释“乘除槽”
对于乘除模块,在进行MD指令的计算过程中,后续若有关于乘除指令,而乘除模块仍处于start或busy则需暂停。那么就可以类似延迟槽行为,在MD指令后接上与乘除无关的指令,充分利用CPU的性能。
(三)举例说明并分析何时按字节访问内存相对于按字访问内存性能上更有优势。(Hint: 考虑C语言中字符串的情况)
当对字符串进行处理时,一个字符占用一个字节,四个字符为一个字。若字符串中字符个数为5个,按字访存,需要2个字,8个字节,按字节访存,仅需要5个。可见按字访存会浪费内存空间。
(四)在本实验中你遇到了哪些不同指令类型组合产生的冲突?你又是如何解决的?相应的测试样例是什么样的?如果你是手动构造的样例,请说明构造策略,说明你的测试程序如何保证覆盖了所有需要测试的情况;如果你是完全随机生成的测试样例,请思考完全随机的测试程序有何不足之处;如果你在生成测试样例时采用了特殊的策略,比如构造连续数据冒险序列,请你描述一下你使用的策略如何结合了随机性达到强测的效果。
如上面第二大点中已列出冲突指令组合以及测试样例,通过Fw_Controller模块,分析传入的各级寄存器编号以及指令类型,输出相应的转发控制信号和暂停控制信号。
通过分析本次要求的各个指令,将会产生冲突的指令写入表格中,再一一列出样例进行测试,先写一条指令再在相应行数后写入一个会与这条指令所改变寄存器冲突的指令,构成冲突,再通过观察输出结果判断是否成功。
(五)为了对抗复杂性你采取了哪些抽象和规范手段?这些手段在译码和处理数据冲突的时候有什么样的特点与帮助?
采用宏定义,将各指令的op、func提前定义好,避免后续一堆数字不好分辨指令。同时利用模块Decoder将当前指令译码并分类,得到当前指令类型以进入Controller得到控制信号,避免了代码过长,并且在后续处理转发或暂停时可直接利用指令类型进行判断,不用将该类型所有指令列出,从而使得逻辑更清晰。并且在加入新指令时只需要将其归类便可直接处理好冲突。