261 lines
8.8 KiB
VHDL
261 lines
8.8 KiB
VHDL
--
|
|
-- Copyright 2021 Ettus Research, a National Instruments Brand
|
|
--
|
|
-- SPDX-License-Identifier: LGPL-3.0-or-later
|
|
--
|
|
-- Module: x410_rf_reset_controller
|
|
--
|
|
-- Description:
|
|
--
|
|
-- Control RFDC, ADC, and DAC resets.
|
|
--
|
|
|
|
library IEEE;
|
|
use IEEE.std_logic_1164.all;
|
|
use IEEE.numeric_std.all;
|
|
|
|
library WORK;
|
|
use WORK.PkgRFDC_REGS_REGMAP.all;
|
|
|
|
entity x410_rf_reset_controller is
|
|
port(
|
|
-- Clocks
|
|
-- Config clock is async to all the others.
|
|
ConfigClk : in std_logic;
|
|
DataClk : in std_logic;
|
|
PllRefClk : in std_logic;
|
|
RfClk : in std_logic;
|
|
RfClk2x : in std_logic;
|
|
DataClk2x : in std_logic;
|
|
|
|
-- Master resets from the Radio
|
|
dAdcResetPulse : in std_logic;
|
|
dDacResetPulse : in std_logic;
|
|
|
|
-- ADC Resets
|
|
dAdcDataOutReset_n : out std_logic;
|
|
r2AdcFirReset_n : out std_logic;
|
|
rAdcRfdcAxiReset_n : out std_logic;
|
|
rAdcEnableData : out std_logic;
|
|
rAdcGearboxReset_n : out std_logic;
|
|
|
|
-- DAC Resets
|
|
dDacDataInReset_n : out std_logic;
|
|
r2DacFirReset_n : out std_logic;
|
|
d2DacFirReset_n : out std_logic;
|
|
rDacRfdcAxiReset_n : out std_logic;
|
|
rDacGearboxReset_n : out std_logic;
|
|
|
|
-- SW Control and Status
|
|
-- Control to initiate resets to RFDC and decimation block including the
|
|
-- gearboxes. The reset status is a sticky status of both ADC and DAC.
|
|
cSoftwareControl : in std_logic_vector(31 downto 0);
|
|
cSoftwareStatus : out std_logic_vector(31 downto 0)
|
|
);
|
|
end x410_rf_reset_controller;
|
|
|
|
|
|
architecture RTL of x410_rf_reset_controller is
|
|
|
|
component pulse_synchronizer
|
|
generic (
|
|
MODE : string := "PULSE";
|
|
STAGES : integer := 2);
|
|
port (
|
|
clk_a : in std_logic;
|
|
rst_a : in std_logic;
|
|
pulse_a : in std_logic;
|
|
busy_a : out std_logic;
|
|
clk_b : in std_logic;
|
|
pulse_b : out std_logic);
|
|
end component;
|
|
|
|
-- POR value for all resets are high.
|
|
signal cTriggerAdcReset : std_logic := '1';
|
|
signal cTriggerAdcResetDlyd : std_logic := '1';
|
|
signal cTriggerDacReset : std_logic := '1';
|
|
signal cTriggerDacResetDlyd : std_logic := '1';
|
|
|
|
signal dTriggerAdcReset_ms : std_logic := '1';
|
|
signal dTriggerAdcReset : std_logic := '1';
|
|
signal dTriggerDacReset_ms : std_logic := '1';
|
|
signal dTriggerDacReset : std_logic := '1';
|
|
|
|
-- POR value of all reset done signals are set to low.
|
|
signal cTriggerAdcResetDone_ms : std_logic := '0';
|
|
signal cTriggerAdcResetDone : std_logic := '0';
|
|
signal cAdcResetDoneSticky : std_logic := '0';
|
|
signal cTriggerDacResetDone_ms : std_logic := '0';
|
|
signal cTriggerDacResetDone : std_logic := '0';
|
|
signal cDacResetDoneSticky : std_logic := '0';
|
|
|
|
attribute ASYNC_REG : string;
|
|
attribute ASYNC_REG of dTriggerAdcReset : signal is "TRUE";
|
|
attribute ASYNC_REG of dTriggerDacReset : signal is "TRUE";
|
|
attribute ASYNC_REG of cTriggerAdcResetDone : signal is "TRUE";
|
|
attribute ASYNC_REG of cTriggerDacResetDone : signal is "TRUE";
|
|
attribute ASYNC_REG of dTriggerAdcReset_ms : signal is "TRUE";
|
|
attribute ASYNC_REG of dTriggerDacReset_ms : signal is "TRUE";
|
|
attribute ASYNC_REG of cTriggerAdcResetDone_ms : signal is "TRUE";
|
|
attribute ASYNC_REG of cTriggerDacResetDone_ms : signal is "TRUE";
|
|
|
|
signal cTriggerAdcGearboxReset : std_logic;
|
|
signal cTriggerDacGearboxReset : std_logic;
|
|
|
|
signal dTriggerAdcGearboxReset : std_logic;
|
|
signal dTriggerDacGearboxReset : std_logic;
|
|
|
|
begin
|
|
|
|
-- rAdcEnableData is set to '1' as we don't control the flow of RX data.
|
|
rAdcEnableData <= '1';
|
|
|
|
cTriggerAdcReset <= cSoftwareControl(kADC_RESET);
|
|
cTriggerDacReset <= cSoftwareControl(kDAC_RESET);
|
|
cTriggerAdcGearboxReset <= cSoftwareControl(kADC_GEARBOX_RESET);
|
|
cTriggerDacGearboxReset <= cSoftwareControl(kDAC_GEARBOX_RESET);
|
|
|
|
cSoftwareStatus <= (
|
|
kADC_SEQ_DONE => cAdcResetDoneSticky,
|
|
kDAC_SEQ_DONE => cDacResetDoneSticky,
|
|
others => '0'
|
|
);
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- High-Level Resets Using ConfigClk
|
|
-----------------------------------------------------------------------------
|
|
-- Pass the master FSM reset around to the other clock domains and then
|
|
-- return them back to the ConfigClk domain. This is also a handy way to
|
|
-- prove all your clocks are toggling to some extent.
|
|
-----------------------------------------------------------------------------
|
|
|
|
SeqResetDataClk : process(DataClk)
|
|
begin
|
|
if rising_edge(DataClk) then
|
|
-- double-syncs have no sync reset!
|
|
dTriggerAdcReset_ms <= cTriggerAdcReset;
|
|
dTriggerAdcReset <= dTriggerAdcReset_ms;
|
|
dTriggerDacReset_ms <= cTriggerDacReset;
|
|
dTriggerDacReset <= dTriggerDacReset_ms;
|
|
end if;
|
|
end process;
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- Reset Sequence Done Status
|
|
-----------------------------------------------------------------------------
|
|
-- Now back to ConfigClk! We provide the status for all software controlled
|
|
-- resets. We move the signal from ConfigClk to DataClk domain and move it
|
|
-- back to ConfigClk domain. This just proves that DataClk is toggling and
|
|
-- the reset requested by software is sampled in the DataClk.
|
|
-----------------------------------------------------------------------------
|
|
|
|
SeqResetDone : process(ConfigClk)
|
|
begin
|
|
if rising_edge(ConfigClk) then
|
|
-- double-syncs have no sync reset!
|
|
cTriggerAdcResetDone_ms <= dTriggerAdcReset;
|
|
cTriggerAdcResetDone <= cTriggerAdcResetDone_ms;
|
|
cTriggerDacResetDone_ms <= dTriggerDacReset;
|
|
cTriggerDacResetDone <= cTriggerDacResetDone_ms;
|
|
end if;
|
|
end process;
|
|
|
|
-- ADC reset done
|
|
SwAdcResetDone: process(ConfigClk)
|
|
begin
|
|
if rising_edge(ConfigClk) then
|
|
cTriggerAdcResetDlyd <= cTriggerAdcReset;
|
|
-- De-assert reset status on the rising edge of SW ADC reset.
|
|
if cTriggerAdcReset = '1' and cTriggerAdcResetDlyd = '0' then
|
|
cAdcResetDoneSticky <= '0';
|
|
-- Assert and hold the ADC reset status on ADC reset strobe.
|
|
elsif cTriggerAdcResetDone = '1' then
|
|
cAdcResetDoneSticky <= '1';
|
|
end if;
|
|
end if;
|
|
end process SwAdcResetDone;
|
|
|
|
-- DAC reset done
|
|
SwDacResetDone: process(ConfigClk)
|
|
begin
|
|
if rising_edge(ConfigClk) then
|
|
cTriggerDacResetDlyd <= cTriggerDacReset;
|
|
-- De-assert reset status on the rising edge of SW DAC reset.
|
|
if cTriggerDacReset = '1' and cTriggerDacResetDlyd = '0' then
|
|
cDacResetDoneSticky <= '0';
|
|
-- Assert and hold the DAC reset status on DAC reset strobe.
|
|
elsif cTriggerDacResetDone = '1' then
|
|
cDacResetDoneSticky <= '1';
|
|
end if;
|
|
end if;
|
|
end process SwDacResetDone;
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- transfer posedge gearbox triggers to DataClk domain
|
|
-----------------------------------------------------------------------------
|
|
adc_gearbox_reset_pulse_sync : pulse_synchronizer
|
|
generic map (
|
|
MODE => "POSEDGE",
|
|
STAGES => 2
|
|
)
|
|
port map (
|
|
clk_a => ConfigClk,
|
|
rst_a => '0',
|
|
pulse_a => cTriggerAdcGearboxReset,
|
|
busy_a => open,
|
|
clk_b => DataClk,
|
|
pulse_b => dTriggerAdcGearboxReset
|
|
);
|
|
|
|
dac_gearbox_reset_pulse_sync : pulse_synchronizer
|
|
generic map (
|
|
MODE => "POSEDGE",
|
|
STAGES => 2
|
|
)
|
|
port map (
|
|
clk_a => ConfigClk,
|
|
rst_a => '0',
|
|
pulse_a => cTriggerDacGearboxReset,
|
|
busy_a => open,
|
|
clk_b => DataClk,
|
|
pulse_b => dTriggerDacGearboxReset
|
|
);
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- rf_reset Instances
|
|
-----------------------------------------------------------------------------
|
|
|
|
AdcResets: entity work.rf_reset (RTL)
|
|
port map (
|
|
DataClk => DataClk,
|
|
PllRefClk => PllRefClk,
|
|
RfClk => RfClk,
|
|
RfClk2x => RfClk2x,
|
|
DataClk2x => DataClk2x,
|
|
dTimedReset => (dAdcResetPulse or dTriggerAdcGearboxReset),
|
|
dSwReset => dTriggerAdcReset,
|
|
dReset_n => dAdcDataOutReset_n,
|
|
d2Reset_n => open,
|
|
r2Reset_n => r2AdcFirReset_n,
|
|
rAxiReset_n => rAdcRfdcAxiReset_n,
|
|
rReset_n => rAdcGearboxReset_n
|
|
);
|
|
|
|
DacResets: entity work.rf_reset (RTL)
|
|
port map (
|
|
DataClk => DataClk,
|
|
PllRefClk => PllRefClk,
|
|
RfClk => RfClk,
|
|
RfClk2x => RfClk2x,
|
|
DataClk2x => DataClk2x,
|
|
dTimedReset => (dDacResetPulse or dTriggerDacGearboxReset),
|
|
dSwReset => dTriggerDacReset,
|
|
dReset_n => dDacDataInReset_n,
|
|
d2Reset_n => d2DacFirReset_n,
|
|
r2Reset_n => r2DacFirReset_n,
|
|
rAxiReset_n => rDacRfdcAxiReset_n,
|
|
rReset_n => rDacGearboxReset_n
|
|
);
|
|
|
|
end RTL;
|