fpga: dsp: distribute reset and clear through DSP paths

This commit is contained in:
Max Köhler 2026-09-08 00:12:10 +02:00 committed by mkoop-ni
parent d394ae626a
commit efa47018e4
7 changed files with 58 additions and 35 deletions

View File

@ -27,13 +27,19 @@
// ACCUM_WIDTH - Accumulator width
// COEFFS_VEC - Vector of NUM_COEFFS values, each of width COEFF_WIDTH to
// initialize coeffs. Defaults to an impulse.
// RELOADABLE_COEFFS - Enable (1) or disable (0) reloading coefficients at runtime (via reload bus)
// BLANK_OUTPUT - Disable (1) or enable (0) output when initially filling internal pipeline
// USE_EMBEDDED_REGS_COEFFS - Reduce register usage by only using embedded registers in DSP slices.
// Updating taps while streaming will cause temporary output corruption!
//
// RELOADABLE_COEFFS - Enable (1) or disable (0) reloading coefficients
// at runtime (via reload bus)
// BLANK_OUTPUT - Disable (1) or enable (0) output when initially filling internal
// pipeline
// USE_EMBEDDED_REGS_COEFFS - Reduce register usage by only using embedded registers in DSP
// slices. Updating taps while streaming will cause temporary output
// corruption!
// RESET_DATA_PATH - Reset FIR arithmetic pipeline registers when
// reset or clear assert.
//
// Notes:
// - If using USE_EMBEDDED_REGS_COEFFS, coefficients must be written at least once as COEFFS_VEC is ignored!
// - If using USE_EMBEDDED_REGS_COEFFS, coefficients must be written at least once as COEFFS_VEC is
// ignored!
// - If using RELOADABLE_COEFFS, coefficients must be written in reverse order!
// - Optimizations: For static coefficients (RELOADABLE_COEFFS = 0), zero and symmetric coefficient
// optimizations are automatically enabled to reduce DSP slice utilization.
@ -52,7 +58,8 @@ module axi_fir_multisample_filter #(
bit [COEFF_WIDTH-1:0] COEFFS_VEC [NUM_COEFFS] = '{0: (1 << (COEFF_WIDTH-1)) - 1, default: 0},
bit RELOADABLE_COEFFS = 1,
bit BLANK_OUTPUT = 1,
bit USE_EMBEDDED_REGS_COEFFS = 1
bit USE_EMBEDDED_REGS_COEFFS = 1,
bit RESET_DATA_PATH = 1
)(
// clocks and control signals
input logic clk,
@ -112,7 +119,8 @@ module axi_fir_multisample_filter #(
? check_coeffs_symmetric() : 0;
localparam int NUM_SLICES = OPTIMIZE_FOR_SYMMETRIC_COEFFS
? NUM_COEFFS/2 + NUM_COEFFS[0] : NUM_COEFFS;
localparam int PIPELINE_DELAY = NUM_SLICES + 5 // +4 pipeline depth in fir_filter_slice.v, +1 of shift register
// +4 pipeline depth in fir_filter_slice.v, +1 of shift register
localparam int PIPELINE_DELAY = NUM_SLICES + 5
- (OPTIMIZE_FOR_ZERO_COEFFS ? count_zeros_up_to_index(NUM_SLICES) : 0);
localparam int SHIFT_REG_WIDTH = (NUM_SPC + 1) * NUM_COEFFS; // length of shift register
@ -262,7 +270,8 @@ module axi_fir_multisample_filter #(
end else begin
localparam int GAP = OPTIMIZE_FOR_ZERO_COEFFS ? count_zeros_up_to_index(j) : 0;
localparam bit APPLY_SYMMETRY = (OPTIMIZE_FOR_SYMMETRIC_COEFFS == 1) // enabled?
&& !((NUM_COEFFS[0] == 1) && (j == NUM_SLICES-1)); // not the center tap for odd NUM_COEFFS
&& !((NUM_COEFFS[0] == 1) && (j == NUM_SLICES-1));
// not the center tap for odd NUM_COEFFS
fir_filter_slice #(
.IN_WIDTH(IN_WIDTH),
@ -271,8 +280,8 @@ module axi_fir_multisample_filter #(
.OUT_WIDTH(ACCUM_WIDTH))
fir_filter_slice (
.clk(clk),
.reset(reset),
.clear(clear),
.reset(RESET_DATA_PATH ? (reset | clear) : 1'b0),
.clear(1'b0),
.sample_in_stb(s_axis_data_tvalid & s_axis_data_tready),
// NUM_SPC is added j times due to the pipeline delay.
// +1 for selecting the next index for the FIR result calculation
@ -287,10 +296,13 @@ module axi_fir_multisample_filter #(
// Mirror index is NUM_COEFFS-1-j, since sample_in_b inside fir_filter_slice
// has one cycle delay less that sample_in_a, we need to take it one cycle
// later such that both values are in-sync. Thus we add another NUM_SPC to the index.
.sample_in_b(APPLY_SYMMETRY ? data_shift_reg[ (NUM_COEFFS-1-j) + (j-GAP+1)*NUM_SPC + K_FLIPPED ] : '0),
.sample_in_b(APPLY_SYMMETRY ?
data_shift_reg[ (NUM_COEFFS-1-j) + (j-GAP+1)*NUM_SPC + K_FLIPPED ] : '0),
.sample_forward(),
// For proper coeffient loading, coeff_forward must be shifted in backwards. coeffs[] is already backwards
.coeff_in(((USE_EMBEDDED_REGS_COEFFS == 1) && (RELOADABLE_COEFFS == 1)) ? coeff_forward[j] : coeffs[j]),
// For proper coeffient loading, coeff_forward must be shifted in backwards.
// coeffs[] is already backwards
.coeff_in(((USE_EMBEDDED_REGS_COEFFS == 1) && (RELOADABLE_COEFFS == 1)) ?
coeff_forward[j] : coeffs[j]),
.coeff_forward(coeff_forward[j+1]),
.coeff_load_stb(coeff_load_stb),
.sample_accum(sample_accum[j]),

View File

@ -149,6 +149,7 @@ module axis_fir_ms_preload #(
//----------------------------------------------------------------------------
// Wrapped FIR instance
//----------------------------------------------------------------------------
localparam bit RESET_DATA_PATH = !PRELOAD_ZEROES;
axi_fir_multisample_filter #(
.IN_WIDTH (IN_WIDTH),
@ -161,7 +162,8 @@ module axis_fir_ms_preload #(
.COEFFS_VEC (COEFFS_VEC),
.RELOADABLE_COEFFS (RELOADABLE_COEFFS),
.BLANK_OUTPUT (BLANK_OUTPUT),
.USE_EMBEDDED_REGS_COEFFS(USE_EMBEDDED_REGS_COEFFS)
.USE_EMBEDDED_REGS_COEFFS(USE_EMBEDDED_REGS_COEFFS),
.RESET_DATA_PATH (RESET_DATA_PATH)
) fir_inst (
.clk (clk),
.reset (reset),

View File

@ -212,8 +212,6 @@ module cic_interpolator #(
always_ff @(posedge clk) begin
if (rst) begin
input_busy <= 1'b0;
input_last <= 'X;
input_samps <= 'X;
end else begin
if (data_in.tvalid && data_in.tready) begin
// Accepted a new input word; busy until end of interpolation group.
@ -280,14 +278,13 @@ module cic_interpolator #(
logic [1:0] tlast_pipe;
logic [1:0][SPC-1:0][SAMP_W-1:0] tdata_pipe;
always_ff @(posedge clk) begin
tlast_pipe <= {tlast_pipe[0], gen_tlast };
tdata_pipe <= {tdata_pipe[0], input_samps};
if (rst) begin
tvalid_pipe <= 2'b00;
tlast_pipe <= 'X;
tdata_pipe <= 'X;
end else if (gen_tready) begin
tvalid_pipe <= {tvalid_pipe[0], gen_tvalid};
tlast_pipe <= {tlast_pipe[0], gen_tlast };
tdata_pipe <= {tdata_pipe[0], input_samps};
end
end

View File

@ -87,7 +87,7 @@ module dsp48_prefix_accum #(
if (k == 0) begin : gen_first
dsp48_add3 #(.AB_CASCADE(0), .USE_PCIN(0)) dsp_inst (
.clk (clk),
.rst (rst),
.rst (1'b0),
.en (en),
.ab (accu_in),
.c (data_in[0]),
@ -99,7 +99,7 @@ module dsp48_prefix_accum #(
end else begin : gen_chain
dsp48_add3 #(.AB_CASCADE(1), .USE_PCIN(USE_PCIN)) dsp_inst (
.clk (clk),
.rst (rst),
.rst (1'b0),
.en (en),
.ab (abcout_cas[k-1]),
.c (data_in[k]),

View File

@ -114,9 +114,7 @@ module axis_upsamp_x2_ser #(
always_ff @(posedge clk) begin : ser_state_proc
if (rst || clr) begin
state <= IDLE_ST;
data_buf <= '0;
last_buf <= 1'b0;
state <= IDLE_ST;
end else begin
unique case (state)
IDLE_ST : begin

View File

@ -178,6 +178,13 @@ module ddc_ms
.rst (reset)
);
// Delay reset/clear by one cycle so updated configuration settles before
// the DSP pipelines are cleared.
logic reset_or_clear;
always_ff @(posedge clk) begin
reset_or_clear <= reset | clear;
end
//--------------------------------------------------------------------------
// Latch configuration during burst processing to avoid corrupted data caused
// by changing the decimation rate or scaling factor mid-burst.
@ -265,7 +272,7 @@ module ddc_ms
localparam int DDS_LATENCY = 6; // matches MULTIPLY_LATENCY in dds_ms
logic [DDS_LATENCY-1:0] dds_drain_mask;
always_ff @(posedge clk) begin
if (reset || clear)
if (reset_or_clear)
dds_drain_mask <= {DDS_LATENCY{1'b1}}; // arm: block next 6 beats
else if (dds_out_tready)
dds_drain_mask <= {1'b0, dds_drain_mask[DDS_LATENCY-1:1]}; // drain one per cycle
@ -284,8 +291,8 @@ module ddc_ms
.ORDER (4)
) cic_filter_decim_i (
.clk (clk),
.rst (reset),
.clear (clear),
.rst (reset_or_clear),
.clear ('0),
.data_in (decim_in),
.data_out (decim_out),
.decim_factor (cic_rate),
@ -303,8 +310,8 @@ module ddc_ms
.PRELOAD_ZEROES (1)
) hbf_cascade_i (
.clk (clk),
.rst (reset),
.clear (clear),
.rst (reset_or_clear),
.clear ('0),
.s_axis_tdata (decim_out.tdata),
.s_axis_tvalid (decim_out.tvalid),
.s_axis_tready (decim_out.tready),

View File

@ -161,6 +161,13 @@ module duc_ms
.rst (reset)
);
// Delay reset/clear by one cycle so updated configuration settles before
// the DSP pipelines are cleared.
logic reset_or_clear;
always_ff @(posedge clk) begin
reset_or_clear <= reset | clear;
end
//-------------------------------------------------------------------------
// Latch configuration during burst processing to avoid corrupted data caused
@ -211,8 +218,8 @@ module duc_ms
.PRELOAD_ZEROES (1)
) hbf_cascade_i (
.clk (clk),
.rst (reset),
.clear (clear),
.rst (reset_or_clear),
.clear ('0),
.s_axis_tdata (sample_in_tdata),
.s_axis_tvalid (sample_in_tvalid),
.s_axis_tready (sample_in_tready),
@ -241,8 +248,8 @@ module duc_ms
.ORDER (4)
) cic_filter_interp_i (
.clk (clk),
.rst (reset),
.clear (clear),
.rst (reset_or_clear),
.clear ('0),
.data_in (cic_in),
.data_out (cic_out),
.interp_factor (cic_rate),