mirror of
https://github.com/EttusResearch/uhd.git
synced 2026-10-25 17:36:10 +00:00
Added variants for the DDC/DUC blocks that can process multiple samples per cycle and can be used for bandwidths higher than 200Mhz. This new feature is integrated into the existing RFNoC DDC/DUC blocks. Depending on the Radio bandwidth specified for the USRP variant, the DxC blocks will instantiate the existing singlesample implementation(for FPGA image variants <= 200MHz) or instantiate the multisample implementation(for FPGA image variants > 200MHz). Co-authored-by: Niels Garibaldi <niels.steffen.garibaldi@emerson.com> Co-authored-by: André Zoch <andre.zoch@emerson.com> Co-authored-by: Meghana Halladamath <meghana.halladamath@emerson.com> Co-authored-by: Wade Fife <wade.fife@ettus.com> Co-authored-by: Max Köhler <max.koehler@emerson.com>
87 lines
3.0 KiB
Systemverilog
87 lines
3.0 KiB
Systemverilog
//
|
|
// Copyright 2026 Ettus Research, a National Instruments Brand
|
|
//
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
//
|
|
// Module: cic_destaircase_pipeline
|
|
//
|
|
// Description:
|
|
//
|
|
// Reverses the stagger introduced by cic_staircase_pipeline so that all
|
|
// lanes are re-aligned to the same clock cycle.
|
|
//
|
|
// cic_staircase_pipeline delays lane k by k cycles.
|
|
// This module delays lane k by (SPC-1-k) cycles, giving every lane a
|
|
// uniform total latency of (SPC-1) clock-enabled cycles.
|
|
//
|
|
// out_data[0] = in_data[0] delayed SPC-1 cycles
|
|
// out_data[k] = in_data[k] delayed SPC-1-k cycles
|
|
// out_data[SPC-1] = in_data[SPC-1] (wire, 0 FFs)
|
|
//
|
|
// valid_in and valid_out are delayed according to lane 0. This is effectively
|
|
// a delay by SPC-1 cycles.
|
|
//
|
|
// Parameters:
|
|
// DATA_W : Bit width of each element.
|
|
// SPC : Number of parallel lanes (samples per clock).
|
|
//
|
|
|
|
module cic_destaircase_pipeline #(
|
|
parameter int DATA_W = 16,
|
|
parameter int SPC = 8
|
|
) (
|
|
input logic clk,
|
|
input logic rst,
|
|
input logic en,
|
|
input logic valid_in,
|
|
input logic [SPC-1:0][DATA_W-1:0] in_data,
|
|
output logic valid_out,
|
|
output logic [SPC-1:0][DATA_W-1:0] out_data
|
|
);
|
|
|
|
// --------------------------------------------------------------------
|
|
// Valid pipeline
|
|
// --------------------------------------------------------------------
|
|
// valid_pipeline[d] = valid_in delayed by d clock-enabled cycles.
|
|
// valid_pipeline[0] is a wire (no register).
|
|
logic valid_pipeline [SPC];
|
|
assign valid_pipeline[0] = valid_in;
|
|
for (genvar d = 1; d < SPC; d++) begin : gen_valid_pipeline
|
|
always_ff @(posedge clk) begin : valid_ff
|
|
if (rst) begin
|
|
valid_pipeline[d] <= 1'b0;
|
|
end else if (en) begin
|
|
valid_pipeline[d] <= valid_pipeline[d-1];
|
|
end
|
|
end : valid_ff
|
|
end : gen_valid_pipeline
|
|
assign valid_out = valid_pipeline[SPC-1];
|
|
|
|
// --------------------------------------------------------------------
|
|
// Data pipeline
|
|
// --------------------------------------------------------------------
|
|
// pipeline[k][d] = in_data[k] delayed by d clock-enabled cycles.
|
|
// pipeline[k][0] is a wire (no register).
|
|
logic [DATA_W-1:0] pipeline [SPC][SPC];
|
|
for (genvar k = 0; k < SPC; k++) begin : gen_pipeline_in
|
|
assign pipeline[k][0] = in_data[k];
|
|
end : gen_pipeline_in
|
|
|
|
// Lane k needs (SPC-1-k) registers; lane SPC-1 needs 0 (wire only).
|
|
for (genvar k = 0; k < SPC-1; k++) begin : gen_pipeline_lane
|
|
for (genvar d = 1; d <= SPC-1-k; d++) begin : gen_pipeline_depth
|
|
always_ff @(posedge clk) begin : pipeline_ff
|
|
if (en) begin
|
|
pipeline[k][d] <= pipeline[k][d-1];
|
|
end
|
|
end : pipeline_ff
|
|
end : gen_pipeline_depth
|
|
end : gen_pipeline_lane
|
|
|
|
// Output: lane k taps the d = SPC-1-k entry.
|
|
for (genvar k = 0; k < SPC; k++) begin : gen_out
|
|
assign out_data[k] = pipeline[k][SPC-1-k];
|
|
end : gen_out
|
|
|
|
endmodule : cic_destaircase_pipeline
|