diff --git a/boards/uniboard2/libraries/unb2_board/hdllib.cfg b/boards/uniboard2/libraries/unb2_board/hdllib.cfg index a9499ba6dd3bc5a4181202fc5564a4289f50fea9..7b29809b3c742af9d2bf4bbb44f4344c246d70c9 100644 --- a/boards/uniboard2/libraries/unb2_board/hdllib.cfg +++ b/boards/uniboard2/libraries/unb2_board/hdllib.cfg @@ -22,6 +22,7 @@ synth_files = src/vhdl/unb2_board_sens_reg.vhd src/vhdl/mms_unb2_board_sens.vhd src/vhdl/unb2_board_wdi_reg.vhd + src/vhdl/unb2_board_qsfp_leds.vhd src/vhdl/ctrl_unb2_board.vhd src/vhdl/unb2_board_front_io.vhd src/vhdl/unb2_board_back_io.vhd @@ -35,6 +36,7 @@ test_bench_files = tb/vhdl/tb_unb2_board_clk200_pll.vhd tb/vhdl/tb_unb2_board_clk25_pll.vhd tb/vhdl/tb_unb2_board_node_ctrl.vhd + tb/vhdl/tb_unb2_board_qsfp_leds.vhd # vsim -L ... -L ... ... modelsim_search_libraries = diff --git a/boards/uniboard2/libraries/unb2_board/src/vhdl/unb2_board_qsfp_leds.vhd b/boards/uniboard2/libraries/unb2_board/src/vhdl/unb2_board_qsfp_leds.vhd new file mode 100644 index 0000000000000000000000000000000000000000..f90d2dc68961b44125a049a8e170d394778f678e --- /dev/null +++ b/boards/uniboard2/libraries/unb2_board/src/vhdl/unb2_board_qsfp_leds.vhd @@ -0,0 +1,186 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2015 +-- 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 dp_lib.dp_stream_pkg.ALL; + +-- Purpose: Provide visual activity information via the UniBoard2 front panel QSFP LEDs. +-- Description: +-- The testio LED on UniBoard2 is not visible via the front panel. The +-- front panel does have a dual colour LED for each QSFP lane. Therefore +-- these QSFP LEDs are used to signal some application information and lane +-- status/activity information. +-- +-- LED lights: +-- +-- 1) Default behaviour for all QSFP leds: +-- . off = no FPGA image is running +-- +-- 2) For factory image: +-- . green off +-- . red toggling every 1 s = factory image is running (g_factory_image=TRUE) +-- +-- 3) For a user image without Gbps lane functionality: +-- . red off +-- . green toggling every 1 s = user image is running (g_factory_image=FALSE and green_on_arr(I)='0' default) +-- +-- 4) For a user image with Gbps lane functionality: +-- . red off +-- . green toggling every 1 s when the lane status is not OK (green_on_arr(I)=xon='0') +-- . green on continously when the lane status is OK (green_on_arr(I)=xon='1') +-- . green led goes off briefly off when there is an Tx or Rx packet (green_evt_arr(I).sop='1') +-- +-- The combined colour amber (= red + green) is not used. The factory image +-- only uses the red led and the user image only uses the green led. +-- +-- Each QSFP carries c_quad = 4 lanes, therefore the green led LED can only +-- signal a combined status of the lanes. The combined status eg. be: +-- +-- 'and-status' = combined status is on when all lanes are on +-- 'or-status' = combined status is on when at least 1 lane is on +-- +-- Choose using 'or-status', because then the LED can give lane status +-- information when less than all 4 lane are connected. +-- + +ENTITY unb2_board_qsfp_leds IS + GENERIC ( + g_sim : BOOLEAN := FALSE; -- when true speed up led toggling in simulation + g_factory_image : BOOLEAN := FALSE; -- distinguish factory image and user images + g_nof_qsfp : NATURAL := 6; -- number of QSFP cages each with one dual led that can light red or green (or amber = red + green) + g_pulse_us : NATURAL := 200 -- nof clk cycles to get us period + ); + PORT ( + rst : IN STD_LOGIC; + clk : IN STD_LOGIC; + -- internal pulser outputs + pulse_us : OUT STD_LOGIC; + pulse_ms : OUT STD_LOGIC; + pulse_s : OUT STD_LOGIC; + -- lane status + tx_siso_arr : IN t_dp_siso_arr(g_nof_qsfp*c_quad-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rst); + tx_sosi_arr : IN t_dp_sosi_arr(g_nof_qsfp*c_quad-1 DOWNTO 0) := (OTHERS=>c_dp_sosi_rst); + rx_sosi_arr : IN t_dp_sosi_arr(g_nof_qsfp*c_quad-1 DOWNTO 0) := (OTHERS=>c_dp_sosi_rst); + -- leds + green_led_arr : OUT STD_LOGIC_VECTOR(g_nof_qsfp-1 DOWNTO 0); + red_led_arr : OUT STD_LOGIC_VECTOR(g_nof_qsfp-1 DOWNTO 0) + ); +END unb2_board_qsfp_leds; + + +ARCHITECTURE str OF unb2_board_qsfp_leds IS + + CONSTANT c_nof_ms : NATURAL := sel_a_b(g_sim, 1, 100); -- force off for c_nof_ms and then on for at least c_nof_ms + CONSTANT c_nof_lanes : NATURAL := g_nof_qsfp*c_quad; -- number of transceiver lanes, fixed 4 per Quad-SFP cage + + SIGNAL i_pulse_ms : STD_LOGIC; + SIGNAL i_pulse_s : STD_LOGIC; + SIGNAL toggle_s : STD_LOGIC; + + SIGNAL green_on_arr : STD_LOGIC_VECTOR(g_nof_qsfp*c_quad-1 DOWNTO 0); + SIGNAL green_evt_arr : STD_LOGIC_VECTOR(g_nof_qsfp*c_quad-1 DOWNTO 0); + + SIGNAL qsfp_on_arr : STD_LOGIC_VECTOR(g_nof_qsfp-1 DOWNTO 0); + SIGNAL qsfp_evt_arr : STD_LOGIC_VECTOR(g_nof_qsfp-1 DOWNTO 0); + +BEGIN + + pulse_ms <= i_pulse_ms; + pulse_s <= i_pulse_s; + + -- Also output the pulses, because they could be useful for other purposes in the clk clock domain as well + u_common_pulser_us_ms_s : ENTITY common_lib.common_pulser_us_ms_s + GENERIC MAP ( + g_pulse_us => g_pulse_us, -- nof clk cycles to get us period + g_pulse_ms => sel_a_b(g_sim, 10, 1000), -- nof pulse_us pulses to get ms period + g_pulse_s => sel_a_b(g_sim, 10, 1000) -- nof pulse_ms pulses to get s period + ) + PORT MAP ( + rst => rst, + clk => clk, + pulse_us => pulse_us, + pulse_ms => i_pulse_ms, + pulse_s => i_pulse_s + ); + + u_common_toggle_s : ENTITY common_lib.common_toggle + PORT MAP ( + rst => rst, + clk => clk, + in_dat => i_pulse_s, + out_dat => toggle_s + ); + + gen_factory_image : IF g_factory_image=TRUE GENERATE + green_led_arr <= (OTHERS=>'0'); + + gen_red_led_arr : FOR I IN g_nof_qsfp-1 DOWNTO 0 GENERATE + u_red_led_controller : ENTITY common_lib.common_led_controller + GENERIC MAP ( + g_nof_ms => c_nof_ms + ) + PORT MAP ( + rst => rst, + clk => clk, + -- led control + ctrl_input => toggle_s, + -- led output + led => red_led_arr(I) + ); + END GENERATE; + END GENERATE; + + gen_user_image : IF g_factory_image=FALSE GENERATE + + red_led_arr <= (OTHERS=>'0'); + + gen_green_ctrl_arr : FOR I IN c_nof_lanes-1 DOWNTO 0 GENERATE + green_on_arr(I) <= tx_siso_arr(I).xon WHEN rising_edge(clk); + green_evt_arr(I) <= tx_sosi_arr(I).sop OR rx_sosi_arr(I).sop WHEN rising_edge(clk); + END GENERATE; + + gen_green_led_arr : FOR I IN g_nof_qsfp-1 DOWNTO 0 GENERATE + + qsfp_on_arr(I) <= orv(green_on_arr( (I+1)*c_quad-1 DOWNTO + I*c_quad)); + qsfp_evt_arr(I) <= orv(green_evt_arr((I+1)*c_quad-1 DOWNTO + I*c_quad)); + + u_green_led_controller : ENTITY common_lib.common_led_controller + GENERIC MAP ( + g_nof_ms => c_nof_ms + ) + PORT MAP ( + rst => rst, + clk => clk, + pulse_ms => i_pulse_ms, + -- led control + ctrl_on => qsfp_on_arr(I), + ctrl_evt => qsfp_evt_arr(I), + ctrl_input => toggle_s, + -- led output + led => green_led_arr(I) + ); + END GENERATE; + END GENERATE; + +END str; diff --git a/boards/uniboard2/libraries/unb2_board/tb/vhdl/tb_unb2_board_qsfp_leds.vhd b/boards/uniboard2/libraries/unb2_board/tb/vhdl/tb_unb2_board_qsfp_leds.vhd new file mode 100644 index 0000000000000000000000000000000000000000..8ca7b73ea19a6d7f63979ebb04bcd2196ff06bc8 --- /dev/null +++ b/boards/uniboard2/libraries/unb2_board/tb/vhdl/tb_unb2_board_qsfp_leds.vhd @@ -0,0 +1,190 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2010 +-- 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/>. +-- +------------------------------------------------------------------------------- + +-- Purpose: Test bench for unb2_board_qsfp_leds +-- Description: +-- The test bench is self-stopping but not self-checking. Manually obeserve +-- in the wave window that: +-- 1) factory image: +-- - green led is off +-- - red led toggles +-- 2) user image +-- - red led is off +-- - green led toggles when any xon='0' +-- - green led is on continously when any xon='1' +-- - green led goes briefly off when any sop='1' +-- Usage: +-- > as 3 +-- > run -a + +LIBRARY IEEE, common_lib, dp_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; + +ENTITY tb_unb2_board_qsfp_leds IS +END tb_unb2_board_qsfp_leds; + +ARCHITECTURE tb OF tb_unb2_board_qsfp_leds IS + + CONSTANT c_clk_freq_hz : NATURAL := 200 * 10**6; + CONSTANT c_clk_period_ns : NATURAL := 10**9 / c_clk_freq_hz; + CONSTANT c_nof_clk_per_us : NATURAL := 1000 / c_clk_period_ns; + + CONSTANT clk_period : TIME := c_clk_period_ns * 1 ns; + + CONSTANT c_nof_qsfp : NATURAL := 2; + CONSTANT c_nof_lanes : NATURAL := c_nof_qsfp*c_quad; + + SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL rst : STD_LOGIC; + SIGNAL clk : STD_LOGIC := '0'; + SIGNAL pulse_us : STD_LOGIC; + SIGNAL pulse_ms : STD_LOGIC; + SIGNAL pulse_s : STD_LOGIC; + + SIGNAL tx_siso_arr : t_dp_siso_arr(c_nof_lanes-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rst); + SIGNAL tx_sosi_arr : t_dp_sosi_arr(c_nof_lanes-1 DOWNTO 0) := (OTHERS=>c_dp_sosi_rst); + SIGNAL rx_sosi_arr : t_dp_sosi_arr(c_nof_lanes-1 DOWNTO 0) := (OTHERS=>c_dp_sosi_rst); + + SIGNAL dbg_xon_arr : STD_LOGIC_VECTOR(c_nof_lanes-1 DOWNTO 0); + SIGNAL dbg_tx_sop_arr : STD_LOGIC_VECTOR(c_nof_lanes-1 DOWNTO 0); + SIGNAL dbg_rx_sop_arr : STD_LOGIC_VECTOR(c_nof_lanes-1 DOWNTO 0); + + SIGNAL factory_green_led_arr : STD_LOGIC_VECTOR(c_nof_qsfp-1 DOWNTO 0); + SIGNAL factory_red_led_arr : STD_LOGIC_VECTOR(c_nof_qsfp-1 DOWNTO 0); + + SIGNAL user_green_led_arr : STD_LOGIC_VECTOR(c_nof_qsfp-1 DOWNTO 0); + SIGNAL user_red_led_arr : STD_LOGIC_VECTOR(c_nof_qsfp-1 DOWNTO 0); + + -- Cannot use proc_common_gen_pulse() to create sop in array. + -- proc_common_gen_pulse() works for dbg_sop, dbg_sosi.sop but not for dbg_sop_slv(I) or for tx_sosi_arr(I).sop. + -- The compiler then gives Error: "(vcom-1450) Actual (indexed name) for formal "pulse" is not a static signal name" + -- It does work if the array index is from a GENERATE statement, but it does not work when it is from a LOOP statement. + SIGNAL dbg_sop : STD_LOGIC; + SIGNAL dbg_sop_slv : STD_LOGIC_VECTOR(c_nof_lanes-1 DOWNTO 0); + SIGNAL dbg_sosi : t_dp_sosi; + +BEGIN + + clk <= NOT clk OR tb_end AFTER clk_period/2; + rst <= '1', '0' AFTER clk_period*7; + + -- Ease observation of record fields in Wave window, by mapping them to a SLV + dbg_xon_arr <= func_dp_stream_arr_get(tx_siso_arr, "XON"); + dbg_tx_sop_arr <= func_dp_stream_arr_get(tx_sosi_arr, "SOP"); + dbg_rx_sop_arr <= func_dp_stream_arr_get(rx_sosi_arr, "SOP"); + + p_stimuli : PROCESS + BEGIN + tx_siso_arr <= (OTHERS=>c_dp_siso_rst); + tx_sosi_arr <= (OTHERS=>c_dp_sosi_rst); + rx_sosi_arr <= (OTHERS=>c_dp_sosi_rst); + proc_common_wait_some_pulses(clk, pulse_ms, 50); + + -- Switch on each lane + FOR I IN 0 TO c_nof_lanes-1 LOOP + tx_siso_arr(I).xon <= '1'; + proc_common_wait_some_pulses(clk, pulse_ms, 10); + END LOOP; + proc_common_wait_some_pulses(clk, pulse_ms, 50); + + -- Issue the sop of a Tx packet on each lane + FOR I IN 0 TO c_nof_lanes-1 LOOP + -- Cannot use proc_common_gen_pulse(), because index I in a LOOP is not static + tx_sosi_arr(I).sop <= '1'; + WAIT UNTIL rising_edge(clk); + tx_sosi_arr(I).sop <= '0'; + proc_common_wait_some_pulses(clk, pulse_ms, 10); + END LOOP; + proc_common_wait_some_pulses(clk, pulse_ms, 50); + + -- Issue the sop of an Rx packet on each lane + FOR I IN 0 TO c_nof_lanes-1 LOOP + -- Cannot use proc_common_gen_pulse(), because index I in a LOOP is not static + rx_sosi_arr(I).sop <= '1'; + WAIT UNTIL rising_edge(clk); + rx_sosi_arr(I).sop <= '0'; + proc_common_wait_some_pulses(clk, pulse_ms, 10); + END LOOP; + proc_common_wait_some_pulses(clk, pulse_ms, 50); + + -- Switch off each lane + FOR I IN 0 TO c_nof_lanes-1 LOOP + tx_siso_arr(I).xon <= '0'; + proc_common_wait_some_pulses(clk, pulse_ms, 10); + END LOOP; + proc_common_wait_some_pulses(clk, pulse_ms, 50); + + tb_end <= '1'; + proc_common_wait_some_pulses(clk, pulse_ms, 10); + WAIT; + END PROCESS; + + u_unb2_factory_qsfp_leds : ENTITY work.unb2_board_qsfp_leds + GENERIC MAP ( + g_sim => TRUE, -- when true speed up led toggling in simulation + g_factory_image => TRUE, -- distinguish factory image and user images + g_nof_qsfp => c_nof_qsfp, -- number of QSFP cages each with one dual led that can light red or green (or amber = red + green) + g_pulse_us => c_nof_clk_per_us -- nof clk cycles to get us period + ) + PORT MAP ( + rst => rst, + clk => clk, + -- internal pulser outputs + pulse_us => pulse_us, + pulse_ms => pulse_ms, + pulse_s => pulse_s, + -- lane status + tx_siso_arr => tx_siso_arr, + tx_sosi_arr => tx_sosi_arr, + rx_sosi_arr => rx_sosi_arr, + -- leds + green_led_arr => factory_green_led_arr, + red_led_arr => factory_red_led_arr + ); + + u_unb2_user_qsfp_leds : ENTITY work.unb2_board_qsfp_leds + GENERIC MAP ( + g_sim => TRUE, -- when true speed up led toggling in simulation + g_factory_image => FALSE, -- distinguish factory image and user images + g_nof_qsfp => c_nof_qsfp, -- number of QSFP cages each with one dual led that can light red or green (or amber = red + green) + g_pulse_us => c_nof_clk_per_us -- nof clk cycles to get us period + ) + PORT MAP ( + rst => rst, + clk => clk, + -- internal pulser outputs + pulse_us => pulse_us, + pulse_ms => pulse_ms, + pulse_s => pulse_s, + -- lane status + tx_siso_arr => tx_siso_arr, + tx_sosi_arr => tx_sosi_arr, + rx_sosi_arr => rx_sosi_arr, + -- leds + green_led_arr => user_green_led_arr, + red_led_arr => user_red_led_arr + ); + +END tb;