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:
Wade Fife
2021-06-10 11:56:58 -05:00
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
205 changed files with 299634 additions and 0 deletions
+233
View File
@@ -0,0 +1,233 @@
--
-- Copyright 2021 Ettus Research, a National Instruments Brand
--
-- SPDX-License-Identifier: LGPL-3.0-or-later
--
-- Module: dac_gearbox_12x8
--
-- Description:
--
-- Gearbox to expand the data width from 12 SPC to 8 SPC.
-- Input Clocks, all aligned to one another and coming from same MMCM.
-- PLL reference clock = 61.44 or 62.5 MHz.
-- RfClk: 184.32 or 187.5 MHz (3x PLL reference clock)
-- Clk1x: 122.88 or 125 MHz (2x PLL reference clock)
-- Clk2x: 245.76 or 250 MHz (4x PLL reference clock)
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity dac_gearbox_12x8 is
port(
Clk1x : in std_logic;
RfClk : in std_logic;
ac1Reset_n : in std_logic;
arReset_n : in std_logic;
-- Data packing: [Q11,I11,Q10,I10,...,Q3,I3,Q2,I2,Q1,I1,Q0,I0] (I in LSBs)
c1DataIn : in std_logic_vector(383 downto 0);
c1DataValidIn : in std_logic;
-- Data packing: [Q7,I7,Q6,I6,...,Q3,I3,Q2,I2,Q1,I1,Q0,I0] (I in LSBs)
rDataOut : out std_logic_vector(255 downto 0) := (others => '0');
rReadyForOutput : in std_logic;
rDataValidOut : out std_logic
);
end dac_gearbox_12x8;
architecture RTL of dac_gearbox_12x8 is
constant kDataWidth : natural := 16;
constant kDataI0Lsb : natural := 0;
constant kDataI0Msb : natural := kDataWidth-1;
constant kDataQ0Lsb : natural := kDataI0Msb+1;
constant kDataQ0Msb : natural := kDataQ0Lsb+kDataWidth-1;
constant kDataI1Lsb : natural := kDataQ0Msb+1;
constant kDataI1Msb : natural := kDataI1Lsb+kDataWidth-1;
constant kDataQ1Lsb : natural := kDataI1Msb+1;
constant kDataQ1Msb : natural := kDataQ1Lsb+kDataWidth-1;
constant kDataI2Lsb : natural := kDataQ1Msb+1;
constant kDataI2Msb : natural := kDataI2Lsb+kDataWidth-1;
constant kDataQ2Lsb : natural := kDataI2Msb+1;
constant kDataQ2Msb : natural := kDataQ2Lsb+kDataWidth-1;
constant kDataI3Lsb : natural := kDataQ2Msb+1;
constant kDataI3Msb : natural := kDataI3Lsb+kDataWidth-1;
constant kDataQ3Lsb : natural := kDataI3Msb+1;
constant kDataQ3Msb : natural := kDataQ3Lsb+kDataWidth-1;
constant kDataI4Lsb : natural := kDataQ3Msb+1;
constant kDataI4Msb : natural := kDataI4Lsb+kDataWidth-1;
constant kDataQ4Lsb : natural := kDataI4Msb+1;
constant kDataQ4Msb : natural := kDataQ4Lsb+kDataWidth-1;
constant kDataI5Lsb : natural := kDataQ4Msb+1;
constant kDataI5Msb : natural := kDataI5Lsb+kDataWidth-1;
constant kDataQ5Lsb : natural := kDataI5Msb+1;
constant kDataQ5Msb : natural := kDataQ5Lsb+kDataWidth-1;
constant kDataI6Lsb : natural := kDataQ5Msb+1;
constant kDataI6Msb : natural := kDataI6Lsb+kDataWidth-1;
constant kDataQ6Lsb : natural := kDataI6Msb+1;
constant kDataQ6Msb : natural := kDataQ6Lsb+kDataWidth-1;
constant kDataI7Lsb : natural := kDataQ6Msb+1;
constant kDataI7Msb : natural := kDataI7Lsb+kDataWidth-1;
constant kDataQ7Lsb : natural := kDataI7Msb+1;
constant kDataQ7Msb : natural := kDataQ7Lsb+kDataWidth-1;
subtype Word_t is std_logic_vector(383 downto 0);
type Words_t is array(natural range<>) of Word_t;
signal rDataInDly : Words_t(3 downto 0);
signal rDataValidDly : std_logic_vector(3 downto 0) := (others => '0');
signal c1PhaseCount, c1DataValidInDly : std_logic := '0';
signal rPhaseShiftReg : std_logic_vector(2 downto 0);
begin
-----------------------------------------------------------------------------
-- Data Packing 12 SPC to 8 SPC
-----------------------------------------------------------------------------
Clk1xDataCount: process(ac1Reset_n, Clk1x)
begin
if ac1Reset_n = '0' then
c1PhaseCount <= '0';
c1DataValidInDly <= '0';
elsif rising_edge(Clk1x) then
c1DataValidInDly <= c1DataValidIn;
c1PhaseCount <= (not c1PhaseCount) and (c1DataValidIn or c1DataValidInDly);
end if;
end process;
DataClkCrossing: process(RfClk)
begin
if rising_edge(RfClk) then
rDataInDly <= rDataInDly(rDataInDly'high-1 downto 0) & c1DataIn;
end if;
end process;
-- Store clock phase information in a shift register. The shift register
-- is a 3 bit register and it used in output data packer.
PhaseClkCrossing: process(arReset_n,RfClk)
begin
if arReset_n = '0' then
rPhaseShiftReg <= (others => '0');
elsif rising_edge(RfClk) then
rPhaseShiftReg(2 downto 1) <= rPhaseShiftReg(1 downto 0);
rPhaseShiftReg(0) <= c1PhaseCount;
end if;
end process;
-----------------------------------------------------------------------------
--
-- Timing diagram: Data valid is asserted when both clock are edge aligned.
--
-- | | |
-- v <-Clocks edge aligned v v
-- Clk1x ¯¯\____/¯¯¯¯¯\_____/¯¯¯¯¯\_____/¯¯¯¯¯\_____/¯¯¯¯¯\_____/¯¯¯¯¯\___
-- |
-- v <- O/p data valid assertion
-- RfClk ¯¯¯\___/¯¯¯\___/¯¯¯\___/¯¯¯\___/¯¯¯\___/¯¯¯\___/¯¯¯\___/¯¯¯\___/¯
-- | | |
-- c1DataValid _/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯|¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
-- | | |
-- c1DValidDly _________/¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯|¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
-- | | |
-- c1PhaseCount _______/¯¯¯¯¯¯¯¯¯¯¯¯\|_______|__/¯¯¯¯|¯¯¯¯¯¯¯\__________/¯¯
-- | | |
-- v <- rPhaseSR= "001"
-- rPhaseSR(0) ________________/¯¯¯¯¯¯¯¯\_____|_______|_/¯¯¯¯¯¯¯\_________________
-- | |
-- v <- rPhaseSR= "010"
-- rPhaseSR(1) _________________________/¯¯¯¯¯¯¯¯\____|__________/¯¯¯¯¯¯¯\____________
-- |
-- v <- rPhaseSR= "100"
-- rPhaseSR(2) __________________________________/¯¯¯¯¯¯¯¯\_______________/¯¯¯¯¯¯¯\___
--
-- rDValidDly0 _________________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
--
-- rDValidDly1 _________________________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
--
-- rDValidDly2 __________________________________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
--
-- In this design use a single bit counter on the input clock (Clk1x) domain
-- and pass it to the RfClk domain. When data valid is asserted when both
-- clocks are rising edge aligned, only one bit in rPhaseSR high, the
-- remaining bits are zero. We use the position of the bit counter in the
-- shift register to do data packing.
--
--
-- Timing diagram: When data valid is asserted when both clock are NOT edge
-- aligned.
--
-- | | |
-- v <-Clocks edge aligned v v
-- Clk1x ¯¯\____/¯¯¯¯¯\_____/¯¯¯¯¯\_____/¯¯¯¯¯\_____/¯¯¯¯¯\_____/¯¯¯¯¯\___
-- |
-- v <- O/p data valid assertion
-- RfClk ¯¯¯\___/¯¯¯\___/¯¯¯\___/¯¯¯\___/¯¯¯\___/¯¯¯\___/¯¯¯\___/¯¯¯\___/¯
-- | | | |
-- c1DataValid ________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯|¯¯¯¯¯¯¯|¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯
-- | | | |
-- c1DValidDly ___________________/¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯|¯¯¯¯¯¯¯|¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
-- | | | |
-- c1PhaseCount ___________________/¯¯¯¯¯¯¯¯¯¯|¯\_____|_____/¯|¯¯¯¯¯¯¯|¯¯\__________/¯¯
-- | | | |
-- v <- rPhaseSR= "001" |
-- rPhaseSR(0) ________________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯\_____|_/¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯
-- | | |
-- v <- rPhaseSR= "011"
-- rPhaseSR(1) ________________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯\_____|_/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
-- | |
-- v <- rPhaseSR= "110"
-- rPhaseSR(2) ________________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯\_______/¯¯¯¯¯¯¯¯¯¯
-- ^
-- | <- rPhaseSR= "101"
--
-- rDValidDly0 _________________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
--
-- rDValidDly1 _________________________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
--
-- The above timing diagram is when input data valid is asserted when both
-- clocks rising edges are not aligned. In this case the more than one bit in
-- rPhaseSR is asserted which is unique to this case. As mentioned in the
-- above case, we use rPhaseSR value to determine data packing.
-- Output Data Packer
DataOut: process(RfClk)
begin
if rising_edge(RfClk) then
-- rPhaseShiftReg = "011"
rDataOut <= rDataInDly(2)(kDataQ7Msb downto kDataI0Lsb);
if rPhaseShiftReg = "110" or rPhaseShiftReg = "100" then
rDataOut <= rDataInDly(2)(kDataQ3Msb downto kDataI0Lsb) &
rDataInDly(3)(c1DataIn'length-1 downto kDataQ7Msb+1);
elsif rPhaseShiftReg = "101" or rPhaseShiftReg = "001" then
rDataOut <= rDataInDly(3)(c1DataIn'length-1 downto kDataI4Lsb);
elsif rPhaseShiftReg = "010" then
rDataOut <= rDataInDly(3)(kDataQ7Msb downto kDataI0Lsb);
end if;
end if;
end process;
DataValidOut: process(RfClk, arReset_n)
begin
if arReset_n = '0' then
rDataValidDly <= (others => '0');
rDataValidOut <= '0';
elsif rising_edge(RfClk) then
rDataValidDly <= rDataValidDly(rDataValidDly'left-1 downto 0) &
c1DataValidIn;
-- Data valid out asserting based on phase alignment RfClk and Clk1x.
-- When RfClk and Clk1x are not phase aligned.
rDataValidOut <= rDataValidDly(2) and rReadyForOutput;
-- When RfClk and Clk1x are phase aligned.
if (rPhaseShiftReg(2) xor rPhaseShiftReg(1) xor rPhaseShiftReg(0)) = '1' then
rDataValidOut <= rDataValidDly(2) and rDataValidDly(3) and rReadyForOutput;
end if;
end if;
end process;
end RTL;