实验-RISCV流水线处理器设计与实现

目录

  • 实验-RISCV流水线处理器设计与实现
    • 一.流水线设计
    • 二、rtl文件
    • 三、流水线实现思路
      • (一)完成各组件的设计
        • 1.运算单元的设计
        • 2.存储单元的设计
        • 3.控制单元的设计
          • ①proc_controller
          • ②branch_unit
          • ③alu_controller
        • 4.解决冒险问题
          • ①结构冒险
          • ②数据冒险
      • (二)、将各组件连接起来(data_path)
        • 1.设计IF单元并向IF/ID寄存器传入当前指令地址和未解码指令。
        • 2.对data_path的理解
        • data_path
        • pipeline_regs
        • proc_controller
        • reg_file
        • riscv_proc
        • adder
        • alu_controller
        • alu
        • branch_unit
        • data_mem
        • flipflop
        • forwarding_unit
        • hazard_detector
        • imm_gen
        • insn_mem
        • mux2
        • mux4

一.流水线设计

![TheStructureChart]

二、rtl文件

在根目录文件夹下。

三、流水线实现思路

(一)完成各组件的设计

1.运算单元的设计

包含adder,alu,data_mem,imm_gen,mux,基本上都很简单。
根据《RISC_V_Experiment-2022》PPT里的内容就可以实现imm_gen,

