Files
b210-k7-fpga/top/x400/rf/100m/dac_1_3_clk_converter.vhd
T
61782b02d7 fpga: x400: Add support for X410 motherboard FPGA
Co-authored-by: Andrew Moch <Andrew.Moch@ni.com>
Co-authored-by: Daniel Jepson <daniel.jepson@ni.com>
Co-authored-by: Javier Valenzuela <javier.valenzuela@ni.com>
Co-authored-by: Joerg Hofrichter <joerg.hofrichter@ni.com>
Co-authored-by: Kumaran Subramoniam <kumaran.subramoniam@ni.com>
Co-authored-by: Max Köhler <max.koehler@ni.com>
Co-authored-by: Michael Auchter <michael.auchter@ni.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Wade Fife <wade.fife@ettus.com>
Co-authored-by: Hector Rubio <hrubio@ni.com>


Original-commit: 6d3765605262016a80f71e36357f749ea35cbe5a
2021-06-10 11:56:58 -05:00

144 lines
4.0 KiB
VHDL

--
-- Copyright 2021 Ettus Research, a National Instruments Brand
--
-- SPDX-License-Identifier: LGPL-3.0-or-later
--
-- Module: dac_1_3_clk_converter
--
-- Description:
--
-- This module transfers data from s_axis_aclk to m_axis_aclk. m_axis_aclk
-- must be three times the frequency of s_axis_aclk, and the two clocks must
-- be related (this module requires timing closure across the clock domain
-- boundary).
--
library IEEE;
use IEEE.std_logic_1164.all;
entity dac_1_3_clk_converter is
port(
s_axis_aclk : in std_logic;
s_axis_aresetn : in std_logic;
s_axis_tvalid : in std_logic;
s_axis_tdata : in std_logic_vector(31 downto 0);
s_axis_tready : out std_logic := '1';
m_axis_aclk : in std_logic;
m_axis_aresetn : in std_logic;
m_axis_tready : in std_logic;
m_axis_tdata : out std_logic_vector(31 downto 0);
m_axis_tvalid : out std_logic
);
end entity dac_1_3_clk_converter;
architecture RTL of dac_1_3_clk_converter is
-- I was unable to think of a simple implementation that implements a correct
-- AXIS handshake on both ports. All my ideas became equivalent to a two
-- clock FIFO (although the clocks are synchronous, so the write-to-read
-- latency would have been certain).
--
-- We don't expect the DAC to ever hold off incoming data, and dac_100m_bd
-- already has the AXIS handshake disconnected: the FIR is configured to
-- disallow back pressure - it has no m_axis_data_tready pin.
--
-- I'm going with the simple, but not strictly correct, implementation.
-- s_axis_tready will be constantly true, even when it shouldn't be. The
-- bottom line is this component is likely useless for any application but
-- dac_100m_bd.
type output_fsm is (
idle,
got_data,
-- The recovery state of delay ensures that we don't re-use an old input
-- valid signal (remember the output clock is 3x the frequency of the input
-- clock)
recovery
);
subtype word is std_logic_vector(s_axis_tdata'range);
signal output_state_mclk : output_fsm;
signal axis_tdata_sclk : word;
signal axis_tvalid_sclk : std_logic;
signal axis_tdata_mclk : word;
signal axis_tvalid_mclk : std_logic;
begin
s_axis_tready <= '1';
input_valid_register:
process(s_axis_aclk, s_axis_aresetn) is
begin
if s_axis_aresetn='0' then
axis_tvalid_sclk <= '0';
elsif rising_edge(s_axis_aclk) then
axis_tvalid_sclk <= s_axis_tvalid;
end if;
end process;
input_data_register:
process (s_axis_aclk) is
begin
if rising_edge(s_axis_aclk) then
axis_tdata_sclk <= s_axis_tdata;
end if;
end process input_data_register;
-- These CDC registers will not become metastable because the two clock
-- domains are related.
cdc_input_valid_register:
process (m_axis_aclk, m_axis_aresetn) is
begin
if m_axis_aresetn='0' then
axis_tvalid_mclk <= '0';
elsif rising_edge(m_axis_aclk) then
axis_tvalid_mclk <= axis_tvalid_sclk;
end if;
end process cdc_input_valid_register;
cdc_input_data_register:
process (m_axis_aclk) is
begin
if rising_edge(m_axis_aclk) then
axis_tdata_mclk <= axis_tdata_sclk;
end if;
end process cdc_input_data_register;
output_data_register:
process (m_axis_aclk) is
begin
if rising_edge(m_axis_aclk) then
if output_state_mclk=idle then
m_axis_tdata <= axis_tdata_mclk;
end if;
end if;
end process output_data_register;
fsm: process(m_axis_aresetn, m_axis_aclk) is
begin
if m_axis_aresetn='0' then
output_state_mclk <= idle;
m_axis_tvalid <= '0';
elsif rising_edge(m_axis_aclk) then
m_axis_tvalid <= '0';
case output_state_mclk is
when idle =>
if axis_tvalid_mclk='1' then
output_state_mclk <= got_data;
end if;
when got_data =>
m_axis_tvalid <= '1';
output_state_mclk <= recovery;
when recovery =>
output_state_mclk <= idle;
end case;
end if;
end process fsm;
end RTL;