blob: eda4468cf67aa1458540dab88c735af6049f7ca3 [file] [log] [blame]
module ibex_if_stage (
clk_i,
rst_ni,
boot_addr_i,
req_i,
instr_req_o,
instr_addr_o,
instr_gnt_i,
instr_rvalid_i,
instr_rdata_i,
instr_err_i,
instr_pmp_err_i,
ic_tag_req_o,
ic_tag_write_o,
ic_tag_addr_o,
ic_tag_wdata_o,
ic_tag_rdata_i,
ic_data_req_o,
ic_data_write_o,
ic_data_addr_o,
ic_data_wdata_o,
ic_data_rdata_i,
instr_valid_id_o,
instr_new_id_o,
instr_rdata_id_o,
instr_rdata_alu_id_o,
instr_rdata_c_id_o,
instr_is_compressed_id_o,
instr_bp_taken_o,
instr_fetch_err_o,
instr_fetch_err_plus2_o,
illegal_c_insn_id_o,
dummy_instr_id_o,
pc_if_o,
pc_id_o,
instr_valid_clear_i,
pc_set_i,
pc_set_spec_i,
pc_mux_i,
nt_branch_mispredict_i,
nt_branch_addr_i,
exc_pc_mux_i,
exc_cause,
dummy_instr_en_i,
dummy_instr_mask_i,
dummy_instr_seed_en_i,
dummy_instr_seed_i,
icache_enable_i,
icache_inval_i,
branch_target_ex_i,
csr_mepc_i,
csr_depc_i,
csr_mtvec_i,
csr_mtvec_init_o,
id_in_ready_i,
pc_mismatch_alert_o,
if_busy_o
);
parameter [31:0] DmHaltAddr = 32'h1a110800;
parameter [31:0] DmExceptionAddr = 32'h1a110808;
parameter [0:0] DummyInstructions = 1'b0;
parameter [0:0] ICache = 1'b0;
parameter [0:0] ICacheECC = 1'b0;
localparam [31:0] ibex_pkg_BUS_SIZE = 32;
parameter [31:0] BusSizeECC = ibex_pkg_BUS_SIZE;
localparam [31:0] ibex_pkg_ADDR_W = 32;
localparam [31:0] ibex_pkg_IC_LINE_SIZE = 64;
localparam [31:0] ibex_pkg_IC_LINE_BYTES = 8;
localparam [31:0] ibex_pkg_IC_NUM_WAYS = 2;
localparam [31:0] ibex_pkg_IC_SIZE_BYTES = 4096;
localparam [31:0] ibex_pkg_IC_NUM_LINES = (ibex_pkg_IC_SIZE_BYTES / ibex_pkg_IC_NUM_WAYS) / ibex_pkg_IC_LINE_BYTES;
localparam [31:0] ibex_pkg_IC_INDEX_W = $clog2(ibex_pkg_IC_NUM_LINES);
localparam [31:0] ibex_pkg_IC_LINE_W = 3;
localparam [31:0] ibex_pkg_IC_TAG_SIZE = ((ibex_pkg_ADDR_W - ibex_pkg_IC_INDEX_W) - ibex_pkg_IC_LINE_W) + 1;
parameter [31:0] TagSizeECC = ibex_pkg_IC_TAG_SIZE;
parameter [31:0] LineSizeECC = ibex_pkg_IC_LINE_SIZE;
parameter [0:0] PCIncrCheck = 1'b0;
parameter [0:0] ResetAll = 1'b0;
localparam signed [31:0] ibex_pkg_LfsrWidth = 32;
localparam [31:0] ibex_pkg_RndCnstLfsrSeedDefault = 32'hac533bf4;
parameter [31:0] RndCnstLfsrSeed = ibex_pkg_RndCnstLfsrSeedDefault;
localparam [159:0] ibex_pkg_RndCnstLfsrPermDefault = 160'h1e35ecba467fd1b12e958152c04fa43878a8daed;
parameter [159:0] RndCnstLfsrPerm = ibex_pkg_RndCnstLfsrPermDefault;
parameter [0:0] BranchPredictor = 1'b0;
input wire clk_i;
input wire rst_ni;
input wire [31:0] boot_addr_i;
input wire req_i;
output wire instr_req_o;
output wire [31:0] instr_addr_o;
input wire instr_gnt_i;
input wire instr_rvalid_i;
input wire [31:0] instr_rdata_i;
input wire instr_err_i;
input wire instr_pmp_err_i;
output wire [1:0] ic_tag_req_o;
output wire ic_tag_write_o;
output wire [ibex_pkg_IC_INDEX_W - 1:0] ic_tag_addr_o;
output wire [TagSizeECC - 1:0] ic_tag_wdata_o;
input wire [(ibex_pkg_IC_NUM_WAYS * TagSizeECC) - 1:0] ic_tag_rdata_i;
output wire [1:0] ic_data_req_o;
output wire ic_data_write_o;
output wire [ibex_pkg_IC_INDEX_W - 1:0] ic_data_addr_o;
output wire [LineSizeECC - 1:0] ic_data_wdata_o;
input wire [(ibex_pkg_IC_NUM_WAYS * LineSizeECC) - 1:0] ic_data_rdata_i;
output wire instr_valid_id_o;
output wire instr_new_id_o;
output reg [31:0] instr_rdata_id_o;
output reg [31:0] instr_rdata_alu_id_o;
output reg [15:0] instr_rdata_c_id_o;
output reg instr_is_compressed_id_o;
output wire instr_bp_taken_o;
output reg instr_fetch_err_o;
output reg instr_fetch_err_plus2_o;
output reg illegal_c_insn_id_o;
output wire dummy_instr_id_o;
output wire [31:0] pc_if_o;
output reg [31:0] pc_id_o;
input wire instr_valid_clear_i;
input wire pc_set_i;
input wire pc_set_spec_i;
input wire [2:0] pc_mux_i;
input wire nt_branch_mispredict_i;
input wire [31:0] nt_branch_addr_i;
input wire [1:0] exc_pc_mux_i;
input wire [5:0] exc_cause;
input wire dummy_instr_en_i;
input wire [2:0] dummy_instr_mask_i;
input wire dummy_instr_seed_en_i;
input wire [31:0] dummy_instr_seed_i;
input wire icache_enable_i;
input wire icache_inval_i;
input wire [31:0] branch_target_ex_i;
input wire [31:0] csr_mepc_i;
input wire [31:0] csr_depc_i;
input wire [31:0] csr_mtvec_i;
output wire csr_mtvec_init_o;
input wire id_in_ready_i;
output wire pc_mismatch_alert_o;
output wire if_busy_o;
wire instr_valid_id_d;
reg instr_valid_id_q;
wire instr_new_id_d;
reg instr_new_id_q;
wire prefetch_busy;
wire branch_req;
wire branch_spec;
reg [31:0] fetch_addr_n;
wire unused_fetch_addr_n0;
wire fetch_valid;
wire fetch_ready;
wire [31:0] fetch_rdata;
wire [31:0] fetch_addr;
wire fetch_err;
wire fetch_err_plus2;
wire if_instr_valid;
wire [31:0] if_instr_rdata;
wire [31:0] if_instr_addr;
wire if_instr_err;
reg [31:0] exc_pc;
wire [5:0] irq_id;
wire unused_irq_bit;
wire if_id_pipe_reg_we;
wire stall_dummy_instr;
wire [31:0] instr_out;
wire instr_is_compressed_out;
wire illegal_c_instr_out;
wire instr_err_out;
wire predict_branch_taken;
wire [31:0] predict_branch_pc;
wire [2:0] pc_mux_internal;
wire [7:0] unused_boot_addr;
wire [7:0] unused_csr_mtvec;
assign unused_boot_addr = boot_addr_i[7:0];
assign unused_csr_mtvec = csr_mtvec_i[7:0];
assign irq_id = {exc_cause};
assign unused_irq_bit = irq_id[5];
always @(*) begin : exc_pc_mux
case (exc_pc_mux_i)
2'd0: exc_pc = {csr_mtvec_i[31:8], 8'h00};
2'd1: exc_pc = {csr_mtvec_i[31:8], 1'b0, irq_id[4:0], 2'b00};
2'd2: exc_pc = DmHaltAddr;
2'd3: exc_pc = DmExceptionAddr;
default: exc_pc = {csr_mtvec_i[31:8], 8'h00};
endcase
end
assign pc_mux_internal = ((BranchPredictor && predict_branch_taken) && !pc_set_i ? 3'd5 : pc_mux_i);
always @(*) begin : fetch_addr_mux
case (pc_mux_internal)
3'd0: fetch_addr_n = {boot_addr_i[31:8], 8'h80};
3'd1: fetch_addr_n = branch_target_ex_i;
3'd2: fetch_addr_n = exc_pc;
3'd3: fetch_addr_n = csr_mepc_i;
3'd4: fetch_addr_n = csr_depc_i;
3'd5: fetch_addr_n = (BranchPredictor ? predict_branch_pc : {boot_addr_i[31:8], 8'h80});
default: fetch_addr_n = {boot_addr_i[31:8], 8'h80};
endcase
end
assign csr_mtvec_init_o = (pc_mux_i == 3'd0) & pc_set_i;
ibex_prefetch_buffer #(.ResetAll(ResetAll)) prefetch_buffer_i(
.clk_i(clk_i),
.rst_ni(rst_ni),
.req_i(req_i),
.branch_i(branch_req),
.branch_spec_i(branch_spec),
.branch_mispredict_i(nt_branch_mispredict_i),
.mispredict_addr_i(nt_branch_addr_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)
);
wire unused_icen;
wire unused_icinv;
wire [(ibex_pkg_IC_NUM_WAYS * TagSizeECC) - 1:0] unused_tag_ram_input;
wire [(ibex_pkg_IC_NUM_WAYS * LineSizeECC) - 1:0] unused_data_ram_input;
assign unused_icen = icache_enable_i;
assign unused_icinv = icache_inval_i;
assign unused_tag_ram_input = ic_tag_rdata_i;
assign unused_data_ram_input = ic_data_rdata_i;
assign ic_tag_req_o = 'b0;
assign ic_tag_write_o = 'b0;
assign ic_tag_addr_o = 'b0;
assign ic_tag_wdata_o = 'b0;
assign ic_data_req_o = 'b0;
assign ic_data_write_o = 'b0;
assign ic_data_addr_o = 'b0;
assign ic_data_wdata_o = 'b0;
wire unused_icache;
wire unused_icacheECC;
wire signed [31:0] unused_bussizeECC;
assign unused_icache = ICache;
assign unused_icacheECC = ICacheECC;
assign unused_bussizeECC = BusSizeECC;
assign unused_fetch_addr_n0 = fetch_addr_n[0];
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;
wire [31:0] instr_decompressed;
wire illegal_c_insn;
wire instr_is_compressed;
ibex_compressed_decoder compressed_decoder_i(
.clk_i(clk_i),
.rst_ni(rst_ni),
.valid_i(fetch_valid & ~fetch_err),
.instr_i(if_instr_rdata),
.instr_o(instr_decompressed),
.is_compressed_o(instr_is_compressed),
.illegal_instr_o(illegal_c_insn)
);
wire unused_dummy_en;
wire [2:0] unused_dummy_mask;
wire unused_dummy_seed_en;
wire [31:0] unused_dummy_seed;
assign unused_dummy_en = dummy_instr_en_i && DummyInstructions;
assign unused_dummy_mask = dummy_instr_mask_i;
assign unused_dummy_seed_en = dummy_instr_seed_en_i;
assign unused_dummy_seed = dummy_instr_seed_i;
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;
assign stall_dummy_instr = 1'b0;
assign dummy_instr_id_o = 1'b0;
wire [31:0] unused_RndCnstLfsrSeed;
assign unused_RndCnstLfsrSeed = RndCnstLfsrSeed;
wire [159:0] unused_RndCnstLfsrPerm;
assign unused_RndCnstLfsrPerm = RndCnstLfsrPerm;
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 @(posedge clk_i or negedge rst_ni)
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
assign instr_valid_id_o = instr_valid_id_q;
assign instr_new_id_o = instr_new_id_q;
assign if_id_pipe_reg_we = instr_new_id_d;
generate
if (ResetAll) begin : g_instr_rdata_ra
always @(posedge clk_i or negedge rst_ni)
if (!rst_ni) begin
instr_rdata_id_o <= 1'sb0;
instr_rdata_alu_id_o <= 1'sb0;
instr_fetch_err_o <= 1'sb0;
instr_fetch_err_plus2_o <= 1'sb0;
instr_rdata_c_id_o <= 1'sb0;
instr_is_compressed_id_o <= 1'sb0;
illegal_c_insn_id_o <= 1'sb0;
pc_id_o <= 1'sb0;
end
else if (if_id_pipe_reg_we) begin
instr_rdata_id_o <= instr_out;
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
else begin : g_instr_rdata_nr
always @(posedge clk_i)
if (if_id_pipe_reg_we) begin
instr_rdata_id_o <= instr_out;
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
if (PCIncrCheck) begin : g_secure_pc
wire [31:0] prev_instr_addr_incr;
reg prev_instr_seq_q;
wire prev_instr_seq_d;
assign prev_instr_seq_d = ((prev_instr_seq_q | instr_new_id_d) & ~branch_req) & ~stall_dummy_instr;
always @(posedge clk_i or negedge rst_ni)
if (!rst_ni)
prev_instr_seq_q <= 1'b0;
else
prev_instr_seq_q <= prev_instr_seq_d;
assign prev_instr_addr_incr = pc_id_o + (instr_is_compressed_id_o && !instr_fetch_err_o ? 32'd2 : 32'd4);
assign pc_mismatch_alert_o = prev_instr_seq_q & (pc_if_o != prev_instr_addr_incr);
end
else begin : g_no_secure_pc
assign pc_mismatch_alert_o = 1'b0;
end
if (BranchPredictor) begin : g_branch_predictor
reg [31:0] instr_skid_data_q;
reg [31:0] instr_skid_addr_q;
reg instr_skid_bp_taken_q;
reg instr_skid_valid_q;
wire instr_skid_valid_d;
wire instr_skid_en;
reg instr_bp_taken_q;
wire instr_bp_taken_d;
wire predict_branch_taken_raw;
if (ResetAll) begin : g_bp_taken_ra
always @(posedge clk_i or negedge rst_ni)
if (!rst_ni)
instr_bp_taken_q <= 1'sb0;
else if (if_id_pipe_reg_we)
instr_bp_taken_q <= instr_bp_taken_d;
end
else begin : g_bp_taken_nr
always @(posedge clk_i)
if (if_id_pipe_reg_we)
instr_bp_taken_q <= instr_bp_taken_d;
end
assign instr_skid_en = ((predict_branch_taken & ~pc_set_i) & ~id_in_ready_i) & ~instr_skid_valid_q;
assign instr_skid_valid_d = ((instr_skid_valid_q & ~id_in_ready_i) & ~stall_dummy_instr) | instr_skid_en;
always @(posedge clk_i or negedge rst_ni)
if (!rst_ni)
instr_skid_valid_q <= 1'b0;
else
instr_skid_valid_q <= instr_skid_valid_d;
if (ResetAll) begin : g_instr_skid_ra
always @(posedge clk_i or negedge rst_ni)
if (!rst_ni) begin
instr_skid_bp_taken_q <= 1'sb0;
instr_skid_data_q <= 1'sb0;
instr_skid_addr_q <= 1'sb0;
end
else if (instr_skid_en) begin
instr_skid_bp_taken_q <= predict_branch_taken;
instr_skid_data_q <= fetch_rdata;
instr_skid_addr_q <= fetch_addr;
end
end
else begin : g_instr_skid_nr
always @(posedge clk_i)
if (instr_skid_en) begin
instr_skid_bp_taken_q <= predict_branch_taken;
instr_skid_data_q <= fetch_rdata;
instr_skid_addr_q <= fetch_addr;
end
end
ibex_branch_predict branch_predict_i(
.clk_i(clk_i),
.rst_ni(rst_ni),
.fetch_rdata_i(fetch_rdata),
.fetch_pc_i(fetch_addr),
.fetch_valid_i(fetch_valid),
.predict_branch_taken_o(predict_branch_taken_raw),
.predict_branch_pc_o(predict_branch_pc)
);
assign predict_branch_taken = (predict_branch_taken_raw & ~instr_skid_valid_q) & ~fetch_err;
assign if_instr_valid = fetch_valid | (instr_skid_valid_q & ~nt_branch_mispredict_i);
assign if_instr_rdata = (instr_skid_valid_q ? instr_skid_data_q : fetch_rdata);
assign if_instr_addr = (instr_skid_valid_q ? instr_skid_addr_q : fetch_addr);
assign if_instr_err = ~instr_skid_valid_q & fetch_err;
assign instr_bp_taken_d = (instr_skid_valid_q ? instr_skid_bp_taken_q : predict_branch_taken);
assign fetch_ready = (id_in_ready_i & ~stall_dummy_instr) & ~instr_skid_valid_q;
assign instr_bp_taken_o = instr_bp_taken_q;
end
else begin : g_no_branch_predictor
assign instr_bp_taken_o = 1'b0;
assign predict_branch_taken = 1'b0;
assign predict_branch_pc = 32'b00000000000000000000000000000000;
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
endgenerate
endmodule