hw/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv Cov: 100%

   1: // Copyright lowRISC contributors.
   2: // Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
   3: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   4: // SPDX-License-Identifier: Apache-2.0
   5: 
   6: /**
   7:  * Instruction Fetch Stage
   8:  *
   9:  * Instruction fetch unit: Selection of the next PC, and buffering (sampling) of
  10:  * the read instruction.
  11:  */
  12: module ibex_if_stage #(
  13:     parameter int unsigned DmHaltAddr      = 32'h1A110800,
  14:     parameter int unsigned DmExceptionAddr = 32'h1A110808
  15: ) (
  16:     input  logic                   clk_i,
  17:     input  logic                   rst_ni,
  18: 
  19:     input  logic [31:0]            boot_addr_i,              // also used for mtvec
  20:     input  logic                   req_i,                    // instruction request control
  21: 
  22:     // instruction cache interface
  23:     output logic                  instr_req_o,
  24:     output logic [31:0]           instr_addr_o,
  25:     input  logic                  instr_gnt_i,
  26:     input  logic                  instr_rvalid_i,
  27:     input  logic [31:0]           instr_rdata_i,
  28:     input  logic                  instr_err_i,
  29:     input  logic                  instr_pmp_err_i,
  30: 
  31:     // output of ID stage
  32:     output logic                  instr_valid_id_o,         // instr in IF-ID is valid
  33:     output logic                  instr_new_id_o,           // instr in IF-ID is new
  34:     output logic [31:0]           instr_rdata_id_o,         // instr for ID stage
  35:     output logic [15:0]           instr_rdata_c_id_o,       // compressed instr for ID stage
  36:                                                             // (mtval), meaningful only if
  37:                                                             // instr_is_compressed_id_o = 1'b1
  38:     output logic                  instr_is_compressed_id_o, // compressed decoder thinks this
  39:                                                             // is a compressed instr
  40:     output logic                  instr_fetch_err_o,        // bus error on fetch
  41:     output logic                  illegal_c_insn_id_o,      // compressed decoder thinks this
  42:                                                             // is an invalid instr
  43:     output logic [31:0]           pc_if_o,
  44:     output logic [31:0]           pc_id_o,
  45: 
  46:     // control signals
  47:     input  logic                  instr_valid_clear_i,      // clear instr valid bit in IF-ID
  48:     input  logic                  pc_set_i,                 // set the PC to a new value
  49:     input  ibex_pkg::pc_sel_e     pc_mux_i,                 // selector for PC multiplexer
  50:     input  ibex_pkg::exc_pc_sel_e exc_pc_mux_i,             // selects ISR address
  51:     input  ibex_pkg::exc_cause_e  exc_cause,                // selects ISR address for
  52:                                                             // vectorized interrupt lines
  53:     // jump and branch target
  54:     input  logic [31:0]           jump_target_ex_i,         // jump target address
  55: 
  56:     // CSRs
  57:     input  logic [31:0]           csr_mepc_i,               // PC to restore after handling
  58:                                                             // the interrupt/exception
  59:     input  logic [31:0]           csr_depc_i,               // PC to restore after handling
  60:                                                             // the debug request
  61:     input  logic [31:0]           csr_mtvec_i,              // base PC to jump to on exception
  62:     output logic                  csr_mtvec_init_o,         // tell CS regfile to init mtvec
  63: 
  64:     // pipeline stall
  65:     input  logic                  id_in_ready_i,            // ID stage is ready for new instr
  66: 
  67:     // misc signals
  68:     output logic                  if_busy_o,                // IF stage is busy fetching instr
  69:     output logic                  perf_imiss_o              // instr fetch miss
  70: );
  71: 
  72:   import ibex_pkg::*;
  73: 
  74:   logic              offset_in_init_d, offset_in_init_q;
  75:   logic              have_instr;
  76: 
  77:   // prefetch buffer related signals
  78:   logic              prefetch_busy;
  79:   logic              branch_req;
  80:   logic       [31:0] fetch_addr_n;
  81: 
  82:   logic              fetch_valid;
  83:   logic              fetch_ready;
  84:   logic       [31:0] fetch_rdata;
  85:   logic       [31:0] fetch_addr;
  86:   logic              fetch_err;
  87: 
  88:   logic       [31:0] exc_pc;
  89: 
  90:   logic        [5:0] irq_id;
  91:   logic              unused_irq_bit;
  92: 
  93:   logic              if_id_pipe_reg_we; // IF-ID pipeline reg write enable
  94: 
  95:   logic        [7:0] unused_boot_addr;
  96:   logic        [7:0] unused_csr_mtvec;
  97: 
  98:   assign unused_boot_addr = boot_addr_i[7:0];
  99:   assign unused_csr_mtvec = csr_mtvec_i[7:0];
 100: 
 101:   // extract interrupt ID from exception cause
 102:   assign irq_id         = {exc_cause};
 103:   assign unused_irq_bit = irq_id[5];   // MSB distinguishes interrupts from exceptions
 104: 
 105:   // exception PC selection mux
 106:   always_comb begin : exc_pc_mux
 107:     unique case (exc_pc_mux_i)
 108:       EXC_PC_EXC:     exc_pc = { csr_mtvec_i[31:8], 8'h00                    };
 109:       EXC_PC_IRQ:     exc_pc = { csr_mtvec_i[31:8], 1'b0, irq_id[4:0], 2'b00 };
 110:       EXC_PC_DBD:     exc_pc = DmHaltAddr;
 111:       EXC_PC_DBG_EXC: exc_pc = DmExceptionAddr;
 112:       default:        exc_pc = { csr_mtvec_i[31:8], 8'h00                    };
 113:     endcase
 114:   end
 115: 
 116:   // fetch address selection mux
 117:   always_comb begin : fetch_addr_mux
 118:     unique case (pc_mux_i)
 119:       PC_BOOT: fetch_addr_n = { boot_addr_i[31:8], 8'h80 };
 120:       PC_JUMP: fetch_addr_n = jump_target_ex_i;
 121:       PC_EXC:  fetch_addr_n = exc_pc;                       // set PC to exception handler
 122:       PC_ERET: fetch_addr_n = csr_mepc_i;                   // restore PC when returning from EXC
 123:       PC_DRET: fetch_addr_n = csr_depc_i;
 124:       default: fetch_addr_n = { boot_addr_i[31:8], 8'h80 };
 125:     endcase
 126:   end
 127: 
 128:   // tell CS register file to initialize mtvec on boot
 129:   assign csr_mtvec_init_o = (pc_mux_i == PC_BOOT) & pc_set_i;
 130: 
 131:   // prefetch buffer, caches a fixed number of instructions
 132:   ibex_prefetch_buffer prefetch_buffer_i (
 133:       .clk_i             ( clk_i                       ),
 134:       .rst_ni            ( rst_ni                      ),
 135: 
 136:       .req_i             ( req_i                       ),
 137: 
 138:       .branch_i          ( branch_req                  ),
 139:       .addr_i            ( {fetch_addr_n[31:1], 1'b0}  ),
 140: 
 141:       .ready_i           ( fetch_ready                 ),
 142:       .valid_o           ( fetch_valid                 ),
 143:       .rdata_o           ( fetch_rdata                 ),
 144:       .addr_o            ( fetch_addr                  ),
 145:       .err_o             ( fetch_err                   ),
 146: 
 147:       // goes to instruction memory / instruction cache
 148:       .instr_req_o       ( instr_req_o                 ),
 149:       .instr_addr_o      ( instr_addr_o                ),
 150:       .instr_gnt_i       ( instr_gnt_i                 ),
 151:       .instr_rvalid_i    ( instr_rvalid_i              ),
 152:       .instr_rdata_i     ( instr_rdata_i               ),
 153:       .instr_err_i       ( instr_err_i                 ),
 154:       .instr_pmp_err_i   ( instr_pmp_err_i             ),
 155: 
 156:       // Prefetch Buffer Status
 157:       .busy_o            ( prefetch_busy               )
 158:   );
 159: 
 160: 
 161:   // offset initialization state
 162:   always_ff @(posedge clk_i or negedge rst_ni) begin
 163:     if (!rst_ni) begin
 164:       offset_in_init_q <= 1'b1;
 165:     end else begin
 166:       offset_in_init_q <= offset_in_init_d;
 167:     end
 168:   end
 169: 
 170:   // offset initialization related transition logic
 171:   always_comb begin
 172:     offset_in_init_d = offset_in_init_q;
 173: 
 174:     fetch_ready      = 1'b0;
 175:     branch_req       = 1'b0;
 176:     have_instr       = 1'b0;
 177: 
 178:     if (offset_in_init_q) begin
 179:       // no valid instruction data for ID stage, assume aligned
 180:       if (req_i) begin
 181:         branch_req       = 1'b1;
 182:         offset_in_init_d = 1'b0;
 183:       end
 184:     end else begin
 185:       // an instruction is ready for ID stage
 186:       if (fetch_valid) begin
 187:         have_instr = 1'b1;
 188: 
 189:         if (req_i && if_id_pipe_reg_we) begin
 190:           fetch_ready      = 1'b1;
 191:           offset_in_init_d = 1'b0;
 192:         end
 193:       end
 194:     end
 195: 
 196:     // take care of jumps and branches
 197:     if (pc_set_i) begin
 198:       have_instr       = 1'b0;
 199: 
 200:       // switch to new PC from ID stage
 201:       branch_req       = 1'b1;
 202:       offset_in_init_d = 1'b0;
 203:     end
 204:   end
 205: 
 206:   assign pc_if_o      = fetch_addr;
 207:   assign if_busy_o    = prefetch_busy;
 208:   assign perf_imiss_o = ~fetch_valid | branch_req;
 209: 
 210:   // compressed instruction decoding, or more precisely compressed instruction
 211:   // expander
 212:   //
 213:   // since it does not matter where we decompress instructions, we do it here
 214:   // to ease timing closure
 215:   logic [31:0] instr_decompressed;
 216:   logic        illegal_c_insn;
 217:   logic        instr_is_compressed_int;
 218: 
 219:   ibex_compressed_decoder compressed_decoder_i (
 220:       .clk_i           ( clk_i                   ),
 221:       .rst_ni          ( rst_ni                  ),
 222:       .valid_i         ( fetch_valid             ),
 223:       .instr_i         ( fetch_rdata             ),
 224:       .instr_o         ( instr_decompressed      ),
 225:       .is_compressed_o ( instr_is_compressed_int ),
 226:       .illegal_instr_o ( illegal_c_insn          )
 227:   );
 228: 
 229:   // IF-ID pipeline registers, frozen when the ID stage is stalled
 230:   assign if_id_pipe_reg_we = have_instr & id_in_ready_i;
 231: 
 232:   always_ff @(posedge clk_i or negedge rst_ni) begin : if_id_pipeline_regs
 233:     if (!rst_ni) begin
 234:       instr_new_id_o             <= 1'b0;
 235:       instr_valid_id_o           <= 1'b0;
 236:       instr_rdata_id_o           <= '0;
 237:       instr_fetch_err_o          <= '0;
 238:       instr_rdata_c_id_o         <= '0;
 239:       instr_is_compressed_id_o   <= 1'b0;
 240:       illegal_c_insn_id_o        <= 1'b0;
 241:       pc_id_o                    <= '0;
 242:     end else begin
 243:       instr_new_id_o             <= if_id_pipe_reg_we;
 244:       if (if_id_pipe_reg_we) begin
 245:         instr_valid_id_o         <= 1'b1;
 246:         instr_rdata_id_o         <= instr_decompressed;
 247:         instr_fetch_err_o        <= fetch_err;
 248:         instr_rdata_c_id_o       <= fetch_rdata[15:0];
 249:         instr_is_compressed_id_o <= instr_is_compressed_int;
 250:         illegal_c_insn_id_o      <= illegal_c_insn;
 251:         pc_id_o                  <= pc_if_o;
 252:       end else if (instr_valid_clear_i) begin
 253:         instr_valid_id_o         <= 1'b0;
 254:       end
 255:     end
 256:   end
 257: 
 258:   ////////////////
 259:   // Assertions //
 260:   ////////////////
 261: 
 262:   // Selectors must be known/valid.
 263:   `ASSERT_KNOWN(IbexExcPcMuxKnown, exc_pc_mux_i, clk_i, !rst_ni)
 264:   `ASSERT(IbexPcMuxValid, pc_mux_i inside {
 265:       PC_BOOT,
 266:       PC_JUMP,
 267:       PC_EXC,
 268:       PC_ERET,
 269:       PC_DRET
 270:       }, clk_i, !rst_ni)
 271: 
 272:   // Boot address must be aligned to 256 bytes.
 273:   `ASSERT(IbexBootAddrUnaligned, boot_addr_i[7:0] == 8'h00, clk_i, !rst_ni)
 274: 
 275:   // Errors must only be sent together with rvalid.
 276:   `ASSERT(IbexInstrErrWithoutRvalid, instr_err_i |-> instr_rvalid_i, clk_i, !rst_ni)
 277: 
 278:   // Address must not contain X when request is sent.
 279:   `ASSERT(IbexInstrAddrUnknown, instr_req_o |-> !$isunknown(instr_addr_o), clk_i, !rst_ni)
 280: 
 281:   // Address must be word aligned when request is sent.
 282:   `ASSERT(IbexInstrAddrUnaligned, instr_req_o |-> (instr_addr_o[1:0] == 2'b00), clk_i, !rst_ni)
 283: 
 284: endmodule
 285: