mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 12:57:13 -04:00
decoupled irq, debug with instr mem
This commit is contained in:
parent
6c679d41c4
commit
f7c2b64270
8 changed files with 105 additions and 117 deletions
|
@ -12,7 +12,7 @@ zeroriscy:
|
|||
zeroriscy_debug_unit.sv,
|
||||
zeroriscy_decoder.sv,
|
||||
zeroriscy_exc_controller.sv,
|
||||
zeroriscy_ex_stage.sv,
|
||||
zeroriscy_ex_block.sv,
|
||||
zeroriscy_id_stage.sv,
|
||||
zeroriscy_if_stage.sv,
|
||||
zeroriscy_load_store_unit.sv,
|
||||
|
|
|
@ -49,6 +49,7 @@ module zeroriscy_controller
|
|||
input logic illegal_insn_i, // decoder encountered an invalid instruction
|
||||
input logic mret_insn_i, // decoder encountered an eret instruction
|
||||
input logic pipe_flush_i, // decoder wants to do a pipe flush
|
||||
input logic ebrk_insn_i, // decoder encountered an ebreak instruction
|
||||
|
||||
// from IF/ID pipeline
|
||||
input logic instr_valid_i, // instruction coming from IF/ID pipeline is valid
|
||||
|
@ -111,7 +112,7 @@ module zeroriscy_controller
|
|||
// FSM state encoding
|
||||
|
||||
enum logic [3:0] { RESET, BOOT_SET, SLEEP, FIRST_FETCH,
|
||||
DECODE, FLUSH,
|
||||
DECODE, FLUSH, IRQ_TAKEN,
|
||||
DBG_SIGNAL, DBG_SIGNAL_SLEEP, DBG_WAIT, DBG_WAIT_BRANCH, DBG_WAIT_SLEEP } ctrl_fsm_cs, ctrl_fsm_ns;
|
||||
|
||||
logic exc_req;
|
||||
|
@ -227,15 +228,12 @@ module zeroriscy_controller
|
|||
ctrl_fsm_ns = DECODE;
|
||||
end
|
||||
|
||||
// handle exceptions
|
||||
if (ext_req_i) begin
|
||||
pc_mux_o = PC_EXCEPTION;
|
||||
pc_set_o = 1'b1;
|
||||
exc_ack_o = 1'b1;
|
||||
irq_ack_o = ext_req_i;
|
||||
// TODO: This assumes that the pipeline is always flushed before
|
||||
// going to sleep.
|
||||
exc_save_if_o = 1'b1;
|
||||
// This assumes that the pipeline is always flushed before
|
||||
// going to sleep.
|
||||
ctrl_fsm_ns = IRQ_TAKEN;
|
||||
halt_if_o = 1'b1;
|
||||
halt_id_o = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -266,51 +264,52 @@ module zeroriscy_controller
|
|||
end
|
||||
int_req_i: begin
|
||||
ctrl_fsm_ns = FLUSH;
|
||||
halt_if_o = 1'b1;
|
||||
halt_id_o = 1'b1;
|
||||
halt_if_o = 1'b1;
|
||||
halt_id_o = 1'b1;
|
||||
end
|
||||
mret_insn_i: begin
|
||||
ctrl_fsm_ns = FLUSH;
|
||||
halt_if_o = 1'b1;
|
||||
halt_id_o = 1'b1;
|
||||
halt_if_o = 1'b1;
|
||||
halt_id_o = 1'b1;
|
||||
end
|
||||
pipe_flush_i: begin
|
||||
// handle WFI instruction, flush pipeline and (potentially) go to
|
||||
// sleep
|
||||
ctrl_fsm_ns = FLUSH;
|
||||
halt_if_o = 1'b1;
|
||||
halt_id_o = 1'b1;
|
||||
end
|
||||
ebrk_insn_i: begin
|
||||
ctrl_fsm_ns = FLUSH;
|
||||
halt_if_o = 1'b1;
|
||||
halt_id_o = 1'b1;
|
||||
end
|
||||
default: begin
|
||||
|
||||
if (ext_req_i & ~instr_multicyle_i & ~branch_in_id_i) begin
|
||||
ctrl_fsm_ns = FLUSH;
|
||||
unique case (1'b1)
|
||||
ext_req_i & ~instr_multicyle_i & ~branch_in_id_i: begin
|
||||
ctrl_fsm_ns = IRQ_TAKEN;
|
||||
halt_if_o = 1'b1;
|
||||
halt_id_o = 1'b1;
|
||||
end
|
||||
// handle WFI instruction, flush pipeline and (potentially) go to
|
||||
// sleep TODO: put it in unique case
|
||||
else if (pipe_flush_i) begin
|
||||
halt_if_o = 1'b1;
|
||||
halt_id_o = 1'b1;
|
||||
ctrl_fsm_ns = FLUSH;
|
||||
end
|
||||
else if (dbg_req_i & ~branch_taken_ex_i)
|
||||
begin
|
||||
halt_if_o = 1'b1;
|
||||
if (id_ready_i) begin
|
||||
ctrl_fsm_ns = DBG_SIGNAL;
|
||||
end
|
||||
end
|
||||
dbg_req_i & ~branch_taken_ex_i: begin
|
||||
halt_if_o = 1'b1;
|
||||
if (id_ready_i) begin
|
||||
ctrl_fsm_ns = DBG_SIGNAL;
|
||||
end
|
||||
end
|
||||
default:;
|
||||
endcase
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
else if (~instr_valid_i)
|
||||
else //~instr_valid_i
|
||||
begin
|
||||
if (ext_req_i) begin
|
||||
pc_mux_o = PC_EXCEPTION;
|
||||
pc_set_o = 1'b1;
|
||||
exc_ack_o = 1'b1;
|
||||
exc_save_if_o = 1'b1;
|
||||
irq_ack_o = 1'b1;
|
||||
// we don't have to change our current state here as the prefetch
|
||||
// buffer is automatically invalidated, thus the next instruction
|
||||
// that is served to the ID stage is the one of the jump to the
|
||||
// exception handler
|
||||
ctrl_fsm_ns = IRQ_TAKEN;
|
||||
halt_if_o = 1'b1;
|
||||
halt_id_o = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -375,17 +374,7 @@ module zeroriscy_controller
|
|||
halt_id_o = 1'b1;
|
||||
|
||||
if(fetch_enable_i) begin
|
||||
if (dbg_req_i) begin
|
||||
ctrl_fsm_ns = DBG_SIGNAL;
|
||||
if(int_req_i) begin
|
||||
//exceptions
|
||||
pc_mux_o = PC_EXCEPTION;
|
||||
pc_set_o = 1'b1;
|
||||
exc_ack_o = 1'b1;
|
||||
exc_save_id_o = 1'b1;
|
||||
end
|
||||
end else begin
|
||||
ctrl_fsm_ns = DECODE;
|
||||
ctrl_fsm_ns = dbg_req_i ? DBG_SIGNAL : DECODE;
|
||||
unique case (1'b1)
|
||||
int_req_i: begin
|
||||
pc_mux_o = PC_EXCEPTION;
|
||||
|
@ -398,35 +387,33 @@ module zeroriscy_controller
|
|||
pc_set_o = 1'b1;
|
||||
exc_restore_id_o = 1'b1;
|
||||
end
|
||||
ext_req_i: begin
|
||||
pc_mux_o = PC_EXCEPTION;
|
||||
pc_set_o = 1'b1;
|
||||
exc_ack_o = 1'b1;
|
||||
//the instruction in id has been already executed
|
||||
exc_save_if_o = 1'b1;
|
||||
irq_ack_o = 1'b1;
|
||||
end
|
||||
default: begin
|
||||
halt_if_o = 1'b0;
|
||||
halt_if_o = dbg_req_i;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
//end
|
||||
end else begin //~fetch_enable_i
|
||||
//mRET goes back to sleep
|
||||
if(mret_insn_i) begin
|
||||
//in order to restore the xPIE in xIE
|
||||
exc_restore_id_o = 1'b1;
|
||||
pc_mux_o = PC_ERET;
|
||||
pc_set_o = 1'b1;
|
||||
end
|
||||
if (dbg_req_i) begin
|
||||
ctrl_fsm_ns = DBG_SIGNAL_SLEEP;
|
||||
end else begin
|
||||
ctrl_fsm_ns = SLEEP;
|
||||
if (mret_insn_i) begin
|
||||
pc_mux_o = PC_ERET;
|
||||
pc_set_o = 1'b1;
|
||||
exc_restore_id_o = 1'b1;
|
||||
end
|
||||
ctrl_fsm_ns = dbg_req_i ? DBG_SIGNAL_SLEEP : SLEEP;
|
||||
end
|
||||
end
|
||||
|
||||
IRQ_TAKEN:
|
||||
begin
|
||||
pc_mux_o = PC_EXCEPTION;
|
||||
pc_set_o = 1'b1;
|
||||
exc_ack_o = 1'b1;
|
||||
//the instruction in id has been already executed or it was not valid
|
||||
exc_save_if_o = 1'b1;
|
||||
irq_ack_o = 1'b1;
|
||||
ctrl_fsm_ns = DECODE;
|
||||
end
|
||||
|
||||
default: begin
|
||||
instr_req_o = 1'b0;
|
||||
ctrl_fsm_ns = RESET;
|
||||
|
|
|
@ -304,7 +304,7 @@ module zeroriscy_core
|
|||
.exception_pc_reg_i ( mepc ), // exception return address
|
||||
.pc_mux_i ( pc_mux_id ), // sel for pc multiplexer
|
||||
.exc_pc_mux_i ( exc_pc_mux_id ),
|
||||
.exc_vec_pc_mux_i ( irq_id_i ),
|
||||
.exc_vec_pc_mux_i ( exc_cause[4:0] ),
|
||||
|
||||
|
||||
// from debug unit
|
||||
|
|
|
@ -90,9 +90,6 @@ module zeroriscy_decoder
|
|||
logic regfile_we;
|
||||
logic data_req;
|
||||
|
||||
logic ebrk_insn;
|
||||
logic pipe_flush;
|
||||
|
||||
logic mult_int_en;
|
||||
logic div_int_en;
|
||||
logic branch_in_id;
|
||||
|
@ -139,10 +136,10 @@ module zeroriscy_decoder
|
|||
data_load_event_o = 1'b0;
|
||||
|
||||
illegal_insn_o = 1'b0;
|
||||
ebrk_insn = 1'b0;
|
||||
ebrk_insn_o = 1'b0;
|
||||
mret_insn_o = 1'b0;
|
||||
ecall_insn_o = 1'b0;
|
||||
pipe_flush = 1'b0;
|
||||
pipe_flush_o = 1'b0;
|
||||
|
||||
unique case (instr_rdata_i[6:0])
|
||||
|
||||
|
@ -494,7 +491,7 @@ module zeroriscy_decoder
|
|||
12'h001: // ebreak
|
||||
begin
|
||||
// debugger trap
|
||||
ebrk_insn = 1'b1;
|
||||
ebrk_insn_o = 1'b1;
|
||||
end
|
||||
|
||||
12'h302: // mret
|
||||
|
@ -505,7 +502,7 @@ module zeroriscy_decoder
|
|||
12'h105: // wfi
|
||||
begin
|
||||
// flush pipeline
|
||||
pipe_flush = 1'b1;
|
||||
pipe_flush_o = 1'b1;
|
||||
end
|
||||
|
||||
default:
|
||||
|
@ -580,7 +577,5 @@ module zeroriscy_decoder
|
|||
assign csr_op_o = (deassert_we_i) ? CSR_OP_NONE : csr_op;
|
||||
assign jump_in_id_o = (deassert_we_i) ? 1'b0 : jump_in_id;
|
||||
assign branch_in_id_o = (deassert_we_i) ? 1'b0 : branch_in_id;
|
||||
assign ebrk_insn_o = (deassert_we_i) ? 1'b0 : ebrk_insn;
|
||||
assign pipe_flush_o = (deassert_we_i) ? 1'b0 : pipe_flush;
|
||||
|
||||
endmodule // controller
|
||||
|
|
|
@ -37,6 +37,8 @@ module zeroriscy_exc_controller
|
|||
output logic ext_req_o,
|
||||
input logic ack_i,
|
||||
|
||||
input logic ctr_decoding_i,
|
||||
|
||||
output logic trap_o,
|
||||
|
||||
// to IF stage
|
||||
|
@ -61,11 +63,12 @@ module zeroriscy_exc_controller
|
|||
);
|
||||
|
||||
|
||||
enum logic [1:0] { IDLE, WAIT_CONTROLLER_INT, WAIT_CONTROLLER_EXT } exc_ctrl_cs, exc_ctrl_ns;
|
||||
enum logic [1:0] { IDLE, WAIT_CONTROLLER_INT, WAIT_CONTROLLER_EXT, WAIT_CONTROLLER_DBG } exc_ctrl_cs, exc_ctrl_ns;
|
||||
|
||||
logic req_int, int_req_int, ext_req_int;
|
||||
logic [1:0] pc_mux_int, pc_mux_int_q;
|
||||
logic [5:0] cause_int, cause_int_q;
|
||||
logic trap_int;
|
||||
|
||||
// a trap towards the debug unit is generated when one of the
|
||||
// following conditions are true:
|
||||
|
@ -74,19 +77,19 @@ module zeroriscy_exc_controller
|
|||
// - illegal instruction exception and IIE bit is set
|
||||
// - IRQ and INTE bit is set and no exception is currently running
|
||||
// - Debuger requests halt
|
||||
assign trap_o = (dbg_settings_i[DBG_SETS_SSTE])
|
||||
assign trap_int = (dbg_settings_i[DBG_SETS_SSTE])
|
||||
| (ecall_insn_i & dbg_settings_i[DBG_SETS_ECALL])
|
||||
| (ebrk_insn_i & dbg_settings_i[DBG_SETS_EBRK])
|
||||
| (illegal_insn_i & dbg_settings_i[DBG_SETS_EILL])
|
||||
| (irq_enable_i & irq_i & dbg_settings_i[DBG_SETS_IRQ]);
|
||||
|
||||
// request for exception/interrupt
|
||||
assign int_req_int = ecall_insn_i
|
||||
| illegal_insn_i;
|
||||
// request for exception/interrupt
|
||||
assign int_req_int = ecall_insn_i
|
||||
| illegal_insn_i;
|
||||
|
||||
assign ext_req_int = irq_enable_i & irq_i;
|
||||
assign ext_req_int = irq_enable_i & irq_i;
|
||||
|
||||
assign req_int = int_req_int | ext_req_int;
|
||||
assign req_int = int_req_int | ext_req_int;
|
||||
|
||||
// Exception cause and ISR address selection
|
||||
always_comb
|
||||
|
@ -131,7 +134,7 @@ assign req_int = int_req_int | ext_req_int;
|
|||
if (rst_n == 1'b0) begin
|
||||
cause_int_q <= '0;
|
||||
pc_mux_int_q <= '0;
|
||||
end else if (exc_ctrl_cs == IDLE && req_int) begin
|
||||
end else if (exc_ctrl_cs == IDLE && (ctr_decoding_i | ext_req_o)) begin
|
||||
// save cause and ISR when new irq request is first sent to controller
|
||||
cause_int_q <= cause_int;
|
||||
pc_mux_int_q <= pc_mux_int;
|
||||
|
@ -140,8 +143,10 @@ assign req_int = int_req_int | ext_req_int;
|
|||
|
||||
|
||||
// Exception cause and mux output (with bypass)
|
||||
assign cause_o = ((exc_ctrl_cs == IDLE && req_int) || ebrk_insn_i) ? cause_int : cause_int_q;
|
||||
assign pc_mux_o = (exc_ctrl_cs == IDLE && req_int) ? pc_mux_int : pc_mux_int_q;
|
||||
// assign cause_o = ((exc_ctrl_cs == IDLE && req_int) || ebrk_insn_i) ? cause_int : cause_int_q;
|
||||
// assign pc_mux_o = (exc_ctrl_cs == IDLE && req_int) ? pc_mux_int : pc_mux_int_q;
|
||||
assign cause_o = cause_int_q;
|
||||
assign pc_mux_o = pc_mux_int_q;
|
||||
|
||||
// Exception controller FSM
|
||||
always_comb
|
||||
|
@ -150,35 +155,30 @@ assign req_int = int_req_int | ext_req_int;
|
|||
int_req_o = 1'b0;
|
||||
ext_req_o = 1'b0;
|
||||
save_cause_o = 1'b0;
|
||||
trap_o = 1'b0;
|
||||
|
||||
unique case (exc_ctrl_cs)
|
||||
IDLE:
|
||||
begin
|
||||
int_req_o = int_req_int;
|
||||
ext_req_o = ext_req_int;
|
||||
if (int_req_int) begin
|
||||
exc_ctrl_ns = WAIT_CONTROLLER_INT;
|
||||
|
||||
if (ack_i) begin
|
||||
save_cause_o = 1'b1;
|
||||
exc_ctrl_ns = IDLE;
|
||||
end
|
||||
end else begin
|
||||
if (ext_req_o) begin
|
||||
exc_ctrl_ns = WAIT_CONTROLLER_EXT;
|
||||
|
||||
if (ack_i) begin
|
||||
save_cause_o = 1'b1;
|
||||
exc_ctrl_ns = IDLE;
|
||||
end
|
||||
end
|
||||
end
|
||||
trap_o = dbg_settings_i[DBG_SETS_SSTE];
|
||||
unique case(1'b1)
|
||||
int_req_int & ctr_decoding_i:
|
||||
exc_ctrl_ns = WAIT_CONTROLLER_INT;
|
||||
ebrk_insn_i & ctr_decoding_i:
|
||||
exc_ctrl_ns = WAIT_CONTROLLER_DBG;
|
||||
default:
|
||||
if (ext_req_o)
|
||||
exc_ctrl_ns = WAIT_CONTROLLER_EXT;
|
||||
endcase
|
||||
end
|
||||
|
||||
WAIT_CONTROLLER_INT:
|
||||
begin
|
||||
int_req_o = 1'b1;
|
||||
ext_req_o = 1'b0;
|
||||
trap_o = trap_int;
|
||||
if (ack_i) begin
|
||||
save_cause_o = 1'b1;
|
||||
exc_ctrl_ns = IDLE;
|
||||
|
@ -189,12 +189,19 @@ assign req_int = int_req_int | ext_req_int;
|
|||
begin
|
||||
int_req_o = 1'b0;
|
||||
ext_req_o = 1'b1;
|
||||
trap_o = trap_int;
|
||||
if (ack_i) begin
|
||||
save_cause_o = 1'b1;
|
||||
exc_ctrl_ns = IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
WAIT_CONTROLLER_DBG:
|
||||
begin
|
||||
exc_ctrl_ns = IDLE;
|
||||
trap_o = trap_int;
|
||||
end
|
||||
|
||||
default:
|
||||
begin
|
||||
exc_ctrl_ns = IDLE;
|
||||
|
|
|
@ -525,6 +525,7 @@ module zeroriscy_id_stage
|
|||
.illegal_insn_i ( illegal_insn_dec | illegal_reg_rv32e ),
|
||||
.mret_insn_i ( mret_insn_dec ),
|
||||
.pipe_flush_i ( pipe_flush_dec ),
|
||||
.ebrk_insn_i ( ebrk_insn ),
|
||||
|
||||
// from IF/ID pipeline
|
||||
.instr_valid_i ( instr_valid_i ),
|
||||
|
@ -600,9 +601,9 @@ module zeroriscy_id_stage
|
|||
.int_req_o ( int_req ),
|
||||
.ext_req_o ( ext_req ),
|
||||
.ack_i ( exc_ack ),
|
||||
.ctr_decoding_i ( is_decoding_o ),
|
||||
|
||||
.trap_o ( dbg_trap_o ),
|
||||
|
||||
// to IF stage
|
||||
.pc_mux_o ( exc_pc_mux_o ),
|
||||
|
||||
|
@ -611,9 +612,9 @@ module zeroriscy_id_stage
|
|||
.irq_id_i ( irq_id_i ),
|
||||
.irq_enable_i ( irq_enable_i ),
|
||||
|
||||
.ebrk_insn_i ( is_decoding_o & ebrk_insn ),
|
||||
.illegal_insn_i ( is_decoding_o & illegal_insn_dec ),
|
||||
.ecall_insn_i ( is_decoding_o & ecall_insn_dec ),
|
||||
.ebrk_insn_i ( ebrk_insn ),
|
||||
.illegal_insn_i ( illegal_insn_dec ),
|
||||
.ecall_insn_i ( ecall_insn_dec ),
|
||||
|
||||
.cause_o ( exc_cause_o ),
|
||||
.save_cause_o ( save_exc_cause_o ),
|
||||
|
@ -645,7 +646,7 @@ module zeroriscy_id_stage
|
|||
assign alu_operand_b_ex_o = alu_operand_b;
|
||||
|
||||
assign csr_access_ex_o = csr_access;
|
||||
assign csr_op_ex_o = id_ready_o ? csr_op : CSR_OP_NONE;
|
||||
assign csr_op_ex_o = csr_op;
|
||||
|
||||
assign branch_in_ex_o = branch_in_id;
|
||||
|
||||
|
@ -682,7 +683,7 @@ module zeroriscy_id_stage
|
|||
always_comb
|
||||
begin
|
||||
id_wb_fsm_ns = id_wb_fsm_cs;
|
||||
regfile_we = regfile_we_id & (~halt_id);
|
||||
regfile_we = regfile_we_id;
|
||||
load_stall = 1'b0;
|
||||
multdiv_stall = 1'b0;
|
||||
jump_stall = 1'b0;
|
||||
|
|
|
@ -102,10 +102,8 @@ module zeroriscy_if_stage
|
|||
unique case (exc_pc_mux_i)
|
||||
EXC_PC_ILLINSN: exc_pc = { boot_addr_i[31:8], EXC_OFF_ILLINSN };
|
||||
EXC_PC_ECALL: exc_pc = { boot_addr_i[31:8], EXC_OFF_ECALL };
|
||||
EXC_PC_LOAD: exc_pc = { boot_addr_i[31:8], EXC_OFF_LSUERR };
|
||||
EXC_PC_IRQ: exc_pc = { boot_addr_i[31:8], 1'b0, exc_vec_pc_mux_i[4:0], 2'b0 };
|
||||
// TODO: Add case for EXC_PC_STORE as soon as it differs from load
|
||||
|
||||
// TODO: Add case for EXC_PC_STORE and EXC_PC_LOAD as soon as they are supported
|
||||
default:;
|
||||
endcase
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue