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
This commit is contained in:
committed by
Aaron Rossetto
co-authored by
Andrew Moch
Daniel Jepson
Javier Valenzuela
Joerg Hofrichter
Kumaran Subramoniam
Max Köhler
Michael Auchter
Paul Butler
Hector Rubio
parent
bfef20ea45
commit
61782b02d7
@@ -0,0 +1,143 @@
|
||||
--
|
||||
-- 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;
|
||||
Reference in New Issue
Block a user