Skip to content
Snippets Groups Projects
Commit fc239c53 authored by Eric Kooistra's avatar Eric Kooistra
Browse files

Ported diag_tx/rx_seq.vhd to RadioHDL.

parent fe531fa0
No related branches found
No related tags found
No related merge requests found
...@@ -8,9 +8,9 @@ build_dir_synth = $HDL_BUILD_DIR ...@@ -8,9 +8,9 @@ build_dir_synth = $HDL_BUILD_DIR
synth_files = synth_files =
$UNB/Firmware/modules/Lofar/diag/src/vhdl/diag_bypass.vhd $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_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_generator.vhd
$UNB/Firmware/modules/Lofar/diag/src/vhdl/diag_frm_monitor.vhd $UNB/Firmware/modules/Lofar/diag/src/vhdl/diag_frm_monitor.vhd
src/vhdl/mms_diag_tx_seq.vhd src/vhdl/mms_diag_tx_seq.vhd
......
--------------------------------------------------------------------------------
--
-- 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;
--------------------------------------------------------------------------------
--
-- 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;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment