mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 04:57:25 -04:00
Rework pipeline flushes and exceptions
WFI is working again, exception controller now only handles exceptions (untested) and no flushes anymore
This commit is contained in:
parent
dd57252f60
commit
88b91c20c5
5 changed files with 80 additions and 114 deletions
|
@ -98,10 +98,9 @@ module controller
|
|||
input logic illegal_c_insn_i, // compressed instruction decode failed
|
||||
output logic illegal_insn_o, // illegal instruction encountered
|
||||
output logic trap_insn_o, // trap instruction encountered
|
||||
output logic pipe_flush_o, // pipe flush requested by controller
|
||||
input logic pc_valid_i, // is the next_pc currently valid?
|
||||
output logic clear_isr_running_o, // an l.rfe instruction was encountered, exit ISR
|
||||
input logic pipe_flushed_i, // Pipe is flushed
|
||||
input logic exc_pipe_flush_i, // flush pipeline after exception handling
|
||||
input logic trap_hit_i, // a trap was hit, so we have to flush EX and WB
|
||||
|
||||
// Debug Unit Signals
|
||||
|
@ -138,7 +137,8 @@ module controller
|
|||
);
|
||||
|
||||
// FSM state encoding
|
||||
enum logic [3:0] { RESET, IDLE, FIRST_FETCH, DECODE, BRANCH, BRANCH_DELAY,
|
||||
enum logic [3:0] { RESET, SLEEP, FIRST_FETCH, DECODE, BRANCH, BRANCH_DELAY,
|
||||
FLUSH_EX, FLUSH_WB,
|
||||
DBG_FLUSH_EX, DBG_FLUSH_WB, DBG_SIGNAL, DBG_WAIT } ctrl_fsm_cs, ctrl_fsm_ns;
|
||||
|
||||
logic reg_d_ex_is_reg_a_id;
|
||||
|
@ -159,6 +159,8 @@ module controller
|
|||
logic data_req;
|
||||
logic [1:0] jump_in_id;
|
||||
logic [1:0] csr_op;
|
||||
logic pipe_flush;
|
||||
logic trap_insn;
|
||||
logic deassert_we;
|
||||
|
||||
logic lsu_stall;
|
||||
|
@ -176,7 +178,8 @@ module controller
|
|||
logic regb_used;
|
||||
logic regc_used;
|
||||
|
||||
logic dbg_halt;
|
||||
logic halt_if;
|
||||
logic halt_id;
|
||||
logic illegal_insn_int;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
|
@ -229,8 +232,8 @@ module controller
|
|||
clear_isr_running_o = 1'b0;
|
||||
|
||||
illegal_insn_int = 1'b0;
|
||||
trap_insn_o = 1'b0;
|
||||
pipe_flush_o = 1'b0;
|
||||
trap_insn = 1'b0;
|
||||
pipe_flush = 1'b0;
|
||||
|
||||
rega_used = 1'b0;
|
||||
regb_used = 1'b0;
|
||||
|
@ -817,7 +820,7 @@ module controller
|
|||
32'h00_10_00_73: // EBREAK
|
||||
begin
|
||||
// debugger trap
|
||||
trap_insn_o = 1'b1;
|
||||
trap_insn = 1'b1;
|
||||
end
|
||||
|
||||
32'h10_00_00_73: // ERET
|
||||
|
@ -830,7 +833,7 @@ module controller
|
|||
32'h10_20_00_73: // WFI
|
||||
begin
|
||||
// flush pipeline
|
||||
pipe_flush_o = 1'b1;
|
||||
pipe_flush = 1'b1;
|
||||
end
|
||||
|
||||
default:
|
||||
|
@ -1008,7 +1011,8 @@ module controller
|
|||
|
||||
core_busy_o = 1'b1;
|
||||
|
||||
dbg_halt = 1'b0;
|
||||
halt_if = 1'b0;
|
||||
halt_id = 1'b0;
|
||||
dbg_trap_o = 1'b0;
|
||||
illegal_insn_o = 1'b0;
|
||||
|
||||
|
@ -1030,18 +1034,20 @@ module controller
|
|||
ctrl_fsm_ns = FIRST_FETCH;
|
||||
end
|
||||
|
||||
IDLE:
|
||||
// instruction in IF stage is already valid, so just jump to DECODE
|
||||
// instead of FIRST_FETCH
|
||||
SLEEP:
|
||||
begin
|
||||
// we begin execution when either fetch_enable is high or an
|
||||
// interrupt has arrived
|
||||
core_busy_o = 1'b0;
|
||||
instr_req_o = fetch_enable_i || irq_present_i;
|
||||
instr_req_o = fetch_enable_i || irq_present_i;
|
||||
|
||||
if (fetch_enable_i || irq_present_i)
|
||||
begin
|
||||
ctrl_fsm_ns = FIRST_FETCH;
|
||||
ctrl_fsm_ns = DECODE;
|
||||
end
|
||||
end // case: IDLE
|
||||
end // case: SLEEP
|
||||
|
||||
FIRST_FETCH:
|
||||
begin
|
||||
|
@ -1080,9 +1086,14 @@ module controller
|
|||
illegal_insn_o = 1'b1;
|
||||
end
|
||||
|
||||
// the pipeline is flushed and we are requested to go to sleep
|
||||
if ((pipe_flushed_i == 1'b1) && (fetch_enable_i == 1'b0))
|
||||
ctrl_fsm_ns = IDLE;
|
||||
// handle WFI instruction, flush pipeline and (potentially) go to
|
||||
// sleep
|
||||
if (pipe_flush || exc_pipe_flush_i)
|
||||
begin
|
||||
halt_if = 1'b1;
|
||||
|
||||
ctrl_fsm_ns = FLUSH_EX;
|
||||
end
|
||||
|
||||
// take care of debug
|
||||
// branches take two cycles, jumps just one
|
||||
|
@ -1090,7 +1101,8 @@ module controller
|
|||
// TODO: there is a bug here, I'm sure of it
|
||||
if(trap_hit_i == 1'b1 && stall_ex_o == 1'b0 && jump_in_id == 2'b0 && jump_in_ex_i == 2'b0)
|
||||
begin
|
||||
dbg_halt = 1'b1;
|
||||
halt_if = 1'b1;
|
||||
halt_id = 1'b1;
|
||||
ctrl_fsm_ns = DBG_FLUSH_EX;
|
||||
end
|
||||
end
|
||||
|
@ -1119,7 +1131,8 @@ module controller
|
|||
|
||||
DBG_FLUSH_EX:
|
||||
begin
|
||||
dbg_halt = 1'b1;
|
||||
halt_if = 1'b1;
|
||||
halt_id = 1'b1;
|
||||
|
||||
if(stall_ex_o == 1'b0)
|
||||
ctrl_fsm_ns = DBG_FLUSH_WB;
|
||||
|
@ -1127,7 +1140,8 @@ module controller
|
|||
|
||||
DBG_FLUSH_WB:
|
||||
begin
|
||||
dbg_halt = 1'b1;
|
||||
halt_if = 1'b1;
|
||||
halt_id = 1'b1;
|
||||
|
||||
if(stall_ex_o == 1'b0)
|
||||
ctrl_fsm_ns = DBG_SIGNAL;
|
||||
|
@ -1136,7 +1150,8 @@ module controller
|
|||
DBG_SIGNAL:
|
||||
begin
|
||||
dbg_trap_o = 1'b1;
|
||||
dbg_halt = 1'b1;
|
||||
halt_if = 1'b1;
|
||||
halt_id = 1'b1;
|
||||
|
||||
ctrl_fsm_ns = DBG_WAIT;
|
||||
end
|
||||
|
@ -1149,6 +1164,36 @@ module controller
|
|||
if(dbg_stall_i == 1'b0)
|
||||
ctrl_fsm_ns = DECODE;
|
||||
end
|
||||
|
||||
FLUSH_EX:
|
||||
begin
|
||||
halt_if = 1'b1;
|
||||
halt_id = 1'b1;
|
||||
|
||||
if(~stall_ex_o)
|
||||
ctrl_fsm_ns = FLUSH_WB;
|
||||
end
|
||||
|
||||
FLUSH_WB:
|
||||
begin
|
||||
halt_if = 1'b1;
|
||||
halt_id = 1'b1;
|
||||
|
||||
if(~stall_wb_o)
|
||||
begin
|
||||
if (fetch_enable_i == 1'b0)
|
||||
ctrl_fsm_ns = SLEEP;
|
||||
else
|
||||
begin
|
||||
// unstall pipeline and continue operation
|
||||
halt_if = 1'b1;
|
||||
halt_id = 1'b0;
|
||||
|
||||
if (~stall_id_o)
|
||||
ctrl_fsm_ns = DECODE;
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
|
@ -1212,6 +1257,7 @@ module controller
|
|||
assign data_we_o = (deassert_we) ? 1'b0 : data_we;
|
||||
assign data_req_o = (deassert_we) ? 1'b0 : data_req;
|
||||
assign csr_op_o = (deassert_we) ? `CSR_OP_NONE : csr_op;
|
||||
assign trap_insn_o = (deassert_we) ? 1'b0 : trap_insn;
|
||||
assign jump_in_id_o = (deassert_we) ? `BRANCH_NONE : jump_in_id;
|
||||
|
||||
|
||||
|
@ -1223,8 +1269,8 @@ module controller
|
|||
// we unstall the if_stage if the debug unit wants to set a new
|
||||
// pc, so that the new value gets written into current_pc_if and is
|
||||
// used by the instr_core_interface
|
||||
stall_if_o = instr_ack_stall | load_stall | jr_stall | lsu_stall | misalign_stall | dbg_halt | dbg_stall_i | (~pc_valid_i) | (jump_in_id_o == `BRANCH_COND);
|
||||
stall_id_o = instr_ack_stall | load_stall | jr_stall | lsu_stall | misalign_stall | dbg_halt | dbg_stall_i;
|
||||
stall_if_o = instr_ack_stall | load_stall | jr_stall | lsu_stall | misalign_stall | halt_if | dbg_stall_i | (~pc_valid_i) | (jump_in_id_o == `BRANCH_COND);
|
||||
stall_id_o = instr_ack_stall | load_stall | jr_stall | lsu_stall | misalign_stall | halt_id | dbg_stall_i;
|
||||
stall_ex_o = instr_ack_stall | lsu_stall | dbg_stall_i;
|
||||
stall_wb_o = lsu_stall | dbg_stall_i;
|
||||
end
|
||||
|
|
|
@ -51,7 +51,6 @@ module debug_unit
|
|||
|
||||
output logic stall_core_o,
|
||||
output logic flush_pipe_o,
|
||||
input logic pipe_flushed_i,
|
||||
input logic trap_i,
|
||||
|
||||
output logic sp_mux_o,
|
||||
|
|
|
@ -58,21 +58,20 @@ module exc_controller
|
|||
input logic illegal_insn_i, // Illegal instruction encountered in ID stage
|
||||
input logic trap_insn_i, // Trap instruction encountered in ID stage
|
||||
input logic drop_instruction_i, // If branch prediction went wrong
|
||||
input logic pipe_flush_i, // pipe flush requested by controller
|
||||
output logic pc_valid_o, // is the PC in the IF stage currently valid?
|
||||
input logic clear_isr_running_i, // exit ISR routine
|
||||
output logic exc_pipe_flush_o, // flush pipeline and go back to sleep
|
||||
|
||||
// Debug Unit Signals
|
||||
input logic dbg_flush_pipe_i, // Pipe flush requested
|
||||
output logic pipe_flushed_o, // Pipe is flushed
|
||||
input logic dbg_st_en_i, // Single-step trace mode enabled
|
||||
input logic [1:0] dbg_dsr_i, // Debug Stop Register
|
||||
output logic trap_hit_o // Software Trap in ID (l.trap or similar stuff)
|
||||
);
|
||||
|
||||
// Exception unit state encoding
|
||||
enum logic [2:0] { Idle, NopDelay, NopDelayIR, NopID, NopEX, NopWB} exc_fsm_cs, exc_fsm_ns;
|
||||
enum logic [1:0] { ExcNone, ExcIR, ExcFlush, ExcIllegalInsn } exc_reason_p, exc_reason_n, exc_reason;
|
||||
enum logic [0:0] { Idle, NopDelayIR } exc_fsm_cs, exc_fsm_ns;
|
||||
enum logic [1:0] { ExcNone, ExcIR, ExcIllegalInsn } exc_reason_p, exc_reason_n, exc_reason;
|
||||
|
||||
// Registers
|
||||
logic exc_running_p, exc_running_n;
|
||||
|
@ -108,7 +107,8 @@ module exc_controller
|
|||
// The decoder also takes care that no nested exceptions are performed
|
||||
always_comb
|
||||
begin
|
||||
exc_reason = ExcNone;
|
||||
exc_reason = ExcNone;
|
||||
exc_pipe_flush_o = 1'b0;
|
||||
|
||||
if (illegal_insn_i == 1'b1)
|
||||
begin
|
||||
|
@ -127,11 +127,6 @@ module exc_controller
|
|||
if (dbg_dsr_i[`DSR_INTE] == 1'b0)
|
||||
exc_reason = ExcIR;
|
||||
end
|
||||
else if(pipe_flush_i == 1'b1)
|
||||
begin
|
||||
// flushing pipeline because of l.psync
|
||||
exc_reason = ExcFlush;
|
||||
end
|
||||
else if (clear_isr_running_i == 1'b1)
|
||||
begin
|
||||
// if we receive an l.rfe instruction when we are not in an
|
||||
|
@ -144,7 +139,7 @@ module exc_controller
|
|||
|
||||
// the CPU should go back to sleep
|
||||
if(fetch_enable_i == 1'b0)
|
||||
exc_reason = ExcFlush;
|
||||
exc_pipe_flush_o = 1'b1;
|
||||
end
|
||||
else
|
||||
exc_reason = ExcIllegalInsn;
|
||||
|
@ -169,7 +164,6 @@ module exc_controller
|
|||
save_pc_if_o = 1'b0;
|
||||
save_pc_id_o = 1'b0;
|
||||
save_sr_o = 1'b0;
|
||||
pipe_flushed_o = 1'b0;
|
||||
force_nop_o = 1'b0;
|
||||
pc_valid_o = 1'b1;
|
||||
exc_pc_sel_o = 1'b0;
|
||||
|
@ -182,26 +176,6 @@ module exc_controller
|
|||
exc_reason_n = exc_reason;
|
||||
|
||||
unique case (exc_reason_n)
|
||||
// A flush of the pipeline was requested by the debug
|
||||
// unit or an l.psync instruction
|
||||
// execute pending delay slot (l.psync won't have one),
|
||||
// flush the pipeline and stop
|
||||
ExcFlush: begin
|
||||
if (jump_in_id_i == 2'b00)
|
||||
begin // no delay slot
|
||||
force_nop_o = 1'b1;
|
||||
exc_pc_sel_o = 1'b1;
|
||||
exc_pc_mux_o = `EXC_PC_NO_INCR;
|
||||
pc_valid_o = 1'b0;
|
||||
|
||||
exc_fsm_ns = NopID;
|
||||
end
|
||||
else
|
||||
begin // delay slot
|
||||
exc_fsm_ns = NopDelay;
|
||||
end
|
||||
end
|
||||
|
||||
// an IRQ is present, execute pending delay slots and jump
|
||||
// to the ISR without flushing the pipeline
|
||||
ExcIR: begin
|
||||
|
@ -262,54 +236,6 @@ module exc_controller
|
|||
exc_fsm_ns = Idle;
|
||||
end
|
||||
|
||||
|
||||
// Execute delay slot, start to force NOPs for new instructions
|
||||
NopDelay:
|
||||
begin
|
||||
force_nop_o = 1'b1;
|
||||
exc_pc_sel_o = 1'b1;
|
||||
exc_pc_mux_o = `EXC_PC_NO_INCR;
|
||||
pc_valid_o = 1'b0;
|
||||
|
||||
exc_fsm_ns = NopID;
|
||||
end
|
||||
|
||||
// First NOP is in ID stage
|
||||
NopID:
|
||||
begin
|
||||
force_nop_o = 1'b1;
|
||||
exc_pc_sel_o = 1'b1;
|
||||
exc_pc_mux_o = `EXC_PC_NO_INCR;
|
||||
pc_valid_o = 1'b0;
|
||||
|
||||
exc_fsm_ns = NopEX;
|
||||
end
|
||||
|
||||
// First NOP is in EX stage
|
||||
NopEX:
|
||||
begin
|
||||
force_nop_o = 1'b1;
|
||||
pc_valid_o = 1'b0;
|
||||
exc_pc_sel_o = 1'b1;
|
||||
exc_pc_mux_o = `EXC_PC_NO_INCR;
|
||||
|
||||
exc_fsm_ns = NopWB;
|
||||
end
|
||||
|
||||
// First NOP is in WB stage
|
||||
// Pipeline is flushed now
|
||||
NopWB: begin
|
||||
exc_pc_sel_o = 1'b1;
|
||||
exc_pc_mux_o = `EXC_PC_NO_INCR;
|
||||
pipe_flushed_o = 1'b1;
|
||||
|
||||
pc_valid_o = 1'b0;
|
||||
force_nop_o = 1'b1;
|
||||
|
||||
clear_exc_reason = 1'b1;
|
||||
exc_fsm_ns = Idle;
|
||||
end
|
||||
|
||||
default: exc_fsm_ns = Idle;
|
||||
endcase // case (exc_fsm_cs)
|
||||
end
|
||||
|
@ -340,7 +266,7 @@ module exc_controller
|
|||
begin : EXC_DISPLAY
|
||||
if ( rst_n == 1'b1 )
|
||||
begin
|
||||
if (exc_reason_n != ExcNone && exc_reason_n != ExcFlush)
|
||||
if (exc_reason_n != ExcNone)
|
||||
$display("%t: Entering exception routine.", $time);
|
||||
end
|
||||
end
|
||||
|
|
|
@ -128,7 +128,6 @@ module id_stage
|
|||
|
||||
// Debug Unit Signals
|
||||
input logic dbg_flush_pipe_i,
|
||||
output logic pipe_flushed_o,
|
||||
input logic dbg_st_en_i,
|
||||
input logic [1:0] dbg_dsr_i,
|
||||
input logic dbg_stall_i,
|
||||
|
@ -193,9 +192,9 @@ module id_stage
|
|||
logic illegal_c_insn;
|
||||
logic trap_insn;
|
||||
logic trap_hit;
|
||||
logic pipe_flush;
|
||||
logic pc_valid;
|
||||
logic clear_isr_running;
|
||||
logic exc_pipe_flush;
|
||||
|
||||
|
||||
logic [4:0] regfile_addr_ra_id;
|
||||
|
@ -596,11 +595,10 @@ module id_stage
|
|||
.illegal_c_insn_i ( illegal_c_insn ),
|
||||
.illegal_insn_o ( illegal_insn ),
|
||||
.trap_insn_o ( trap_insn ),
|
||||
.pipe_flush_o ( pipe_flush ),
|
||||
.pc_valid_i ( pc_valid ),
|
||||
.clear_isr_running_o ( clear_isr_running ),
|
||||
.pipe_flushed_i ( pipe_flushed_o ),
|
||||
.trap_hit_i ( trap_hit ),
|
||||
.exc_pipe_flush_i ( exc_pipe_flush ),
|
||||
|
||||
// Debug Unit Signals
|
||||
.dbg_stall_i ( dbg_stall_i ),
|
||||
|
@ -687,14 +685,13 @@ module id_stage
|
|||
.illegal_insn_i ( illegal_insn ),
|
||||
.trap_insn_i ( trap_insn ),
|
||||
.drop_instruction_i ( 1'b0 ),
|
||||
.pipe_flush_i ( pipe_flush ),
|
||||
.pc_valid_o ( pc_valid ),
|
||||
.clear_isr_running_i ( clear_isr_running ),
|
||||
.trap_hit_o ( trap_hit ),
|
||||
.exc_pipe_flush_o ( exc_pipe_flush ),
|
||||
|
||||
// Debug Unit Signals
|
||||
.dbg_flush_pipe_i ( dbg_flush_pipe_i ),
|
||||
.pipe_flushed_o ( pipe_flushed_o ),
|
||||
.dbg_st_en_i ( dbg_st_en_i ),
|
||||
.dbg_dsr_i ( dbg_dsr_i )
|
||||
);
|
||||
|
|
|
@ -213,7 +213,6 @@ module riscv_core
|
|||
// Debug Unit
|
||||
logic dbg_stall;
|
||||
logic dbg_flush_pipe;
|
||||
logic pipe_flushed;
|
||||
logic dbg_trap;
|
||||
logic dbg_st_en; // single-step trace mode enabled
|
||||
logic [1:0] dbg_dsr; // Debug Stop Register
|
||||
|
@ -404,7 +403,6 @@ module riscv_core
|
|||
|
||||
// Debug Unit Signals
|
||||
.dbg_flush_pipe_i ( dbg_flush_pipe ),
|
||||
.pipe_flushed_o ( pipe_flushed ),
|
||||
.dbg_st_en_i ( dbg_st_en ),
|
||||
.dbg_dsr_i ( dbg_dsr ),
|
||||
.dbg_stall_i ( dbg_stall ),
|
||||
|
@ -683,7 +681,6 @@ module riscv_core
|
|||
.dbg_dsr_o ( dbg_dsr ),
|
||||
.stall_core_o ( dbg_stall ),
|
||||
.flush_pipe_o ( dbg_flush_pipe ),
|
||||
.pipe_flushed_i ( pipe_flushed ),
|
||||
.trap_i ( dbg_trap ),
|
||||
|
||||
// register file access
|
||||
|
@ -748,7 +745,8 @@ module riscv_core
|
|||
rs2 = instr[`REG_S2];
|
||||
rs2_value = id_stage_i.operand_b_fw_id;
|
||||
|
||||
if (id_stage_i.stall_id_o == 1'b0 && id_stage_i.controller_i.ctrl_fsm_cs == id_stage_i.controller_i.DECODE)
|
||||
// special case for WFI because we don't wait for unstalling there
|
||||
if ((id_stage_i.stall_id_o == 1'b0 && id_stage_i.controller_i.ctrl_fsm_cs == id_stage_i.controller_i.DECODE) || id_stage_i.controller_i.pipe_flush)
|
||||
begin
|
||||
mnemonic = "";
|
||||
imm = 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue