../src/lowrisc_ibex_ibex_core_0.1/rtl/ibex_wb_stage.sv Cov: 72.9%

   1: // Copyright lowRISC contributors.
   2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   3: // SPDX-License-Identifier: Apache-2.0
   4: 
   5: /**
   6:  * Writeback Stage
   7:  *
   8:  * Writeback is an optional third pipeline stage. It writes data back to the register file that was
   9:  * produced in the ID/EX stage or awaits a response to a load/store (LSU writes direct to register
  10:  * file for load data). If the writeback stage is not present (WritebackStage == 0) this acts as
  11:  * a simple passthrough to write data direct to the register file.
  12:  */
  13: 
  14: `include "prim_assert.sv"
  15: 
  16: module ibex_wb_stage #(
  17:   parameter bit WritebackStage = 1'b0
  18: ) (
  19:   input  logic                     clk_i,
  20:   input  logic                     rst_ni,
  21: 
  22:   input  logic                     en_wb_i,
  23:   input  ibex_pkg::wb_instr_type_e instr_type_wb_i,
  24:   input  logic [31:0]              pc_id_i,
  25: 
  26:   output logic                     ready_wb_o,
  27:   output logic                     rf_write_wb_o,
  28:   output logic                     outstanding_load_wb_o,
  29:   output logic                     outstanding_store_wb_o,
  30:   output logic [31:0]              pc_wb_o,
  31: 
  32:   input  logic [4:0]               rf_waddr_id_i,
  33:   input  logic [31:0]              rf_wdata_id_i,
  34:   input  logic                     rf_we_id_i,
  35: 
  36:   input  logic [31:0]              rf_wdata_lsu_i,
  37:   input  logic                     rf_we_lsu_i,
  38: 
  39:   output logic [31:0]              rf_wdata_fwd_wb_o,
  40: 
  41:   output logic [4:0]               rf_waddr_wb_o,
  42:   output logic [31:0]              rf_wdata_wb_o,
  43:   output logic                     rf_we_wb_o,
  44: 
  45:   input logic                      lsu_resp_valid_i,
  46: 
  47:   output logic                     instr_done_wb_o
  48: );
  49: 
  50:   import ibex_pkg::*;
  51: 
  52:   // 0 == RF write from ID
  53:   // 1 == RF write from LSU
  54:   logic [31:0] rf_wdata_wb_mux    [2];
  55:   logic [1:0]  rf_wdata_wb_mux_we;
  56: 
  57:   if(WritebackStage) begin : g_writeback_stage
  58:     logic [31:0]    rf_wdata_wb_q;
  59:     logic           rf_we_wb_q;
  60:     logic [4:0]     rf_waddr_wb_q;
  61: 
  62:     logic           wb_done;
  63: 
  64:     logic           wb_valid_q;
  65:     logic [31:0]    wb_pc_q;
  66:     wb_instr_type_e wb_instr_type_q;
  67: 
  68:     logic           wb_valid_d;
  69: 
  70:     // Stage becomes valid if an instruction enters for ID/EX and valid is cleared when instruction
  71:     // is done
  72:     assign wb_valid_d = (en_wb_i & ready_wb_o) | (wb_valid_q & ~wb_done);
  73: 
  74:     // Writeback for non load/store instructions always completes in a cycle (so instantly done)
  75:     // Writeback for load/store must wait for response to be received by the LSU
  76:     // Signal only relevant if wb_valid_q set
  77:     assign wb_done = (wb_instr_type_q == WB_INSTR_OTHER) | lsu_resp_valid_i;
  78: 
  79:     always_ff @(posedge clk_i or negedge rst_ni) begin
  80:       if(~rst_ni) begin
  81:         wb_valid_q <= 1'b0;
  82:       end else begin
  83:         wb_valid_q <= wb_valid_d;
  84:       end
  85:     end
  86: 
  87:     always_ff @(posedge clk_i) begin
  88:       if(en_wb_i) begin
  89:         rf_we_wb_q      <= rf_we_id_i;
  90:         rf_waddr_wb_q   <= rf_waddr_id_i;
  91:         rf_wdata_wb_q   <= rf_wdata_id_i;
  92:         wb_instr_type_q <= instr_type_wb_i;
  93:         wb_pc_q         <= pc_id_i;
  94:       end
  95:     end
  96: 
  97:     assign rf_waddr_wb_o         = rf_waddr_wb_q;
  98:     assign rf_wdata_wb_mux[0]    = rf_wdata_wb_q;
  99:     assign rf_wdata_wb_mux_we[0] = rf_we_wb_q & wb_valid_q;
 100: 
 101:     assign ready_wb_o = ~wb_valid_q | wb_done;
 102: 
 103:     // Instruction in writeback will be writing to register file if either rf_we is set or writeback
 104:     // is awaiting load data. This is used for determining RF read hazards in ID/EX
 105:     assign rf_write_wb_o = wb_valid_q & (rf_we_wb_q | (wb_instr_type_q == WB_INSTR_LOAD));
 106: 
 107:     assign outstanding_load_wb_o  = wb_valid_q & (wb_instr_type_q == WB_INSTR_LOAD);
 108:     assign outstanding_store_wb_o = wb_valid_q & (wb_instr_type_q == WB_INSTR_STORE);
 109: 
 110:     assign pc_wb_o = wb_pc_q;
 111: 
 112:     assign instr_done_wb_o = wb_valid_q & wb_done;
 113: 
 114:     // Forward data that will be written to the RF back to ID to resolve data hazards. The flopped
 115:     // rf_wdata_wb_q is used rather than rf_wdata_wb_o as the latter includes read data from memory
 116:     // that returns too late to be used on the forwarding path.
 117:     assign rf_wdata_fwd_wb_o = rf_wdata_wb_q;
 118:   end else begin : g_bypass_wb
 119:     // without writeback stage just pass through register write signals
 120:     assign rf_waddr_wb_o         = rf_waddr_id_i;
 121:     assign rf_wdata_wb_mux[0]    = rf_wdata_id_i;
 122:     assign rf_wdata_wb_mux_we[0] = rf_we_id_i;
 123: 
 124:     // ready needs to be constant 1 without writeback stage (otherwise ID/EX stage will stall)
 125:     assign ready_wb_o    = 1'b1;
 126: 
 127:     // Unused Writeback stage only IO & wiring
 128:     // Assign inputs and internal wiring to unused signals to satisfy lint checks
 129:     // Tie-off outputs to constant values
 130:     logic           unused_clk;
 131:     logic           unused_rst;
 132:     logic           unused_en_wb;
 133:     wb_instr_type_e unused_instr_type_wb;
 134:     logic [31:0]    unused_pc_id;
 135:     logic           unused_lsu_resp_valid;
 136: 
 137:     assign unused_clk            = clk_i;
 138:     assign unused_rst            = rst_ni;
 139:     assign unused_en_wb          = en_wb_i;
 140:     assign unused_instr_type_wb  = instr_type_wb_i;
 141:     assign unused_pc_id          = pc_id_i;
 142:     assign unused_lsu_resp_valid = lsu_resp_valid_i;
 143: 
 144:     assign outstanding_load_wb_o  = 1'b0;
 145:     assign outstanding_store_wb_o = 1'b0;
 146:     assign pc_wb_o                = '0;
 147:     assign rf_write_wb_o          = 1'b0;
 148:     assign rf_wdata_fwd_wb_o      = 32'b0;
 149:     assign instr_done_wb_o        = 1'b0;
 150:   end
 151: 
 152:   assign rf_wdata_wb_mux[1]    = rf_wdata_lsu_i;
 153:   assign rf_wdata_wb_mux_we[1] = rf_we_lsu_i;
 154: 
 155:   // RF write data can come from ID results (all RF writes that aren't because of loads will come
 156:   // from here) or the LSU (RF writes for load data)
 157:   assign rf_wdata_wb_o = rf_wdata_wb_mux_we[0] ? rf_wdata_wb_mux[0] : rf_wdata_wb_mux[1];
 158:   assign rf_we_wb_o    = |rf_wdata_wb_mux_we;
 159: 
 160:   `ASSERT(RFWriteFromOneSourceOnly, $onehot0(rf_wdata_wb_mux_we))
 161: endmodule
 162: