aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/top/x400/rf/sim
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/top/x400/rf/sim')
-rw-r--r--fpga/usrp3/top/x400/rf/sim/Makefile91
-rw-r--r--fpga/usrp3/top/x400/rf/sim/rf_all_tb.sv57
-rw-r--r--fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_2x1.vhd186
-rw-r--r--fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_2x4.vhd197
-rw-r--r--fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_8x4.vhd206
-rw-r--r--fpga/usrp3/top/x400/rf/sim/tb_capture_sysref.vhd119
-rw-r--r--fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_12x8.vhd197
-rw-r--r--fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_4x2.vhd168
-rw-r--r--fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_6x12.vhd187
-rw-r--r--fpga/usrp3/top/x400/rf/sim/tb_ddc_400m_saturate.vhd125
-rw-r--r--fpga/usrp3/top/x400/rf/sim/tb_duc_400m_saturate.vhd133
-rw-r--r--fpga/usrp3/top/x400/rf/sim/tb_rf_nco_reset.vhd281
-rw-r--r--fpga/usrp3/top/x400/rf/sim/tb_rf_reset_controller.vhd436
13 files changed, 2383 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x400/rf/sim/Makefile b/fpga/usrp3/top/x400/rf/sim/Makefile
new file mode 100644
index 000000000..08b62f4fb
--- /dev/null
+++ b/fpga/usrp3/top/x400/rf/sim/Makefile
@@ -0,0 +1,91 @@
+#
+# Copyright 2021 Ettus Research, a National Instruments Brand
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+
+#-------------------------------------------------
+# Top-of-Makefile
+#-------------------------------------------------
+# Define BASE_DIR to point to the "top" dir. Note:
+# UHD_FPGA_DIR must be passed into this Makefile.
+BASE_DIR = ../../..
+# Include viv_sim_preample after defining BASE_DIR
+include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak
+
+#-------------------------------------------------
+# Design Specific
+#-------------------------------------------------
+# Define part using PART_ID (<device>/<package>/<speedgrade>)
+ARCH = zynquplusRFSOC
+PART_ID = xczu28dr/ffvg1517/-1/e
+
+# Include makefiles and sources for the DUT and its dependencies
+include $(BASE_DIR)/../lib/fifo/Makefile.srcs
+include $(BASE_DIR)/../lib/axi/Makefile.srcs
+include $(BASE_DIR)/../lib/control/Makefile.srcs
+
+DESIGN_SRCS += $(abspath \
+$(FIFO_SRCS) \
+$(AXI_SRCS) \
+$(CONTROL_LIB_SRCS) \
+)
+
+include ../common/Makefile.srcs
+include ../100m/Makefile.srcs
+include ../200m/Makefile.srcs
+include ../400m/Makefile.srcs
+
+DESIGN_SRCS += $(abspath \
+../../regmap/PkgRFDC_REGS_REGMAP.vhd \
+$(RF_COMMON_SRCS) \
+$(RF_100M_SRCS) \
+$(RF_200M_SRCS) \
+$(RF_400M_SRCS) \
+)
+
+#-------------------------------------------------
+# IP Specific
+#-------------------------------------------------
+# If simulation contains IP, define the IP_DIR and point
+# it to the base level IP directory
+IP_DIR = $(BASE_DIR)/x400/ip
+LIB_IP_DIR = $(BASE_DIR)/../lib/ip
+
+# Include makefiles and sources for all IP components
+# *after* defining the IP_DIR
+#
+# These TBs don't use any IP yet :)
+
+#-------------------------------------------------
+# Testbench Specific
+#-------------------------------------------------
+include $(BASE_DIR)/../sim/general/Makefile.srcs
+
+# Define only one top-level module
+SIM_TOP = rf_all_tb
+
+# Simulation runtime in microseconds
+SIM_RUNTIME_US = 1000
+
+SIM_SRCS = \
+$(abspath tb_adc_gearbox_2x1.vhd ) \
+$(abspath tb_adc_gearbox_2x4.vhd ) \
+$(abspath tb_adc_gearbox_8x4.vhd ) \
+$(abspath tb_capture_sysref.vhd ) \
+$(abspath tb_dac_gearbox_12x8.vhd ) \
+$(abspath tb_dac_gearbox_4x2.vhd ) \
+$(abspath tb_dac_gearbox_6x12.vhd ) \
+$(abspath tb_ddc_400m_saturate.vhd ) \
+$(abspath tb_duc_400m_saturate.vhd ) \
+$(abspath tb_rf_nco_reset.vhd ) \
+$(abspath tb_rf_reset_controller.vhd) \
+$(abspath rf_all_tb.sv ) \
+
+#-------------------------------------------------
+# Bottom-of-Makefile
+#-------------------------------------------------
+# Include all simulator specific makefiles here
+# Each should define a unique target to simulate
+# e.g. xsim, vsim, etc and a common "clean" target
+include $(BASE_DIR)/../tools/make/viv_simulator.mak
diff --git a/fpga/usrp3/top/x400/rf/sim/rf_all_tb.sv b/fpga/usrp3/top/x400/rf/sim/rf_all_tb.sv
new file mode 100644
index 000000000..c64bcf923
--- /dev/null
+++ b/fpga/usrp3/top/x400/rf/sim/rf_all_tb.sv
@@ -0,0 +1,57 @@
+//
+// Copyright 2021 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: rf_all_tb
+//
+// Description:
+//
+// Top-level testbench for X400 RF components. This instantiates all the RF
+// testbenches.
+//
+
+module rf_all_tb;
+ `include "test_exec.svh"
+ import PkgTestExec::*;
+
+ tb_adc_gearbox_2x1 tb_adc_gearbox_2x1_i ();
+ tb_adc_gearbox_2x4 tb_adc_gearbox_2x4_i ();
+ tb_adc_gearbox_8x4 tb_adc_gearbox_8x4_i ();
+ tb_capture_sysref tb_capture_sysref_i ();
+ tb_dac_gearbox_12x8 tb_dac_gearbox_12x8_i ();
+ tb_dac_gearbox_4x2 tb_dac_gearbox_4x2_i ();
+ tb_dac_gearbox_6x12 tb_dac_gearbox_6x12_i ();
+ tb_ddc_400m_saturate tb_ddc_400m_saturate_i ();
+ tb_duc_400m_saturate tb_duc_400m_saturate_i ();
+ tb_rf_nco_reset tb_rf_nco_reset_i ();
+ tb_rf_reset_controller tb_rf_reset_controller_i ();
+
+ initial begin
+ test.start_tb("rf_all_tb", 1ms);
+
+ test.start_test("Run RF TBs");
+ forever begin
+ #100ns;
+ if (
+ tb_adc_gearbox_2x1_i.StopSim &&
+ tb_adc_gearbox_2x4_i.StopSim &&
+ tb_adc_gearbox_8x4_i.StopSim &&
+ tb_capture_sysref_i.StopSim &&
+ tb_dac_gearbox_12x8_i.StopSim &&
+ tb_dac_gearbox_4x2_i.StopSim &&
+ tb_dac_gearbox_6x12_i.StopSim &&
+ tb_ddc_400m_saturate_i.StopSim &&
+ tb_duc_400m_saturate_i.StopSim &&
+ tb_rf_nco_reset_i.StopSim &&
+ tb_rf_reset_controller_i.StopSim
+ ) break;
+ end
+ test.end_test();
+
+ // If they all stop before the timeout, and there are no errors, then we
+ // assume everything passed.
+ test.end_tb();
+ end
+
+endmodule : rf_all_tb
diff --git a/fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_2x1.vhd b/fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_2x1.vhd
new file mode 100644
index 000000000..f5c58ccf5
--- /dev/null
+++ b/fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_2x1.vhd
@@ -0,0 +1,186 @@
+--
+-- Copyright 2021 Ettus Research, a National Instruments Brand
+--
+-- SPDX-License-Identifier: LGPL-3.0-or-later
+--
+-- Module: tb_adc_gearbox_2x1
+--
+-- Description:
+--
+-- Self-checking testbench for adc_gearbox_2x1.
+--
+
+library IEEE;
+ use IEEE.std_logic_1164.all;
+ use IEEE.numeric_std.all;
+
+entity tb_adc_gearbox_2x1 is
+end tb_adc_gearbox_2x1;
+
+
+architecture RTL of tb_adc_gearbox_2x1 is
+
+ component adc_gearbox_2x1
+ port (
+ clk1x : in std_logic;
+ reset_n_1x : in std_logic;
+ adc_q_in_1x : in std_logic_vector(31 downto 0);
+ adc_i_in_1x : in std_logic_vector(31 downto 0);
+ valid_in_1x : in std_logic;
+ enable_1x : in std_logic;
+ clk2x : in std_logic;
+ swap_iq_2x : in std_logic;
+ adc_out_2x : out std_logic_vector(31 downto 0);
+ valid_out_2x : out std_logic);
+ end component;
+
+ signal cDataCheckNxtLo, cDataCheckLo : std_logic_vector(31 downto 0);
+ signal cDataCheckNxtHi, cDataCheckHi1, cDataCheckHi2 : std_logic_vector(31 downto 0);
+
+ signal adc_i_in_1x : std_logic_vector(31 downto 0);
+ signal adc_out_2x : std_logic_vector(31 downto 0);
+ signal adc_q_in_1x : std_logic_vector(31 downto 0);
+ signal enable_1x : std_logic;
+ signal reset_n_1x : std_logic;
+ signal swap_iq_2x : std_logic;
+ signal valid_in_1x : std_logic;
+ signal valid_out_2x : std_logic;
+
+ signal StopSim : boolean;
+ constant kPer : time := 10 ns;
+
+ signal Clk : std_logic := '1';
+ signal Clk2x : std_logic := '1';
+
+ procedure ClkWait(X : positive := 1) is
+ begin
+ for i in 1 to X loop
+ wait until rising_edge(Clk);
+ end loop;
+ end procedure ClkWait;
+
+begin
+
+ Clk <= not Clk after kPer/2 when not StopSim else '0';
+ Clk2x <= not Clk2x after kPer/4 when not StopSim else '0';
+
+ dut: adc_gearbox_2x1
+ port map (
+ clk1x => Clk,
+ reset_n_1x => reset_n_1x,
+ adc_q_in_1x => adc_q_in_1x,
+ adc_i_in_1x => adc_i_in_1x,
+ valid_in_1x => valid_in_1x,
+ enable_1x => enable_1x,
+ clk2x => Clk2x,
+ swap_iq_2x => swap_iq_2x,
+ adc_out_2x => adc_out_2x,
+ valid_out_2x => valid_out_2x
+ );
+
+ main: process
+ begin
+ swap_iq_2x <= '0';
+ valid_in_1x <= '0';
+ enable_1x <= '0';
+ reset_n_1x <= '0';
+ ClkWait(5);
+ reset_n_1x <= '1';
+ ClkWait(5);
+
+ -- Ensure the outputs are quiet.
+ ClkWait(20);
+ assert valid_out_2x'stable(kPer*20) and valid_out_2x = '0'
+ report "valid not stable at de-asserted at startup"
+ severity error;
+ assert adc_out_2x'stable(kPer*20) and (adc_out_2x = x"00000000")
+ report "data not stable at zero at startup"
+ severity error;
+
+ -- Valid asserted, Enable asserted, Enable de-asserted, Valid de-asserted.
+
+ ClkWait(10);
+ valid_in_1x <= '1';
+ ClkWait(10);
+ enable_1x <= '1';
+
+ ClkWait(110);
+ assert valid_out_2x'stable(kPer*100) and valid_out_2x = '1'
+ report "valid not stable at asserted"
+ severity error;
+
+ ClkWait(10);
+ enable_1x <= '0';
+ ClkWait(10);
+ valid_in_1x <= '0';
+
+ ClkWait(110);
+ assert valid_out_2x'stable(kPer*100) and valid_out_2x = '0'
+ report "valid not stable at de-asserted"
+ severity error;
+
+ -- Enable asserted, Valid asserted, Enable de-asserted, Valid de-asserted.
+
+ ClkWait(10);
+ enable_1x <= '1';
+ ClkWait(10);
+ valid_in_1x <= '1';
+
+ ClkWait(110);
+ assert valid_out_2x'stable(kPer*100) and valid_out_2x = '1'
+ report "valid not stable at asserted"
+ severity error;
+
+ ClkWait(10);
+ enable_1x <= '0';
+ ClkWait(10);
+ valid_in_1x <= '0';
+
+ ClkWait(110);
+ assert valid_out_2x'stable(kPer*100) and valid_out_2x = '0'
+ report "valid not stable at de-asserted"
+ severity error;
+
+ StopSim <= true;
+ wait;
+ end process;
+
+
+ driver: process(Clk)
+ variable tempQdata : integer := 1;
+ variable tempIdata : integer := 128;
+ begin
+ if rising_edge(Clk) then
+ adc_q_in_1x <= std_logic_vector(to_unsigned(tempQdata+1,16)) & std_logic_vector(to_unsigned(tempQdata, 16));
+ adc_i_in_1x <= std_logic_vector(to_unsigned(tempIdata+1,16)) & std_logic_vector(to_unsigned(tempIdata, 16));
+ cDataCheckNxtLo <= std_logic_vector(to_unsigned(tempQdata,16)) & std_logic_vector(to_unsigned(tempIdata, 16));
+ cDataCheckNxtHi <= std_logic_vector(to_unsigned(tempQdata+1,16)) & std_logic_vector(to_unsigned(tempIdata+1,16));
+ tempQdata := tempQdata+2;
+ tempIdata := tempIdata+2;
+ end if;
+ end process;
+
+
+ checker: process(Clk2x)
+ variable tempout : integer := 1;
+ variable ExpectedData : std_logic_vector(31 downto 0) := (others => '0');
+ begin
+ if falling_edge(Clk2x) then
+ if Clk = '1' then
+ ExpectedData := cDataCheckLo;
+ else
+ ExpectedData := cDataCheckHi2;
+ end if;
+ if valid_out_2x = '1' then
+ assert adc_out_2x = ExpectedData
+ report "ADC data out mismatch from expected"
+ severity error;
+ tempout := tempout +1;
+ end if;
+ cDataCheckLo <= cDataCheckNxtLo;
+ cDataCheckHi1 <= cDataCheckNxtHi;
+ cDataCheckHi2 <= cDataCheckHi1;
+ end if;
+ end process;
+
+end RTL;
diff --git a/fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_2x4.vhd b/fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_2x4.vhd
new file mode 100644
index 000000000..b36f7de54
--- /dev/null
+++ b/fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_2x4.vhd
@@ -0,0 +1,197 @@
+--
+-- Copyright 2021 Ettus Research, a National Instruments Brand
+--
+-- SPDX-License-Identifier: LGPL-3.0-or-later
+--
+-- Module: tb_adc_gearbox_2x4
+--
+-- Description:
+--
+-- Self-checking testbench for the gearbox that expands the data width from 2
+-- SPC to 4 SPC.
+--
+
+library IEEE;
+ use IEEE.std_logic_1164.all;
+ use IEEE.numeric_std.all;
+
+entity tb_adc_gearbox_2x4 is
+end tb_adc_gearbox_2x4;
+
+
+architecture RTL of tb_adc_gearbox_2x4 is
+
+ component adc_gearbox_2x4
+ port (
+ Clk1x : in std_logic;
+ Clk3x : in std_logic;
+ ac1Reset_n : in std_logic;
+ ac3Reset_n : in std_logic;
+ c3DataIn : in std_logic_vector(95 downto 0);
+ c3DataValidIn : in std_logic;
+ c1DataOut : out std_logic_vector(191 downto 0);
+ c1DataValidOut : out std_logic);
+ end component;
+
+ signal aTestReset : boolean;
+
+ signal ac1Reset_n : std_logic := '1';
+ signal ac3Reset_n : std_logic := '1';
+ signal c3DataIn : std_logic_vector( 95 downto 0) := (others => '0');
+ signal c3DataValidIn : std_logic := '0';
+ signal c1ExpectedData : std_logic_vector(191 downto 0) := (others => '0');
+ signal c1DataOut : std_logic_vector(191 downto 0) := (others => '0');
+ signal c1DataValidOut : std_logic;
+
+ signal StopSim : boolean;
+ constant kPer : time := 12 ns;
+
+ signal Clk1x : std_logic := '1';
+ signal Clk3x : std_logic := '1';
+
+ procedure Clk3xWait(X : positive := 1) is
+ begin
+ for i in 1 to X loop
+ wait until rising_edge(Clk3x);
+ end loop;
+ end procedure Clk3xWait;
+
+ procedure Clk1xWait(X : positive := 1) is
+ begin
+ for i in 1 to X loop
+ wait until rising_edge(Clk1x);
+ end loop;
+ end procedure Clk1xWait;
+
+begin
+
+ Clk1x <= not Clk1x after kPer/2 when not StopSim else '0';
+ Clk3x <= not Clk3x after kPer/6 when not StopSim else '0';
+
+ dut: adc_gearbox_2x4
+ port map (
+ Clk1x => Clk1x,
+ Clk3x => Clk3x,
+ ac1Reset_n => ac1Reset_n,
+ ac3Reset_n => ac3Reset_n,
+ c3DataIn => c3DataIn,
+ c3DataValidIn => c3DataValidIn,
+ c1DataOut => c1DataOut,
+ c1DataValidOut => c1DataValidOut
+ );
+
+ main: process
+ procedure PhaseTest(WaitCycles : positive := 1) is
+ begin
+ -- Stop data generation by asserting this reset.
+ aTestReset <= true;
+ Clk1xWait;
+ ac1Reset_n <= '0';
+ ac3Reset_n <= '0';
+ Clk1xWait;
+ ac1Reset_n <= '1';
+ ac3Reset_n <= '1';
+
+ -- This wait is in Clk3x domain. This is used to change phase in which
+ -- data valid is asserted with respect to Clk3x and Clk1x rising edge.
+ -- Wait an additional 12 Clk3x cycles for the output data valid to be
+ -- de-asserted.
+ Clk3xWait(WaitCycles+12);
+
+ -- De-asserting test reset will start data generation.
+ aTestReset <= false;
+
+ -- Wait for a random time before we stop the test.
+ Clk3xWait(1000);
+ end procedure;
+
+ begin
+ -- Change phase between Clk1x and Clk3x. See details in the DUT.
+ -- The wait in each phase test is used to move the de-assertion of data
+ -- generation logic reset. By doing this, we can change data valid
+ -- assertion phase between Clk3x and Clk1x.
+ -- p0.
+ PhaseTest(1);
+
+ -- p1
+ PhaseTest(2);
+
+ -- p2.
+ PhaseTest(6);
+
+ -- Stop simulation
+ StopSim <= true;
+ wait;
+ end process;
+
+ -- Process to generate data to the DUT.
+ driver: process(Clk3x, aTestReset)
+ variable tempQdata : integer := 1;
+ variable tempIdata : integer := 128;
+ variable dataCount : integer := 0;
+ begin
+ if aTestReset then
+ tempQdata := 1;
+ tempIdata := 128;
+ dataCount := 0;
+ c3DataIn <= (others => '0');
+ c3DataValidIn <= '0';
+ elsif rising_edge(Clk3x) then
+
+ if dataCount < 2 then
+ c3DataIn <= "0000000" & std_logic_vector(to_unsigned(tempQdata+1,17)) &
+ "0000000" & std_logic_vector(to_unsigned(tempIdata+1,17)) &
+ "0000000" & std_logic_vector(to_unsigned(tempQdata+0,17)) &
+ "0000000" & std_logic_vector(to_unsigned(tempIdata+0,17));
+ dataCount := dataCount + 1;
+ c3DataValidIn <= '1';
+ tempQdata := tempQdata +2;
+ tempIdata := tempIdata +2;
+ elsif dataCount = 2 then
+ c3DataIn <= (others => '0');
+ dataCount := 0;
+ c3DataValidIn <= '0';
+ end if;
+
+ end if;
+ end process;
+
+ -- Process to generate expected data that is used to verify the DUT output.
+ expected_data: process(Clk1x)
+ variable tempQdata : integer := 1;
+ variable tempIdata : integer := 128;
+ begin
+ if rising_edge(Clk1x) then
+
+ if aTestReset and c1DataValidOut = '0' then
+ tempQdata := 1;
+ tempIdata := 128;
+ elsif c1DataValidOut = '1' then
+ tempQdata := tempQdata+4;
+ tempIdata := tempIdata+4;
+ end if;
+ c1ExpectedData <= "0000000" & std_logic_vector(to_unsigned(tempQdata+3,17)) &
+ "0000000" & std_logic_vector(to_unsigned(tempIdata+3,17)) &
+ "0000000" & std_logic_vector(to_unsigned(tempQdata+2,17)) &
+ "0000000" & std_logic_vector(to_unsigned(tempIdata+2,17)) &
+ "0000000" & std_logic_vector(to_unsigned(tempQdata+1,17)) &
+ "0000000" & std_logic_vector(to_unsigned(tempIdata+1,17)) &
+ "0000000" & std_logic_vector(to_unsigned(tempQdata+0,17)) &
+ "0000000" & std_logic_vector(to_unsigned(tempIdata+0,17));
+
+ end if;
+ end process;
+
+ -- Process to continuously check output data from the DUT.
+ checker: process(Clk1x)
+ begin
+ if falling_edge(Clk1x) then
+ if c1DataValidOut = '1' then
+ assert c1DataOut = c1ExpectedData
+ report "ADC data out mismatch from expected"
+ severity error;
+ end if;
+ end if;
+ end process;
+
+end RTL;
diff --git a/fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_8x4.vhd b/fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_8x4.vhd
new file mode 100644
index 000000000..88e520a6b
--- /dev/null
+++ b/fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_8x4.vhd
@@ -0,0 +1,206 @@
+--
+-- Copyright 2021 Ettus Research, a National Instruments Brand
+--
+-- SPDX-License-Identifier: LGPL-3.0-or-later
+--
+-- Module: tb_adc_gearbox_8x4
+--
+-- Description:
+--
+-- Self-checking testbench for adc_gearbox_8x4.
+--
+
+library IEEE;
+ use IEEE.std_logic_1164.all;
+ use IEEE.numeric_std.all;
+
+entity tb_adc_gearbox_8x4 is
+end tb_adc_gearbox_8x4;
+
+
+architecture RTL of tb_adc_gearbox_8x4 is
+
+ component adc_gearbox_8x4
+ port (
+ clk1x : in std_logic;
+ reset_n_1x : in std_logic;
+ adc_q_in_1x : in std_logic_vector(127 downto 0);
+ adc_i_in_1x : in std_logic_vector(127 downto 0);
+ valid_in_1x : in std_logic;
+ enable_1x : in std_logic;
+ clk2x : in std_logic;
+ swap_iq_2x : in std_logic;
+ adc_out_2x : out std_logic_vector(127 downto 0);
+ valid_out_2x : out std_logic);
+ end component;
+
+ signal cDataCheckNxtLo, cDataCheckLo: std_logic_vector(127 downto 0);
+ signal cDataCheckNxtHi : std_logic_vector(127 downto 0);
+ signal cDataCheckHi1, cDataCheckHi2: std_logic_vector(127 downto 0);
+
+ signal adc_i_in_1x : std_logic_vector(127 downto 0);
+ signal adc_out_2x : std_logic_vector(127 downto 0);
+ signal adc_q_in_1x : std_logic_vector(127 downto 0);
+ signal enable_1x : std_logic;
+ signal reset_n_1x : std_logic;
+ signal swap_iq_2x : std_logic;
+ signal valid_in_1x : std_logic;
+ signal valid_out_2x : std_logic;
+
+ signal StopSim : boolean;
+ constant kPer : time := 10 ns;
+
+ signal Clk : std_logic := '1';
+ signal Clk2x : std_logic := '1';
+
+ procedure ClkWait(X : positive := 1) is
+ begin
+ for i in 1 to X loop
+ wait until rising_edge(Clk);
+ end loop;
+ end procedure ClkWait;
+
+begin
+
+ Clk <= not Clk after kPer/2 when not StopSim else '0';
+ Clk2x <= not Clk2x after kPer/4 when not StopSim else '0';
+
+ dut: adc_gearbox_8x4
+ port map (
+ clk1x => Clk,
+ reset_n_1x => reset_n_1x,
+ adc_q_in_1x => adc_q_in_1x,
+ adc_i_in_1x => adc_i_in_1x,
+ valid_in_1x => valid_in_1x,
+ enable_1x => enable_1x,
+ clk2x => Clk2x,
+ swap_iq_2x => swap_iq_2x,
+ adc_out_2x => adc_out_2x,
+ valid_out_2x => valid_out_2x
+ );
+
+ main: process
+ begin
+ swap_iq_2x <= '0';
+ valid_in_1x <= '0';
+ enable_1x <= '0';
+ reset_n_1x <= '0';
+ ClkWait(5);
+ reset_n_1x <= '1';
+ ClkWait(5);
+
+ -- Ensure the outputs are quiet.
+ ClkWait(20);
+ assert valid_out_2x'stable(kPer*20) and valid_out_2x = '0'
+ report "valid not stable at de-asserted at startup"
+ severity error;
+ assert adc_out_2x'stable(kPer*20) and (adc_out_2x = std_logic_vector(to_unsigned(0,128)))
+ report "data not stable at zero at startup"
+ severity error;
+
+ -- Valid asserted, Enable asserted, Enable de-asserted, Valid de-asserted.
+
+ ClkWait(10);
+ valid_in_1x <= '1';
+ ClkWait(10);
+ enable_1x <= '1';
+
+ ClkWait(110);
+ assert valid_out_2x'stable(kPer*100) and valid_out_2x = '1'
+ report "valid not stable at asserted"
+ severity error;
+
+ ClkWait(10);
+ enable_1x <= '0';
+ ClkWait(10);
+ valid_in_1x <= '0';
+
+ ClkWait(110);
+ assert valid_out_2x'stable(kPer*100) and valid_out_2x = '0'
+ report "valid not stable at de-asserted"
+ severity error;
+
+ -- Enable asserted, Valid asserted, Enable de-asserted, Valid de-asserted.
+
+ ClkWait(10);
+ enable_1x <= '1';
+ ClkWait(10);
+ valid_in_1x <= '1';
+
+ ClkWait(110);
+ assert valid_out_2x'stable(kPer*100) and valid_out_2x = '1'
+ report "valid not stable at asserted"
+ severity error;
+
+ ClkWait(10);
+ enable_1x <= '0';
+ ClkWait(10);
+ valid_in_1x <= '0';
+
+ ClkWait(110);
+ assert valid_out_2x'stable(kPer*100) and valid_out_2x = '0'
+ report "valid not stable at de-asserted"
+ severity error;
+
+ StopSim <= true;
+ wait;
+ end process;
+
+ -- Process to generate input data to DUT and expected output data.
+ driver: process(Clk)
+ variable tempQdata : integer := 1;
+ variable tempIdata : integer := 128;
+ variable qData8spc : std_logic_vector(127 downto 0);
+ variable iData8spc : std_logic_vector(127 downto 0);
+ begin
+ if rising_edge(Clk) then
+ qdata8Spc := std_logic_vector(to_unsigned(tempQdata+7,16)) & std_logic_vector(to_unsigned(tempQdata+6,16)) &
+ std_logic_vector(to_unsigned(tempQdata+5,16)) & std_logic_vector(to_unsigned(tempQdata+4,16)) &
+ std_logic_vector(to_unsigned(tempQdata+3,16)) & std_logic_vector(to_unsigned(tempQdata+2,16)) &
+ std_logic_vector(to_unsigned(tempQdata+1,16)) & std_logic_vector(to_unsigned(tempQdata ,16));
+ adc_q_in_1x <= qData8Spc;
+
+ iData8spc := std_logic_vector(to_unsigned(tempIdata+7,16)) & std_logic_vector(to_unsigned(tempIdata+6,16)) &
+ std_logic_vector(to_unsigned(tempIdata+5,16)) & std_logic_vector(to_unsigned(tempIdata+4,16)) &
+ std_logic_vector(to_unsigned(tempIdata+3,16)) & std_logic_vector(to_unsigned(tempIdata+2,16)) &
+ std_logic_vector(to_unsigned(tempIdata+1,16)) & std_logic_vector(to_unsigned(tempIdata ,16));
+ adc_i_in_1x <= iData8Spc;
+
+
+ cDataCheckNxtLo <= qData8spc( 63 downto 48) & iData8spc( 63 downto 48) &
+ qData8spc( 47 downto 32) & iData8spc( 47 downto 32) &
+ qData8spc( 31 downto 16) & iData8spc( 31 downto 16) &
+ qData8spc( 15 downto 0) & iData8spc( 15 downto 0);
+ cDataCheckNxtHi <= qData8spc(127 downto 112) & iData8spc(127 downto 112) &
+ qData8spc(111 downto 96) & iData8spc(111 downto 96) &
+ qData8spc( 95 downto 80) & iData8spc( 95 downto 80) &
+ qData8spc( 79 downto 64) & iData8spc( 79 downto 64);
+ tempQdata := tempQdata+8;
+ tempIdata := tempIdata+8;
+ end if;
+ end process;
+
+ -- Process to check DUT output with expected data.
+ checker: process(Clk2x)
+ variable tempout : integer := 1;
+ variable ExpectedData : std_logic_vector(127 downto 0) := (others => '0');
+ begin
+ if falling_edge(Clk2x) then
+ if Clk = '1' then
+ ExpectedData := cDataCheckLo;
+ else
+ ExpectedData := cDataCheckHi2;
+ end if;
+ if valid_out_2x = '1' then
+ assert adc_out_2x = ExpectedData
+ report "ADC data out mismatch from expected"
+ severity error;
+ tempout := tempout +1;
+ end if;
+ cDataCheckLo <= cDataCheckNxtLo;
+ cDataCheckHi1 <= cDataCheckNxtHi;
+ cDataCheckHi2 <= cDataCheckHi1;
+ end if;
+ end process;
+
+end RTL;
diff --git a/fpga/usrp3/top/x400/rf/sim/tb_capture_sysref.vhd b/fpga/usrp3/top/x400/rf/sim/tb_capture_sysref.vhd
new file mode 100644
index 000000000..eb5cbcf08
--- /dev/null
+++ b/fpga/usrp3/top/x400/rf/sim/tb_capture_sysref.vhd
@@ -0,0 +1,119 @@
+--
+-- Copyright 2021 Ettus Research, a National Instruments Brand
+--
+-- SPDX-License-Identifier: LGPL-3.0-or-later
+--
+-- Module: tb_capture_sysref
+--
+-- Description:
+--
+-- Self-checking testbench for tb_capture_sysref.
+--
+
+library IEEE;
+ use IEEE.std_logic_1164.all;
+ use IEEE.numeric_std.all;
+
+entity tb_capture_sysref is
+end tb_capture_sysref;
+
+
+architecture RTL of tb_capture_sysref is
+
+ component capture_sysref
+ port (
+ pll_ref_clk : in std_logic;
+ rfdc_clk : in std_logic;
+ sysref_in : in std_logic;
+ enable_rclk : in std_logic;
+ sysref_out_pclk : out std_logic;
+ sysref_out_rclk : out std_logic);
+ end component;
+
+ signal enable_rclk : std_logic := '0';
+ signal sysref_out_pclk : std_logic := '0';
+ signal sysref_out_rclk : std_logic := '0';
+ signal sysref_in : std_logic := '0';
+
+ signal SysrefDly, SysrefDlyDly, rSysref : std_logic := '0';
+
+ signal StopSim : boolean;
+ constant kPerPRC : time := 30 ns;
+ constant kPerRF : time := 10 ns;
+
+ signal PllRefClk : std_logic := '1';
+ signal RfdcClk : std_logic := '1';
+
+ procedure ClkWait(X : positive := 1) is
+ begin
+ for i in 1 to X loop
+ wait until rising_edge(PllRefClk);
+ end loop;
+ end procedure ClkWait;
+
+begin
+
+ PllRefClk <= not PllRefClk after kPerPRC/2 when not StopSim else '0';
+ RfdcClk <= not RfdcClk after kPerRF/2 when not StopSim else '0';
+
+ dut: capture_sysref
+ port map (
+ pll_ref_clk => PllRefClk,
+ rfdc_clk => RfdcClk,
+ sysref_in => sysref_in,
+ enable_rclk => enable_rclk,
+ sysref_out_pclk => sysref_out_pclk,
+ sysref_out_rclk => sysref_out_rclk
+ );
+
+ main: process
+ begin
+ enable_rclk <= '1';
+ ClkWait(100);
+ wait until falling_edge(sysref_out_rclk);
+ ClkWait;
+ wait until falling_edge(RfdcClk);
+ enable_rclk <= '0';
+ ClkWait(100);
+ wait until falling_edge(RfdcClk);
+ enable_rclk <= '1';
+ ClkWait(100);
+
+ StopSim <= true;
+ wait;
+ end process;
+
+ sysref: process(PllRefClk)
+ variable count : integer := 1;
+ begin
+ if rising_edge(PllRefClk) then
+ count := count +1;
+ if count = 10 then
+ sysref_in <= not sysref_in;
+ count := 1;
+ end if;
+ end if;
+ end process;
+
+ checker_pll_ref_clk: process(PllRefClk)
+ begin
+ if falling_edge(PllRefClk) then
+ SysrefDly <= sysref_in;
+ SysrefDlyDly <= SysrefDly;
+ assert SysrefDlyDly = sysref_out_pclk
+ report "SYSREF incorrectly captured in the PllRefClk domain"
+ severity error;
+ end if;
+ end process;
+
+ checker_rfdc_clk: process(RfdcClk)
+ begin
+ if falling_edge(RfdcClk) then
+ rSysref <= sysref_out_pclk;
+ assert (rSysref = sysref_out_rclk) or (enable_rclk = '0')
+ report "SYSREF incorrectly captured in the RfdcClk domain."
+ severity error;
+ end if;
+ end process;
+
+end RTL;
diff --git a/fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_12x8.vhd b/fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_12x8.vhd
new file mode 100644
index 000000000..cde766cbd
--- /dev/null
+++ b/fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_12x8.vhd
@@ -0,0 +1,197 @@
+--
+-- Copyright 2021 Ettus Research, a National Instruments Brand
+--
+-- SPDX-License-Identifier: LGPL-3.0-or-later
+--
+-- Module: tb_dac_gearbox_12x8
+--
+-- Description:
+--
+-- Self-checking testbench for a gearbox that decreases the SPCs from 12 to
+-- 8.
+--
+
+library IEEE;
+ use IEEE.std_logic_1164.all;
+ use IEEE.numeric_std.all;
+
+entity tb_dac_gearbox_12x8 is
+end tb_dac_gearbox_12x8;
+
+
+architecture RTL of tb_dac_gearbox_12x8 is
+
+ signal TestStart : boolean;
+
+ signal ac1Reset_n : std_logic := '0';
+ signal arReset_n : std_logic := '0';
+ signal c1DataIn : std_logic_vector(383 downto 0) := (others => '0');
+ signal c1DataValidIn : std_logic := '0';
+ signal rDataOut : std_logic_vector(255 downto 0);
+ signal rReadyForOutput : std_logic := '1';
+ signal rDataValidOut : std_logic;
+ signal rDataToCheck, rDataToCheckDly0, rDataToCheckDly1, rDataToCheckDly2,
+ rDataToCheckDly3, rDataToCheckDly4
+ : std_logic_vector(255 downto 0) := (others => '0');
+
+ signal StopSim : boolean;
+ constant kPer : time := 12 ns;
+
+ signal Clk1x: std_logic := '1';
+ signal RfClk: std_logic := '1';
+
+ procedure RfClkWait(X : positive := 1) is
+ begin
+ for i in 1 to X loop
+ wait until rising_edge(RfClk);
+ end loop;
+ end procedure RfClkWait;
+
+ procedure Clk1xWait(X : positive := 1) is
+ begin
+ for i in 1 to X loop
+ wait until rising_edge(Clk1x);
+ end loop;
+ end procedure Clk1xWait;
+
+begin
+
+ Clk1x <= not Clk1x after kPer/4 when not StopSim else '0';
+ RfClk <= not RfClk after kPer/6 when not StopSim else '0';
+
+ dut: entity WORK.dac_gearbox_12x8 (RTL)
+ port map (
+ Clk1x => Clk1x,
+ RfClk => RfClk,
+ ac1Reset_n => ac1Reset_n,
+ arReset_n => arReset_n,
+ c1DataIn => c1DataIn,
+ c1DataValidIn => c1DataValidIn,
+ rDataOut => rDataOut,
+ rReadyForOutput => rReadyForOutput,
+ rDataValidOut => rDataValidOut
+ );
+
+ main: process
+ -- Procedure to start and stop data generation.
+ -- WaitCycles : This is a wait in Clk1x cycle. This is used to shift data
+ -- valid assertion. Depending on the Clk1x cycle, data valid
+ -- will be asserted either when both RfClk and Clk1x are phase
+ -- aligned or when both clocks are not phase aligned.
+ procedure PhaseTest(WaitCycles : positive := 1) is
+ begin
+ for i in 0 to 31 loop
+ -- Wait for certain RfClk cycles before starting the test.
+ Clk1xWait(WaitCycles);
+ TestStart <= true;
+ -- Random wait
+ Clk1xWait(1000+i);
+ TestStart <= false;
+ -- wait for few clock cycles for the output data valid to de-assert.
+ Clk1xWait(10);
+ end loop;
+ end procedure;
+
+ begin
+ ac1Reset_n <= '0';
+ arReset_n <= '0';
+ TestStart <= false;
+ Clk1xWait(5);
+ ac1Reset_n <= '1';
+ arReset_n <= '1';
+ rReadyForOutput <= '1';
+
+ -- RfClk and Clk1x are phase aligned
+ PhaseTest(1);
+
+ -- RfClk and Clk1x are phase aligned
+ PhaseTest(2);
+
+ -- RfClk and Clk1x are not phase aligned
+ PhaseTest(3);
+
+ -- Stop data input to the DUT and wait for few clock cycles for the output
+ -- data valid to be de-asserted.
+ TestStart <= false;
+ RfClkWait(10);
+
+ StopSim <= true;
+ wait;
+ end process;
+
+ -- Process to generate input data.
+ driver: process(Clk1x)
+ variable qDataIn : unsigned(15 downto 0) := x"0001";
+ variable iDataIn : unsigned(15 downto 0) := x"0080";
+ begin
+ if rising_edge(Clk1x) then
+ c1DataValidIn <= '0';
+ if TestStart then
+ c1DataValidIn <= '1';
+ c1DataIn <= std_logic_vector((qDataIn+11) & (iDataIn+11) &
+ (qDataIn+10) & (iDataIn+10) &
+ (qDataIn+9) & (iDataIn+9) &
+ (qDataIn+8) & (iDataIn+8) &
+ (qDataIn+7) & (iDataIn+7) &
+ (qDataIn+6) & (iDataIn+6) &
+ (qDataIn+5) & (iDataIn+5) &
+ (qDataIn+4) & (iDataIn+4) &
+ (qDataIn+3) & (iDataIn+3) &
+ (qDataIn+2) & (iDataIn+2) &
+ (qDataIn+1) & (iDataIn+1) &
+ (qDataIn+0) & (iDataIn+0));
+ qDataIn := qDataIn+12;
+ iDataIn := iDataIn+12;
+
+ else
+ c1DataValidIn <= '0';
+ qDataIn := x"0001";
+ iDataIn := x"0080";
+ end if;
+ end if;
+ end process;
+
+ -- Process to generate expected output data.
+ ExpectedData: process(RfClk)
+ variable qDataOut : unsigned(15 downto 0) := x"0001";
+ variable iDataOut : unsigned(15 downto 0) := x"0080";
+ begin
+ if rising_edge(RfClk) then
+ if TestStart then
+ rDataToCheck <= std_logic_vector((qDataOut+7) & (iDataOut+7) &
+ (qDataOut+6) & (iDataOut+6) &
+ (qDataOut+5) & (iDataOut+5) &
+ (qDataOut+4) & (iDataOut+4) &
+ (qDataOut+3) & (iDataOut+3) &
+ (qDataOut+2) & (iDataOut+2) &
+ (qDataOut+1) & (iDataOut+1) &
+ (qDataOut+0) & (iDataOut+0));
+
+ -- Data output that has to be verified.
+ qDataOut := qDataOut+8;
+ iDataOut := iDataOut+8;
+ else
+ qDataOut := x"0001";
+ iDataOut := x"0080";
+ end if;
+ rDataToCheckDly0 <= rDataToCheck;
+ rDataToCheckDly1 <= rDataToCheckDly0;
+ rDataToCheckDly2 <= rDataToCheckDly1;
+ rDataToCheckDly3 <= rDataToCheckDly2;
+ rDataToCheckDly4 <= rDataToCheckDly3;
+ end if;
+ end process;
+
+ -- Process to check output data with expected data.
+ checker: process(RfClk)
+ begin
+ if falling_edge(RfClk) then
+ if rDataValidOut = '1' then
+ assert rDataOut = rDataToCheckDly4
+ report "DAC data out mismatch from expected"
+ severity error;
+ end if;
+ end if;
+ end process;
+
+end RTL;
diff --git a/fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_4x2.vhd b/fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_4x2.vhd
new file mode 100644
index 000000000..45fe9e150
--- /dev/null
+++ b/fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_4x2.vhd
@@ -0,0 +1,168 @@
+--
+-- Copyright 2021 Ettus Research, a National Instruments Brand
+--
+-- SPDX-License-Identifier: LGPL-3.0-or-later
+--
+-- Module: tb_dac_gearbox_4x2
+--
+-- Description:
+--
+-- Self-checking testbench used to test the gearbox that reduces a 4 SPC data
+-- into a 2 SPC data.
+--
+
+library IEEE;
+ use IEEE.std_logic_1164.all;
+ use IEEE.numeric_std.all;
+
+entity tb_dac_gearbox_4x2 is
+end tb_dac_gearbox_4x2;
+
+
+architecture RTL of tb_dac_gearbox_4x2 is
+
+ component dac_gearbox_4x2
+ port (
+ clk1x : in std_logic;
+ reset_n_1x : in std_logic;
+ data_in_1x : in std_logic_vector(127 downto 0);
+ valid_in_1x : in std_logic;
+ ready_out_1x : out std_logic;
+ clk2x : in std_logic;
+ data_out_2x : out std_logic_vector(63 downto 0);
+ valid_out_2x : out std_logic);
+ end component;
+
+ signal TestStart : boolean;
+
+ signal data_in_1x : std_logic_vector(127 downto 0);
+ signal data_out_2x : std_logic_vector(63 downto 0);
+ signal ready_out_1x : std_logic;
+ signal reset_n_1x : std_logic;
+ signal valid_in_1x : std_logic;
+ signal valid_out_2x : std_logic;
+
+ signal StopSim : boolean;
+ constant kPer : time := 10 ns;
+
+ signal Clk: std_logic := '1';
+ signal Clk2x: std_logic := '1';
+
+ signal c2DataToCheck, c2DataToCheckDly0, c2DataToCheckDly1, c2DataToCheckDly2
+ : std_logic_vector(63 downto 0) := (others => '0');
+
+ procedure ClkWait(X : positive := 1) is
+ begin
+ for i in 1 to X loop
+ wait until rising_edge(Clk);
+ end loop;
+ end procedure ClkWait;
+
+begin
+
+ Clk <= not Clk after kPer/2 when not StopSim else '0';
+ Clk2x <= not Clk2x after kPer/4 when not StopSim else '0';
+
+ dut: dac_gearbox_4x2
+ port map (
+ clk1x => Clk,
+ reset_n_1x => reset_n_1x,
+ data_in_1x => data_in_1x,
+ valid_in_1x => valid_in_1x,
+ ready_out_1x => ready_out_1x,
+ clk2x => Clk2x,
+ data_out_2x => data_out_2x,
+ valid_out_2x => valid_out_2x
+ );
+
+ main: process
+ begin
+ reset_n_1x <= '0';
+ TestStart <= false;
+ ClkWait(5);
+ reset_n_1x <= '1';
+ ClkWait(5);
+
+ -- Ensure the outputs are quiet.
+ ClkWait(20);
+ assert valid_out_2x'stable(kPer*20) and valid_out_2x = '0'
+ report "valid not stable at de-asserted at startup"
+ severity error;
+ assert data_out_2x'stable(kPer*20) and (data_out_2x = x"0000000000000000")
+ report "data not stable at zero at startup"
+ severity error;
+
+ -- Valid asserted, Enable asserted, Enable de-asserted, Valid de-asserted.
+
+ ClkWait(10);
+ TestStart <= true;
+
+ ClkWait(110);
+ assert valid_out_2x'stable(kPer*100) and valid_out_2x = '1'
+ report "valid not stable at asserted"
+ severity error;
+
+ TestStart <= false;
+ ClkWait(10);
+ StopSim <= true;
+ wait;
+ end process;
+
+ -- Process to generate input data to DUT.
+ driver: process(Clk)
+ variable tempQdata : integer := 1;
+ variable tempIdata : integer := 128;
+ begin
+ if rising_edge(Clk) then
+ valid_in_1x <= '0';
+ if TestStart then
+ valid_in_1x <= '1';
+ data_in_1x <= std_logic_vector(to_unsigned(tempQdata+3,16)) & std_logic_vector(to_unsigned(tempIdata+3,16)) &
+ std_logic_vector(to_unsigned(tempQdata+2,16)) & std_logic_vector(to_unsigned(tempIdata+2,16)) &
+ std_logic_vector(to_unsigned(tempQdata+1,16)) & std_logic_vector(to_unsigned(tempIdata+1,16)) &
+ std_logic_vector(to_unsigned(tempQdata+0,16)) & std_logic_vector(to_unsigned(tempIdata+0,16));
+ tempQdata := tempQdata+4;
+ tempIdata := tempIdata+4;
+ end if;
+ end if;
+ end process;
+
+ -- Process to generate expected data out of the DUT.
+ ExpectedData: process(Clk2x)
+ variable qDataOut : unsigned(15 downto 0) := x"0001";
+ variable iDataOut : unsigned(15 downto 0) := x"0080";
+ begin
+ if rising_edge(Clk2x) then
+ if TestStart then
+ c2DataToCheck <= std_logic_vector((qDataOut+1) & (iDataOut+1) &
+ (qDataOut+0) & (iDataOut+0));
+
+ qDataOut := qDataOut+2;
+ iDataOut := iDataOut+2;
+ else
+ qDataOut := x"0001";
+ iDataOut := x"0080";
+ end if;
+ c2DataToCheckDly0 <= c2DataToCheck;
+ c2DataToCheckDly1 <= c2DataToCheckDly0;
+ c2DataToCheckDly2 <= c2DataToCheckDly1;
+ end if;
+ end process;
+
+ -- Process to check DUT output data with expected data.
+ checker: process(Clk2x)
+ begin
+ if falling_edge(Clk2x) then
+ if valid_out_2x = '1' then
+ assert data_out_2x = c2DataToCheckDly2
+ report "DAC data out mismatch from expected"
+ severity error;
+ end if;
+ assert ready_out_1x = '1'
+ report "Ready for output is not asserted"
+ severity error;
+
+ end if;
+ end process;
+
+end RTL;
diff --git a/fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_6x12.vhd b/fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_6x12.vhd
new file mode 100644
index 000000000..950ed8db1
--- /dev/null
+++ b/fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_6x12.vhd
@@ -0,0 +1,187 @@
+--
+-- Copyright 2021 Ettus Research, a National Instruments Brand
+--
+-- SPDX-License-Identifier: LGPL-3.0-or-later
+--
+-- Module: tb_dac_gearbox_6x12
+--
+-- Description:
+--
+-- Self-checking testbench used to test the gearbox that expands a 6 SPC data
+-- into a 12 SPC data.
+--
+
+library IEEE;
+ use IEEE.std_logic_1164.all;
+ use IEEE.numeric_std.all;
+
+entity tb_dac_gearbox_6x12 is
+end tb_dac_gearbox_6x12;
+
+
+architecture RTL of tb_dac_gearbox_6x12 is
+
+ signal TestStart : boolean;
+
+ signal ac1Reset_n : std_logic;
+ signal ac2Reset_n : std_logic;
+ signal c1DataOut : std_logic_vector(383 downto 0);
+ signal c1DataValidOut : std_logic;
+ signal c2DataIn : std_logic_vector(191 downto 0) := (others => '0');
+ signal c2DataValidIn : std_logic := '0';
+ signal InPhase : boolean := false;
+
+ signal c1DataToCheck, c1DataToCheckDly0, c1DataToCheckDly1, c1DataToCheckDly2
+ : std_logic_vector(383 downto 0) := (others => '0');
+
+ signal StopSim : boolean;
+ constant kPer : time := 12 ns;
+
+ signal Clk1x: std_logic := '1';
+ signal Clk2x: std_logic := '1';
+
+ procedure Clk2xWait(X : positive := 1) is
+ begin
+ for i in 1 to X loop
+ wait until rising_edge(Clk2x);
+ end loop;
+ end procedure Clk2xWait;
+
+begin
+
+ Clk1x <= not Clk1x after kPer/4 when not StopSim else '0';
+ Clk2x <= not Clk2x after kPer/8 when not StopSim else '0';
+
+ dut: entity WORK.dac_gearbox_6x12 (RTL)
+ port map (
+ Clk1x => Clk1x,
+ Clk2x => Clk2x,
+ ac1Reset_n => ac1Reset_n,
+ ac2Reset_n => ac2Reset_n,
+ c2DataIn => c2DataIn,
+ c2DataValidIn => c2DataValidIn,
+ c1DataOut => c1DataOut,
+ c1DataValidOut => c1DataValidOut
+ );
+
+
+ main: process
+
+ -- Procedure to start and stop data generation.
+ -- WaitCycles : This is a wait in Clk2x cycle. This is used to shift data
+ -- valid assertion. Depending on the Clk2x cycle, data valid
+ -- will be asserted either when both Clk1x and Clk2x are phase
+ -- aligned or when both clocks are not phase aligned.
+ -- Phase : This input is used in the logic that is used to check
+ -- output data with expected data. If data valid was asserted
+ -- when both clocks were phase aligned, then this input is
+ -- set to true and vice versa.
+ procedure PhaseTest(WaitCycles : positive := 1;
+ Phase : boolean := false) is
+ begin
+ -- Wait for certain Clk2x cycles before starting the test.
+ Clk2xWait(WaitCycles);
+ InPhase <= Phase;
+ TestStart <= true;
+ Clk2xWait(1000); -- Random wait.
+ TestStart <= false;
+ -- wait for few clock cycles for the output data valid to de-assert.
+ Clk2xWait(10);
+ end procedure;
+
+ begin
+
+ -- Assert and de-assert reset.
+ ac1Reset_n <= '0';
+ ac2Reset_n <= '0';
+ TestStart <= false;
+ Clk2xWait(5);
+ ac1Reset_n <= '1';
+ ac2Reset_n <= '1';
+
+ PhaseTest(1, true);
+ PhaseTest(3, false);
+ PhaseTest(5, true);
+
+ -- Stop data input to the DUT and wait for few clock cycles for the output
+ -- data valid to be de-asserted.
+ TestStart <= false;
+ Clk2xWait(10);
+
+ StopSim <= true;
+ wait;
+ end process;
+
+ driver: process(Clk2x)
+ variable tempQdata : unsigned(15 downto 0) := x"0001";
+ variable tempIdata : unsigned(15 downto 0) := x"0080";
+ begin
+ if rising_edge(Clk2x) then
+ c2DataValidIn <= '0';
+ if TestStart then
+ c2DataValidIn <= '1';
+ c2DataIn <= std_logic_vector((tempQdata+5) & (tempIdata+5) &
+ (tempQdata+4) & (tempIdata+4) &
+ (tempQdata+3) & (tempIdata+3) &
+ (tempQdata+2) & (tempIdata+2) &
+ (tempQdata+1) & (tempIdata+1) &
+ (tempQdata+0) & (tempIdata+0));
+ tempQdata := tempQdata +6;
+ tempIdata := tempIdata +6;
+ else
+ c2DataValidIn <= '0';
+ tempQdata := x"0001";
+ tempIdata := x"0080";
+ end if;
+ end if;
+ end process;
+
+ -- Process to generate expected data out of the DUT.
+ ExpectedData: process(Clk1x)
+ variable qDataOut : unsigned(15 downto 0) := x"0001";
+ variable iDataOut : unsigned(15 downto 0) := x"0080";
+ begin
+ if rising_edge(Clk1x) then
+ if TestStart then
+ c1DataToCheck <= std_logic_vector((qDataOut+11) & (iDataOut+11) &
+ (qDataOut+10) & (iDataOut+10) &
+ (qDataOut+9) & (iDataOut+9) &
+ (qDataOut+8) & (iDataOut+8) &
+ (qDataOut+7) & (iDataOut+7) &
+ (qDataOut+6) & (iDataOut+6) &
+ (qDataOut+5) & (iDataOut+5) &
+ (qDataOut+4) & (iDataOut+4) &
+ (qDataOut+3) & (iDataOut+3) &
+ (qDataOut+2) & (iDataOut+2) &
+ (qDataOut+1) & (iDataOut+1) &
+ (qDataOut+0) & (iDataOut+0));
+
+ qDataOut := qDataOut+12;
+ iDataOut := iDataOut+12;
+ else
+ qDataOut := x"0001";
+ iDataOut := x"0080";
+ end if;
+ c1DataToCheckDly0 <= c1DataToCheck;
+ c1DataToCheckDly1 <= c1DataToCheckDly0;
+ c1DataToCheckDly2 <= c1DataToCheckDly1;
+ end if;
+ end process;
+
+ -- Process to check output data with expected data.
+ checker: process(Clk1x)
+ begin
+ if falling_edge(Clk1x) then
+ if c1DataValidOut = '1' and InPhase then
+ assert c1DataOut = c1DataToCheckDly1
+ report "ADC data out mismatch from expected"
+ severity warning;
+ elsif c1DataValidOut = '1' and (not InPhase) then
+ assert c1DataOut = c1DataToCheckDly2
+ report "ADC data out mismatch from expected"
+ severity warning;
+ end if;
+ end if;
+ end process;
+
+end RTL;
diff --git a/fpga/usrp3/top/x400/rf/sim/tb_ddc_400m_saturate.vhd b/fpga/usrp3/top/x400/rf/sim/tb_ddc_400m_saturate.vhd
new file mode 100644
index 000000000..37f570d87
--- /dev/null
+++ b/fpga/usrp3/top/x400/rf/sim/tb_ddc_400m_saturate.vhd
@@ -0,0 +1,125 @@
+--
+-- Copyright 2021 Ettus Research, a National Instruments Brand
+--
+-- SPDX-License-Identifier: LGPL-3.0-or-later
+--
+-- Module: tb_ddc_400m_saturate
+--
+-- Description:
+--
+-- Self-checking testbench used to check the saturation logic needed in DDC.
+--
+
+library IEEE;
+ use IEEE.std_logic_1164.all;
+ use IEEE.numeric_std.all;
+
+library WORK;
+ use WORK.PkgRf.all;
+
+entity tb_ddc_400m_saturate is
+end tb_ddc_400m_saturate;
+
+
+architecture RTL of tb_ddc_400m_saturate is
+
+ component ddc_400m_saturate
+ port (
+ Clk : in std_logic;
+ cDataIn : in std_logic_vector(191 downto 0);
+ cDataValidIn : in std_logic;
+ cDataOut : out std_logic_vector(127 downto 0);
+ cDataValidOut : out std_logic);
+ end component;
+
+ signal TestStart : boolean := false;
+
+ signal cDataIn : std_logic_vector(191 downto 0);
+ signal cDataOut : std_logic_vector(127 downto 0);
+ signal cDataValidIn : std_logic;
+ signal cDataValidOut : std_logic;
+
+ signal StopSim : boolean;
+ constant kPer : time := 10 ns;
+ constant kSamplesPerClock : integer := 8;
+
+ signal Clk: std_logic := '1';
+
+ procedure ClkWait(X : positive := 1) is
+ begin
+ for i in 1 to X loop
+ wait until rising_edge(Clk);
+ end loop;
+ end procedure ClkWait;
+
+begin
+
+ Clk <= not Clk after kPer/2 when not StopSim else '0';
+
+ dut: ddc_400m_saturate
+ port map (
+ Clk => Clk,
+ cDataIn => cDataIn,
+ cDataValidIn => cDataValidIn,
+ cDataOut => cDataOut,
+ cDataValidOut => cDataValidOut);
+
+ main: process
+ begin
+
+ ClkWait;
+ TestStart <= false;
+ ClkWait;
+ TestStart <= true;
+
+ -- This wait is needed to sweep through the entire range of 17 bits signed
+ -- value. Since we operate the saturation logic with 8 samples per cycle,
+ -- we need to wait for 2^kDdcDataOutWidth/8. We are adding an extra 10
+ -- clock cycles wait just as a buffer for the DUT latency.
+ ClkWait(2**kDdcDataOutWidth/kSamplesPerClock + 10);
+ StopSim <= true;
+ wait;
+ end process;
+
+ -- Process to generate 17-bit signed data.
+ DataGen: process(Clk)
+ variable Sample : Sample17_t := kSmallest17;
+ begin
+ if falling_edge(Clk) then
+ if TestStart then
+ cDataValidIn <= '1';
+ cDataIn <= "0000000" & std_logic_vector(Sample+kSamplesPerClock-1) &
+ "0000000" & std_logic_vector(Sample+kSamplesPerClock-2) &
+ "0000000" & std_logic_vector(Sample+kSamplesPerClock-3) &
+ "0000000" & std_logic_vector(Sample+kSamplesPerClock-4) &
+ "0000000" & std_logic_vector(Sample+kSamplesPerClock-5) &
+ "0000000" & std_logic_vector(Sample+kSamplesPerClock-6) &
+ "0000000" & std_logic_vector(Sample+kSamplesPerClock-7) &
+ "0000000" & std_logic_vector(Sample+kSamplesPerClock-8);
+ Sample := Sample +8;
+ end if;
+ end if;
+ end process;
+
+ -- Check if saturation and data packing is done correctly.
+ DataCheck: process(Clk)
+ variable Sample : Sample17_t := kSmallest17;
+ variable ExpectedData : std_logic_vector(15 downto 0);
+
+ begin
+ if falling_edge(Clk) then
+ if cDataValidOut then
+ for i in 1 to 8 loop
+ ExpectedData := tb_saturate(std_logic_vector(Sample));
+ assert cDataOut(kSatDataWidth*i-1 downto kSatDataWidth*(i-1)) = ExpectedData
+ report "Saturation data out mismatch in index : " & to_string(i) & LF &
+ "Expected data is : " & to_hstring(ExpectedData) & LF &
+ "Received data is : " & to_hstring(cDataOut(kSatDataWidth*i-1 downto kSatDataWidth*(i-1)))
+ severity error;
+ Sample := Sample+1;
+ end loop;
+ end if;
+ end if;
+ end process;
+
+end RTL;
diff --git a/fpga/usrp3/top/x400/rf/sim/tb_duc_400m_saturate.vhd b/fpga/usrp3/top/x400/rf/sim/tb_duc_400m_saturate.vhd
new file mode 100644
index 000000000..e3117bdd6
--- /dev/null
+++ b/fpga/usrp3/top/x400/rf/sim/tb_duc_400m_saturate.vhd
@@ -0,0 +1,133 @@
+--
+-- Copyright 2021 Ettus Research, a National Instruments Brand
+--
+-- SPDX-License-Identifier: LGPL-3.0-or-later
+--
+-- Module: tb_duc_400m_saturate
+--
+-- Description:
+--
+-- Self-checking testbench used to check the saturation logic needed in DDC.
+--
+
+library IEEE;
+ use IEEE.std_logic_1164.all;
+ use IEEE.numeric_std.all;
+
+library WORK;
+ use WORK.PkgRf.all;
+
+entity tb_duc_400m_saturate is
+end tb_duc_400m_saturate;
+
+
+architecture RTL of tb_duc_400m_saturate is
+
+ component duc_400m_saturate
+ port (
+ Clk : in std_logic;
+ cDataIn : in std_logic_vector(287 downto 0);
+ cDataValidIn : in std_logic;
+ cReadyForInput : out std_logic;
+ cDataOut : out std_logic_vector(191 downto 0);
+ cDataValidOut : out std_logic := '0');
+ end component;
+
+ signal TestStart : boolean := false;
+
+ signal cDataIn : std_logic_vector(287 downto 0);
+ signal cDataOut : std_logic_vector(191 downto 0);
+ signal cDataValidIn : std_logic;
+ signal cDataValidOut : std_logic;
+
+ signal StopSim : boolean;
+ constant kPer : time := 10 ns;
+ constant kSamplesPerClock : integer := 12;
+
+ signal Clk: std_logic := '1';
+
+ procedure ClkWait(X : positive := 1) is
+ begin
+ for i in 1 to X loop
+ wait until rising_edge(Clk);
+ end loop;
+ end procedure ClkWait;
+
+begin
+
+ Clk <= not Clk after kPer/2 when not StopSim else '0';
+
+
+ -- cReadyForInput is a constant in the design and is not being tested.
+ dut: duc_400m_saturate
+ port map (
+ Clk => Clk,
+ cDataIn => cDataIn,
+ cDataValidIn => cDataValidIn,
+ cReadyForInput => open,
+ cDataOut => cDataOut,
+ cDataValidOut => cDataValidOut);
+
+ main: process
+ begin
+
+ ClkWait;
+ TestStart <= false;
+ ClkWait;
+ TestStart <= true;
+
+ -- This wait is needed to sweep through the entire range of 18 bits signed
+ -- value. Since we operate the saturation logic with 12 samples per cycle,
+ -- we need to wait for 2^kDucDataOutWidth/12. We are adding an extra 10
+ -- clock cycles wait just as a buffer for the DUT latency.
+ ClkWait(2**kDucDataOutWidth/kSamplesPerClock + 10);
+ StopSim <= true;
+ wait;
+ end process;
+
+ -- Process to generate 18-bit signed data.
+ DataGen: process(Clk)
+ variable Sample : Sample18_t := kSmallest18;
+ begin
+ if falling_edge(Clk) then
+ if TestStart then
+ cDataValidIn <= '1';
+ cDataIn <= "000000" & std_logic_vector(Sample+kSamplesPerClock-1) &
+ "000000" & std_logic_vector(Sample+kSamplesPerClock-2) &
+ "000000" & std_logic_vector(Sample+kSamplesPerClock-3) &
+ "000000" & std_logic_vector(Sample+kSamplesPerClock-4) &
+ "000000" & std_logic_vector(Sample+kSamplesPerClock-5) &
+ "000000" & std_logic_vector(Sample+kSamplesPerClock-6) &
+ "000000" & std_logic_vector(Sample+kSamplesPerClock-7) &
+ "000000" & std_logic_vector(Sample+kSamplesPerClock-8) &
+ "000000" & std_logic_vector(Sample+kSamplesPerClock-9) &
+ "000000" & std_logic_vector(Sample+kSamplesPerClock-10) &
+ "000000" & std_logic_vector(Sample+kSamplesPerClock-11) &
+ "000000" & std_logic_vector(Sample+kSamplesPerClock-12);
+ Sample := Sample +12;
+ end if;
+ end if;
+ end process;
+
+ -- Check if saturation and data packing is done correctly.
+ DataCheck: process(Clk)
+ variable Sample : Sample18_t := kSmallest18;
+ variable ExpectedData : std_logic_vector(15 downto 0);
+
+ begin
+ if falling_edge(Clk) then
+ if cDataValidOut then
+ for i in 1 to 12 loop
+ ExpectedData := tb_saturate(std_logic_vector(Sample));
+ assert cDataOut(kSatDataWidth*i-1 downto kSatDataWidth*(i-1)) = ExpectedData
+ report "Saturation data out mismatch in index : " & to_string(i) & LF &
+ "Expected data is : " & to_hstring(ExpectedData) & LF &
+ "Received data is : " & to_hstring(cDataOut(kSatDataWidth*i-1 downto kSatDataWidth*(i-1)))
+ severity error;
+ Sample := Sample+1;
+ end loop;
+ end if;
+ end if;
+ end process;
+
+end RTL;
diff --git a/fpga/usrp3/top/x400/rf/sim/tb_rf_nco_reset.vhd b/fpga/usrp3/top/x400/rf/sim/tb_rf_nco_reset.vhd
new file mode 100644
index 000000000..066dd5f4b
--- /dev/null
+++ b/fpga/usrp3/top/x400/rf/sim/tb_rf_nco_reset.vhd
@@ -0,0 +1,281 @@
+--
+-- Copyright 2021 Ettus Research, a National Instruments Brand
+--
+-- SPDX-License-Identifier: LGPL-3.0-or-later
+--
+-- Module: tb_rf_nco_reset
+--
+-- Description:
+--
+-- Self-checking testbench for NCO reset sequencing.
+--
+
+library IEEE;
+ use IEEE.std_logic_1164.all;
+ use IEEE.numeric_std.all;
+
+entity tb_rf_nco_reset is
+end tb_rf_nco_reset;
+
+
+architecture RTL of tb_rf_nco_reset is
+
+ signal cAdc0xNcoUpdateReq : std_logic;
+ signal cAdc2xNcoUpdateReq : std_logic;
+ signal cDac0xNcoUpdateReq : std_logic;
+ signal cDac0xSysrefIntGating : std_logic;
+ signal cDac0xSysrefIntReenable : std_logic;
+ signal cDac1xNcoUpdateReq : std_logic;
+ signal cNcoPhaseRst : std_logic;
+ signal cNcoUpdateEn : std_logic_vector(5 downto 0);
+ signal dNcoResetDone : std_logic;
+
+ signal cDac0xNcoUpdateBusy : std_logic_vector(1 downto 0) := "00";
+ signal dStartNcoReset : std_logic := '0';
+ signal cAdc0xNcoUpdateBusy : std_logic := '0';
+ signal cAdc2xNcoUpdateBusy : std_logic := '0';
+ signal cDac1xNcoUpdateBusy : std_logic := '0';
+
+ signal cSysref_ms, cSysref : std_logic := '0';
+ signal cSysrefDlyd : std_logic_vector(1 downto 0) := "00";
+ signal cDac0xSysrefIntGatingDlyd : std_logic := '0';
+ signal cNcoPhaseRstDlyd : std_logic_vector(2 downto 0) := "000";
+
+ signal cWrCount : integer := 0;
+ type RfdcNcoState_t is (Idle, GateSysref, UpdateReq, CheckUpdate,
+ SysrefEn, WaitForSysref, ResetDone);
+ signal cRfdcNcoState : RfdcNcoState_t := Idle;
+
+ signal StopSim : boolean;
+ constant kConfigClkPer : time := 25 ns;
+ -- SYSREF period is 2.5 MHz.
+ constant kSysrefPer : time := 400 ns;
+ -- DataClk period is 125 MHz and generated from the same clocking chip that
+ -- generated SYSREF and are related.
+ constant kDataClkPer : time := kSysrefPer/50;
+
+ signal ConfigClk : std_logic := '0';
+ signal DataClk : std_logic := '0';
+ signal dSysref : std_logic := '0';
+
+ procedure DataClkWait(X : positive := 1) is
+ begin
+ for i in 1 to X loop
+ wait until rising_edge(DataClk);
+ end loop;
+ end procedure DataClkWait;
+
+ procedure ConfigClkWait(X : positive := 1) is
+ begin
+ for i in 1 to X loop
+ wait until rising_edge(ConfigClk);
+ end loop;
+ end procedure ConfigClkWait;
+
+ procedure SysrefWait(X : positive := 1) is
+ begin
+ for i in 1 to X loop
+ wait until rising_edge(dSysref);
+ end loop;
+ end procedure SysrefWait;
+
+begin
+
+ ConfigClk <= not ConfigClk after kConfigClkPer/2 when not StopSim else '0';
+ DataClk <= not DataClk after kDataClkPer/2 when not StopSim else '0';
+ dSysref <= not dSysref after kSysrefPer/2 when not StopSim else '0';
+
+ -- Both cNcoPhaseRst and cNcoUpdateEn are constants in the DUT.
+ dut: entity WORK.rf_nco_reset (RTL)
+ port map (
+ ConfigClk => ConfigClk,
+ DataClk => DataClk,
+ dSysref => dSysref,
+ dStartNcoReset => dStartNcoReset,
+ cDac0xNcoUpdateBusy => cDac0xNcoUpdateBusy,
+ cDac0xNcoUpdateReq => cDac0xNcoUpdateReq,
+ cDac0xSysrefIntGating => cDac0xSysrefIntGating,
+ cDac0xSysrefIntReenable => cDac0xSysrefIntReenable,
+ cDac1xNcoUpdateBusy => cDac1xNcoUpdateBusy,
+ cDac1xNcoUpdateReq => cDac1xNcoUpdateReq,
+ cAdc0xNcoUpdateBusy => cAdc0xNcoUpdateBusy,
+ cAdc0xNcoUpdateReq => cAdc0xNcoUpdateReq,
+ cAdc2xNcoUpdateBusy => cAdc2xNcoUpdateBusy,
+ cAdc2xNcoUpdateReq => cAdc2xNcoUpdateReq,
+ cNcoPhaseRst => cNcoPhaseRst,
+ cNcoUpdateEn => cNcoUpdateEn,
+ dNcoResetDone => dNcoResetDone
+ );
+
+ main: process
+
+ -- Procedure to sweep the entire SYSREF period.
+ -- When we strobe dStartNcoReset for one DataClk cycle. NCO reset sequence
+ -- is initiated. In this procedure, we sweep the dStartNcoReset strobe the
+ -- entire SYSREF cycle.
+ procedure SysrefSweep is
+ constant kSysrefInRfCycles : integer := kSysrefPer/kDataClkPer;
+ begin
+ for i in 1 to kSysrefInRfCycles loop
+ wait until cDac0xSysrefIntGating = '0' for 1 us;
+ assert cDac0xSysrefIntGating = '0'
+ report "NCO phase reset does not de-assert"
+ severity error;
+ SysrefWait;
+ DataClkWait(i);
+ dStartNcoReset <= '0';
+ DataClkWait;
+ dStartNcoReset <= '1';
+ DataClkWait;
+ dStartNcoReset <= '0';
+ -- Wait for a minimum of 3 SYSREF period. 1 SYSREF edge is used to
+ -- initiate NCO reset, 1 SYSREF edge is used to re-enable SYSREF and 1
+ -- SYSREF edge is used by RFDC to reset all NCOs.
+ SysrefWait(3);
+ end loop;
+ end procedure;
+
+ begin
+
+ -- Strobe dStartNcoReset across entire SYSREF period.
+ SysrefSweep;
+ -- Wait for a minimum of 3 SYSREF cycles to make sure NCO reset is complete.
+ SysrefWait(3);
+
+ StopSim <= true;
+ wait;
+ end process;
+
+ -- Process to mimic RFDC NCO reset
+ -- This state machine is based of "NCO frequency hopping" section in PG269
+ -- (v2.2). Refer to multi-mode subsection for more details.
+ MimicRfdc: process(ConfigClk)
+ begin
+ if falling_edge(ConfigClk) then
+ cRfdcNcoState <= Idle;
+ case cRfdcNcoState is
+
+ -- Wait until SYSREF internal gating is asserted.
+ when Idle =>
+ cWrCount <= 0;
+ if cDac0xSysrefIntGating = '1' then
+ cRfdcNcoState <= GateSysref;
+ end if;
+
+ -- Change cDac0xNcoUpdateBusy to "11" to indicate SYSREF is gated
+ -- internally when NCO update is requested on DAC tile 228.
+ -- cDac0xNcoUpdateBusy(0) is set to '1', the SYSREF is gated and
+ -- cDac0xNcoUpdateBusy(1) is set to '1', to indicate the NCO reset
+ -- process has started, but not complete.
+ when GateSysref =>
+ cRfdcNcoState <= GateSysref;
+ if cDac0xNcoUpdateReq = '1' then
+ cRfdcNcoState <= UpdateReq;
+ cDac0xNcoUpdateBusy <= "11";
+ end if;
+
+ -- If NCO reset is requested on other tiles, assert NCO update busy on
+ -- other tiles as well.
+ when UpdateReq =>
+ cRfdcNcoState <= CheckUpdate;
+ cDac1xNcoUpdateBusy <= cDac1xNcoUpdateReq;
+ cAdc0xNcoUpdateBusy <= cAdc0xNcoUpdateReq;
+ cAdc2xNcoUpdateBusy <= cAdc2xNcoUpdateReq;
+
+ -- It takes 5 clock cycles to update each RFDC internal registers with
+ -- the used request change. In rf_nco_reset entity, we only want to
+ -- reset the NCO, which is a single bit. So, it should take only 5
+ -- ConfigClk for the update. When the internal register is updated, set
+ -- cDac0xNcoUpdateBusy(0) to '0'.
+ when CheckUpdate =>
+ cRfdcNcoState <= CheckUpdate;
+ if cWrCount > 4 then
+ cRfdcNcoState <= SysrefEn;
+ cDac0xNcoUpdateBusy <= "10"; --Indicates that SYSREF is gated.
+ cDac1xNcoUpdateBusy <= '0';
+ cAdc0xNcoUpdateBusy <= '0';
+ cAdc2xNcoUpdateBusy <= '0';
+ end if;
+ cWrCount <= cWrCount + 1;
+
+ -- Wait until internal SYSREF gating is disabled.
+ when SysrefEn =>
+ cWrCount <= 0;
+ cRfdcNcoState <= SysrefEn;
+ if cDac0xSysrefIntReenable = '1' then
+ if cSysrefDlyd(0) = '0' and cSysref = '1' then
+ cDac0xNcoUpdateBusy <= "00"; --Indicates that NCO reset is complete.
+ cRfdcNcoState <= ResetDone;
+ else
+ cRfdcNcoState <= WaitForSysref;
+ end if;
+ end if;
+
+ -- NCO reset is done on the rising edge of SYSREF. When NCO reset is
+ -- complete, set cDac0xNcoUpdateBusy(1) to '0'.
+ when WaitForSysref =>
+ cRfdcNcoState <= WaitForSysref;
+ if cSysrefDlyd(0) = '0' and cSysref = '1' then
+ cDac0xNcoUpdateBusy <= "00"; --Indicates that NCO reset is complete.
+ cRfdcNcoState <= ResetDone;
+ end if;
+
+ -- Wait in this state, until the next NCO reset is requested.
+ when ResetDone =>
+ cRfdcNcoState <= ResetDone;
+ if cDac0xSysrefIntGating = '1' then
+ cRfdcNcoState <= GateSysref;
+ end if;
+ end case;
+ end if;
+ end process;
+
+ -- SYSREF clock crossing from DataClk to ConfigClk and some pipelines.
+ ConfigClkSysref: process(ConfigClk)
+ begin
+ if rising_edge(ConfigClk) then
+ cSysref_ms <= dSysref;
+ cSysref <= cSysref_ms;
+ cSysrefDlyd <= cSysrefDlyd(cSysrefDlyd'high-1) & cSysref;
+ cDac0xSysrefIntGatingDlyd <= cDac0xSysrefIntGating;
+ cNcoPhaseRstDlyd <= cNcoPhaseRstDlyd(cNcoPhaseRstDlyd'high downto 1)
+ & cDac0xNcoUpdateBusy(1);
+ end if;
+ end process;
+
+ -- Assertions
+ process(ConfigClk)
+ begin
+ if falling_edge(ConfigClk) then
+
+ --Check if cNcoPhaseRst is a constant of '1'.
+ assert cNcoPhaseRst = '1'
+ report "NCO phase reset signal should be constant."
+ severity error;
+ -- Check if cNcoUpdateEn is a constant of "100000".
+ assert cNcoUpdateEn = "100000"
+ report "NCO phase reset signal should be constant."
+ severity error;
+ -- Check if NCO reset was requested on the rising edge of SYSREF.
+ if cDac0xSysrefIntGating = '1' and cDac0xSysrefIntGatingDlyd = '0' then
+ assert cSysrefDlyd = "01"
+ report "NCO reset did not start on SYSREF rising edge"
+ severity error;
+ end if;
+
+ -- We wait for couple of clock cycles after NCO done signal is toggled in
+ -- from the RFDC. RFDC uses cDac0xNcoUpdateBusy(1) to indicate NCO reset
+ -- process is done. It is important to wait a minimum of three clock
+ -- cycles before this check is done. This wait is needed for clock
+ -- crossing.
+ if cNcoPhaseRstDlyd(2) = '1' and cNcoPhaseRstDlyd(1) = '0' then
+ assert dNcoResetDone = '1'
+ report "NCO Reset done should have been asserted after NCO " &
+ "reset request is de-asserted"
+ severity error;
+ end if;
+
+ end if;
+ end process;
+
+end RTL;
diff --git a/fpga/usrp3/top/x400/rf/sim/tb_rf_reset_controller.vhd b/fpga/usrp3/top/x400/rf/sim/tb_rf_reset_controller.vhd
new file mode 100644
index 000000000..31a98fd67
--- /dev/null
+++ b/fpga/usrp3/top/x400/rf/sim/tb_rf_reset_controller.vhd
@@ -0,0 +1,436 @@
+--
+-- Copyright 2021 Ettus Research, a National Instruments Brand
+--
+-- SPDX-License-Identifier: LGPL-3.0-or-later
+--
+-- Module: tb_rf_reset_controller
+--
+-- Description:
+--
+-- Testbench for rf_reset_controller.
+--
+
+library IEEE;
+ use IEEE.std_logic_1164.all;
+ use IEEE.numeric_std.all;
+
+library WORK;
+ use WORK.PkgRFDC_REGS_REGMAP.all;
+
+entity tb_rf_reset_controller is
+end tb_rf_reset_controller;
+
+
+architecture RTL of tb_rf_reset_controller is
+
+ component rf_reset_controller
+ port (
+ ConfigClk : in std_logic;
+ DataClk : in std_logic;
+ PllRefClk : in std_logic;
+ RfClk : in std_logic;
+ RfClk2x : in std_logic;
+ DataClk2x : in std_logic;
+ dAdcResetPulse : in std_logic;
+ dDacResetPulse : in std_logic;
+ dAdcDataOutReset_n : out std_logic;
+ r2AdcFirReset_n : out std_logic;
+ rAdcRfdcAxiReset_n : out std_logic;
+ rAdcEnableData : out std_logic;
+ rAdcGearboxReset_n : out std_logic;
+ 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;
+ cSoftwareControl : in std_logic_vector(31 downto 0);
+ cSoftwareStatus : out std_logic_vector(31 downto 0));
+ end component;
+
+ signal cSoftwareStatus : std_logic_vector(31 downto 0);
+ signal r2AdcFirReset_n : std_logic;
+ signal r2DacFirReset_n : std_logic;
+ signal rAdcGearboxReset_n : std_logic;
+ signal rDacGearboxReset_n : std_logic;
+
+ signal cSoftwareControl : std_logic_vector(31 downto 0) := (others => '0');
+ signal dAdcResetPulse : std_logic := '0';
+ signal dDacResetPulse : std_logic := '0';
+
+ constant kSwReset : std_logic := '0';
+ constant kTimedReset : std_logic := '1';
+
+ -- All constants mentioned below are number of the particular clock cycles
+ -- PllRefClk period. For example, kDataClkCycles is the total number of
+ -- DataClk cycles in the PllRefClk period.
+ constant kDataClkCycles : integer := 2;
+ constant kDataClk2xCycles : integer := 4;
+ constant kRfClkCycles : integer := 3;
+ constant kRfClk2xCycles : integer := 6;
+ constant kConfigPer : time := 25 ns;
+ -- Make sure the PllRefClk period is a least common multiple of all the other
+ -- derived clock.
+ constant kPllRefClkPer : time := 12 ns;
+ constant kDataClkPer : time := kPllRefClkPer/2;
+ constant kDataClk2xPer : time := kPllRefClkPer/4;
+ constant kRfClkPer : time := kPllRefClkPer/3;
+ constant kRfClk2xPer : time := kPllRefClkPer/6;
+
+ signal pReset : boolean := false;
+ signal dCount : integer := 0;
+ signal d2Count : integer := 0;
+ signal rCount : integer := 0;
+ signal r2Count : integer := 0;
+
+ signal StopSim : boolean;
+ signal ConfigClk : std_logic := '1';
+ signal RfClk : std_logic := '1';
+ signal RfClk2x : std_logic := '1';
+ signal DataClk : std_logic := '1';
+ signal DataClk2x : std_logic := '1';
+ signal PllRefClk : std_logic := '1';
+
+ signal dAdcDataOutReset_n : std_logic := '0';
+ signal dAdcDataOutResetDlyd_n : std_logic := '0';
+ signal dDacDataInReset_n : std_logic := '0';
+ signal dDacDataInResetDlyd_n : std_logic := '0';
+ signal d2DacFirReset_n : std_logic := '0';
+ signal d2DacFirResetDlyd_n : std_logic := '0';
+ signal rAdcRfdcAxiReset_n : std_logic := '0';
+ signal rAdcRfdcAxiResetDlyd_n : std_logic := '0';
+ signal rDacRfdcAxiReset_n : std_logic := '0';
+ signal rDacRfdcAxiResetDlyd_n : std_logic := '0';
+ signal r2AdcFirResetDlyd_n : std_logic := '0';
+ signal r2DacFirResetDlyd_n : std_logic := '0';
+
+ signal ExpectedSwAdcResetDone : std_logic := '0';
+ signal ExpectedAdcReset : std_logic := '0';
+ signal ExpectedSwDacResetDone : std_logic := '0';
+ signal ExpectedDacReset : std_logic := '0';
+ signal ExpectedAxiAdcResetOut : std_logic := '0';
+ signal ExpectedAxiDacResetOut : std_logic := '0';
+
+ -- Make sure the wait time for reset done check is at least 10 ConfigClk
+ -- cycles to account for all clock domain crossings. We also have some status
+ -- check in the testbench which requires the wait to be additional ConfigClk
+ -- cycles. This wait is in ConfigClk period.
+ constant kResetDoneWait : positive := 10;
+
+ procedure ClkWait(signal clk : in std_logic; X : positive := 1) is
+ begin
+ for i in 1 to X loop
+ wait until rising_edge(clk);
+ end loop;
+ end procedure ClkWait;
+
+ -- Check phase alignment of reset. We want to make sure the reset is asserted
+ -- on the 1st rising clock edge after the rising edge of PllRefClk.
+ procedure CheckAlignment(
+ signal Clk : in std_logic; -- Synchronous reset clock
+ signal Reset_n : in std_logic; -- Synchronous reset
+ signal ResetDlyd_n : inout std_logic; -- Delayed synchronous reset
+ signal PhaseCount : in integer; -- Phase count used to check alignment
+ Message : string) is -- Assertion message
+ begin
+
+ -- Check if reset is asserted on the 1st Clk after the rising edge of
+ -- PllRefClk.
+ if falling_edge(Clk) then
+ ResetDlyd_n <= Reset_n;
+ if Reset_n = '0' and ResetDlyd_n = '1' then
+ assert PhaseCount = 1
+ report Message & " reset is not asserted in the expected time" severity error;
+ end if;
+ end if;
+ end procedure CheckAlignment;
+
+ -- Procedure to generate phase counter that is used to check the alignment of
+ -- phase of all clocks related to PllRefClk.
+ procedure PhaseCounter(
+ signal Clk : in std_logic; -- Clock related to PllRefClk
+ signal Reset : in boolean; -- Reset synchronous to PllRefClk
+ signal PhaseCount : inout integer; -- Phase count of Clk with respect to PllRefClk
+ ClockCycles : integer) is -- Number of Clk clock cycles in PllRefClk period
+ begin
+ if rising_edge(Clk) then
+ if Reset or PhaseCount = ClockCycles-1 then
+ PhaseCount <= 0;
+ else
+ PhaseCount <= PhaseCount+1;
+ end if;
+ end if;
+ end procedure PhaseCounter;
+
+ procedure CheckExpectedValue(
+ signal Clk : in std_logic;
+ signal Actual : in std_logic;
+ signal Expected : in std_logic;
+ Message : string) is
+ begin
+ if falling_edge(Clk) then
+ -- Check if the actual value is as expected.
+ assert std_match(Actual, Expected)
+ report Message & " not as expected" & LF
+ & "Expected = " & std_logic'image(Expected) & LF
+ & "Actual = " & std_logic'image(Actual) severity error;
+ end if;
+ end procedure CheckExpectedValue;
+begin
+
+ ConfigClk <= not ConfigClk after kConfigPer/2 when not StopSim else '0';
+ RfClk <= not RfClk after kRfClkPer/2 when not StopSim else '0';
+ RfClk2x <= not RfClk2x after kRfClk2xPer/2 when not StopSim else '0';
+ DataClk <= not DataClk after kDataClkPer/2 when not StopSim else '0';
+ DataClk2x <= not DataClk2x after kDataClk2xPer/2 when not StopSim else '0';
+ PllRefClk <= not PllRefClk after kPllRefClkPer/2 when not StopSim else '0';
+
+ -- rAdcEnableData is a constant and is not tested.
+ dut: rf_reset_controller
+ port map (
+ ConfigClk => ConfigClk,
+ DataClk => DataClk,
+ PllRefClk => PllRefClk,
+ RfClk => RfClk,
+ RfClk2x => RfClk2x,
+ DataClk2x => DataClk2x,
+ dAdcResetPulse => dAdcResetPulse,
+ dDacResetPulse => dDacResetPulse,
+ dAdcDataOutReset_n => dAdcDataOutReset_n,
+ r2AdcFirReset_n => r2AdcFirReset_n,
+ rAdcRfdcAxiReset_n => rAdcRfdcAxiReset_n,
+ rAdcEnableData => open,
+ rAdcGearboxReset_n => rAdcGearboxReset_n,
+ dDacDataInReset_n => dDacDataInReset_n,
+ r2DacFirReset_n => r2DacFirReset_n,
+ d2DacFirReset_n => d2DacFirReset_n,
+ rDacRfdcAxiReset_n => rDacRfdcAxiReset_n,
+ rDacGearboxReset_n => rDacGearboxReset_n,
+ cSoftwareControl => cSoftwareControl,
+ cSoftwareStatus => cSoftwareStatus
+ );
+
+ main: process
+
+ -- Procedure to generate software reset and expected DUR reset output.
+ procedure StrobeReset(
+ signal TimedReset : out std_logic; -- SW Reset control
+ signal ExpectedResetOut : out std_logic; -- Expected reset values
+ signal ExpectedAxiResetOut : out std_logic; -- Expected reset values
+ signal SwResetStatus : out std_logic; -- Expected SW reset status
+ SwReset : integer; -- SW Reset control
+ ResetType : std_logic; -- 0 = SW reset, 1 = UHD timed reset
+ ResetWait : positive := 1) is -- Wait time for test iteration
+ begin
+ if ResetType = kSwReset then
+ -- Assert software reset control on the rising edge of ConfigClk. Also
+ -- change the expected status to don't care as the status will change
+ -- only after few ConfigClk period.
+ ClkWait(ConfigClk);
+ TimedReset <= '0';
+ cSoftwareControl(SwReset) <= '1';
+ SwResetStatus <= '-';
+ ExpectedResetOut <= '-';
+ ExpectedAxiResetOut <= '-';
+ ClkWait(ConfigClk, 1);
+ SwResetStatus <= '0';
+ -- Wait for additional ConfigClk before changing the expected reset
+ -- value to '0'. This wait is needed to account for pipeline and clock
+ -- crossing delays.
+ ClkWait(ConfigClk, 1);
+ -- Changed expected reset output to '0' (active low).
+ ExpectedResetOut <= '0';
+ ExpectedAxiResetOut <= '0';
+ ClkWait(ConfigClk,1);
+ -- SW reset status should be asserted after 3 ConfigClk periods. This
+ -- wait is needed to account for pipeline and clock crossings.
+ SwResetStatus <= '1';
+ -- De-assert software reset
+ ClkWait(ConfigClk,2);
+ cSoftwareControl(SwReset) <= '0';
+ -- Change the expected reset outputs to don't care as it will take few
+ -- PllRefClk cycles and ConfigClk to DataClock crossing.
+ ExpectedAxiResetOut <= '-';
+ ClkWait(ConfigClk,1);
+ ExpectedAxiResetOut <= '1';
+ -- After few ConfigClk cycles, all reset outputs should be de-asserted.
+ ClkWait(ConfigClk,1);
+ ExpectedResetOut <= '-';
+ ClkWait(ConfigClk,2);
+ ExpectedResetOut <= '1';
+ -- Wait for ResetWait time before exiting the test iteration.
+ ClkWait(ConfigClk,ResetWait);
+ else -- Timed command.
+ ClkWait(DataClk,ResetWait);
+ TimedReset <= '1';
+ -- RFDC should not be asserted with timed reset.
+ ExpectedAxiResetOut <= '1';
+ -- Strobe the reset pulse only for one DataClk period.
+ ClkWait(DataClk,1);
+ TimedReset <= '0';
+ ClkWait(PllRefClk,2);
+ ExpectedResetOut <= '-';
+ -- Wait for 3 PllRefClk to account for pipeline delays.
+ ClkWait(PllRefClk,1);
+ ExpectedResetOut <= '0';
+ ClkWait(PllRefClk,2);
+ ExpectedResetOut <= '-';
+ -- Reset should be asserted only for two PllRefClk cycles.
+ ClkWait(PllRefClk,2);
+ ExpectedResetOut <= '1';
+ ClkWait(DataClk,ResetWait); -- Wait between test.
+ end if;
+ end procedure StrobeReset;
+
+ begin
+ -- Expected power on reset values.
+ ExpectedAdcReset <= '0';
+ ExpectedAxiAdcResetOut <= '0';
+ ExpectedDacReset <= '0';
+ ExpectedAxiDacResetOut <= '0';
+
+ ClkWait(ConfigClk,1);
+ ClkWait(RfClk,1);
+ ExpectedAxiAdcResetOut <= '1';
+ ExpectedAxiDacResetOut <= '1';
+ ClkWait(ConfigClk,1);
+ ExpectedAdcReset <= '-';
+ ExpectedDacReset <= '-';
+ ClkWait(ConfigClk,1);
+ ExpectedAdcReset <= '1';
+ ExpectedDacReset <= '1';
+ ClkWait(ConfigClk,5);
+ -- This reset is for simulation to have a common reference to check for
+ -- clock alignment.
+ ClkWait(PllRefClk,1);
+ pReset <= true;
+ ClkWait(PllRefClk,1);
+ pReset <= false;
+ ClkWait(PllRefClk,1);
+
+ ---------------------------------------------------------------------------
+ -- Test resets from software
+ ---------------------------------------------------------------------------
+
+ -----------------------------------
+ -- ADC
+ -----------------------------------
+
+ StrobeReset(dAdcResetPulse, ExpectedAdcReset, ExpectedAxiAdcResetOut,
+ ExpectedSwAdcResetDone, kADC_RESET, kSwReset, kResetDoneWait);
+
+ -- Align reset to the rising edge of PllRefClk
+ ClkWait(PllRefClk,1);
+ StrobeReset(dAdcResetPulse, ExpectedAdcReset, ExpectedAxiAdcResetOut,
+ ExpectedSwAdcResetDone, kADC_RESET, kTimedReset, kResetDoneWait);
+ StrobeReset(dAdcResetPulse, ExpectedAdcReset, ExpectedAxiAdcResetOut,
+ ExpectedSwAdcResetDone, kADC_RESET, kSwReset, kResetDoneWait);
+
+ -- Align reset to the falling edge of PllRefClk.
+ ClkWait(PllRefClk,1);
+ ClkWait(DataClk,1);
+ StrobeReset(dAdcResetPulse, ExpectedAdcReset, ExpectedAxiAdcResetOut,
+ ExpectedSwAdcResetDone, kADC_RESET, kTimedReset, kResetDoneWait);
+
+ -----------------------------------
+ -- DAC
+ -----------------------------------
+
+ StrobeReset(dDacResetPulse, ExpectedDacReset, ExpectedAxiDacResetOut,
+ ExpectedSwDacResetDone, kDAC_RESET, kSwReset, kResetDoneWait);
+
+ -- Align reset to the rising edge of PllRefClk.
+ ClkWait(PllRefClk,1);
+ StrobeReset(dDacResetPulse, ExpectedDacReset, ExpectedAxiDacResetOut,
+ ExpectedSwDacResetDone, kDAC_RESET, kTimedReset, kResetDoneWait);
+ StrobeReset(dDacResetPulse, ExpectedDacReset, ExpectedAxiDacResetOut,
+ ExpectedSwDacResetDone, kDAC_RESET, kSwReset, kResetDoneWait);
+
+ -- Align reset to the falling edge of PllRefClk.
+ ClkWait(PllRefClk,1);
+ ClkWait(DataClk,1);
+ StrobeReset(dDacResetPulse, ExpectedDacReset, ExpectedAxiDacResetOut,
+ ExpectedSwDacResetDone, kDAC_RESET, kTimedReset, kResetDoneWait);
+
+ StopSim <= true;
+ wait;
+ end process main;
+
+ -----------------------------------------------------------------------------
+ -- Reset from software and UHD timed command
+ -----------------------------------------------------------------------------
+ -- Check if the correct resets are getting asserted when UHD timed reset or
+ -- software reset is asserted. Except for RFDC AXI-S reset all other resets
+ -- should be strobed for UHD timed reset.
+ -----------------------------------------------------------------------------
+
+ -- Check if the reset done status is getting asserted as expected.
+ CheckExpectedValue(ConfigClk, cSoftwareStatus(kADC_SEQ_DONE),
+ ExpectedSwAdcResetDone, "ADC reset done status");
+ CheckExpectedValue(ConfigClk, cSoftwareStatus(kDAC_SEQ_DONE),
+ ExpectedSwDacResetDone, "DAC reset done status");
+
+ -- Check if resets state in DataClk is as expected.
+ CheckExpectedValue(DataClk, dAdcDataOutReset_n, ExpectedAdcReset,
+ "ADC data out reset");
+ CheckExpectedValue(DataClk, dDacDataInReset_n, ExpectedDacReset,
+ "DAC data out reset");
+
+ -- Check if resets state in DataClk2x is as expected.
+ CheckExpectedValue(DataClk2x, d2DacFirReset_n, ExpectedDacReset,
+ "400M interpolator reset");
+
+ ---- Check if resets state in RfClk2x is as expected.
+ CheckExpectedValue(RfClk2x, r2AdcFirReset_n, ExpectedAdcReset,
+ "ADC re-sampler reset");
+ CheckExpectedValue(RfClk2x, r2DacFirReset_n, ExpectedDacReset,
+ "DAC re-sampler reset");
+
+ ---- Check if resets state in RfClk is as expected.
+ CheckExpectedValue(RfClk, rAdcRfdcAxiReset_n, ExpectedAxiAdcResetOut,
+ "ADC RFDC AXI-S interface reset");
+ CheckExpectedValue(RfClk, rDacRfdcAxiReset_n, ExpectedAxiDacResetOut,
+ "DAC RFDC AXI-S interface reset");
+ CheckExpectedValue(RfClk, rAdcGearboxReset_n, ExpectedAdcReset,
+ "ADC gearbox reset");
+ CheckExpectedValue(RfClk, rDacGearboxReset_n, ExpectedDacReset,
+ "DAC gearbox reset");
+
+
+ -----------------------------------------------------------------------------
+ -- Reset alignment checks for resets
+ -----------------------------------------------------------------------------
+
+ -----------------------------------
+ -- Clock counter
+ -----------------------------------
+ -- We use counters to check the phase of all the derived clocks with respect
+ -- to PllRefClk. Each counter will rollover at the rising edge of PllRefClk.
+ -----------------------------------
+ PhaseCounter(DataClk, pReset, dCount, kDataClkCycles);
+ PhaseCounter(DataClk2x, pReset, d2Count, kDataClk2xCycles);
+ PhaseCounter(RfClk, pReset, rCount, kRfClkCycles);
+ PhaseCounter(RfClk2x, pReset, r2Count, kRfClk2xCycles);
+
+ -- Check for DataClk based synchronous reset alignment to PllRefClk.
+ CheckAlignment(DataClk, dAdcDataOutReset_n, dAdcDataOutResetDlyd_n, dCount,
+ "ADC data out");
+ CheckAlignment(DataClk, dDacDataInReset_n, dDacDataInResetDlyd_n, dCount,
+ "DAC data in");
+
+ -- Check for DataClk2x based synchronous reset alignment to PllRefClk.
+ CheckAlignment(DataClk2x, d2DacFirReset_n, d2DacFirResetDlyd_n, d2Count,
+ "400M DAC FIR Filter");
+
+ -- Check for RfClk based synchronous reset alignment to PllRefClk.
+ CheckAlignment(RfClk, rAdcRfdcAxiReset_n, rAdcRfdcAxiResetDlyd_n, rCount,
+ "ADC RFDC reset ");
+ CheckAlignment(RfClk, rDacRfdcAxiReset_n, rDacRfdcAxiResetDlyd_n, rCount,
+ "DAC RFDC reset ");
+
+ -- Check for RfClk2x based synchronous reset alignment to PllRefClk.
+ CheckAlignment(RfClk2x, r2AdcFirReset_n, r2AdcFirResetDlyd_n, r2Count,
+ "ADC decimation filter reset ");
+ CheckAlignment(RfClk2x, r2DacFirReset_n, r2DacFirResetDlyd_n, r2Count,
+ "DAC interpolation filter reset ");
+
+end RTL;