rv32g-core

Pipelined, synthesizable, and fabricable RISC-V core in SystemVerilog+Yosys+OpenROAD
Log | Files | Refs | LICENSE

rv32g_hart.sv (9365B)


      1 module rv32g_hart
      2   import rv32g_pkg::*;
      3    (input logic		clk,
      4     input logic		rstN,
      5 
      6     output logic [31:0]	imem_addr,
      7     input logic [31:0]	imem_data,
      8     input logic		imem_valid,
      9 
     10     output logic [31:0]	dmem_addr,
     11     input logic		dmem_valid,
     12     input logic [31:0]	dmem_rdata,
     13     output logic [31:0]	dmem_wdata,
     14     output logic	dmem_we,
     15     output logic [3:0]	dmem_be,
     16 
     17     output reg_t	pc_out,
     18 
     19     output exception_t	exception);
     20 
     21    reg_t	next_pc;
     22 
     23    // pipeline registers
     24    ifid_reg_t	ifid_reg;
     25    idex_reg_t	idex_reg;
     26    exmem_reg_t	exmem_reg;
     27    memwb_reg_t	memwb_reg;
     28 
     29    // temporary fetch signals
     30    logic [31:0]	fetch_inst, ifid_inst, replay_inst;
     31    logic	replay_valid;
     32    reg_t	pc_reg, pc_plus4; // pre-computed registered +4 for critical path
     33 
     34    // temporary decode signals
     35    ctrl_t	dec_ctrl;
     36    reg_t	dec_pc, dec_imm, idex_rs1_val, idex_rs2_val;
     37    logic [4:0]	dec_rs1_num, dec_rs2_num, dec_rd_num;
     38 
     39    // temporary execute signals
     40    reg_t	ex_rs1_val, ex_rs2_val, ex_alu_out, ex_jalr_target, ex_wb_value;
     41    logic	ex_branch_taken;
     42 
     43    // temporary memory signals
     44    loadop_t	mem_loadop;
     45    storeop_t	mem_storeop;
     46    logic [31:0]	mem_mem_out;
     47    reg_t	memwb_value;
     48 
     49    // temporary writeback signals
     50    logic	wb_valid, wb_we;
     51 
     52    // hazards and control flow
     53    logic	dec_uses_rs1, dec_uses_rs2;
     54    forward_t	dec_rs1_forward, dec_rs2_forward;
     55    logic	load_use_stall;
     56    logic	redirect_valid;
     57    reg_t	redirect_target;
     58 
     59    // =============
     60    // === FETCH ===
     61    // =============
     62 
     63    assign pc_out = pc_reg;
     64    assign ifid_inst = replay_valid ? replay_inst : fetch_inst;
     65 
     66    stage_fetch u_fetch(.clk, .rstN, .flush_i(idex_reg.valid && idex_reg.ctrl.fence_flush),
     67 		       .pc(pc_reg), .imem_addr, .imem_data, .imem_valid,
     68 		       .inst(fetch_inst));
     69    // IF/ID pipeline register
     70    always_ff @(posedge clk) begin
     71      if (!rstN) begin
     72        pc_reg <= BASE_ADDR;
     73        pc_plus4 <= BASE_ADDR + 4;
     74        ifid_reg.valid <= 1'b0;
     75        replay_valid <= 1'b0;
     76      end else if (redirect_valid) begin
     77        pc_reg <= redirect_target;
     78        pc_plus4 <= redirect_target + 4;
     79        ifid_reg.valid <= 1'b0;
     80        replay_valid <= 1'b0;
     81      end else if (load_use_stall) begin
     82        if (!replay_valid) replay_inst <= fetch_inst;
     83        replay_valid <= 1'b1;
     84      end else begin
     85        pc_reg <= next_pc;
     86        pc_plus4 <= next_pc + 4;
     87        ifid_reg.valid <= 1'b1;
     88        ifid_reg.pc <= pc_reg;
     89        replay_valid <= 1'b0;
     90      end
     91    end
     92 
     93    // ==============
     94    // === DECODE ===
     95    // ==============
     96 
     97    stage_decode u_decode(.clk, .rstN, .inst(ifid_inst),
     98 			 .wb_we, .wb_rd_num(memwb_reg.rd_num), .wb_data(memwb_value),
     99 			 .ctrl(dec_ctrl), .imm(dec_imm),
    100 			 .rs1_num(dec_rs1_num), .rs2_num(dec_rs2_num),
    101 			 .rs1_val(idex_rs1_val), .rs2_val(idex_rs2_val),
    102 			 .rd_num(dec_rd_num));
    103 
    104    // assign control hazard signals
    105    always_comb begin
    106      dec_uses_rs1 = 1'b0;
    107      dec_uses_rs2 = 1'b0;
    108      dec_rs1_forward = FWD_REG;
    109      dec_rs2_forward = FWD_REG;
    110 
    111      unique case (opcode_t'(ifid_inst[6:0]))
    112        OPCODE_JALR, OPCODE_LOAD, OPCODE_OP_IMM: dec_uses_rs1 = 1'b1;
    113        OPCODE_BRANCH, OPCODE_STORE, OPCODE_OP: begin
    114          dec_uses_rs1 = 1'b1;
    115          dec_uses_rs2 = 1'b1;
    116        end
    117        default: ;
    118      endcase
    119 
    120      if (dec_uses_rs1 && dec_rs1_num != 0) begin
    121        if (idex_reg.valid && idex_reg.ctrl.wbsrc != WB_NONE &&
    122 	   idex_reg.ctrl.wbsrc != WB_MEM && idex_reg.rd_num == dec_rs1_num)
    123 	 dec_rs1_forward = FWD_EXMEM;
    124        else if (exmem_reg.valid && exmem_reg.wbsrc != WB_NONE &&
    125 		exmem_reg.wbsrc != WB_MEM && exmem_reg.rd_num == dec_rs1_num)
    126 	 dec_rs1_forward = FWD_MEMWB;
    127      end
    128 
    129      if (dec_uses_rs2 && dec_rs2_num != 0) begin
    130        if (idex_reg.valid && idex_reg.ctrl.wbsrc != WB_NONE &&
    131 	   idex_reg.ctrl.wbsrc != WB_MEM && idex_reg.rd_num == dec_rs2_num)
    132 	 dec_rs2_forward = FWD_EXMEM;
    133        else if (exmem_reg.valid && exmem_reg.wbsrc != WB_NONE &&
    134 		exmem_reg.wbsrc != WB_MEM && exmem_reg.rd_num == dec_rs2_num)
    135 	 dec_rs2_forward = FWD_MEMWB;
    136      end
    137 
    138      load_use_stall = ifid_reg.valid && imem_valid &&
    139 		      ((idex_reg.valid && idex_reg.ctrl.wbsrc == WB_MEM &&
    140 			idex_reg.rd_num != 0 &&
    141 			((dec_uses_rs1 && dec_rs1_num == idex_reg.rd_num) ||
    142 			 (dec_uses_rs2 && dec_rs2_num == idex_reg.rd_num))) ||
    143 		       (exmem_reg.valid && exmem_reg.wbsrc == WB_MEM &&
    144 			exmem_reg.rd_num != 0 &&
    145 			((dec_uses_rs1 && dec_rs1_num == exmem_reg.rd_num) ||
    146 			 (dec_uses_rs2 && dec_rs2_num == exmem_reg.rd_num))));
    147    end
    148 
    149    // ID/EX pipeline register
    150    always_ff @(posedge clk or negedge rstN) begin
    151      if (!rstN) begin
    152        idex_reg <= '0;
    153      end else if (redirect_valid || load_use_stall) begin
    154        idex_reg.valid <= 1'b0;
    155      end else begin
    156        // latch decode outputs in normal operation
    157        idex_reg.valid <= ifid_reg.valid && imem_valid;
    158        idex_reg.ctrl <= dec_ctrl;
    159        idex_reg.pc <= ifid_reg.pc;
    160        idex_reg.imm <= dec_imm;
    161        idex_reg.rs1_forward <= dec_rs1_forward;
    162        idex_reg.rs2_forward <= dec_rs2_forward;
    163        idex_reg.rd_num <= dec_rd_num;
    164      end
    165    end
    166 
    167    // ===============
    168    // === EXECUTE ===
    169    // ===============
    170 
    171    // select EX stage operands via forwarding from EX/MEM and MEM/WB pipeline registers
    172    always_comb begin
    173      unique case (idex_reg.ctrl.wbsrc)
    174        WB_PC: ex_wb_value = idex_reg.pc + 4;
    175        WB_ALU: ex_wb_value = ex_alu_out;
    176        WB_IMM: ex_wb_value = idex_reg.imm;
    177        default: ex_wb_value = '0;
    178      endcase
    179 
    180      memwb_value = memwb_reg.wbsrc == WB_MEM ? mem_mem_out :
    181 		   memwb_reg.wb_value;
    182 
    183      unique case (idex_reg.rs1_forward)
    184        FWD_REG: ex_rs1_val = idex_rs1_val;
    185        FWD_EXMEM: ex_rs1_val = exmem_reg.wb_value;
    186        FWD_MEMWB: ex_rs1_val = memwb_reg.wb_value;
    187        default: ex_rs1_val = '0;
    188      endcase
    189 
    190      unique case (idex_reg.rs2_forward)
    191        FWD_REG: ex_rs2_val = idex_rs2_val;
    192        FWD_EXMEM: ex_rs2_val = exmem_reg.wb_value;
    193        FWD_MEMWB: ex_rs2_val = memwb_reg.wb_value;
    194        default: ex_rs2_val = '0;
    195      endcase
    196    end
    197 
    198    stage_execute u_execute(.clk,
    199 			   .imm(idex_reg.imm),
    200 			   .pc(idex_reg.pc),
    201 			   .rs1_val(ex_rs1_val),
    202 			   .rs2_val(ex_rs2_val),
    203 			   .op(idex_reg.ctrl.aluop),
    204 			   .op1src(idex_reg.ctrl.aluop1src),
    205 			   .op2src(idex_reg.ctrl.aluop2src),
    206 			   .branchop(idex_reg.ctrl.branchop),
    207 			   .out(ex_alu_out),
    208 			   .branch_taken(ex_branch_taken),
    209 			   .jalr_target(ex_jalr_target));
    210    // EX/MEM pipeline register
    211    always_ff @(posedge clk or negedge rstN) begin
    212      if (!rstN) begin
    213        exmem_reg <= '0;
    214      end else begin
    215        exmem_reg.valid <= idex_reg.valid;
    216        exmem_reg.alu_out <= ex_alu_out;
    217        exmem_reg.rs2_val <= ex_rs2_val;
    218        exmem_reg.wb_value <= ex_wb_value;
    219        exmem_reg.rd_num <= idex_reg.rd_num;
    220        exmem_reg.branch_taken <= ex_branch_taken;
    221        exmem_reg.branchop <= idex_reg.ctrl.branchop;
    222        exmem_reg.loadop <= idex_reg.ctrl.loadop;
    223        exmem_reg.storeop <= idex_reg.ctrl.storeop;
    224        exmem_reg.wbsrc <= idex_reg.ctrl.wbsrc;
    225        exmem_reg.pcsrc <= idex_reg.ctrl.pcsrc;
    226        exmem_reg.exception <= idex_reg.ctrl.exception;
    227        exmem_reg.fence_flush <= idex_reg.ctrl.fence_flush;
    228      end
    229    end
    230 
    231    // resolve control transfers in EX stage and select the next PC
    232    always_comb begin
    233      redirect_valid = 1'b0;
    234      redirect_target = idex_reg.pc + 4;
    235 
    236      if (idex_reg.valid) begin
    237        if (idex_reg.ctrl.fence_flush) begin
    238 	 redirect_valid = 1'b1;
    239        end else begin
    240 	 unique case (idex_reg.ctrl.pcsrc)
    241 	   PC_IMM: begin
    242 	     if (idex_reg.ctrl.branchop == BRANCH_NONE || ex_branch_taken) begin
    243 	       redirect_valid = 1'b1;
    244 	       redirect_target = idex_reg.pc + idex_reg.imm;
    245 	     end
    246 	   end
    247 	   PC_ALU: begin
    248 	     redirect_valid = 1'b1;
    249 	     redirect_target = ex_jalr_target & ~32'b1;
    250 	   end
    251 	   default: ;
    252 	 endcase
    253        end
    254      end
    255 
    256      next_pc = redirect_valid ? redirect_target : pc_plus4;
    257    end
    258 
    259    // ==============
    260    // === MEMORY ===
    261    // ==============
    262 
    263    assign mem_loadop = memwb_reg.valid ? memwb_reg.loadop : LD_NONE;
    264    assign mem_storeop = exmem_reg.valid ? exmem_reg.storeop : ST_NONE;
    265 
    266    stage_memory u_mem(.loadop(mem_loadop),
    267 		      .storeop(mem_storeop),
    268 		      .addr(memwb_reg.alu_out),
    269 		      .alu_out(exmem_reg.alu_out),
    270 		      .rs2_val(exmem_reg.rs2_val),
    271 		      .mem_out(mem_mem_out),
    272 		      .dmem_addr, .dmem_rdata, .dmem_wdata, .dmem_we, .dmem_be);
    273    // MEM/WB pipeline register
    274    always_ff @(posedge clk or negedge rstN) begin
    275      if (!rstN) begin
    276        memwb_reg <= '0;
    277      end else begin
    278        memwb_reg.valid <= exmem_reg.valid;
    279        memwb_reg.alu_out <= exmem_reg.alu_out;
    280        memwb_reg.wb_value <= exmem_reg.wb_value;
    281        memwb_reg.rd_num <= exmem_reg.rd_num;
    282        memwb_reg.loadop <= exmem_reg.loadop;
    283        memwb_reg.storeop <= exmem_reg.storeop;
    284        memwb_reg.wbsrc <= exmem_reg.wbsrc;
    285        memwb_reg.exception <= exmem_reg.exception;
    286      end
    287    end
    288 
    289    // =================
    290    // === WRITEBACK ===
    291    // =================
    292 
    293    // assigns signals that are forwarded back to ID stage
    294    always_comb begin
    295      wb_valid = memwb_reg.valid &&
    296 		(memwb_reg.wbsrc != WB_MEM || dmem_valid);
    297      wb_we = wb_valid && memwb_reg.wbsrc != WB_NONE && memwb_reg.rd_num != 0;
    298    end
    299 
    300    assign exception = memwb_reg.valid ? memwb_reg.exception : EXC_NONE;
    301 
    302 endmodule: rv32g_hart