Files
b210-k7-fpga/top/x400/rf/sim/tb_rf_nco_reset.vhd
T
Wade Fife 77a66a4de4 x400: sim: Move testbenches to sim folder
Original-commit: c0f9496d59947f8c9411b28d63d0c8e6244102a0
2021-06-17 08:16:59 -05:00

282 lines
9.9 KiB
VHDL

--
-- 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;