diff --git a/libraries/base/diag/hdllib.cfg b/libraries/base/diag/hdllib.cfg index fd071bc1aaf4ac5945ed6b4608cdd34ecaefb835..bbeae9b7c8658cb0a8346b16729fadfd0815e39a 100644 --- a/libraries/base/diag/hdllib.cfg +++ b/libraries/base/diag/hdllib.cfg @@ -8,9 +8,9 @@ build_dir_synth = $HDL_BUILD_DIR synth_files = $UNB/Firmware/modules/Lofar/diag/src/vhdl/diag_bypass.vhd - $UNB/Firmware/modules/Lofar/diag/src/vhdl/diag_tx_seq.vhd + src/vhdl/diag_tx_seq.vhd $UNB/Firmware/modules/Lofar/diag/src/vhdl/diag_tx_frm.vhd - $UNB/Firmware/modules/Lofar/diag/src/vhdl/diag_rx_seq.vhd + src/vhdl/diag_rx_seq.vhd $UNB/Firmware/modules/Lofar/diag/src/vhdl/diag_frm_generator.vhd $UNB/Firmware/modules/Lofar/diag/src/vhdl/diag_frm_monitor.vhd src/vhdl/mms_diag_tx_seq.vhd diff --git a/libraries/base/diag/src/vhdl/diag_rx_seq.vhd b/libraries/base/diag/src/vhdl/diag_rx_seq.vhd new file mode 100644 index 0000000000000000000000000000000000000000..33d721703386bc51e167f3f4ac40b63ad0b79814 --- /dev/null +++ b/libraries/base/diag/src/vhdl/diag_rx_seq.vhd @@ -0,0 +1,283 @@ +-------------------------------------------------------------------------------- +-- +-- Copyright (C) 2009 +-- 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 IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_lfsr_sequences_pkg.ALL; + + +-- Purpose: Verify received continuous PRSG or COUNTER test sequence data. +-- Description: +-- The test data can be PRSG or COUNTER dependent on diag_sel. +-- The Rx is enabled by diag_en. Typically the Tx should already be running, +-- but it is also allowed to first enable the Rx. +-- The Rx is always ready to accept data, therefore it has no in_ready output. +-- Inititally when diag_en is low then diag_res = -1, when diag_en is high +-- then diag_res becomes valid, indicated by diag_res_val, after two test +-- data words have been received. The diag_res verifies per input dat bit, +-- when an in_dat bit goes wrong then the corresponding bit in diag_res goes +-- high and remains high until the Rx is restarted again. This is useful if +-- the test data bits go via separate physical lines (e.g. an LVDS bus). +-- When the Rx is disabled then diag_res = -1. Typically the g_diag_res_w > +-- g_dat_w: +-- . diag_res(g_diag_res_w-1:g_dat_w) => NOT diag_res_val +-- . diag_res( g_dat_w-1:0 ) => aggregated diff of in_dat during +-- diag_en +-- It is possible to use g_diag_res_w=g_dat_w, but then it is not possible to +-- distinguish between whether the test has ran at all or whether all bits +-- got errors. + +ENTITY diag_rx_seq IS + GENERIC ( + g_input_reg : BOOLEAN := FALSE; -- Use unregistered input to save logic, use registered input to ease achieving timing constrains. + g_sel : STD_LOGIC := '1'; -- '0' = PRSG, '1' = COUNTER + g_dat_w : NATURAL := 12; + g_diag_res_w : NATURAL := 16 + ); + PORT ( + rst : IN STD_LOGIC; + clk : IN STD_LOGIC; + clken : IN STD_LOGIC := '1'; + + -- Static control input (connect via MM or leave open to use default) + diag_en : IN STD_LOGIC; -- '0' = init and disable, '1' = enable + diag_sel : IN STD_LOGIC := g_sel; + diag_res : OUT STD_LOGIC_VECTOR(g_diag_res_w-1 DOWNTO 0); -- diag_res valid indication bits & aggregate diff of in_dat during diag_en + diag_res_val : OUT STD_LOGIC; + + -- ST input + in_dat : IN STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0); + in_val : IN STD_LOGIC -- gaps are allowed, however diag_res requires at least 2 valid in_dat to report a valid result + ); +END diag_rx_seq; + + +ARCHITECTURE rtl OF diag_rx_seq IS + + CONSTANT c_lfsr_nr : NATURAL := g_dat_w - c_common_lfsr_first; + + CONSTANT c_diag_res_latency : NATURAL := 3; + + -- Used special value to signal invalid diag_res, unique assuming g_diag_res_w > g_dat_w + CONSTANT c_diag_res_invalid : STD_LOGIC_VECTOR(diag_res'RANGE) := (OTHERS=>'1'); + + SIGNAL in_val_reg : STD_LOGIC; + SIGNAL in_dat_reg : STD_LOGIC_VECTOR(in_dat'RANGE); + + SIGNAL in_dat_dly1 : STD_LOGIC_VECTOR(in_dat'RANGE); -- latency common_lfsr_nxt_seq + SIGNAL in_dat_dly2 : STD_LOGIC_VECTOR(in_dat'RANGE); -- latency ref_dat + SIGNAL in_val_dly1 : STD_LOGIC; -- latency common_lfsr_nxt_seq + SIGNAL in_val_dly2 : STD_LOGIC; -- latency ref_dat + + SIGNAL prsg : STD_LOGIC_VECTOR(in_dat'RANGE); + SIGNAL nxt_prsg : STD_LOGIC_VECTOR(in_dat'RANGE); + SIGNAL cntr : STD_LOGIC_VECTOR(in_dat'RANGE); + SIGNAL nxt_cntr : STD_LOGIC_VECTOR(in_dat'RANGE); + + SIGNAL diag_dis : STD_LOGIC; + SIGNAL ref_en : STD_LOGIC; + SIGNAL diff_dis : STD_LOGIC; + SIGNAL diag_res_en : STD_LOGIC; + SIGNAL nxt_diag_res_en : STD_LOGIC; + SIGNAL nxt_diag_res_val: STD_LOGIC; + + SIGNAL in_val_1 : STD_LOGIC; + SIGNAL in_val_act : STD_LOGIC; + SIGNAL in_val_2 : STD_LOGIC; + SIGNAL in_val_2_dly : STD_LOGIC_VECTOR(0 TO c_diag_res_latency-1) := (OTHERS=>'0'); + SIGNAL in_val_2_act : STD_LOGIC; + + SIGNAL ref_dat : STD_LOGIC_VECTOR(in_dat'RANGE); + SIGNAL nxt_ref_dat : STD_LOGIC_VECTOR(in_dat'RANGE); + SIGNAL diff_dat : STD_LOGIC_VECTOR(in_dat'RANGE) := (OTHERS=>'0'); + SIGNAL nxt_diff_dat : STD_LOGIC_VECTOR(in_dat'RANGE); + SIGNAL diff_res : STD_LOGIC_VECTOR(in_dat'RANGE); + SIGNAL nxt_diag_res : STD_LOGIC_VECTOR(diag_res'RANGE); + + SIGNAL diag_res_int : STD_LOGIC_VECTOR(diag_res'RANGE) := c_diag_res_invalid; + +BEGIN + + diag_dis <= NOT diag_en; + + gen_input_reg : IF g_input_reg=TRUE GENERATE + p_reg : PROCESS (clk) + BEGIN + IF rising_edge(clk) THEN + IF clken='1' THEN + in_val_reg <= in_val; + in_dat_reg <= in_dat; + END IF; + END IF; + END PROCESS; + END GENERATE; + no_input_reg : IF g_input_reg=FALSE GENERATE + in_val_reg <= in_val; + in_dat_reg <= in_dat; + END GENERATE; + + -- Use initialisation to set initial diag_res to invalid + diag_res <= diag_res_int; -- use initialisation of internal signal diag_res_int rather than initialisation of entity output diag_res + +-- -- Use rst to set initial diag_res to invalid +-- p_rst_clk : PROCESS (rst, clk) +-- BEGIN +-- IF rst='1' THEN +-- diag_res <= c_diag_res_invalid; +-- ELSIF rising_edge(clk) THEN +-- IF clken='1' THEN +-- -- Internal. +-- diag_res <= nxt_diag_res; +-- -- Outputs. +-- END IF; +-- END IF; +-- END PROCESS; + + p_clk : PROCESS (clk) + BEGIN + IF rising_edge(clk) THEN + IF clken='1' THEN + -- Inputs. + in_dat_dly1 <= in_dat_reg; + in_dat_dly2 <= in_dat_dly1; + in_val_dly1 <= in_val_reg; + in_val_dly2 <= in_val_dly1; + -- Internal. + in_val_2_dly <= in_val_2 & in_val_2_dly(0 TO c_diag_res_latency-2); + prsg <= nxt_prsg; + cntr <= nxt_cntr; + ref_dat <= nxt_ref_dat; + diff_dat <= nxt_diff_dat; + diag_res_int <= nxt_diag_res; + diag_res_en <= nxt_diag_res_en; + diag_res_val <= nxt_diag_res_val; + -- Outputs. + END IF; + END IF; + END PROCESS; + + ------------------------------------------------------------------------------ + -- Detect that there has been valid input data for at least two clock cycles + ------------------------------------------------------------------------------ + + u_in_val_1 : ENTITY common_lib.common_switch + PORT MAP( + clk => clk, + rst => rst, + switch_high => in_val_reg, + switch_low => diag_dis, + out_level => in_val_1 -- first in_val has been detected, but this one was used as seed for common_lfsr_nxt_seq + ); + + in_val_act <= in_val_1 AND in_val_reg; -- Signal the second valid in_dat after diag_en='1' + + u_in_val_2 : ENTITY common_lib.common_switch + PORT MAP( + clk => clk, + rst => rst, + switch_high => in_val_act, + switch_low => diag_dis, + out_level => in_val_2 -- second in_val has been detected, representing a true next sequence value + ); + + -- Use in_val_2_act instead of in_val_2 to have stable start in case diag_dis takes just a pulse and in_val is continue high + in_val_2_act <= vector_and(in_val_2 & in_val_2_dly); + + ------------------------------------------------------------------------------ + -- Compare the in_dat bus with the reference dat + ------------------------------------------------------------------------------ + + -- Use the first valid in_dat after diag_en='1' to initialize the reference data sequence + ref_en <= in_val_1; + + common_lfsr_nxt_seq(c_lfsr_nr, -- IN + ref_en, -- IN + in_val_reg, -- IN, use in_val_reg to allow gaps in the input data valid stream + in_dat_reg, -- IN + prsg, -- IN + cntr, -- IN + nxt_prsg, -- OUT + nxt_cntr); -- OUT + + nxt_ref_dat <= prsg WHEN diag_sel='0' ELSE cntr; + + -- The ref_dat has latency 2 compared to the in_dat, because of the register + -- stage in psrg/cntr and the register stage in ref_dat. + p_diff : PROCESS (diff_dat, ref_dat, in_val_dly2, in_dat_dly2) + BEGIN + nxt_diff_dat <= diff_dat; + IF in_val_dly2='1' THEN + FOR I IN in_dat'RANGE LOOP + nxt_diff_dat(I) <= ref_dat(I) XOR in_dat_dly2(I); + END LOOP; + END IF; + END PROCESS; + + + ------------------------------------------------------------------------------ + -- Hold any difference on the in_dat bus lines + ------------------------------------------------------------------------------ + + diff_dis <= NOT in_val_2_act; + + gen_verify_dat : FOR I IN in_dat'RANGE GENERATE + -- Detect and report undefined diff input 'X', which in simulation leaves diff_res at OK, because switch_high only acts on '1' + p_sim_only : PROCESS(clk) + BEGIN + IF rising_edge(clk) THEN + IF diff_dat(I)/='0' AND diff_dat(I)/='1' THEN + REPORT "diag_rx_seq : undefined input" SEVERITY FAILURE; + END IF; + END IF; + END PROCESS; + + u_dat : ENTITY common_lib.common_switch + PORT MAP( + clk => clk, + rst => rst, + switch_high => diff_dat(I), + switch_low => diff_dis, + out_level => diff_res(I) + ); + END GENERATE; + + + ------------------------------------------------------------------------------ + -- Report valid diag_res + ------------------------------------------------------------------------------ + + nxt_diag_res_en <= diag_en AND in_val_2_act; + nxt_diag_res_val <= diag_res_en; + + p_diag_res : PROCESS (diff_res, diag_res_en) + BEGIN + nxt_diag_res <= c_diag_res_invalid; + IF diag_res_en='1' THEN + -- The test runs AND there have been valid input samples to verify + nxt_diag_res <= (OTHERS=>'0'); -- MSBits of valid diag_res are 0 + nxt_diag_res(diff_res'RANGE) <= diff_res; -- diff_res of dat[] + END IF; + END PROCESS; + +END rtl; diff --git a/libraries/base/diag/src/vhdl/diag_tx_seq.vhd b/libraries/base/diag/src/vhdl/diag_tx_seq.vhd new file mode 100644 index 0000000000000000000000000000000000000000..cd084b02482166053072c4b3090c41162eebf1c5 --- /dev/null +++ b/libraries/base/diag/src/vhdl/diag_tx_seq.vhd @@ -0,0 +1,103 @@ +-------------------------------------------------------------------------------- +-- +-- 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/>. +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_lfsr_sequences_pkg.ALL; + +-- Purpose: Transmit continuous PRSG or COUNTER test sequence data. +-- Description: +-- The Tx test data can be PRSG or COUNTER dependent on diag_sel. +-- The Tx is enabled by diag_en. When the Tx is disabled then the sequence +-- gets initialised with diag_dat. +-- The out_ready acts as a data request. When the generator is enabled then +-- output is valid for every active out_ready, to support streaming flow +-- control. + +ENTITY diag_tx_seq IS + GENERIC ( + g_sel : STD_LOGIC := '1'; -- '0' = PRSG, '1' = COUNTER + g_init : NATURAL := 0; -- init value for out_dat when diag_en = '0' + g_dat_w : NATURAL -- >= 1, test data width + ); + PORT ( + rst : IN STD_LOGIC; + clk : IN STD_LOGIC; + clken : IN STD_LOGIC := '1'; + -- Static control input (connect via MM or leave open to use default) + diag_en : IN STD_LOGIC; -- '0' = init and disable output sequence, '1' = enable output sequence + diag_sel : IN STD_LOGIC := g_sel; + diag_dat : IN STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0) := TO_UVEC(g_init, g_dat_w); -- init value for out_dat when diag_en = '0' + -- ST output + diag_req : IN STD_LOGIC := '1'; -- '1' = request output, '0' = halt output + out_dat : OUT STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0); -- test sequence data + out_val : OUT STD_LOGIC -- '1' when out_dat is valid + ); +END diag_tx_seq; + + +ARCHITECTURE rtl OF diag_tx_seq IS + + CONSTANT c_lfsr_nr : NATURAL := g_dat_w - c_common_lfsr_first; + + SIGNAL prsg : STD_LOGIC_VECTOR(out_dat'RANGE); + SIGNAL nxt_prsg : STD_LOGIC_VECTOR(out_dat'RANGE); + SIGNAL cntr : STD_LOGIC_VECTOR(out_dat'RANGE); + SIGNAL nxt_cntr : STD_LOGIC_VECTOR(out_dat'RANGE); + + SIGNAL nxt_out_dat : STD_LOGIC_VECTOR(out_dat'RANGE); + SIGNAL nxt_out_val : STD_LOGIC; + +BEGIN + + p_clk : PROCESS (rst, clk) + BEGIN + IF rst='1' THEN + prsg <= (OTHERS=>'0'); + cntr <= (OTHERS=>'0'); + out_dat <= (OTHERS=>'0'); + out_val <= '0'; + ELSIF rising_edge(clk) THEN + IF clken='1' THEN + prsg <= nxt_prsg; + cntr <= nxt_cntr; + out_dat <= nxt_out_dat; + out_val <= nxt_out_val; + END IF; + END IF; + END PROCESS; + + common_lfsr_nxt_seq(c_lfsr_nr, -- IN + diag_en, -- IN + diag_req, -- IN + diag_dat, -- IN + prsg, -- IN + cntr, -- IN + nxt_prsg, -- OUT + nxt_cntr); -- OUT + + nxt_out_dat <= prsg WHEN diag_sel='0' ELSE cntr; + nxt_out_val <= diag_en AND diag_req; -- 'en' for entire test on/off, 'req' for dynamic invalid gaps in the stream + +END rtl;