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