diff --git a/base/general/rtl/AsyncGearbox.vhd b/base/general/rtl/AsyncGearbox.vhd index af950fb691..d47520600d 100644 --- a/base/general/rtl/AsyncGearbox.vhd +++ b/base/general/rtl/AsyncGearbox.vhd @@ -19,18 +19,16 @@ use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; - library surf; use surf.StdRtlPkg.all; entity AsyncGearbox is - generic ( TPD_G : time := 1 ns; SLAVE_WIDTH_G : positive; - SLAVE_BIT_REVERSE_G : boolean := false; + SLAVE_BIT_REVERSE_G : boolean := false; MASTER_WIDTH_G : positive; - MASTER_BIT_REVERSE_G : boolean := false; + MASTER_BIT_REVERSE_G : boolean := false; -- Pipelining generics INPUT_PIPE_STAGES_G : natural := 0; OUTPUT_PIPE_STAGES_G : natural := 0; @@ -38,25 +36,22 @@ entity AsyncGearbox is FIFO_MEMORY_TYPE_G : string := "distributed"; FIFO_ADDR_WIDTH_G : positive := 4); port ( - slaveClk : in sl; - slaveRst : in sl; - - -- input side data and flow control - slaveData : in slv(SLAVE_WIDTH_G-1 downto 0); - slaveValid : in sl := '1'; - slaveReady : out sl; - - -- sequencing and slip - slip : in sl := '0'; - - masterClk : in sl; - masterRst : in sl; - - -- output side data and flow control - masterData : out slv(MASTER_WIDTH_G-1 downto 0); - masterValid : out sl; - masterReady : in sl := '1'); - + -- input side data and flow control (slaveClk domain) + slaveClk : in sl; + slaveRst : in sl; + slaveData : in slv(SLAVE_WIDTH_G-1 downto 0); + slaveValid : in sl := '1'; + slaveReady : out sl; + slaveBitOrder : in sl := ite(SLAVE_BIT_REVERSE_G, '1', '0'); + -- sequencing and slip (ASYNC input) + slip : in sl := '0'; + -- output side data and flow control (masterClk domain) + masterClk : in sl; + masterRst : in sl; + masterData : out slv(MASTER_WIDTH_G-1 downto 0); + masterValid : out sl; + masterReady : in sl := '1'; + masterBitOrder : in sl := ite(MASTER_BIT_REVERSE_G, '1', '0')); end entity AsyncGearbox; architecture mapping of AsyncGearbox is @@ -66,15 +61,17 @@ architecture mapping of AsyncGearbox is signal fastClk : sl; signal fastRst : sl; - signal gearboxDataIn : slv(SLAVE_WIDTH_G-1 downto 0); - signal gearboxValidIn : sl; - signal gearboxReadyIn : sl; - signal gearboxDataOut : slv(MASTER_WIDTH_G-1 downto 0); - signal gearboxValidOut : sl; - signal gearboxReadyOut : sl; - signal gearboxSlip : sl; - signal almostFull : sl; - signal writeEnable : sl; + signal gearboxDataIn : slv(SLAVE_WIDTH_G-1 downto 0); + signal gearboxValidIn : sl; + signal gearboxReadyIn : sl; + signal gearboxDataOut : slv(MASTER_WIDTH_G-1 downto 0); + signal gearboxValidOut : sl; + signal gearboxReadyOut : sl; + signal gearboxSlip : sl; + signal gearboxSlaveBitOrder : sl; + signal gearboxMasterBitOrder : sl; + signal almostFull : sl; + signal writeEnable : sl; begin @@ -90,6 +87,24 @@ begin dataIn => slip, -- [in] dataOut => gearboxSlip); -- [out] + U_slaveBitOrder : entity surf.Synchronizer + generic map ( + TPD_G => TPD_G, + INIT_G => ite(SLAVE_BIT_REVERSE_G, "11", "00")) + port map ( + clk => fastClk, + dataIn => slaveBitOrder, + dataOut => gearboxSlaveBitOrder); + + U_masterBitOrder : entity surf.Synchronizer + generic map ( + TPD_G => TPD_G, + INIT_G => ite(MASTER_BIT_REVERSE_G, "11", "00")) + port map ( + clk => fastClk, + dataIn => masterBitOrder, + dataOut => gearboxMasterBitOrder); + SLAVE_FIFO_GEN : if (not SLAVE_FASTER_C) generate U_FifoAsync_1 : entity surf.FifoAsync generic map ( @@ -142,15 +157,17 @@ begin MASTER_WIDTH_G => MASTER_WIDTH_G, MASTER_BIT_REVERSE_G => MASTER_BIT_REVERSE_G) port map ( - clk => fastClk, -- [in] - rst => fastRst, -- [in] - slaveData => gearboxDataIn, -- [in] - slaveValid => gearboxValidIn, -- [in] - slaveReady => gearboxReadyIn, -- [out] - masterData => gearboxDataOut, -- [out] - masterValid => gearboxValidOut, -- [out] - masterReady => gearboxReadyOut, -- [in] - slip => gearboxSlip); -- [in] + clk => fastClk, -- [in] + rst => fastRst, -- [in] + slaveData => gearboxDataIn, -- [in] + slaveValid => gearboxValidIn, -- [in] + slaveReady => gearboxReadyIn, -- [out] + slaveBitOrder => gearboxSlaveBitOrder, -- [in] + masterData => gearboxDataOut, -- [out] + masterValid => gearboxValidOut, -- [out] + masterReady => gearboxReadyOut, -- [in] + masterBitOrder => gearboxMasterBitOrder, -- [in] + slip => gearboxSlip); -- [in] MASTER_FIFO_GEN : if (SLAVE_FASTER_C) generate U_FifoAsync_1 : entity surf.FifoAsync @@ -162,15 +179,15 @@ begin PIPE_STAGES_G => OUTPUT_PIPE_STAGES_G, ADDR_WIDTH_G => FIFO_ADDR_WIDTH_G) port map ( - rst => fastRst, -- [in] - wr_clk => fastClk, -- [in] - wr_en => writeEnable, -- [in] - din => gearboxDataOut, -- [in] - almost_full => almostFull, -- [out] - rd_clk => masterClk, -- [in] - rd_en => masterReady, -- [in] - dout => masterData, -- [out] - valid => masterValid); -- [out] + rst => fastRst, -- [in] + wr_clk => fastClk, -- [in] + wr_en => writeEnable, -- [in] + din => gearboxDataOut, -- [in] + almost_full => almostFull, -- [out] + rd_clk => masterClk, -- [in] + rd_en => masterReady, -- [in] + dout => masterData, -- [out] + valid => masterValid); -- [out] gearboxReadyOut <= not(almostFull); writeEnable <= gearboxValidOut and not(almostFull); end generate MASTER_FIFO_GEN; diff --git a/base/general/rtl/Gearbox.vhd b/base/general/rtl/Gearbox.vhd index 7b906429c5..5959abe40c 100644 --- a/base/general/rtl/Gearbox.vhd +++ b/base/general/rtl/Gearbox.vhd @@ -19,37 +19,33 @@ use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; - library surf; use surf.StdRtlPkg.all; entity Gearbox is - generic ( - TPD_G : time := 1 ns; + TPD_G : time := 1 ns; SLAVE_BIT_REVERSE_G : boolean := false; SLAVE_WIDTH_G : positive; MASTER_BIT_REVERSE_G : boolean := false; MASTER_WIDTH_G : positive); - port ( - clk : in sl; - rst : in sl; - + -- Clock and Reset + clk : in sl; + rst : in sl; -- input side data and flow control - slaveData : in slv(SLAVE_WIDTH_G-1 downto 0); - slaveValid : in sl := '1'; - slaveReady : out sl; - + slaveData : in slv(SLAVE_WIDTH_G-1 downto 0); + slaveValid : in sl := '1'; + slaveReady : out sl; + slaveBitOrder : in sl := ite(SLAVE_BIT_REVERSE_G, '1', '0'); -- sequencing and slip - startOfSeq : in sl := '0'; - slip : in sl := '0'; - + startOfSeq : in sl := '0'; + slip : in sl := '0'; -- output side data and flow control - masterData : out slv(MASTER_WIDTH_G-1 downto 0); - masterValid : out sl; - masterReady : in sl := '1'); - + masterData : out slv(MASTER_WIDTH_G-1 downto 0); + masterValid : out sl; + masterReady : in sl := '1'; + masterBitOrder : in sl := ite(MASTER_BIT_REVERSE_G, '1', '0')); end entity Gearbox; architecture rtl of Gearbox is @@ -80,7 +76,8 @@ architecture rtl of Gearbox is begin - comb : process (slaveData, r, masterReady, rst, slip, startOfSeq, slaveValid) is + comb : process (masterBitOrder, masterReady, r, rst, slaveBitOrder, + slaveData, slaveValid, slip, startOfSeq) is variable v : RegType; begin v := r; @@ -98,12 +95,11 @@ begin v.writeIndex := r.writeIndex - 1; end if; - -- Only do anything if ready for data output if (v.masterValid = '0') then -- If current write index (assigned last cycle) is greater than output width, - -- then we have to shift down before assinging an new input + -- then we have to shift down before assigning an new input if (v.writeIndex >= MASTER_WIDTH_G) then v.shiftReg := slvZero(MASTER_WIDTH_G) & r.shiftReg(SHIFT_WIDTH_C-1 downto MASTER_WIDTH_G); v.writeIndex := v.writeIndex - MASTER_WIDTH_G; @@ -128,8 +124,8 @@ begin -- Accept the input word v.slaveReady := '1'; - -- Assign incomming data at proper location in shift reg - if SLAVE_BIT_REVERSE_G then + -- Assign incoming data at proper location in shift reg + if (slaveBitOrder = '1') then v.shiftReg(v.writeIndex+SLAVE_WIDTH_G-1 downto v.writeIndex) := bitReverse(slaveData); else v.shiftReg(v.writeIndex+SLAVE_WIDTH_G-1 downto v.writeIndex) := slaveData; @@ -154,10 +150,10 @@ begin rin <= v; masterValid <= r.masterValid; - if MASTER_BIT_REVERSE_G then - masterData <= bitReverse(r.shiftReg(MASTER_WIDTH_G-1 downto 0)); + if (masterBitOrder = '1') then + masterData <= bitReverse(r.shiftReg(MASTER_WIDTH_G-1 downto 0)); else - masterData <= r.shiftReg(MASTER_WIDTH_G-1 downto 0); + masterData <= r.shiftReg(MASTER_WIDTH_G-1 downto 0); end if; end process comb; @@ -169,4 +165,4 @@ begin end if; end process sync; -end rtl; +end rtl; diff --git a/base/ram/inferred/DualPortRam.vhd b/base/ram/inferred/DualPortRam.vhd index e8c273a9e3..8444ff8f39 100644 --- a/base/ram/inferred/DualPortRam.vhd +++ b/base/ram/inferred/DualPortRam.vhd @@ -97,7 +97,7 @@ begin end generate; GEN_LUTRAM : if (MEMORY_TYPE_G="distributed") generate - QuadPortRam_Inst : entity surf.QuadPortRam + LutRam_Inst : entity surf.LutRam generic map ( TPD_G => TPD_G, RST_POLARITY_G => RST_POLARITY_G, @@ -107,6 +107,7 @@ begin DATA_WIDTH_G => DATA_WIDTH_G, BYTE_WIDTH_G => BYTE_WIDTH_G, ADDR_WIDTH_G => ADDR_WIDTH_G, + NUM_PORTS_G => 2, INIT_G => INIT_G) port map ( -- Port A @@ -123,19 +124,7 @@ begin en_b => enb, rstb => rstb, addrb => addrb, - doutb => doutb, - -- Port C - clkc => '0', - en_c => '0', - rstc => FORCE_RST_C, - addrc => (others => '0'), - doutc => open, - -- Port C - clkd => '0', - en_d => '0', - rstd => FORCE_RST_C, - addrd => (others => '0'), - doutd => open); + doutb => doutb); end generate; end mapping; diff --git a/base/ram/inferred/OctalPortRam.vhd b/base/ram/inferred/LutRam.vhd similarity index 81% rename from base/ram/inferred/OctalPortRam.vhd rename to base/ram/inferred/LutRam.vhd index 98e0d71d5b..660bdbe2dd 100644 --- a/base/ram/inferred/OctalPortRam.vhd +++ b/base/ram/inferred/LutRam.vhd @@ -1,7 +1,8 @@ ------------------------------------------------------------------------------- -- Company : SLAC National Accelerator Laboratory ------------------------------------------------------------------------------- --- Description: This module infers a Quad Port RAM as distributed RAM +-- Description: This module infers distributed RAM +-- with configurable number of outputs ------------------------------------------------------------------------------- -- This file is part of 'SLAC Firmware Standard Library'. -- It is subject to the license terms in the LICENSE.txt file found in the @@ -17,21 +18,21 @@ use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; - library surf; use surf.StdRtlPkg.all; -entity OctalPortRam is +entity LutRam is generic ( - TPD_G : time := 1 ns; - RST_POLARITY_G : sl := '1'; -- '1' for active high rst, '0' for active low - REG_EN_G : boolean := true; - MODE_G : string := "no-change"; - BYTE_WR_EN_G : boolean := false; - DATA_WIDTH_G : integer range 1 to (2**24) := 16; - BYTE_WIDTH_G : integer := 8; - ADDR_WIDTH_G : integer range 1 to (2**24) := 4; - INIT_G : slv := "0"); + TPD_G : time := 1 ns; + RST_POLARITY_G : sl := '1'; -- '1' for active high rst, '0' for active low + REG_EN_G : boolean := true; + MODE_G : string := "no-change"; + BYTE_WR_EN_G : boolean := false; + DATA_WIDTH_G : positive := 16; + BYTE_WIDTH_G : positive := 8; + ADDR_WIDTH_G : positive := 4; + NUM_PORTS_G : positive; + INIT_G : slv := "0"); port ( -- Port A (Read/Write) clka : in sl := '0'; @@ -42,51 +43,51 @@ entity OctalPortRam is addra : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); dina : in slv(DATA_WIDTH_G-1 downto 0) := (others => '0'); douta : out slv(DATA_WIDTH_G-1 downto 0); - -- Port B (Read Only) + -- Port B (Read Only, NUM_PORTS_G>=2) clkb : in sl := '0'; en_b : in sl := '1'; rstb : in sl := not(RST_POLARITY_G); addrb : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); - doutb : out slv(DATA_WIDTH_G-1 downto 0); - -- Port C (Read Only) + doutb : out slv(DATA_WIDTH_G-1 downto 0) := (others => '0'); + -- Port C (Read Only, NUM_PORTS_G>=3) en_c : in sl := '1'; clkc : in sl := '0'; rstc : in sl := not(RST_POLARITY_G); addrc : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); - doutc : out slv(DATA_WIDTH_G-1 downto 0); - -- Port D (Read Only) + doutc : out slv(DATA_WIDTH_G-1 downto 0) := (others => '0'); + -- Port D (Read Only, NUM_PORTS_G>=4) en_d : in sl := '1'; clkd : in sl := '0'; rstd : in sl := not(RST_POLARITY_G); addrd : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); - doutd : out slv(DATA_WIDTH_G-1 downto 0); - -- Port E (Read Only) + doutd : out slv(DATA_WIDTH_G-1 downto 0) := (others => '0'); + -- Port E (Read Only, NUM_PORTS_G>=5) en_e : in sl := '1'; clke : in sl := '0'; rste : in sl := not(RST_POLARITY_G); addre : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); - doute : out slv(DATA_WIDTH_G-1 downto 0); - -- Port F (Read Only) + doute : out slv(DATA_WIDTH_G-1 downto 0) := (others => '0'); + -- Port F (Read Only, NUM_PORTS_G>=6) en_f : in sl := '1'; clkf : in sl := '0'; rstf : in sl := not(RST_POLARITY_G); addrf : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); - doutf : out slv(DATA_WIDTH_G-1 downto 0); - -- Port G (Read Only) + doutf : out slv(DATA_WIDTH_G-1 downto 0) := (others => '0'); + -- Port G (Read Only, NUM_PORTS_G>=7) en_g : in sl := '1'; clkg : in sl := '0'; rstg : in sl := not(RST_POLARITY_G); addrg : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); - doutg : out slv(DATA_WIDTH_G-1 downto 0); - -- Port H (Read Only) + doutg : out slv(DATA_WIDTH_G-1 downto 0) := (others => '0'); + -- Port H (Read Only, NUM_PORTS_G>=8) en_h : in sl := '1'; clkh : in sl := '0'; rsth : in sl := not(RST_POLARITY_G); addrh : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); - douth : out slv(DATA_WIDTH_G-1 downto 0)); -end OctalPortRam; + douth : out slv(DATA_WIDTH_G-1 downto 0) := (others => '0')); +end LutRam; -architecture rtl of OctalPortRam is +architecture rtl of LutRam is -- Initial RAM Values constant NUM_BYTES_C : natural := wordCount(DATA_WIDTH_G, BYTE_WIDTH_G); @@ -221,7 +222,7 @@ begin end generate; -- Port B - PORT_B_REG : if (REG_EN_G = true) generate + PORT_B_REG : if (REG_EN_G = true) and (NUM_PORTS_G >= 2) generate process(clkb) begin if rising_edge(clkb) then @@ -234,12 +235,12 @@ begin end process; end generate; - PORT_B_NOT_REG : if (REG_EN_G = false) generate + PORT_B_NOT_REG : if (REG_EN_G = false) and (NUM_PORTS_G >= 2) generate doutb <= mem(conv_integer(addrb)); end generate; -- Port C - PORT_C_REG : if (REG_EN_G = true) generate + PORT_C_REG : if (REG_EN_G = true) and (NUM_PORTS_G >= 3) generate process(clkc) begin if rising_edge(clkc) then @@ -252,12 +253,12 @@ begin end process; end generate; - PORT_C_NOT_REG : if (REG_EN_G = false) generate + PORT_C_NOT_REG : if (REG_EN_G = false) and (NUM_PORTS_G >= 3) generate doutc <= mem(conv_integer(addrc)); end generate; -- Port D - PORT_D_REG : if (REG_EN_G = true) generate + PORT_D_REG : if (REG_EN_G = true) and (NUM_PORTS_G >= 4) generate process(clkd) begin if rising_edge(clkd) then @@ -270,12 +271,12 @@ begin end process; end generate; - PORT_D_NOT_REG : if (REG_EN_G = false) generate + PORT_D_NOT_REG : if (REG_EN_G = false) and (NUM_PORTS_G >= 4) generate doutd <= mem(conv_integer(addrd)); end generate; -- Port E - PORT_E_REG : if (REG_EN_G = true) generate + PORT_E_REG : if (REG_EN_G = true) and (NUM_PORTS_G >= 5) generate process(clke) begin if rising_edge(clke) then @@ -288,12 +289,12 @@ begin end process; end generate; - PORT_E_NOT_REG : if (REG_EN_G = false) generate + PORT_E_NOT_REG : if (REG_EN_G = false) and (NUM_PORTS_G >= 5) generate doute <= mem(conv_integer(addre)); end generate; -- Port F - PORT_F_REG : if (REG_EN_G = true) generate + PORT_F_REG : if (REG_EN_G = true) and (NUM_PORTS_G >= 6) generate process(clkf) begin if rising_edge(clkf) then @@ -306,12 +307,12 @@ begin end process; end generate; - PORT_F_NOT_REG : if (REG_EN_G = false) generate + PORT_F_NOT_REG : if (REG_EN_G = false) and (NUM_PORTS_G >= 6) generate doutf <= mem(conv_integer(addrf)); end generate; -- Port G - PORT_G_REG : if (REG_EN_G = true) generate + PORT_G_REG : if (REG_EN_G = true) and (NUM_PORTS_G >= 7) generate process(clkg) begin if rising_edge(clkg) then @@ -324,12 +325,12 @@ begin end process; end generate; - PORT_G_NOT_REG : if (REG_EN_G = false) generate + PORT_G_NOT_REG : if (REG_EN_G = false) and (NUM_PORTS_G >= 7) generate doutg <= mem(conv_integer(addrg)); end generate; -- Port H - PORT_H_REG : if (REG_EN_G = true) generate + PORT_H_REG : if (REG_EN_G = true) and (NUM_PORTS_G >= 8) generate process(clkh) begin if rising_edge(clkh) then @@ -342,7 +343,7 @@ begin end process; end generate; - PORT_H_NOT_REG : if (REG_EN_G = false) generate + PORT_H_NOT_REG : if (REG_EN_G = false) and (NUM_PORTS_G >= 8) generate douth <= mem(conv_integer(addrh)); end generate; diff --git a/base/ram/inferred/QuadPortRam.vhd b/base/ram/inferred/QuadPortRam.vhd deleted file mode 100644 index 909871942c..0000000000 --- a/base/ram/inferred/QuadPortRam.vhd +++ /dev/null @@ -1,254 +0,0 @@ -------------------------------------------------------------------------------- --- Company : SLAC National Accelerator Laboratory -------------------------------------------------------------------------------- --- Description: This module infers a Quad Port RAM as distributed RAM -------------------------------------------------------------------------------- --- This file is part of 'SLAC Firmware Standard Library'. --- It is subject to the license terms in the LICENSE.txt file found in the --- top-level directory of this distribution and at: --- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. --- No part of 'SLAC Firmware Standard Library', including this file, --- may be copied, modified, propagated, or distributed except according to --- the terms contained in the LICENSE.txt file. -------------------------------------------------------------------------------- - -library ieee; -use ieee.std_logic_1164.all; -use ieee.std_logic_arith.all; -use ieee.std_logic_unsigned.all; - - -library surf; -use surf.StdRtlPkg.all; - -entity QuadPortRam is - generic ( - TPD_G : time := 1 ns; - RST_POLARITY_G : sl := '1'; -- '1' for active high rst, '0' for active low - REG_EN_G : boolean := true; - MODE_G : string := "read-first"; - BYTE_WR_EN_G : boolean := false; - DATA_WIDTH_G : integer range 1 to (2**24) := 16; - BYTE_WIDTH_G : integer := 8; - ADDR_WIDTH_G : integer range 1 to (2**24) := 4; - INIT_G : slv := "0"); - port ( - -- Port A (Read/Write) - clka : in sl := '0'; - en_a : in sl := '1'; - wea : in sl := '0'; - weaByte : in slv(wordCount(DATA_WIDTH_G, BYTE_WIDTH_G)-1 downto 0) := (others => '0'); - rsta : in sl := not(RST_POLARITY_G); - addra : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); - dina : in slv(DATA_WIDTH_G-1 downto 0) := (others => '0'); - douta : out slv(DATA_WIDTH_G-1 downto 0); - -- Port B (Read Only) - clkb : in sl := '0'; - en_b : in sl := '1'; - rstb : in sl := not(RST_POLARITY_G); - addrb : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); - doutb : out slv(DATA_WIDTH_G-1 downto 0); - -- Port C (Read Only) - en_c : in sl := '1'; - clkc : in sl := '0'; - rstc : in sl := not(RST_POLARITY_G); - addrc : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); - doutc : out slv(DATA_WIDTH_G-1 downto 0); - -- Port D (Read Only) - en_d : in sl := '1'; - clkd : in sl := '0'; - rstd : in sl := not(RST_POLARITY_G); - addrd : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); - doutd : out slv(DATA_WIDTH_G-1 downto 0)); -end QuadPortRam; - -architecture rtl of QuadPortRam is - - -- Initial RAM Values - constant NUM_BYTES_C : natural := wordCount(DATA_WIDTH_G, BYTE_WIDTH_G); - constant FULL_DATA_WIDTH_C : natural := NUM_BYTES_C*BYTE_WIDTH_G; - - constant INIT_C : slv(DATA_WIDTH_G-1 downto 0) := ite(INIT_G = "0", slvZero(DATA_WIDTH_G), INIT_G); - - - -- Shared memory - type mem_type is array ((2**ADDR_WIDTH_G)-1 downto 0) of slv(DATA_WIDTH_G-1 downto 0); - signal mem : mem_type := (others => INIT_C); - - signal weaByteInt : slv(weaByte'range); - - -- Attribute for XST (Xilinx Synthesis) - attribute ram_style : string; - attribute ram_style of mem : signal is "distributed"; - - attribute ram_extract : string; - attribute ram_extract of mem : signal is "TRUE"; - - -- Attribute for Synplicity Synthesizer - attribute syn_ramstyle : string; - attribute syn_ramstyle of mem : signal is "distributed"; - - attribute syn_keep : string; - attribute syn_keep of mem : signal is "TRUE"; - -begin - - - -- MODE_G check - assert (MODE_G = "no-change") or (MODE_G = "read-first") or (MODE_G = "write-first") - report "MODE_G must be either no-change, read-first, or write-first" - severity failure; - - weaByteInt <= weaByte when BYTE_WR_EN_G else (others => wea); - - -- Port A - PORT_A_NOT_REG : if (REG_EN_G = false) generate - - process(clka) - begin - if rising_edge(clka) then - if (en_a = '1') then - for i in NUM_BYTES_C-1 downto 0 loop - if (weaByteInt(i) = '1') then - mem(conv_integer(addra))(minimum(DATA_WIDTH_G-1, (i+1)*BYTE_WIDTH_G-1) downto i*BYTE_WIDTH_G) <= - dina(minimum(DATA_WIDTH_G-1, (i+1)*BYTE_WIDTH_G-1) downto i*BYTE_WIDTH_G); - end if; - end loop; - end if; - end if; - end process; - - douta <= mem(conv_integer(addra)); - - - end generate; - - PORT_A_REG : if (REG_EN_G = true) generate - - NO_CHANGE_MODE : if MODE_G = "no-change" generate - process(clka) - begin - if rising_edge(clka) then - if en_a = '1' then - for i in NUM_BYTES_C-1 downto 0 loop - if (weaByteInt(i) = '1') then - mem(conv_integer(addra))(minimum(DATA_WIDTH_G-1, (i+1)*BYTE_WIDTH_G-1) downto i*BYTE_WIDTH_G) <= - dina(minimum(DATA_WIDTH_G-1, (i+1)*BYTE_WIDTH_G-1) downto i*BYTE_WIDTH_G); - end if; - end loop; - end if; - end if; - end process; - - process(clka) - begin - if rising_edge(clka) then - if (en_a = '1' and weaByteInt = 0) then - douta <= mem(conv_integer(addra)) after TPD_G; - end if; - if rsta = RST_POLARITY_G then - douta <= INIT_C after TPD_G; - end if; - end if; - end process; - - end generate; - - READ_FIRST_MODE : if MODE_G = "read-first" generate - process(clka) - begin - if rising_edge(clka) then - if en_a = '1' then - douta <= mem(conv_integer(addra)) after TPD_G; - for i in 0 to NUM_BYTES_C-1 loop - if (weaByteInt(i) = '1') then - mem(conv_integer(addra))(minimum(DATA_WIDTH_G-1, (i+1)*BYTE_WIDTH_G-1) downto i*BYTE_WIDTH_G) <= - dina(minimum(DATA_WIDTH_G-1, (i+1)*BYTE_WIDTH_G-1) downto i*BYTE_WIDTH_G); - end if; - end loop; - end if; - if rsta = RST_POLARITY_G then - douta <= INIT_C after TPD_G; - end if; - end if; - end process; - end generate; - - WRITE_FIRST_MODE : if MODE_G = "write-first" generate - process(clka) - begin - if rising_edge(clka) then - if en_a = '1' then - for i in NUM_BYTES_C-1 downto 0 loop - if (weaByteInt(i) = '1') then - mem(conv_integer(addra))(minimum(DATA_WIDTH_G-1, (i+1)*BYTE_WIDTH_G-1) downto i*BYTE_WIDTH_G) <= - dina(minimum(DATA_WIDTH_G-1, (i+1)*BYTE_WIDTH_G-1) downto i*BYTE_WIDTH_G); - end if; - end loop; - douta <= mem(conv_integer(addra)) after TPD_G; - end if; - - if rsta = RST_POLARITY_G then - douta <= INIT_C after TPD_G; - end if; - end if; - end process; - end generate; - - end generate; - --- Port B - PORT_B_REG : if (REG_EN_G = true) generate - process(clkb) - begin - if rising_edge(clkb) then - if rstb = RST_POLARITY_G then - doutb <= INIT_C after TPD_G; - elsif en_b = '1' then - doutb <= mem(conv_integer(addrb)) after TPD_G; - end if; - end if; - end process; - end generate; - - PORT_B_NOT_REG : if (REG_EN_G = false) generate - doutb <= mem(conv_integer(addrb)); - end generate; - - -- Port C - PORT_C_REG : if (REG_EN_G = true) generate - process(clkc) - begin - if rising_edge(clkc) then - if rstc = RST_POLARITY_G then - doutc <= INIT_C after TPD_G; - elsif en_c = '1' then - doutc <= mem(conv_integer(addrc)) after TPD_G; - end if; - end if; - end process; - end generate; - - PORT_C_NOT_REG : if (REG_EN_G = false) generate - doutc <= mem(conv_integer(addrc)); - end generate; - - -- Port D - PORT_D_REG : if (REG_EN_G = true) generate - process(clkd) - begin - if rising_edge(clkd) then - if rstd = RST_POLARITY_G then - doutd <= INIT_C after TPD_G; - elsif en_d = '1' then - doutd <= mem(conv_integer(addrd)) after TPD_G; - end if; - end if; - end process; - end generate; - - PORT_D_NOT_REG : if (REG_EN_G = false) generate - doutd <= mem(conv_integer(addrd)); - end generate; - -end rtl; diff --git a/dsp/fixed/FirFilterMultiChannel.vhd b/dsp/fixed/FirFilterMultiChannel.vhd new file mode 100644 index 0000000000..7d9b2e201f --- /dev/null +++ b/dsp/fixed/FirFilterMultiChannel.vhd @@ -0,0 +1,325 @@ +------------------------------------------------------------------------------- +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: Multi-Channel Finite Impulse Response (FIR) Filter +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_arith.all; + +library surf; +use surf.StdRtlPkg.all; +use surf.AxiLitePkg.all; +use surf.AxiStreamPkg.all; + +entity FirFilterMultiChannel is + generic ( + TPD_G : time := 1 ns; + TAP_SIZE_G : positive := 21; -- Number of programmable taps + CH_SIZE_G : positive := 128; -- Number of data channels + PARALLEL_G : positive := 4; -- Number of parallel channel processing + WIDTH_G : positive := 12; -- Number of bits per data word + MEMORY_INIT_FILE_G : string := "none"; -- Used to load tap coefficients into RAM at boot up + MEMORY_TYPE_G : string := "distributed"; + SYNTH_MODE_G : string := "inferred"); + port ( + -- AXI Stream Interface (axilClk domain) + axisClk : in sl; + axisRst : in sl; + sAxisMaster : in AxiStreamMasterType; + sAxisSlave : out AxiStreamSlaveType; + mAxisMaster : out AxiStreamMasterType; + mAxisSlave : in AxiStreamSlaveType; + -- AXI-Lite Interface (axilClk domain) + axilClk : in sl; + axilRst : in sl; + axilReadMaster : in AxiLiteReadMasterType; + axilReadSlave : out AxiLiteReadSlaveType; + axilWriteMaster : in AxiLiteWriteMasterType; + axilWriteSlave : out AxiLiteWriteSlaveType); +end FirFilterMultiChannel; + +architecture mapping of FirFilterMultiChannel is + + constant WORD_PER_FRAME : positive := CH_SIZE_G/PARALLEL_G; + constant RAM_ADDR_WIDTH_C : positive := bitSize(WORD_PER_FRAME-1); + + type DataArray is array (PARALLEL_G-1 downto 0) of slv(WIDTH_G-1 downto 0); + type CoeffArray is array (TAP_SIZE_G-1 downto 0, PARALLEL_G-1 downto 0) of slv(WIDTH_G-1 downto 0); + type CascArray is array (TAP_SIZE_G-1 downto 0, PARALLEL_G-1 downto 0) of slv(2*WIDTH_G downto 0); + + function toSlv (din : CascArray) return slv is + variable retValue : slv((2*WIDTH_G+1)*TAP_SIZE_G*PARALLEL_G-1 downto 0) := (others => '0'); + variable idx : integer := 0; + begin + for i in 0 to TAP_SIZE_G-1 loop + for j in 0 to PARALLEL_G-1 loop + assignSlv(idx, retValue, din(i, j)); + end loop; + end loop; + return(retValue); + end function; + + function toCascArray (din : slv) return CascArray is + variable retValue : CascArray := (others => (others => (others => '0'))); + variable idx : integer := 0; + begin + for i in 0 to TAP_SIZE_G-1 loop + for j in 0 to PARALLEL_G-1 loop + assignRecord(idx, din, retValue(i, j)); + end loop; + end loop; + return(retValue); + end function; + + function toCoeffArray (din : slv) return CoeffArray is + variable retValue : CoeffArray := (others => (others => (others => '0'))); + variable idx : integer := 0; + begin + for j in 0 to PARALLEL_G-1 loop + for i in 0 to TAP_SIZE_G-1 loop + assignRecord(idx, din, retValue(i, j)); + end loop; + end loop; + return(retValue); + end function; + + type RegType is record + ramWe : sl; + addr : slv(RAM_ADDR_WIDTH_C-1 downto 0); + datain : DataArray; + cascin : CascArray; + sAxisSlave : AxiStreamSlaveType; + axisMeta : AxiStreamMasterType; + mAxisMaster : AxiStreamMasterType; + end record RegType; + constant REG_INIT_C : RegType := ( + ramWe => '0', + addr => (others => '0'), + datain => (others => (others => '0')), + cascin => (others => (others => (others => '0'))), + sAxisSlave => AXI_STREAM_SLAVE_INIT_C, + axisMeta => AXI_STREAM_MASTER_INIT_C, + mAxisMaster => AXI_STREAM_MASTER_INIT_C); + + signal r : RegType := REG_INIT_C; + signal rin : RegType; + + signal datain : DataArray; + signal coeffin : CoeffArray; + + signal cascin : CascArray; + signal cascout : CascArray; + signal cascCache : CascArray; + + signal ramWe : sl; + signal raddr : slv(RAM_ADDR_WIDTH_C-1 downto 0); + signal waddr : slv(RAM_ADDR_WIDTH_C-1 downto 0); + signal coeffinSlv : slv(WIDTH_G*TAP_SIZE_G*PARALLEL_G-1 downto 0); + signal ramDin : slv((2*WIDTH_G+1)*TAP_SIZE_G*PARALLEL_G-1 downto 0); + signal ramDout : slv((2*WIDTH_G+1)*TAP_SIZE_G*PARALLEL_G-1 downto 0); + +begin + + assert (CH_SIZE_G mod PARALLEL_G = 0) + report "PARALLEL_G must be even number multiples of CH_SIZE_G" severity failure; + + assert (CH_SIZE_G >= PARALLEL_G) + report "CH_SIZE_G must be >= PARALLEL_G" severity failure; + + U_TapCoeff : entity surf.AxiDualPortRam + generic map ( + TPD_G => TPD_G, + SYNTH_MODE_G => ite(MEMORY_INIT_FILE_G /= "none", "xpm", SYNTH_MODE_G), + MEMORY_INIT_FILE_G => MEMORY_INIT_FILE_G, + MEMORY_TYPE_G => MEMORY_TYPE_G, + READ_LATENCY_G => 1, + ADDR_WIDTH_G => RAM_ADDR_WIDTH_C, + DATA_WIDTH_G => WIDTH_G*TAP_SIZE_G*PARALLEL_G) + port map ( + -- Axi Port + axiClk => axilClk, + axiRst => axilRst, + axiReadMaster => axilReadMaster, + axiReadSlave => axilReadSlave, + axiWriteMaster => axilWriteMaster, + axiWriteSlave => axilWriteSlave, + -- Standard Port + clk => axisClk, + addr => raddr, + dout => coeffinSlv); + + coeffin <= toCoeffArray(coeffinSlv); + + GEN_CACHE : if (WORD_PER_FRAME > 1) generate + + U_Cache : entity surf.DualPortRam + generic map ( + TPD_G => TPD_G, + MEMORY_TYPE_G => MEMORY_TYPE_G, + ADDR_WIDTH_G => RAM_ADDR_WIDTH_C, + DATA_WIDTH_G => (2*WIDTH_G+1)*TAP_SIZE_G*PARALLEL_G) + port map ( + -- Port A + clka => axisClk, + wea => ramWe, + addra => waddr, + dina => ramDin, + -- Port B + clkb => axisClk, + addrb => raddr, + doutb => ramDout); + + ramDin <= toSlv(cascout); + cascCache <= toCascArray(ramDout); + + end generate; + + comb : process (axisRst, cascCache, cascout, mAxisSlave, r, sAxisMaster) is + variable v : RegType; + begin + -- Latch the current value + v := r; + + -- Reset strobes + v.ramWe := '0'; + + -- AXI Stream Flow Control + v.sAxisSlave.tReady := '0'; + if (mAxisSlave.tReady = '1') then + v.mAxisMaster.tValid := '0'; + end if; + + -- Check for new data + if (sAxisMaster.tValid = '1') and (r.axisMeta.tValid = '0') then + + -- Accept the data + v.sAxisSlave.tReady := '1'; + + for j in PARALLEL_G-1 downto 0 loop + + -- Map to the TAPs' data inputs + v.datain(j) := sAxisMaster.tData(j*WIDTH_G+WIDTH_G-1 downto j*WIDTH_G); + + -- Load zero into the 1st tap's cascaded input + v.cascin(0, j) := (others => '0'); + + end loop; + + -- Map to the cascaded input + for i in TAP_SIZE_G-2 downto 0 loop + for j in PARALLEL_G-1 downto 0 loop + + -- Check for 1 word per frame + if (WORD_PER_FRAME = 1) then + + -- Use the previous cascade out values + v.cascin(i+1, j) := cascout(i, j); + + else + + -- Use the cached values + v.cascin(i+1, j) := cascCache(i, j); + + end if; + + end loop; + end loop; + + -- Cache the AXI stream meta data + v.axisMeta := sAxisMaster; + + end if; + + --- Check if we can move data + if (v.mAxisMaster.tValid = '0') and (r.axisMeta.tValid = '1') then + + -- Set the flags + v.axisMeta.tValid := '0'; + v.ramWe := '1'; + v.mAxisMaster := r.axisMeta; + + -- Map to the TAPs' data outputs + for j in PARALLEL_G-1 downto 0 loop + + -- Truncating the LSBs + v.mAxisMaster.tData(j*WIDTH_G+WIDTH_G-1 downto j*WIDTH_G) := cascout(TAP_SIZE_G-1, j)(2*WIDTH_G-1 downto WIDTH_G); + + end loop; + + -- Check for tLast + if (r.axisMeta.tLast = '1') then + -- Reset the counter + v.addr := (others => '0'); + else + -- Increment the counter + v.addr := r.addr + 1; + end if; + + end if; + + -- AXI stream Outputs + sAxisSlave <= v.sAxisSlave; -- Comb output + mAxisMaster <= r.mAxisMaster; + + -- RAM Outputs + ramWe <= v.ramWe; -- Comb output + waddr <= r.addr; + raddr <= v.addr; -- Comb output + + -- FIR TAP Outputs + datain <= v.datain; -- Comb output + cascin <= v.cascin; -- Comb output + + -- Reset + if (axisRst = '1') then + v := REG_INIT_C; + end if; + + -- Register the variable for next clock cycle + rin <= v; + + end process comb; + + seq : process (axisClk) is + begin + if rising_edge(axisClk) then + r <= rin after TPD_G; + end if; + end process seq; + + GEN_TAP : + for i in TAP_SIZE_G-1 downto 0 generate + + GEN_PARALLEL : + for j in PARALLEL_G-1 downto 0 generate + + U_Tap : entity surf.FirFilterTap + generic map ( + TPD_G => TPD_G, + WIDTH_G => WIDTH_G) + port map ( + -- Clock Only (Infer into DSP) + clk => axisClk, + -- Data and tap coefficient Interface + datain => datain(j), -- Common data input because Transpose Multiply-Accumulate architecture + coeffin => coeffin(TAP_SIZE_G-1-i, j), -- Reversed order because Transpose Multiply-Accumulate architecture + -- Cascade Interface + cascin => cascin(i, j), + cascout => cascout(i, j)); + + end generate GEN_PARALLEL; + + end generate GEN_TAP; + +end mapping; diff --git a/dsp/fixed/FirFilterSingleChannel.vhd b/dsp/fixed/FirFilterSingleChannel.vhd new file mode 100644 index 0000000000..22cbc0ceed --- /dev/null +++ b/dsp/fixed/FirFilterSingleChannel.vhd @@ -0,0 +1,251 @@ +------------------------------------------------------------------------------- +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: Single Channel Finite Impulse Response (FIR) Filter +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library surf; +use surf.StdRtlPkg.all; +use surf.AxiLitePkg.all; + +entity FirFilterSingleChannel is + generic ( + TPD_G : time := 1 ns; + RST_POLARITY_G : sl := '1'; -- '1' for active high rst, '0' for active low + PIPE_STAGES_G : natural := 0; + COMMON_CLK_G : boolean := false; + TAP_SIZE_G : positive; -- Number of programmable taps + WIDTH_G : positive; -- Number of bits per data word + COEFFICIENTS_G : IntegerArray); -- Tap Coefficients Init Constants + port ( + -- Clock and Reset + clk : in sl; + rst : in sl := not(RST_POLARITY_G); + -- Inbound Interface + ibValid : in sl := '1'; + ibReady : out sl; + din : in slv(WIDTH_G-1 downto 0); + -- Outbound Interface + obValid : out sl; + obReady : in sl := '1'; + dout : out slv(WIDTH_G-1 downto 0); + -- AXI-Lite Interface (axilClk domain) + axilClk : in sl; + axilRst : in sl; + axilReadMaster : in AxiLiteReadMasterType; + axilReadSlave : out AxiLiteReadSlaveType; + axilWriteMaster : in AxiLiteWriteMasterType; + axilWriteSlave : out AxiLiteWriteSlaveType); +end FirFilterSingleChannel; + +architecture mapping of FirFilterSingleChannel is + + type CoeffArray is array (TAP_SIZE_G-1 downto 0) of slv(WIDTH_G-1 downto 0); + type CascArray is array (TAP_SIZE_G-1 downto 0) of slv(2*WIDTH_G downto 0); + + impure function InitCoeffArray return CoeffArray is + variable retValue : CoeffArray := (others => (others => '0')); + begin + for i in 0 to TAP_SIZE_G-1 loop + retValue(i) := std_logic_vector(to_signed(COEFFICIENTS_G(i), WIDTH_G)); + end loop; + return(retValue); + end function; + + constant COEFFICIENTS_C : CoeffArray := InitCoeffArray; + + constant NUM_ADDR_BITS_C : positive := bitSize(TAP_SIZE_G-1)+2; + + type RegType is record + cnt : natural range 0 to TAP_SIZE_G-1; + datain : slv(WIDTH_G-1 downto 0); + cascin : CascArray; + coeffin : CoeffArray; + ibReady : sl; + tValid : sl; + tdata : slv(WIDTH_G-1 downto 0); + readSlave : AxiLiteReadSlaveType; + writeSlave : AxiLiteWriteSlaveType; + end record RegType; + constant REG_INIT_C : RegType := ( + cnt => 0, + datain => (others => '0'), + cascin => (others => (others => '0')), + coeffin => COEFFICIENTS_C, + ibReady => '0', + tValid => '0', + tdata => (others => '0'), + readSlave => AXI_LITE_READ_SLAVE_INIT_C, + writeSlave => AXI_LITE_WRITE_SLAVE_INIT_C); + + signal r : RegType := REG_INIT_C; + signal rin : RegType; + + signal cascin : CascArray; + signal cascout : CascArray; + + signal datain : slv(WIDTH_G-1 downto 0); + signal tReady : sl; + + signal readMaster : AxiLiteReadMasterType; + signal readSlave : AxiLiteReadSlaveType; + signal writeMaster : AxiLiteWriteMasterType; + signal writeSlave : AxiLiteWriteSlaveType; + +begin + + U_AxiLiteAsync : entity surf.AxiLiteAsync + generic map ( + TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, + NUM_ADDR_BITS_G => NUM_ADDR_BITS_C) + port map ( + -- Slave Interface + sAxiClk => axilClk, + sAxiClkRst => axilRst, + sAxiReadMaster => axilReadMaster, + sAxiReadSlave => axilReadSlave, + sAxiWriteMaster => axilWriteMaster, + sAxiWriteSlave => axilWriteSlave, + -- Master Interface + mAxiClk => clk, + mAxiClkRst => rst, + mAxiReadMaster => readMaster, + mAxiReadSlave => readSlave, + mAxiWriteMaster => writeMaster, + mAxiWriteSlave => writeSlave); + + comb : process (cascout, din, ibValid, r, readMaster, rst, tReady, + writeMaster) is + variable v : RegType; + variable axilEp : AxiLiteEndPointType; + begin + -- Latch the current value + v := r; + + -- Determine the transaction type + axiSlaveWaitTxn(axilEp, writeMaster, readMaster, v.writeSlave, v.readSlave); + + -- Map the registers + for i in TAP_SIZE_G-1 downto 0 loop + axiSlaveRegister (axilEp, toSlv((4*i), NUM_ADDR_BITS_C), 0, v.coeffin(i)); + end loop; + + -- Closeout the transaction + axiSlaveDefault(axilEp, v.writeSlave, v.readSlave, AXI_RESP_DECERR_C); + + -- Flow Control + v.ibReady := '0'; + if (tReady = '1') then + v.tValid := '0'; + end if; + + -- Check for new data + if (ibValid = '1') and (v.tValid = '0') then + + -- Accept the data + v.ibReady := '1'; + + -- Latch the value + v.datain := din; + + -- Load zero into the 1st tap's cascaded input + v.cascin(0) := (others => '0'); + + -- Map to the cascaded input + for i in TAP_SIZE_G-2 downto 0 loop + + -- Use the previous cascade out values + v.cascin(i+1) := cascout(i); + + end loop; + + -- Truncating the LSBs + v.tData := cascout(TAP_SIZE_G-1)(2*WIDTH_G-1 downto WIDTH_G); + + -- Check the latency init counter + if (r.cnt = TAP_SIZE_G-1) then + -- Output data now valid + v.tValid := '1'; + else + -- Increment the count + v.cnt := r.cnt + 1; + end if; + + end if; + + -- Outputs + writeSlave <= r.writeSlave; + readSlave <= r.readSlave; + ibReady <= v.ibReady; + datain <= v.datain; + cascin <= v.cascin; + + -- Reset + if (rst = RST_POLARITY_G) then + v := REG_INIT_C; + end if; + + -- Register the variable for next clock cycle + rin <= v; + + end process comb; + + seq : process (clk) is + begin + if rising_edge(clk) then + r <= rin after TPD_G; + end if; + end process seq; + + GEN_TAP : + for i in TAP_SIZE_G-1 downto 0 generate + + U_Tap : entity surf.FirFilterTap + generic map ( + TPD_G => TPD_G, + WIDTH_G => WIDTH_G) + port map ( + -- Clock Only (Infer into DSP) + clk => clk, + -- Data and tap coefficient Interface + datain => datain, -- Common data input because Transpose Multiply-Accumulate architecture + coeffin => r.coeffin(TAP_SIZE_G-1-i), -- Reversed order because Transpose Multiply-Accumulate architecture + -- Cascade Interface + cascin => cascin(i), + cascout => cascout(i)); + + end generate GEN_TAP; + + U_Pipe : entity surf.FifoOutputPipeline + generic map ( + TPD_G => TPD_G, + RST_POLARITY_G => RST_POLARITY_G, + DATA_WIDTH_G => WIDTH_G, + PIPE_STAGES_G => PIPE_STAGES_G) + port map ( + -- Slave Port + sData => r.tdata, + sValid => r.tValid, + sRdEn => tReady, + -- Master Port + mData => dout, + mValid => obValid, + mRdEn => obReady, + -- Clock and Reset + clk => clk, + rst => rst); + +end mapping; diff --git a/dsp/fixed/FirFilterTap.vhd b/dsp/fixed/FirFilterTap.vhd new file mode 100644 index 0000000000..802ac081a6 --- /dev/null +++ b/dsp/fixed/FirFilterTap.vhd @@ -0,0 +1,86 @@ +------------------------------------------------------------------------------- +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: Using Transpose Multiply-Accumulate for FIR engine stage +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library surf; +use surf.StdRtlPkg.all; + +entity FirFilterTap is + generic ( + TPD_G : time := 1 ns; + WIDTH_G : positive := 12); + port ( + -- Clock Only (Infer into DSP) + clk : in sl; + -- Data and tap coefficient Interface + datain : in slv(WIDTH_G-1 downto 0); + coeffin : in slv(WIDTH_G-1 downto 0); + -- Cascade Interface + cascin : in slv(2*WIDTH_G downto 0); + cascout : out slv(2*WIDTH_G downto 0)); +end FirFilterTap; + +architecture rtl of FirFilterTap is + + type RegType is record + accum : signed(2*WIDTH_G downto 0); + end record RegType; + constant REG_INIT_C : RegType := ( + accum => (others => '0')); + + signal r : RegType := REG_INIT_C; + signal rin : RegType; + +begin + + comb : process (cascin, coeffin, datain, r) is + variable v : RegType; + variable din : signed(WIDTH_G-1 downto 0); + variable coeff : signed(WIDTH_G-1 downto 0); + variable product : signed(2*WIDTH_G-1 downto 0); + variable cascade : signed(2*WIDTH_G downto 0); + begin + -- Latch the current value + v := r; + + -- typecast from slv to signed + din := signed(datain); + coeff := signed(coeffin); + cascade := signed(cascin); + + -- Multiplier + product := din * coeff; + + -- Accumulator + v.accum := resize(product, 2*WIDTH_G) + cascade; + + -- Register the variable for next clock cycle + rin <= v; + + -- Outputs + cascout <= std_logic_vector(r.accum); + + end process comb; + + seq : process (clk) is + begin + if rising_edge(clk) then + r <= rin after TPD_G; + end if; + end process seq; + +end rtl; diff --git a/dsp/tb/FirFilterSingleChannelTb.vhd b/dsp/tb/FirFilterSingleChannelTb.vhd new file mode 100644 index 0000000000..601909ca03 --- /dev/null +++ b/dsp/tb/FirFilterSingleChannelTb.vhd @@ -0,0 +1,230 @@ +------------------------------------------------------------------------------- +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.math_real.all; + +library surf; +use surf.StdRtlPkg.all; +use surf.AxiLitePkg.all; + +entity FirFilterSingleChannelTb is end FirFilterSingleChannelTb; + +architecture testbed of FirFilterSingleChannelTb is + + constant TPD_G : time := 1 ns; + + constant WIDTH_C : positive := 12; + constant TAP_SIZE_C : positive := 101; + + --------------------------------------------------------------- + -- Python Code to generate FIR taps for 1 MHz low pass filter + --------------------------------------------------------------- + -- taps = scipy.signal.firwin(101, cutoff = 1.0e6/nyquist_freq, window = "hanning") + -- for i in range(len(taps)): + -- taps[i] = floor(taps[i]*4096); + -- print( f'{i} => {int(taps[i])},' ) + --------------------------------------------------------------- + constant COEFFICIENTS_C : IntegerArray(TAP_SIZE_C-1 downto 0) := ( + 0 => 0, + 1 => 0, + 2 => 0, + 3 => 0, + 4 => 0, + 5 => 0, + 6 => 0, + 7 => 0, + 8 => 1, + 9 => 1, + 10 => 2, + 11 => 2, + 12 => 3, + 13 => 4, + 14 => 6, + 15 => 7, + 16 => 9, + 17 => 11, + 18 => 12, + 19 => 15, + 20 => 17, + 21 => 20, + 22 => 22, + 23 => 25, + 24 => 28, + 25 => 31, + 26 => 35, + 27 => 38, + 28 => 42, + 29 => 46, + 30 => 49, + 31 => 53, + 32 => 57, + 33 => 61, + 34 => 64, + 35 => 68, + 36 => 72, + 37 => 75, + 38 => 78, + 39 => 82, + 40 => 85, + 41 => 87, + 42 => 90, + 43 => 92, + 44 => 94, + 45 => 96, + 46 => 97, + 47 => 99, + 48 => 99, + 49 => 100, + 50 => 100, + 51 => 100, + 52 => 99, + 53 => 99, + 54 => 97, + 55 => 96, + 56 => 94, + 57 => 92, + 58 => 90, + 59 => 87, + 60 => 85, + 61 => 82, + 62 => 78, + 63 => 75, + 64 => 72, + 65 => 68, + 66 => 64, + 67 => 61, + 68 => 57, + 69 => 53, + 70 => 49, + 71 => 46, + 72 => 42, + 73 => 38, + 74 => 35, + 75 => 31, + 76 => 28, + 77 => 25, + 78 => 22, + 79 => 20, + 80 => 17, + 81 => 15, + 82 => 12, + 83 => 11, + 84 => 9, + 85 => 7, + 86 => 6, + 87 => 4, + 88 => 3, + 89 => 2, + 90 => 2, + 91 => 1, + 92 => 1, + 93 => 0, + 94 => 0, + 95 => 0, + 96 => 0, + 97 => 0, + 98 => 0, + 99 => 0, + 100 => 0); + + type RegType is record + t : real; + din : slv(WIDTH_C-1 downto 0); + end record RegType; + constant REG_INIT_C : RegType := ( + t => 0.0, + din => (others => '0')); + + signal r : RegType := REG_INIT_C; + signal rin : RegType; + + signal clk : sl := '0'; + signal rst : sl := '1'; + + signal dout : slv(WIDTH_C-1 downto 0) := (others => '0'); + +begin + + U_ClkRst : entity surf.ClkRst + generic map ( + CLK_PERIOD_G => 10 ns, -- 100 MHz + RST_START_DELAY_G => 0 ns, + RST_HOLD_TIME_G => 1000 ns) + port map ( + clkP => clk, + rst => rst); + + U_Fir : entity surf.FirFilterSingleChannel + generic map ( + TPD_G => TPD_G, + TAP_SIZE_G => TAP_SIZE_C, -- Number of programmable taps + WIDTH_G => WIDTH_C, -- Number of bits per data word + COEFFICIENTS_G => COEFFICIENTS_C) -- Tap Coefficients Init Constants + port map ( + -- Clock and Reset + clk => clk, + rst => rst, + -- Inbound Interface + din => r.din, + -- Outbound Interface + dout => dout, + -- AXI-Lite Interface (axilClk domain) + axilClk => clk, + axilRst => rst, + axilReadMaster => AXI_LITE_READ_MASTER_INIT_C, + axilReadSlave => open, + axilWriteMaster => AXI_LITE_WRITE_MASTER_INIT_C, + axilWriteSlave => open); + + comb : process (r, rst) is + variable v : RegType; + variable retValue : real; + begin + -- Latch the current value + v := r; + + -- Init + retValue := 0.0; + + -- 100 kHz Sine-wave (will NOT get filtered out) + retValue := retValue + 1000.0*sin(2.0*MATH_PI*0.1E+6*r.t); + + -- 10 MHz Sine-wave (will get filtered out) + retValue := retValue + 1000.0*sin(2.0*MATH_PI*10.0E+6*r.t); + + -- Assign to output + v.din := std_logic_vector(to_signed(integer(retValue), WIDTH_C)); + + -- Calculate next time sample + v.t := r.t + 10.0E-9; + + -- Reset + if (rst = '1') then + v := REG_INIT_C; + end if; + + -- Register the variable for next clock cycle + rin <= v; + + end process comb; + + seq : process (clk) is + begin + if rising_edge(clk) then + r <= rin after TPD_G; + end if; + end process seq; + +end testbed; diff --git a/ethernet/RawEthFramer/rtl/RawEthFramerTx.vhd b/ethernet/RawEthFramer/rtl/RawEthFramerTx.vhd index d6ee97cd24..db79f4fbd6 100644 --- a/ethernet/RawEthFramer/rtl/RawEthFramerTx.vhd +++ b/ethernet/RawEthFramer/rtl/RawEthFramerTx.vhd @@ -95,9 +95,10 @@ architecture rtl of RawEthFramerTx is begin - U_MinEthCache : entity surf.QuadPortRam + U_MinEthCache : entity surf.LutRam generic map ( TPD_G => TPD_G, + NUM_PORTS_G => 2, REG_EN_G => false, -- 1 cycle read DATA_WIDTH_G => 64, ADDR_WIDTH_G => 3) diff --git a/protocols/pgp/pgp2b/gtyUltraScale+/ip/PgpGtyCore.dcp b/protocols/pgp/pgp2b/gtyUltraScale+/ip/PgpGtyCore.dcp new file mode 100644 index 0000000000..09345c2008 --- /dev/null +++ b/protocols/pgp/pgp2b/gtyUltraScale+/ip/PgpGtyCore.dcp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:53ae761ec01ce7e2973284a6c8d6f1148f527bbdd20efd1062bec0921ff7d2c8 +size 445718 diff --git a/protocols/pgp/pgp2b/gtyUltraScale+/ip/PgpGtyCore.txt b/protocols/pgp/pgp2b/gtyUltraScale+/ip/PgpGtyCore.txt new file mode 100644 index 0000000000..40796a74ec --- /dev/null +++ b/protocols/pgp/pgp2b/gtyUltraScale+/ip/PgpGtyCore.txt @@ -0,0 +1,20 @@ +## LLR - 22SEPT2020 +## After generating each of the .DCP files from their corresponding .XCI files, +## performed the following TCL commands in the DCP to generate a modified DCP file: + +# Remove the IO Lock Constraints +set_property is_loc_fixed false [get_ports [list gtytxp_out[0]]] +set_property is_loc_fixed false [get_ports [list gtytxn_out[0]]] +set_property is_loc_fixed false [get_ports [list gtyrxp_in[0]]] +set_property is_loc_fixed false [get_ports [list gtyrxn_in[0]]] + +# Removed the IO location Constraints +set_property package_pin "" [get_ports [list gtytxp_out[0]]] +set_property package_pin "" [get_ports [list gtytxn_out[0]]] +set_property package_pin "" [get_ports [list gtyrxp_in[0]]] +set_property package_pin "" [get_ports [list gtyrxn_in[0]]] + +# Removed the Placement Constraints +set_property is_bel_fixed false [get_cells -hierarchical *GTYE4_CHANNEL_PRIM_INST*] +set_property is_loc_fixed false [get_cells -hierarchical *GTYE4_CHANNEL_PRIM_INST*] +unplace_cell [get_cells -hierarchical *GTYE4_CHANNEL_PRIM_INST*] diff --git a/protocols/pgp/pgp2b/gtyUltraScale+/ip/PgpGtyCore.xci b/protocols/pgp/pgp2b/gtyUltraScale+/ip/PgpGtyCore.xci new file mode 100644 index 0000000000..e56f2607bf --- /dev/null +++ b/protocols/pgp/pgp2b/gtyUltraScale+/ip/PgpGtyCore.xci @@ -0,0 +1,1405 @@ + + + xilinx.com + xci + unknown + 1.0 + + + PgpGtyCore + + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + 1 + 3125.0 + 0 + 0 + 156.25 + 67 + 3 + 2 + 0 + 2 + 0 + 0 + 1 + 0 + 1 + 0 + 250 + 0 + 0 + 0 + 0 + 0 + 1 + "00000000" + "00000000" + 1 + 1 + 0 + "00000000000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000" + 1 + "00001111" + 4 + 1 + 5000 + "00000000000000000000000000000000000000000000011100000001110000000111000010111100" + 1 + "1010000011" + 1 + "0101111100" + 1 + 1 + 20 + 3.125 + 0 + 1 + 156.2500000 + 1 + 2 + 0x000000000000000000000000000000000000000000000000 + 156.25 + 0 + 0 + 0 + 1 + 1 + 0 + 16 + 156.2500000 + 156.2500000 + 0 + 257.8125 + 1 + 1 + 0 + 0 + 0 + 2 + 156.25 + 0 + 0 + 1 + 1 + 1 + 20 + 3.125 + 0 + 1 + 156.2500000 + 1 + 2 + 156.25 + 0 + 0 + 1 + 1 + 0 + 16 + 156.2500000 + 156.2500000 + 1 + X0Y0 + PgpGtyCore + 0 + 0 + drpaddr_in drpclk_in drpdi_in drpen_in drpwe_in loopback_in rxpolarity_in txpolarity_in drpdo_out drprdy_out + 156.25 + BOTH + 0 + GTY + 2 + 14 + 96 + 5 + gtye4 + 0 + 0 + -1 + -1 + -1 + -1 + -1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -1 + 0 + -1 + 0 + -1 + 0 + -1 + 0 + -1 + 0 + -1 + 0 + 0 + -1 + 0 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + 0 + -1 + 0 + 0 + 0 + -1 + -1 + 0 + -1 + -1 + -1 + -1 + -1 + -1 + 0 + -1 + -1 + 0 + 1 + -1 + -1 + 1 + -1 + -1 + 0 + 0 + -1 + 0 + 0 + -1 + -1 + -1 + 0 + -1 + -1 + 0 + 0 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + 1 + 1 + -1 + -1 + -1 + -1 + 1 + 1 + -1 + 1 + 1 + 1 + -1 + 1 + 1 + 1 + -1 + -1 + -1 + -1 + -1 + 1 + -1 + 1 + -1 + -1 + -1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 0 + -1 + -1 + -1 + 0 + 0 + 0 + -1 + -1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -1 + 0 + 0 + 0 + 0 + -1 + -1 + -1 + -1 + -1 + 0 + -1 + -1 + 0 + -1 + -1 + 0 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + 0 + -1 + -1 + -1 + 0 + -1 + -1 + 0 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + 0 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + 0 + 0 + -1 + 1 + 0 + 1 + 1 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + -1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 1 + 0 + 0 + 1 + 1 + 1 + 1 + 0 + 0 + 0 + -1 + -1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + -1 + 0 + -1 + -1 + -1 + 0 + 0 + 0 + -1 + -1 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -1 + -1 + -1 + -1 + 0 + 0 + 0 + -1 + -1 + -1 + -1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -1 + 1 + 1 + 0 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + 0 + -1 + -1 + -1 + -1 + -1 + -1 + 0 + 0 + 1 + -1 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 0 + -1 + 0 + 0 + 0 + 0 + 0 + 0 + -1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + -1 + 0 + 0 + 0 + -1 + 0 + 0 + -1 + -1 + -1 + -1 + -1 + -1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -1 + 1 + 1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + 29 + 0 + Aurora_8B10B + 8 + 156.2500000 + 1 + 0 + 156.2500000 + true + CORE + NONE + CORE + CORE + EXAMPLE_DESIGN + CORE + EXAMPLE_DESIGN + CORE + false + NAME + false + 250 + false + false + 250 + GTY-Aurora_8B10B + 0 + MULTI + 1 + ENABLE + DISABLE + ENABLE + 00000000 + false + false + false + false + false + false + false + false + 00000000 + false + false + false + false + false + false + false + false + 1 + 00000000 + false + false + false + false + false + false + false + false + 1 + 1 + 0 + 00000000000000000000000000000000000000000000000000000000000000000000000000000000 + 00000000 + 00000000 + 00000000 + 00000000 + 00000000 + 00000000 + 00000000 + 00000000 + 00000000 + false + false + false + false + false + false + false + false + 00001111 + DISABLE + true + true + true + true + false + false + false + false + 4 + 00000000 + false + false + false + false + false + false + false + false + 1 + 5000 + ENABLE + 0 + 00000000000000000000000000000000000000000000011100000001110000000111000010111100 + 10111100 + 00011100 + 00011100 + 00011100 + 00000000 + 00000000 + 00000000 + 00000000 + 2 + false + 1111111111 + true + 1010000011 + K28.5 + true + 0101111100 + true + 0 + AC + 8B10B + true + AUTO + 20 + 1.8746251 + -20 + 3.125 + X0Y0 + RXOUTCLKPMA + CPLL + 200 + 0 + + 156.25 + + OFF + 0 + PROGRAMMABLE + 800 + 16 + 15 + false + 0 + 10.3125 + 257.8125 + 1 + false + CPLL + 156.25 + 1 + ENABLE + 8B10B + CUSTOM + true + 20 + 3.125 + X0Y0 + TXOUTCLKPMA + CPLL + 0 + 156.25 + + 16 + false + 1 + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + true + false + false + true + false + true + false + true + false + true + false + false + true + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + true + false + false + true + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + true + true + false + false + false + false + true + true + false + true + true + true + false + true + true + true + false + false + false + false + false + true + false + true + false + false + false + true + true + true + true + true + true + false + true + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + true + false + true + true + true + true + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + true + false + true + true + false + false + true + true + true + true + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + true + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + true + false + false + false + true + false + false + false + false + false + false + false + false + false + false + false + true + true + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + true + true + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + true + false + false + false + false + false + false + true + true + true + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + true + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + true + true + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + true + true + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + false + kintexuplus + xilinx.com:kcu116:part0:1.2 + + xcku5p + ffvb676 + VHDL + + MIXED + -2 + + E + TRUE + TRUE + IP_Flow + 8 + TRUE + . + + . + 2020.1 + OUT_OF_CONTEXT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/protocols/pgp/pgp2b/gtyUltraScale+/rtl/Pgp2bGtyUltra.vhd b/protocols/pgp/pgp2b/gtyUltraScale+/rtl/Pgp2bGtyUltra.vhd new file mode 100644 index 0000000000..c8f32fd6ec --- /dev/null +++ b/protocols/pgp/pgp2b/gtyUltraScale+/rtl/Pgp2bGtyUltra.vhd @@ -0,0 +1,223 @@ +------------------------------------------------------------------------------- +-- Title : PGPv2b: https://confluence.slac.stanford.edu/x/q86fD +------------------------------------------------------------------------------- +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: PGPv2b GTY Ultrascale Core Module +------------------------------------------------------------------------------- +-- This file is part of 'Example Project Firmware'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'Example Project Firmware', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + + +library surf; +use surf.StdRtlPkg.all; +use surf.AxiStreamPkg.all; +use surf.AxiLitePkg.all; +use surf.Pgp2bPkg.all; + +library UNISIM; +use UNISIM.VCOMPONENTS.all; + +entity Pgp2bGtyUltra is + generic ( + TPD_G : time := 1 ns; + ---------------------------------------------------------------------------------------------- + -- PGP Settings + ---------------------------------------------------------------------------------------------- + TX_POLARITY_G : sl := '0'; + RX_POLARITY_G : sl := '0'; + TX_ENABLE_G : boolean := true; + RX_ENABLE_G : boolean := true; + PAYLOAD_CNT_TOP_G : integer := 7; -- Top bit for payload counter + VC_INTERLEAVE_G : integer := 0; -- Interleave Frames + NUM_VC_EN_G : integer range 1 to 4 := 4); + port ( + -- GT Clocking + stableClk : in sl; -- GT needs a stable clock to "boot up" + stableRst : in sl; + gtRefClk : in sl; + -- Gt Serial IO + pgpGtTxP : out sl; + pgpGtTxN : out sl; + pgpGtRxP : in sl; + pgpGtRxN : in sl; + -- Tx Clocking + pgpTxReset : in sl; + pgpTxResetDone : out sl; + pgpTxOutClk : out sl; -- recovered clock + pgpTxClk : in sl; + pgpTxMmcmLocked : in sl; + -- Rx clocking + pgpRxReset : in sl; + pgpRxResetDone : out sl; + pgpRxOutClk : out sl; -- recovered clock + pgpRxClk : in sl; + pgpRxMmcmLocked : in sl; + -- Non VC Rx Signals + pgpRxIn : in Pgp2bRxInType; + pgpRxOut : out Pgp2bRxOutType; + -- Non VC Tx Signals + pgpTxIn : in Pgp2bTxInType; + pgpTxOut : out Pgp2bTxOutType; + -- Frame Transmit Interface - 1 Lane, Array of 4 VCs + pgpTxMasters : in AxiStreamMasterArray(3 downto 0) := (others => AXI_STREAM_MASTER_INIT_C); + pgpTxSlaves : out AxiStreamSlaveArray(3 downto 0); + -- Frame Receive Interface - 1 Lane, Array of 4 VCs + pgpRxMasters : out AxiStreamMasterArray(3 downto 0); + pgpRxMasterMuxed : out AxiStreamMasterType; + pgpRxCtrl : in AxiStreamCtrlArray(3 downto 0); + -- AXI-Lite DRP interface + axilClk : in sl := '0'; + axilRst : in sl := '0'; + axilReadMaster : in AxiLiteReadMasterType := AXI_LITE_READ_MASTER_INIT_C; + axilReadSlave : out AxiLiteReadSlaveType; + axilWriteMaster : in AxiLiteWriteMasterType := AXI_LITE_WRITE_MASTER_INIT_C; + axilWriteSlave : out AxiLiteWriteSlaveType); +end Pgp2bGtyUltra; + +architecture mapping of Pgp2bGtyUltra is + + signal resetGtSync : sl; + signal gtHardReset : sl; + + -- PgpRx Signals + signal resetRxSync : sl; + signal gtRxUserReset : sl; + signal phyRxLaneIn : Pgp2bRxPhyLaneInType; + signal phyRxLaneOut : Pgp2bRxPhyLaneOutType; + signal phyRxReady : sl; + signal phyRxInit : sl; + + -- PgpTx Signals + signal gtTxUserReset : sl; + signal phyTxLaneOut : Pgp2bTxPhyLaneOutType; + signal phyTxReady : sl; + + signal phyRxInitSync : sl; + +begin + + pgpTxResetDone <= phyTxReady; + pgpRxResetDone <= phyRxReady; + + U_RstSync_1 : entity surf.PwrUpRst + generic map ( + TPD_G => TPD_G, + DURATION_G => 125000000) + port map ( + arst => pgpTxIn.resetGt, -- [in] + clk => stableClk, -- [in] + rstOut => resetGtSync); -- [out] + + gtHardReset <= resetGtSync or stableRst; + + U_RstSync_4 : entity surf.SynchronizerOneShot + generic map ( + TPD_G => TPD_G, + PULSE_WIDTH_G => 12500000) + port map ( + clk => stableClk, -- [in] + dataIn => phyRxInit, -- [in] + dataOut => phyRxInitSync); -- [out] + + -- Sync pgpRxIn.rxReset to stableClk and tie to gtRxUserReset + U_RstSync_2 : entity surf.PwrUpRst + generic map ( + TPD_G => TPD_G, + DURATION_G => 125000000) + port map ( + arst => pgpRxIn.resetRx, -- [in] + clk => stableClk, -- [in] + rstOut => resetRxSync); -- [out] + + gtRxUserReset <= phyRxInitSync or resetRxSync; + + U_RstSync_3 : entity surf.PwrUpRst + generic map ( + TPD_G => TPD_G, + DURATION_G => 125000000) + port map ( + arst => pgpTxIn.resetTx, -- [in] + clk => stableClk, -- [in] + rstOut => gtTxUserReset); -- [out] + + U_Pgp2bLane : entity surf.Pgp2bLane + generic map ( + LANE_CNT_G => 1, + VC_INTERLEAVE_G => VC_INTERLEAVE_G, + PAYLOAD_CNT_TOP_G => PAYLOAD_CNT_TOP_G, + NUM_VC_EN_G => NUM_VC_EN_G, + TX_ENABLE_G => TX_ENABLE_G, + RX_ENABLE_G => RX_ENABLE_G) + port map ( + pgpTxClk => pgpTxClk, + pgpTxClkRst => pgpTxReset, + pgpTxIn => pgpTxIn, + pgpTxOut => pgpTxOut, + pgpTxMasters => pgpTxMasters, + pgpTxSlaves => pgpTxSlaves, + phyTxLanesOut(0) => phyTxLaneOut, + phyTxReady => phyTxReady, + pgpRxClk => pgpRxClk, + pgpRxClkRst => pgpRxReset, + pgpRxIn => pgpRxIn, + pgpRxOut => pgpRxOut, + pgpRxMasters => pgpRxMasters, + pgpRxMasterMuxed => pgpRxMasterMuxed, + pgpRxCtrl => pgpRxCtrl, + phyRxLanesOut(0) => phyRxLaneOut, + phyRxLanesIn(0) => phyRxLaneIn, + phyRxReady => phyRxReady, + phyRxInit => phyRxInit); + + -------------------------- + -- Wrapper for GTY IP core + -------------------------- + PgpGtyCoreWrapper_1 : entity surf.PgpGtyCoreWrapper + generic map ( + TPD_G => TPD_G) + port map ( + stableClk => stableClk, + stableRst => gtHardReset, + gtRefClk => gtRefClk, + gtRxP => pgpGtRxP, + gtRxN => pgpGtRxN, + gtTxP => pgpGtTxP, + gtTxN => pgpGtTxN, + rxReset => gtRxUserReset, + rxUsrClkActive => pgpRxMmcmLocked, + rxResetDone => phyRxReady, + rxUsrClk => pgpRxClk, + rxData => phyRxLaneIn.data, + rxDataK => phyRxLaneIn.dataK, + rxDispErr => phyRxLaneIn.dispErr, + rxDecErr => phyRxLaneIn.decErr, + rxPolarity => RX_POLARITY_G, + rxOutClk => pgpRxOutClk, + txReset => gtTxUserReset, + txUsrClk => pgpTxClk, + txUsrClkActive => pgpTxMmcmLocked, + txResetDone => phyTxReady, + txData => phyTxLaneOut.data, + txDataK => phyTxLaneOut.dataK, + txPolarity => TX_POLARITY_G, + txOutClk => pgpTxOutClk, + loopback => pgpRxIn.loopback, + axilClk => axilClk, + axilRst => axilRst, + axilReadMaster => axilReadMaster, + axilReadSlave => axilReadSlave, + axilWriteMaster => axilWriteMaster, + axilWriteSlave => axilWriteSlave); + +end mapping; diff --git a/protocols/pgp/pgp2b/gtyUltraScale+/rtl/PgpGtyCoreWrapper.vhd b/protocols/pgp/pgp2b/gtyUltraScale+/rtl/PgpGtyCoreWrapper.vhd new file mode 100644 index 0000000000..f6f8fdac86 --- /dev/null +++ b/protocols/pgp/pgp2b/gtyUltraScale+/rtl/PgpGtyCoreWrapper.vhd @@ -0,0 +1,239 @@ +------------------------------------------------------------------------------- +-- Title : PGPv2b: https://confluence.slac.stanford.edu/x/q86fD +------------------------------------------------------------------------------- +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: PGPv2b GTY Ultrascale IP Core Wrapper +------------------------------------------------------------------------------- +-- This file is part of 'Example Project Firmware'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'Example Project Firmware', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +library surf; +use surf.StdRtlPkg.all; +use surf.AxiLitePkg.all; + +entity PgpGtyCoreWrapper is + + generic ( + TPD_G : time := 1 ns); + port ( + stableClk : in sl; + stableRst : in sl; + -- GTY FPGA IO + gtRefClk : in sl; + gtRxP : in sl; + gtRxN : in sl; + gtTxP : out sl; + gtTxN : out sl; + + -- Rx ports + rxReset : in sl; + rxUsrClkActive : in sl; + rxResetDone : out sl; + rxUsrClk : in sl; + rxData : out slv(15 downto 0); + rxDataK : out slv(1 downto 0); + rxDispErr : out slv(1 downto 0); + rxDecErr : out slv(1 downto 0); + rxPolarity : in sl; + rxOutClk : out sl; + + -- Tx Ports + txReset : in sl; + txUsrClk : in sl; + txUsrClkActive : in sl; + txResetDone : out sl; + txData : in slv(15 downto 0); + txDataK : in slv(1 downto 0); + txPolarity : in sl; + txOutClk : out sl; + loopback : in slv(2 downto 0); + + -- AXI-Lite DRP interface + axilClk : in sl := '0'; + axilRst : in sl := '0'; + axilReadMaster : in AxiLiteReadMasterType := AXI_LITE_READ_MASTER_INIT_C; + axilReadSlave : out AxiLiteReadSlaveType; + axilWriteMaster : in AxiLiteWriteMasterType := AXI_LITE_WRITE_MASTER_INIT_C; + axilWriteSlave : out AxiLiteWriteSlaveType); + +end entity PgpGtyCoreWrapper; + +architecture mapping of PgpGtyCoreWrapper is + + component PgpGtyCore + port ( + gtwiz_userclk_tx_reset_in : in std_logic_vector(0 downto 0); + gtwiz_userclk_tx_active_in : in std_logic_vector(0 downto 0); + gtwiz_userclk_rx_active_in : in std_logic_vector(0 downto 0); + gtwiz_reset_clk_freerun_in : in std_logic_vector(0 downto 0); + gtwiz_reset_all_in : in std_logic_vector(0 downto 0); + gtwiz_reset_tx_pll_and_datapath_in : in std_logic_vector(0 downto 0); + gtwiz_reset_tx_datapath_in : in std_logic_vector(0 downto 0); + gtwiz_reset_rx_pll_and_datapath_in : in std_logic_vector(0 downto 0); + gtwiz_reset_rx_datapath_in : in std_logic_vector(0 downto 0); + gtwiz_reset_rx_cdr_stable_out : out std_logic_vector(0 downto 0); + gtwiz_reset_tx_done_out : out std_logic_vector(0 downto 0); + gtwiz_reset_rx_done_out : out std_logic_vector(0 downto 0); + gtwiz_userdata_tx_in : in std_logic_vector(15 downto 0); + gtwiz_userdata_rx_out : out std_logic_vector(15 downto 0); + drpaddr_in : in std_logic_vector(9 downto 0); + drpclk_in : in std_logic_vector(0 downto 0); + drpdi_in : in std_logic_vector(15 downto 0); + drpen_in : in std_logic_vector(0 downto 0); + drpwe_in : in std_logic_vector(0 downto 0); + gtrefclk0_in : in std_logic_vector(0 downto 0); + gtyrxn_in : in std_logic_vector(0 downto 0); + gtyrxp_in : in std_logic_vector(0 downto 0); + loopback_in : in std_logic_vector(2 downto 0); + rx8b10ben_in : in std_logic_vector(0 downto 0); + rxbufreset_in : in std_logic_vector(0 downto 0); + rxcommadeten_in : in std_logic_vector(0 downto 0); + rxmcommaalignen_in : in std_logic_vector(0 downto 0); + rxpcommaalignen_in : in std_logic_vector(0 downto 0); + rxpolarity_in : in std_logic_vector(0 downto 0); + rxusrclk_in : in std_logic_vector(0 downto 0); + rxusrclk2_in : in std_logic_vector(0 downto 0); + tx8b10ben_in : in std_logic_vector(0 downto 0); + txctrl0_in : in std_logic_vector(15 downto 0); + txctrl1_in : in std_logic_vector(15 downto 0); + txctrl2_in : in std_logic_vector(7 downto 0); + txpolarity_in : in std_logic_vector(0 downto 0); + txusrclk_in : in std_logic_vector(0 downto 0); + txusrclk2_in : in std_logic_vector(0 downto 0); + drpdo_out : out std_logic_vector(15 downto 0); + drprdy_out : out std_logic_vector(0 downto 0); + gtpowergood_out : out std_logic_vector(0 downto 0); + gtytxn_out : out std_logic_vector(0 downto 0); + gtytxp_out : out std_logic_vector(0 downto 0); + rxbufstatus_out : out std_logic_vector(2 downto 0); + rxbyteisaligned_out : out std_logic_vector(0 downto 0); + rxbyterealign_out : out std_logic_vector(0 downto 0); + rxclkcorcnt_out : out std_logic_vector(1 downto 0); + rxcommadet_out : out std_logic_vector(0 downto 0); + rxctrl0_out : out std_logic_vector(15 downto 0); + rxctrl1_out : out std_logic_vector(15 downto 0); + rxctrl2_out : out std_logic_vector(7 downto 0); + rxctrl3_out : out std_logic_vector(7 downto 0); + rxoutclk_out : out std_logic_vector(0 downto 0); + rxpmaresetdone_out : out std_logic_vector(0 downto 0); + txoutclk_out : out std_logic_vector(0 downto 0); + txpmaresetdone_out : out std_logic_vector(0 downto 0) + ); + end component; + + signal drpAddr : slv(9 downto 0); + signal drpDi : slv(15 downto 0); + signal drpDo : slv(15 downto 0); + signal drpEn : sl; + signal drpWe : sl; + signal drpRdy : sl; + + signal dummy0_6 : slv(5 downto 0); + signal dummy1_14 : slv(13 downto 0); + signal dummy2_14 : slv(13 downto 0); + signal dummy3_6 : slv(5 downto 0); + signal dummy4_1 : sl; + signal dummy5_1 : sl; + + signal txctrl2 : slv(7 downto 0); + +begin + + -- Note: Has to be generated from aurora core in order to work properly + U_PgpGtyCore : PgpGtyCore + port map ( + gtwiz_userclk_tx_reset_in(0) => txReset, + gtwiz_userclk_tx_active_in(0) => txUsrClkActive, + gtwiz_userclk_rx_active_in(0) => rxUsrClkActive, + gtwiz_reset_clk_freerun_in(0) => stableClk, + gtwiz_reset_all_in(0) => stableRst, + gtwiz_reset_tx_pll_and_datapath_in(0) => '0', + gtwiz_reset_tx_datapath_in(0) => txReset, + gtwiz_reset_rx_pll_and_datapath_in(0) => '0', + gtwiz_reset_rx_datapath_in(0) => rxReset, + gtwiz_reset_rx_cdr_stable_out => open, + gtwiz_reset_tx_done_out(0) => txResetDone, + gtwiz_reset_rx_done_out(0) => rxResetDone, + gtwiz_userdata_tx_in => txData, + gtwiz_userdata_rx_out => rxData, + drpclk_in(0) => stableClk, + drpaddr_in => drpAddr, + drpdi_in => drpDi, + drpen_in(0) => drpEn, + drpwe_in(0) => drpWe, + drpdo_out => drpDo, + drprdy_out(0) => drpRdy, + gtyrxn_in(0) => gtRxN, + gtyrxp_in(0) => gtRxP, + gtrefclk0_in(0) => gtRefClk, + loopback_in => loopback, + rxbufreset_in(0) => '0', + rx8b10ben_in(0) => '1', + rxcommadeten_in(0) => '1', + rxmcommaalignen_in(0) => '1', + rxpcommaalignen_in(0) => '1', + rxpolarity_in(0) => rxPolarity, + rxusrclk_in(0) => rxUsrClk, + rxusrclk2_in(0) => rxUsrClk, + tx8b10ben_in(0) => '1', + txctrl0_in => X"0000", + txctrl1_in => X"0000", + txctrl2_in => txctrl2, + txpolarity_in(0) => txPolarity, + txusrclk_in(0) => txUsrClk, + txusrclk2_in(0) => txUsrClk, + gtytxn_out(0) => gtTxN, + gtytxp_out(0) => gtTxP, + rxbyteisaligned_out => open, + rxbyterealign_out => open, + rxcommadet_out => open, + rxctrl0_out(1 downto 0) => rxDataK, + rxctrl0_out(15 downto 2) => dummy1_14, + rxctrl1_out(1 downto 0) => rxDispErr, + rxctrl1_out(15 downto 2) => dummy2_14, + rxctrl2_out => open, + rxctrl3_out(1 downto 0) => rxDecErr, + rxctrl3_out(7 downto 2) => dummy0_6, + rxoutclk_out(0) => rxOutClk, + rxpmaresetdone_out => open, + txoutclk_out(0) => txOutClk, + txpmaresetdone_out => open); + + txctrl2 <= "000000" & txDataK; + + U_AxiLiteToDrp_1 : entity surf.AxiLiteToDrp + generic map ( + TPD_G => TPD_G, + COMMON_CLK_G => false, + EN_ARBITRATION_G => false, + ADDR_WIDTH_G => 10, + DATA_WIDTH_G => 16) + port map ( + axilClk => axilClk, -- [in] + axilRst => axilRst, -- [in] + axilReadMaster => axilReadMaster, -- [in] + axilReadSlave => axilReadSlave, -- [out] + axilWriteMaster => axilWriteMaster, -- [in] + axilWriteSlave => axilWriteSlave, -- [out] + drpClk => stableClk, -- [in] + drpRst => stableRst, -- [in] + drpReq => open, -- [out] + drpRdy => drpRdy, -- [in] + drpEn => drpEn, -- [out] + drpWe => drpWe, -- [out] + drpUsrRst => open, -- [out] + drpAddr => drpAddr, -- [out] + drpDi => drpDi, -- [out] + drpDo => drpDo); -- [in] + +end architecture mapping; diff --git a/protocols/pgp/pgp2b/gtyUltraScale+/ruckus.tcl b/protocols/pgp/pgp2b/gtyUltraScale+/ruckus.tcl new file mode 100644 index 0000000000..5ab2965a37 --- /dev/null +++ b/protocols/pgp/pgp2b/gtyUltraScale+/ruckus.tcl @@ -0,0 +1,14 @@ +# Load RUCKUS library +source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl + +# Load local source Code and constraints +if { $::env(VIVADO_VERSION) >= 2020.1 } { + + loadSource -lib surf -dir "$::DIR_PATH/rtl" + + loadSource -lib surf -path "$::DIR_PATH/ip/PgpGtyCore.dcp" + # loadIpCore -path "$::DIR_PATH/ip/PgpGtyCore.xci" + +} else { + puts "\n\nWARNING: $::DIR_PATH requires Vivado 2020.1 (or later)\n\n" +} \ No newline at end of file diff --git a/protocols/pgp/pgp2b/ruckus.tcl b/protocols/pgp/pgp2b/ruckus.tcl index 4b9a3f61f7..1eff1add80 100644 --- a/protocols/pgp/pgp2b/ruckus.tcl +++ b/protocols/pgp/pgp2b/ruckus.tcl @@ -36,10 +36,10 @@ if { ${family} eq {kintexuplus} || ${family} eq {zynquplusRFSOC} || ${family} eq {qzynquplusRFSOC} } { loadRuckusTcl "$::DIR_PATH/gthUltraScale+" - # loadRuckusTcl "$::DIR_PATH/gtyUltraScale+" + loadRuckusTcl "$::DIR_PATH/gtyUltraScale+" } -# if { ${family} eq {virtexuplus} || - # ${family} eq {virtexuplusHBM} } { - # loadRuckusTcl "$::DIR_PATH/gtyUltraScale+" -# } +if { ${family} eq {virtexuplus} || + ${family} eq {virtexuplusHBM} } { + loadRuckusTcl "$::DIR_PATH/gtyUltraScale+" +} diff --git a/protocols/ssp/rtl/SspLowSpeedDecoder10b12bWrapper.vhd b/protocols/ssp/rtl/SspLowSpeedDecoder10b12bWrapper.vhd index 64a6fe65b2..1ed98e1fca 100644 --- a/protocols/ssp/rtl/SspLowSpeedDecoder10b12bWrapper.vhd +++ b/protocols/ssp/rtl/SspLowSpeedDecoder10b12bWrapper.vhd @@ -60,6 +60,7 @@ architecture mapping of SspLowSpeedDecoder10b12bWrapper is signal minEyeWidth : slv(7 downto 0); signal lockingCntCfg : slv(23 downto 0); signal bypFirstBerDet : sl; + signal bitOrder : slv(1 downto 0); signal polarity : slv(NUM_LANE_G-1 downto 0); signal errorDet : slv(NUM_LANE_G-1 downto 0); signal bitSlip : slv(NUM_LANE_G-1 downto 0); @@ -92,6 +93,7 @@ begin lockingCntCfg => lockingCntCfg, bypFirstBerDet => bypFirstBerDet, polarity => polarity(i), + bitOrder => bitOrder, errorDet => errorDet(i), bitSlip => bitSlip(i), locked => locked(i), @@ -125,6 +127,7 @@ begin lockingCntCfg => lockingCntCfg, bypFirstBerDet => bypFirstBerDet, polarity => polarity, + bitOrder => bitOrder, -- AXI-Lite Interface (axilClk domain) axilClk => axilClk, axilRst => axilRst, diff --git a/protocols/ssp/rtl/SspLowSpeedDecoder12b14bWrapper.vhd b/protocols/ssp/rtl/SspLowSpeedDecoder12b14bWrapper.vhd index a444ed38fb..451ac5faed 100644 --- a/protocols/ssp/rtl/SspLowSpeedDecoder12b14bWrapper.vhd +++ b/protocols/ssp/rtl/SspLowSpeedDecoder12b14bWrapper.vhd @@ -60,6 +60,7 @@ architecture mapping of SspLowSpeedDecoder12b14bWrapper is signal minEyeWidth : slv(7 downto 0); signal lockingCntCfg : slv(23 downto 0); signal bypFirstBerDet : sl; + signal bitOrder : slv(1 downto 0); signal polarity : slv(NUM_LANE_G-1 downto 0); signal errorDet : slv(NUM_LANE_G-1 downto 0); signal bitSlip : slv(NUM_LANE_G-1 downto 0); @@ -92,6 +93,7 @@ begin lockingCntCfg => lockingCntCfg, bypFirstBerDet => bypFirstBerDet, polarity => polarity(i), + bitOrder => bitOrder, errorDet => errorDet(i), bitSlip => bitSlip(i), locked => locked(i), @@ -125,6 +127,7 @@ begin lockingCntCfg => lockingCntCfg, bypFirstBerDet => bypFirstBerDet, polarity => polarity, + bitOrder => bitOrder, -- AXI-Lite Interface (axilClk domain) axilClk => axilClk, axilRst => axilRst, diff --git a/protocols/ssp/rtl/SspLowSpeedDecoder8b10bWrapper.vhd b/protocols/ssp/rtl/SspLowSpeedDecoder8b10bWrapper.vhd index c6d4279239..58f61fcb16 100644 --- a/protocols/ssp/rtl/SspLowSpeedDecoder8b10bWrapper.vhd +++ b/protocols/ssp/rtl/SspLowSpeedDecoder8b10bWrapper.vhd @@ -60,6 +60,7 @@ architecture mapping of SspLowSpeedDecoder8b10bWrapper is signal minEyeWidth : slv(7 downto 0); signal lockingCntCfg : slv(23 downto 0); signal bypFirstBerDet : sl; + signal bitOrder : slv(1 downto 0); signal polarity : slv(NUM_LANE_G-1 downto 0); signal errorDet : slv(NUM_LANE_G-1 downto 0); signal bitSlip : slv(NUM_LANE_G-1 downto 0); @@ -92,6 +93,7 @@ begin lockingCntCfg => lockingCntCfg, bypFirstBerDet => bypFirstBerDet, polarity => polarity(i), + bitOrder => bitOrder, errorDet => errorDet(i), bitSlip => bitSlip(i), locked => locked(i), @@ -125,6 +127,7 @@ begin lockingCntCfg => lockingCntCfg, bypFirstBerDet => bypFirstBerDet, polarity => polarity, + bitOrder => bitOrder, -- AXI-Lite Interface (axilClk domain) axilClk => axilClk, axilRst => axilRst, diff --git a/protocols/ssp/rtl/SspLowSpeedDecoderLane.vhd b/protocols/ssp/rtl/SspLowSpeedDecoderLane.vhd index 0d26acb0c0..9873fc6aa4 100644 --- a/protocols/ssp/rtl/SspLowSpeedDecoderLane.vhd +++ b/protocols/ssp/rtl/SspLowSpeedDecoderLane.vhd @@ -40,6 +40,7 @@ entity SspLowSpeedDecoderLane is lockingCntCfg : in slv(23 downto 0); bypFirstBerDet : in sl; polarity : in sl; + bitOrder : in slv(1 downto 0); errorDet : out sl; bitSlip : out sl; locked : out sl; @@ -102,16 +103,18 @@ begin SLAVE_WIDTH_G => 8, MASTER_WIDTH_G => ENCODE_WIDTH_C) port map ( - clk => clk, - rst => reset, - slip => slip, + clk => clk, + rst => reset, + slip => slip, -- Slave Interface - slaveValid => '1', - slaveData => deserDataMask, + slaveValid => '1', + slaveData => deserDataMask, + slaveBitOrder => bitOrder(0), -- Master Interface - masterValid => encodeValid, - masterData => encodeData, - masterReady => '1'); + masterValid => encodeValid, + masterData => encodeData, + masterReady => '1', + masterBitOrder => bitOrder(1)); U_GearboxAligner : entity surf.SelectIoRxGearboxAligner generic map ( diff --git a/protocols/ssp/rtl/SspLowSpeedDecoderReg.vhd b/protocols/ssp/rtl/SspLowSpeedDecoderReg.vhd index 78ece5f304..37bce5c61f 100644 --- a/protocols/ssp/rtl/SspLowSpeedDecoderReg.vhd +++ b/protocols/ssp/rtl/SspLowSpeedDecoderReg.vhd @@ -41,6 +41,7 @@ entity SspLowSpeedDecoderReg is lockingCntCfg : out slv(23 downto 0); bypFirstBerDet : out sl; polarity : out slv(NUM_LANE_G-1 downto 0); + bitOrder : out slv(1 downto 0); -- AXI-Lite Interface (axilClk domain) axilClk : in sl; axilRst : in sl; @@ -62,6 +63,7 @@ architecture mapping of SspLowSpeedDecoderReg is lockingCntCfg : slv(23 downto 0); bypFirstBerDet : sl; polarity : slv(NUM_LANE_G-1 downto 0); + bitOrder : slv(1 downto 0); cntRst : sl; rollOverEn : slv(STATUS_SIZE_C-1 downto 0); readSlave : AxiLiteReadSlaveType; @@ -75,6 +77,7 @@ architecture mapping of SspLowSpeedDecoderReg is lockingCntCfg => ite(SIMULATION_G, x"00_0004", x"00_FFFF"), bypFirstBerDet => '1', polarity => (others => '0'), + bitOrder => (others => '0'), cntRst => '1', rollOverEn => (others => '0'), readSlave => AXI_LITE_READ_SLAVE_INIT_C, @@ -148,6 +151,7 @@ begin axiSlaveRegister (axilEp, x"810", 0, v.bypFirstBerDet); axiSlaveRegister (axilEp, x"814", 0, v.polarity); + axiSlaveRegister (axilEp, x"818", 0, v.bitOrder); axiSlaveRegister (axilEp, x"FF8", 0, v.rollOverEn); axiSlaveRegister (axilEp, x"FFC", 0, v.cntRst); @@ -164,6 +168,7 @@ begin lockingCntCfg <= r.lockingCntCfg; bypFirstBerDet <= r.bypFirstBerDet; polarity <= r.polarity; + bitOrder <= r.bitOrder; -- Synchronous Reset if (deserRst = '1') then diff --git a/python/surf/devices/analog_devices/_Ad9249.py b/python/surf/devices/analog_devices/_Ad9249.py index 6691443dca..d0c1b5dfbd 100644 --- a/python/surf/devices/analog_devices/_Ad9249.py +++ b/python/surf/devices/analog_devices/_Ad9249.py @@ -96,23 +96,39 @@ def __init__(self, )) self.add(pr.RemoteVariable( - name = 'DevIndexMask[7:0]', - offset = [0x10, 0x14], + name = 'DevIndexMask_DataCh[0]', + offset = 0x10, bitSize = 4, bitOffset = 0, mode = 'RW', disp = '{:#b}', - base = pr.UInt, )) self.add(pr.RemoteVariable( - name = 'DevIndexMask[DCO:FCO]', + name = 'DevIndexMask_DataCh[1]', offset = 0x14, - bitSize = 2, - bitOffset = 0x4, + bitSize = 4, + bitOffset = 0, + mode = 'RW', + disp = '{:#b}', + )) + + self.add(pr.RemoteVariable( + name = 'DevIndexMask_FCO', + offset = 0x14, + bitSize = 1, + bitOffset = 4, + mode = 'RW', + disp = '{:#b}', + )) + + self.add(pr.RemoteVariable( + name = 'DevIndexMask_DCO', + offset = 0x14, + bitSize = 1, + bitOffset = 5, mode = 'RW', disp = '{:#b}', - base = pr.UInt, )) self.add(pr.RemoteVariable( @@ -256,8 +272,8 @@ def __init__(self, base = pr.Bool, mode = 'RW', )) - self.add(Ad9249ConfigGroup(name=f'Ad9249Chip[{i}].BankConfig[0]', offset=i*0x1000)) - self.add(Ad9249ConfigGroup(name=f'Ad9249Chip[{i}].BankConfig[1]', offset=i*0x1000+0x0800)) + self.add(Ad9249ConfigGroup(name=f'Ad9249ChipBankConfig0[{i}]', offset=i*0x1000)) + self.add(Ad9249ConfigGroup(name=f'Ad9249ChipBankConfig1[{i}]', offset=i*0x1000+0x0800)) class Ad9249ReadoutGroup(pr.Device): def __init__(self, @@ -380,23 +396,140 @@ def setDelay(var, value, write): def getDelay(var, read): return var.dependencies[0].get(read) - def readBlocks(self, recurse=True, variable=None, checkEach=False): + def readBlocks(self, *, recurse=True, variable=None, checkEach=False, index=-1, **kwargs): + """ + Perform background reads + """ + checkEach = checkEach or self.forceCheckEach + if variable is not None: freeze = isinstance(variable, list) and any(v.name.startswith('AdcChannel') for v in variable) if freeze: self.FreezeDebug(1) - for b in self._getBlocks(variable): - b.startTransaction(rim.Read, checkEach) + pr.startTransaction(variable._block, type=rim.Read, checkEach=checkEach, variable=variable, index=index, **kwargs) if freeze: self.FreezeDebug(0) + else: self.FreezeDebug(1) for block in self._blocks: - if block.bulkEn: - block.startTransaction(rim.Read, checkEach) + if block.bulkOpEn: + pr.startTransaction(block, type=rim.Read, checkEach=checkEach, **kwargs) self.FreezeDebug(0) - if recurse: - for key, value in self.devices.items(): - value.readBlocks(recurse=True, checkEach=checkEach) + for key,value in self.devices.items(): + value.readBlocks(recurse=True, checkEach=checkEach, **kwargs) + +class AdcTester(pr.Device): + def __init__(self, **kwargs): + """Create AdcTester""" + super().__init__(description='ADC Pattern Tester Regsisters', **kwargs) + + # Creation. memBase is either the register bus server (srp, rce mapped memory, etc) or the device which + # contains this object. In most cases the parent and memBase are the same but they can be + # different in more complex bus structures. They will also be different for the top most node. + # The setMemBase call can be used to update the memBase for this Device. All sub-devices and local + # blocks will be updated. + + ############################################# + # Create block / variable combinations + ############################################# + + + #Setup registers & variables + self.add(pr.RemoteVariable( + name = 'TestChannel', + description= 'Test Channel Select', + offset = 0x00000000, + bitSize = 32, + bitOffset = 0, + base = pr.UInt, + mode = 'RW', + )) + + self.add(pr.RemoteVariable( + name = 'TestDataMask', + description= 'Test Data Mask', + offset = 0x00000004, + bitSize = 32, + bitOffset = 0, + base = pr.UInt, + mode = 'RW', + )) + + self.add(pr.RemoteVariable( + name = 'TestPattern', + description= 'Test Pattern', + offset = 0x00000008, + bitSize = 32, + bitOffset = 0, + base = pr.UInt, + mode = 'RW', + )) + + self.add(pr.RemoteVariable( + name = 'TestSamples', + description= 'Test Samples Number', + offset = 0x0000000C, + bitSize = 32, + bitOffset = 0, + base = pr.UInt, + mode = 'RW', + )) + + self.add(pr.RemoteVariable( + name = 'TestTimeout', + description= 'Test Timeout', + offset = 0x00000010, + bitSize = 32, + bitOffset = 0, + base = pr.UInt, + mode = 'RW', + )) + + self.add(pr.RemoteVariable( + name = 'TestRequest', + description= 'Test Request', + offset = 0x00000014, + bitSize = 1, + bitOffset = 0, + base = pr.Bool, + mode = 'RW', + )) + + self.add(pr.RemoteVariable( + name = 'TestPassed', + description= 'Test Passed Flag', + offset = 0x00000018, + bitSize = 1, + bitOffset = 0, + base = pr.Bool, + mode = 'RO', + )) + + self.add(pr.RemoteVariable( + name = 'TestFailed', + description= 'Test Failed Flag', + offset = 0x0000001C, + bitSize = 1, + bitOffset = 0, + base = pr.Bool, + mode = 'RO', + )) + + ##################################### + # Create commands + ##################################### + + # A command has an associated function. The function can be a series of + # python commands in a string. Function calls are executed in the command scope + # the passed arg is available as 'arg'. Use 'dev' to get to device scope. + # A command can also be a call to a local function with local scope. + # The command object and the arg are passed + + @staticmethod + def frequencyConverter(self): + def func(dev, var): + return '{:.3f} kHz'.format(1/(self.clkPeriod * self._count(var.dependencies)) * 1e-3) + return func diff --git a/python/surf/dsp/__init__.py b/python/surf/dsp/__init__.py new file mode 100644 index 0000000000..b0085f1a17 --- /dev/null +++ b/python/surf/dsp/__init__.py @@ -0,0 +1,9 @@ +############################################################################## +## This file is part of 'SLAC Firmware Standard Library'. +## It is subject to the license terms in the LICENSE.txt file found in the +## top-level directory of this distribution and at: +## https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +## No part of 'SLAC Firmware Standard Library', including this file, +## may be copied, modified, propagated, or distributed except according to +## the terms contained in the LICENSE.txt file. +############################################################################## diff --git a/python/surf/dsp/fixed/_FirFilterMultiChannel.py b/python/surf/dsp/fixed/_FirFilterMultiChannel.py new file mode 100644 index 0000000000..7177bfebf1 --- /dev/null +++ b/python/surf/dsp/fixed/_FirFilterMultiChannel.py @@ -0,0 +1,57 @@ +#----------------------------------------------------------------------------- +# This file is part of the 'SLAC Firmware Standard Library'. It is subject to +# the license terms in the LICENSE.txt file found in the top-level directory +# of this distribution and at: +# https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +# No part of the 'SLAC Firmware Standard Library', including this file, may be +# copied, modified, propagated, or distributed except according to the terms +# contained in the LICENSE.txt file. +#----------------------------------------------------------------------------- + +import pyrogue as pr + +class FirFilterMultiChannel(pr.Device): + def __init__( + self, + numberTaps = None, # TAP_SIZE_G + numberChannels = None, # CH_SIZE_G + dataWordBitSize = None, # WIDTH_G + **kwargs): + super().__init__(**kwargs) + + if numberTaps is None: + raise ValueError( f'{self.path}: numberTaps is undefined' ) + + if numberChannels is None: + raise ValueError( f'{self.path}: numberChannels is undefined' ) + + if dataWordBitSize is None: + raise ValueError( f'{self.path}: dataWordBitSize is undefined' ) + + def addBoolPair(ch,tap): + self.add(pr.RemoteVariable( + name = f'RawCh{ch}Tap[{tap}]', + description = f'Tap[{tap}] Fixed Point Coefficient', + offset = 0x0, + bitSize = dataWordBitSize, + bitOffset = (ch*numberTaps+tap)*dataWordBitSize, + base = pr.Int, + mode = 'RW', + hidden = True, + )) + + var = self.variables[ f'RawCh{ch}Tap[{tap}]' ] + + self.add(pr.LinkVariable( + name = f'Ch{ch}Tap[{tap}]', + description = f'Tap[{tap}] Floating Point Coefficient', + mode = 'RW', + linkedGet = lambda: var.value()/2**dataWordBitSize, + linkedSet = lambda value, write: var.set(int(value*2**dataWordBitSize)), + dependencies = [var], + disp = '{:1.3f}', + )) + + for ch in range(numberChannels): + for tap in range(numberTaps): + addBoolPair(ch=ch,tap=tap) diff --git a/python/surf/dsp/fixed/_FirFilterSingleChannel.py b/python/surf/dsp/fixed/_FirFilterSingleChannel.py new file mode 100644 index 0000000000..30cbd70ecb --- /dev/null +++ b/python/surf/dsp/fixed/_FirFilterSingleChannel.py @@ -0,0 +1,51 @@ +#----------------------------------------------------------------------------- +# This file is part of the 'SLAC Firmware Standard Library'. It is subject to +# the license terms in the LICENSE.txt file found in the top-level directory +# of this distribution and at: +# https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +# No part of the 'SLAC Firmware Standard Library', including this file, may be +# copied, modified, propagated, or distributed except according to the terms +# contained in the LICENSE.txt file. +#----------------------------------------------------------------------------- + +import pyrogue as pr + +class FirFilterSingleChannel(pr.Device): + def __init__( + self, + numberTaps = None, # TAP_SIZE_G + dataWordBitSize = None, # WIDTH_G + **kwargs): + super().__init__(**kwargs) + + if numberTaps is None: + raise ValueError( f'{self.path}: numberTaps is undefined' ) + + if dataWordBitSize is None: + raise ValueError( f'{self.path}: dataWordBitSize is undefined' ) + + def addBoolPair(tap): + self.add(pr.RemoteVariable( + name = f'RawTap[{tap}]', + description = f'Tap[{tap}] Fixed Point Coefficient', + offset = 4*tap, + bitSize = dataWordBitSize, + base = pr.Int, + mode = 'RW', + hidden = True, + )) + + var = self.variables[ f'RawTap[{tap}]' ] + + self.add(pr.LinkVariable( + name = f'Tap[{tap}]', + description = f'Tap[{tap}] Floating Point Coefficient', + mode = 'RW', + linkedGet = lambda: var.value()/2**dataWordBitSize, + linkedSet = lambda value, write: var.set(int(value*2**dataWordBitSize)), + dependencies = [var], + disp = '{:1.3f}', + )) + + for tap in range(numberTaps): + addBoolPair(tap=tap) diff --git a/python/surf/dsp/fixed/__init__.py b/python/surf/dsp/fixed/__init__.py new file mode 100644 index 0000000000..71680494dc --- /dev/null +++ b/python/surf/dsp/fixed/__init__.py @@ -0,0 +1,11 @@ +############################################################################## +## This file is part of 'SLAC Firmware Standard Library'. +## It is subject to the license terms in the LICENSE.txt file found in the +## top-level directory of this distribution and at: +## https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +## No part of 'SLAC Firmware Standard Library', including this file, +## may be copied, modified, propagated, or distributed except according to +## the terms contained in the LICENSE.txt file. +############################################################################## +from surf.dsp.fixed._FirFilterSingleChannel import * +from surf.dsp.fixed._FirFilterMultiChannel import * diff --git a/python/surf/protocols/ssp/_SspLowSpeedDecoderReg.py b/python/surf/protocols/ssp/_SspLowSpeedDecoderReg.py index 3fe4e6b6a1..cd8fa8a0f7 100644 --- a/python/surf/protocols/ssp/_SspLowSpeedDecoderReg.py +++ b/python/surf/protocols/ssp/_SspLowSpeedDecoderReg.py @@ -128,6 +128,24 @@ def __init__(self, numberLanes=1, **kwargs): mode = 'RW', )) + self.add(pr.RemoteVariable( + name = 'GearboxSlaveBitOrder', + description = '1: reserve, 0: normal', + offset = 0x818, + bitSize = 1, + bitOffset = 0, + mode = 'RW', + )) + + self.add(pr.RemoteVariable( + name = 'GearboxMasterBitOrder', + description = '1: reserve, 0: normal', + offset = 0x818, + bitSize = 1, + bitOffset = 1, + mode = 'RW', + )) + self.add(pr.RemoteVariable( name = 'RollOverEn', description = 'Rollover enable for status counters', diff --git a/xilinx/7Series/general/rtl/OutputBufferReg.vhd b/xilinx/7Series/general/rtl/OutputBufferReg.vhd index 2e8a2177df..53850b67b7 100644 --- a/xilinx/7Series/general/rtl/OutputBufferReg.vhd +++ b/xilinx/7Series/general/rtl/OutputBufferReg.vhd @@ -17,7 +17,6 @@ use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; - library surf; use surf.StdRtlPkg.all; @@ -28,7 +27,7 @@ entity OutputBufferReg is generic ( TPD_G : time := 1 ns; DIFF_PAIR_G : boolean := false; - DDR_CLK_EDGE_G : string := "OPPOSITE_EDGE"; + DDR_CLK_EDGE_G : string := "SAME_EDGE"; INIT_G : bit := '0'; SRTYPE_G : string := "SYNC"); port (