From b7a92cd9d90a302b77401de5f93f509e2428163b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20K=C3=B6hler?= Date: Tue, 8 Sep 2026 00:13:23 +0200 Subject: [PATCH] fpga: dsp: block input during reset and reconfiguration --- fpga/usrp3/lib/rfnoc/ddc_ms.sv | 73 +++++++++++++++++++----------- fpga/usrp3/lib/rfnoc/duc_ms.sv | 81 ++++++++++++++++++++++------------ 2 files changed, 101 insertions(+), 53 deletions(-) diff --git a/fpga/usrp3/lib/rfnoc/ddc_ms.sv b/fpga/usrp3/lib/rfnoc/ddc_ms.sv index 5bd070c1b..5d510bb3d 100644 --- a/fpga/usrp3/lib/rfnoc/ddc_ms.sv +++ b/fpga/usrp3/lib/rfnoc/ddc_ms.sv @@ -178,9 +178,8 @@ 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; + // Register reset or clear to reduce fanout on both signals. + logic reset_or_clear = '1; always_ff @(posedge clk) begin reset_or_clear <= reset | clear; end @@ -190,35 +189,57 @@ module ddc_ms // by changing the decimation rate or scaling factor mid-burst. //-------------------------------------------------------------------------- logic [REG_SR_DECIM_W-1:0] decim_rate_latched; - logic [ SCALING_WIDTH-1:0] scale_iq_latched; + logic [ SCALING_WIDTH-1:0] scale_iq_latched; logic latched_rate_changed; - logic active_burst; + typedef enum logic [1:0] {IDLE, PROCESSING, WAIT} state_t; + state_t state; - // Track whether input samples are currently being processed as a burst. always_ff @(posedge clk) begin - if (reset || clear) begin - active_burst <= 1'b0; - end else if (!active_burst && sample_in_tvalid && sample_in_tready) begin - active_burst <= 1'b1; - end - end - - // Apply new configuration while idle and hold it through the burst. - // Changes written during a burst are applied after the EoB clear pulse. - always_ff @(posedge clk) begin - latched_rate_changed <= 1'b0; if (reset) begin - decim_rate_latched <= REG_SR_DECIM_W'(1); - scale_iq_latched <= 1 << SCALE_FRAC_W; // 1.0 in Q2.15 format - end else if (clear || !active_burst) begin - scale_iq_latched <= reg_scale_iq; - decim_rate_latched <= reg_decim; - if (clear || (reg_decim != decim_rate_latched)) begin - latched_rate_changed <= 1'b1; - end + state <= WAIT; + decim_rate_latched <= REG_SR_DECIM_W'(1); + scale_iq_latched <= 1 << SCALE_FRAC_W; // 1.0 in Q2.15 format + latched_rate_changed <= 1'b0; + end else begin + latched_rate_changed <= 1'b0; + case (state) + IDLE: begin + // update scaling factor unconditionally as it aligns data as the last + // step of this filter. + scale_iq_latched <= reg_scale_iq; + if (sample_in_tvalid && sample_in_tready) begin + state <= PROCESSING; + end else if (reg_decim != decim_rate_latched) begin + decim_rate_latched <= reg_decim; + latched_rate_changed <= 1'b1; + state <= WAIT; + end + end + PROCESSING: begin + if (clear) begin + decim_rate_latched <= reg_decim; + latched_rate_changed <= 1'b1; + state <= WAIT; + end + end + // Hold input until the registered reset or clear is released and + // downstream registers based on the updated configuration are settled. + WAIT: begin + if (!reset_or_clear) begin + state <= IDLE; + end + end + default: begin + state <= WAIT; + end + endcase end end + logic allow_data_path; + assign allow_data_path = (state == IDLE) || (state == PROCESSING); + assign sample_in_tready = allow_data_path && dds_out_tready; + // ------------------------------------------------------------------------- // Multisample DDS frequency shift // Note: @@ -241,7 +262,7 @@ module ddc_ms .rst (reset), .s_axis_din_tdata (sample_in_tdata), .s_axis_din_tlast (sample_in_tlast), - .s_axis_din_tvalid (sample_in_tvalid), + .s_axis_din_tvalid (sample_in_tvalid && allow_data_path), .s_axis_din_tready (sample_in_tready), .s_axis_din_tuser (sample_in_tuser), .s_axis_phase_tdata (phase_in_tdata), diff --git a/fpga/usrp3/lib/rfnoc/duc_ms.sv b/fpga/usrp3/lib/rfnoc/duc_ms.sv index d81b568c0..10e11c1c8 100644 --- a/fpga/usrp3/lib/rfnoc/duc_ms.sv +++ b/fpga/usrp3/lib/rfnoc/duc_ms.sv @@ -150,6 +150,8 @@ module duc_ms // HBF output → CIC input (plain logic; cic_in is driven from these after the HBF instance) logic hbf_out_tvalid, hbf_out_tready, hbf_out_tlast; logic [SPC-1:0][SAMP_W-1:0] hbf_out_tdata; + logic hbf_in_tready; + // CIC AxiStreamIf #(SPC*SAMP_W) cic_in ( .clk (clk), @@ -163,7 +165,7 @@ module duc_ms // Delay reset/clear by one cycle so updated configuration settles before // the DSP pipelines are cleared. - logic reset_or_clear; + logic reset_or_clear = '1; always_ff @(posedge clk) begin reset_or_clear <= reset | clear; end @@ -176,38 +178,59 @@ module duc_ms logic [REG_SR_INTERP_W-1:0] interp_rate_latched; logic [ SCALING_WIDTH-1:0] scale_iq_latched; logic latched_rate_changed; - logic active_burst; - // Track whether input samples are currently being processed as a burst. - always_ff @(posedge clk) begin - if (reset || clear) begin - active_burst <= 1'b0; - end else if (!active_burst && sample_in_tvalid && sample_in_tready) begin - active_burst <= 1'b1; - end - end + typedef enum logic [1:0] {IDLE, PROCESSING, WAIT} state_t; + state_t state; - // Apply new configuration while idle and hold it through the burst. - // Changes written during a burst are applied after the EoB clear pulse. + // Capture configuration before a burst and settle it for one cycle before + // accepting input again. always_ff @(posedge clk) begin - latched_rate_changed <= 1'b0; if (reset) begin + state <= WAIT; interp_rate_latched <= REG_SR_INTERP_W'(1); scale_iq_latched <= 1 << SCALE_FRAC_W; // 1.0 in Q2.15 format - end else if (clear || !active_burst) begin - scale_iq_latched <= reg_scale_iq; - interp_rate_latched <= reg_interp; - if (clear || (reg_interp != interp_rate_latched)) begin - latched_rate_changed <= 1'b1; - end + end else begin + latched_rate_changed <= 1'b0; + case (state) + IDLE: begin + scale_iq_latched <= reg_scale_iq; + if (sample_in_tvalid && sample_in_tready) begin + state <= PROCESSING; + end else if (reg_interp != interp_rate_latched) begin + interp_rate_latched <= reg_interp; + latched_rate_changed <= 1'b1; + state <= WAIT; + end + end + PROCESSING: begin + if (clear) begin + interp_rate_latched <= reg_interp; + latched_rate_changed <= 1'b1; + state <= WAIT; + end + end + // Hold input until the registered reset or clear is released and + // downstream registers based on the updated configuration are settled. + WAIT: begin + if (!reset_or_clear) begin + state <= IDLE; + end + end + default: begin + state <= WAIT; + end + endcase end end + // Do not accept input while reset or configuration is being settled. + logic allow_data_path; + assign allow_data_path = (state == IDLE) || (state == PROCESSING); + assign sample_in_tready = allow_data_path && hbf_in_tready; + assign cic_rate = interp_rate_latched[7:0]; assign hb_enables = interp_rate_latched[9:8]; - - // ------------------------------------------------------------------------- // HBF cascade interpolator // ------------------------------------------------------------------------- @@ -219,10 +242,10 @@ module duc_ms ) hbf_cascade_i ( .clk (clk), .rst (reset_or_clear), - .clear ('0), + .clear (1'b0), .s_axis_tdata (sample_in_tdata), - .s_axis_tvalid (sample_in_tvalid), - .s_axis_tready (sample_in_tready), + .s_axis_tvalid (sample_in_tvalid && allow_data_path), + .s_axis_tready (hbf_in_tready), .s_axis_tlast (sample_in_tlast), .m_axis_tdata (hbf_out_tdata), .m_axis_tvalid (hbf_out_tvalid), @@ -249,7 +272,11 @@ module duc_ms ) cic_filter_interp_i ( .clk (clk), .rst (reset_or_clear), +<<<<<<< HEAD .clear ('0), +======= + .clear (1'b0), +>>>>>>> a7d5324fc3 (fixing stuff) .data_in (cic_in), .data_out (cic_out), .interp_factor (cic_rate), @@ -280,7 +307,7 @@ module duc_ms .USER_WIDTH (0) ) scale_factor_in ( .clk (clk), - .rst (reset) + .rst (reset_or_clear) ); AxiStreamIf #( @@ -290,7 +317,7 @@ module duc_ms .USER_WIDTH (0) ) iq_in ( .clk (clk), - .rst (reset) + .rst (reset_or_clear) ); AxiStreamIf #( @@ -300,7 +327,7 @@ module duc_ms .USER_WIDTH (0) ) iq_scaled_out ( .clk (clk), - .rst (reset) + .rst (reset_or_clear) ); // Convert real scale factor to complex format {q, i}