decoupled irq, debug with instr mem

This commit is contained in:
Pasquale Davide Schiavone 2017-03-30 13:49:52 +02:00
parent 6c679d41c4
commit f7c2b64270
8 changed files with 105 additions and 117 deletions

View file

@ -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,

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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