blob: a6187b78419263d9dc4c14423e2e3d000f813cd3 [file] [log] [blame]
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