Cleanup interplay of IF and ID stage (controller)

Once the core is executing, the IF stage now only gets two signals
from the controller: One to clear the instruction valid output and one
to prevent the IF stage from pushing new instructions.

The former `if_valid_o` of the IF stage has been renamed to clarify
that this is not a valid bit but just the write enable for the
pipeline register.
This commit is contained in:
Pirmin Vogel 2019-07-10 11:38:14 +01:00
parent 1456e8e0da
commit 6b5d26bae2
5 changed files with 61 additions and 67 deletions

View file

@ -49,8 +49,7 @@ module ibex_controller (
// to IF-ID pipeline stage
output logic instr_valid_clear_o, // kill instr in IF-ID reg
output logic id_ready_o, // ID stage is ready for new instr
output logic halt_if_o, // IF stage must not forward new instr
output logic id_in_ready_o, // ID stage is ready for new instr
// to prefetcher
output logic instr_req_o, // start fetching instructions
@ -103,7 +102,7 @@ module ibex_controller (
input logic stall_jump_i,
input logic stall_branch_i,
output logic id_valid_o,
output logic id_out_valid_o, // ID stage has valid output
// performance monitors
output logic perf_jump_o, // we are executing a jump
@ -126,6 +125,7 @@ module ibex_controller (
logic store_err_q, store_err_d;
logic stall;
logic halt_if;
logic halt_id;
logic irq;
logic exc_req;
@ -186,7 +186,7 @@ module ibex_controller (
is_decoding_o = 1'b0;
first_fetch_o = 1'b0;
halt_if_o = 1'b0;
halt_if = 1'b0;
halt_id = 1'b0;
irq_ack_o = 1'b0;
irq_id_o = irq_id_ctrl_i;
@ -221,17 +221,17 @@ module ibex_controller (
WAIT_SLEEP: begin
ctrl_busy_o = 1'b0;
instr_req_o = 1'b0;
halt_if_o = 1'b1;
halt_if = 1'b1;
halt_id = 1'b1;
ctrl_fsm_ns = SLEEP;
end
SLEEP: begin
// instruction in if_stage is already valid
// instruction in IF stage is already valid
// we begin execution when an interrupt has arrived
ctrl_busy_o = 1'b0;
instr_req_o = 1'b0;
halt_if_o = 1'b1;
halt_if = 1'b1;
halt_id = 1'b1;
// normal execution flow
@ -244,7 +244,7 @@ module ibex_controller (
FIRST_FETCH: begin
first_fetch_o = 1'b1;
// Stall because of IF miss
if (id_ready_o) begin
if (id_in_ready_o) begin
ctrl_fsm_ns = DECODE;
end
@ -253,14 +253,14 @@ module ibex_controller (
// This assumes that the pipeline is always flushed before
// going to sleep.
ctrl_fsm_ns = IRQ_TAKEN;
halt_if_o = 1'b1;
halt_if = 1'b1;
halt_id = 1'b1;
end
// enter debug mode
if (debug_req_i && !debug_mode_q) begin
ctrl_fsm_ns = DBG_TAKEN_IF;
halt_if_o = 1'b1;
halt_if = 1'b1;
halt_id = 1'b1;
end
end
@ -287,21 +287,21 @@ module ibex_controller (
// get ready for special instructions, exceptions, pipeline flushes
end else if (special_req) begin
ctrl_fsm_ns = FLUSH;
halt_if_o = 1'b1;
halt_if = 1'b1;
halt_id = 1'b1;
end
// stall IF stage to not starve debug and interrupt requests, these just
// need to wait until after the current (multicycle) instruction
if ((debug_req_i || irq) && stall && !debug_mode_q) begin
halt_if_o = 1'b1;
halt_if = 1'b1;
end
// single stepping:
// execute a single instruction and then enter debug mode, in case of exceptions,
// set registers but do not jump into handler [Debug Spec v0.13.2, p.44]
if (debug_single_step_i && !debug_mode_q) begin
halt_if_o = 1'b1;
halt_if = 1'b1;
if (!special_req && !stall) begin
ctrl_fsm_ns = DBG_TAKEN_IF;
@ -312,13 +312,13 @@ module ibex_controller (
if (debug_req_i && !stall && !special_req && !debug_mode_q) begin
// enter debug mode
ctrl_fsm_ns = DBG_TAKEN_ID;
halt_if_o = 1'b1;
halt_if = 1'b1;
halt_id = 1'b1;
end else if (irq && !stall && !special_req && !debug_mode_q) begin
// handle interrupt (not in debug mode)
ctrl_fsm_ns = IRQ_TAKEN;
halt_if_o = 1'b1;
halt_if = 1'b1;
halt_id = 1'b1;
end
@ -403,7 +403,7 @@ module ibex_controller (
FLUSH: begin
// flush the pipeline
halt_if_o = 1'b1;
halt_if = 1'b1;
halt_id = 1'b1;
ctrl_fsm_ns = DECODE;
@ -508,14 +508,15 @@ module ibex_controller (
// multicycle instructions have this set except during the last cycle
assign stall = stall_lsu_i | stall_multdiv_i | stall_jump_i | stall_branch_i;
// signal to IF stage that ID stage is ready for next instruction
assign id_ready_o = ~stall;
// signal to IF stage that ID stage is ready for next instr
assign id_in_ready_o = ~stall & ~halt_if;
// kill instruction in IF-ID reg for instructions that are done
assign instr_valid_clear_o = id_ready_o | halt_id;
// kill instr in IF-ID pipeline reg that are done, or if a
// multicycle instr causes an exception for example
assign instr_valid_clear_o = ~stall | halt_id;
// signal that ID stage has valid output
assign id_valid_o = id_ready_o & ~halt_id;
assign id_out_valid_o = ~stall & instr_valid_i & ~special_req;
// update registers
always_ff @(posedge clk_i or negedge rst_ni) begin : update_regs

View file

@ -181,12 +181,11 @@ module ibex_core #(
logic [31:0] regfile_wdata_lsu;
// stall control
logic halt_if;
logic id_ready;
logic id_in_ready;
logic ex_valid;
logic if_valid;
logic id_valid;
logic if_id_pipe_reg_we;
logic id_out_valid;
logic lsu_data_valid;
@ -336,9 +335,8 @@ module ibex_core #(
.csr_mtvec_o ( csr_mtvec ), // trap-vector base address
// pipeline stalls
.halt_if_i ( halt_if ),
.id_ready_i ( id_ready ),
.if_valid_o ( if_valid ),
.id_in_ready_i ( id_in_ready ),
.if_id_pipe_reg_we_o ( if_id_pipe_reg_we ),
.if_busy_o ( if_busy ),
.perf_imiss_o ( perf_imiss )
@ -376,6 +374,7 @@ module ibex_core #(
.branch_decision_i ( branch_decision ),
// IF and ID control signals
.id_in_ready_o ( id_in_ready ),
.instr_valid_clear_o ( instr_valid_clear ),
.instr_req_o ( instr_req_int ),
.pc_set_o ( pc_set ),
@ -388,13 +387,10 @@ module ibex_core #(
.pc_id_i ( pc_id ),
// Stalls
.halt_if_o ( halt_if ),
.id_ready_o ( id_ready ),
.ex_valid_i ( ex_valid ),
.lsu_valid_i ( lsu_data_valid ),
.id_valid_o ( id_valid ),
.id_out_valid_o ( id_out_valid ),
.alu_operator_ex_o ( alu_operator_ex ),
.alu_operand_a_ex_o ( alu_operand_a_ex ),
@ -553,7 +549,7 @@ module ibex_core #(
// An instruction has been executed and retired if the ID stage gets a new instruction and
// the previously seen instruction was valid.
assign insn_ret = if_valid & ~illegal_insn_id;
assign insn_ret = if_id_pipe_reg_we & ~illegal_insn_id;
ibex_cs_registers #(
.MHPMCounterNum ( MHPMCounterNum ),
@ -602,7 +598,7 @@ module ibex_core #(
// performance counter related signals
.insn_ret_i ( insn_ret ),
.id_valid_i ( id_valid ),
.id_out_valid_i ( id_out_valid ),
.instr_is_compressed_i ( instr_is_compressed_id ),
.is_decoding_i ( is_decoding ),
@ -668,7 +664,7 @@ module ibex_core #(
endcase
end
assign rvfi_valid_int = id_valid && if_valid && !illegal_c_insn_id;
assign rvfi_valid_int = id_out_valid && if_id_pipe_reg_we && !illegal_c_insn_id;
always_comb begin
if (instr_is_compressed_id) begin

View file

@ -74,7 +74,7 @@ module ibex_cs_registers #(
// missing write permissions
// Performance Counters
input logic insn_ret_i, // instr retired in ID/EX stage
input logic id_valid_i, // ID stage is done
input logic id_out_valid_i, // ID stage is done
input logic instr_is_compressed_i, // compressed instr in ID
input logic is_decoding_i, // controller is in DECODE state
@ -551,7 +551,7 @@ module ibex_cs_registers #(
mhpmcounter_incr[8] = branch_i; // num of branches (conditional)
mhpmcounter_incr[9] = branch_taken_i; // num of taken branches (conditional)
mhpmcounter_incr[10] = is_decoding_i // num of compressed instr
& id_valid_i & instr_is_compressed_i;
& id_out_valid_i & instr_is_compressed_i;
// inactive counters
for (int unsigned i=3+MHPMCounterNum; i<32; i++) begin : gen_mhpmcounter_incr_inactive

View file

@ -54,8 +54,7 @@ module ibex_id_stage #(
input logic instr_is_compressed_i,
output logic instr_req_o,
output logic instr_valid_clear_o, // kill instr in IF-ID reg
output logic id_ready_o, // ID stage is ready for next instr
output logic halt_if_o, // ID stage requests IF stage to halt
output logic id_in_ready_o, // ID stage is ready for next instr
// Jumps and branches
input logic branch_decision_i,
@ -70,9 +69,9 @@ module ibex_id_stage #(
input logic [31:0] pc_id_i,
// Stalls
input logic ex_valid_i, // EX stage has valid output
input logic lsu_valid_i, // LSU has valid output, or is done
output logic id_valid_o, // ID stage is done
input logic ex_valid_i, // EX stage has valid output
input logic lsu_valid_i, // LSU has valid output, or is done
output logic id_out_valid_o, // ID stage is done
// ALU
output ibex_defines::alu_op_e alu_operator_ex_o,
@ -427,8 +426,7 @@ module ibex_id_stage #(
// to IF-ID pipeline
.instr_valid_clear_o ( instr_valid_clear_o ),
.id_ready_o ( id_ready_o ),
.halt_if_o ( halt_if_o ),
.id_in_ready_o ( id_in_ready_o ),
// from prefetcher
.instr_req_o ( instr_req_o ),
@ -481,7 +479,7 @@ module ibex_id_stage #(
.stall_jump_i ( stall_jump ),
.stall_branch_i ( stall_branch ),
.id_valid_o ( id_valid_o ),
.id_out_valid_o ( id_out_valid_o ),
// Performance Counters
.perf_jump_o ( perf_jump_o ),

View file

@ -80,9 +80,8 @@ module ibex_if_stage #(
output logic [31:0] csr_mtvec_o,
// pipeline stall
input logic halt_if_i,
input logic id_ready_i,
output logic if_valid_o,
input logic id_in_ready_i, // ID stage is ready for new instr
output logic if_id_pipe_reg_we_o, // IF-ID pipeline reg write enable
// misc signals
output logic if_busy_o, // IF stage is busy fetching instr
@ -92,8 +91,8 @@ module ibex_if_stage #(
import ibex_defines::*;
logic offset_in_init_d, offset_in_init_q;
logic valid;
logic if_ready;
logic have_instr;
// prefetch buffer related signals
logic prefetch_busy;
logic branch_req;
@ -183,22 +182,23 @@ module ibex_if_stage #(
always_comb begin
offset_in_init_d = offset_in_init_q;
fetch_ready = 1'b0;
branch_req = 1'b0;
valid = 1'b0;
fetch_ready = 1'b0;
branch_req = 1'b0;
have_instr = 1'b0;
if (offset_in_init_q) begin
// no valid instruction data for ID stage, assume aligned
if (req_i) begin
branch_req = 1'b1;
branch_req = 1'b1;
offset_in_init_d = 1'b0;
end
end else begin
// an instruction is ready for ID stage
if (fetch_valid) begin
valid = 1'b1; // an instruction is ready for ID stage
have_instr = 1'b1;
if (req_i && if_valid_o) begin
fetch_ready = 1'b1;
if (req_i && if_id_pipe_reg_we_o) begin
fetch_ready = 1'b1;
offset_in_init_d = 1'b0;
end
end
@ -206,17 +206,17 @@ module ibex_if_stage #(
// take care of jumps and branches
if (pc_set_i) begin
valid = 1'b0;
have_instr = 1'b0;
// switch to new PC from ID stage
branch_req = 1'b1;
branch_req = 1'b1;
offset_in_init_d = 1'b0;
end
end
assign pc_if_o = fetch_addr;
assign if_busy_o = prefetch_busy;
assign perf_imiss_o = ~fetch_valid | branch_req;
assign pc_if_o = fetch_addr;
assign if_busy_o = prefetch_busy;
assign perf_imiss_o = ~fetch_valid | branch_req;
// compressed instruction decoding, or more precisely compressed instruction
// expander
@ -235,6 +235,8 @@ module ibex_if_stage #(
);
// IF-ID pipeline registers, frozen when the ID stage is stalled
assign if_id_pipe_reg_we_o = have_instr & id_in_ready_i;
always_ff @(posedge clk_i or negedge rst_ni) begin : if_id_pipeline_regs
if (!rst_ni) begin
instr_new_id_o <= 1'b0;
@ -245,8 +247,8 @@ module ibex_if_stage #(
illegal_c_insn_id_o <= 1'b0;
pc_id_o <= '0;
end else begin
instr_new_id_o <= if_valid_o;
if (if_valid_o) begin
instr_new_id_o <= if_id_pipe_reg_we_o;
if (if_id_pipe_reg_we_o) begin
instr_valid_id_o <= 1'b1;
instr_rdata_id_o <= instr_decompressed;
instr_rdata_c_id_o <= fetch_rdata[15:0];
@ -259,9 +261,6 @@ module ibex_if_stage #(
end
end
assign if_ready = valid & id_ready_i;
assign if_valid_o = ~halt_if_i & if_ready;
////////////////
// Assertions //
////////////////