blob: 6171de0ded0af47f121ba096ffaf304b4638feae [file] [log] [blame]
module ibex_if_stage (
clk,
rst_n,
boot_addr_i,
req_i,
instr_req_o,
instr_addr_o,
instr_gnt_i,
instr_rvalid_i,
instr_rdata_i,
instr_valid_id_o,
instr_rdata_id_o,
is_compressed_id_o,
illegal_c_insn_id_o,
pc_if_o,
pc_id_o,
clear_instr_valid_i,
pc_set_i,
exception_pc_reg_i,
depc_i,
pc_mux_i,
exc_pc_mux_i,
exc_vec_pc_mux_i,
jump_target_ex_i,
halt_if_i,
id_ready_i,
if_valid_o,
if_busy_o,
perf_imiss_o
);
parameter DM_HALT_ADDRESS = 32'h1a110800;
parameter DM_EXCEPTION_ADDRESS = 32'h1a110808;
input wire clk;
input wire rst_n;
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;
output reg instr_valid_id_o;
output reg [31:0] instr_rdata_id_o;
output reg is_compressed_id_o;
output reg illegal_c_insn_id_o;
output wire [31:0] pc_if_o;
output reg [31:0] pc_id_o;
input wire clear_instr_valid_i;
input wire pc_set_i;
input wire [31:0] exception_pc_reg_i;
input wire [31:0] depc_i;
input wire [2:0] pc_mux_i;
input wire [2:0] exc_pc_mux_i;
input wire [5:0] exc_vec_pc_mux_i;
input wire [31:0] jump_target_ex_i;
input wire halt_if_i;
input wire id_ready_i;
output wire if_valid_o;
output wire if_busy_o;
output wire perf_imiss_o;
reg offset_in_init_d;
reg offset_in_init_q;
reg valid;
wire if_ready;
wire prefetch_busy;
reg branch_req;
reg [31:0] fetch_addr_n;
wire fetch_valid;
reg fetch_ready;
wire [31:0] fetch_rdata;
wire [31:0] fetch_addr;
reg [31:0] exc_pc;
localparam [7:0] ibex_defines_EXC_OFF_BREAKPOINT = 8'h90;
localparam [7:0] ibex_defines_EXC_OFF_ECALL = 8'h88;
localparam [7:0] ibex_defines_EXC_OFF_ILLINSN = 8'h84;
localparam [2:0] ibex_defines_EXC_PC_BREAKPOINT = 7;
localparam [2:0] ibex_defines_EXC_PC_DBD = 5;
localparam [2:0] ibex_defines_EXC_PC_DBGEXC = 6;
localparam [2:0] ibex_defines_EXC_PC_ECALL = 1;
localparam [2:0] ibex_defines_EXC_PC_ILLINSN = 0;
localparam [2:0] ibex_defines_EXC_PC_IRQ = 4;
always @(*) begin : EXC_PC_MUX
exc_pc = {32 {1'sb0}};
case (exc_pc_mux_i)
ibex_defines_EXC_PC_ILLINSN: exc_pc = {boot_addr_i[31:8], {ibex_defines_EXC_OFF_ILLINSN}};
ibex_defines_EXC_PC_ECALL: exc_pc = {boot_addr_i[31:8], {ibex_defines_EXC_OFF_ECALL}};
ibex_defines_EXC_PC_BREAKPOINT: exc_pc = {boot_addr_i[31:8], {ibex_defines_EXC_OFF_BREAKPOINT}};
ibex_defines_EXC_PC_IRQ: exc_pc = {boot_addr_i[31:8], {exc_vec_pc_mux_i}, 2'b00};
ibex_defines_EXC_PC_DBD: exc_pc = {DM_HALT_ADDRESS};
ibex_defines_EXC_PC_DBGEXC: exc_pc = {DM_EXCEPTION_ADDRESS};
default:
;
endcase
end
localparam [7:0] ibex_defines_EXC_OFF_RST = 8'h80;
localparam [2:0] ibex_defines_PC_BOOT = 0;
localparam [2:0] ibex_defines_PC_DRET = 4;
localparam [2:0] ibex_defines_PC_ERET = 3;
localparam [2:0] ibex_defines_PC_EXCEPTION = 2;
localparam [2:0] ibex_defines_PC_JUMP = 1;
always @(*) begin
fetch_addr_n = {32 {1'sb0}};
case (pc_mux_i)
ibex_defines_PC_BOOT: fetch_addr_n = {boot_addr_i[31:8], {ibex_defines_EXC_OFF_RST}};
ibex_defines_PC_JUMP: fetch_addr_n = jump_target_ex_i;
ibex_defines_PC_EXCEPTION: fetch_addr_n = exc_pc;
ibex_defines_PC_ERET: fetch_addr_n = exception_pc_reg_i;
ibex_defines_PC_DRET: fetch_addr_n = depc_i;
default:
;
endcase
end
ibex_prefetch_buffer prefetch_buffer_i(
.clk(clk),
.rst_n(rst_n),
.req_i(req_i),
.branch_i(branch_req),
.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),
.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),
.busy_o(prefetch_busy)
);
always @(posedge clk or negedge rst_n)
if (!rst_n)
offset_in_init_q <= 1'b1;
else
offset_in_init_q <= offset_in_init_d;
always @(*) begin
offset_in_init_d = offset_in_init_q;
fetch_ready = 1'b0;
branch_req = 1'b0;
valid = 1'b0;
if (offset_in_init_q) begin
if (req_i) begin
branch_req = 1'b1;
offset_in_init_d = 1'b0;
end
end
else if (fetch_valid) begin
valid = 1'b1;
if (req_i && if_valid_o) begin
fetch_ready = 1'b1;
offset_in_init_d = 1'b0;
end
end
if (pc_set_i) begin
valid = 1'b0;
branch_req = 1'b1;
offset_in_init_d = 1'b0;
end
end
assign pc_if_o = fetch_addr;
assign if_busy_o = prefetch_busy;
assign perf_imiss_o = ~fetch_valid | branch_req;
wire [31:0] instr_decompressed;
wire illegal_c_insn;
wire instr_compressed_int;
ibex_compressed_decoder compressed_decoder_i(
.instr_i(fetch_rdata),
.instr_o(instr_decompressed),
.is_compressed_o(instr_compressed_int),
.illegal_instr_o(illegal_c_insn)
);
always @(posedge clk or negedge rst_n) begin : IF_ID_PIPE_REGISTERS
if (!rst_n) begin
instr_valid_id_o <= 1'b0;
instr_rdata_id_o <= {32 {1'sb0}};
illegal_c_insn_id_o <= 1'b0;
is_compressed_id_o <= 1'b0;
pc_id_o <= {32 {1'sb0}};
end
else if (if_valid_o) begin
instr_valid_id_o <= 1'b1;
instr_rdata_id_o <= instr_decompressed;
illegal_c_insn_id_o <= illegal_c_insn;
is_compressed_id_o <= instr_compressed_int;
pc_id_o <= pc_if_o;
end
else if (clear_instr_valid_i)
instr_valid_id_o <= 1'b0;
end
assign if_ready = valid & id_ready_i;
assign if_valid_o = ~halt_if_i & if_ready;
endmodule