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,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;
|
||||
Reference in New Issue
Block a user