blob: d44024ce010c600102a01034fe90e1c81d9db3f0 [file] [log] [blame]
/**
* Instruction Fetch Stage
*
* Instruction fetch unit: Selection of the next PC, and buffering (sampling) of
* the read instruction.
*/
module brq_ifu #(
parameter int unsigned DmHaltAddr = 32'h1A110800,
parameter int unsigned DmExceptionAddr = 32'h1A110808,
parameter bit DummyInstructions = 1'b0,
parameter bit ICache = 1'b0,
parameter bit ICacheECC = 1'b0,
parameter bit PCIncrCheck = 1'b0,
parameter bit BranchPredictor = 1'b0
) (
input logic clk_i,
input logic rst_ni,
input logic [31:0] boot_addr_i, // also used for mtvec
input logic req_i, // instruction request control
// instruction cache interface
output logic instr_req_o,
output logic [31:0] instr_addr_o,
input logic instr_gnt_i,
input logic instr_rvalid_i,
input logic [31:0] instr_rdata_i,
input logic instr_err_i,
input logic instr_pmp_err_i,
// output of ID stage
output logic instr_valid_id_o, // instr in IF-ID is valid
output logic instr_new_id_o, // instr in IF-ID is new
output logic [31:0] instr_rdata_id_o, // instr for ID stage
output logic [31:0] instr_rdata_alu_id_o, // replicated instr for ID stage
// to reduce fan-out
output logic [15:0] instr_rdata_c_id_o, // compressed instr for ID stage
// (mtval), meaningful only if
// instr_is_compressed_id_o = 1'b1
output logic instr_is_compressed_id_o, // compressed decoder thinks this
// is a compressed instr
// output logic instr_bp_taken_o, // instruction was predicted to be
// a taken branch
output logic instr_fetch_err_o, // bus error on fetch
output logic instr_fetch_err_plus2_o, // bus error misaligned
output logic illegal_c_insn_id_o, // compressed decoder thinks this
// is an invalid instr
// output logic dummy_instr_id_o, // Instruction is a dummy
output logic [31:0] pc_if_o,
output logic [31:0] pc_id_o,
// control signals
input logic instr_valid_clear_i, // clear instr valid bit in IF-ID
input logic pc_set_i, // set the PC to a new value
input logic pc_set_spec_i,
input brq_pkg::pc_sel_e pc_mux_i, // selector for PC multiplexer
// input logic nt_branch_mispredict_i, // Not-taken branch in ID/EX was
// mispredicted (predicted taken)
input brq_pkg::exc_pc_sel_e exc_pc_mux_i, // selects ISR address
// jump and branch target
input logic [31:0] branch_target_ex_i, // branch/jump target address
// CSRs
input logic [31:0] csr_mepc_i, // PC to restore after handling
// the interrupt/exception
input logic [31:0] csr_depc_i, // PC to restore after handling
// the debug request
input logic [31:0] csr_mtvec_i, // base PC to jump to on exception
output logic csr_mtvec_init_o, // tell CS regfile to init mtvec
// pipeline stall
input logic id_in_ready_i, // ID stage is ready for new instr
// misc signals
output logic pc_mismatch_alert_o,
output logic if_busy_o // IF stage is busy fetching instr
);
import brq_pkg::*;
logic instr_valid_id_d, instr_valid_id_q;
logic instr_new_id_d, instr_new_id_q;
// prefetch buffer related signals
logic prefetch_busy;
logic branch_req;
logic branch_spec;
logic predicted_branch;
logic [31:0] fetch_addr_n;
logic fetch_valid;
logic fetch_ready;
logic [31:0] fetch_rdata;
logic [31:0] fetch_addr;
logic fetch_err;
logic fetch_err_plus2;
logic if_instr_valid;
logic [31:0] if_instr_rdata;
logic [31:0] if_instr_addr;
logic if_instr_err;
logic [31:0] exc_pc;
logic if_id_pipe_reg_we; // IF-ID pipeline reg write enable
logic [31:0] instr_out;
logic instr_is_compressed_out;
logic illegal_c_instr_out;
logic instr_err_out;
logic predict_branch_taken;
logic [31:0] predict_branch_pc;
brq_pkg::pc_sel_e pc_mux_internal;
// exception PC selection mux
always_comb begin : exc_pc_mux
unique case (exc_pc_mux_i)
EXC_PC_EXC: exc_pc = { csr_mtvec_i[31:2], 2'b00 };
EXC_PC_IRQ: exc_pc = { csr_mtvec_i[31:2], 2'b00 };
EXC_PC_DBD: exc_pc = DmHaltAddr;
EXC_PC_DBG_EXC: exc_pc = DmExceptionAddr;
// default: exc_pc = { csr_mtvec_i[31:8], 8'h00 };
endcase
end
// The Branch predictor can provide a new PC which is internal to ifu. Only override the mux
// select to choose this if the core isn't already trying to set a PC.
assign pc_mux_internal =
(BranchPredictor && predict_branch_taken && !pc_set_i) ? PC_BP : pc_mux_i;
// fetch address selection mux
always_comb begin : fetch_addr_mux
unique case (pc_mux_internal)
PC_BOOT: fetch_addr_n = { boot_addr_i[31:2], 2'b00 };
PC_JUMP: fetch_addr_n = branch_target_ex_i;
PC_EXC: fetch_addr_n = exc_pc; // set PC to exception handler
PC_ERET: fetch_addr_n = csr_mepc_i; // restore PC when returning from EXC
PC_DRET: fetch_addr_n = csr_depc_i;
// Without branch predictor will never get pc_mux_internal == PC_BP. We still handle no branch
// predictor case here to ensure redundant mux logic isn't synthesised.
PC_BP: fetch_addr_n = BranchPredictor ? predict_branch_pc : { boot_addr_i[31:2], 2'b00 };
default: fetch_addr_n = { boot_addr_i[31:2], 2'b00 };
endcase
end
// tell CS register file to initialize mtvec on boot
assign csr_mtvec_init_o = (pc_mux_i == PC_BOOT) & pc_set_i;
// prefetch buffer, caches a fixed number of instructions
brq_ifu_prefetch_buffer #(
.BranchPredictor (BranchPredictor)
) ifu_prefetch_buffer_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.req_i ( req_i ),
.branch_i ( branch_req ),
.branch_spec_i ( branch_spec ),
.predicted_branch_i ( predicted_branch ),
// .branch_mispredict_i ( nt_branch_mispredict_i ),
.addr_i ( {fetch_addr_n[31:1], 1'b0} ),
.ready_i ( fetch_ready ),
.valid_o ( fetch_valid ),
.rdata_o ( fetch_rdata ),
.addr_o ( fetch_addr ),
.err_o ( fetch_err ),
.err_plus2_o ( fetch_err_plus2 ),
.instr_req_o ( instr_req_o ),
.instr_addr_o ( instr_addr_o ),
.instr_gnt_i ( instr_gnt_i ),
.instr_rvalid_i ( instr_rvalid_i ),
.instr_rdata_i ( instr_rdata_i ),
.instr_err_i ( instr_err_i ),
.instr_pmp_err_i ( instr_pmp_err_i ),
.busy_o ( prefetch_busy )
);
assign branch_req = pc_set_i | predict_branch_taken;
assign branch_spec = pc_set_spec_i | predict_branch_taken;
assign pc_if_o = if_instr_addr;
assign if_busy_o = prefetch_busy;
// compressed instruction decoding, or more precisely compressed instruction
// expander
//
// since it does not matter where we decompress instructions, we do it here
// to ease timing closure
logic [31:0] instr_decompressed;
logic illegal_c_insn;
logic instr_is_compressed;
brq_ifu_compressed_decoder ifu_compressed_decoder_i (
.instr_i ( if_instr_rdata ),
.instr_o ( instr_decompressed ),
.is_compressed_o ( instr_is_compressed ),
.illegal_instr_o ( illegal_c_insn )
);
assign instr_out = instr_decompressed;
assign instr_is_compressed_out = instr_is_compressed;
assign illegal_c_instr_out = illegal_c_insn;
assign instr_err_out = if_instr_err;
// The ID stage becomes valid as soon as any instruction is registered in the ID stage flops.
// Note that the current instruction is squashed by the incoming pc_set_i signal.
// Valid is held until it is explicitly cleared (due to an instruction completing or an exception)
assign instr_valid_id_d = (if_instr_valid & id_in_ready_i & ~pc_set_i) |
(instr_valid_id_q & ~instr_valid_clear_i);
assign instr_new_id_d = if_instr_valid & id_in_ready_i;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
instr_valid_id_q <= 1'b0;
instr_new_id_q <= 1'b0;
end else begin
instr_valid_id_q <= instr_valid_id_d;
instr_new_id_q <= instr_new_id_d;
end
end
assign instr_valid_id_o = instr_valid_id_q;
// Signal when a new instruction enters the ID stage (only used for RVFI signalling).
assign instr_new_id_o = instr_new_id_q;
// IF-ID pipeline registers, frozen when the ID stage is stalled
assign if_id_pipe_reg_we = instr_new_id_d;
always_ff @(posedge clk_i) begin
if (if_id_pipe_reg_we) begin
instr_rdata_id_o <= instr_out;
// To reduce fan-out and help timing from the instr_rdata_id flops they are replicated.
instr_rdata_alu_id_o <= instr_out;
instr_fetch_err_o <= instr_err_out;
instr_fetch_err_plus2_o <= fetch_err_plus2;
instr_rdata_c_id_o <= if_instr_rdata[15:0];
instr_is_compressed_id_o <= instr_is_compressed_out;
illegal_c_insn_id_o <= illegal_c_instr_out;
pc_id_o <= pc_if_o;
end
end
assign pc_mismatch_alert_o = 1'b0;
// end else begin : g_no_ifu_branch_predictor
// assign instr_bp_taken_o = 1'b0;
assign predict_branch_taken = 1'b0;
assign predicted_branch = 1'b0;
assign predict_branch_pc = 32'b0;
assign if_instr_valid = fetch_valid;
assign if_instr_rdata = fetch_rdata;
assign if_instr_addr = fetch_addr;
assign if_instr_err = fetch_err;
assign fetch_ready = id_in_ready_i; //& ~stall_dummy_instr;
// end
endmodule