比较复杂的是data_mem文件,首先RISC-V采用小端格式,而且根据load/store指令funct3的不同,要进行读/写的长度不一样,不同的指令还要进行不同的符号/无符号扩展,如lhu和lh。

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 Counterparameter INS_W      = 32,  // Instruction Widthparameter DATA_W     = 32,  // reigster widthparameter DM_ADDRESS = 9,   // width of the data memory addressparameter ALU_CC_W   = 4    // width of the ALU Control code
) (input logic clock,// reset , sets the PC to zeroinput logic reset,// Register file writing enableinput logic reg_write_en,// Selection signal for the source of value used to write the regiserinput logic WrRegDataSrc,// Register file or Immediate MUXinput logic alu_src,// Memroy Writing Enableinput logic mem_write_en,// Memroy Reading Enableinput logic mem_read_en,// Branch Enableinput logic branch_taken,// Jalr Mux Selectinput logic jalr_sel,// Jal Instruction distinguish from jalr used in the branch functioninput logic jal_sel,input logic [1:0] alu_op,// Mux4to1 Selectinput 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 registeroutput logic [DATA_W-1:0] wb_data
);// define the pipeline registersif_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 generationassign PCplus4 = PC + 4;assign PC_mux_result = BrFlush ? BrPC : PCplus4;always @(posedge clock) begin//stall, do not update the PCPC <= reset ? 0 :  stall  ? PC : PC_mux_result;//①:如果遇到reset指令,则将pc进行初始化//②:如果遇到stall则不执行下一条指令//这里pc赋值必须用<=而不能用=end// your instruction memoryInsn_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_Registerif(!stall) beginPipeRegIFID.Curr_Pc    <= (reset|BrFlush) ? 9'b0:PC;PipeRegIFID.Curr_Instr <= (reset|BrFlush) ? 32'b0:instr;endend// ====================================================================================//                                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_Registerif (reset | stall | BrFlush) beginPipeRegIDEX.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) beginPipeRegIDEX.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;endend// ====================================================================================//                                    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_Registerif (reset) beginPipeRegEXMEM.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 beginPipeRegEXMEM.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;endend// ====================================================================================//                                    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_Registerif (reset) beginPipeRegMEWB.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 beginPipeRegMEWB.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);endend// ====================================================================================//                                  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 Atypedef struct packed{logic [8:0]     Curr_Pc;logic [31:0]    Curr_Instr;} if_id_reg;// Reg Btypedef 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_Instrlogic [4:0]     RS_Two;     // 2nd read register address of Curr_Instrlogic [4:0]     rd;         // dst register to write of Curr_Instrlogic [31:0]    ImmG;       // Immediate value generated by Imm_genlogic [2:0]     func3;logic [6:0]     func7;logic [31:0]    Curr_Instr;} id_ex_reg;// Reg Ctypedef 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 memorylogic [4:0]     rd;         // dst register to write of Curr_Instrlogic [2:0]     func3;logic [6:0]     func7;logic [31:0]    Curr_Instr;} ex_mem_reg;// Reg Dtypedef 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_genoutput logic ALU2ndOperandSrc,// Selection signal for the source of value used to write the regiser:// 0: ALU; 1: data memory.output logic WrRegDataSrc,// Write register enableoutput logic WrRegEn,// Write memory enableoutput logic WrMemEn,// Read memory enableoutput 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 takenoutput logic Branch,//0: Jalr is not taken; 1: jalr is takenoutput 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*****************************************************///RTypelogic [6:0] RType= 7'b0110011;//include slt//ITypelogic [6:0] ori= 7'b0010011;//andilogic [6:0] lw= 7'b0000011;//lb,lh,lbu,lhulogic [6:0] jalr= 7'b1100111;//UTypelogic [6:0] jal= 7'b1101111;//logic [6:0] lui= 7'b0110111;////STypelogic [6:0] sw= 7'b0100011;//sb,shlogic [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 registerparameter ADDRESS_WIDTH = 5, //number of registers = 2^ADDRESS_WIDTHparameter NUM_REGS      = 2 ** ADDRESS_WIDTH
)(// Inputsinput  clock,                  //clockinput  reset,                  //synchronous reset; reset all regs to 0  upon assertion.input  write_en,            //write enableinput  [ADDRESS_WIDTH-1:0] write_addr, //address of the register that supposed to written intoinput  [DATA_WIDTH-1:0]    data_in, // data that supposed to be written into the register fileinput  [ADDRESS_WIDTH-1:0] read_addr1, //first address to be read frominput  [ADDRESS_WIDTH-1:0] read_addr2, //second address to be read from// Outputsoutput logic [DATA_WIDTH-1:0] data_out1, //content of reg_file[read_addr1] is loaded intooutput 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 )
beginif( reset == 1'b1 )for (i = 0; i < NUM_REGS ; i = i + 1) beginregister_file [i] <= 0;endelse if( write_en == 1'b1 && write_addr ) beginregister_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;logicALU2ndOperandSrc,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 hereassign 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_controllerinput  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 begincase (alu_op)2'b00: //Store & loadoperation = 4'b0010;2'b01://branch case (funct3)3'b000: operation = 4'b0110; // beq -> sub3'b001: operation = 4'b1001; // bne3'b100: operation = 4'b1010; // blt3'b101: operation = 4'b1011; // bge3'b110: operation = 4'b1100; // bltu3'b111: operation = 4'b1101; // bgeudefault:beginoperation = 4'b0000;$display("---------------------------------->Undfined_ALU_controller_Type\n");end endcase2'b10://RTypecase (funct3)3'b000:case (funct7)//add7'b0000000: operation = 4'b0010;//sub7'b0100000: operation = 4'b0110;//addidefault: operation = 4'b0000;endcase3'b111://andoperation = 4'b0000;3'b110://oroperation = 4'b0001;3'b100://xoroperation = 4'b0111;3'b101://mul//funct7=0funct3=101operation = 4'b0011;3'b010:case (funct7)//slt7'b0000000: operation = 4'b1000;default:beginoperation = 4'b0000;$display("---------------------------------->Undfined_ALU_controller_Type\n");end endcasedefault:beginoperation = 4'b0000;$display("---------------------------------->Undfined_ALU_controller_Type\n");end endcase2'b11: //IType、Utypecase (opcode) 7'b0010011:case (funct3)3'b000: operation = 4'b0010;//addi3'b111: operation = 4'b0000;//andi3'b110: operation = 4'b0001;//ori3'b101: operation = 4'b0011;//mulidefault: operation = 4'b0000;endcasedefault:operation = 4'b0010;//jalrendcaseendcaseendendmodule

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,    // Operationoutput 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 thiscase (alu_ctrl)4'b0000: //andalu_result = operand_a & operand_b;4'b0001: //oralu_result = operand_a | operand_b;4'b0010: //addalu_result = operand_a + operand_b;4'b0110: //sub include beqalu_result = operand_a - operand_b;4'b0111: //xoralu_result = operand_a ^ operand_b;4'b0011: //mul、mulialu_result = operand_a * operand_b;4'b1000: //sltalu_result = (operand_a < operand_b) ? 1'b1 : 1'b0;4'b1001: //bnealu_result = (operand_a != operand_b) ? 1'b0 : 1'b1;4'b1010: //bltalu_result = (operand_a < operand_b) ? 1'b0 : 1'b1;4'b1011: //bgealu_result = (operand_a >= operand_b) ? 1'b0 : 1'b1;4'b1100: //bltualu_result = (unsigned_operand_a < unsigned_operand_b) ? 1'b0 : 1'b1;4'b1101: //bgeualu_result = (unsigned_operand_a >= unsigned_operand_b) ? 1'b0 : 1'b1;default: beginalu_result = 32'b0;$display("---------------------------------->Undfined_ALU_Type\n");end    endcaseassign 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);endendmodule

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,   // Branchinput  logic [      31:0] alu_result,output logic [      31:0] pc_plus_imm,    // PC + immoutput logic [      31:0] pc_plus_4,      // PC + 4output logic [      31:0] branch_target,  // BrPCoutput logic              pc_sel
);logic [31:0] pc;assign pc = {23'b0, cur_pc};always_comb beginpc_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;endendmodule

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 addressinput  logic [DATA_WIDTH -1 : 0] data_in,   // write Datainput  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 widthcase(funct3)3'b000://sbbeginMEM[address] <= data_in[7:0];end3'b001://shbeginMEM[address] <= data_in[7:0];MEM[address + 1] <= data_in[15:8];end3'b010://swbeginMEM[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];endendcaseend// maybe some extra code herealways_comb beginif (read_en) begin// modify thisdata_out = 32'b0;case(funct3)3'b000://lbbegindata_out = {{(24){MEM[address][7]}},MEM[address]};end3'b001://lhbegindata_out = {{(16){MEM[address+1][7]}}, MEM[address + 1],MEM[address]};end3'b010://lwbegin//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;end3'b100://lhubegindata_out[7:0] = MEM[address];//8'b01110110;end3'b101://lbubegindata_out[15:8] = MEM[address + 1];//8'b01010100;data_out[7:0] = MEM[address];//8'b01110110;endendcaseendendendmodule

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)beginif (reset)q <= 0;else if (!stall)q <= d;endendmodule

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 见书P300assign 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 herelogic [1:0] counter;always @(negedge clock) beginstall <= (id_ex_memread && ((id_ex_rd == if_id_rs1) || (id_ex_rd == if_id_rs2)))? 1'b1 : 1'b0;endendmodule

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 beginimm_out = 32'b0;//init but seem not been usedcase (test)7'b0110011://Rtype 用不到immimm_out = 32'b0;7'b0010011://addi ori 等都是零扩展lw是符号拓展?//the answer is signed extendimm_out =  {{20{inst_code[31]}},inst_code[31:20]};7'b0000011,7'b1100111://lw//jalrimm_out = {{(20){inst_code[31]}},inst_code[31:20]};7'b0110111://luiimm_out =  inst_code[31:12] << 12;7'b1101111://jalimm_out = {{10{inst_code[31]}},inst_code[31],inst_code[19:12],inst_code[20],inst_code[30:21],1'b0};7'b0100011://35://swbeginimm_out[11:5] = inst_code[31:25];imm_out[4:0] = inst_code[11:7];end7'b1100011://beqimm_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;endcaseend
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 hereassign y = (s == 2'b00) ? d00 :(s == 2'b01) ? d01 :(s == 2'b10) ? d10 : d11 ;endmodule

简记一次计算机系统课程实验-RISCV流水线处理器设计与实现相关推荐

  1. 微机原理课程实验(十字路口红绿灯设计)

    微机原理课程实验(十字路口红绿灯设计) 软件:protuse 8.4 具体要求 设计实现交通信号灯系统.设A车道与B车道交叉组成十字路口,A是主道,B是支道,直接对车辆进行交通管理,基本要求如下: ( ...

  2. 大学计算机课实验,大学计算机课程实验教学平台的设计与实现

    摘要: 随着信息技术的发展,<大学计算机>作为通识教育的核心课程早已被列入公共必修课程.<大学计算机>课程本身的特点决定了实验教学是整个教学活动中十分重要的环节,实验教学设计要 ...

  3. 湖南大学_数电实验_模型机设计_CPU设计_verilog_课程实验报告

    本学期的数电课程实验就是模型机设计,由四次小实验构成,最后一次实验验收要求使用quartus做出一个模型机. 该实验的重要性:该实验的核心在于基于实验指导书设计CPU,从而帮我们理解CPU的工作原理. ...

  4. 《深入理解计算机系统》实验四Architecture Lab下载和官方文档机翻

    前言 <深入理解计算机系统>官网:http://csapp.cs.cmu.edu/3e/labs.html 该篇文章是是实验四Architecture Lab中的Writeup(archl ...

  5. 计算机文化基础课程实验,山东经贸职业学院计算机文化基础课程实验教学大纲.doc...

    文档介绍: 山东经贸职业学院计算机文化基础课程实验教学大纲计算机文化基础是一门实践性很强的课程,为加深学生对理论知识的理解,提高学生的实际动手能力,必须在理论教学的同时安排适当的上机实验.一.基本要求 ...

  6. 华中科技大学计算机系统基础实验3报告,华中科技大学计算机系统基础实验报告.doc...

    文档介绍: 课程实验报告课程名称:计算机系统基础专业班级:学号:姓名:指导教师:报告日期:2016年5月24日计算机科学与技术学院目录实验1: 2实验2: 9实验3: 22实验总结 30 实验1:数据 ...

  7. 华中科技大学计算机系统基础实验3报告,华中科技大学计算机系统基础实验报告...

    华中科技大学计算机系统基础实验报告 1 课 程 实 验 报 告 课程名称: 计算机系统基础 专业班级: 学 号: 姓 名: 指导教师: 报告日期: 2016年 5月 24 日 计算机科学与技术学院2 ...

  8. 计算机组成原理课内实验,【计算机基础论文】计算机组成原理课程实验教学改革(共2885字)...

    摘要:目前<计算机组成原理>的实验内容存在与课程定位目标相悖的问题,一味追求实验内容的复杂性,而忽视了计算机组成原理实验教学的完整性和概念性.针对上述问题,本文对<计算机组成原理&g ...

  9. 数字信号处理课程实验

    问题重述 DSP课程实验 计算机模拟产生多频率信号: 编写通用的FFT子程序 设置参数,对信号进行频谱分析 对信号分别以满足和不满足奈奎斯特采样定理的采样率进行采样,观察其频谱变化 设计低通.高通.带 ...

最新文章

  1. Gartner:2018年十大科技趋势与其对IT和执行的影响
  2. 图像处理:Hough变换原理分析
  3. 华为鸿蒙公测链接,华为鸿蒙系统2.0启动第二轮公测,新增6款nova机型
  4. ISAkmp载荷头部
  5. (王道408考研操作系统)第二章进程管理-第二节4:调度算法详解2(RR、HPF和MFQ)
  6. 排序sort,统计wc
  7. 对博客园的建议与意见
  8. 微软 Exchange Autodiscover 协议存bug,数十万域凭据可遭泄露
  9. windows下python调用C/C++以及使用C扩展python python通过pythonnet调用C# dll
  10. Centos7解压Zip文件
  11. 请问ECSHOP首页站内快讯在哪里添加和修改?
  12. (百度贴吧发帖)html5,百度贴吧怎么发帖子
  13. Data URL实现用户头像上传
  14. 巴洛克超级学习音乐和罗扎夫记忆音乐实际作用能有多大? - 知乎
  15. 报告预测,到2050年将有超过10亿人流离失所
  16. 简单讲解前序遍历,中序遍历,后序遍历和层次遍历
  17. POJ1017-Packets
  18. Bootstrap栅格布局分析grid源码
  19. 超级详细的注释C语言简单实现童年小游戏:贪吃蛇
  20. java gb18030 转 utf-8_Java:GB18030字节数组与UTF8互转

热门文章

  1. 内存修改器 android,Android 内存修改
  2. 南瑞许继平高相继停牌,国家电网要加快整合了吗?
  3. IT面试技巧之亲徒弟的面经分享
  4. SD_Writer write error
  5. 美国国会百万富翁何其多
  6. CAD开发 UCS转WCS(用户坐标转为世界坐标)
  7. Hive优化【提高效率,减少资源浪费等】
  8. 如何利用ChatPDF快速阅读英文论文,帮你写作业
  9. 量化投资在中国行得通吗?
  10. 多任务学习原理与优化