x400: sim: Move testbenches to sim folder
Original-commit: c0f9496d59947f8c9411b28d63d0c8e6244102a0
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
#
|
||||
# Copyright 2021 Ettus Research, a National Instruments Brand
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
#
|
||||
|
||||
#-------------------------------------------------
|
||||
# Top-of-Makefile
|
||||
#-------------------------------------------------
|
||||
# Define BASE_DIR to point to the "top" dir. Note:
|
||||
# UHD_FPGA_DIR must be passed into this Makefile.
|
||||
BASE_DIR = ../../..
|
||||
# Include viv_sim_preample after defining BASE_DIR
|
||||
include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak
|
||||
|
||||
#-------------------------------------------------
|
||||
# Design Specific
|
||||
#-------------------------------------------------
|
||||
# Define part using PART_ID (<device>/<package>/<speedgrade>)
|
||||
ARCH = zynquplusRFSOC
|
||||
PART_ID = xczu28dr/ffvg1517/-1/e
|
||||
|
||||
# Include makefiles and sources for the DUT and its dependencies
|
||||
include $(BASE_DIR)/../lib/fifo/Makefile.srcs
|
||||
include $(BASE_DIR)/../lib/axi/Makefile.srcs
|
||||
include $(BASE_DIR)/../lib/control/Makefile.srcs
|
||||
|
||||
DESIGN_SRCS += $(abspath \
|
||||
$(FIFO_SRCS) \
|
||||
$(AXI_SRCS) \
|
||||
$(CONTROL_LIB_SRCS) \
|
||||
)
|
||||
|
||||
include ../common/Makefile.srcs
|
||||
include ../100m/Makefile.srcs
|
||||
include ../200m/Makefile.srcs
|
||||
include ../400m/Makefile.srcs
|
||||
|
||||
DESIGN_SRCS += $(abspath \
|
||||
../../regmap/PkgRFDC_REGS_REGMAP.vhd \
|
||||
$(RF_COMMON_SRCS) \
|
||||
$(RF_100M_SRCS) \
|
||||
$(RF_200M_SRCS) \
|
||||
$(RF_400M_SRCS) \
|
||||
)
|
||||
|
||||
#-------------------------------------------------
|
||||
# IP Specific
|
||||
#-------------------------------------------------
|
||||
# If simulation contains IP, define the IP_DIR and point
|
||||
# it to the base level IP directory
|
||||
IP_DIR = $(BASE_DIR)/x400/ip
|
||||
LIB_IP_DIR = $(BASE_DIR)/../lib/ip
|
||||
|
||||
# Include makefiles and sources for all IP components
|
||||
# *after* defining the IP_DIR
|
||||
#
|
||||
# These TBs don't use any IP yet :)
|
||||
|
||||
#-------------------------------------------------
|
||||
# Testbench Specific
|
||||
#-------------------------------------------------
|
||||
include $(BASE_DIR)/../sim/general/Makefile.srcs
|
||||
|
||||
# Define only one top-level module
|
||||
SIM_TOP = rf_all_tb
|
||||
|
||||
# Simulation runtime in microseconds
|
||||
SIM_RUNTIME_US = 1000
|
||||
|
||||
SIM_SRCS = \
|
||||
$(abspath tb_adc_gearbox_2x1.vhd ) \
|
||||
$(abspath tb_adc_gearbox_2x4.vhd ) \
|
||||
$(abspath tb_adc_gearbox_8x4.vhd ) \
|
||||
$(abspath tb_capture_sysref.vhd ) \
|
||||
$(abspath tb_dac_gearbox_12x8.vhd ) \
|
||||
$(abspath tb_dac_gearbox_4x2.vhd ) \
|
||||
$(abspath tb_dac_gearbox_6x12.vhd ) \
|
||||
$(abspath tb_ddc_400m_saturate.vhd ) \
|
||||
$(abspath tb_duc_400m_saturate.vhd ) \
|
||||
$(abspath tb_rf_nco_reset.vhd ) \
|
||||
$(abspath tb_rf_reset_controller.vhd) \
|
||||
$(abspath rf_all_tb.sv ) \
|
||||
|
||||
#-------------------------------------------------
|
||||
# Bottom-of-Makefile
|
||||
#-------------------------------------------------
|
||||
# Include all simulator specific makefiles here
|
||||
# Each should define a unique target to simulate
|
||||
# e.g. xsim, vsim, etc and a common "clean" target
|
||||
include $(BASE_DIR)/../tools/make/viv_simulator.mak
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user