Files
5cadf901c7 fpga: Add X440/FBX support
Co-authored-by: Martin Braun <martin.braun@ettus.com>
Co-authored-by: Wade Fife <wade.fife@ni.com>
Co-authored-by: Ryan Marlow <ryan@lmarlow.com>


Original-commit: 596760a12e4834e47589c12f8a4fd083aa2f7c25
2023-06-12 10:27:29 -05:00

116 lines
4.7 KiB
Verilog

//
// Copyright 2022 Ettus Research, A National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: adc_iq_repacker
//
// Description:
//
// This component repacks IQ from independent vectors into a single
// output signal, and implements data swapping when requested.
//
// The parameters for this component describe the expected amount of
// data to be received as well as the data to be generated.
//
// - SPC = Samples per cycle: amount of samples to be expected
// on each I and Q input vector on each "clk" cycle.
// - SAMPLE_WIDTH = Amount of bits composing each sample
//
// This modules incurs in two clk cycles of delay on the data and valid
// signals from input to output.
//
// Example case : SPC = 2, SAMPLE_WIDTH = 16
//
// adc_x_in size(for I and Q) = 2 x 16 = 32
// adc_out size = 2 x 2 x 16 = 64
//
// _______ _______ _______ ______
// clk _| |_______| |_______| |_______|
// _ _______________ _______________ _______________ ______
// adc_i_in _X_____I1,I0_____X_____I3,I2_____X____32{'X'}____X______
// _ _______________ _______________ _______________ ______
// adc_q_in _X_____Q1,Q0_____X_____Q3,Q2_____X____32{'X'}____X______
// _______________________________
// valid_in _| |______________________
// _ _______________ _______________ _______________ ______
// adc_out _X____64{'X'}____X____64{'X'}____X__Q1,I1,Q0,I0__X__Q3,..
// ______________________
// valid_out _________________________________|
//
// When the swap input is high, the order in which Q and I samples
// appear on the output vector is inverted
//
// _______ _______ _______ ______
// clk _| |_______| |_______| |_______|
// _ _______________ _______________ _______________ ______
// adc_i_in _X_____I1,I0_____X_____I3,I2_____X____32{'X'}____X______
// _ _______________ _______________ _______________ ______
// adc_q_in _X_____Q1,Q0_____X_____Q3,Q2_____X____32{'X'}____X______
// _______________________________
// valid_in _| |______________________
// _ _______________ _______________ _______________ ______
// adc_out _X____64{'X'}____X____64{'X'}____X__I1,Q1,I0,Q0__X__I3,..
// ______________________
// valid_out _________________________________|
//
// Parameters:
// SPC = Samples per cycle
// SAMPLE_WIDTH = width of i/q sample inputs. Output will be 2*SAMPLE_WIDTH
//
module adc_iq_repacker #(
parameter SPC = 1,
parameter SAMPLE_WIDTH = 16
)
(
input wire clk,
// Data in
input wire [SPC*SAMPLE_WIDTH-1:0] adc_q_in,
input wire [SPC*SAMPLE_WIDTH-1:0] adc_i_in,
input wire valid_in,
// This signal is currently driven in a related clock, and even though it runs at half the rate is should be fine
// to handle it in this clock domain(in nature it will also stay high one asserted until the next reset.)
input wire enable,
// Data is packed [Q,I] (I in LSBs) when swap_iq is '0', and [I,Q] otherwise
input wire swap_iq,
// Data out
output reg [SPC*SAMPLE_WIDTH*2-1:0] data_out_tdata,
output reg data_out_tvalid
);
localparam IQ_WIDTH = SAMPLE_WIDTH*2;
reg valid = 1'b0, valid_dly = 1'b0;
reg [SPC*SAMPLE_WIDTH-1:0] adc_q_data_in = {SPC*SAMPLE_WIDTH{1'b0}};
reg [SPC*SAMPLE_WIDTH-1:0] adc_i_data_in = {SPC*SAMPLE_WIDTH{1'b0}};
integer sample_num;
// It is safe to not reset this domain because all of the input signals will be cleared
// by a synchronous reset. Safe default values are assigned to all these registers.
always @(posedge clk) begin
adc_q_data_in <= adc_q_in;
adc_i_data_in <= adc_i_in;
// Place Q in the MSBs, I in the LSBs by default, unless swapped = 1.
for (sample_num=0; sample_num < (SPC); sample_num = sample_num + 1)
begin : data_out_gen
if (swap_iq) begin
data_out_tdata[sample_num*(IQ_WIDTH) +: IQ_WIDTH] <=
{adc_i_data_in[sample_num*(SAMPLE_WIDTH) +: SAMPLE_WIDTH],
adc_q_data_in[sample_num*(SAMPLE_WIDTH) +: SAMPLE_WIDTH]};
end else begin
data_out_tdata[sample_num*(IQ_WIDTH) +: IQ_WIDTH] <=
{adc_q_data_in[sample_num*(SAMPLE_WIDTH) +: SAMPLE_WIDTH],
adc_i_data_in[sample_num*(SAMPLE_WIDTH) +: SAMPLE_WIDTH]};
end
end
// Valid is simply a transferred version of the 1x clock's valid. Delay it one
// more cycle to align outputs.
valid <= valid_in && enable;
data_out_tvalid <= valid;
end
endmodule