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
This commit is contained in:
committed by
Aki Tomita
co-authored by
Martin Braun
Wade Fife
Ryan Marlow
parent
a405111ce7
commit
5cadf901c7
@@ -6,6 +6,7 @@
|
||||
|
||||
RF_COMMON_SRCS = $(abspath $(addprefix $(BASE_DIR)/../top/x400/rf/common/, \
|
||||
PkgRf.vhd \
|
||||
adc_iq_repacker.v \
|
||||
axis_mux.vhd \
|
||||
capture_sysref.v \
|
||||
gpio_to_axis_mux.vhd \
|
||||
|
||||
@@ -0,0 +1,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
|
||||
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# Copyright 2023 Ettus Research, a National Instruments Brand
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
#
|
||||
|
||||
RF_FULL_SRCS = $(abspath $(addprefix $(BASE_DIR)/../top/x400/rf/full/, \
|
||||
rf_core_full.v \
|
||||
))
|
||||
@@ -0,0 +1,436 @@
|
||||
//
|
||||
// Copyright 2023 Ettus Research, a National Instruments Brand
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: rf_core_full
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// Top-level wrapper for the ADC/DAC processing logic. One of these wrappers
|
||||
// exists for every supported Data Rate. An instance of this core should
|
||||
// exist per dboard.
|
||||
//
|
||||
// Data/RF Specs:
|
||||
// DBs: 1
|
||||
// RX/DB: 4
|
||||
// TX/DB: 4
|
||||
// Data Rate: rfdc_clk @ 8 SPC
|
||||
//
|
||||
// Input Clocks, all aligned to one another and coming from same MMCM
|
||||
// rfdc_clk: 15.625 to 250 MHz
|
||||
// rfdc_clk_2x: 2 * rfdc_clk
|
||||
//
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module rf_core_full # (
|
||||
parameter NUM_ADC_CHANNELS = 4,
|
||||
parameter NUM_DAC_CHANNELS = 4
|
||||
) (
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Clocking
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Main Clock Inputs
|
||||
input wire rfdc_clk,
|
||||
input wire rfdc_clk_2x,
|
||||
|
||||
// AXI4-Lite Config Clock
|
||||
// This clock is used to synchronize status bits for the RFDC
|
||||
// registers in the AXI-S clock domain.
|
||||
input wire s_axi_config_clk,
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// RFDC Data Interfaces
|
||||
//---------------------------------------------------------------------------
|
||||
// All ports here are in the rfdc_clk domain.
|
||||
|
||||
// ADC
|
||||
input wire [127:0] adc_data_in_i_tdata_0,
|
||||
output wire adc_data_in_i_tready_0,
|
||||
input wire adc_data_in_i_tvalid_0,
|
||||
input wire [127:0] adc_data_in_q_tdata_0,
|
||||
output wire adc_data_in_q_tready_0,
|
||||
input wire adc_data_in_q_tvalid_0,
|
||||
input wire [127:0] adc_data_in_i_tdata_1,
|
||||
output wire adc_data_in_i_tready_1,
|
||||
input wire adc_data_in_i_tvalid_1,
|
||||
input wire [127:0] adc_data_in_q_tdata_1,
|
||||
output wire adc_data_in_q_tready_1,
|
||||
input wire adc_data_in_q_tvalid_1,
|
||||
input wire [127:0] adc_data_in_i_tdata_2,
|
||||
output wire adc_data_in_i_tready_2,
|
||||
input wire adc_data_in_i_tvalid_2,
|
||||
input wire [127:0] adc_data_in_q_tdata_2,
|
||||
output wire adc_data_in_q_tready_2,
|
||||
input wire adc_data_in_q_tvalid_2,
|
||||
input wire [127:0] adc_data_in_i_tdata_3,
|
||||
output wire adc_data_in_i_tready_3,
|
||||
input wire adc_data_in_i_tvalid_3,
|
||||
input wire [127:0] adc_data_in_q_tdata_3,
|
||||
output wire adc_data_in_q_tready_3,
|
||||
input wire adc_data_in_q_tvalid_3,
|
||||
|
||||
|
||||
// DAC
|
||||
output wire [255:0] dac_data_out_tdata_0,
|
||||
input wire dac_data_out_tready_0,
|
||||
output wire dac_data_out_tvalid_0,
|
||||
output wire [255:0] dac_data_out_tdata_1,
|
||||
input wire dac_data_out_tready_1,
|
||||
output wire dac_data_out_tvalid_1,
|
||||
output wire [255:0] dac_data_out_tdata_2,
|
||||
input wire dac_data_out_tready_2,
|
||||
output wire dac_data_out_tvalid_2,
|
||||
output wire [255:0] dac_data_out_tdata_3,
|
||||
input wire dac_data_out_tready_3,
|
||||
output wire dac_data_out_tvalid_3,
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// User Data Interfaces
|
||||
//---------------------------------------------------------------------------
|
||||
// All ports here are in the rfdc_clk domain on the X440.
|
||||
|
||||
// ADC
|
||||
output wire [255:0] adc_data_out_tdata_0, // Packed [Q7,I7, ... , Q0,I0] with Q in MSBs
|
||||
output wire adc_data_out_tvalid_0,
|
||||
output wire [255:0] adc_data_out_tdata_1, // Packed [Q7,I7, ... , Q0,I0] with Q in MSBs
|
||||
output wire adc_data_out_tvalid_1,
|
||||
output wire [255:0] adc_data_out_tdata_2, // Packed [Q7,I7, ... , Q0,I0] with Q in MSBs
|
||||
output wire adc_data_out_tvalid_2,
|
||||
output wire [255:0] adc_data_out_tdata_3, // Packed [Q7,I7, ... , Q0,I0] with Q in MSBs
|
||||
output wire adc_data_out_tvalid_3,
|
||||
|
||||
// DAC
|
||||
input wire [255:0] dac_data_in_tdata_0, // Packed [Q7,I7, ... , Q0,I0] with Q in MSBs
|
||||
output wire dac_data_in_tready_0,
|
||||
input wire dac_data_in_tvalid_0,
|
||||
input wire [255:0] dac_data_in_tdata_1, // Packed [Q7,I7, ... , Q0,I0] with Q in MSBs
|
||||
output wire dac_data_in_tready_1,
|
||||
input wire dac_data_in_tvalid_1,
|
||||
input wire [255:0] dac_data_in_tdata_2, // Packed [Q7,I7, ... , Q0,I0] with Q in MSBs
|
||||
output wire dac_data_in_tready_2,
|
||||
input wire dac_data_in_tvalid_2,
|
||||
input wire [255:0] dac_data_in_tdata_3, // Packed [Q7,I7, ... , Q0,I0] with Q in MSBs
|
||||
output wire dac_data_in_tready_3,
|
||||
input wire dac_data_in_tvalid_3,
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Miscellaneous
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Invert I/Q control signals from RFDC to DSP chain.
|
||||
input wire [3:0] invert_adc_iq_rclk2,
|
||||
input wire [3:0] invert_dac_iq_rclk2,
|
||||
|
||||
// Control/status vectors from/to RFDC.
|
||||
// Notice these are all in the s_axi_config_clk domain.
|
||||
output wire [9:0] dsp_info_sclk,
|
||||
output wire [15:0] axi_status_sclk,
|
||||
output wire [15:0] rfdc_info_sclk,
|
||||
|
||||
// Resets.
|
||||
input wire adc_enable_data_rclk,
|
||||
input wire adc_rfdc_axi_resetn_rclk,
|
||||
|
||||
// Version (Constant)
|
||||
output wire [95:0] version_info
|
||||
);
|
||||
|
||||
`include "../../regmap/x440/rfdc_regs_regmap_utils.vh"
|
||||
`include "../../regmap/x440/versioning_regs_regmap_utils.vh"
|
||||
`include "../../regmap/versioning_utils.vh"
|
||||
|
||||
// ADC data interface from RFDC.
|
||||
wire [127:0] adc_data_in_i_tdata [0:NUM_ADC_CHANNELS-1]; // 8 SPC (I)
|
||||
wire [127:0] adc_data_in_q_tdata [0:NUM_ADC_CHANNELS-1]; // 8 SPC (Q)
|
||||
wire [NUM_ADC_CHANNELS-1:0] adc_data_in_i_tready;
|
||||
wire [NUM_ADC_CHANNELS-1:0] adc_data_in_q_tready;
|
||||
wire [NUM_ADC_CHANNELS-1:0] adc_data_in_i_tvalid;
|
||||
wire [NUM_ADC_CHANNELS-1:0] adc_data_in_q_tvalid;
|
||||
// DAC data interface to RFDC.
|
||||
wire [255:0] dac_data_out_tdata [0:NUM_DAC_CHANNELS-1]; // 8 SPC (I + Q)
|
||||
wire [NUM_DAC_CHANNELS-1:0] dac_data_out_tready;
|
||||
wire [NUM_DAC_CHANNELS-1:0] dac_data_out_tvalid;
|
||||
|
||||
// ADC data interface to user.
|
||||
wire [255:0] adc_data_out_tdata [0:NUM_ADC_CHANNELS-1]; // 8 SPC (I + Q)
|
||||
wire [NUM_ADC_CHANNELS-1:0] adc_data_out_tready;
|
||||
wire [NUM_ADC_CHANNELS-1:0] adc_data_out_tvalid;
|
||||
// DAC data interface from user.
|
||||
wire [255:0] dac_data_in_tdata_preswap [0:NUM_DAC_CHANNELS-1]; // 8 SPC (I + Q)
|
||||
wire [255:0] dac_data_in_tdata [0:NUM_DAC_CHANNELS-1]; // 8 SPC (I + Q)
|
||||
wire [NUM_DAC_CHANNELS-1:0] dac_data_in_tready;
|
||||
wire [NUM_DAC_CHANNELS-1:0] dac_data_in_tvalid;
|
||||
|
||||
wire [15:0] axi_status;
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Resets, Debug and Misc.
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Group all these status bits together. They don't toggle frequently so data
|
||||
// coherency is not an issue here.
|
||||
// Using constants for DB0 since the bits are the 16 LSBs in a 32-bit vector.
|
||||
// DB1 simply uses the 16 MSBs when wiring the status vector.
|
||||
assign axi_status[USER_ADC_TREADY_MSB :USER_ADC_TREADY ] = adc_data_out_tready[1:0];
|
||||
assign axi_status[USER_ADC_TVALID_MSB :USER_ADC_TVALID ] = adc_data_out_tvalid[1:0];
|
||||
assign axi_status[RFDC_ADC_I_TVALID_MSB:RFDC_ADC_I_TVALID] = adc_data_in_i_tvalid[1:0];
|
||||
assign axi_status[RFDC_ADC_Q_TVALID_MSB:RFDC_ADC_Q_TVALID] = adc_data_in_q_tvalid[1:0];
|
||||
assign axi_status[RFDC_ADC_I_TREADY_MSB:RFDC_ADC_I_TREADY] = adc_data_in_i_tready[1:0];
|
||||
assign axi_status[RFDC_ADC_Q_TREADY_MSB:RFDC_ADC_Q_TREADY] = adc_data_in_q_tready[1:0];
|
||||
assign axi_status[RFDC_DAC_TVALID_MSB :RFDC_DAC_TVALID ] = dac_data_out_tvalid[1:0];
|
||||
assign axi_status[RFDC_DAC_TREADY_MSB :RFDC_DAC_TREADY ] = dac_data_out_tready[1:0];
|
||||
|
||||
synchronizer #(
|
||||
.WIDTH (16),
|
||||
.STAGES (2),
|
||||
.INITIAL_VAL (0),
|
||||
.FALSE_PATH_TO_IN (1)
|
||||
) synchronizer_axis_status (
|
||||
.clk (s_axi_config_clk),
|
||||
.rst (1'b0),
|
||||
.in (axi_status),
|
||||
.out (axi_status_sclk)
|
||||
);
|
||||
|
||||
// Drive the DSP info vector with information on this specific DSP chain.
|
||||
assign dsp_info_sclk[FABRIC_DSP_RX_CNT_MSB:FABRIC_DSP_RX_CNT] = NUM_ADC_CHANNELS;
|
||||
assign dsp_info_sclk[FABRIC_DSP_TX_CNT_MSB:FABRIC_DSP_TX_CNT] = NUM_DAC_CHANNELS;
|
||||
|
||||
// This RF core always consumes 8 SPC from the gearbox per I/Q signal
|
||||
assign rfdc_info_sclk[RFDC_INFO_SPC_RX_MSB:RFDC_INFO_SPC_RX] = $clog2(8);
|
||||
assign rfdc_info_sclk[RFDC_INFO_SPC_TX_MSB:RFDC_INFO_SPC_TX] = $clog2(16);
|
||||
// This RF core module contains no additional resampling
|
||||
assign rfdc_info_sclk[RFDC_INFO_XTRA_RESAMP_MSB:RFDC_INFO_XTRA_RESAMP] = 4'd1;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// ADC Post-Processing
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Data comes from the RFDC as 8 SPC, separate streams for each channel and
|
||||
// I/Q.
|
||||
assign adc_data_in_i_tdata[0] = adc_data_in_i_tdata_0;
|
||||
assign adc_data_in_q_tdata[0] = adc_data_in_q_tdata_0;
|
||||
assign adc_data_in_i_tdata[1] = adc_data_in_i_tdata_1;
|
||||
assign adc_data_in_q_tdata[1] = adc_data_in_q_tdata_1;
|
||||
assign adc_data_in_i_tdata[2] = adc_data_in_i_tdata_2;
|
||||
assign adc_data_in_q_tdata[2] = adc_data_in_q_tdata_2;
|
||||
assign adc_data_in_i_tdata[3] = adc_data_in_i_tdata_3;
|
||||
assign adc_data_in_q_tdata[3] = adc_data_in_q_tdata_3;
|
||||
|
||||
assign adc_data_in_i_tready_0 = adc_data_in_i_tready[0];
|
||||
assign adc_data_in_i_tvalid[0] = adc_data_in_i_tvalid_0;
|
||||
assign adc_data_in_q_tready_0 = adc_data_in_q_tready[0];
|
||||
assign adc_data_in_q_tvalid[0] = adc_data_in_q_tvalid_0;
|
||||
assign adc_data_in_i_tready_1 = adc_data_in_i_tready[1];
|
||||
assign adc_data_in_i_tvalid[1] = adc_data_in_i_tvalid_1;
|
||||
assign adc_data_in_q_tready_1 = adc_data_in_q_tready[1];
|
||||
assign adc_data_in_q_tvalid[1] = adc_data_in_q_tvalid_1;
|
||||
assign adc_data_in_i_tready_2 = adc_data_in_i_tready[2];
|
||||
assign adc_data_in_i_tvalid[2] = adc_data_in_i_tvalid_2;
|
||||
assign adc_data_in_q_tready_2 = adc_data_in_q_tready[2];
|
||||
assign adc_data_in_q_tvalid[2] = adc_data_in_q_tvalid_2;
|
||||
assign adc_data_in_i_tready_3 = adc_data_in_i_tready[3];
|
||||
assign adc_data_in_i_tvalid[3] = adc_data_in_i_tvalid_3;
|
||||
assign adc_data_in_q_tready_3 = adc_data_in_q_tready[3];
|
||||
assign adc_data_in_q_tvalid[3] = adc_data_in_q_tvalid_3;
|
||||
|
||||
// ADC Data from the RFDC arrives here as 8 SPC with separate I and Q
|
||||
// streams. It leaves the adc_full_rate_bd as 8 SPC with I and Q packed into
|
||||
// a single 256 bit word.
|
||||
genvar adc_num;
|
||||
generate
|
||||
for (adc_num=0; adc_num < (NUM_ADC_CHANNELS); adc_num = adc_num + 1)
|
||||
begin : adc_gen
|
||||
adc_full_bd adc_full_bd_gen (
|
||||
.enable_data_to_repacker_rclk (adc_enable_data_rclk),
|
||||
.rfdc_adc_axi_resetn_rclk (adc_rfdc_axi_resetn_rclk),
|
||||
.rfdc_clk (rfdc_clk),
|
||||
.swap_iq_rclk (invert_adc_iq_rclk2 [adc_num]),
|
||||
.adc_q_data_in_tvalid (adc_data_in_q_tvalid[adc_num]),
|
||||
.adc_q_data_in_tready (adc_data_in_q_tready[adc_num]),
|
||||
.adc_q_data_in_tdata (adc_data_in_q_tdata [adc_num]),
|
||||
.adc_i_data_in_tvalid (adc_data_in_i_tvalid[adc_num]),
|
||||
.adc_i_data_in_tready (adc_data_in_i_tready[adc_num]),
|
||||
.adc_i_data_in_tdata (adc_data_in_i_tdata [adc_num]),
|
||||
.adc_data_out_tvalid (adc_data_out_tvalid [adc_num]),
|
||||
.adc_data_out_tdata (adc_data_out_tdata [adc_num])
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// Data is released to the user as 8 SPC, separate streams for each channel.
|
||||
assign adc_data_out_tdata_0 = adc_data_out_tdata[0];
|
||||
assign adc_data_out_tdata_1 = adc_data_out_tdata[1];
|
||||
assign adc_data_out_tdata_2 = adc_data_out_tdata[2];
|
||||
assign adc_data_out_tdata_3 = adc_data_out_tdata[3];
|
||||
|
||||
// There is no tready going to the ADC (one has to be always ready for ADC
|
||||
// data), but it is still a component of the axi_status vector as a generic
|
||||
// AXI stream status. Report 1'b1 to the status vector consistent with being
|
||||
// always ready
|
||||
assign adc_data_out_tready[0] = 1'b1;
|
||||
assign adc_data_out_tvalid_0 = adc_data_out_tvalid[0];
|
||||
assign adc_data_out_tready[1] = 1'b1;
|
||||
assign adc_data_out_tvalid_1 = adc_data_out_tvalid[1];
|
||||
assign adc_data_out_tready[2] = 1'b1;
|
||||
assign adc_data_out_tvalid_2 = adc_data_out_tvalid[2];
|
||||
assign adc_data_out_tready[3] = 1'b1;
|
||||
assign adc_data_out_tvalid_3 = adc_data_out_tvalid[3];
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// DAC Pre-Processing
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Data comes from the user as 8 SPC, separate streams for each channel.
|
||||
assign dac_data_in_tdata_preswap[0] = dac_data_in_tdata_0;
|
||||
assign dac_data_in_tdata_preswap[1] = dac_data_in_tdata_1;
|
||||
assign dac_data_in_tdata_preswap[2] = dac_data_in_tdata_2;
|
||||
assign dac_data_in_tdata_preswap[3] = dac_data_in_tdata_3;
|
||||
|
||||
assign dac_data_in_tready_0 = dac_data_in_tready[0];
|
||||
assign dac_data_in_tvalid[0] = dac_data_in_tvalid_0;
|
||||
assign dac_data_in_tready_1 = dac_data_in_tready[1];
|
||||
assign dac_data_in_tvalid[1] = dac_data_in_tvalid_1;
|
||||
assign dac_data_in_tready_2 = dac_data_in_tready[2];
|
||||
assign dac_data_in_tvalid[2] = dac_data_in_tvalid_2;
|
||||
assign dac_data_in_tready_3 = dac_data_in_tready[3];
|
||||
assign dac_data_in_tvalid[3] = dac_data_in_tvalid_3;
|
||||
|
||||
genvar dac_num;
|
||||
generate
|
||||
for (dac_num=0; dac_num < (NUM_DAC_CHANNELS); dac_num = dac_num + 1)
|
||||
begin : dac_swap_gen
|
||||
//IO and Q0 swap
|
||||
assign dac_data_in_tdata[dac_num][15:00] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][31:16]) : (dac_data_in_tdata_preswap[dac_num][15:0]);
|
||||
assign dac_data_in_tdata[dac_num][31:16] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][15:00]) : (dac_data_in_tdata_preswap[dac_num][31:16]);
|
||||
|
||||
//I1 and Q1 swap
|
||||
assign dac_data_in_tdata[dac_num][47:32] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][63:48]) : (dac_data_in_tdata_preswap[dac_num][47:32]);
|
||||
assign dac_data_in_tdata[dac_num][63:48] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][47:32]) : (dac_data_in_tdata_preswap[dac_num][63:48]);
|
||||
|
||||
//I2 and Q2 swap
|
||||
assign dac_data_in_tdata[dac_num][79:64] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][95:80]) : (dac_data_in_tdata_preswap[dac_num][79:64]);
|
||||
assign dac_data_in_tdata[dac_num][95:80] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][79:64]) : (dac_data_in_tdata_preswap[dac_num][95:80]);
|
||||
|
||||
//I3 and Q3 swap
|
||||
assign dac_data_in_tdata[dac_num][111:96] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][127:112]) : (dac_data_in_tdata_preswap[dac_num][111:96]);
|
||||
assign dac_data_in_tdata[dac_num][127:112] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][111:96]) : (dac_data_in_tdata_preswap[dac_num][127:112]);
|
||||
|
||||
//I4 and Q4 swap
|
||||
assign dac_data_in_tdata[dac_num][143:128] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][159:144]) : (dac_data_in_tdata_preswap[dac_num][143:128]);
|
||||
assign dac_data_in_tdata[dac_num][159:144] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][143:128]) : (dac_data_in_tdata_preswap[dac_num][159:144]);
|
||||
|
||||
//I5 and Q5 swap
|
||||
assign dac_data_in_tdata[dac_num][175:160] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][191:176]) : (dac_data_in_tdata_preswap[dac_num][175:160]);
|
||||
assign dac_data_in_tdata[dac_num][191:176] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][175:160]) : (dac_data_in_tdata_preswap[dac_num][191:176]);
|
||||
|
||||
//I6 and Q6 swap
|
||||
assign dac_data_in_tdata[dac_num][207:192] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][223:208]) : (dac_data_in_tdata_preswap[dac_num][207:192]);
|
||||
assign dac_data_in_tdata[dac_num][223:208] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][207:192]) : (dac_data_in_tdata_preswap[dac_num][223:208]);
|
||||
|
||||
//I7 and Q7 swap
|
||||
assign dac_data_in_tdata[dac_num][239:224] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][255:240]) : (dac_data_in_tdata_preswap[dac_num][239:224]);
|
||||
assign dac_data_in_tdata[dac_num][255:240] = invert_dac_iq_rclk2[dac_num] ?
|
||||
(dac_data_in_tdata_preswap[dac_num][239:224]) : (dac_data_in_tdata_preswap[dac_num][255:240]);
|
||||
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// These streams are then connected to data out, no need for a bd, and form a single
|
||||
// stream per channel, 8 SPC, packed: MSB [Sample7Q, Sample7I, ... ,
|
||||
// Sample0Q, Sample0I] LSB.
|
||||
generate
|
||||
for (dac_num=0; dac_num < (NUM_DAC_CHANNELS); dac_num = dac_num + 1)
|
||||
begin : dac_gen
|
||||
assign dac_data_out_tdata[dac_num] = dac_data_in_tdata[dac_num];
|
||||
assign dac_data_out_tvalid[dac_num] = dac_data_in_tvalid[dac_num];
|
||||
assign dac_data_in_tready[dac_num] = dac_data_out_tready[dac_num];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// Data is released to the RFDC as 8 SPC, separate streams per channel (I/Q
|
||||
// together).
|
||||
assign dac_data_out_tdata_0 = dac_data_out_tdata[0];
|
||||
assign dac_data_out_tdata_1 = dac_data_out_tdata[1];
|
||||
assign dac_data_out_tdata_2 = dac_data_out_tdata[2];
|
||||
assign dac_data_out_tdata_3 = dac_data_out_tdata[3];
|
||||
|
||||
assign dac_data_out_tready[0] = dac_data_out_tready_0;
|
||||
assign dac_data_out_tvalid_0 = dac_data_out_tvalid[0];
|
||||
assign dac_data_out_tready[1] = dac_data_out_tready_1;
|
||||
assign dac_data_out_tvalid_1 = dac_data_out_tvalid[1];
|
||||
assign dac_data_out_tready[2] = dac_data_out_tready_2;
|
||||
assign dac_data_out_tvalid_2 = dac_data_out_tvalid[2];
|
||||
assign dac_data_out_tready[3] = dac_data_out_tready_3;
|
||||
assign dac_data_out_tvalid_3 = dac_data_out_tvalid[3];
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Version
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Version metadata, constants come from auto-generated
|
||||
// versioning_regs_regmap_utils.vh
|
||||
assign version_info = build_component_versions(
|
||||
RF_CORE_FULL_VERSION_LAST_MODIFIED_TIME,
|
||||
build_version(
|
||||
RF_CORE_FULL_OLDEST_COMPATIBLE_VERSION_MAJOR,
|
||||
RF_CORE_FULL_OLDEST_COMPATIBLE_VERSION_MINOR,
|
||||
RF_CORE_FULL_OLDEST_COMPATIBLE_VERSION_BUILD
|
||||
),
|
||||
build_version(
|
||||
RF_CORE_FULL_CURRENT_VERSION_MAJOR,
|
||||
RF_CORE_FULL_CURRENT_VERSION_MINOR,
|
||||
RF_CORE_FULL_CURRENT_VERSION_BUILD
|
||||
)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
`default_nettype wire
|
||||
|
||||
//XmlParse xml_on
|
||||
//<regmap name="VERSIONING_REGS_REGMAP">
|
||||
// <group name="VERSIONING_CONSTANTS">
|
||||
// <enumeratedtype name="RF_CORE_FULL_VERSION" showhex="true">
|
||||
// <info>
|
||||
// Full BW RF core.{BR/}
|
||||
// For guidance on when to update these revision numbers,
|
||||
// please refer to the register map documentation accordingly:
|
||||
// <li> Current version: @.VERSIONING_REGS_REGMAP..CURRENT_VERSION
|
||||
// <li> Oldest compatible version: @.VERSIONING_REGS_REGMAP..OLDEST_COMPATIBLE_VERSION
|
||||
// <li> Version last modified: @.VERSIONING_REGS_REGMAP..VERSION_LAST_MODIFIED
|
||||
// </info>
|
||||
// <value name="RF_CORE_FULL_CURRENT_VERSION_MAJOR" integer="1"/>
|
||||
// <value name="RF_CORE_FULL_CURRENT_VERSION_MINOR" integer="0"/>
|
||||
// <value name="RF_CORE_FULL_CURRENT_VERSION_BUILD" integer="0"/>
|
||||
// <value name="RF_CORE_FULL_OLDEST_COMPATIBLE_VERSION_MAJOR" integer="1"/>
|
||||
// <value name="RF_CORE_FULL_OLDEST_COMPATIBLE_VERSION_MINOR" integer="0"/>
|
||||
// <value name="RF_CORE_FULL_OLDEST_COMPATIBLE_VERSION_BUILD" integer="0"/>
|
||||
// <value name="RF_CORE_FULL_VERSION_LAST_MODIFIED_TIME" integer="0x22062900"/>
|
||||
// </enumeratedtype>
|
||||
// </group>
|
||||
//</regmap>
|
||||
//XmlParse xml_off
|
||||
@@ -80,6 +80,7 @@ $(abspath tb_ddc_400m_saturate.vhd ) \
|
||||
$(abspath tb_duc_400m_saturate.vhd ) \
|
||||
$(abspath tb_rf_nco_reset.vhd ) \
|
||||
$(abspath tb_x410_rf_reset_controller.vhd ) \
|
||||
$(abspath tb_adc_iq_repacker.sv ) \
|
||||
$(abspath rf_all_tb.sv ) \
|
||||
|
||||
#-------------------------------------------------
|
||||
|
||||
@@ -26,6 +26,7 @@ module rf_all_tb;
|
||||
tb_duc_400m_saturate tb_duc_400m_saturate_i ();
|
||||
tb_rf_nco_reset tb_rf_nco_reset_i ();
|
||||
tb_x410_rf_reset_controller tb_x410_rf_reset_controller_i ();
|
||||
tb_adc_iq_repacker tb_adc_iq_repacker_i ();
|
||||
|
||||
initial begin
|
||||
test.start_tb("rf_all_tb", 1ms);
|
||||
@@ -44,7 +45,8 @@ module rf_all_tb;
|
||||
tb_ddc_400m_saturate_i.StopSim &&
|
||||
tb_duc_400m_saturate_i.StopSim &&
|
||||
tb_rf_nco_reset_i.StopSim &&
|
||||
tb_x410_rf_reset_controller_i.StopSim
|
||||
tb_x410_rf_reset_controller_i.StopSim &&
|
||||
tb_adc_iq_repacker_i.StopSim
|
||||
) break;
|
||||
end
|
||||
test.end_test();
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// Copyright 2022 Ettus Research, a National Instruments Brand
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: tb_adc_iq_repacker
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// This testbench mainly tests tb_adc_iq_repacker. It runs
|
||||
// 3 different tests:
|
||||
// - test data propagation when not swapping data
|
||||
// - test data propagation when swapping data
|
||||
// - check that data valid does not propagate when block
|
||||
// is not enabled.
|
||||
//
|
||||
|
||||
`timescale 1ns/1ps
|
||||
`define NS_PER_TICK 1
|
||||
`define NUM_TEST_CASES 3
|
||||
|
||||
`include "sim_clks_rsts.vh"
|
||||
`include "sim_exec_report.vh"
|
||||
|
||||
module tb_adc_iq_repacker();
|
||||
import PkgRandom::*;
|
||||
|
||||
`TEST_BENCH_INIT("tb_adc_iq_repacker", `NUM_TEST_CASES, `NS_PER_TICK);
|
||||
//sets up clock
|
||||
localparam CLK_PERIOD = $ceil(1e9/100.0e6);
|
||||
`DEFINE_CLK(clk, CLK_PERIOD, 50);
|
||||
//declare parameters
|
||||
localparam SPC = 1;
|
||||
localparam SAMPLE_WIDTH = 16;
|
||||
|
||||
//declare wires and regs
|
||||
|
||||
reg enable;
|
||||
reg valid_in;
|
||||
reg swap_iq;
|
||||
reg [SPC*SAMPLE_WIDTH-1:0] adc_q_in;
|
||||
reg [SPC*SAMPLE_WIDTH-1:0] adc_i_in;
|
||||
reg StopSim;
|
||||
|
||||
wire [SPC*SAMPLE_WIDTH*2-1:0] data_out_tdata;
|
||||
wire data_out_tvalid;
|
||||
|
||||
PkgRandom::Rand #(SPC*SAMPLE_WIDTH) rand_i;
|
||||
PkgRandom::Rand #(SPC*SAMPLE_WIDTH) rand_q;
|
||||
|
||||
// instance adc_iq_repacker
|
||||
adc_iq_repacker #(
|
||||
.SPC(SPC),
|
||||
.SAMPLE_WIDTH(SAMPLE_WIDTH)
|
||||
) adc_iq_repacker_inst (
|
||||
.clk(clk),
|
||||
// Data in
|
||||
.adc_q_in(adc_q_in),
|
||||
.adc_i_in(adc_i_in),
|
||||
.valid_in(valid_in),
|
||||
.enable(enable),
|
||||
// Data is packed [Q,I] (I in LSBs) when swap_iq is '0', and [I,Q] otherwise
|
||||
.swap_iq(swap_iq),
|
||||
// Data out
|
||||
.data_out_tdata(data_out_tdata),
|
||||
.data_out_tvalid(data_out_tvalid)
|
||||
);
|
||||
|
||||
|
||||
// initial statement with test cases
|
||||
initial begin : tb_main
|
||||
|
||||
// test data propagation when not swapping data
|
||||
`TEST_CASE_START("test data propagation, no swap, core enabled");
|
||||
repeat (10) @(posedge clk);
|
||||
swap_iq = 0;
|
||||
enable = 1;
|
||||
StopSim = 0;
|
||||
valid_in = 1;
|
||||
for (int i = 0; i < 10; i++) begin
|
||||
adc_q_in = rand_q.rand_bit();
|
||||
adc_i_in = rand_i.rand_bit();
|
||||
repeat (3) @(posedge clk);
|
||||
`ASSERT_ERROR(data_out_tdata[SAMPLE_WIDTH*2-1:0] == {adc_q_in[SAMPLE_WIDTH-1:0], adc_i_in[SAMPLE_WIDTH-1:0]}, "Output data is wrong");
|
||||
`ASSERT_ERROR(data_out_tvalid == 1, "output valid not asserted");
|
||||
end
|
||||
`TEST_CASE_DONE(1);
|
||||
// test data propagation when swapping data
|
||||
`TEST_CASE_START("test data propagation w/ swap_iq=1");
|
||||
swap_iq = 1;
|
||||
for (int i = 0; i < 10; i++) begin
|
||||
adc_q_in = rand_q.rand_bit();
|
||||
adc_i_in = rand_i.rand_bit();
|
||||
repeat (3) @(posedge clk);
|
||||
`ASSERT_ERROR(data_out_tdata[SAMPLE_WIDTH*2-1:0] == {adc_i_in[SAMPLE_WIDTH-1:0], adc_q_in[SAMPLE_WIDTH-1:0]}, "Output data is wrong");
|
||||
`ASSERT_ERROR(data_out_tvalid == 1, "output valid not asserted");
|
||||
end
|
||||
`TEST_CASE_DONE(1);
|
||||
// check that data valid does not propagate when block
|
||||
// is not enabled.
|
||||
`TEST_CASE_START("test data valid when enable = 0");
|
||||
enable = 0;
|
||||
repeat (10) @(posedge clk);
|
||||
`ASSERT_ERROR(data_out_tvalid == 0, "block should be disabled");
|
||||
`TEST_CASE_DONE(1);
|
||||
StopSim = 1;
|
||||
|
||||
end
|
||||
endmodule : tb_adc_iq_repacker
|
||||
Binary file not shown.
@@ -1,13 +1,13 @@
|
||||
--
|
||||
-- Copyright 2021 Ettus Research, a National Instruments Brand
|
||||
-- Copyright 2022 Ettus Research, a National Instruments Brand
|
||||
--
|
||||
-- SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
--
|
||||
-- Module: clock_gates
|
||||
-- Module: x440_clock_gates
|
||||
--
|
||||
-- Description:
|
||||
--
|
||||
-- Gate propagation of DataClk and RfdcClk instances until the PLL lock
|
||||
-- Gate propagation of RfdcClk instances until the PLL lock
|
||||
-- status signal is stable and software has acknowledged it by asserting the
|
||||
-- pertinent controls.
|
||||
--
|
||||
@@ -16,9 +16,10 @@
|
||||
-- explicitly instantiated in the Block Design. Therefore, we only generate
|
||||
-- the buffer enable signals for these clocks within this component.
|
||||
--
|
||||
-- Since DataClk are only used in other Custom IP blocks within the Block
|
||||
-- design, it is possible to instantiate the clock buffers within this block
|
||||
-- for without running into IP generation failures.
|
||||
-- This file heavily leverages the code from '../x410/x410_clock_gates.vhd'.
|
||||
-- The main changes when comparing against that file are:
|
||||
-- - One RFDC Clock pair per radio.
|
||||
-- - No DataClk buffer instantiations (since DataClk is removed from BD).
|
||||
--
|
||||
-- Parameters:
|
||||
--
|
||||
@@ -36,7 +37,7 @@ library WORK;
|
||||
use WORK.PkgRFDC_REGS_REGMAP.all;
|
||||
|
||||
|
||||
entity clock_gates is
|
||||
entity x440_clock_gates is
|
||||
generic (
|
||||
kReliableClkPeriodNs : integer := 25
|
||||
);
|
||||
@@ -51,18 +52,14 @@ entity clock_gates is
|
||||
|
||||
-- Input Clocks (from MMCM)
|
||||
ReliableClk : in std_logic;
|
||||
DataClk1xPll : in std_logic;
|
||||
DataClk2xPll : in std_logic;
|
||||
|
||||
-- Buffered Clock Outputs (to design)
|
||||
DataClk1x : out std_logic;
|
||||
DataClk2x : out std_logic;
|
||||
|
||||
-- Buffers for these signals must be instantiated on Block design for clock
|
||||
-- rates to be identified. The Utility Buffers instantiated on the Block
|
||||
-- Design require signals to be of type std_logic_vector.
|
||||
aEnableRfBufg1x : out std_logic_vector(0 downto 0);
|
||||
aEnableRfBufg2x : out std_logic_vector(0 downto 0);
|
||||
aEnableRf0Bufg1x : out std_logic_vector(0 downto 0);
|
||||
aEnableRf0Bufg2x : out std_logic_vector(0 downto 0);
|
||||
aEnableRf1Bufg1x : out std_logic_vector(0 downto 0);
|
||||
aEnableRf1Bufg2x : out std_logic_vector(0 downto 0);
|
||||
|
||||
-- PLL Status Signals
|
||||
rPllLocked : out std_logic;
|
||||
@@ -75,9 +72,9 @@ entity clock_gates is
|
||||
rSoftwareControl : in std_logic_vector(31 downto 0);
|
||||
rSoftwareStatus : out std_logic_vector(31 downto 0)
|
||||
);
|
||||
end clock_gates;
|
||||
end x440_clock_gates;
|
||||
|
||||
architecture STRUCT of clock_gates is
|
||||
architecture STRUCT of x440_clock_gates is
|
||||
|
||||
component sync_wrapper
|
||||
generic (
|
||||
@@ -92,15 +89,6 @@ architecture STRUCT of clock_gates is
|
||||
signal_out : out std_logic_vector((WIDTH-1) downto 0));
|
||||
end component;
|
||||
|
||||
component BUFGCE
|
||||
generic(
|
||||
CE_TYPE : string);
|
||||
port (
|
||||
O : out std_ulogic;
|
||||
CE : in std_ulogic;
|
||||
I : in std_ulogic);
|
||||
end component;
|
||||
|
||||
-- UltraScale MMCM max lock time = 100 us / 25 ns = 4,000 clk cycles. If the
|
||||
-- division kPllLockTimeNs / kReliableClkPeriodNs does not evaluate to an
|
||||
-- integer, Vivado could either round up or down. In case they round down, we
|
||||
@@ -126,15 +114,15 @@ architecture STRUCT of clock_gates is
|
||||
signal rPllUnlockedSticky : std_logic := '0';
|
||||
|
||||
-- Safe BUFG enable signals
|
||||
signal rEnableDataClk1x,
|
||||
rEnableDataClk2x,
|
||||
rEnableRfdcClk1x,
|
||||
rEnableRfdcClk2x : std_logic;
|
||||
signal rEnableRfdc0Clk1x,
|
||||
rEnableRfdc0Clk2x,
|
||||
rEnableRfdc1Clk1x,
|
||||
rEnableRfdc1Clk2x : std_logic;
|
||||
|
||||
signal rEnableDataBufg1x : std_logic := '0';
|
||||
signal rEnableDataBufg2x : std_logic := '0';
|
||||
signal rEnableRfdcBufg1xLcl : std_logic := '0';
|
||||
signal rEnableRfdcBufg2xLcl : std_logic := '0';
|
||||
signal rEnableRfdc0Bufg1xLcl : std_logic := '0';
|
||||
signal rEnableRfdc0Bufg2xLcl : std_logic := '0';
|
||||
signal rEnableRfdc1Bufg1xLcl : std_logic := '0';
|
||||
signal rEnableRfdc1Bufg2xLcl : std_logic := '0';
|
||||
|
||||
-- Active high version of reset required for synchronizer blocks.
|
||||
signal rPllReset : std_logic;
|
||||
@@ -143,18 +131,10 @@ architecture STRUCT of clock_gates is
|
||||
-- a dont_touch attribute to preserve the signals through both synthesis and
|
||||
-- P&R. Implementation of "dont_touch" has been confirmed after P&R.
|
||||
attribute dont_touch : string;
|
||||
attribute dont_touch of rEnableDataBufg1x : signal is "TRUE";
|
||||
attribute dont_touch of rEnableDataBufg2x : signal is "TRUE";
|
||||
attribute dont_touch of aEnableRfBufg1x : signal is "TRUE";
|
||||
attribute dont_touch of aEnableRfBufg2x : signal is "TRUE";
|
||||
|
||||
attribute X_INTERFACE_INFO : string;
|
||||
attribute X_INTERFACE_PARAMETER : string;
|
||||
|
||||
attribute X_INTERFACE_INFO of DataClk1xPll : signal is
|
||||
"xilinx.com:signal:clock:1.0 DataClk1xPll CLK";
|
||||
attribute X_INTERFACE_INFO of DataClk2xPll : signal is
|
||||
"xilinx.com:signal:clock:1.0 DataClk2xPll CLK";
|
||||
attribute dont_touch of aEnableRf0Bufg1x : signal is "TRUE";
|
||||
attribute dont_touch of aEnableRf0Bufg2x : signal is "TRUE";
|
||||
attribute dont_touch of aEnableRf1Bufg1x : signal is "TRUE";
|
||||
attribute dont_touch of aEnableRf1Bufg2x : signal is "TRUE";
|
||||
|
||||
begin
|
||||
|
||||
@@ -168,57 +148,38 @@ begin
|
||||
begin
|
||||
if rising_edge(ReliableClk) then
|
||||
if rPllReset_n = '0' then
|
||||
rEnableDataBufg1x <= '0';
|
||||
rEnableDataBufg2x <= '0';
|
||||
rEnableRfdcBufg1xLcl <= '0';
|
||||
rEnableRfdcBufg2xLcl <= '0';
|
||||
rEnableRfdc0Bufg1xLcl <= '0';
|
||||
rEnableRfdc0Bufg2xLcl <= '0';
|
||||
rEnableRfdc1Bufg1xLcl <= '0';
|
||||
rEnableRfdc1Bufg2xLcl <= '0';
|
||||
else
|
||||
rEnableDataBufg1x <=
|
||||
rEnableRfdc0Bufg1xLcl <=
|
||||
rSafeToEnableGatedClks and
|
||||
rEnableDataClk1x and
|
||||
rEnableRfdc0Clk1x and
|
||||
(not rPllUnlockedSticky);
|
||||
|
||||
rEnableDataBufg2x <=
|
||||
rEnableRfdc0Bufg2xLcl <=
|
||||
rSafeToEnableGatedClks and
|
||||
rEnableDataClk2x and
|
||||
rEnableRfdc0Clk2x and
|
||||
(not rPllUnlockedSticky);
|
||||
|
||||
rEnableRfdcBufg1xLcl <=
|
||||
rEnableRfdc1Bufg1xLcl <=
|
||||
rSafeToEnableGatedClks and
|
||||
rEnableRfdcClk1x and
|
||||
rEnableRfdc1Clk1x and
|
||||
(not rPllUnlockedSticky);
|
||||
|
||||
rEnableRfdcBufg2xLcl <=
|
||||
rEnableRfdc1Bufg2xLcl <=
|
||||
rSafeToEnableGatedClks and
|
||||
rEnableRfdcClk2x and
|
||||
rEnableRfdc1Clk2x and
|
||||
(not rPllUnlockedSticky);
|
||||
end if;
|
||||
end if;
|
||||
end process DataClkEnables;
|
||||
|
||||
aEnableRfBufg1x(0) <= rEnableRfdcBufg1xLcl;
|
||||
aEnableRfBufg2x(0) <= rEnableRfdcBufg2xLcl;
|
||||
|
||||
DataClk1xSafeBufg: BUFGCE
|
||||
generic map(
|
||||
CE_TYPE => "ASYNC"
|
||||
)
|
||||
port map (
|
||||
I => DataClk1xPll,
|
||||
CE => rEnableDataBufg1x,
|
||||
O => DataClk1x
|
||||
);
|
||||
|
||||
DataClk2xSafeBufg: BUFGCE
|
||||
generic map(
|
||||
CE_TYPE => "ASYNC"
|
||||
)
|
||||
port map (
|
||||
I => DataClk2xPll,
|
||||
CE => rEnableDataBufg2x,
|
||||
O => DataClk2x
|
||||
);
|
||||
|
||||
aEnableRf0Bufg1x(0) <= rEnableRfdc0Bufg1xLcl;
|
||||
aEnableRf0Bufg2x(0) <= rEnableRfdc0Bufg2xLcl;
|
||||
aEnableRf1Bufg1x(0) <= rEnableRfdc1Bufg1xLcl;
|
||||
aEnableRf1Bufg2x(0) <= rEnableRfdc1Bufg2xLcl;
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Create PLL Lock Signal
|
||||
@@ -288,11 +249,11 @@ begin
|
||||
rPllLocked <= rPllLockedLcl;
|
||||
|
||||
-- AXI transaction decoding
|
||||
rClearDataClkUnlockedSticky <= rSoftwareControl(kCLEAR_DATA_CLK_UNLOCKED);
|
||||
rEnableDataClk1x <= rSoftwareControl(kENABLE_DATA_CLK);
|
||||
rEnableDataClk2x <= rSoftwareControl(kENABLE_DATA_CLK_2X);
|
||||
rEnableRfdcClk1x <= rSoftwareControl(kENABLE_RF_CLK);
|
||||
rEnableRfdcClk2x <= rSoftwareControl(kENABLE_RF_CLK_2X);
|
||||
rClearDataClkUnlockedSticky <= rSoftwareControl(kCLEAR_DATA_CLK_UNLOCKED);
|
||||
rEnableRfdc0Clk1x <= rSoftwareControl(kENABLE_RF0_CLK);
|
||||
rEnableRfdc0Clk2x <= rSoftwareControl(kENABLE_RF0_CLK_2X);
|
||||
rEnableRfdc1Clk1x <= rSoftwareControl(kENABLE_RF1_CLK);
|
||||
rEnableRfdc1Clk2x <= rSoftwareControl(kENABLE_RF1_CLK_2X);
|
||||
|
||||
rSoftwareStatus(kDATA_CLK_PLL_LOCKED) <= rPllLockedLcl;
|
||||
rSoftwareStatus(kDATA_CLK_PLL_UNLOCKED_STICKY) <= rPllUnlockedSticky;
|
||||
+51
-70
@@ -1,13 +1,18 @@
|
||||
--
|
||||
-- Copyright 2021 Ettus Research, a National Instruments Brand
|
||||
-- Copyright 2022 Ettus Research, a National Instruments Brand
|
||||
--
|
||||
-- SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
--
|
||||
-- Module: rf_reset_controller
|
||||
-- Module: x440_rf_reset_controller
|
||||
--
|
||||
-- Description:
|
||||
--
|
||||
-- Control RFDC, ADC, and DAC resets.
|
||||
-- This file contains a similar structure to '../x410/x410_rf_reset_controller',
|
||||
-- with the main difference of not having to support a complex reset chain.
|
||||
-- This means that the instantiations of 'rf_reset' can be taken out in favor
|
||||
-- having a simple combination of the incoming pulses and the software triggers
|
||||
-- to generate the different outputs.
|
||||
--
|
||||
|
||||
library IEEE;
|
||||
@@ -17,45 +22,38 @@ library IEEE;
|
||||
library WORK;
|
||||
use WORK.PkgRFDC_REGS_REGMAP.all;
|
||||
|
||||
entity rf_reset_controller is
|
||||
entity x440_rf_reset_controller is
|
||||
port(
|
||||
-- Clocks
|
||||
-- Config clock is async to all the others.
|
||||
ConfigClk : in std_logic;
|
||||
DataClk : in std_logic;
|
||||
PllRefClk : in std_logic;
|
||||
RfClk : in std_logic;
|
||||
RfClk2x : in std_logic;
|
||||
DataClk2x : in std_logic;
|
||||
|
||||
-- Master resets from the Radio
|
||||
dAdcResetPulse : in std_logic;
|
||||
dDacResetPulse : in std_logic;
|
||||
rAdcResetPulse : in std_logic;
|
||||
rDacResetPulse : in std_logic;
|
||||
|
||||
-- ADC Resets
|
||||
dAdcDataOutReset_n : out std_logic;
|
||||
r2AdcFirReset_n : out std_logic;
|
||||
rAdcRfdcAxiReset_n : out std_logic;
|
||||
r2AdcReset_n : out std_logic;
|
||||
rAdcEnableData : out std_logic;
|
||||
rAdcGearboxReset_n : out std_logic;
|
||||
rAdcReset_n : out std_logic;
|
||||
|
||||
-- DAC Resets
|
||||
dDacDataInReset_n : out std_logic;
|
||||
r2DacFirReset_n : out std_logic;
|
||||
d2DacFirReset_n : out std_logic;
|
||||
rDacRfdcAxiReset_n : out std_logic;
|
||||
rDacGearboxReset_n : out std_logic;
|
||||
r2DacReset_n : out std_logic;
|
||||
rDacReset_n : out std_logic;
|
||||
|
||||
-- SW Control and Status
|
||||
-- Control to initiate resets to RFDC and decimation block including the
|
||||
-- gearboxes. The reset status is a sticky status of both ADC and DAC.
|
||||
-- Control to initiate resets to RFDC.
|
||||
-- The reset status is a sticky status of both ADC and DAC.
|
||||
cSoftwareControl : in std_logic_vector(31 downto 0);
|
||||
cSoftwareStatus : out std_logic_vector(31 downto 0)
|
||||
);
|
||||
end rf_reset_controller;
|
||||
end x440_rf_reset_controller;
|
||||
|
||||
|
||||
architecture RTL of rf_reset_controller is
|
||||
architecture RTL of x440_rf_reset_controller is
|
||||
|
||||
-- POR value for all resets are high.
|
||||
signal cTriggerAdcReset : std_logic := '1';
|
||||
@@ -63,10 +61,10 @@ architecture RTL of rf_reset_controller is
|
||||
signal cTriggerDacReset : std_logic := '1';
|
||||
signal cTriggerDacResetDlyd : std_logic := '1';
|
||||
|
||||
signal dTriggerAdcReset_ms : std_logic := '1';
|
||||
signal dTriggerAdcReset : std_logic := '1';
|
||||
signal dTriggerDacReset_ms : std_logic := '1';
|
||||
signal dTriggerDacReset : std_logic := '1';
|
||||
signal rTriggerAdcReset_ms : std_logic := '1';
|
||||
signal rTriggerAdcReset : std_logic := '1';
|
||||
signal rTriggerDacReset_ms : std_logic := '1';
|
||||
signal rTriggerDacReset : std_logic := '1';
|
||||
|
||||
-- POR value of all reset done signals are set to low.
|
||||
signal cTriggerAdcResetDone_ms : std_logic := '0';
|
||||
@@ -77,12 +75,12 @@ architecture RTL of rf_reset_controller is
|
||||
signal cDacResetDoneSticky : std_logic := '0';
|
||||
|
||||
attribute ASYNC_REG : string;
|
||||
attribute ASYNC_REG of dTriggerAdcReset : signal is "TRUE";
|
||||
attribute ASYNC_REG of dTriggerDacReset : signal is "TRUE";
|
||||
attribute ASYNC_REG of rTriggerAdcReset : signal is "TRUE";
|
||||
attribute ASYNC_REG of rTriggerDacReset : signal is "TRUE";
|
||||
attribute ASYNC_REG of cTriggerAdcResetDone : signal is "TRUE";
|
||||
attribute ASYNC_REG of cTriggerDacResetDone : signal is "TRUE";
|
||||
attribute ASYNC_REG of dTriggerAdcReset_ms : signal is "TRUE";
|
||||
attribute ASYNC_REG of dTriggerDacReset_ms : signal is "TRUE";
|
||||
attribute ASYNC_REG of rTriggerAdcReset_ms : signal is "TRUE";
|
||||
attribute ASYNC_REG of rTriggerDacReset_ms : signal is "TRUE";
|
||||
attribute ASYNC_REG of cTriggerAdcResetDone_ms : signal is "TRUE";
|
||||
attribute ASYNC_REG of cTriggerDacResetDone_ms : signal is "TRUE";
|
||||
|
||||
@@ -108,14 +106,14 @@ begin
|
||||
-- prove all your clocks are toggling to some extent.
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
SeqResetDataClk : process(DataClk)
|
||||
SeqResetRfClk : process(RfClk)
|
||||
begin
|
||||
if rising_edge(DataClk) then
|
||||
if rising_edge(RfClk) then
|
||||
-- double-syncs have no sync reset!
|
||||
dTriggerAdcReset_ms <= cTriggerAdcReset;
|
||||
dTriggerAdcReset <= dTriggerAdcReset_ms;
|
||||
dTriggerDacReset_ms <= cTriggerDacReset;
|
||||
dTriggerDacReset <= dTriggerDacReset_ms;
|
||||
rTriggerAdcReset_ms <= cTriggerAdcReset;
|
||||
rTriggerAdcReset <= rTriggerAdcReset_ms;
|
||||
rTriggerDacReset_ms <= cTriggerDacReset;
|
||||
rTriggerDacReset <= rTriggerDacReset_ms;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
@@ -123,18 +121,18 @@ begin
|
||||
-- Reset Sequence Done Status
|
||||
-----------------------------------------------------------------------------
|
||||
-- Now back to ConfigClk! We provide the status for all software controlled
|
||||
-- resets. We move the signal from ConfigClk to DataClk domain and move it
|
||||
-- back to ConfigClk domain. This just proves that DataClk is toggling and
|
||||
-- the reset requested by software is sampled in the DataClk.
|
||||
-- resets. We move the signal from ConfigClk to RfClk domain and move it
|
||||
-- back to ConfigClk domain. This just proves that RfClk is toggling and
|
||||
-- the reset requested by software is sampled in the RfClk.
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
SeqResetDone : process(ConfigClk)
|
||||
begin
|
||||
if rising_edge(ConfigClk) then
|
||||
-- double-syncs have no sync reset!
|
||||
cTriggerAdcResetDone_ms <= dTriggerAdcReset;
|
||||
cTriggerAdcResetDone_ms <= rTriggerAdcReset;
|
||||
cTriggerAdcResetDone <= cTriggerAdcResetDone_ms;
|
||||
cTriggerDacResetDone_ms <= dTriggerDacReset;
|
||||
cTriggerDacResetDone_ms <= rTriggerDacReset;
|
||||
cTriggerDacResetDone <= cTriggerDacResetDone_ms;
|
||||
end if;
|
||||
end process;
|
||||
@@ -172,37 +170,20 @@ begin
|
||||
-----------------------------------------------------------------------------
|
||||
-- rf_reset Instances
|
||||
-----------------------------------------------------------------------------
|
||||
RfClkResets: process(RfClk)
|
||||
begin
|
||||
if rising_edge(RfClk) then
|
||||
rAdcReset_n <= not (rAdcResetPulse or rTriggerAdcReset);
|
||||
rDacReset_n <= not (rDacResetPulse or rTriggerDacReset);
|
||||
end if;
|
||||
end process RfClkResets;
|
||||
|
||||
AdcResets: entity work.rf_reset (RTL)
|
||||
port map (
|
||||
DataClk => DataClk,
|
||||
PllRefClk => PllRefClk,
|
||||
RfClk => RfClk,
|
||||
RfClk2x => RfClk2x,
|
||||
DataClk2x => DataClk2x,
|
||||
dTimedReset => dAdcResetPulse,
|
||||
dSwReset => dTriggerAdcReset,
|
||||
dReset_n => dAdcDataOutReset_n,
|
||||
d2Reset_n => open,
|
||||
r2Reset_n => r2AdcFirReset_n,
|
||||
rAxiReset_n => rAdcRfdcAxiReset_n,
|
||||
rReset_n => rAdcGearboxReset_n
|
||||
);
|
||||
|
||||
DacResets: entity work.rf_reset (RTL)
|
||||
port map (
|
||||
DataClk => DataClk,
|
||||
PllRefClk => PllRefClk,
|
||||
RfClk => RfClk,
|
||||
RfClk2x => RfClk2x,
|
||||
DataClk2x => DataClk2x,
|
||||
dTimedReset => dDacResetPulse,
|
||||
dSwReset => dTriggerDacReset,
|
||||
dReset_n => dDacDataInReset_n,
|
||||
d2Reset_n => d2DacFirReset_n,
|
||||
r2Reset_n => r2DacFirReset_n,
|
||||
rAxiReset_n => rDacRfdcAxiReset_n,
|
||||
rReset_n => rDacGearboxReset_n
|
||||
);
|
||||
RfClk2xResets: process(RfClk2x)
|
||||
begin
|
||||
if rising_edge(RfClk2x) then
|
||||
r2AdcReset_n <= not (rAdcResetPulse or rTriggerAdcReset);
|
||||
r2DacReset_n <= not (rDacResetPulse or rTriggerDacReset);
|
||||
end if;
|
||||
end process RfClk2xResets;
|
||||
|
||||
end RTL;
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// Copyright 2022 Ettus Research, A National Instruments Brand
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: x440_rfdc_tx_control_remap.v
|
||||
// Description:
|
||||
// Allows for remapping control signals to the correct tile on X440.
|
||||
// This file targets the DAC tiles specifically
|
||||
//
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module x440_rfdc_tx_control_remap (
|
||||
// Input control (Front-Panel ordering)
|
||||
input wire [7:0] input_controls,
|
||||
// output_control (DAC Tile ordering)
|
||||
output wire [7:0] output_controls
|
||||
);
|
||||
|
||||
`include "../../regmap/x440/rfdc_mapping_regmap_utils.vh"
|
||||
|
||||
// Decode TX Channel mapping
|
||||
assign output_controls[CH0_TX_MAPPING] = input_controls[0];
|
||||
assign output_controls[CH1_TX_MAPPING] = input_controls[1];
|
||||
assign output_controls[CH2_TX_MAPPING] = input_controls[2];
|
||||
assign output_controls[CH3_TX_MAPPING] = input_controls[3];
|
||||
assign output_controls[CH4_TX_MAPPING] = input_controls[4];
|
||||
assign output_controls[CH5_TX_MAPPING] = input_controls[5];
|
||||
assign output_controls[CH6_TX_MAPPING] = input_controls[6];
|
||||
assign output_controls[CH7_TX_MAPPING] = input_controls[7];
|
||||
|
||||
endmodule
|
||||
|
||||
`default_nettype wire
|
||||
Reference in New Issue
Block a user