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
116 lines
4.7 KiB
Verilog
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
|