diff --git a/libraries/io/tr_xaui/src/vhdl/mms_tr_xaui.vhd b/libraries/io/tr_xaui/src/vhdl/mms_tr_xaui.vhd new file mode 100644 index 0000000000000000000000000000000000000000..297719de10de77b8849197fa9dc79eb7c1ea690e --- /dev/null +++ b/libraries/io/tr_xaui/src/vhdl/mms_tr_xaui.vhd @@ -0,0 +1,296 @@ +-------------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib, mdio_lib, diagnostics_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_interface_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE mdio_lib.mdio_pkg.ALL; +USE mdio_lib.mdio_vitesse_vsc8486_pkg.ALL; + +ENTITY mms_tr_xaui IS + GENERIC( + g_sim : BOOLEAN := FALSE; + g_nof_xaui : NATURAL := 1; -- Up to 3 (hard XAUI only) supported + g_mdio : BOOLEAN := FALSE +-- g_mdio_mm_ctrl : BOOLEAN := FALSE -- FALSE uses mdio_ctlr to auto execute the initialization +-- -- sequence for the Vitesse chips. TRUE enables MM control. + ); + PORT ( + -- Transceiver PLL reference clock + tr_clk : IN STD_LOGIC; + + -- Calibration & reconfig clock + cal_rec_clk : IN STD_LOGIC; + + -- MM clock for register of optional MDIO master + mm_clk : IN STD_LOGIC := '0'; + mm_rst : IN STD_LOGIC := '0'; + + -- Streaming RX interfaces + rx_clk : OUT STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + rx_rst : OUT STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + rx_sosi_arr : OUT t_dp_sosi_arr(g_nof_xaui-1 DOWNTO 0); + rx_siso_arr : IN t_dp_siso_arr(g_nof_xaui-1 DOWNTO 0); + + -- Streaming TX interfaces + tx_clk : IN STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + tx_rst : OUT STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + tx_sosi_arr : IN t_dp_sosi_arr(g_nof_xaui-1 DOWNTO 0); + tx_siso_arr : OUT t_dp_siso_arr(g_nof_xaui-1 DOWNTO 0); + + --Serial I/O + xaui_rx : IN t_xaui_arr(g_nof_xaui-1 DOWNTO 0); + xaui_tx : OUT t_xaui_arr(g_nof_xaui-1 DOWNTO 0); + + -- MDIO master = mm slave + mdio_mosi_arr : IN t_mem_mosi_arr(g_nof_xaui-1 DOWNTO 0) := (OTHERS=>c_mem_mosi_rst); + mdio_miso_arr : OUT t_mem_miso_arr(g_nof_xaui-1 DOWNTO 0); + + -- MDIO External clock and serial data. + mdio_rst : OUT STD_LOGIC; + mdio_mdc : OUT STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + mdio_mdat_in : IN STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0) := (OTHERS=>'0'); + mdio_mdat_oen : OUT STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + + diagnostics_mosi : IN t_mem_mosi := c_mem_mosi_rst; + diagnostics_miso : OUT t_mem_miso := c_mem_miso_rst; + + xaui_mosi : IN t_mem_mosi := c_mem_mosi_rst; + xaui_miso : OUT t_mem_miso := c_mem_miso_rst + ); +END mms_tr_xaui; + + +ARCHITECTURE wrap OF mms_tr_xaui IS + + CONSTANT c_nof_select : NATURAL := 2; + CONSTANT c_nof_select_w : NATURAL := ceil_log2(c_nof_select); + CONSTANT c_sel_user : NATURAL := 0; + CONSTANT c_sel_diag : NATURAL := 1; + + TYPE t_select_sosi_2arr IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(c_nof_select-1 DOWNTO 0); + TYPE t_select_siso_2arr IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_arr(c_nof_select-1 DOWNTO 0); + + TYPE t_select_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_nof_select_w-1 DOWNTO 0); + + SIGNAL i_tx_rst : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + SIGNAL i_rx_clk : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + SIGNAL i_rx_rst : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + + SIGNAL diagnostics_rx_sosi_arr : t_dp_sosi_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL diagnostics_rx_siso_arr : t_dp_siso_arr(g_nof_xaui-1 DOWNTO 0); + + SIGNAL diagnostics_tx_sosi_arr : t_dp_sosi_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL diagnostics_tx_siso_arr : t_dp_siso_arr(g_nof_xaui-1 DOWNTO 0); + + SIGNAL diagnostics_tx_en_arr : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + SIGNAL diagnostics_rx_en_arr : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + + SIGNAL mux_in_siso_2arr : t_select_siso_2arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL mux_in_sosi_2arr : t_select_sosi_2arr(g_nof_xaui-1 DOWNTO 0); + + SIGNAL mux_out_sosi_arr : t_dp_sosi_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL mux_out_siso_arr : t_dp_siso_arr(g_nof_xaui-1 DOWNTO 0); + + SIGNAL demux_in_siso_arr : t_dp_siso_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL demux_in_sosi_arr : t_dp_sosi_arr(g_nof_xaui-1 DOWNTO 0); + + SIGNAL demux_out_sosi_2arr : t_select_sosi_2arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL demux_out_siso_2arr : t_select_siso_2arr(g_nof_xaui-1 DOWNTO 0); + + SIGNAL mux_select_arr : t_select_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL nxt_mux_select_arr : t_select_arr(g_nof_xaui-1 DOWNTO 0); + + SIGNAL demux_select_arr : t_select_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL nxt_demux_select_arr : t_select_arr(g_nof_xaui-1 DOWNTO 0); + +BEGIN + + rx_rst <= i_rx_rst; + rx_clk <= i_rx_clk; + tx_rst <= i_tx_rst; + + u_tr_xaui: ENTITY work.tr_xaui + GENERIC MAP ( + g_sim => g_sim, + g_mdio => g_mdio, + g_nof_xaui => g_nof_xaui + ) + PORT MAP ( + tr_clk => tr_clk, + + mm_rst => mm_rst, + mm_clk => mm_clk, + + --Serial data + xaui_tx => xaui_tx, + xaui_rx => xaui_rx, + + mdio_mosi_arr => mdio_mosi_arr, + mdio_miso_arr => mdio_miso_arr, + + mdio_rst => mdio_rst, + mdio_mdc => mdio_mdc, + mdio_mdat_in => mdio_mdat_in, + mdio_mdat_oen => mdio_mdat_oen, + + --Parallel data + rx_rst => i_rx_rst, + rx_clk => i_rx_clk, + rx_sosi_arr => demux_in_sosi_arr, + rx_siso_arr => demux_in_siso_arr, + + tx_rst => i_tx_rst, + tx_clk => tx_clk, + tx_sosi_arr => mux_out_sosi_arr, + tx_siso_arr => mux_out_siso_arr, + + cal_rec_clk => cal_rec_clk, + + xaui_mosi => xaui_mosi, + xaui_miso => xaui_miso + ); + + u_mms_diagnostics: ENTITY diagnostics_lib.mms_diagnostics + GENERIC MAP( + g_data_w => c_xgmii_data_w, + g_nof_streams => g_nof_xaui, + g_separate_clk => TRUE + ) + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + + src_rst => i_tx_rst, + src_clk => tx_clk, + + snk_rst => i_rx_rst, + snk_clk => i_rx_clk, + + mm_mosi => diagnostics_mosi, + mm_miso => diagnostics_miso, + + src_out_arr => diagnostics_tx_sosi_arr, + src_in_arr => diagnostics_tx_siso_arr, + + snk_out_arr => diagnostics_rx_siso_arr, + snk_in_arr => diagnostics_rx_sosi_arr, + + src_en_out => diagnostics_tx_en_arr, + snk_en_out => diagnostics_rx_en_arr + ); + + gen_select : FOR i IN 0 TO g_nof_xaui-1 GENERATE + + -- 0 = user data, + tx_siso_arr(i) <= mux_in_siso_2arr(i)(c_sel_user); + mux_in_sosi_2arr(i)(c_sel_user) <= tx_sosi_arr(i); + + demux_out_siso_2arr(i)(c_sel_user) <= rx_siso_arr(i); + rx_sosi_arr(i) <= demux_out_sosi_2arr(i)(c_sel_user); + + -- 1 = internal diagnostics data + diagnostics_tx_siso_arr(i) <= mux_in_siso_2arr(i)(c_sel_diag); + mux_in_sosi_2arr(i)(c_sel_diag) <= diagnostics_tx_sosi_arr(i); + + demux_out_siso_2arr(i)(c_sel_diag) <= diagnostics_rx_siso_arr(i); + diagnostics_rx_sosi_arr(i) <= demux_out_sosi_2arr(i)(c_sel_diag); + + -- If user enables internal diagnostics source, the dp_mux automatically forwards that data to the corresponding transmitter + nxt_mux_select_arr(i) <= slv(diagnostics_tx_en_arr(i)); + + -- If user enables internal diagnostics sink, the dp_demux is automatically set to forward the corresponding receiver data + nxt_demux_select_arr(i) <= slv(diagnostics_rx_en_arr(i)); + + u_dp_mux : ENTITY dp_lib.dp_mux + GENERIC MAP ( + -- Mux + g_sel_ctrl_invert => TRUE, -- We're using DOWNTO ranges in out streaming arrays, so we must invert the selection input + g_mode => 2, + g_nof_input => c_nof_select, + g_append_channel_lo => FALSE, + -- Input FIFO + g_use_fifo => FALSE, + g_fifo_size => array_init(1024, c_nof_select), + g_fifo_fill => array_init( 0, c_nof_select) + ) + PORT MAP ( + rst => i_tx_rst(i), + clk => tx_clk(i), + + sel_ctrl => TO_UINT(mux_select_arr(i)), + + -- ST sinks + snk_out_arr => mux_in_siso_2arr(i), + snk_in_arr => mux_in_sosi_2arr(i), + -- ST source + src_in => mux_out_siso_arr(i), + src_out => mux_out_sosi_arr(i) + ); + + p_tx_clk : PROCESS(i_tx_rst, tx_clk) + BEGIN + IF i_tx_rst(i)='1' THEN + mux_select_arr(i) <= (OTHERS=>'0'); + ELSIF rising_edge(tx_clk(i)) THEN + mux_select_arr(i) <= nxt_mux_select_arr(i); + END IF; + END PROCESS; + + u_dp_demux : ENTITY dp_lib.dp_demux + GENERIC MAP ( + g_sel_ctrl_invert => TRUE, -- We're using DOWNTO ranges in out streaming arrays, so we must invert the selection input + g_mode => 2, + g_nof_output => c_nof_select, + g_remove_channel_lo => FALSE, + g_combined => FALSE + ) + PORT MAP ( + rst => i_rx_rst(i), + clk => i_rx_clk(i), + + sel_ctrl => TO_UINT(demux_select_arr(i)), + + -- ST sinks + snk_out => demux_in_siso_arr(i), + snk_in => demux_in_sosi_arr(i), + -- ST source + src_in_arr => demux_out_siso_2arr(i), + src_out_arr => demux_out_sosi_2arr(i) + ); + + p_rx_clk : PROCESS(i_rx_rst, i_rx_clk) + BEGIN + IF i_rx_rst(i)='1' THEN + demux_select_arr(i) <= (OTHERS=>'0'); + ELSIF rising_edge(i_rx_clk(i)) THEN + demux_select_arr(i) <= nxt_demux_select_arr(i); + END IF; + END PROCESS; + + END GENERATE; + +END wrap; + diff --git a/libraries/io/tr_xaui/src/vhdl/tr_xaui.vhd b/libraries/io/tr_xaui/src/vhdl/tr_xaui.vhd new file mode 100644 index 0000000000000000000000000000000000000000..fb72fdb53f276ae4dbe172a168d8394e15572f6c --- /dev/null +++ b/libraries/io/tr_xaui/src/vhdl/tr_xaui.vhd @@ -0,0 +1,455 @@ +-------------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib, mdio_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_interface_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE mdio_lib.mdio_pkg.ALL; +USE mdio_lib.mdio_vitesse_vsc8486_pkg.ALL; + +ENTITY tr_xaui IS + GENERIC ( + g_sim : BOOLEAN := FALSE; + g_sim_level : NATURAL := 0; -- 0 = use IP; 1 = use fast serdes model + g_use_xgmii : BOOLEAN := FALSE; -- Don't use streaming I/O but XGMII (e.g. conenct to 10GbE MAC) + g_nof_xaui : NATURAL := 1; -- Up to 3 (hard XAUI only) supported + g_mdio : BOOLEAN := FALSE; + g_mdio_epcs_dis : BOOLEAN := FALSE -- TRUE disables EPCS on init; e.g. to target a 10GbE card in PC that does not support it + --g_mdio_mm_ctrl : BOOLEAN := FALSE -- FALSE uses mdio_ctlr to auto execute the initialization sequence for the Vitesse chips. TRUE enables MM control. + ); + PORT ( + -- Transceiver PLL reference clock + tr_clk : IN STD_LOGIC; + + -- Calibration & reconfig clock + cal_rec_clk : IN STD_LOGIC; + + -- MM clock for register of optional MDIO master + mm_clk : IN STD_LOGIC := '0'; + mm_rst : IN STD_LOGIC := '0'; + + -- Streaming RX interfaces + rx_clk : OUT STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + rx_rst : OUT STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + rx_sosi_arr : OUT t_dp_sosi_arr(g_nof_xaui-1 DOWNTO 0); + rx_siso_arr : IN t_dp_siso_arr(g_nof_xaui-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rst); + + -- Streaming TX interfaces + tx_clk : IN STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + tx_rst : OUT STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + tx_sosi_arr : IN t_dp_sosi_arr(g_nof_xaui-1 DOWNTO 0) := (OTHERS=>c_dp_sosi_rst); + tx_siso_arr : OUT t_dp_siso_arr(g_nof_xaui-1 DOWNTO 0); + + -- Direct XGMII interface + xgmii_tx_dc_arr : IN t_xgmii_dc_arr(g_nof_xaui-1 DOWNTO 0) := (OTHERS=>(OTHERS=>'0')); + xgmii_rx_dc_arr : OUT t_xgmii_dc_arr(g_nof_xaui-1 DOWNTO 0); + + --Serial I/O + xaui_rx : IN t_xaui_arr(g_nof_xaui-1 DOWNTO 0); + xaui_tx : OUT t_xaui_arr(g_nof_xaui-1 DOWNTO 0); + + -- XAUI PHY IP MM control/status + xaui_mosi : IN t_mem_mosi := c_mem_mosi_rst; + xaui_miso : OUT t_mem_miso; + + -- MDIO master = mm slave + mdio_mosi_arr : IN t_mem_mosi_arr(g_nof_xaui-1 DOWNTO 0) := (OTHERS=>c_mem_mosi_rst); + mdio_miso_arr : OUT t_mem_miso_arr(g_nof_xaui-1 DOWNTO 0); + + -- MDIO External clock and serial data. + mdio_rst : OUT STD_LOGIC; + mdio_mdc : OUT STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + mdio_mdat_in : IN STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0) := (OTHERS=>'0'); + mdio_mdat_oen : OUT STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0) + ); +END tr_xaui; + + +ARCHITECTURE str OF tr_xaui IS + + SIGNAL crc_rx_ready : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); --crc = synchronous to Cal_Rec_Clk + SIGNAL crc_tx_ready : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + + SIGNAL rxc_rx_ready : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + SIGNAL txc_tx_ready : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + + SIGNAL i_rx_rst : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + SIGNAL i_tx_rst : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + + SIGNAL trc_rst : STD_LOGIC; + SIGNAL i_rx_clk : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + + --XGMII data and control combined: + SIGNAL xgmii_tx_dc : t_xgmii_dc_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL xgmii_rx_dc : t_xgmii_dc_arr(g_nof_xaui-1 DOWNTO 0); + + --XGMII control bits (one for each XGMII lane): + SIGNAL xgmii_tx_c : t_xgmii_c_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL xgmii_rx_c : t_xgmii_c_arr(g_nof_xaui-1 DOWNTO 0); + + --XGMII data + SIGNAL xgmii_tx_d : t_xgmii_d_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL xgmii_rx_d : t_xgmii_d_arr(g_nof_xaui-1 DOWNTO 0); + + SIGNAL a_rx_channelaligned : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); +-- SIGNAL rxc_rx_channelaligned : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + SIGNAL txc_rx_channelaligned_dly : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + + -- MDIO (optional) signals + SIGNAL mdio_hdr : t_slv_16_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL mdio_tx_dat : t_slv_16_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL mdio_rx_dat : t_slv_16_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL mdio_en_evt : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + SIGNAL mdio_done : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + SIGNAL mdio_done_ack_evt : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + + SIGNAL reg_mdio_hdr : t_slv_16_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL reg_mdio_tx_dat : t_slv_16_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL reg_mdio_rx_dat : t_slv_16_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL reg_mdio_en_evt : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + SIGNAL reg_mdio_done : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + SIGNAL reg_mdio_done_ack_evt : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + + SIGNAL ctlr_mdio_rst : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + SIGNAL ctlr_mdio_hdr : t_slv_16_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL ctlr_mdio_tx_dat : t_slv_16_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL ctlr_mdio_rx_dat : t_slv_16_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL ctlr_mdio_en_evt : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + SIGNAL ctlr_mdio_done : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + SIGNAL ctlr_mdio_done_ack_evt : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + + SIGNAL ctlr_exec_complete : STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + + SIGNAL tx_framer_siso_arr : t_dp_siso_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL tx_framer_sosi_arr : t_dp_sosi_arr(g_nof_xaui-1 DOWNTO 0); + +BEGIN + + ----------------------------------------------------------------------------- + -- XAUI PHY + ----------------------------------------------------------------------------- + gen_phy: IF g_sim = FALSE OR g_sim_level = 0 GENERATE + -- Altera's IP + u_phy_xaui : ENTITY work.phy_xaui + GENERIC MAP ( + g_nof_xaui => g_nof_xaui + ) + PORT MAP ( + tr_clk => tr_clk, + trc_rst => trc_rst, + + mm_rst => mm_rst, + mm_clk => mm_clk, + + cal_rec_clk => cal_rec_clk, + + tx_clk => tx_clk, + rx_clk => i_rx_clk, + + crc_rx_ready => crc_rx_ready, + crc_tx_ready => crc_tx_ready, + + a_rx_channelaligned => a_rx_channelaligned, + + xgmii_tx_dc => xgmii_tx_dc, + xgmii_rx_dc => xgmii_rx_dc, + + xaui_rx => xaui_rx, + xaui_tx => xaui_tx, + + xaui_mosi => xaui_mosi, + xaui_miso => xaui_miso + ); + END GENERATE; + + gen_sim: IF g_sim = TRUE AND g_sim_level = 1 GENERATE + -- Behavioural serdes model (fast) + u_sim_xaui : ENTITY work.sim_xaui + GENERIC MAP ( + g_nof_xaui => g_nof_xaui + ) + PORT MAP ( + tr_clk => tr_clk, + trc_rst => trc_rst, + + cal_rec_clk => cal_rec_clk, + + tx_clk => tx_clk, + rx_clk => i_rx_clk, + + crc_rx_ready => crc_rx_ready, + crc_tx_ready => crc_tx_ready, + + a_rx_channelaligned => a_rx_channelaligned, + + xgmii_tx_dc => xgmii_tx_dc, + xgmii_rx_dc => xgmii_rx_dc, + + xaui_rx => xaui_rx, + xaui_tx => xaui_tx + ); + END GENERATE; + + ----------------------------------------------------------------------------- + -- Clock and reset generation + ----------------------------------------------------------------------------- + u_areset_trc_rst : ENTITY common_lib.common_areset + GENERIC MAP( + g_rst_level => '1', + g_delay_len => 4 + ) + PORT MAP( + clk => tr_clk, + in_rst => '0', + out_rst => trc_rst + ); + + gen_nof_xaui : FOR i IN g_nof_xaui-1 DOWNTO 0 GENERATE + + tx_rst(i) <= i_tx_rst(i); + + rx_clk(i) <= i_rx_clk(i); + rx_rst(i) <= i_rx_rst(i); + + i_rx_rst(i) <= NOT rxc_rx_ready(i); + i_tx_rst(i) <= NOT txc_tx_ready(i); + + u_async_rxc_rx_ready: ENTITY common_lib.common_async + GENERIC MAP( + g_rst_level => '0' + ) + PORT MAP( + clk => i_rx_clk(i), + din => crc_rx_ready(i), + dout => rxc_rx_ready(i) + ); + + u_async_txc_tx_ready: ENTITY common_lib.common_async + GENERIC MAP( + g_rst_level => '0' + ) + PORT MAP( + clk => tx_clk(i), + din => crc_tx_ready(i), + dout => txc_tx_ready(i) + ); + + ----------------------------------------------------------------------------- + -- SOSI <-> XGMII + ----------------------------------------------------------------------------- + gen_sosi_io: IF g_use_xgmii=FALSE GENERATE + + xgmii_tx_dc(i) <= xgmii_dc(xgmii_tx_d(i), xgmii_tx_c(i)); + + xgmii_rx_d(i) <= xgmii_d(xgmii_rx_dc(i)); + xgmii_rx_c(i) <= xgmii_c(xgmii_rx_dc(i)); + + tx_siso_arr(i).ready <= '0' WHEN txc_rx_channelaligned_dly(i) = '0' ELSE tx_framer_siso_arr(i).ready; + tx_siso_arr(i).xon <= txc_rx_channelaligned_dly(i); + + tx_framer_sosi_arr(i) <= tx_sosi_arr(i); + + u_tx_framer : ENTITY work.tr_xaui_framer + GENERIC MAP ( + g_dat_len => sel_a_b(g_sim, 100, 100000), + g_gap_len => 10 + ) + PORT MAP ( + tx_rst => i_tx_rst(i), + tx_clk => tx_clk(i), + + snk_out => tx_framer_siso_arr(i), + snk_in => tx_framer_sosi_arr(i), + + xgmii_tx_d => xgmii_tx_d(i), + xgmii_tx_c => xgmii_tx_c(i) + ); + + u_rx_deframer : ENTITY work.tr_xaui_deframer + PORT MAP ( + rx_rst => i_rx_rst(i), + rx_clk => i_rx_clk(i), + + xgmii_rx_d => xgmii_rx_d(i), + xgmii_rx_c => xgmii_rx_c(i), + + src_out => rx_sosi_arr(i) + ); + + u_tr_xaui_align_dly: ENTITY work.tr_xaui_align_dly + GENERIC MAP( + g_sim => g_sim + ) + PORT MAP( + tx_rst => i_tx_rst(i), + tx_clk => tx_clk(i), + + a_rx_channelaligned => a_rx_channelaligned(i), + txc_rx_channelaligned_dly => txc_rx_channelaligned_dly(i) + ); + + END GENERATE; + + ----------------------------------------------------------------------------- + -- Direct XGMII + ----------------------------------------------------------------------------- + gen_xgmii_io: IF g_use_xgmii=TRUE GENERATE + xgmii_tx_dc(i) <= xgmii_tx_dc_arr(i); + xgmii_rx_dc_arr(i) <= xgmii_rx_dc(i); + END GENERATE; + + gen_mdio: IF g_mdio = TRUE GENERATE + + -- UniBoard FN resets 4 Vitesse chips using one output. + mdio_rst <= ctlr_mdio_rst(0); + + ----------------------------------------------------------------------------- + -- MDIO: the PHY core itself + ----------------------------------------------------------------------------- + u_mdio_phy : ENTITY mdio_lib.mdio_phy + GENERIC MAP( + g_add_mdc_cycle => TRUE + ) + PORT MAP ( + gs_sim => g_sim, + + rst => trc_rst, + clk => tr_clk, + + mdio_en_evt => mdio_en_evt(i), + mdio_done => mdio_done(i), + mdio_done_ack_evt => mdio_done_ack_evt(i), + + hdr => mdio_hdr(i), + tx_dat => mdio_tx_dat(i), + rx_dat => mdio_rx_dat(i), + + -- External clock and serial data + mdc => mdio_mdc(i), + mdat_in => mdio_mdat_in(i), + mdat_oen => mdio_mdat_oen(i) + ); + + ----------------------------------------------------------------------------- + -- MDIO: MM port + ----------------------------------------------------------------------------- + u_mdio_phy_reg : ENTITY mdio_lib.mdio_phy_reg + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + + mdio_rst => trc_rst, + mdio_clk => tr_clk, + + sla_in => mdio_mosi_arr(i), + sla_out => mdio_miso_arr(i), + + mdio_en_evt => reg_mdio_en_evt(i), + mdio_done_ack_evt => reg_mdio_done_ack_evt(i), + mdio_done => reg_mdio_done(i), + + mdio_hdr => reg_mdio_hdr(i), + mdio_tx_dat => reg_mdio_tx_dat(i), + mdio_rx_dat => reg_mdio_rx_dat(i) + ); + + ----------------------------------------------------------------------------- + -- MDIO controller auto-executes MDIO sequence on startup + ----------------------------------------------------------------------------- + gen_mdio_epcs : IF g_mdio_epcs_dis = FALSE GENERATE + u_mdio_ctlr_epcs : ENTITY mdio_lib.mdio_ctlr + GENERIC MAP ( + g_mdio_prtad => c_mdio_vsc8486_prtad, + g_mdio_cmd_arr => c_mdio_vsc8486_init_cmd_arr, + g_mdio_rst_level => '0', + g_mdio_rst_cycles => 250000, + g_mdio_post_rst_cycles => 250000 + ) + PORT MAP ( + rst => trc_rst, + clk => tr_clk, + + mdio_rst => ctlr_mdio_rst(i), + mdio_en_evt => ctlr_mdio_en_evt(i), + mdio_done => ctlr_mdio_done(i), + + mdio_done_ack_evt => ctlr_mdio_done_ack_evt(i), + + hdr => ctlr_mdio_hdr(i), + tx_dat => ctlr_mdio_tx_dat(i), + + exec_complete => ctlr_exec_complete(i) + ); + END GENERATE; + + ----------------------------------------------------------------------------- + -- MDIO controller auto-executes MDIO sequence on startup + ----------------------------------------------------------------------------- + gen_mdio_no_epcs : IF g_mdio_epcs_dis = TRUE GENERATE + u_mdio_ctlr_no_epcs : ENTITY mdio_lib.mdio_ctlr + GENERIC MAP ( + g_mdio_prtad => c_mdio_vsc8486_prtad, + g_mdio_cmd_arr => c_mdio_vsc8486_init_epcs_dis_cmd_arr, + g_mdio_rst_level => '0', + g_mdio_rst_cycles => 250000, + g_mdio_post_rst_cycles => 250000 + ) + PORT MAP ( + rst => trc_rst, + clk => tr_clk, + + mdio_rst => ctlr_mdio_rst(i), + mdio_en_evt => ctlr_mdio_en_evt(i), + mdio_done => ctlr_mdio_done(i), + + mdio_done_ack_evt => ctlr_mdio_done_ack_evt(i), + + hdr => ctlr_mdio_hdr(i), + tx_dat => ctlr_mdio_tx_dat(i), + + exec_complete => ctlr_exec_complete(i) + ); + END GENERATE; + + ----------------------------------------------------------------------------- + -- MDIO: Connect the mdio_ctlr to the mdio_phy initially, when it's done + -- connect the MM controller to allow user control/monitoring. + ----------------------------------------------------------------------------- + mdio_en_evt(i) <= ctlr_mdio_en_evt(i) WHEN ctlr_exec_complete(i)='0' ELSE reg_mdio_en_evt(i); + mdio_done_ack_evt(i) <= ctlr_mdio_done_ack_evt(i) WHEN ctlr_exec_complete(i)='0' ELSE reg_mdio_done_ack_evt(i); + mdio_hdr(i) <= ctlr_mdio_hdr(i) WHEN ctlr_exec_complete(i)='0' ELSE reg_mdio_hdr(i); + mdio_tx_dat(i) <= ctlr_mdio_tx_dat(i) WHEN ctlr_exec_complete(i)='0' ELSE reg_mdio_tx_dat(i); + + ctlr_mdio_done(i) <= mdio_done(i) WHEN ctlr_exec_complete(i)='0' ELSE '0'; + reg_mdio_done(i) <= mdio_done(i) WHEN ctlr_exec_complete(i)='1' ELSE '0'; + reg_mdio_rx_dat(i) <= mdio_rx_dat(i) WHEN ctlr_exec_complete(i)='1' ELSE (OTHERS=>'0'); + + + END GENERATE; -- if g_mdio = True + + END GENERATE; -- for i in 0..g_nof_xaui + +END str; + diff --git a/libraries/io/tr_xaui/src/vhdl/tr_xaui_align_dly.vhd b/libraries/io/tr_xaui/src/vhdl/tr_xaui_align_dly.vhd new file mode 100644 index 0000000000000000000000000000000000000000..0a4a1578f66c3841c7369094e9c31cd4f6a89b53 --- /dev/null +++ b/libraries/io/tr_xaui/src/vhdl/tr_xaui_align_dly.vhd @@ -0,0 +1,122 @@ +-------------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; + +ENTITY tr_xaui_align_dly IS + GENERIC( + g_sim : BOOLEAN + ); + PORT ( + tx_clk : IN STD_LOGIC; + tx_rst : IN STD_LOGIC; + + a_rx_channelaligned : IN STD_LOGIC; + txc_rx_channelaligned_dly : OUT STD_LOGIC + + ); +END tr_xaui_align_dly; + + +ARCHITECTURE rtl OF tr_xaui_align_dly IS + + -- FSM to delay txc_rx_channelaligned (txc_rx_channelaligned_dly is connected to tx_siso.ready) + CONSTANT c_align_dly_cnt : NATURAL := sel_a_b(g_sim, 50, 150000000); -- about 1 second on hw + CONSTANT c_align_dly_cnt_w : NATURAL := ceil_log2(c_align_dly_cnt); + + TYPE t_state_enum IS (s_init, s_aligned, s_aligned_dly); + + SIGNAL state : t_state_enum; + SIGNAL nxt_state : t_state_enum; + + SIGNAL txc_rx_channelaligned : STD_LOGIC; + + SIGNAL txc_align_dly_cycle_cnt : STD_LOGIC_VECTOR(c_align_dly_cnt_w-1 DOWNTO 0); + SIGNAL nxt_txc_align_dly_cycle_cnt : STD_LOGIC_VECTOR(c_align_dly_cnt_w-1 DOWNTO 0); + + SIGNAL i_txc_rx_channelaligned_dly : STD_LOGIC; + SIGNAL nxt_txc_rx_channelaligned_dly : STD_LOGIC; + +BEGIN + + txc_rx_channelaligned_dly <= i_txc_rx_channelaligned_dly; + + u_async_txc_rx_channelaligned: ENTITY common_lib.common_async + GENERIC MAP( + g_rst_level => '0' + ) + PORT MAP( + rst => tx_rst, + clk => tx_clk, + din => a_rx_channelaligned, + dout => txc_rx_channelaligned + ); + + -- Assert txc_rx_channelaligned: basically indicates whether or not the RX of the receiving + -- XAUI core (NOT this one) is assumed to be channelaligned. + -- We assume the RX connected to our TX will be channel aligned within txc_align_dly_cycle_cnt cycles + -- after 'our own' RX has asserted channelaligned. This is important because txc_tx_channelaligned_dly + -- connects directly to tx_siso.ready. + p_tx_clk : PROCESS(tx_rst, tx_clk) + BEGIN + IF tx_rst='1' THEN + state <= s_init; + txc_align_dly_cycle_cnt <= (OTHERS=>'0'); + i_txc_rx_channelaligned_dly <= '0'; + ELSIF rising_edge(tx_clk) THEN + state <= nxt_state; + txc_align_dly_cycle_cnt <= nxt_txc_align_dly_cycle_cnt; + i_txc_rx_channelaligned_dly <= nxt_txc_rx_channelaligned_dly; + END IF; + END PROCESS; + + p_state : PROCESS(state, txc_align_dly_cycle_cnt, txc_rx_channelaligned, i_txc_rx_channelaligned_dly) + BEGIN + nxt_state <= state; + nxt_txc_align_dly_cycle_cnt <= txc_align_dly_cycle_cnt; + nxt_txc_rx_channelaligned_dly <= i_txc_rx_channelaligned_dly; + CASE state IS + + WHEN s_init => --Wait until our own RX is channel aligned + IF txc_rx_channelaligned= '1' THEN + nxt_state <= s_aligned; + END IF; + + WHEN s_aligned => -- We assume the connecting RX is aligned after this delay... + nxt_txc_align_dly_cycle_cnt <= INCR_UVEC(txc_align_dly_cycle_cnt, 1); + IF txc_align_dly_cycle_cnt = TO_UVEC(c_align_dly_cnt, c_align_dly_cnt_w) THEN + nxt_txc_rx_channelaligned_dly <= '1'; + nxt_state <= s_aligned_dly; + END IF; + + WHEN s_aligned_dly => -- ... So now we can assume connected RX has aligned. + -- Do nothing. + + END CASE; + END PROCESS; + + +END rtl; + diff --git a/libraries/io/tr_xaui/src/vhdl/tr_xaui_deframer.vhd b/libraries/io/tr_xaui/src/vhdl/tr_xaui_deframer.vhd new file mode 100644 index 0000000000000000000000000000000000000000..9a2981a420d5ae990a246e27eebacbe119e0771c --- /dev/null +++ b/libraries/io/tr_xaui/src/vhdl/tr_xaui_deframer.vhd @@ -0,0 +1,212 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_interface_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; + +ENTITY tr_xaui_deframer IS + PORT ( + rx_clk : IN STD_LOGIC; + rx_rst : IN STD_LOGIC; + + xgmii_rx_d : IN STD_LOGIC_VECTOR(c_xgmii_data_w-1 DOWNTO 0); + xgmii_rx_c : IN STD_LOGIC_VECTOR(c_xgmii_nof_lanes-1 DOWNTO 0); + + src_out : OUT t_dp_sosi + ); +END tr_xaui_deframer; + +ARCHITECTURE rtl OF tr_xaui_deframer IS + + CONSTANT c_xgmii_c_start_lo : STD_LOGIC_VECTOR(c_xgmii_nof_lanes/2-1 DOWNTO 0) := c_xgmii_c_start(c_xgmii_nof_lanes/2-1 DOWNTO 0); -- 0x1 + CONSTANT c_xgmii_c_term_lo : STD_LOGIC_VECTOR(c_xgmii_nof_lanes/2-1 DOWNTO 0) := c_xgmii_c_term (c_xgmii_nof_lanes/2-1 DOWNTO 0); -- 0x8 + + -- We need to look at the data when we receive the c_xgmii_c_start_lo as control, as the control bits happen to be the same during lane alignment. + -- In that case, the incoming data word is 0x01000009C on both the LS and MS word, and we don't want to mistake that for data. + CONSTANT c_xgmii_d_start_lo : STD_LOGIC_VECTOR(c_xgmii_data_w/2-1 DOWNTO 0) := c_xgmii_d_start(c_xgmii_data_w/2-1 DOWNTO 0); -- 0x000000FB + + TYPE t_state_enum IS (s_init, s_gap, s_data, s_data_misaligned); + + SIGNAL prev_state : t_state_enum; + SIGNAL state : t_state_enum; + SIGNAL nxt_state : t_state_enum; + + -- XGMII RX data & control IN: + SIGNAL xgmii_rx_d_hi : STD_LOGIC_VECTOR(c_xgmii_data_w/2-1 DOWNTO 0); + SIGNAL xgmii_rx_d_lo : STD_LOGIC_VECTOR(c_xgmii_data_w/2-1 DOWNTO 0); + + SIGNAL prev_xgmii_rx_d_hi : STD_LOGIC_VECTOR(c_xgmii_data_w/2-1 DOWNTO 0); + + SIGNAL xgmii_rx_c_hi : STD_LOGIC_VECTOR(c_xgmii_nof_lanes/2-1 DOWNTO 0); + SIGNAL xgmii_rx_c_lo : STD_LOGIC_VECTOR(c_xgmii_nof_lanes/2-1 DOWNTO 0); + + -- RX data & valid OUT: + SIGNAL rx_data_hi : STD_LOGIC_VECTOR(c_xgmii_data_w/2-1 DOWNTO 0); + SIGNAL rx_data_lo : STD_LOGIC_VECTOR(c_xgmii_data_w/2-1 DOWNTO 0); + SIGNAL rx_data_val : STD_LOGIC; + + SIGNAL nxt_rx_data_hi : STD_LOGIC_VECTOR(c_xgmii_data_w/2-1 DOWNTO 0); + SIGNAL nxt_rx_data_lo : STD_LOGIC_VECTOR(c_xgmii_data_w/2-1 DOWNTO 0); + SIGNAL nxt_rx_data_val : STD_LOGIC; + +BEGIN + + src_out.data(c_xgmii_data_w-1 DOWNTO 0) <= rx_data_hi & rx_data_lo; + src_out.valid <= rx_data_val; + + xgmii_rx_d_hi <= xgmii_rx_d(c_xgmii_data_w -1 DOWNTO c_xgmii_data_w/2); + xgmii_rx_d_lo <= xgmii_rx_d(c_xgmii_data_w/2-1 DOWNTO 0); + + xgmii_rx_c_hi <= xgmii_rx_c(c_xgmii_nof_lanes -1 DOWNTO c_xgmii_nof_lanes/2); + xgmii_rx_c_lo <= xgmii_rx_c(c_xgmii_nof_lanes/2-1 DOWNTO 0); + + -- FSM function if word boundary was 64b (it's not): + -- ================================================= + -- xgmii_rx_d I I S D0 D1 D2 D3 T I I I S D4 D5 + + -- nxt_rx_sosi: G G G D0 D1 D2 D3 G G G G G D4 D5 + -- State : G G G D D D D G G G G G D D + + + -- FSM function, word boundary is 32b, tx_data_lo aligned to rx_data_lo: + -- ===================================================================== + -- nxt_rx_sosi_hi = xgmii_rx_d_hi (during s_data) + -- nxt_rx_sosi_lo = xgmii_rx_d_lo (during s_data) + -- ----------------------- + -- xgmii_rx_d_hi: I_hi I_hi S_hi D0_hi D1_hi D2_hi D3_hi T_hi I_hi I_hi I_hi S_hi D4_hi D5_hi + -- xgmii_rx_d_lo: I_lo I_lo S_lo D0_lo D1_lo D2_lo D3_lo T_lo I_lo I_lo I_lo S_lo D4_lo D5_lo + + -- nxt_rx_data_hi: G G G D0_hi D1_hi D2_hi D3_hi G_hi G_hi G_hi G_hi G_hi D4_hi D5_hi + -- nxt_rx_data_lo: G G G D0_lo D1_lo D2_lo D3_lo G_lo G_lo G_lo G_lo G_lo D4_lo D5_lo + -- State : G G G D D D D D G G G G D D + -- ^ ^ ^ + -- | | TERM(LS portion) detected: nxt_rx_data = GAP during last s_data + -- | nxt_rx_data<=DATA during all s_data cycles but the last + -- START(LS portion) detected on xgmii_rx_d_lo: nxt_state <= s_data + + + -- FSM function, word boundary is 32b, tx_data_lo aligned to rx_data_hi: + -- ===================================================================== + -- We need to use the previous rx_data_hi: + -- nxt_rx_sosi_hi = xgmii_rx_d_lo (during s_data_misaligned) + -- nxt_rx_sosi_lo = prev_xgmii_rx_d_hi (during s_data_misaligned) + -- --------------------------- + -- xgmii_rx_d_hi: I_lo S_lo D0_lo D1_lo D2_lo D3_lo T_lo I_lo I_lo I_lo S_lo D4_lo D5_lo + -- xgmii_rx_d_lo: I_hi I_hi S_hi D0_hi D1_hi D2_hi D3_hi T_hi I_hi I_hi I_hi S_hi D4_hi D5_hi + -- prev_xgmii_rx_d_hi: I_lo S_lo D0_lo D1_lo D2_lo D3_lo T_lo I_lo I_lo I_lo S_lo D4_lo D5_lo + + -- nxt_rx_data_hi G G G D0_hi D1_hi D2_hi D3_hi G_hi G_hi G_hi G_hi G_hi D4_hi D5_hi + -- nxt_rx_data_lo G G G D0_lo D1_lo D2_lo D3_lo G_lo G_lo G_lo G_lo G_lo D4_lo D5_lo + -- State : G G D D D D D G G G G G D D + -- ^ ^ ^ + -- | | TERM(LS portion) detected: nxt_rx_data = DATA during last s_data_misaligned + -- | nxt_rx_data<=GAP during first s_data_misaligned cycle (prev_state=s_gap) + -- START(LS portion) detected on xgmii_rx_d_hi: nxt_state <= s_data_misaligned + + + p_clk : PROCESS(rx_clk, rx_rst) + BEGIN + IF rx_rst='1' THEN + state <= s_init; + prev_state <= s_init; + prev_xgmii_rx_d_hi <= (OTHERS=>'0'); + rx_data_hi <= (OTHERS=>'0'); + rx_data_lo <= (OTHERS=>'0'); + rx_data_val <= '0'; + ELSIF rising_edge(rx_clk) THEN + state <= nxt_state; + prev_state <= state; + prev_xgmii_rx_d_hi <= xgmii_rx_d_hi; + rx_data_hi <= nxt_rx_data_hi; + rx_data_lo <= nxt_rx_data_lo; + rx_data_val <= nxt_rx_data_val; + END IF; + END PROCESS; + + -- Note: we only need the XGMII control as input to determine gaps and (mis)alignment + p_state : PROCESS(state, prev_state, prev_xgmii_rx_d_hi, xgmii_rx_c, xgmii_rx_c_lo, xgmii_rx_c_hi, xgmii_rx_d_hi, xgmii_rx_d_lo) + BEGIN + nxt_state <= state; + + CASE state IS + + WHEN s_gap => + nxt_rx_data_hi <= (OTHERS=>'0'); + nxt_rx_data_lo <= (OTHERS=>'0'); + nxt_rx_data_val <= '0'; + IF xgmii_rx_c_lo = c_xgmii_c_start_lo AND xgmii_rx_d_lo = c_xgmii_d_start_lo THEN + -- Data happens to be aligned correctly + nxt_state <= s_data; + ELSIF xgmii_rx_c_hi = c_xgmii_c_start_lo AND xgmii_rx_d_hi = c_xgmii_d_start_lo THEN + -- Data misaligned + nxt_state <= s_data_misaligned; + END IF; + + WHEN s_data => + nxt_rx_data_hi <= xgmii_rx_d_hi; + nxt_rx_data_lo <= xgmii_rx_d_lo; + nxt_rx_data_val <= '1'; + IF xgmii_rx_c_lo = c_xgmii_c_term_lo THEN + -- As we're aligned properly, we can expect a TERM char in the LS word. + -- The MS word will contain the MS portion of the c_xgmii_c_term, + -- and after that we expect idle patterns, so nxt_rx_data is a GAP. + nxt_state <= s_gap; + nxt_rx_data_hi <= (OTHERS=>'0'); + nxt_rx_data_lo <= (OTHERS=>'0'); + nxt_rx_data_val <= '0'; + ELSIF xgmii_rx_c = c_xgmii_c_init THEN + -- Data interrupted due to re-initialization + nxt_state <= s_gap; + END IF; + + WHEN s_data_misaligned => + nxt_rx_data_hi <= xgmii_rx_d_lo; + nxt_rx_data_lo <= prev_xgmii_rx_d_hi; + nxt_rx_data_val <= '1'; + IF prev_state = s_gap THEN + nxt_rx_data_hi <= (OTHERS=>'0'); + nxt_rx_data_lo <= (OTHERS=>'0'); + nxt_rx_data_val <= '0'; + END IF; + IF xgmii_rx_c_hi = c_xgmii_c_term_lo THEN + -- As we're misaligned, we can expect the LS portion of c_xgmii_c_term on the MS position. + nxt_state <= s_gap; + ELSIF xgmii_rx_c = c_xgmii_c_init THEN + -- Data interrupted due to re-initialization + nxt_state <= s_gap; + END IF; + + WHEN OTHERS => + nxt_state <= s_gap; + nxt_rx_data_hi <= (OTHERS=>'0'); + nxt_rx_data_lo <= (OTHERS=>'0'); + nxt_rx_data_val <= '0'; + + END CASE; + END PROCESS; + +END rtl; + + diff --git a/libraries/io/tr_xaui/src/vhdl/tr_xaui_framer.vhd b/libraries/io/tr_xaui/src/vhdl/tr_xaui_framer.vhd new file mode 100644 index 0000000000000000000000000000000000000000..414f3cee9c5dbe0b5ed09e108122c55e116dbb4b --- /dev/null +++ b/libraries/io/tr_xaui/src/vhdl/tr_xaui_framer.vhd @@ -0,0 +1,161 @@ + +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_interface_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; + +ENTITY tr_xaui_framer IS + GENERIC ( + g_dat_len : NATURAL := 1000000; -- Max number of cycles carrying user data + g_gap_len : NATURAL := 5 -- Gap length, including 2 cycles for the START and TERMINATE words + ); + PORT ( + tx_clk : IN STD_LOGIC; + tx_rst : IN STD_LOGIC; + -- ST sink + snk_out : OUT t_dp_siso; + snk_in : IN t_dp_sosi; + + xgmii_tx_d : OUT STD_LOGIC_VECTOR(c_xgmii_data_w-1 DOWNTO 0); + xgmii_tx_c : OUT STD_LOGIC_VECTOR(c_xgmii_nof_lanes-1 DOWNTO 0) + + ); +END tr_xaui_framer; + +ARCHITECTURE rtl OF tr_xaui_framer IS + + TYPE t_state_enum IS (s_init, s_gap, s_data); + + SIGNAL prev_state : t_state_enum; + SIGNAL state : t_state_enum; + SIGNAL nxt_state : t_state_enum; + + SIGNAL i_xgmii_tx_d : STD_LOGIC_VECTOR(c_xgmii_data_w-1 DOWNTO 0); + SIGNAL nxt_xgmii_tx_d : STD_LOGIC_VECTOR(c_xgmii_data_w-1 DOWNTO 0); + + SIGNAL i_xgmii_tx_c : STD_LOGIC_VECTOR(c_xgmii_nof_lanes-1 DOWNTO 0); + SIGNAL nxt_xgmii_tx_c : STD_LOGIC_VECTOR(c_xgmii_nof_lanes-1 DOWNTO 0); + + SIGNAL gap_siso : t_dp_siso; + SIGNAL gap_sosi : t_dp_sosi; + + SIGNAL prev_gap_sosi : t_dp_sosi; + +BEGIN + + xgmii_tx_d <= i_xgmii_tx_d; + xgmii_tx_c <= i_xgmii_tx_c; + + -- We're using a dp_gap instance to make sure gaps occur on a regular basis. This is + -- required as idle patterns (that are converted to lane alignment and other control + -- chars by the xaui phy IP) are inserted during these gaps. Dp_gap also extends any + -- gap on its snk_in to the minimum gap_len by deasserting snk_out.ready. + u_dp_gap : ENTITY dp_lib.dp_gap + GENERIC MAP ( + g_dat_len => g_dat_len, + g_gap_len => g_gap_len, + g_gap_extend => TRUE + ) + PORT MAP ( + rst => tx_rst, + clk => tx_clk, + + snk_out => snk_out, + snk_in => snk_in, + + src_in => gap_siso, + src_out => gap_sosi + ); + + gap_siso.ready <= '1'; + + -- As the dp_gap takes care of the frame length and the gap length, all our FSM needs + -- to do is to take care of xgmii data and control words: + -- * idle->data should be separated by a START (0xFB=Frame Begin) control char (inserted during 1 invalid cycle) + -- * data: encoded as data + -- * data->idle should be separated by a TERMINATE (0xFD=Frame Delimiter) control char (inserted during 1 invalid cycle) + -- * idle: encoded as control + -- ..so we need only 2 states (gap & data) and a data buffer: + -- + -- gap_sosi: G G D0 D1 D2 D3 G G G G G D4 D5 + -- prev_gap_sosi: G G G D0 D1 D2 D3 G G G G G D4 D5 + -- nxt tx data : I I S D0 D1 D2 D3 T I I I S D4 D5 + -- State : G G G D D D D G G G G G D D + p_clk : PROCESS(tx_clk, tx_rst) + BEGIN + IF tx_rst='1' THEN + state <= s_init; + i_xgmii_tx_d <= c_xgmii_d_idle; + i_xgmii_tx_c <= c_xgmii_c_idle; + ELSIF rising_edge(tx_clk) THEN + state <= nxt_state; + prev_state <= state; + prev_gap_sosi <= gap_sosi; + i_xgmii_tx_d <= nxt_xgmii_tx_d; + i_xgmii_tx_c <= nxt_xgmii_tx_c; + END IF; + END PROCESS; + + p_state : PROCESS(state, prev_state, gap_sosi) + BEGIN + nxt_state <= state; + + CASE state IS + + WHEN s_gap => + -- Insert idle words during gaps + nxt_xgmii_tx_d <= c_xgmii_d_idle; + nxt_xgmii_tx_c <= c_xgmii_c_idle; + IF prev_state = s_data THEN + -- Insert the TERM word during transition from data to idle + nxt_xgmii_tx_d <= c_xgmii_d_term; + nxt_xgmii_tx_c <= c_xgmii_c_term; + END IF; + IF gap_sosi.valid = '1' THEN + -- Insert the START word during transition from idle to data + nxt_state <= s_data; + nxt_xgmii_tx_d <= c_xgmii_d_start; + nxt_xgmii_tx_c <= c_xgmii_c_start; + END IF; + + WHEN s_data => -- Forward the data stored in prev_gap_sosi + nxt_xgmii_tx_d <= prev_gap_sosi.data(c_xgmii_data_w-1 DOWNTO 0); + nxt_xgmii_tx_c <= c_xgmii_c_data; + IF gap_sosi.valid = '0' THEN + nxt_state <= s_gap; + END IF; + + WHEN OTHERS => -- s_init + nxt_state <= s_gap; + nxt_xgmii_tx_d <= c_xgmii_d_idle; + nxt_xgmii_tx_c <= c_xgmii_c_idle; + + END CASE; + END PROCESS; + +END rtl; + + diff --git a/libraries/io/tr_xaui/tb/vhdl/sim_xaui.vhd b/libraries/io/tr_xaui/tb/vhdl/sim_xaui.vhd new file mode 100644 index 0000000000000000000000000000000000000000..12ef7dee8f55a244ad2ced8aa7418cd782e2aa1a --- /dev/null +++ b/libraries/io/tr_xaui/tb/vhdl/sim_xaui.vhd @@ -0,0 +1,154 @@ +-------------------------------------------------------------------------------- +-- +-- Copyright (C) 2013 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, tr_nonbonded_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_interface_layers_pkg.ALL; + +ENTITY sim_xaui IS + GENERIC( + g_nof_xaui : NATURAL := 1 + ); + PORT ( + -- Transceiver PLL reference clock + tr_clk : IN STD_LOGIC; + trc_rst : IN STD_LOGIC; + + -- Calibration & reconfig clock + cal_rec_clk : IN STD_LOGIC; + + tx_clk : IN STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + rx_clk : OUT STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + + crc_rx_ready : OUT STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); --crc = synchronous to Cal_Rec_Clk + crc_tx_ready : OUT STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + + a_rx_channelaligned : OUT STD_LOGIC_VECTOR(g_nof_xaui-1 DOWNTO 0); + + xgmii_tx_dc : IN t_xgmii_dc_arr(g_nof_xaui-1 DOWNTO 0); + xgmii_rx_dc : OUT t_xgmii_dc_arr(g_nof_xaui-1 DOWNTO 0); + + xaui_rx : IN t_xaui_arr(g_nof_xaui-1 DOWNTO 0); + xaui_tx : OUT t_xaui_arr(g_nof_xaui-1 DOWNTO 0) + ); +END sim_xaui; + + +ARCHITECTURE wrap OF sim_xaui IS + + CONSTANT c_xaui_serdes_data_w : NATURAL := 16; + CONSTANT c_xaui_serdes_ctrl_w : NATURAL := c_xaui_serdes_data_w/c_byte_w; + CONSTANT c_xaui_serdes_line_rate : NATURAL := 3125; + + --XGMII control bits (one for each XGMII lane): + SIGNAL xgmii_tx_c : t_xgmii_c_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL xgmii_rx_c : t_xgmii_c_arr(g_nof_xaui-1 DOWNTO 0); + + --XGMII data + SIGNAL xgmii_tx_d : t_xgmii_d_arr(g_nof_xaui-1 DOWNTO 0); + SIGNAL xgmii_rx_d : t_xgmii_d_arr(g_nof_xaui-1 DOWNTO 0); + +BEGIN + + rx_clk <= tx_clk; + + gen_nof_xaui : FOR i IN g_nof_xaui-1 DOWNTO 0 GENERATE + + xgmii_tx_d(i) <= xgmii_d(xgmii_tx_dc(i)); + xgmii_tx_c(i) <= xgmii_c(xgmii_tx_dc(i)); + + xgmii_rx_dc(i) <= xgmii_dc(xgmii_rx_d(i), xgmii_rx_c(i)); + + u_areset_tx_rdy : ENTITY common_lib.common_areset + GENERIC MAP( + g_rst_level => '0', + g_delay_len => 10 + ) + PORT MAP( + clk => cal_rec_clk, + in_rst => '0', + out_rst => crc_tx_ready(i) + ); + + u_areset_rx_rdy : ENTITY common_lib.common_areset + GENERIC MAP( + g_rst_level => '0', + g_delay_len => 20 + ) + PORT MAP( + clk => cal_rec_clk, + in_rst => '0', + out_rst => crc_rx_ready(i) + ); + + u_areset_rx_channelaligned : ENTITY common_lib.common_areset + GENERIC MAP( + g_rst_level => '0', + g_delay_len => 30 + ) + PORT MAP( + clk => cal_rec_clk, + in_rst => '0', + out_rst => a_rx_channelaligned(i) + ); + + gen_serdes: FOR j IN c_nof_xaui_lanes-1 DOWNTO 0 GENERATE + + u_ser: ENTITY tr_nonbonded_lib.serializer + GENERIC MAP ( + g_data_w => c_xaui_serdes_data_w, + g_line_rate => c_xaui_serdes_line_rate + ) + PORT MAP ( + + tr_clk => tr_clk, + tr_rst => trc_rst, + + tx_in_data => xgmii_tx_d(i)(j*c_xaui_serdes_data_w+c_xaui_serdes_data_w-1 DOWNTO j*c_xaui_serdes_data_w), + tx_in_ctrl => xgmii_tx_c(i)(j*c_xaui_serdes_ctrl_w+c_xaui_serdes_ctrl_w-1 DOWNTO j*c_xaui_serdes_ctrl_w), + + tx_out => xaui_tx(i)(j) + ); + + u_des: ENTITY tr_nonbonded_lib.deserializer + GENERIC MAP ( + g_data_w => c_xaui_serdes_data_w, + g_line_rate => c_xaui_serdes_line_rate + ) + PORT MAP ( + + tr_clk => tr_clk, + tr_rst => trc_rst, + + rx_out_data => xgmii_rx_d(i)(j*c_xaui_serdes_data_w+c_xaui_serdes_data_w-1 DOWNTO j*c_xaui_serdes_data_w), + rx_out_ctrl => xgmii_rx_c(i)(j*c_xaui_serdes_ctrl_w+c_xaui_serdes_ctrl_w-1 DOWNTO j*c_xaui_serdes_ctrl_w), + + rx_in => xaui_rx(i)(j) + ); + + END GENERATE; + + END GENERATE; + +END wrap; + diff --git a/libraries/io/tr_xaui/tb/vhdl/tb_tr_xaui_deframer.vhd b/libraries/io/tr_xaui/tb/vhdl/tb_tr_xaui_deframer.vhd new file mode 100644 index 0000000000000000000000000000000000000000..bc2b2d58d66fea4d3264297d906eaeb47247a4d0 --- /dev/null +++ b/libraries/io/tr_xaui/tb/vhdl/tb_tr_xaui_deframer.vhd @@ -0,0 +1,197 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE common_lib.common_interface_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE dp_lib.tb_dp_pkg.ALL; + +ENTITY tb_tr_xaui_deframer IS +END tb_tr_xaui_deframer; + +ARCHITECTURE tb OF tb_tr_xaui_deframer IS + + CONSTANT c_clk_period : TIME := 10 ns; + CONSTANT c_rl : NATURAL := 1; + CONSTANT c_tx_init : NATURAL := 0; + + SIGNAL rst : STD_LOGIC; + SIGNAL clk : STD_LOGIC := '1'; + + SIGNAL tx_enable : STD_LOGIC; + + SIGNAL tx_siso : t_dp_siso; + SIGNAL tx_sosi : t_dp_sosi; + + SIGNAL gap_siso : t_dp_siso; + SIGNAL gap_sosi : t_dp_sosi; + + SIGNAL xgmii_tx_d : STD_LOGIC_VECTOR(c_xgmii_data_w-1 DOWNTO 0); + SIGNAL xgmii_tx_c : STD_LOGIC_VECTOR(c_xgmii_nof_lanes-1 DOWNTO 0); + + SIGNAL xgmii_rx_d : STD_LOGIC_VECTOR(c_xgmii_data_w-1 DOWNTO 0); + SIGNAL xgmii_rx_c : STD_LOGIC_VECTOR(c_xgmii_nof_lanes-1 DOWNTO 0); + + SIGNAL deframer_sosi : t_dp_sosi; + SIGNAL deframer_siso : t_dp_siso; + + SIGNAL verify_en : STD_LOGIC; + SIGNAL prev_data1 : STD_LOGIC_VECTOR(c_xgmii_data_w-1 DOWNTO 0); + SIGNAL prev_data2 : STD_LOGIC_VECTOR(c_xgmii_data_w-1 DOWNTO 0); + + SIGNAL xgmii_rx_d_hi : STD_LOGIC_VECTOR(c_xgmii_data_w/2-1 DOWNTO 0); + SIGNAL xgmii_rx_d_lo : STD_LOGIC_VECTOR(c_xgmii_data_w/2-1 DOWNTO 0); + + SIGNAL xgmii_tx_d_hi : STD_LOGIC_VECTOR(c_xgmii_data_w/2-1 DOWNTO 0); + SIGNAL xgmii_tx_d_lo : STD_LOGIC_VECTOR(c_xgmii_data_w/2-1 DOWNTO 0); + + SIGNAL prev_xgmii_tx_d_hi : STD_LOGIC_VECTOR(c_xgmii_data_w/2-1 DOWNTO 0); + SIGNAL prev_xgmii_tx_c_hi : STD_LOGIC_VECTOR(c_xgmii_nof_lanes/2-1 DOWNTO 0); + + SIGNAL xgmii_tx_c_hi : STD_LOGIC_VECTOR(c_xgmii_nof_lanes/2-1 DOWNTO 0); + SIGNAL xgmii_tx_c_lo : STD_LOGIC_VECTOR(c_xgmii_nof_lanes/2-1 DOWNTO 0); + + SIGNAL xgmii_rx_c_hi : STD_LOGIC_VECTOR(c_xgmii_nof_lanes/2-1 DOWNTO 0); + SIGNAL xgmii_rx_c_lo : STD_LOGIC_VECTOR(c_xgmii_nof_lanes/2-1 DOWNTO 0); + + SIGNAL misalign : STD_LOGIC; + +BEGIN + + rst <= '1', '0' AFTER c_clk_period*7; + clk <= NOT clk AFTER c_clk_period/2; + + xgmii_tx_d_hi <= xgmii_tx_d(c_xgmii_data_w -1 DOWNTO c_xgmii_data_w/2); + xgmii_tx_d_lo <= xgmii_tx_d(c_xgmii_data_w/2-1 DOWNTO 0); + + xgmii_tx_c_hi <= xgmii_tx_c(c_xgmii_nof_lanes -1 DOWNTO c_xgmii_nof_lanes/2); + xgmii_tx_c_lo <= xgmii_tx_c(c_xgmii_nof_lanes/2-1 DOWNTO 0); + + xgmii_rx_d <= xgmii_rx_d_hi & xgmii_rx_d_lo; + xgmii_rx_c <= xgmii_rx_c_hi & xgmii_rx_c_lo; + + p_stim : PROCESS + BEGIN + tx_enable <= '0'; + verify_en <= '0'; + misalign <= '0'; + + WAIT FOR c_clk_period*100; + tx_enable <= '1'; + gap_siso.ready <= '1'; + + WAIT FOR c_clk_period*20; + verify_en <= '1'; + + -- Let run for a while with aligned data + WAIT FOR 3 us; + + WAIT UNTIL deframer_sosi.valid = '0'; + WAIT UNTIL rising_edge(clk); + misalign <= '1'; -- Now change the 32b word boundary + + WAIT; + END PROCESS; + + -- Generate tx_sosi for DUT using counter data generator + proc_dp_gen_data(c_rl, c_xgmii_data_w, c_tx_init, rst, clk, tx_enable, tx_siso, tx_sosi); + + -- Introduce some gaps in the streaming data to make sure framer handles them correctly. + u_dp_gap : ENTITY dp_lib.dp_gap + GENERIC MAP ( + g_dat_len => 40, + g_gap_len => 20 + ) + PORT MAP ( + rst => rst, + clk => clk, + + snk_out => tx_siso, + snk_in => tx_sosi, + + src_in => gap_siso, + src_out => gap_sosi + ); + + u_framer : ENTITY work.tr_xaui_framer + GENERIC MAP ( + g_dat_len => 100, + g_gap_len => 5 + ) + PORT MAP ( + tx_rst => rst, + tx_clk => clk, + + snk_out => gap_siso, + snk_in => gap_sosi, + + xgmii_tx_d => xgmii_tx_d, + xgmii_tx_c => xgmii_tx_c + ); + + -- ============== We'll emulate misalignment here =========================== + + -- Aligned data: + -- RX Hi: 0 1 2 3 4 5 + -- RX Lo: 0 1 2 3 4 5 + xgmii_rx_d_hi <= xgmii_tx_d_lo WHEN misalign = '1' ELSE xgmii_tx_d_hi; + xgmii_rx_c_hi <= xgmii_tx_c_lo WHEN misalign = '1' ELSE xgmii_tx_c_hi; + + -- Misligned data: + -- RX Hi: 1 2 3 4 5 6 + -- RX Lo: 0 1 2 3 4 5 + xgmii_rx_d_lo <= prev_xgmii_tx_d_hi WHEN misalign = '1' ELSE xgmii_tx_d_lo; + xgmii_rx_c_lo <= prev_xgmii_tx_c_hi WHEN misalign = '1' ELSE xgmii_tx_c_lo; + + p_clk : PROCESS(clk, rst) + BEGIN + IF rst='1' THEN + prev_xgmii_tx_d_hi <= x"07070707"; + prev_xgmii_tx_c_hi <= x"F"; + ELSIF rising_edge(clk) THEN + prev_xgmii_tx_d_hi <= xgmii_tx_d_hi; + prev_xgmii_tx_c_hi <= xgmii_tx_c_hi; + END IF; + END PROCESS; + + -- =========================================================================== + + dut : ENTITY work.tr_xaui_deframer + PORT MAP ( + rx_rst => rst, + rx_clk => clk, + + xgmii_rx_d => xgmii_rx_d, + xgmii_rx_c => xgmii_rx_c, + + src_out => deframer_sosi + + ); + + -- Verify DUT output incrementing data, prev_data is an auxiliary signal needed by the proc + proc_common_verify_data(c_rl, clk, verify_en, deframer_siso.ready, deframer_sosi.valid, deframer_sosi.data(c_xgmii_data_w-1 DOWNTO 0), prev_data1); + proc_dp_verify_data("data", c_rl, clk, verify_en, deframer_siso.ready, deframer_sosi.valid, deframer_sosi.data(c_xgmii_data_w-1 DOWNTO 0), prev_data2); + +END tb; diff --git a/libraries/io/tr_xaui/tb/vhdl/tb_tr_xaui_framer.vhd b/libraries/io/tr_xaui/tb/vhdl/tb_tr_xaui_framer.vhd new file mode 100644 index 0000000000000000000000000000000000000000..dee798e02ab6598f90a9e525f11ef83cb5b6a3c3 --- /dev/null +++ b/libraries/io/tr_xaui/tb/vhdl/tb_tr_xaui_framer.vhd @@ -0,0 +1,106 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE common_lib.common_interface_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE dp_lib.tb_dp_pkg.ALL; + +ENTITY tb_tr_xaui_framer IS +END tb_tr_xaui_framer; + +ARCHITECTURE tb OF tb_tr_xaui_framer IS + + CONSTANT c_clk_period : TIME := 10 ns; + CONSTANT c_rl : NATURAL := 1; + CONSTANT c_tx_init : NATURAL := 0; + + SIGNAL rst : STD_LOGIC; + SIGNAL clk : STD_LOGIC := '1'; + + SIGNAL tx_enable : STD_LOGIC; + + SIGNAL tx_siso : t_dp_siso; + SIGNAL tx_sosi : t_dp_sosi; + + SIGNAL gap_siso : t_dp_siso; + SIGNAL gap_sosi : t_dp_sosi; + + SIGNAL xgmii_tx_d : STD_LOGIC_VECTOR(c_xgmii_data_w-1 DOWNTO 0); + SIGNAL xgmii_tx_c : STD_LOGIC_VECTOR(c_xgmii_nof_lanes-1 DOWNTO 0); + +BEGIN + + rst <= '1', '0' AFTER c_clk_period*7; + clk <= NOT clk AFTER c_clk_period/2; + + p_stim : PROCESS + BEGIN + tx_enable <= '0'; + + WAIT FOR c_clk_period*100; + tx_enable <= '1'; + + WAIT; + END PROCESS; + + -- Generate tx_sosi for DUT using counter data generator + proc_dp_gen_data(c_rl, c_xgmii_data_w, c_tx_init, rst, clk, tx_enable, tx_siso, tx_sosi); + + -- Introduce some gaps in the streaming data to make sure framer handles them correctly. + u_dp_gap : ENTITY dp_lib.dp_gap + GENERIC MAP ( + g_dat_len => 40, + g_gap_len => 20 + ) + PORT MAP ( + rst => rst, + clk => clk, + + snk_out => tx_siso, + snk_in => tx_sosi, + + src_in => gap_siso, + src_out => gap_sosi + ); + + dut : ENTITY work.tr_xaui_framer + GENERIC MAP ( + g_dat_len => 100, + g_gap_len => 5 + ) + PORT MAP ( + tx_rst => rst, + tx_clk => clk, + + snk_out => gap_siso, + snk_in => gap_sosi, + + xgmii_tx_d => xgmii_tx_d, + xgmii_tx_c => xgmii_tx_c + + ); + +END tb;