Add an instr_valid_id signal to completely decouple the pipeline stages,

hopefully fixes the exception controller
This commit is contained in:
Andreas Traber 2015-11-17 18:16:18 +01:00
parent 4a166db65b
commit f5d408d7f4
4 changed files with 117 additions and 111 deletions

View file

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

View file

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

View file

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

View file

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