diff options
author | Wade Fife <wade.fife@ettus.com> | 2021-06-08 19:40:46 -0500 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2021-06-10 11:56:58 -0500 |
commit | 6d3765605262016a80f71e36357f749ea35cbe5a (patch) | |
tree | 7d62d6622befd4132ac1ee085effa1426f7f53e5 /fpga/usrp3/top/x400/rf/400m/adc_gearbox_8x4.v | |
parent | f706b89e6974e28ce76aadeeb06169becc86acba (diff) | |
download | uhd-6d3765605262016a80f71e36357f749ea35cbe5a.tar.gz uhd-6d3765605262016a80f71e36357f749ea35cbe5a.tar.bz2 uhd-6d3765605262016a80f71e36357f749ea35cbe5a.zip |
fpga: x400: Add support for X410 motherboard FPGA
Co-authored-by: Andrew Moch <Andrew.Moch@ni.com>
Co-authored-by: Daniel Jepson <daniel.jepson@ni.com>
Co-authored-by: Javier Valenzuela <javier.valenzuela@ni.com>
Co-authored-by: Joerg Hofrichter <joerg.hofrichter@ni.com>
Co-authored-by: Kumaran Subramoniam <kumaran.subramoniam@ni.com>
Co-authored-by: Max Köhler <max.koehler@ni.com>
Co-authored-by: Michael Auchter <michael.auchter@ni.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Wade Fife <wade.fife@ettus.com>
Co-authored-by: Hector Rubio <hrubio@ni.com>
Diffstat (limited to 'fpga/usrp3/top/x400/rf/400m/adc_gearbox_8x4.v')
-rw-r--r-- | fpga/usrp3/top/x400/rf/400m/adc_gearbox_8x4.v | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x400/rf/400m/adc_gearbox_8x4.v b/fpga/usrp3/top/x400/rf/400m/adc_gearbox_8x4.v new file mode 100644 index 000000000..02e2684ad --- /dev/null +++ b/fpga/usrp3/top/x400/rf/400m/adc_gearbox_8x4.v @@ -0,0 +1,105 @@ +// +// Copyright 2021 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: adc_gearbox_8x4 +// +// Description: +// +// Gearbox ADC data from 8 SPC to 4 SPC and corresponding 2x clock to 1x +// clock. Also implement data swapping to format packets to fit the FIR +// filter input requirements. +// +// This modules incurs one clk1x cycle of delay on the data and valid signals +// from input on the 1x domain to output on the 2x domain. +// + +`default_nettype none + +module adc_gearbox_8x4 ( + input wire clk1x, + input wire reset_n_1x, + // Data is _presumed_ to be packed [Sample7, ..., Sample0] (Sample0 in LSBs). + input wire [127:0] adc_q_in_1x, + input wire [127:0] adc_i_in_1x, + input wire valid_in_1x, + // De-assert enable_1x to clear the data valid output synchronously. + input wire enable_1x, + + input wire clk2x, + // Data is packed [Q3,I3, ... , Q0, I0] (I in LSBs) when swap_iq_1x is '0' + input wire swap_iq_2x, + output wire [127:0] adc_out_2x, + output wire valid_out_2x +); + + // Re-create the 1x clock in the 2x domain to produce a deterministic + // crossing. + reg toggle_1x, toggle_2x = 1'b0, toggle_2x_dly = 1'b0, valid_2x = 1'b0, valid_dly_2x = 1'b0; + reg [127:0] data_out_2x = 128'b0, adc_q_data_in_2x = 128'b0, adc_i_data_in_2x = 128'b0; + + // Create a toggle in the 1x clock domain (clock divider /2). + always @(posedge clk1x or negedge reset_n_1x) begin + if ( ! reset_n_1x) begin + toggle_1x <= 1'b0; + end else begin + toggle_1x <= ! toggle_1x; + end + end + + // Transfer the toggle from the 1x to the 2x domain. Delay the toggle in the + // 2x domain by one cycle and compare it to the non-delayed version. When + // they differ, push data_in[63:0] onto the output. When the match, push + // [127:64] onto the output. The datasheet is unclear on the exact + // implementation. + // + // It is safe to not reset this domain because all of the input signals will + // be cleared by the 1x reset. Safe default values are assigned to all these + // registers. + always @(posedge clk2x) begin + toggle_2x <= toggle_1x; + toggle_2x_dly <= toggle_2x; + adc_q_data_in_2x <= adc_q_in_1x; + adc_i_data_in_2x <= adc_i_in_1x; + data_out_2x <= 128'b0; + // Place Q in the MSBs, I in the LSBs by default, unless swapped = 1. + if (valid_2x) begin + if (swap_iq_2x) begin + if (toggle_2x != toggle_2x_dly) begin + data_out_2x <= {adc_i_data_in_2x[63:48], adc_q_data_in_2x[63:48], + adc_i_data_in_2x[47:32], adc_q_data_in_2x[47:32], + adc_i_data_in_2x[31:16], adc_q_data_in_2x[31:16], + adc_i_data_in_2x[15: 0], adc_q_data_in_2x[15: 0]}; + end else begin + data_out_2x <= {adc_i_data_in_2x[127:112], adc_q_data_in_2x[127:112], + adc_i_data_in_2x[111: 96], adc_q_data_in_2x[111: 96], + adc_i_data_in_2x[95 : 80], adc_q_data_in_2x[95 : 80], + adc_i_data_in_2x[79 : 64], adc_q_data_in_2x[79 : 64]}; + end + end else begin + if (toggle_2x != toggle_2x_dly) begin + data_out_2x <= {adc_q_data_in_2x[63:48], adc_i_data_in_2x[63:48], + adc_q_data_in_2x[47:32], adc_i_data_in_2x[47:32], + adc_q_data_in_2x[31:16], adc_i_data_in_2x[31:16], + adc_q_data_in_2x[15: 0], adc_i_data_in_2x[15: 0]}; + end else begin + data_out_2x <= {adc_q_data_in_2x[127:112], adc_i_data_in_2x[127:112], + adc_q_data_in_2x[111: 96], adc_i_data_in_2x[111: 96], + adc_q_data_in_2x[95 : 80], adc_i_data_in_2x[95 : 80], + adc_q_data_in_2x[79 : 64], adc_i_data_in_2x[79 : 64]}; + end + end + end + // Valid is simply a transferred version of the 1x clock's valid. Delay it one + // more cycle to align outputs. + valid_2x <= valid_in_1x && enable_1x; + valid_dly_2x <= valid_2x; + end + + assign adc_out_2x = data_out_2x; + assign valid_out_2x = valid_dly_2x; + +endmodule + +`default_nettype wire |