| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 
 | //
// 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
 |