blob: ade64aa3be52ba263e89af30b61cee329bed4d4c [file] [log] [blame]
module flexbex_ibex_controller (
clk,
rst_n,
fetch_enable_i,
ctrl_busy_o,
first_fetch_o,
is_decoding_o,
deassert_we_o,
illegal_insn_i,
ecall_insn_i,
mret_insn_i,
dret_insn_i,
pipe_flush_i,
ebrk_insn_i,
csr_status_i,
instr_valid_i,
instr_req_o,
pc_set_o,
pc_mux_o,
exc_pc_mux_o,
data_misaligned_i,
branch_in_id_i,
branch_set_i,
jump_set_i,
instr_multicyle_i,
irq_i,
irq_req_ctrl_i,
irq_id_ctrl_i,
m_IE_i,
irq_ack_o,
irq_id_o,
exc_cause_o,
exc_ack_o,
exc_kill_o,
debug_req_i,
debug_cause_o,
debug_csr_save_o,
debug_single_step_i,
debug_ebreakm_i,
csr_save_if_o,
csr_save_id_o,
csr_cause_o,
csr_restore_mret_id_o,
csr_restore_dret_id_o,
csr_save_cause_o,
operand_a_fw_mux_sel_o,
halt_if_o,
halt_id_o,
id_ready_i,
perf_jump_o,
perf_tbranch_o
);
input wire clk;
input wire rst_n;
input wire fetch_enable_i;
output reg ctrl_busy_o;
output reg first_fetch_o;
output reg is_decoding_o;
output wire deassert_we_o;
input wire illegal_insn_i;
input wire ecall_insn_i;
input wire mret_insn_i;
input wire dret_insn_i;
input wire pipe_flush_i;
input wire ebrk_insn_i;
input wire csr_status_i;
input wire instr_valid_i;
output reg instr_req_o;
output reg pc_set_o;
output reg [2:0] pc_mux_o;
output reg [2:0] exc_pc_mux_o;
input wire data_misaligned_i;
input wire branch_in_id_i;
input wire branch_set_i;
input wire jump_set_i;
input wire instr_multicyle_i;
input wire irq_i;
input wire irq_req_ctrl_i;
input wire [4:0] irq_id_ctrl_i;
input wire m_IE_i;
output reg irq_ack_o;
output reg [4:0] irq_id_o;
output reg [5:0] exc_cause_o;
output reg exc_ack_o;
output reg exc_kill_o;
input wire debug_req_i;
output reg [2:0] debug_cause_o;
output reg debug_csr_save_o;
input wire debug_single_step_i;
input wire debug_ebreakm_i;
output reg csr_save_if_o;
output reg csr_save_id_o;
output reg [5:0] csr_cause_o;
output reg csr_restore_mret_id_o;
output reg csr_restore_dret_id_o;
output reg csr_save_cause_o;
output wire operand_a_fw_mux_sel_o;
output reg halt_if_o;
output reg halt_id_o;
input wire id_ready_i;
output reg perf_jump_o;
output reg perf_tbranch_o;
reg [3:0] ctrl_fsm_cs;
reg [3:0] ctrl_fsm_ns;
reg irq_enable_int;
reg debug_mode_q;
reg debug_mode_n;
function automatic [5:0] sv2v_cast_6;
input reg [5:0] inp;
sv2v_cast_6 = inp;
endfunction
always @(*) begin
instr_req_o = 1'b1;
exc_ack_o = 1'b0;
exc_kill_o = 1'b0;
csr_save_if_o = 1'b0;
csr_save_id_o = 1'b0;
csr_restore_mret_id_o = 1'b0;
csr_restore_dret_id_o = 1'b0;
csr_save_cause_o = 1'b0;
exc_cause_o = 6'h00;
exc_pc_mux_o = 3'd4;
csr_cause_o = 6'h00;
pc_mux_o = 3'd0;
pc_set_o = 1'b0;
ctrl_fsm_ns = ctrl_fsm_cs;
ctrl_busy_o = 1'b1;
is_decoding_o = 1'b0;
first_fetch_o = 1'b0;
halt_if_o = 1'b0;
halt_id_o = 1'b0;
irq_ack_o = 1'b0;
irq_id_o = irq_id_ctrl_i;
irq_enable_int = m_IE_i;
debug_csr_save_o = 1'b0;
debug_cause_o = 3'h1;
debug_mode_n = debug_mode_q;
perf_tbranch_o = 1'b0;
perf_jump_o = 1'b0;
case (ctrl_fsm_cs)
4'd0: begin
instr_req_o = 1'b0;
pc_mux_o = 3'd0;
pc_set_o = 1'b1;
if (fetch_enable_i)
ctrl_fsm_ns = 4'd1;
end
4'd1: begin
instr_req_o = 1'b1;
pc_mux_o = 3'd0;
pc_set_o = 1'b1;
ctrl_fsm_ns = 4'd4;
end
4'd2: begin
ctrl_busy_o = 1'b0;
instr_req_o = 1'b0;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
ctrl_fsm_ns = 4'd3;
end
4'd3: begin
ctrl_busy_o = 1'b0;
instr_req_o = 1'b0;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
if (((irq_i || debug_req_i) || debug_mode_q) || debug_single_step_i)
ctrl_fsm_ns = 4'd4;
end
4'd4: begin
first_fetch_o = 1'b1;
if (id_ready_i)
ctrl_fsm_ns = 4'd5;
if (irq_req_ctrl_i && irq_enable_int) begin
ctrl_fsm_ns = 4'd7;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
if (debug_req_i && !debug_mode_q) begin
ctrl_fsm_ns = 4'd8;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
end
4'd5: begin
is_decoding_o = 1'b0;
case (1'b1)
debug_req_i && !debug_mode_q: begin
ctrl_fsm_ns = 4'd9;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
((irq_req_ctrl_i && irq_enable_int) && !debug_req_i) && !debug_mode_q: begin
ctrl_fsm_ns = 4'd7;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
default: begin
exc_kill_o = (irq_req_ctrl_i & ~instr_multicyle_i) & ~branch_in_id_i;
if (instr_valid_i) begin
is_decoding_o = 1'b1;
if (branch_set_i || jump_set_i) begin
pc_mux_o = 3'd1;
pc_set_o = 1'b1;
perf_tbranch_o = branch_set_i;
perf_jump_o = jump_set_i;
end
else if ((((((mret_insn_i || dret_insn_i) || ecall_insn_i) || pipe_flush_i) || ebrk_insn_i) || illegal_insn_i) || csr_status_i) begin
ctrl_fsm_ns = 4'd6;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
end
end
endcase
if (debug_single_step_i && !debug_mode_q) begin
halt_if_o = 1'b1;
ctrl_fsm_ns = 4'd8;
end
end
4'd7: begin
pc_mux_o = 3'd2;
pc_set_o = 1'b1;
exc_pc_mux_o = 3'd4;
exc_cause_o = sv2v_cast_6({1'b0, irq_id_ctrl_i});
csr_save_cause_o = 1'b1;
csr_cause_o = sv2v_cast_6({1'b1, irq_id_ctrl_i});
csr_save_if_o = 1'b1;
irq_ack_o = 1'b1;
exc_ack_o = 1'b1;
ctrl_fsm_ns = 4'd5;
end
4'd8: begin
pc_mux_o = 3'd2;
pc_set_o = 1'b1;
exc_pc_mux_o = 3'd5;
csr_save_if_o = 1'b1;
debug_csr_save_o = 1'b1;
csr_save_cause_o = 1'b1;
if (debug_single_step_i)
debug_cause_o = 3'h4;
else if (debug_req_i)
debug_cause_o = 3'h3;
else if (ebrk_insn_i)
debug_cause_o = 3'h1;
debug_mode_n = 1'b1;
ctrl_fsm_ns = 4'd5;
end
4'd9: begin
pc_mux_o = 3'd2;
pc_set_o = 1'b1;
exc_pc_mux_o = 3'd5;
if (((ebrk_insn_i && debug_ebreakm_i) && !debug_mode_q) || (debug_req_i && !debug_mode_q)) begin
csr_save_cause_o = 1'b1;
csr_save_id_o = 1'b1;
debug_csr_save_o = 1'b1;
if (debug_req_i)
debug_cause_o = 3'h3;
else if (ebrk_insn_i)
debug_cause_o = 3'h1;
end
debug_mode_n = 1'b1;
ctrl_fsm_ns = 4'd5;
end
4'd6: begin
halt_if_o = 1'b1;
halt_id_o = 1'b1;
if (!pipe_flush_i)
ctrl_fsm_ns = 4'd5;
else
ctrl_fsm_ns = 4'd2;
case (1'b1)
ecall_insn_i: begin
pc_mux_o = 3'd2;
pc_set_o = 1'b1;
csr_save_id_o = 1'b1;
csr_save_cause_o = 1'b1;
exc_pc_mux_o = 3'd1;
exc_cause_o = 6'h0b;
csr_cause_o = 6'h0b;
end
illegal_insn_i: begin
pc_mux_o = 3'd2;
pc_set_o = 1'b1;
csr_save_id_o = 1'b1;
csr_save_cause_o = 1'b1;
if (debug_mode_q)
exc_pc_mux_o = 3'd6;
else
exc_pc_mux_o = 3'd0;
exc_cause_o = 6'h02;
csr_cause_o = 6'h02;
end
mret_insn_i: begin
pc_mux_o = 3'd3;
pc_set_o = 1'b1;
csr_restore_mret_id_o = 1'b1;
end
dret_insn_i: begin
pc_mux_o = 3'd4;
pc_set_o = 1'b1;
debug_mode_n = 1'b0;
csr_restore_dret_id_o = 1'b1;
end
ebrk_insn_i:
if (debug_mode_q)
ctrl_fsm_ns = 4'd9;
else if (debug_ebreakm_i)
ctrl_fsm_ns = 4'd9;
else begin
pc_mux_o = 3'd2;
pc_set_o = 1'b1;
csr_save_id_o = 1'b1;
csr_save_cause_o = 1'b1;
exc_pc_mux_o = 3'd7;
exc_cause_o = 6'h03;
csr_cause_o = 6'h03;
end
default:
;
endcase
end
default: begin
instr_req_o = 1'b0;
ctrl_fsm_ns = 4'd0;
end
endcase
end
assign deassert_we_o = ~is_decoding_o | illegal_insn_i;
assign operand_a_fw_mux_sel_o = (data_misaligned_i ? 1'd1 : 1'd0);
always @(posedge clk or negedge rst_n) begin : UPDATE_REGS
if (!rst_n) begin
ctrl_fsm_cs <= 4'd0;
debug_mode_q <= 1'b0;
end
else begin
ctrl_fsm_cs <= ctrl_fsm_ns;
debug_mode_q <= debug_mode_n;
end
end
endmodule