diff --git a/libraries/base/diag/hdllib.cfg b/libraries/base/diag/hdllib.cfg index 9d2908c37881c121f32ace35a24ee7dba4391efc..10d51293521cf0bbf384b5461308ba2af5a3719a 100644 --- a/libraries/base/diag/hdllib.cfg +++ b/libraries/base/diag/hdllib.cfg @@ -14,7 +14,7 @@ synth_files = src/vhdl/diag_tx_seq.vhd $UNB/Firmware/modules/Lofar/diag/src/vhdl/diag_tx_frm.vhd src/vhdl/diag_rx_seq.vhd - $UNB/Firmware/modules/Lofar/diag/src/vhdl/diag_frm_generator.vhd + src/vhdl/diag_frm_generator.vhd $UNB/Firmware/modules/Lofar/diag/src/vhdl/diag_frm_monitor.vhd src/vhdl/mms_diag_tx_seq.vhd src/vhdl/mms_diag_rx_seq.vhd diff --git a/libraries/base/diag/src/vhdl/diag_frm_generator.vhd b/libraries/base/diag/src/vhdl/diag_frm_generator.vhd new file mode 100644 index 0000000000000000000000000000000000000000..e334b8f244d13e69753b84ce0f5f252ae8d7c582 --- /dev/null +++ b/libraries/base/diag/src/vhdl/diag_frm_generator.vhd @@ -0,0 +1,187 @@ +-------------------------------------------------------------------------------- +-- +-- 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; + + +-- Purpose: Generate a stream of frames with test sequence data. +-- Description: +-- Each frame has g_frame_len words of out_dat. The test data can be PRSG or +-- COUNTER dependent on diag_sel. +-- The frame generator is enabled by diag_en. The actual frame rate depends +-- on the g_sop_period and on out_ready. +-- The out_ready acts as a data request. During a frame the out_dat is valid +-- for every active out_ready, to support streaming flow control. +-- Remark: +-- . This component can be easily mapped to standard MM and ST interfaces. + + +ENTITY diag_frm_generator IS + GENERIC ( + g_sel : STD_LOGIC := '1'; -- '0' = PRSG, '1' = COUNTER + g_frame_len : NATURAL := 2; -- >= 2, test frame length in nof dat words + g_sof_period : NATURAL := 1; -- >= 1, nof cycles between sop that start a frame, typically >> g_frame_len + -- to generate frames with idle in between + g_frame_cnt_w : NATURAL := 32; + g_dat_w : NATURAL := 16; -- >= 1, test data width + g_symbol_w : NATURAL := 16; -- >= 1, and nof_symbols_per_dat = g_dat_w/g_symbol_w, must be an integer + g_empty : NATURAL := 0 -- >= 0 and < nof symbols per dat, + ); + 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; + diag_sel : IN STD_LOGIC := g_sel; + diag_frame_len : IN STD_LOGIC_VECTOR(ceil_log2(g_frame_len)-1 DOWNTO 0) := TO_UVEC(g_frame_len, ceil_log2(g_frame_len)); + diag_frame_empty : IN STD_LOGIC_VECTOR(ceil_log2(g_dat_w/g_symbol_w)-1 DOWNTO 0) := TO_UVEC(g_empty, ceil_log2(g_dat_w/g_symbol_w)); + diag_sof_period : IN STD_LOGIC_VECTOR(ceil_log2(g_sof_period)-1 DOWNTO 0) := TO_UVEC(g_sof_period, ceil_log2(g_sof_period)); + diag_frame_cnt : OUT STD_LOGIC_VECTOR(g_frame_cnt_w-1 DOWNTO 0); + + -- ST output + out_ready : IN STD_LOGIC := '1'; -- '1' = request ST test data output, '0' = halt ST test data output + out_dat : OUT STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0); -- test sequence data + out_val : OUT STD_LOGIC; -- '1' when out_data is valid + out_sop : OUT STD_LOGIC; -- '1' for first valid frame data + out_eop : OUT STD_LOGIC; -- '1' for last valid frame data + out_empty : OUT STD_LOGIC_VECTOR(ceil_log2(g_dat_w/g_symbol_w)-1 DOWNTO 0) -- nof empty symbols in last out_dat word marked by out_eop + ); +END diag_frm_generator; + + +ARCHITECTURE str OF diag_frm_generator IS + + CONSTANT c_init : NATURAL := 0; -- first data word of first frame that is generated after diag_en = '1' + CONSTANT c_frame_len_w : NATURAL := ceil_log2(g_frame_len); + + SIGNAL diag_en_revt : STD_LOGIC; + SIGNAL diag_dat : STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0) := TO_UVEC(c_init, g_dat_w); -- init data for out_dat when diag_sop = '1' + SIGNAL nxt_diag_dat : STD_LOGIC_VECTOR(diag_dat'RANGE); + SIGNAL diag_sop : STD_LOGIC; + SIGNAL diag_ready : STD_LOGIC; + + SIGNAL frame_cnt : STD_LOGIC_VECTOR(diag_frame_cnt'RANGE); + SIGNAL nxt_diag_frame_cnt : STD_LOGIC_VECTOR(diag_frame_cnt'RANGE); + + SIGNAL i_out_sop : STD_LOGIC; + SIGNAL i_out_eop : STD_LOGIC; + +BEGIN + + out_sop <= i_out_sop; + out_eop <= i_out_eop; + out_empty <= diag_frame_empty; + + -- Signal begin of diag_en + u_diag_en_revt : ENTITY common_lib.common_evt + GENERIC MAP ( + g_evt_type => "RISING", + g_out_reg => FALSE + ) + PORT MAP ( + rst => rst, + clk => clk, + clken => clken, + in_sig => diag_en, + out_evt => diag_en_revt + ); + + p_clk : PROCESS (rst, clk) + BEGIN + IF rst='1' THEN + diag_dat <= TO_UVEC(c_init, g_dat_w); + diag_frame_cnt <= (OTHERS=>'0'); + ELSIF rising_edge(clk) THEN + IF clken='1' THEN + diag_dat <= nxt_diag_dat; + diag_frame_cnt <= nxt_diag_frame_cnt; + END IF; + END IF; + END PROCESS; + + nxt_diag_dat <= TO_UVEC(c_init, g_dat_w) WHEN diag_en='0' ELSE INCR_UVEC(diag_dat, 1) WHEN i_out_sop='1'; + + u_pulse_sop : ENTITY common_lib.common_pulser + GENERIC MAP ( + g_pulse_period => g_sof_period + ) + PORT MAP ( + rst => rst, + clk => clk, + clken => clken, + pulse_period => diag_sof_period, + pulse_en => diag_en, + pulse_clr => diag_en_revt, + pulse_out => diag_sop + ); + + -- Hold last frame count also when the generator is disabled, clear when it is restarted + nxt_diag_frame_cnt <= (OTHERS=>'0') WHEN diag_en_revt='1' ELSE frame_cnt; + + u_frm_cnt : ENTITY common_lib.common_counter + GENERIC MAP ( + g_width => g_frame_cnt_w + ) + PORT MAP ( + rst => rst, + clk => clk, + clken => clken, + cnt_clr => diag_en_revt, + cnt_en => i_out_eop, + count => frame_cnt + ); + + u_tx_frm : ENTITY work.diag_tx_frm + GENERIC MAP ( + g_sel => g_sel, + g_init => c_init, + g_frame_len => g_frame_len, + g_dat_w => g_dat_w + ) + PORT MAP ( + rst => rst, + clk => clk, + clken => clken, + + -- Static control input (connect via MM or leave open to use default) + diag_sel => diag_sel, + diag_frame_len => diag_frame_len, + + -- Dynamic control input (connect via MM or via ST input or leave open to use defaults) + diag_ready => diag_ready, + diag_dat => diag_dat, + diag_sop => diag_sop, + + -- ST output + out_ready => out_ready, + out_dat => out_dat, + out_val => out_val, + out_sop => i_out_sop, + out_eop => i_out_eop + ); + +END str; diff --git a/libraries/base/diag/src/vhdl/diag_tx_frm.vhd b/libraries/base/diag/src/vhdl/diag_tx_frm.vhd new file mode 100644 index 0000000000000000000000000000000000000000..f5cc14a13f5868e597327bff50c59c81afa882ed --- /dev/null +++ b/libraries/base/diag/src/vhdl/diag_tx_frm.vhd @@ -0,0 +1,172 @@ +-------------------------------------------------------------------------------- +-- +-- 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 a frame with PRSG or COUNTER test sequence data. +-- Description: +-- The test data can be PRSG or COUNTER dependent on diag_sel. +-- A frame generation is enabled (started) by diag_sop. It does not need +-- diag_eop to end the frame generation, because the generator ends itself +-- when it has generated g_frame_len words of out_dat. +-- After a test frame has finished then diag_ready with RL=0 is active to +-- indicate that a new diag_sof can be handled. The next frame will then +-- immediatly follow the previous frame, so out_sop of new frame direct after +-- out_eop of previous frame, if allowed by out_ready from the sink. +-- It is allowed to keep diag_sop continue high or to make diag_sop = +-- diag_ready, both will result in maximum frame rate. +-- The out_ready acts as a data request. During a frame the out_dat is valid +-- for every active out_ready, to support streaming flow control. +-- Remark: +-- . This component can be easily mapped to standard MM and ST interfaces. + + +ENTITY diag_tx_frm IS + GENERIC ( + g_sel : STD_LOGIC := '1'; -- '0' = PRSG, '1' = COUNTER + g_init : NATURAL := 0; -- default test sequence init value + g_frame_len : NATURAL := 2; -- >= 2, test frame length + g_dat_w : NATURAL := 16 -- >= 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_sel : IN STD_LOGIC := g_sel; + diag_frame_len : IN STD_LOGIC_VECTOR(ceil_log2(g_frame_len)-1 DOWNTO 0) := TO_UVEC(g_frame_len, ceil_log2(g_frame_len)); + + -- Dynamic control input (connect via MM or via ST input or leave open to use defaults) + diag_ready : OUT STD_LOGIC; -- '1' when the generator can accept a new diag_sop + diag_dat : IN STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0) := TO_UVEC(g_init, g_dat_w); -- init data for out_dat when diag_sop = '1' + diag_sop : IN STD_LOGIC := '1'; -- '1' start a frame generation + + -- ST output + out_ready : IN STD_LOGIC := '1'; -- '1' = request ST test data output, '0' = halt ST test data output + out_dat : OUT STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0); -- test sequence data + out_val : OUT STD_LOGIC; -- '1' when out_data is valid + out_sop : OUT STD_LOGIC; -- '1' for first valid frame data + out_eop : OUT STD_LOGIC -- '1' for last valid frame data + ); +END diag_tx_frm; + + +ARCHITECTURE rtl OF diag_tx_frm IS + + CONSTANT c_lfsr_nr : NATURAL := g_dat_w - c_common_lfsr_first; + + SIGNAL i_diag_ready : STD_LOGIC; + + SIGNAL frm_sop : STD_LOGIC; + SIGNAL frm_busy : STD_LOGIC; + SIGNAL nxt_frm_busy : STD_LOGIC; + + SIGNAL diag_en : STD_LOGIC; + + SIGNAL cnt : STD_LOGIC_VECTOR(diag_frame_len'RANGE); + SIGNAL cnt_clr : STD_LOGIC; + SIGNAL cnt_en : STD_LOGIC; + SIGNAL cnt_done : STD_LOGIC; + + SIGNAL nxt_out_val : STD_LOGIC; + SIGNAL nxt_out_sop : STD_LOGIC; + SIGNAL nxt_out_eop : STD_LOGIC; + +BEGIN + + diag_ready <= i_diag_ready; + + p_clk : PROCESS (rst, clk) + BEGIN + IF rst='1' THEN + frm_busy <= '0'; + out_val <= '0'; + out_sop <= '0'; + out_eop <= '0'; + ELSIF rising_edge(clk) THEN + IF clken='1' THEN + frm_busy <= nxt_frm_busy; + out_val <= nxt_out_val; + out_sop <= nxt_out_sop; + out_eop <= nxt_out_eop; + END IF; + END IF; + END PROCESS; + + i_diag_ready <= NOT diag_en; + + -- Use frm_sop to support diag_sop pulse for frame rate control and also + -- diag_sop continue high for maximum frame rate. + frm_sop <= i_diag_ready AND diag_sop; + + nxt_frm_busy <= '1' WHEN frm_sop = '1' ELSE + '0' WHEN cnt_done = '1' ELSE frm_busy; + + cnt_clr <= frm_sop; + cnt_en <= '1' WHEN frm_busy='1' AND out_ready='1' AND UNSIGNED(cnt)<=g_frame_len-1 ELSE '0'; + cnt_done <= '1' WHEN frm_busy='1' AND out_ready='1' AND UNSIGNED(cnt) =g_frame_len-1 ELSE '0'; + + -- Distinguish between frm_busy and diag_en to be able to generated frames + -- that are output without idle cycles in between. The diag_en therefore + -- make uses of the feature of diag_tx_seq that the next sequence data is + -- already available at its output when out_val is still '0'. + diag_en <= frm_busy AND NOT cnt_done; + + nxt_out_val <= cnt_en; + nxt_out_sop <= '1' WHEN frm_busy='1' AND out_ready='1' AND UNSIGNED(cnt) =0 ELSE '0'; + nxt_out_eop <= cnt_done; + + u_cnt_len : ENTITY common_lib.common_counter + GENERIC MAP ( + g_width => diag_frame_len'LENGTH + ) + PORT MAP ( + rst => rst, + clk => clk, + clken => clken, + cnt_clr => cnt_clr, + cnt_en => cnt_en, + count => cnt + ); + + u_frame_dat : ENTITY work.diag_tx_seq + GENERIC MAP ( + g_dat_w => g_dat_w + ) + PORT MAP ( + rst => rst, + clk => clk, + clken => clken, + diag_en => diag_en, + diag_sel => diag_sel, + diag_dat => diag_dat, + diag_req => out_ready, + out_dat => out_dat, + out_val => OPEN + ); + +END rtl;