mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-20 11:57:12 -04:00
When the writeback stage is present the retired instruction counter (minstret) and the retired compressed instruction counter could see an off by one error when an instruction was in the writeback stage when reading the counters. With this fix the ID stage observes the incremented value of the counters when an instruction that would increment them is in writeback.
99 lines
2.9 KiB
Systemverilog
99 lines
2.9 KiB
Systemverilog
module ibex_counter #(
|
|
parameter int CounterWidth = 32,
|
|
// When set `counter_val_upd_o` provides an incremented version of the counter value, otherwise
|
|
// the output is hard-wired to 0. This is required to allow Xilinx DSP inference to work
|
|
// correctly. When `ProvideValUpd` is set no DSPs are inferred.
|
|
parameter bit ProvideValUpd = 0
|
|
) (
|
|
input logic clk_i,
|
|
input logic rst_ni,
|
|
|
|
input logic counter_inc_i,
|
|
input logic counterh_we_i,
|
|
input logic counter_we_i,
|
|
input logic [31:0] counter_val_i,
|
|
output logic [63:0] counter_val_o,
|
|
output logic [63:0] counter_val_upd_o
|
|
);
|
|
|
|
logic [63:0] counter;
|
|
logic [CounterWidth-1:0] counter_upd;
|
|
logic [63:0] counter_load;
|
|
logic we;
|
|
logic [CounterWidth-1:0] counter_d;
|
|
|
|
// Increment
|
|
assign counter_upd = counter[CounterWidth-1:0] + {{CounterWidth - 1{1'b0}}, 1'b1};
|
|
|
|
// Update
|
|
always_comb begin
|
|
// Write
|
|
we = counter_we_i | counterh_we_i;
|
|
counter_load[63:32] = counter[63:32];
|
|
counter_load[31:0] = counter_val_i;
|
|
if (counterh_we_i) begin
|
|
counter_load[63:32] = counter_val_i;
|
|
counter_load[31:0] = counter[31:0];
|
|
end
|
|
|
|
// Next value logic
|
|
if (we) begin
|
|
counter_d = counter_load[CounterWidth-1:0];
|
|
end else if (counter_inc_i) begin
|
|
counter_d = counter_upd[CounterWidth-1:0];
|
|
end else begin
|
|
counter_d = counter[CounterWidth-1:0];
|
|
end
|
|
end
|
|
|
|
`ifdef FPGA_XILINX
|
|
// Set DSP pragma for supported xilinx FPGAs
|
|
localparam int DspPragma = CounterWidth < 49 ? "yes" : "no";
|
|
(* use_dsp = DspPragma *) logic [CounterWidth-1:0] counter_q;
|
|
|
|
// DSP output register requires synchronous reset.
|
|
`define COUNTER_FLOP_RST posedge clk_i
|
|
`else
|
|
logic [CounterWidth-1:0] counter_q;
|
|
|
|
`define COUNTER_FLOP_RST posedge clk_i or negedge rst_ni
|
|
`endif
|
|
|
|
// Counter flop
|
|
always_ff @(`COUNTER_FLOP_RST) begin
|
|
if (!rst_ni) begin
|
|
counter_q <= '0;
|
|
end else begin
|
|
counter_q <= counter_d;
|
|
end
|
|
end
|
|
|
|
if (CounterWidth < 64) begin : g_counter_narrow
|
|
logic [63:CounterWidth] unused_counter_load;
|
|
|
|
assign counter[CounterWidth-1:0] = counter_q;
|
|
assign counter[63:CounterWidth] = '0;
|
|
|
|
if (ProvideValUpd) begin : g_counter_val_upd_o
|
|
assign counter_val_upd_o[CounterWidth-1:0] = counter_upd;
|
|
end else begin : g_no_counter_val_upd_o
|
|
assign counter_val_upd_o[CounterWidth-1:0] = '0;
|
|
end
|
|
assign counter_val_upd_o[63:CounterWidth] = '0;
|
|
assign unused_counter_load = counter_load[63:CounterWidth];
|
|
end else begin : g_counter_full
|
|
assign counter = counter_q;
|
|
|
|
if (ProvideValUpd) begin : g_counter_val_upd_o
|
|
assign counter_val_upd_o = counter_upd;
|
|
end else begin : g_no_counter_val_upd_o
|
|
assign counter_val_upd_o = '0;
|
|
end
|
|
end
|
|
|
|
assign counter_val_o = counter;
|
|
|
|
endmodule
|
|
|
|
// Keep helper defines file-local.
|
|
`undef COUNTER_FLOP_RST
|