实验-RISCV流水线处理器设计与实现
一.流水线设计
![TheStructureChart]
二、rtl文件
在根目录文件夹下。
三、流水线实现思路
(一)完成各组件的设计
1.运算单元的设计
包含adder,alu,data_mem,imm_gen,mux,基本上都很简单。
根据《RISC_V_Experiment-2022》PPT里的内容就可以实现imm_gen,


2.存储单元的设计
3.控制单元的设计
①proc_controller
proc_controller是非常重要的控制单元。
在PPT《2021-第4章第3讲-单周期控制器》里的这张图给出了一些主控制单元控制信号设计的方法
在proc_controller文件中也给出了一些控制信号设计的提示:
(ps:这里额外设置了jar_sel变量,是因为branch进行特殊运算的需要,后面branch会提到)
(pss:这里ALUop信号的设置与付老师一开始给的不一样,将rtype与IType分离开,而且将IType中的store/load与addi、ori和jalr也分离开,因为觉得这样方便设计alu_controller)
我们这里首先将各所需要设计的指令用变量表示出来,方便之后代码的书写
②branch_unit
branch_unit是为了确定下一条指令的地址,如果不执行jal、jalr、branch,则下一条指令地址为pc+4,否则更改branch_target的值为相应指令的跳转地址,这里额外设置了jal_sel变量,是因为jal与jalr所执行的跳转动作是不一样的,jalr指令中包含源寄存器。如图:
(ps:其实这里jalr的运算结果不应该放在pc_plus_imm变量里的,这个变量里应该只放jal和branch的pc+imm,因为jalr指令的pc_plu_imm里实际为pc+imm+rs1)
③alu_controller
(ps:首先这里input的变量额外添加了opcode,是为了为了区分IType和UType中的funct部分与imm部分,例如UType没有funct,但是imm有部分可能与funct有相同的值)
这里的output的operation是可以自己定义的,只要定义的4位operation预期执行的运算与alu文件中的alu_ctrl控制执行的运算保持一致即可。
4.解决冒险问题
①结构冒险
在本实验中寄存器等存储器同时被多条指令使用貌似不会产生结构冒险、资源冲突,如寄存器的读、写口是类似于分离开的,可以同时被读写
②数据冒险
用stall和forward,即hazard文件和forward_unit文件解决该问题,解决写后读的问题,
采取PPt《2021-第4章第4讲-流水线原理》上的此图设计思路
即:如图:
如果当前指令经过ID部分译码后,检测到出现数据冒险(forward文件的代码实现后续附上)
则当前指令ID后阻塞,pc值不发生改变,下一条执行的指令依然为该条指令,且ALU的操作数通过如下图所示的ALU数据选择器,将上一条指令写入的,当前指令的,其中一源寄存器的结果,取代未修改的寄存器的值:
至此实现了如PPT上所示的阻塞操作。
forward文件代码如下:
③控制冒险
控制冒险解决方法的基本思路有三种,如图:
本实验采用第一种方法,即阻塞分支指令后的三条指令,首先如果出现了分支指令且满足跳转条件,在BrFlush文件中,先将BrFlush控制信号置为1:
pc_sel = ((branch_taken && alu_result == 0) || jalr_sel || jal_sel) ? 1'b1 : 1'b0;
而后阻塞接下来的指令,
当前指令的下一条指令由下图所示代码完成阻塞,将ID/IF寄存器“冲刷”为“空”:
当前指令的再下一条指令由下图代码完成阻塞,将本条指令设为“空指令”:
当branch_unit中的branch_target值计算出来后,通过下图的代码,将当前应该执行的指令的地址置为branch_target:
(二)、将各组件连接起来(data_path)
1.设计IF单元并向IF/ID寄存器传入当前指令地址和未解码指令。
①如果遇到reset指令,则将pc进行初始化,pc值为0,如果遇到stall则不执行下一条指令,PC保持不变
PC <= reset ? 0 : stall ? PC : PC_mux_result;
②设置Brflush的值,根据branch_unit的output来设置。
assign PC_mux_result = BrFlush ? BrPC : PCplus4
③向IF/ID寄存器传入当前指令地址和未解码指令
(ps:这两条指令要控制其在非阻塞的情况下)
2.对data_path的理解
这个文件的代码条理很清晰,简单来说就是类似下图的结构:
data_path
`timescale 1ns / 1ps
// 数据通路
`include "pipeline_regs.sv"
import Pipe_Buf_Reg_PKG::*;
module Datapath #(
parameter PC_W = 9, // width of the Program Counter
parameter INS_W = 32, // Instruction Width
parameter DATA_W = 32, // reigster width
parameter DM_ADDRESS = 9, // width of the data memory address
parameter ALU_CC_W = 4 // width of the ALU Control code
) (
input logic clock,
// reset , sets the PC to zero
input logic reset,
// Register file writing enable
input logic reg_write_en,
// Selection signal for the source of value used to write the regiser
input logic WrRegDataSrc,
// Register file or Immediate MUX
input logic alu_src,
// Memroy Writing Enable
input logic mem_write_en,
// Memroy Reading Enable
input logic mem_read_en,
// Branch Enable
input logic branch_taken,
// Jalr Mux Select
input logic jalr_sel,
// Jal Instruction distinguish from jalr used in the branch function
input logic jal_sel,
input logic [1:0] alu_op,
// Mux4to1 Select
input logic [1:0] RWSel,
// ALU Control Code ( input of the ALU )
input logic [ALU_CC_W -1:0] alu_cc,
output logic [6:0] opcode,
output logic [6:0] opcode_IDEX,
output logic [6:0] funct7,
output logic [2:0] funct3,
output logic [1:0] aluop_current,
// data write back to register
output logic [DATA_W-1:0] wb_data
);
// define the pipeline registers
if_id_reg PipeRegIFID;
id_ex_reg PipeRegIDEX;
ex_mem_reg PipeRegEXMEM;
mem_wb_reg PipeRegMEWB;
/*todo: analysis here
* the registers are declared here.
* each struct in pipeline_regs.sv is a set of registers
*/
// ====================================================================================
// Instruction Fetch (IF)
// ====================================================================================
//
// peripheral logic here.
//
logic BrFlush, stall;
logic [31:0] PC_mux_result, PC, PCplus4, BrPC, instr;
// add your code here for PC generation
assign PCplus4 = PC + 4;
assign PC_mux_result = BrFlush ? BrPC : PCplus4;
always @(posedge clock) begin
//stall, do not update the PC
PC <= reset ? 0 : stall ? PC : PC_mux_result;//①:如果遇到reset指令,则将pc进行初始化//②:如果遇到stall则不执行下一条指令
//这里pc赋值必须用<=而不能用=
end
// your instruction memory
Insn_mem IM (
.read_address(PC[PC_W-1 : 0]),
.insn(instr)
);
// ====================================================================================
// End of Instruction Fetch (IF)
// ====================================================================================
// ====================================================================================
//IF/ID寄存器,有控制pc和instr同步的功能 ,也有遇到stall时,将后续元件清空(设为bubble)的作用
// ====================================================================================
always @(posedge clock, posedge reset) begin
// add your logic here to update the IF_ID_Register
if(!stall) begin
PipeRegIFID.Curr_Pc <= (reset|BrFlush) ? 9'b0:PC;
PipeRegIFID.Curr_Instr <= (reset|BrFlush) ? 32'b0:instr;
end
end
// ====================================================================================
// Instruction Decoding (ID)
// ====================================================================================
//
// peripheral logic here.
//
assign opcode = PipeRegIFID.Curr_Instr[6:0];
logic [31:0] rd1, rd2, ImmG;
//
// add your register file here.
//
// ====================================================================================
// 寄存器文件(空间?),放的是寄存器的内容,在tb文件夹的test_r文件夹下的的rf_init文件的内容从上至下为寄存器x0-x31
// ====================================================================================
Reg_file RF (
.clock(clock),
.reset(reset),
.write_en(PipeRegMEWB.RegWrite),
.write_addr(PipeRegMEWB.rd),
.data_in(wb_data),
.read_addr1(PipeRegIFID.Curr_Instr[19:15]),
.read_addr2(PipeRegIFID.Curr_Instr[24:20]),
.data_out1(rd1),
.data_out2(rd2)
);
//
// add your immediate generator here
//
// ====================================================================================
// 立即数拓展元件
// ====================================================================================
Imm_gen Imm_Gen (
.inst_code(PipeRegIFID.Curr_Instr),
.imm_out (ImmG)
);
// ====================================================================================
// End of Instruction Decoding (ID)
// ====================================================================================
always @(posedge clock, posedge reset) begin
// add your logic here to update the ID_EX_Register
if (reset | stall | BrFlush) begin
PipeRegIDEX.ALU2ndOperandSrc <= 1'b0;
PipeRegIDEX.WrRegDataSrc <= 1'b0;
PipeRegIDEX.RegWrite <= 1'b0;
PipeRegIDEX.MemRead <= 1'b0;
PipeRegIDEX.MemWrite <= 1'b0;
PipeRegIDEX.ALUOp <= 2'b0;
PipeRegIDEX.Branch <= 1'b0;
PipeRegIDEX.JalrSel <= 1'b0;
PipeRegIDEX.JalSel <= 1'b0;
PipeRegIDEX.RWSel <= 2'b0;
PipeRegIDEX.Curr_Pc <= 9'b0;
PipeRegIDEX.RD_One <= 32'b0;
PipeRegIDEX.RD_Two <= 32'b0;
PipeRegIDEX.RS_One <= 5'b0;
PipeRegIDEX.RS_Two <= 5'b0;
PipeRegIDEX.rd <= 5'b0;
PipeRegIDEX.ImmG <= 32'b0;
PipeRegIDEX.func3 <= 3'b0;
PipeRegIDEX.func7 <= 7'b0;
PipeRegIDEX.Curr_Instr <= 32'b0;
end else if (!stall) begin
PipeRegIDEX.ALU2ndOperandSrc <= alu_src;
PipeRegIDEX.WrRegDataSrc <= WrRegDataSrc;
PipeRegIDEX.RegWrite <= reg_write_en;
PipeRegIDEX.MemRead <= mem_read_en;
PipeRegIDEX.MemWrite <= mem_write_en;
PipeRegIDEX.ALUOp <= alu_op;
PipeRegIDEX.Branch <= branch_taken;
PipeRegIDEX.JalrSel <= jalr_sel;
PipeRegIDEX.JalSel <= jal_sel;
PipeRegIDEX.RWSel <= RWSel;
PipeRegIDEX.Curr_Pc <= PipeRegIFID.Curr_Pc;
PipeRegIDEX.RD_One <= rd1;
PipeRegIDEX.RD_Two <= rd2;
PipeRegIDEX.RS_One <= PipeRegIFID.Curr_Instr[19:15];
PipeRegIDEX.RS_Two <= PipeRegIFID.Curr_Instr[24:20];
PipeRegIDEX.rd <= PipeRegIFID.Curr_Instr[11:7];
PipeRegIDEX.ImmG <= ImmG;
PipeRegIDEX.func3 <= PipeRegIFID.Curr_Instr[14:12];
PipeRegIDEX.func7 <= PipeRegIFID.Curr_Instr[31:25];
PipeRegIDEX.Curr_Instr <= PipeRegIFID.Curr_Instr;
end
end
// ====================================================================================
// Execution (EX)
// ====================================================================================
//
// add your ALU, branch unit and with peripheral logic here
//
logic [31:0] FA_mux_result, FB_mux_result;
logic [31:0] ALU_result, PCplusImm, PCplus4_EX, src_mux_result, mem_data;
logic [1:0] ForwardA, ForwardB;
logic zero;
assign aluop_current = PipeRegIDEX.ALUOp;
assign opcode_IDEX = PipeRegIDEX.Curr_Instr[6:0];
assign funct3 = PipeRegIDEX.func3;
assign funct7 = PipeRegIDEX.func7;
alu ALU (
.operand_a(FA_mux_result),
.operand_b(src_mux_result),
.alu_ctrl(alu_cc),
.alu_result(ALU_result),
.zero(zero)
);
// ====================================================================================
// 若有有传递则更新传递
// ====================================================================================
BranchUnit Branch_unit (
.cur_pc(PipeRegIDEX.Curr_Pc),
.imm(PipeRegIDEX.ImmG),
.jalr_sel(PipeRegIDEX.JalrSel),
.jal_sel(PipeRegIDEX.JalSel),
.branch_taken(PipeRegIDEX.Branch),
.alu_result(ALU_result),
.pc_plus_imm(PCplusImm),
.pc_plus_4(PCplus4_EX),
.branch_target(BrPC),
.pc_sel(BrFlush)
);
mux4 FA_mux (
.d00(PipeRegIDEX.RD_One),
.d10(mem_data),
.d01(wb_data),
.d11(32'b0),
.s (ForwardA),
.y (FA_mux_result)
);
mux4 FB_mux (
.d00(PipeRegIDEX.RD_Two),
.d10(mem_data),
.d01(wb_data),
.d11(32'b0),
.s (ForwardB),
.y (FB_mux_result)
);
mux2 src_mux (
.d0(FB_mux_result),
.d1(PipeRegIDEX.ImmG),
.s (PipeRegIDEX.ALU2ndOperandSrc),
.y (src_mux_result)
);
// ====================================================================================
// End of Execution (EX)
// ====================================================================================
always @(posedge clock, posedge reset) begin
// add your logic here to update the EX_MEM_Register
if (reset) begin
PipeRegEXMEM.RegWrite <= 1'b0;
PipeRegEXMEM.WrRegDataSrc <= 1'b0;
PipeRegEXMEM.MemRead <= 1'b0;
PipeRegEXMEM.MemWrite <= 1'b0;
PipeRegEXMEM.RWSel <= 2'b0;
PipeRegEXMEM.Pc_Imm <= 32'b0;
PipeRegEXMEM.Pc_Four <= 32'b0;
PipeRegEXMEM.Imm_Out <= 32'b0;
PipeRegEXMEM.Alu_Result <= 32'b0;
PipeRegEXMEM.MemWrData <= 32'b0;
PipeRegEXMEM.rd <= 5'b0;
PipeRegEXMEM.func3 <= 3'b0;
PipeRegEXMEM.func7 <= 7'b0;
PipeRegEXMEM.Curr_Instr <= 32'b0;
end else begin
PipeRegEXMEM.RegWrite <= PipeRegIDEX.RegWrite;
PipeRegEXMEM.WrRegDataSrc <= PipeRegIDEX.WrRegDataSrc;
PipeRegEXMEM.MemRead <= PipeRegIDEX.MemRead;
PipeRegEXMEM.MemWrite <= PipeRegIDEX.MemWrite;
PipeRegEXMEM.RWSel <= PipeRegIDEX.RWSel;
PipeRegEXMEM.Pc_Imm <= PCplusImm;
PipeRegEXMEM.Pc_Four <= PCplus4_EX;
PipeRegEXMEM.Imm_Out <= PipeRegIDEX.ImmG;
PipeRegEXMEM.Alu_Result <= ALU_result;
PipeRegEXMEM.MemWrData <= FB_mux_result;
PipeRegEXMEM.rd <= PipeRegIDEX.rd;
PipeRegEXMEM.func3 <= PipeRegIDEX.func3;
PipeRegEXMEM.func7 <= PipeRegIDEX.func7;
PipeRegEXMEM.Curr_Instr <= PipeRegIDEX.Curr_Instr;
end
end
// ====================================================================================
// Memory Access (MEM)
// ====================================================================================
// add your data memory here.
logic [31:0] ReadData;
datamemory DM (
.clock(clock),
.read_en(PipeRegEXMEM.MemRead),
.write_en(PipeRegEXMEM.MemWrite),
.address(PipeRegEXMEM.Alu_Result[11:0]),
.data_in(PipeRegEXMEM.MemWrData),
.funct3(PipeRegEXMEM.func3),
.data_out(ReadData)
);
mux4 mem_mux (
.d00(PipeRegEXMEM.Alu_Result),
.d01(PipeRegEXMEM.Pc_Four),
.d10(PipeRegEXMEM.Imm_Out),
.d11(PipeRegEXMEM.Pc_Imm),
.s (PipeRegEXMEM.RWSel),
.y (mem_data)
);
// ====================================================================================
// End of Memory Access (MEM)
// ====================================================================================
always @(posedge clock) begin
// add your logic here to update the MEM_WB_Register
if (reset) begin
PipeRegMEWB.RegWrite <= 1'b0;
PipeRegMEWB.WrRegDataSrc <= 1'b0;
PipeRegMEWB.RWSel <= 2'b0;
PipeRegMEWB.Pc_Imm <= 32'b0;
PipeRegMEWB.Pc_Four <= 32'b0;
PipeRegMEWB.Imm_Out <= 32'b0;
PipeRegMEWB.Alu_Result <= 32'b0;
PipeRegMEWB.MemReadData <= 32'b0;
PipeRegMEWB.rd <= 5'b0;
PipeRegMEWB.Curr_Instr <= 5'b0;
end else begin
PipeRegMEWB.RegWrite <= PipeRegEXMEM.RegWrite;
PipeRegMEWB.WrRegDataSrc <= PipeRegEXMEM.WrRegDataSrc;
PipeRegMEWB.RWSel <= PipeRegEXMEM.RWSel;
PipeRegMEWB.Pc_Imm <= PipeRegEXMEM.Pc_Imm;
PipeRegMEWB.Pc_Four <= PipeRegEXMEM.Pc_Four;
PipeRegMEWB.Imm_Out <= PipeRegEXMEM.Imm_Out;
PipeRegMEWB.Alu_Result <= PipeRegEXMEM.Alu_Result;
PipeRegMEWB.MemReadData <= ReadData;
PipeRegMEWB.rd <= PipeRegEXMEM.rd;
PipeRegMEWB.Curr_Instr <= PipeRegEXMEM.Curr_Instr;
// $display("------------------------------------------------------------------");
// $display("PipeRegMEWB.Curr_Instr = %x",PCplus4);
// // $display("PipeRegMEWB.Imm_Out = %x", PipeRegMEWB.Imm_Out);
// // $display("PipeRegMEWB.Pc_Four = %x", PipeRegMEWB.Pc_Four);
// $display("PCplusImm = %x", PipeRegMEWB.Imm_Out);
// $display("PCplus4_EX = %x", PipeRegMEWB.Pc_Four);
// $display("PipeRegMEWB.WrRegDataSrc = %x", BrPC);
// $display("PipeRegIDEX.Curr_Pc = %x", PipeRegIDEX.Curr_Pc);
// $display("PipeRegMEWB.Alu_Result = %x", PipeRegMEWB.Alu_Result);
// $display("wb_data = %x",wb_data);
end
end
// ====================================================================================
// Write Back (WB)
// ====================================================================================
//
// add your write back logic here.
//
logic [31:0] res_mux_result;
mux2 res_mux (
.d0(PipeRegMEWB.Alu_Result),
.d1(PipeRegMEWB.MemReadData),
.s (PipeRegMEWB.WrRegDataSrc),
.y (res_mux_result)
);
mux4 wrs_mux (
.d00(res_mux_result),
.d01(PipeRegMEWB.Pc_Four),
.d10(PipeRegMEWB.Imm_Out),
.d11(PipeRegMEWB.Pc_Imm),
.s (PipeRegMEWB.RWSel),
.y (wb_data)
);
// ====================================================================================
// End of Write Back (WB)
// ====================================================================================
// ====================================================================================
// other logic
// ====================================================================================
//
// add your hazard detection logic here
//
Hazard_detector hazard_unit (
.clock(clock),
.reset(reset),
.if_id_rs1(PipeRegIFID.Curr_Instr[19:15]),
.if_id_rs2(PipeRegIFID.Curr_Instr[24:20]),
.id_ex_rd(PipeRegIDEX.rd),
.id_ex_memread(PipeRegIDEX.MemRead),
.stall(stall)
);
//
// add your forwarding logic here
//
ForwardingUnit forwarding_unit (
.rs1(PipeRegIDEX.RS_One),
.rs2(PipeRegIDEX.RS_Two),
.ex_mem_rd(PipeRegEXMEM.rd),
.mem_wb_rd(PipeRegMEWB.rd),
.ex_mem_regwrite(PipeRegEXMEM.RegWrite),
.mem_wb_regwrite(PipeRegMEWB.RegWrite),
.forward_a(ForwardA),
.forward_b(ForwardB)
);
//
// possible extra code
//
endmodule
pipeline_regs
//
package Pipe_Buf_Reg_PKG;
// Reg A
typedef struct packed{
logic [8:0] Curr_Pc;
logic [31:0] Curr_Instr;
} if_id_reg;
// Reg B
typedef struct packed{
logic ALU2ndOperandSrc;
logic WrRegDataSrc;
logic RegWrite;
logic MemRead;
logic MemWrite;
logic [1:0] ALUOp;
logic Branch;
logic JalrSel;
logic JalSel;
logic [1:0] RWSel;
logic [8:0] Curr_Pc;
logic [31:0] RD_One; // 1st read data from the reg file.
logic [31:0] RD_Two; // 2nd read data from the reg file.
logic [4:0] RS_One; // 1st read register address of Curr_Instr
logic [4:0] RS_Two; // 2nd read register address of Curr_Instr
logic [4:0] rd; // dst register to write of Curr_Instr
logic [31:0] ImmG; // Immediate value generated by Imm_gen
logic [2:0] func3;
logic [6:0] func7;
logic [31:0] Curr_Instr;
} id_ex_reg;
// Reg C
typedef struct packed{
logic RegWrite;
logic WrRegDataSrc;
logic MemRead;
logic MemWrite;
logic [1:0] RWSel;
logic [31:0] Pc_Imm;
logic [31:0] Pc_Four;
logic [31:0] Imm_Out;
logic [31:0] Alu_Result;
logic [31:0] MemWrData; // data written to the memory
logic [4:0] rd; // dst register to write of Curr_Instr
logic [2:0] func3;
logic [6:0] func7;
logic [31:0] Curr_Instr;
} ex_mem_reg;
// Reg D
typedef struct packed{
logic RegWrite;
logic WrRegDataSrc;
logic [1:0] RWSel;
logic [31:0] Pc_Imm;
logic [31:0] Pc_Four;
logic [31:0] Imm_Out;
logic [31:0] Alu_Result;
logic [31:0] MemReadData;
logic [4:0] rd;
logic [31:0] Curr_Instr;
} mem_wb_reg;
endpackage
proc_controller
`timescale 1ns / 1ps
// 主控制器
module Proc_controller (
// ======================== Inputs ========================
input logic [6:0] Opcode, // 7-bit opcode field of the instruction
// ======================== Outputs ========================
// Selection signal for the source of the 2nd ALU operand:
//0: the 2nd read data from the register file;
//1: the immediate value generated by Imm_gen
output logic ALU2ndOperandSrc,
// Selection signal for the source of value used to write the regiser:
// 0: ALU; 1: data memory.
output logic WrRegDataSrc,
// Write register enable
output logic WrRegEn,
// Write memory enable
output logic WrMemEn,
// Read memory enable
output logic RdMemEn,
// 00: LW/SW/AUIPC; 01: Branch;
// 10: Rtype/Itype(Itype wrong!); 11: JAL/LUI/JALR//Itype(include jalr)//这里是考虑到itype中的funct3和rtype中的有重合交叉的指令,辨别不清
output logic [1:0] ALUOp,
//0: branch is not taken; 1: branch is taken
output logic Branch,
//0: Jalr is not taken; 1: jalr is taken
output logic JalrSel,
output logic JalSel,//分开是因为branch选择器对jalr和jal做出不同的处理,jal直接加
// 00:Register Write Back;
// 01: PC+4 write back(JAL/JALR);
// 10: imm-gen write back(LUI);
// 11: pc+imm-gen write back(AUIPC)
output logic [1:0] RWSel
);
logic [10:0] con;
/*****************************************************instruction's Type*****************************************************/
//RType
logic [6:0] RType= 7'b0110011;//include slt
//IType
logic [6:0] ori= 7'b0010011;//andi
logic [6:0] lw= 7'b0000011;//lb,lh,lbu,lhu
logic [6:0] jalr= 7'b1100111;
//UType
logic [6:0] jal= 7'b1101111;//
logic [6:0] lui= 7'b0110111;//
//SType
logic [6:0] sw= 7'b0100011;//sb,sh
logic [6:0] beq= 7'b1100011;//bne,blt,bge,bltu,bgeu
/*****************************************************controll signs*****************************************************/
assign ALU2ndOperandSrc = (Opcode == lw || Opcode == sw || Opcode == ori || Opcode == jalr || Opcode == jal) ? 1'b1 : 1'b0;
assign WrRegDataSrc = (Opcode == lw) ? 1'b1 : 1'b0;
assign WrRegEn = (Opcode == RType || Opcode == lw || Opcode == ori || Opcode == lui || Opcode == jal || Opcode == jalr) ? 1'b1 : 1'b0;
assign RdMemEn = (Opcode == lw) ? 1'b1 : 1'b0;
assign WrMemEn = (Opcode == sw) ? 1'b1 : 1'b0;
assign ALUOp = (Opcode == RType) ? 2'b10 : (Opcode == beq) ? 2'b01 : (Opcode == jal || Opcode == jalr || Opcode == lui || Opcode == ori) ? 2'b11 : 2'b00;
assign Branch = (Opcode == beq) ? 1'b1 : 1'b0;
assign JalrSel = (Opcode == jalr) ? 1'b1 : 1'b0;
assign JalSel = (Opcode == jal) ? 1'b1 : 1'b0;
assign RWSel = (Opcode == jalr || Opcode == jal)? 2'b01 : (Opcode == lui) ? 2'b10 :(Opcode == beq) ? 2'b11 : 2'b00;
endmodule
reg_file
`timescale 1ns / 1ps
// 寄存器文件
module Reg_file #(
parameter DATA_WIDTH = 32, // number of bits in each register
parameter ADDRESS_WIDTH = 5, //number of registers = 2^ADDRESS_WIDTH
parameter NUM_REGS = 2 ** ADDRESS_WIDTH
)(
// Inputs
input clock, //clock
input reset, //synchronous reset; reset all regs to 0 upon assertion.
input write_en, //write enable
input [ADDRESS_WIDTH-1:0] write_addr, //address of the register that supposed to written into
input [DATA_WIDTH-1:0] data_in, // data that supposed to be written into the register file
input [ADDRESS_WIDTH-1:0] read_addr1, //first address to be read from
input [ADDRESS_WIDTH-1:0] read_addr2, //second address to be read from
// Outputs
output logic [DATA_WIDTH-1:0] data_out1, //content of reg_file[read_addr1] is loaded into
output logic [DATA_WIDTH-1:0] data_out2 //content of reg_file[read_addr2] is loaded into
);
integer i;
logic [DATA_WIDTH-1:0] register_file [NUM_REGS-1:0];
always @( negedge clock )
begin
if( reset == 1'b1 )
for (i = 0; i < NUM_REGS ; i = i + 1) begin
register_file [i] <= 0;
end
else if( write_en == 1'b1 && write_addr ) begin
register_file [ write_addr ] <= data_in;
end
end
assign data_out1 = register_file[read_addr1];
assign data_out2 = register_file[read_addr2];
endmodule
riscv_proc
`timescale 1ns / 1ps
// the top module for the RISC-V processor
// basically, you do not need to modify this file.
module riscv #(
parameter DATA_W = 32
) (
input logic clock,
input logic reset,
output logic [31:0] WB_Data // The ALU_Result
);
logic [6:0] opcode;
logic [6:0] opcode_IDEX;
logic
ALU2ndOperandSrc,
WrRegDataSrc,
RegWrite,
MemRead,
MemWrite,
Branch,
JalrSel;
logic [1:0] RWSel;
logic [1:0] ALUop;
logic [1:0] ALUop_Reg;
logic [6:0] Funct7;
logic [2:0] Funct3;
logic [3:0] Operation;
Proc_controller proc_controller (
opcode,
ALU2ndOperandSrc,
WrRegDataSrc,
RegWrite,
MemWrite,
MemRead,
ALUop,
Branch,
JalrSel,
JalSel,
RWSel
);
ALU_Controller proc_alu_controller (
ALUop_Reg,
Funct7,
Funct3,
opcode_IDEX,
Operation
);
Datapath proc_data_path (
clock,
reset,
RegWrite,
WrRegDataSrc,
ALU2ndOperandSrc,
MemWrite,
MemRead,
Branch,
JalrSel,
JalSel,
ALUop,
RWSel,
Operation,
opcode,
opcode_IDEX,
Funct7,
Funct3,
ALUop_Reg,
WB_Data
);
endmodule
adder
`timescale 1ns / 1ps
// 加法器
module adder #(
parameter WIDTH = 8
) (
input logic [WIDTH-1:0] a,
b,
output logic [WIDTH-1:0] y
);
// add your adder logic here
assign y = a + b;
endmodule
alu_controller
`timescale 1ns / 1ps
// 算数逻辑单元控制器
module ALU_Controller (
input logic [1:0] alu_op, // 2-bit opcode field from the Proc_controller
input logic [6:0] funct7, // insn[31:25]
input logic [2:0] funct3, // insn[14:12]
input logic [6:0] opcode, // insn[6:0] //为了区分Itype和UType中的funct部分与imm部分,例如utype没有funct,但是imm有部分可能与funct有相同的值
output logic [3:0] operation // operation selection for ALU
);
// add your code here.
always_comb begin
case (alu_op)
2'b00: //Store & load
operation = 4'b0010;
2'b01://branch
case (funct3)
3'b000:
operation = 4'b0110; // beq -> sub
3'b001:
operation = 4'b1001; // bne
3'b100:
operation = 4'b1010; // blt
3'b101:
operation = 4'b1011; // bge
3'b110:
operation = 4'b1100; // bltu
3'b111:
operation = 4'b1101; // bgeu
default:begin
operation = 4'b0000;
$display("---------------------------------->Undfined_ALU_controller_Type\n");
end
endcase
2'b10://RType
case (funct3)
3'b000:
case (funct7)
//add
7'b0000000:
operation = 4'b0010;
//sub
7'b0100000:
operation = 4'b0110;
//addi
default:
operation = 4'b0000;
endcase
3'b111://and
operation = 4'b0000;
3'b110://or
operation = 4'b0001;
3'b100://xor
operation = 4'b0111;
3'b101://mul//funct7=0funct3=101
operation = 4'b0011;
3'b010:
case (funct7)
//slt
7'b0000000: operation = 4'b1000;
default:begin
operation = 4'b0000;
$display("---------------------------------->Undfined_ALU_controller_Type\n");
end
endcase
default:begin
operation = 4'b0000;
$display("---------------------------------->Undfined_ALU_controller_Type\n");
end
endcase
2'b11: //IType、Utype
case (opcode)
7'b0010011:
case (funct3)
3'b000: operation = 4'b0010;//addi
3'b111: operation = 4'b0000;//andi
3'b110: operation = 4'b0001;//ori
3'b101: operation = 4'b0011;//muli
default: operation = 4'b0000;
endcase
default:operation = 4'b0010;//jalr
endcase
endcase
end
endmodule
alu
`timescale 1ns / 1ps
// 算数逻辑单元
module alu #(
parameter DATA_WIDTH = 32,
parameter OPCODE_LENGTH = 4
) (
input logic signed [ DATA_WIDTH - 1 : 0] operand_a,
input logic signed [ DATA_WIDTH - 1 : 0] operand_b,
input logic [OPCODE_LENGTH - 1 : 0] alu_ctrl, // Operation
output logic signed [ DATA_WIDTH - 1 : 0] alu_result,
output logic zero
);
logic [31:0] s;
logic [31:0] signed_s, unsigned_operand_a, unsigned_operand_b;
// modify this
//这里面没有考虑无符号整数和有符号整数
assign unsigned_operand_a = operand_a;
assign unsigned_operand_b = operand_b;
always_comb begin
// modify this
case (alu_ctrl)
4'b0000: //and
alu_result = operand_a & operand_b;
4'b0001: //or
alu_result = operand_a | operand_b;
4'b0010: //add
alu_result = operand_a + operand_b;
4'b0110: //sub include beq
alu_result = operand_a - operand_b;
4'b0111: //xor
alu_result = operand_a ^ operand_b;
4'b0011: //mul、muli
alu_result = operand_a * operand_b;
4'b1000: //slt
alu_result = (operand_a < operand_b) ? 1'b1 : 1'b0;
4'b1001: //bne
alu_result = (operand_a != operand_b) ? 1'b0 : 1'b1;
4'b1010: //blt
alu_result = (operand_a < operand_b) ? 1'b0 : 1'b1;
4'b1011: //bge
alu_result = (operand_a >= operand_b) ? 1'b0 : 1'b1;
4'b1100: //bltu
alu_result = (unsigned_operand_a < unsigned_operand_b) ? 1'b0 : 1'b1;
4'b1101: //bgeu
alu_result = (unsigned_operand_a >= unsigned_operand_b) ? 1'b0 : 1'b1;
default: begin
alu_result = 32'b0;
$display("---------------------------------->Undfined_ALU_Type\n");
end
endcase
assign zero = (alu_result == 0) ? 1'b1 : 1'b0;
//$display("this operation: oper_a:%x oper_b:%x ctrl:%x result:%x", operand_a, operand_b, alu_ctrl, alu_result);
end
endmodule
branch_unit
`timescale 1ns / 1ps
// 跳转单元
module BranchUnit #(
parameter PC_W = 9
) (
input logic [PC_W - 1:0] cur_pc,
input logic [ 31:0] imm,
input logic jalr_sel,
input logic jal_sel,
input logic branch_taken, // Branch
input logic [ 31:0] alu_result,
output logic [ 31:0] pc_plus_imm, // PC + imm
output logic [ 31:0] pc_plus_4, // PC + 4
output logic [ 31:0] branch_target, // BrPC
output logic pc_sel
);
logic [31:0] pc;
assign pc = {23'b0, cur_pc};
always_comb begin
pc_plus_4 = pc + 4;//3'b100;
pc_plus_imm = (jalr_sel) //jal与jalr进行的操作不一样,根本原因在于jalr有用到寄存器rs1,而jal只用到了imm
? (alu_result >> 1) << 1/*这里将alu_reslut的最低为置为0,alu_result的值为rs1+imm*/
: pc + imm ;//{double_pc_plus_imm[31:0],1'b0}//将sum最低位置0的另外一种方法
pc_sel = ((branch_taken && alu_result == 0) || jalr_sel || jal_sel) ? 1'b1 : 1'b0;
branch_target = pc_plus_imm;
end
endmodule
data_mem
`timescale 1ns / 1ps
// 数据存储器
module datamemory #(
parameter ADDR_WIDTH = 12,
parameter DATA_WIDTH = 32
) (
input logic clock,
input logic read_en,
input logic write_en,
input logic [ADDR_WIDTH -1 : 0] address, // read/write address
input logic [DATA_WIDTH -1 : 0] data_in, // write Data
input logic [ 2:0] funct3, // insn[14:12]
output logic [DATA_WIDTH -1 : 0] data_out // read data
);
logic [7 : 0] MEM[(2**12) - 1 : 0] ;//一开始没考虑读或写一字节2字节4字节的区别
logic sin01, sin00;//没用上》-《
always @(posedge clock)
if (write_en) begin
// modify this. Note the data width
case(funct3)
3'b000://sb
begin
MEM[address] <= data_in[7:0];
end
3'b001://sh
begin
MEM[address] <= data_in[7:0];
MEM[address + 1] <= data_in[15:8];
end
3'b010://sw
begin
MEM[address] <= data_in[7:0];
MEM[address + 1] <= data_in[15:8];
MEM[address + 2] <= data_in[23:16];
MEM[address + 3] <= data_in[31:24];
end
endcase
end
// maybe some extra code here
always_comb begin
if (read_en) begin
// modify this
data_out = 32'b0;
case(funct3)
3'b000://lb
begin
data_out = {{(24){MEM[address][7]}},MEM[address]};
end
3'b001://lh
begin
data_out = {{(16){MEM[address+1][7]}}, MEM[address + 1],MEM[address]};
end
3'b010://lw
begin
//data_out = {MEM[address],MEM[address + 1],MEM[address + 2],MEM[address + 3]};
data_out[31:24] = MEM[address + 3];//8'b00000001;
data_out[23:16] = MEM[address + 2];//8'b00110010;
data_out[15:8] = MEM[address + 1];//8'b01010100;
data_out[7:0] = MEM[address];//8'b01110110;
end
3'b100://lhu
begin
data_out[7:0] = MEM[address];//8'b01110110;
end
3'b101://lbu
begin
data_out[15:8] = MEM[address + 1];//8'b01010100;
data_out[7:0] = MEM[address];//8'b01110110;
end
endcase
end
end
endmodule
flipflop
`timescale 1ns / 1ps
//
// Module Name: flipflop
// Description: An edge-triggered register
// When reset is `1`, the value of the register is set to 0.
// 当reset被置为1时,重置该寄存器的信号为全0
// Otherwise:
// 否则
// - if stall is set, the register preserves its original data
// - else, it is updated by `d`.
// 如果stall被置为1,寄存器保留原来的值,stall被置为0,将d的值写入寄存器
//
// 边沿触发寄存器
module flipflop # (
parameter WIDTH = 8
)(
input logic clock,
input logic reset,
input logic [WIDTH-1:0] d,
input logic stall,
output logic [WIDTH-1:0] q
);
always_ff @(posedge clock, posedge reset)
begin
if (reset)
q <= 0;
else if (!stall)
q <= d;
end
endmodule
forwarding_unit
`timescale 1ns / 1ps
// 数据定向处理单元
module ForwardingUnit (
input logic [4:0] rs1,
input logic [4:0] rs2,
input logic [4:0] ex_mem_rd,
input logic [4:0] mem_wb_rd,
input logic ex_mem_regwrite,
input logic mem_wb_regwrite,
output logic [1:0] forward_a,
output logic [1:0] forward_b
);
// define your forwarding logic here.
// forward_a & forward_b 见书P300
assign forward_a =
((ex_mem_regwrite) && (ex_mem_rd != 0) && (ex_mem_rd == rs1)) ? 2'b10 :
((mem_wb_regwrite) && (mem_wb_rd != 5'b0) && (rs1 == mem_wb_rd)) ? 2'b01 :
2'b00 ;
assign forward_b =
((ex_mem_regwrite) && (ex_mem_rd != 0) && (rs2 == ex_mem_rd)) ? 2'b10 :
((mem_wb_regwrite) && (mem_wb_rd != 5'b0) && (rs2 == mem_wb_rd)) ? 2'b01 :
2'b00 ;
endmodule
hazard_detector
`timescale 1ns / 1ps
// 冒险探测器(阻塞生成器)
module Hazard_detector (
input logic clock,
input logic reset,
input logic [4:0] if_id_rs1,
input logic [4:0] if_id_rs2,
input logic [4:0] id_ex_rd,
input logic id_ex_memread,
output logic stall
);
// define your hazard detection logic here
logic [1:0] counter;
always @(negedge clock) begin
stall <= (id_ex_memread && ((id_ex_rd == if_id_rs1) || (id_ex_rd == if_id_rs2)))? 1'b1 : 1'b0;
end
endmodule
imm_gen
`timescale 1ns / 1ps
// 立即数扩展
module Imm_gen (
input logic [31:0] inst_code,
output logic [31:0] imm_out
);
logic [6:0] test;
assign test = inst_code[6:0];
always_comb begin
imm_out = 32'b0;//init but seem not been used
case (test)
7'b0110011://Rtype 用不到imm
imm_out = 32'b0;
7'b0010011://addi ori 等都是零扩展lw是符号拓展?//the answer is signed extend
imm_out = {{20{inst_code[31]}},inst_code[31:20]};
7'b0000011,7'b1100111://lw//jalr
imm_out = {{(20){inst_code[31]}},inst_code[31:20]};
7'b0110111://lui
imm_out = inst_code[31:12] << 12;
7'b1101111://jal
imm_out = {{10{inst_code[31]}},inst_code[31],inst_code[19:12],inst_code[20],inst_code[30:21],1'b0};
7'b0100011://35://sw
begin
imm_out[11:5] = inst_code[31:25];
imm_out[4:0] = inst_code[11:7];
end
7'b1100011://beq
imm_out = {{(19){inst_code[31]}},inst_code[31],inst_code[7],inst_code[30:25],inst_code[11:8],1'b0} ;//
default: imm_out = 32'b0;
endcase
end
endmodule
insn_mem
`timescale 1ns / 1ps
//
// 指令存储器?
module Insn_mem #(
parameter ADDR_WIDTH = 9,
parameter INSN_WIDTH = 32
)(
input logic [ADDR_WIDTH - 1 : 0] read_address,
output logic [INSN_WIDTH - 1 : 0] insn
);
logic [INSN_WIDTH-1 :0] insn_array [(2**(ADDR_WIDTH - 2))-1:0];
assign insn = insn_array[read_address[ADDR_WIDTH - 1 : 2]];
endmodule
mux2
`timescale 1ns / 1ps
// 二端口多路选择器
module mux2 #(
parameter WIDTH = 32
) (
input logic [WIDTH-1:0] d0,
d1,
input logic s,
output logic [WIDTH-1:0] y
);
assign y = s ? d1 : d0;
endmodule
mux4
`timescale 1ns / 1ps
// 四端口多路选择器
module mux4 #(
parameter WIDTH = 32
) (
input logic [WIDTH-1:0] d00,
input logic [WIDTH-1:0] d01,
input logic [WIDTH-1:0] d10,
input logic [WIDTH-1:0] d11,
input logic [1:0] s,
output logic [WIDTH-1:0] y
);
// add your logic here
assign y = (s == 2'b00) ? d00 :
(s == 2'b01) ? d01 :
(s == 2'b10) ? d10 :
d11 ;
endmodule