mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 04:47:25 -04:00
Add an instr_valid_id signal to completely decouple the pipeline stages,
hopefully fixes the exception controller
This commit is contained in:
parent
4a166db65b
commit
f5d408d7f4
4 changed files with 117 additions and 111 deletions
181
controller.sv
181
controller.sv
|
@ -52,6 +52,7 @@ module riscv_controller
|
|||
input logic regc_used_i, // register C is used
|
||||
|
||||
// from IF/ID pipeline
|
||||
input logic instr_valid_i, // instruction coming from IF/ID pipeline is valid
|
||||
input logic [31:0] instr_rdata_i, // Instruction read from instr memory/cache: (sampled in the if stage)
|
||||
|
||||
// from prefetcher
|
||||
|
@ -125,7 +126,8 @@ module riscv_controller
|
|||
|
||||
// FSM state encoding
|
||||
enum logic [3:0] { RESET, BOOT_SET, SLEEP, FIRST_FETCH,
|
||||
DECODE, BRANCH_DELAY,
|
||||
DECODE,
|
||||
JUMP_EXC,
|
||||
FLUSH_EX, FLUSH_WB,
|
||||
DBG_WAIT_BRANCH, DBG_SIGNAL, DBG_WAIT } ctrl_fsm_cs, ctrl_fsm_ns;
|
||||
|
||||
|
@ -249,93 +251,104 @@ module riscv_controller
|
|||
|
||||
DECODE:
|
||||
begin
|
||||
is_decoding_o = 1'b1;
|
||||
is_decoding_o = 1'b0;
|
||||
|
||||
// decode and execute instructions only if the current conditional
|
||||
// branch in the EX stage is either not taken, or there is no
|
||||
// conditional branch in the EX stage
|
||||
if ((jump_in_ex_i == `BRANCH_COND && ~branch_decision_i) ||
|
||||
(jump_in_ex_i != `BRANCH_COND))
|
||||
begin // now analyze the current instruction in the ID stage
|
||||
// TODO: integrate this with the next loop, rename branch_decision
|
||||
// into branch_taken and remove the jump_in_ex signal completely,
|
||||
// there is no need to propagate it into the controller
|
||||
if (instr_valid_i) begin
|
||||
|
||||
// handle unconditional jumps
|
||||
// we can jump directly since we know the address already
|
||||
// we don't need to worry about conditional branches here as they
|
||||
// will be evaluated in the EX stage
|
||||
if (jump_in_dec_i == `BRANCH_JALR || jump_in_dec_i == `BRANCH_JAL) begin
|
||||
pc_mux_sel_o = `PC_JUMP;
|
||||
// decode and execute instructions only if the current conditional
|
||||
// branch in the EX stage is either not taken, or there is no
|
||||
// conditional branch in the EX stage
|
||||
if ((jump_in_ex_i == `BRANCH_COND && ~branch_decision_i) ||
|
||||
(jump_in_ex_i != `BRANCH_COND))
|
||||
begin // now analyze the current instruction in the ID stage
|
||||
is_decoding_o = 1'b1;
|
||||
|
||||
// if there is a jr stall, wait for it to be gone
|
||||
if (~jr_stall_o)
|
||||
pc_set_o = 1'b1;
|
||||
// handle unconditional jumps
|
||||
// we can jump directly since we know the address already
|
||||
// we don't need to worry about conditional branches here as they
|
||||
// will be evaluated in the EX stage
|
||||
if (jump_in_dec_i == `BRANCH_JALR || jump_in_dec_i == `BRANCH_JAL) begin
|
||||
pc_mux_sel_o = `PC_JUMP;
|
||||
|
||||
// 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 target
|
||||
end
|
||||
// if there is a jr stall, wait for it to be gone
|
||||
if (~jr_stall_o)
|
||||
pc_set_o = 1'b1;
|
||||
|
||||
// handle hwloops
|
||||
if (hwloop_jump_i) begin
|
||||
pc_mux_sel_o = `PC_HWLOOP;
|
||||
pc_set_o = 1'b1;
|
||||
end
|
||||
// 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 target
|
||||
end
|
||||
|
||||
// handle exceptions
|
||||
if (exc_req_i) begin
|
||||
pc_mux_sel_o = `PC_EXCEPTION;
|
||||
pc_set_o = 1'b1;
|
||||
exc_ack_o = 1'b1;
|
||||
// handle hwloops
|
||||
if (hwloop_jump_i) begin
|
||||
pc_mux_sel_o = `PC_HWLOOP;
|
||||
pc_set_o = 1'b1;
|
||||
end
|
||||
|
||||
save_pc_id_o = 1'b1;
|
||||
if (eret_insn_i) begin
|
||||
pc_mux_sel_o = `PC_ERET;
|
||||
pc_set_o = 1'b1;
|
||||
end
|
||||
|
||||
// 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
|
||||
end
|
||||
|
||||
if (eret_insn_i) begin
|
||||
pc_mux_sel_o = `PC_ERET;
|
||||
pc_set_o = 1'b1;
|
||||
|
||||
// go back to sleep if core was woken up for this interrupt
|
||||
if (fetch_enable_i == 1'b0) begin
|
||||
// handle WFI instruction, flush pipeline and (potentially) go to
|
||||
// sleep
|
||||
// also handles eret when the core should go back to sleep
|
||||
if (pipe_flush_i || (eret_insn_i && (~fetch_enable_i)))
|
||||
begin
|
||||
halt_if_o = 1'b1;
|
||||
halt_id_o = 1'b1;
|
||||
|
||||
ctrl_fsm_ns = FLUSH_EX;
|
||||
end
|
||||
end
|
||||
|
||||
// handle WFI instruction, flush pipeline and (potentially) go to
|
||||
// sleep
|
||||
if (pipe_flush_i)
|
||||
begin
|
||||
halt_if_o = 1'b1;
|
||||
halt_id_o = 1'b1;
|
||||
// handle exceptions
|
||||
if (exc_req_i) begin
|
||||
// to not loose the hwloop, we to into a special state where we
|
||||
// save the new PC
|
||||
if (hwloop_jump_i)
|
||||
begin
|
||||
ctrl_fsm_ns = JUMP_EXC;
|
||||
end else begin
|
||||
pc_mux_sel_o = `PC_EXCEPTION;
|
||||
pc_set_o = 1'b1;
|
||||
exc_ack_o = 1'b1;
|
||||
|
||||
ctrl_fsm_ns = FLUSH_EX;
|
||||
end
|
||||
halt_id_o = 1'b1; // we don't want to propagate this instruction to EX
|
||||
save_pc_id_o = 1'b1;
|
||||
|
||||
// take care of debug
|
||||
// branch conditional will be handled in next state
|
||||
if (trap_hit_i)
|
||||
begin
|
||||
// halt pipeline immediately
|
||||
halt_if_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
|
||||
end
|
||||
end
|
||||
|
||||
// make sure the current instruction has been executed
|
||||
// before changing state to non-decode
|
||||
if (id_valid_i) begin
|
||||
if (jump_in_id_i == `BRANCH_COND)
|
||||
ctrl_fsm_ns = DBG_WAIT_BRANCH;
|
||||
else
|
||||
ctrl_fsm_ns = DBG_SIGNAL;
|
||||
// take care of debug
|
||||
// branch conditional will be handled in next state
|
||||
if (trap_hit_i)
|
||||
begin
|
||||
// halt pipeline immediately
|
||||
halt_if_o = 1'b1;
|
||||
|
||||
// make sure the current instruction has been executed
|
||||
// before changing state to non-decode
|
||||
if (id_valid_i) begin
|
||||
if (jump_in_id_i == `BRANCH_COND)
|
||||
ctrl_fsm_ns = DBG_WAIT_BRANCH;
|
||||
else
|
||||
ctrl_fsm_ns = DBG_SIGNAL;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
|
||||
// TODO: make sure this is not done multiple times in a row!!!
|
||||
// maybe with an assertion?
|
||||
// handle conditional branches
|
||||
if (jump_in_ex_i == `BRANCH_COND && branch_decision_i) begin
|
||||
// there is a branch in the EX stage that is taken
|
||||
pc_mux_sel_o = `PC_BRANCH;
|
||||
pc_set_o = 1'b1;
|
||||
|
@ -349,26 +362,9 @@ module riscv_controller
|
|||
begin
|
||||
ctrl_fsm_ns = DBG_SIGNAL;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (if_valid_i)
|
||||
ctrl_fsm_ns = DECODE;
|
||||
else // change to special state when the new instruction is not yet ready
|
||||
ctrl_fsm_ns = BRANCH_DELAY;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// a branch was executed, but the instruction cache was not ready to
|
||||
// serve a new instruction
|
||||
BRANCH_DELAY:
|
||||
begin
|
||||
is_decoding_o = 1'b0;
|
||||
|
||||
if (if_valid_i)
|
||||
ctrl_fsm_ns = DECODE;
|
||||
end
|
||||
|
||||
// a branch was in ID when a debug trap is hit
|
||||
DBG_WAIT_BRANCH:
|
||||
begin
|
||||
|
@ -406,7 +402,7 @@ module riscv_controller
|
|||
end
|
||||
|
||||
if(dbg_stall_i == 1'b0) begin
|
||||
ctrl_fsm_ns = BRANCH_DELAY;
|
||||
ctrl_fsm_ns = DECODE;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -437,6 +433,19 @@ module riscv_controller
|
|||
end
|
||||
end
|
||||
|
||||
// go to an exception handler after a jump
|
||||
JUMP_EXC:
|
||||
begin
|
||||
// we can just save the IF PC, since it propagated through the
|
||||
// prefetcher
|
||||
save_pc_if_o = 1'b1;
|
||||
pc_mux_sel_o = `PC_EXCEPTION;
|
||||
pc_set_o = 1'b1;
|
||||
exc_ack_o = 1'b1;
|
||||
|
||||
ctrl_fsm_ns = DECODE;
|
||||
end
|
||||
|
||||
default: begin
|
||||
instr_req_o = 1'b0;
|
||||
ctrl_fsm_ns = RESET;
|
||||
|
|
20
id_stage.sv
20
id_stage.sv
|
@ -44,11 +44,11 @@ module riscv_id_stage
|
|||
output logic core_busy_o,
|
||||
output logic is_decoding_o,
|
||||
|
||||
// Interface to instruction memory
|
||||
// Interface to IF stage
|
||||
input logic instr_valid_i,
|
||||
input logic [31:0] instr_rdata_i, // comes from pipeline of IF stage
|
||||
output logic instr_req_o,
|
||||
|
||||
input logic id_execute_i,
|
||||
|
||||
// Jumps and branches
|
||||
output logic [1:0] jump_in_id_o,
|
||||
|
@ -57,7 +57,7 @@ module riscv_id_stage
|
|||
output logic [31:0] jump_target_o,
|
||||
|
||||
// IF and ID stage signals
|
||||
output logic clear_id_execute_o,
|
||||
output logic clear_instr_valid_o,
|
||||
output logic pc_set_o,
|
||||
output logic [2:0] pc_mux_sel_o,
|
||||
output logic [1:0] exc_pc_mux_o,
|
||||
|
@ -317,12 +317,9 @@ module riscv_id_stage
|
|||
regfile_waddr_id : regfile_addr_ra_id;
|
||||
|
||||
|
||||
// ID execute signal control
|
||||
// This signal is used to detect when an instruction first enters the ID
|
||||
// stage. Based on this hardware loops are decremented and it's also useful
|
||||
// for exceptions, i.e. to suppress the illegal instruction signal during
|
||||
// an if stall of a jump.
|
||||
assign clear_id_execute_o = (~jr_stall) | (|hwloop_end_addr);
|
||||
// kill instruction in the IF/ID stage by setting the instr_valid_id control
|
||||
// signal to 0 for instructions that are done
|
||||
assign clear_instr_valid_o = id_ready_o;
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
|
@ -644,6 +641,7 @@ module riscv_id_stage
|
|||
.regc_used_i ( regc_used_dec ),
|
||||
|
||||
// from IF/ID pipeline
|
||||
.instr_valid_i ( instr_valid_i ),
|
||||
.instr_rdata_i ( instr ),
|
||||
|
||||
// from prefetcher
|
||||
|
@ -796,7 +794,7 @@ module riscv_id_stage
|
|||
.hwloop_regid_i ( hwloop_regid ),
|
||||
|
||||
// from controller
|
||||
.stall_id_i ( id_execute_i ),
|
||||
.stall_id_i ( instr_valid_i ),
|
||||
|
||||
// to hwloop controller
|
||||
.hwloop_start_addr_o ( hwloop_start_addr ),
|
||||
|
@ -942,6 +940,6 @@ module riscv_id_stage
|
|||
|
||||
// stall control
|
||||
assign id_ready_o = (~misaligned_stall) & (~jr_stall) & (~load_stall) & ex_ready_i;
|
||||
assign id_valid_o = (~halt_id) & if_ready_i & id_ready_o;
|
||||
assign id_valid_o = (~halt_id) & id_ready_o;
|
||||
|
||||
endmodule
|
||||
|
|
14
if_stage.sv
14
if_stage.sv
|
@ -55,7 +55,7 @@ module riscv_if_stage
|
|||
input logic [RDATA_WIDTH-1:0] instr_rdata_i,
|
||||
|
||||
// Output of IF Pipeline stage
|
||||
output logic id_execute_o, // execute current instruction in ID
|
||||
output logic instr_valid_id_o, // instruction in IF/ID pipeline is valid
|
||||
output logic [31:0] instr_rdata_id_o, // read instruction is sampled and sent to ID stage for decoding
|
||||
output logic is_compressed_id_o, // compressed decoder thinks this is a compressed instruction
|
||||
output logic illegal_c_insn_id_o, // compressed decoder thinks this is an invalid instruction
|
||||
|
@ -63,7 +63,7 @@ module riscv_if_stage
|
|||
output logic [31:0] current_pc_id_o,
|
||||
|
||||
// Forwarding ports - control signals
|
||||
input logic clear_id_execute_i, // clear execute bit
|
||||
input logic clear_instr_valid_i, // clear instruction valid bit in IF/ID pipe
|
||||
input logic pc_set_i, // set the program counter to a new value
|
||||
input logic [31:0] exception_pc_reg_i, // address used to restore PC when the interrupt/exception is served
|
||||
input logic [2:0] pc_mux_sel_i, // sel for pc multiplexer
|
||||
|
@ -396,7 +396,7 @@ module riscv_if_stage
|
|||
begin : IF_ID_PIPE_REGISTERS
|
||||
if (rst_n == 1'b0)
|
||||
begin
|
||||
id_execute_o <= 1'b0;
|
||||
instr_valid_id_o <= 1'b0;
|
||||
instr_rdata_id_o <= '0;
|
||||
illegal_c_insn_id_o <= 1'b0;
|
||||
is_compressed_id_o <= 1'b0;
|
||||
|
@ -404,12 +404,12 @@ module riscv_if_stage
|
|||
end
|
||||
else
|
||||
begin
|
||||
if (clear_id_execute_i)
|
||||
id_execute_o <= 1'b0;
|
||||
if (clear_instr_valid_i)
|
||||
instr_valid_id_o <= 1'b0;
|
||||
|
||||
if (if_valid_o)
|
||||
begin : ENABLED_PIPE
|
||||
id_execute_o <= 1'b0;
|
||||
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;
|
||||
|
|
|
@ -85,14 +85,14 @@ module riscv_core
|
|||
|
||||
|
||||
// IF/ID signals
|
||||
logic id_execute;
|
||||
logic instr_valid_id;
|
||||
logic [31:0] instr_rdata_id; // Instruction sampled inside IF stage
|
||||
logic is_compressed_id;
|
||||
logic illegal_c_insn_id; // Illegal compressed instruction sent to ID stage
|
||||
logic [31:0] current_pc_if; // Current Program counter
|
||||
logic [31:0] current_pc_id; // Current Program counter
|
||||
|
||||
logic clear_id_execute;
|
||||
logic clear_instr_valid;
|
||||
logic pc_set;
|
||||
logic [2:0] pc_mux_sel_id; // Mux selector for next PC
|
||||
logic [1:0] exc_pc_mux_id; // Mux selector for exception PC
|
||||
|
@ -258,7 +258,7 @@ module riscv_core
|
|||
.instr_rdata_i ( instr_rdata_i ),
|
||||
|
||||
// outputs to ID stage
|
||||
.id_execute_o ( id_execute ),
|
||||
.instr_valid_id_o ( instr_valid_id ),
|
||||
.instr_rdata_id_o ( instr_rdata_id ),
|
||||
.is_compressed_id_o ( is_compressed_id ),
|
||||
.illegal_c_insn_id_o ( illegal_c_insn_id ),
|
||||
|
@ -266,7 +266,7 @@ module riscv_core
|
|||
.current_pc_id_o ( current_pc_id ),
|
||||
|
||||
// control signals
|
||||
.clear_id_execute_i ( clear_id_execute ),
|
||||
.clear_instr_valid_i ( clear_instr_valid ),
|
||||
.pc_set_i ( pc_set ),
|
||||
.exception_pc_reg_i ( epcr ), // exception return address
|
||||
.pc_mux_sel_i ( pc_mux_sel_id ), // sel for pc multiplexer
|
||||
|
@ -322,11 +322,10 @@ module riscv_core
|
|||
.is_decoding_o ( is_decoding ),
|
||||
|
||||
// Interface to instruction memory
|
||||
.instr_valid_i ( instr_valid_id ),
|
||||
.instr_rdata_i ( instr_rdata_id ),
|
||||
.instr_req_o ( instr_req_int ),
|
||||
|
||||
.id_execute_i ( id_execute ),
|
||||
|
||||
// Jumps and branches
|
||||
.jump_in_id_o ( jump_in_id ),
|
||||
.jump_in_ex_o ( jump_in_ex ),
|
||||
|
@ -334,7 +333,7 @@ module riscv_core
|
|||
.jump_target_o ( jump_target_id ),
|
||||
|
||||
// IF and ID control signals
|
||||
.clear_id_execute_o ( clear_id_execute ),
|
||||
.clear_instr_valid_o ( clear_instr_valid ),
|
||||
.pc_set_o ( pc_set ),
|
||||
.pc_mux_sel_o ( pc_mux_sel_id ),
|
||||
.exc_pc_mux_o ( exc_pc_mux_id ),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue