../src/lowrisc_ibex_ibex_core_0.1/rtl/ibex_if_stage.sv Cov: 79.2%

   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: 
  13: `include "prim_assert.sv"
  14: 
  15: module ibex_if_stage #(
  16:     parameter int unsigned DmHaltAddr        = 32'h1A110800,
  17:     parameter int unsigned DmExceptionAddr   = 32'h1A110808,
  18:     parameter bit          DummyInstructions = 1'b0,
  19:     parameter bit          ICache            = 1'b0,
  20:     parameter bit          ICacheECC         = 1'b0
  21: ) (
  22:     input  logic                   clk_i,
  23:     input  logic                   rst_ni,
  24: 
  25:     input  logic [31:0]            boot_addr_i,              // also used for mtvec
  26:     input  logic                   req_i,                    // instruction request control
  27: 
  28:     // instruction cache interface
  29:     output logic                  instr_req_o,
  30:     output logic [31:0]           instr_addr_o,
  31:     input  logic                  instr_gnt_i,
  32:     input  logic                  instr_rvalid_i,
  33:     input  logic [31:0]           instr_rdata_i,
  34:     input  logic                  instr_err_i,
  35:     input  logic                  instr_pmp_err_i,
  36: 
  37:     // output of ID stage
  38:     output logic                  instr_valid_id_o,         // instr in IF-ID is valid
  39:     output logic                  instr_new_id_o,           // instr in IF-ID is new
  40:     output logic [31:0]           instr_rdata_id_o,         // instr for ID stage
  41:     output logic [31:0]           instr_rdata_alu_id_o,     // replicated instr for ID stage
  42:                                                             // to reduce fan-out
  43:     output logic [15:0]           instr_rdata_c_id_o,       // compressed instr for ID stage
  44:                                                             // (mtval), meaningful only if
  45:                                                             // instr_is_compressed_id_o = 1'b1
  46:     output logic                  instr_is_compressed_id_o, // compressed decoder thinks this
  47:                                                             // is a compressed instr
  48:     output logic                  instr_fetch_err_o,        // bus error on fetch
  49:     output logic                  instr_fetch_err_plus2_o,  // bus error misaligned
  50:     output logic                  illegal_c_insn_id_o,      // compressed decoder thinks this
  51:                                                             // is an invalid instr
  52:     output logic                  dummy_instr_id_o,         // Instruction is a dummy
  53:     output logic [31:0]           pc_if_o,
  54:     output logic [31:0]           pc_id_o,
  55: 
  56:     // control signals
  57:     input  logic                  instr_valid_clear_i,      // clear instr valid bit in IF-ID
  58:     input  logic                  pc_set_i,                 // set the PC to a new value
  59:     input  logic                  pc_set_spec_i,
  60:     input  ibex_pkg::pc_sel_e     pc_mux_i,                 // selector for PC multiplexer
  61:     input  ibex_pkg::exc_pc_sel_e exc_pc_mux_i,             // selects ISR address
  62:     input  ibex_pkg::exc_cause_e  exc_cause,                // selects ISR address for
  63:                                                             // vectorized interrupt lines
  64:     input logic                   dummy_instr_en_i,
  65:     input logic [2:0]             dummy_instr_mask_i,
  66:     input logic                   dummy_instr_seed_en_i,
  67:     input logic [31:0]            dummy_instr_seed_i,
  68:     input logic                   icache_enable_i,
  69:     input logic                   icache_inval_i,
  70: 
  71:     // jump and branch target
  72:     input  logic [31:0]           branch_target_ex_i,       // branch/jump target address
  73: 
  74:     // CSRs
  75:     input  logic [31:0]           csr_mepc_i,               // PC to restore after handling
  76:                                                             // the interrupt/exception
  77:     input  logic [31:0]           csr_depc_i,               // PC to restore after handling
  78:                                                             // the debug request
  79:     input  logic [31:0]           csr_mtvec_i,              // base PC to jump to on exception
  80:     output logic                  csr_mtvec_init_o,         // tell CS regfile to init mtvec
  81: 
  82:     // pipeline stall
  83:     input  logic                  id_in_ready_i,            // ID stage is ready for new instr
  84: 
  85:     // misc signals
  86:     output logic                  if_busy_o                 // IF stage is busy fetching instr
  87: );
  88: 
  89:   import ibex_pkg::*;
  90: 
  91:   logic              instr_valid_id_d, instr_valid_id_q;
  92:   logic              instr_new_id_d, instr_new_id_q;
  93: 
  94:   // prefetch buffer related signals
  95:   logic              prefetch_busy;
  96:   logic              branch_req;
  97:   logic       [31:0] fetch_addr_n;
  98: 
  99:   logic              fetch_valid;
 100:   logic              fetch_ready;
 101:   logic       [31:0] fetch_rdata;
 102:   logic       [31:0] fetch_addr;
 103:   logic              fetch_err;
 104:   logic              fetch_err_plus2;
 105: 
 106:   logic       [31:0] exc_pc;
 107: 
 108:   logic        [5:0] irq_id;
 109:   logic              unused_irq_bit;
 110: 
 111:   logic              if_id_pipe_reg_we; // IF-ID pipeline reg write enable
 112: 
 113:   // Dummy instruction signals
 114:   logic              fetch_valid_out;
 115:   logic              stall_dummy_instr;
 116:   logic [31:0]       instr_out;
 117:   logic              instr_is_compressed_out;
 118:   logic              illegal_c_instr_out;
 119:   logic              instr_err_out;
 120: 
 121:   logic        [7:0] unused_boot_addr;
 122:   logic        [7:0] unused_csr_mtvec;
 123: 
 124:   assign unused_boot_addr = boot_addr_i[7:0];
 125:   assign unused_csr_mtvec = csr_mtvec_i[7:0];
 126: 
 127:   // extract interrupt ID from exception cause
 128:   assign irq_id         = {exc_cause};
 129:   assign unused_irq_bit = irq_id[5];   // MSB distinguishes interrupts from exceptions
 130: 
 131:   // exception PC selection mux
 132:   always_comb begin : exc_pc_mux
 133:     unique case (exc_pc_mux_i)
 134:       EXC_PC_EXC:     exc_pc = { csr_mtvec_i[31:8], 8'h00                    };
 135:       EXC_PC_IRQ:     exc_pc = { csr_mtvec_i[31:8], 1'b0, irq_id[4:0], 2'b00 };
 136:       EXC_PC_DBD:     exc_pc = DmHaltAddr;
 137:       EXC_PC_DBG_EXC: exc_pc = DmExceptionAddr;
 138:       default:        exc_pc = { csr_mtvec_i[31:8], 8'h00                    };
 139:     endcase
 140:   end
 141: 
 142:   // fetch address selection mux
 143:   always_comb begin : fetch_addr_mux
 144:     unique case (pc_mux_i)
 145:       PC_BOOT: fetch_addr_n = { boot_addr_i[31:8], 8'h80 };
 146:       PC_JUMP: fetch_addr_n = branch_target_ex_i;
 147:       PC_EXC:  fetch_addr_n = exc_pc;                       // set PC to exception handler
 148:       PC_ERET: fetch_addr_n = csr_mepc_i;                   // restore PC when returning from EXC
 149:       PC_DRET: fetch_addr_n = csr_depc_i;
 150:       default: fetch_addr_n = { boot_addr_i[31:8], 8'h80 };
 151:     endcase
 152:   end
 153: 
 154:   // tell CS register file to initialize mtvec on boot
 155:   assign csr_mtvec_init_o = (pc_mux_i == PC_BOOT) & pc_set_i;
 156: 
 157:   if (ICache) begin : gen_icache
 158:     // Full I-Cache option
 159:     ibex_icache #(
 160:       .ICacheECC (ICacheECC)
 161:     ) icache_i (
 162:         .clk_i             ( clk_i                       ),
 163:         .rst_ni            ( rst_ni                      ),
 164: 
 165:         .req_i             ( req_i                       ),
 166: 
 167:         .branch_i          ( branch_req                  ),
 168:         .branch_spec_i     ( pc_set_spec_i               ),
 169:         .addr_i            ( {fetch_addr_n[31:1], 1'b0}  ),
 170: 
 171:         .ready_i           ( fetch_ready                 ),
 172:         .valid_o           ( fetch_valid                 ),
 173:         .rdata_o           ( fetch_rdata                 ),
 174:         .addr_o            ( fetch_addr                  ),
 175:         .err_o             ( fetch_err                   ),
 176:         .err_plus2_o       ( fetch_err_plus2             ),
 177: 
 178:         .instr_req_o       ( instr_req_o                 ),
 179:         .instr_addr_o      ( instr_addr_o                ),
 180:         .instr_gnt_i       ( instr_gnt_i                 ),
 181:         .instr_rvalid_i    ( instr_rvalid_i              ),
 182:         .instr_rdata_i     ( instr_rdata_i               ),
 183:         .instr_err_i       ( instr_err_i                 ),
 184:         .instr_pmp_err_i   ( instr_pmp_err_i             ),
 185: 
 186:         .icache_enable_i   ( icache_enable_i             ),
 187:         .icache_inval_i    ( icache_inval_i              ),
 188:         .busy_o            ( prefetch_busy               )
 189:     );
 190:   end else begin : gen_prefetch_buffer
 191:     // prefetch buffer, caches a fixed number of instructions
 192:     ibex_prefetch_buffer prefetch_buffer_i (
 193:         .clk_i             ( clk_i                       ),
 194:         .rst_ni            ( rst_ni                      ),
 195: 
 196:         .req_i             ( req_i                       ),
 197: 
 198:         .branch_i          ( branch_req                  ),
 199:         .branch_spec_i     ( pc_set_spec_i               ),
 200:         .addr_i            ( {fetch_addr_n[31:1], 1'b0}  ),
 201: 
 202:         .ready_i           ( fetch_ready                 ),
 203:         .valid_o           ( fetch_valid                 ),
 204:         .rdata_o           ( fetch_rdata                 ),
 205:         .addr_o            ( fetch_addr                  ),
 206:         .err_o             ( fetch_err                   ),
 207:         .err_plus2_o       ( fetch_err_plus2             ),
 208: 
 209:         .instr_req_o       ( instr_req_o                 ),
 210:         .instr_addr_o      ( instr_addr_o                ),
 211:         .instr_gnt_i       ( instr_gnt_i                 ),
 212:         .instr_rvalid_i    ( instr_rvalid_i              ),
 213:         .instr_rdata_i     ( instr_rdata_i               ),
 214:         .instr_err_i       ( instr_err_i                 ),
 215:         .instr_pmp_err_i   ( instr_pmp_err_i             ),
 216: 
 217:         .busy_o            ( prefetch_busy               )
 218:     );
 219:     // ICache tieoffs
 220:     logic unused_icen, unused_icinv;
 221:     assign unused_icen  = icache_enable_i;
 222:     assign unused_icinv = icache_inval_i;
 223:   end
 224: 
 225:   assign branch_req  = pc_set_i;
 226:   assign fetch_ready = id_in_ready_i & ~stall_dummy_instr;
 227: 
 228:   assign pc_if_o     = fetch_addr;
 229:   assign if_busy_o   = prefetch_busy;
 230: 
 231:   // compressed instruction decoding, or more precisely compressed instruction
 232:   // expander
 233:   //
 234:   // since it does not matter where we decompress instructions, we do it here
 235:   // to ease timing closure
 236:   logic [31:0] instr_decompressed;
 237:   logic        illegal_c_insn;
 238:   logic        instr_is_compressed;
 239: 
 240:   ibex_compressed_decoder compressed_decoder_i (
 241:       .clk_i           ( clk_i                    ),
 242:       .rst_ni          ( rst_ni                   ),
 243:       .valid_i         ( fetch_valid & ~fetch_err ),
 244:       .instr_i         ( fetch_rdata              ),
 245:       .instr_o         ( instr_decompressed       ),
 246:       .is_compressed_o ( instr_is_compressed      ),
 247:       .illegal_instr_o ( illegal_c_insn           )
 248:   );
 249: 
 250:   // Dummy instruction insertion
 251:   if (DummyInstructions) begin : gen_dummy_instr
 252:     logic        insert_dummy_instr;
 253:     logic [31:0] dummy_instr_data;
 254: 
 255:     ibex_dummy_instr dummy_instr_i (
 256:       .clk_i                 ( clk_i                 ),
 257:       .rst_ni                ( rst_ni                ),
 258:       .dummy_instr_en_i      ( dummy_instr_en_i      ),
 259:       .dummy_instr_mask_i    ( dummy_instr_mask_i    ),
 260:       .dummy_instr_seed_en_i ( dummy_instr_seed_en_i ),
 261:       .dummy_instr_seed_i    ( dummy_instr_seed_i    ),
 262:       .fetch_valid_i         ( fetch_valid           ),
 263:       .id_in_ready_i         ( id_in_ready_i         ),
 264:       .insert_dummy_instr_o  ( insert_dummy_instr    ),
 265:       .dummy_instr_data_o    ( dummy_instr_data      )
 266:     );
 267: 
 268:     // Mux between actual instructions and dummy instructions
 269:     assign fetch_valid_out         = insert_dummy_instr | fetch_valid;
 270:     assign instr_out               = insert_dummy_instr ? dummy_instr_data : instr_decompressed;
 271:     assign instr_is_compressed_out = insert_dummy_instr ? 1'b0 : instr_is_compressed;
 272:     assign illegal_c_instr_out     = insert_dummy_instr ? 1'b0 : illegal_c_insn;
 273:     assign instr_err_out           = insert_dummy_instr ? 1'b0 : fetch_err;
 274: 
 275:     // Stall the IF stage if we insert a dummy instruction. The dummy will execute between whatever
 276:     // is currently in the ID stage and whatever is valid from the prefetch buffer this cycle. The
 277:     // PC of the dummy instruction will match whatever is next from the prefetch buffer.
 278:     assign stall_dummy_instr = insert_dummy_instr;
 279: 
 280:     // Register the dummy instruction indication into the ID stage
 281:     always_ff @(posedge clk_i or negedge rst_ni) begin
 282:       if (!rst_ni) begin
 283:         dummy_instr_id_o <= 1'b0;
 284:       end else if (if_id_pipe_reg_we) begin
 285:         dummy_instr_id_o <= insert_dummy_instr;
 286:       end
 287:     end
 288: 
 289:   end else begin : gen_no_dummy_instr
 290:     logic        unused_dummy_en;
 291:     logic [2:0]  unused_dummy_mask;
 292:     logic        unused_dummy_seed_en;
 293:     logic [31:0] unused_dummy_seed;
 294: 
 295:     assign unused_dummy_en         = dummy_instr_en_i;
 296:     assign unused_dummy_mask       = dummy_instr_mask_i;
 297:     assign unused_dummy_seed_en    = dummy_instr_seed_en_i;
 298:     assign unused_dummy_seed       = dummy_instr_seed_i;
 299:     assign fetch_valid_out         = fetch_valid;
 300:     assign instr_out               = instr_decompressed;
 301:     assign instr_is_compressed_out = instr_is_compressed;
 302:     assign illegal_c_instr_out     = illegal_c_insn;
 303:     assign instr_err_out           = fetch_err;
 304:     assign stall_dummy_instr       = 1'b0;
 305:     assign dummy_instr_id_o        = 1'b0;
 306:   end
 307: 
 308:   // The ID stage becomes valid as soon as any instruction is registered in the ID stage flops.
 309:   // Note that the current instruction is squashed by the incoming pc_set_i signal.
 310:   // Valid is held until it is explicitly cleared (due to an instruction completing or an exception)
 311:   assign instr_valid_id_d = (fetch_valid_out & id_in_ready_i & ~pc_set_i) |
 312:                             (instr_valid_id_q & ~instr_valid_clear_i);
 313:   assign instr_new_id_d   = fetch_valid_out & id_in_ready_i;
 314: 
 315:   always_ff @(posedge clk_i or negedge rst_ni) begin
 316:     if (!rst_ni) begin
 317:       instr_valid_id_q <= 1'b0;
 318:       instr_new_id_q   <= 1'b0;
 319:     end else begin
 320:       instr_valid_id_q <= instr_valid_id_d;
 321:       instr_new_id_q   <= instr_new_id_d;
 322:     end
 323:   end
 324: 
 325:   assign instr_valid_id_o = instr_valid_id_q;
 326:   // Signal when a new instruction enters the ID stage (only used for RVFI signalling).
 327:   assign instr_new_id_o   = instr_new_id_q;
 328: 
 329:   // IF-ID pipeline registers, frozen when the ID stage is stalled
 330:   assign if_id_pipe_reg_we = instr_new_id_d;
 331: 
 332:   always_ff @(posedge clk_i) begin
 333:     if (if_id_pipe_reg_we) begin
 334:       instr_rdata_id_o         <= instr_out;
 335:       // To reduce fan-out and help timing from the instr_rdata_id flops they are replicated.
 336:       instr_rdata_alu_id_o     <= instr_out;
 337:       instr_fetch_err_o        <= instr_err_out;
 338:       instr_fetch_err_plus2_o  <= fetch_err_plus2;
 339:       instr_rdata_c_id_o       <= fetch_rdata[15:0];
 340:       instr_is_compressed_id_o <= instr_is_compressed_out;
 341:       illegal_c_insn_id_o      <= illegal_c_instr_out;
 342:       pc_id_o                  <= pc_if_o;
 343:     end
 344:   end
 345: 
 346:   ////////////////
 347:   // Assertions //
 348:   ////////////////
 349: 
 350:   // Selectors must be known/valid.
 351:   `ASSERT_KNOWN(IbexExcPcMuxKnown, exc_pc_mux_i)
 352:   `ASSERT(IbexPcMuxValid, pc_mux_i inside {
 353:       PC_BOOT,
 354:       PC_JUMP,
 355:       PC_EXC,
 356:       PC_ERET,
 357:       PC_DRET})
 358: 
 359:   // Boot address must be aligned to 256 bytes.
 360:   `ASSERT(IbexBootAddrUnaligned, boot_addr_i[7:0] == 8'h00)
 361: 
 362:   // Errors must only be sent together with rvalid.
 363:   `ASSERT(IbexInstrErrWithoutRvalid, instr_err_i |-> instr_rvalid_i)
 364: 
 365:   // Address must not contain X when request is sent.
 366:   `ASSERT(IbexInstrAddrUnknown, instr_req_o |-> !$isunknown(instr_addr_o))
 367: 
 368:   // Address must be word aligned when request is sent.
 369:   `ASSERT(IbexInstrAddrUnaligned, instr_req_o |-> (instr_addr_o[1:0] == 2'b00))
 370: 
 371: endmodule
 372: