From c0f9496d59947f8c9411b28d63d0c8e6244102a0 Mon Sep 17 00:00:00 2001 From: Wade Fife Date: Fri, 11 Jun 2021 14:34:06 -0500 Subject: x400: sim: Move testbenches to sim folder --- fpga/usrp3/top/x400/rf/sim/Makefile | 91 +++++ fpga/usrp3/top/x400/rf/sim/rf_all_tb.sv | 57 +++ fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_2x1.vhd | 186 +++++++++ fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_2x4.vhd | 197 ++++++++++ fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_8x4.vhd | 206 ++++++++++ fpga/usrp3/top/x400/rf/sim/tb_capture_sysref.vhd | 119 ++++++ fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_12x8.vhd | 197 ++++++++++ fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_4x2.vhd | 168 ++++++++ fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_6x12.vhd | 187 +++++++++ .../usrp3/top/x400/rf/sim/tb_ddc_400m_saturate.vhd | 125 ++++++ .../usrp3/top/x400/rf/sim/tb_duc_400m_saturate.vhd | 133 +++++++ fpga/usrp3/top/x400/rf/sim/tb_rf_nco_reset.vhd | 281 +++++++++++++ .../top/x400/rf/sim/tb_rf_reset_controller.vhd | 436 +++++++++++++++++++++ fpga/usrp3/top/x400/rf/testbench/Makefile | 91 ----- fpga/usrp3/top/x400/rf/testbench/rf_all_tb.sv | 57 --- .../top/x400/rf/testbench/tb_adc_gearbox_2x1.vhd | 186 --------- .../top/x400/rf/testbench/tb_adc_gearbox_2x4.vhd | 197 ---------- .../top/x400/rf/testbench/tb_adc_gearbox_8x4.vhd | 206 ---------- .../top/x400/rf/testbench/tb_capture_sysref.vhd | 119 ------ .../top/x400/rf/testbench/tb_dac_gearbox_12x8.vhd | 197 ---------- .../top/x400/rf/testbench/tb_dac_gearbox_4x2.vhd | 168 -------- .../top/x400/rf/testbench/tb_dac_gearbox_6x12.vhd | 187 --------- .../top/x400/rf/testbench/tb_ddc_400m_saturate.vhd | 125 ------ .../top/x400/rf/testbench/tb_duc_400m_saturate.vhd | 133 ------- .../top/x400/rf/testbench/tb_rf_nco_reset.vhd | 281 ------------- .../x400/rf/testbench/tb_rf_reset_controller.vhd | 436 --------------------- 26 files changed, 2383 insertions(+), 2383 deletions(-) create mode 100644 fpga/usrp3/top/x400/rf/sim/Makefile create mode 100644 fpga/usrp3/top/x400/rf/sim/rf_all_tb.sv create mode 100644 fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_2x1.vhd create mode 100644 fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_2x4.vhd create mode 100644 fpga/usrp3/top/x400/rf/sim/tb_adc_gearbox_8x4.vhd create mode 100644 fpga/usrp3/top/x400/rf/sim/tb_capture_sysref.vhd create mode 100644 fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_12x8.vhd create mode 100644 fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_4x2.vhd create mode 100644 fpga/usrp3/top/x400/rf/sim/tb_dac_gearbox_6x12.vhd create mode 100644 fpga/usrp3/top/x400/rf/sim/tb_ddc_400m_saturate.vhd create mode 100644 fpga/usrp3/top/x400/rf/sim/tb_duc_400m_saturate.vhd create mode 100644 fpga/usrp3/top/x400/rf/sim/tb_rf_nco_reset.vhd create mode 100644 fpga/usrp3/top/x400/rf/sim/tb_rf_reset_controller.vhd delete mode 100644 fpga/usrp3/top/x400/rf/testbench/Makefile delete mode 100644 fpga/usrp3/top/x400/rf/testbench/rf_all_tb.sv delete mode 100644 fpga/usrp3/top/x400/rf/testbench/tb_adc_gearbox_2x1.vhd delete mode 100644 fpga/usrp3/top/x400/rf/testbench/tb_adc_gearbox_2x4.vhd delete mode 100644 fpga/usrp3/top/x400/rf/testbench/tb_adc_gearbox_8x4.vhd delete mode 100644 fpga/usrp3/top/x400/rf/testbench/tb_capture_sysref.vhd delete mode 100644 fpga/usrp3/top/x400/rf/testbench/tb_dac_gearbox_12x8.vhd delete mode 100644 fpga/usrp3/top/x400/rf/testbench/tb_dac_gearbox_4x2.vhd delete mode 100644 fpga/usrp3/top/x400/rf/testbench/tb_dac_gearbox_6x12.vhd delete mode 100644 fpga/usrp3/top/x400/rf/testbench/tb_ddc_400m_saturate.vhd delete mode 100644 fpga/usrp3/top/x400/rf/testbench/tb_duc_400m_saturate.vhd delete mode 100644 fpga/usrp3/top/x400/rf/testbench/tb_rf_nco_reset.vhd delete mode 100644 fpga/usrp3/top/x400/rf/testbench/tb_rf_reset_controller.vhd (limited to 'fpga/usrp3/top/x400') 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 (//) +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; diff --git a/fpga/usrp3/top/x400/rf/testbench/Makefile b/fpga/usrp3/top/x400/rf/testbench/Makefile deleted file mode 100644 index 08b62f4fb..000000000 --- a/fpga/usrp3/top/x400/rf/testbench/Makefile +++ /dev/null @@ -1,91 +0,0 @@ -# -# 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 (//) -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/testbench/rf_all_tb.sv b/fpga/usrp3/top/x400/rf/testbench/rf_all_tb.sv deleted file mode 100644 index c64bcf923..000000000 --- a/fpga/usrp3/top/x400/rf/testbench/rf_all_tb.sv +++ /dev/null @@ -1,57 +0,0 @@ -// -// 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/testbench/tb_adc_gearbox_2x1.vhd b/fpga/usrp3/top/x400/rf/testbench/tb_adc_gearbox_2x1.vhd deleted file mode 100644 index f5c58ccf5..000000000 --- a/fpga/usrp3/top/x400/rf/testbench/tb_adc_gearbox_2x1.vhd +++ /dev/null @@ -1,186 +0,0 @@ --- --- 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/testbench/tb_adc_gearbox_2x4.vhd b/fpga/usrp3/top/x400/rf/testbench/tb_adc_gearbox_2x4.vhd deleted file mode 100644 index b36f7de54..000000000 --- a/fpga/usrp3/top/x400/rf/testbench/tb_adc_gearbox_2x4.vhd +++ /dev/null @@ -1,197 +0,0 @@ --- --- 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/testbench/tb_adc_gearbox_8x4.vhd b/fpga/usrp3/top/x400/rf/testbench/tb_adc_gearbox_8x4.vhd deleted file mode 100644 index 88e520a6b..000000000 --- a/fpga/usrp3/top/x400/rf/testbench/tb_adc_gearbox_8x4.vhd +++ /dev/null @@ -1,206 +0,0 @@ --- --- 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/testbench/tb_capture_sysref.vhd b/fpga/usrp3/top/x400/rf/testbench/tb_capture_sysref.vhd deleted file mode 100644 index eb5cbcf08..000000000 --- a/fpga/usrp3/top/x400/rf/testbench/tb_capture_sysref.vhd +++ /dev/null @@ -1,119 +0,0 @@ --- --- 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/testbench/tb_dac_gearbox_12x8.vhd b/fpga/usrp3/top/x400/rf/testbench/tb_dac_gearbox_12x8.vhd deleted file mode 100644 index cde766cbd..000000000 --- a/fpga/usrp3/top/x400/rf/testbench/tb_dac_gearbox_12x8.vhd +++ /dev/null @@ -1,197 +0,0 @@ --- --- 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/testbench/tb_dac_gearbox_4x2.vhd b/fpga/usrp3/top/x400/rf/testbench/tb_dac_gearbox_4x2.vhd deleted file mode 100644 index 45fe9e150..000000000 --- a/fpga/usrp3/top/x400/rf/testbench/tb_dac_gearbox_4x2.vhd +++ /dev/null @@ -1,168 +0,0 @@ --- --- 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/testbench/tb_dac_gearbox_6x12.vhd b/fpga/usrp3/top/x400/rf/testbench/tb_dac_gearbox_6x12.vhd deleted file mode 100644 index 950ed8db1..000000000 --- a/fpga/usrp3/top/x400/rf/testbench/tb_dac_gearbox_6x12.vhd +++ /dev/null @@ -1,187 +0,0 @@ --- --- 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/testbench/tb_ddc_400m_saturate.vhd b/fpga/usrp3/top/x400/rf/testbench/tb_ddc_400m_saturate.vhd deleted file mode 100644 index 37f570d87..000000000 --- a/fpga/usrp3/top/x400/rf/testbench/tb_ddc_400m_saturate.vhd +++ /dev/null @@ -1,125 +0,0 @@ --- --- 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/testbench/tb_duc_400m_saturate.vhd b/fpga/usrp3/top/x400/rf/testbench/tb_duc_400m_saturate.vhd deleted file mode 100644 index e3117bdd6..000000000 --- a/fpga/usrp3/top/x400/rf/testbench/tb_duc_400m_saturate.vhd +++ /dev/null @@ -1,133 +0,0 @@ --- --- 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/testbench/tb_rf_nco_reset.vhd b/fpga/usrp3/top/x400/rf/testbench/tb_rf_nco_reset.vhd deleted file mode 100644 index 066dd5f4b..000000000 --- a/fpga/usrp3/top/x400/rf/testbench/tb_rf_nco_reset.vhd +++ /dev/null @@ -1,281 +0,0 @@ --- --- 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/testbench/tb_rf_reset_controller.vhd b/fpga/usrp3/top/x400/rf/testbench/tb_rf_reset_controller.vhd deleted file mode 100644 index 31a98fd67..000000000 --- a/fpga/usrp3/top/x400/rf/testbench/tb_rf_reset_controller.vhd +++ /dev/null @@ -1,436 +0,0 @@ --- --- 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; -- cgit v1.2.3