mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-24 05:47:36 -04:00
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:
parent
1456e8e0da
commit
6b5d26bae2
5 changed files with 61 additions and 67 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ),
|
||||
|
|
|
@ -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 //
|
||||
////////////////
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue