Skip to content
Snippets Groups Projects
Commit 39ce6939 authored by Daniel van der Schuur's avatar Daniel van der Schuur
Browse files

-Added dp_folder, dp_unfolder, tb_dp_folder

-Added dp_switch + tb_dp_switch
-Added functions func_dp_stream_concat and func_dp_stream_deconcat to
 dp_stream_pkg.
parent 4f088081
No related branches found
No related tags found
No related merge requests found
......@@ -124,6 +124,9 @@ synth_files =
src/vhdl/dp_src_out_timer.vhd
src/vhdl/dp_sync_checker.vhd
src/vhdl/mms_dp_sync_checker.vhd
src/vhdl/dp_folder.vhd
src/vhdl/dp_unfolder.vhd
src/vhdl/dp_switch.vhd
tb/vhdl/dp_stream_player.vhd
tb/vhdl/dp_sosi_recorder.vhd
tb/vhdl/dp_stream_rec_play.vhd
......@@ -187,6 +190,9 @@ test_bench_files =
tb/vhdl/tb_dp_xonoff.vhd
tb/vhdl/tb_mms_dp_xonoff.vhd
tb/vhdl/tb_dp_sync_insert.vhd
tb/vhdl/tb_dp_folder.vhd
tb/vhdl/tb_dp_switch.vhd
tb/vhdl/tb_tb_dp_block_gen.vhd
tb/vhdl/tb_tb_dp_bsn_align.vhd
......
--------------------------------------------------------------------------------
--
-- Copyright (C) 2016
-- 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 dp_lib.dp_stream_pkg.ALL;
-- Author:
-- . Daniel van der Schuur
-- Purpose:
-- . Fold n input streams into n/2, n/2/2, n/2/2/2, .. output streams
-- Description:
-- . This component assumes the user has scheduled the input streams properly.
-- . Input data that is to be folded onto one stream must not be valid at the same clock cycle
-- . nof_outputs = ceil_div(g_nof_inputs, 2^(g_nof_folds)) for g_nof_folds>=0
-- . Examples:
-- . g_nof_inputs=10, g_nof_folds=0 -> nof_outputs=10
-- . g_nof_inputs=10, g_nof_folds=1 -> nof_outputs= 5
-- . g_nof_inputs=10, g_nof_folds=2 -> nof_outputs= 3
-- . g_nof_inputs=10, g_nof_folds=3 -> nof_outputs= 2
-- . g_nof_inputs=10, g_nof_folds=4 -> nof_outputs= 1
-- . g_nof_inputs=10, g_nof_folds<0 -> nof_outputs= 1
-- . This entity recursively instantiates (registered) stages of itself when folding streams multiple times.
ENTITY dp_folder IS
GENERIC (
g_nof_inputs : NATURAL; -- Number of inputs to fold >0
g_nof_folds : INTEGER := -1; -- >0: Number of folds; 0: Wire out to in; <0: Fold until one output remains
g_output_block_size : NATURAL := 0; -- >0: Create SOP/EOP tagged output blocks of this size. 0: Forward incoming SOP,EOP.
g_fwd_sync_bsn : BOOLEAN := FALSE -- TRUE: forwards (stored) input Sync+BSN (from snk_in_arr(0)) to all output streams
);
PORT (
clk : IN STD_LOGIC;
rst : IN STD_LOGIC;
snk_in_arr : IN t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0);
src_out_arr : OUT t_dp_sosi_arr(sel_a_b(g_nof_folds>=0, ceil_div(g_nof_inputs, ceil_pow2(g_nof_folds)), 1)-1 DOWNTO 0)
);
END dp_folder;
ARCHITECTURE str OF dp_folder IS
COMPONENT dp_folder IS
GENERIC (
g_nof_inputs : NATURAL;
g_nof_folds : INTEGER := -1;
g_output_block_size : NATURAL := 0;
g_fwd_sync_bsn : BOOLEAN := FALSE
);
PORT (
rst : IN STD_LOGIC;
clk : IN STD_LOGIC;
snk_in_arr : IN t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0);
src_out_arr : OUT t_dp_sosi_arr(sel_a_b(g_nof_folds>=0, ceil_div(g_nof_inputs, ceil_pow2(g_nof_folds)), 1)-1 DOWNTO 0)
);
END COMPONENT;
CONSTANT c_nof_muxes : NATURAL := ceil_div(g_nof_inputs, 2); -- Using ceil_div always yields an even number of mux inputs
SIGNAL mux_snk_in_arr : t_dp_sosi_arr(2*c_nof_muxes-1 DOWNTO 0);
SIGNAL mux_snk_in_2arr_2 : t_dp_sosi_2arr_2(c_nof_muxes-1 DOWNTO 0);
SIGNAL mux_src_out_arr : t_dp_sosi_arr(c_nof_muxes-1 DOWNTO 0);
SIGNAL nxt_mux_src_out_arr : t_dp_sosi_arr(c_nof_muxes-1 DOWNTO 0);
SIGNAL dp_folder_src_out_arr : t_dp_sosi_arr(sel_a_b(g_nof_folds>=0, ceil_div(g_nof_inputs, ceil_pow2(g_nof_folds)), 1)-1 DOWNTO 0);
SIGNAL dp_block_gen_snk_in_arr : t_dp_sosi_arr(sel_a_b(g_nof_folds>=0, ceil_div(g_nof_inputs, ceil_pow2(g_nof_folds)), 1)-1 DOWNTO 0);
SIGNAL dp_block_gen_src_out_arr : t_dp_sosi_arr(sel_a_b(g_nof_folds>=0, ceil_div(g_nof_inputs, ceil_pow2(g_nof_folds)), 1)-1 DOWNTO 0);
BEGIN
gen_arch: IF g_nof_folds/=0 GENERATE
-----------------------------------------------------------------------------
-- Wire input array to mux_snk_in_arr to make sure we have an even number
-- of buses to work with in case of an odd number of inputs
-- . We want an even number of buses because we will wire up 2-input muxes
-----------------------------------------------------------------------------
gen_even_nof_buses: FOR i IN 0 TO g_nof_inputs-1 GENERATE
mux_snk_in_arr(i) <= snk_in_arr(i);
END GENERATE;
-----------------------------------------------------------------------------
-- Wire inputs to the 2-input muxes
-----------------------------------------------------------------------------
gen_mux_inputs_0: FOR i IN 0 TO c_nof_muxes-1 GENERATE
mux_snk_in_2arr_2(i)(0) <= mux_snk_in_arr(2*i);
mux_snk_in_2arr_2(i)(1) <= mux_snk_in_arr(2*i+1);
END GENERATE;
-----------------------------------------------------------------------------
-- Simple 2-input mux logic
-----------------------------------------------------------------------------
p_mux : PROCESS(mux_snk_in_2arr_2)
BEGIN
FOR i IN 0 TO c_nof_muxes-1 LOOP
nxt_mux_src_out_arr(i) <= c_dp_sosi_rst;
IF mux_snk_in_2arr_2(i)(0).valid='1' THEN
nxt_mux_src_out_arr(i).data <= mux_snk_in_2arr_2(i)(0).data;
nxt_mux_src_out_arr(i).re <= mux_snk_in_2arr_2(i)(0).re;
nxt_mux_src_out_arr(i).im <= mux_snk_in_2arr_2(i)(0).im;
nxt_mux_src_out_arr(i).valid <= '1';
ELSIF mux_snk_in_2arr_2(i)(1).valid='1' THEN
nxt_mux_src_out_arr(i).data <= mux_snk_in_2arr_2(i)(1).data;
nxt_mux_src_out_arr(i).re <= mux_snk_in_2arr_2(i)(1).re;
nxt_mux_src_out_arr(i).im <= mux_snk_in_2arr_2(i)(1).im;
nxt_mux_src_out_arr(i).valid <= '1';
END IF;
END LOOP;
END PROCESS;
-- Registers
p_clk: PROCESS(clk, rst)
BEGIN
IF rst='1' THEN
mux_src_out_arr <= (OTHERS=>c_dp_sosi_rst);
ELSIF rising_edge(clk) THEN
mux_src_out_arr <= nxt_mux_src_out_arr;
END IF;
END PROCESS;
-----------------------------------------------------------------------------
-- Not done folding; add a stage.
-- . g_nof_folds <0 : user wants to fold all the way to one output
-- . g_nof_folds >0 : user wants to fold n times
-----------------------------------------------------------------------------
gen_dp_folder: IF (g_nof_folds<0 AND c_nof_muxes>1) OR g_nof_folds>1 GENERATE
u_dp_folder : dp_folder
GENERIC MAP (
g_nof_inputs => c_nof_muxes,
g_nof_folds => g_nof_folds-1,
g_output_block_size => g_output_block_size,
g_fwd_sync_bsn => g_fwd_sync_bsn
)
PORT MAP (
rst => rst,
clk => clk,
snk_in_arr => mux_src_out_arr,
src_out_arr => dp_folder_src_out_arr
);
src_out_arr <= dp_folder_src_out_arr;
END GENERATE;
-----------------------------------------------------------------------------
-- c_nof_muxes=1 or g_nof_folds=1, so this is the last stage.
-----------------------------------------------------------------------------
gen_src_out_arr: IF (g_nof_folds<0 AND c_nof_muxes=1) OR g_nof_folds=1 GENERATE
dp_block_gen_snk_in_arr <= mux_src_out_arr;
-----------------------------------------------------------------------------
-- Add SOP and EOP to the outputs
-----------------------------------------------------------------------------
gen_ctrl : IF g_output_block_size>0 GENERATE
gen_dp_block_gen : FOR i IN 0 TO c_nof_muxes-1 GENERATE
u_dp_block_gen : ENTITY work.dp_block_gen
GENERIC MAP (
g_use_src_in => FALSE,
g_nof_data => g_output_block_size,
g_preserve_sync => TRUE,
g_preserve_bsn => TRUE
)
PORT MAP(
rst => rst,
clk => clk,
snk_in => dp_block_gen_snk_in_arr(i),
src_out => dp_block_gen_src_out_arr(i)
);
END GENERATE;
END GENERATE;
no_ctrl : IF g_output_block_size=0 GENERATE
dp_block_gen_src_out_arr <= dp_block_gen_snk_in_arr;
END GENERATE;
-----------------------------------------------------------------------------
-- Re-add input sync + BSN to all output streams
-----------------------------------------------------------------------------
gen_sync_bsn : IF g_fwd_sync_bsn = TRUE GENERATE
gen_dp_fifo_info: FOR i IN 0 TO c_nof_muxes-1 GENERATE
u_dp_fifo_info : ENTITY work.dp_fifo_info
GENERIC MAP (
g_use_sync => TRUE,
g_use_bsn => TRUE
)
PORT MAP (
rst => rst,
clk => clk,
data_snk_in => dp_block_gen_src_out_arr(i), -- delayed snk_in data
info_snk_in => snk_in_arr(0), -- original snk_in info
src_in => c_dp_siso_rdy,
src_out => src_out_arr(i)
);
END GENERATE;
END GENERATE;
no_sync_bsn : IF g_fwd_sync_bsn = FALSE GENERATE
src_out_arr <= dp_block_gen_src_out_arr;
END GENERATE;
END GENERATE;
END GENERATE;
-----------------------------------------------------------------------------
-- Wire output to input if g_nof_folds=0
-----------------------------------------------------------------------------
gen_wire_out_to_in: IF g_nof_folds=0 GENERATE
dp_block_gen_snk_in_arr <= snk_in_arr;
END GENERATE;
END str;
......@@ -329,6 +329,12 @@ PACKAGE dp_stream_pkg Is
FUNCTION func_dp_stream_set_data(dp : t_dp_sosi_arr; slv : STD_LOGIC_VECTOR; str : STRING ) RETURN t_dp_sosi_arr;
FUNCTION func_dp_stream_set_data(dp : t_dp_sosi_arr; slv : STD_LOGIC_VECTOR; str : STRING; mask : STD_LOGIC_VECTOR) RETURN t_dp_sosi_arr;
-- Concatenate the data from a SOSI array into a single SOSI stream (assumes streams are in sync)
FUNCTION func_dp_stream_concat(snk_in_arr : t_dp_sosi_arr; data_w : NATURAL) RETURN t_dp_sosi; -- Concat SOSI_ARR data into single SOSI
FUNCTION func_dp_stream_concat(src_in : t_dp_siso; nof_streams : NATURAL) RETURN t_dp_siso_arr; -- Wire single SISO to SISO_ARR
-- Deconcatenate data from SOSI into SOSI array
FUNCTION func_dp_stream_deconcat(snk_in : t_dp_sosi; nof_streams, data_w : NATURAL) RETURN t_dp_sosi_arr; -- Deconcat SOSI data
FUNCTION func_dp_stream_deconcat(src_out_arr : t_dp_siso_arr) RETURN t_dp_siso; -- Wire SISO_ARR(0) to single SISO
END dp_stream_pkg;
......@@ -1150,5 +1156,46 @@ PACKAGE BODY dp_stream_pkg IS
RETURN v_dp;
END;
-- Concatenate the data (and complex fields) from a SOSI array into a single SOSI stream (assumes streams are in sync)
FUNCTION func_dp_stream_concat(snk_in_arr : t_dp_sosi_arr; data_w : NATURAL) RETURN t_dp_sosi IS
VARIABLE v_src_out : t_dp_sosi := snk_in_arr(0);
VARIABLE v_compl_data_w : NATURAL := data_w/2;
BEGIN
FOR i IN snk_in_arr'RANGE LOOP
v_src_out.data((i+1)* data_w-1 DOWNTO i* data_w) := snk_in_arr(i).data( data_w-1 DOWNTO 0);
v_src_out.re( (i+1)*v_compl_data_w-1 DOWNTO i*v_compl_data_w) := snk_in_arr(i).re(v_compl_data_w-1 DOWNTO 0);
v_src_out.im( (i+1)*v_compl_data_w-1 DOWNTO i*v_compl_data_w) := snk_in_arr(i).im(v_compl_data_w-1 DOWNTO 0);
END LOOP;
RETURN v_src_out;
END;
FUNCTION func_dp_stream_concat(src_in : t_dp_siso; nof_streams : NATURAL) RETURN t_dp_siso_arr IS -- Wire single SISO to SISO_ARR
VARIABLE v_snk_out_arr : t_dp_siso_arr(nof_streams-1 DOWNTO 0);
BEGIN
FOR i IN v_snk_out_arr'RANGE LOOP
v_snk_out_arr(i) := src_in;
END LOOP;
RETURN v_snk_out_arr;
END;
-- Deconcatenate data from SOSI into SOSI array
FUNCTION func_dp_stream_deconcat(snk_in : t_dp_sosi; nof_streams, data_w : NATURAL) RETURN t_dp_sosi_arr IS
VARIABLE v_src_out_arr : t_dp_sosi_arr(nof_streams-1 DOWNTO 0);
VARIABLE v_compl_data_w : NATURAL := data_w/2;
BEGIN
FOR i IN v_src_out_arr'RANGE LOOP
v_src_out_arr(i) := snk_in;
v_src_out_arr(i).data( data_w-1 DOWNTO 0) := snk_in.data((i+1)* data_w-1 DOWNTO i* data_w);
v_src_out_arr(i).re( v_compl_data_w-1 DOWNTO 0) := snk_in.re ((i+1)*v_compl_data_w-1 DOWNTO i*v_compl_data_w);
v_src_out_arr(i).im( v_compl_data_w-1 DOWNTO 0) := snk_in.im ((i+1)*v_compl_data_w-1 DOWNTO i*v_compl_data_w);
END LOOP;
RETURN v_src_out_arr;
END;
FUNCTION func_dp_stream_deconcat(src_out_arr : t_dp_siso_arr) RETURN t_dp_siso IS -- Wire SISO_ARR(0) to single SISO
BEGIN
RETURN src_out_arr(0);
END;
END dp_stream_pkg;
-------------------------------------------------------------------------------
--
-- Copyright (C) 2016
-- 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/>.
--
-------------------------------------------------------------------------------
-- Author:
-- . Daniel van der Schuur
-- Purpose:
-- . Switch one of g_nof_inputs input streams to the output.
-- Description:
-- . Respects frame boundaries (SOP..EOP).
-- . This is basically an MM-controlled dp_mux (with g_mode=4).
-- . There is always one input enabled. If undesired, add your own input and
-- assign c_dp_sosi_rst to it. Switching to that input will disable the output.
-- Remark:
-- . dp_mux requires a minimum invaled gap of 1 cycle to switch to a new input!
-- . So this does not work for continuous streams!
LIBRARY IEEE, common_lib, mm_lib;
USE IEEE.std_logic_1164.ALL;
USE common_lib.common_pkg.ALL;
USE common_lib.common_mem_pkg.ALL;
USE common_lib.common_field_pkg.ALL;
USE work.dp_stream_pkg.ALL;
ENTITY dp_switch IS
GENERIC (
g_nof_inputs : NATURAL; -- Number of inputs
g_default_enabled : NATURAL := 0; -- This input number 0..g_nof_inputs-1 will be enabled by default
g_use_fifo : BOOLEAN := FALSE; -- This and the generics below are forwarded to dp_mux only
g_bsn_w : NATURAL := 16;
g_data_w : NATURAL := 16;
g_empty_w : NATURAL := 1;
g_in_channel_w : NATURAL := 1;
g_error_w : NATURAL := 1;
g_use_bsn : BOOLEAN := FALSE;
g_use_empty : BOOLEAN := FALSE;
g_use_in_channel : BOOLEAN := FALSE;
g_use_error : BOOLEAN := FALSE;
g_use_sync : BOOLEAN := FALSE;
g_fifo_af_margin : NATURAL := 4; -- Nof words below max (full) at which fifo is considered almost full
g_fifo_size : NATURAL := 1024;
g_fifo_fill : NATURAL := 0
);
PORT (
dp_clk : IN STD_LOGIC;
dp_rst : IN STD_LOGIC;
mm_clk : IN STD_LOGIC;
mm_rst : IN STD_LOGIC;
snk_in_arr : IN t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0);
src_out : OUT t_dp_sosi;
reg_mosi : IN t_mem_mosi;
reg_miso : OUT t_mem_miso
);
END dp_switch;
ARCHITECTURE str OF dp_switch IS
CONSTANT c_field_arr : t_common_field_arr(0 DOWNTO 0) := (0=> ( field_name_pad("input_select"), "RW", ceil_log2(g_nof_inputs), field_default(g_default_enabled) ));
SIGNAL mm_fields_out : STD_LOGIC_VECTOR(field_slv_out_len(c_field_arr)-1 DOWNTO 0);
SIGNAL dp_mux_sel_ctrl_req : NATURAL;
SIGNAL dp_mux_sel_ctrl : NATURAL;
BEGIN
------------------------------------------------------------------------------
-- A single MM register contains input to select
------------------------------------------------------------------------------
u_mm_fields: ENTITY mm_lib.mm_fields
GENERIC MAP(
g_field_arr => c_field_arr
)
PORT MAP (
mm_clk => mm_clk,
mm_rst => mm_rst,
mm_mosi => reg_mosi,
mm_miso => reg_miso,
slv_clk => dp_clk,
slv_rst => dp_rst,
slv_out => mm_fields_out
);
------------------------------------------------------------------------------
-- Don't allow user to select a non-existent input
-- . If user requests non-existent input, the default input is forwarded instead.
------------------------------------------------------------------------------
dp_mux_sel_ctrl_req <= TO_UINT(mm_fields_out(field_hi(c_field_arr, "input_select") DOWNTO field_lo(c_field_arr, "input_select")));
dp_mux_sel_ctrl <= dp_mux_sel_ctrl_req WHEN dp_mux_sel_ctrl_req<g_nof_inputs ELSE g_default_enabled;
------------------------------------------------------------------------------
-- DP mux forwards input based on dp_mux_sel_ctrl
------------------------------------------------------------------------------
u_dp_mux : ENTITY work.dp_mux
GENERIC MAP (
g_mode => 4, -- Use sel_ctrl
g_sel_ctrl_invert => TRUE, -- Invert the control as we're using DOWNTO ranged sosi_arrays.
g_nof_input => g_nof_inputs,
g_use_fifo => g_use_fifo,
g_bsn_w => g_bsn_w,
g_data_w => g_data_w,
g_empty_w => g_empty_w,
g_in_channel_w => g_in_channel_w,
g_error_w => g_error_w,
g_use_bsn => g_use_bsn,
g_use_empty => g_use_empty,
g_use_in_channel => g_use_in_channel,
g_use_error => g_use_error,
g_use_sync => g_use_sync,
g_fifo_af_margin => g_fifo_af_margin,
g_fifo_size => array_init(g_fifo_size, g_nof_inputs),
g_fifo_fill => array_init(g_fifo_fill, g_nof_inputs)
)
PORT MAP (
clk => dp_clk,
rst => dp_rst,
sel_ctrl => dp_mux_sel_ctrl,
snk_in_arr => snk_in_arr,
src_out => src_out,
src_in => c_dp_siso_rdy
);
END str;
--------------------------------------------------------------------------------
--
-- Copyright (C) 2016
-- 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 dp_lib.dp_stream_pkg.ALL;
-- Author:
-- . Daniel van der Schuur
-- Purpose:
-- . Unfold n input streams into n*2, n*2*2, n*2*2*2, .. output streams
-- Description:
-- . Reversed operation of dp_folder.
ENTITY dp_unfolder IS
GENERIC (
g_nof_inputs : NATURAL; -- Number of inputs
g_nof_unfolds : NATURAL := 0; -- Number of times to unfold
g_output_block_size : NATURAL := 0; -- >0: Create SOP/EOP tagged output blocks of this size.
g_fwd_sync_bsn : BOOLEAN := FALSE; -- TRUE: forwards (stored) input Sync+BSN (from snk_in_arr(0)) to all output streams
g_output_align : BOOLEAN := TRUE -- TRUE: Use pipeline stages to align the outputs
);
PORT (
rst : IN STD_LOGIC;
clk : IN STD_LOGIC;
snk_in_arr : IN t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0);
src_out_arr : OUT t_dp_sosi_arr(g_nof_inputs*pow2(g_nof_unfolds)-1 DOWNTO 0)
);
END dp_unfolder;
ARCHITECTURE str OF dp_unfolder IS
COMPONENT dp_unfolder IS
GENERIC (
g_nof_inputs : NATURAL;
g_nof_unfolds : NATURAL := 0;
g_output_align : BOOLEAN := TRUE
);
PORT (
rst : IN STD_LOGIC;
clk : IN STD_LOGIC;
snk_in_arr : IN t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0);
src_out_arr : OUT t_dp_sosi_arr(g_nof_inputs*pow2(g_nof_unfolds)-1 DOWNTO 0)
);
END COMPONENT;
CONSTANT c_nof_demuxes : NATURAL := g_nof_inputs;
CONSTANT c_nof_outputs : NATURAL := g_nof_inputs*pow2(g_nof_unfolds);
SIGNAL output_sel_arr : STD_LOGIC_VECTOR(c_nof_demuxes-1 DOWNTO 0);
SIGNAL nxt_output_sel_arr : STD_LOGIC_VECTOR(c_nof_demuxes-1 DOWNTO 0);
SIGNAL demux_src_out_2arr_2 : t_dp_sosi_2arr_2(c_nof_demuxes-1 DOWNTO 0);
SIGNAL nxt_demux_src_out_2arr_2 : t_dp_sosi_2arr_2(c_nof_demuxes-1 DOWNTO 0);
SIGNAL demux_src_out_arr : t_dp_sosi_arr(2*c_nof_demuxes-1 DOWNTO 0);
SIGNAL dp_pipeline_snk_in_arr : t_dp_sosi_arr(c_nof_outputs-1 DOWNTO 0);
SIGNAL dp_block_gen_snk_in_arr : t_dp_sosi_arr(c_nof_outputs-1 DOWNTO 0);
SIGNAL dp_block_gen_src_out_arr : t_dp_sosi_arr(c_nof_outputs-1 DOWNTO 0);
BEGIN
gen_arch: IF g_nof_unfolds/=0 GENERATE
-----------------------------------------------------------------------------
-- Simple 2-output demux logic
-----------------------------------------------------------------------------
gen_demux_comb: FOR i IN 0 TO c_nof_demuxes-1 GENERATE
nxt_output_sel_arr(i) <= NOT output_sel_arr(i) WHEN snk_in_arr(i).valid='1' ELSE output_sel_arr(i);
END GENERATE;
p_demux : PROCESS(snk_in_arr, output_sel_arr)
BEGIN
FOR i IN 0 TO c_nof_demuxes-1 LOOP
nxt_demux_src_out_2arr_2(i)(0) <= c_dp_sosi_rst;
nxt_demux_src_out_2arr_2(i)(1) <= c_dp_sosi_rst;
IF snk_in_arr(i).valid='1' THEN
IF output_sel_arr(i)='0' THEN
nxt_demux_src_out_2arr_2(i)(0).data <= snk_in_arr(i).data;
nxt_demux_src_out_2arr_2(i)(0).re <= snk_in_arr(i).re;
nxt_demux_src_out_2arr_2(i)(0).im <= snk_in_arr(i).im;
nxt_demux_src_out_2arr_2(i)(0).valid <= '1';
ELSE
nxt_demux_src_out_2arr_2(i)(1).data <= snk_in_arr(i).data;
nxt_demux_src_out_2arr_2(i)(1).re <= snk_in_arr(i).re;
nxt_demux_src_out_2arr_2(i)(1).im <= snk_in_arr(i).im;
nxt_demux_src_out_2arr_2(i)(1).valid <= '1';
END IF;
END IF;
END LOOP;
END PROCESS;
-- Registers
p_clk: PROCESS(clk, rst)
BEGIN
IF rst='1' THEN
demux_src_out_2arr_2 <= (OTHERS=>(OTHERS=>c_dp_sosi_rst));
output_sel_arr <= (OTHERS=>'0');
ELSIF rising_edge(clk) THEN
demux_src_out_2arr_2 <= nxt_demux_src_out_2arr_2;
output_sel_arr <= nxt_output_sel_arr;
END IF;
END PROCESS;
-----------------------------------------------------------------------------
-- Wire the 2D demux output array to 1D array to match entity I/O type
-----------------------------------------------------------------------------
gen_demux_inputs_0: FOR i IN 0 TO c_nof_demuxes-1 GENERATE
demux_src_out_arr(2*i) <= demux_src_out_2arr_2(i)(0);
demux_src_out_arr(2*i+1) <= demux_src_out_2arr_2(i)(1);
END GENERATE;
-----------------------------------------------------------------------------
-- g_nof_unfolds>1, so add an unfolder stage.
-----------------------------------------------------------------------------
gen_dp_unfolder: IF g_nof_unfolds>1 GENERATE
u_dp_unfolder : dp_unfolder
GENERIC MAP (
g_nof_inputs => c_nof_demuxes*2, -- Next stage has all our demux outputs as inputs
g_nof_unfolds => g_nof_unfolds-1,
g_output_align => g_output_align
)
PORT MAP (
rst => rst,
clk => clk,
snk_in_arr => demux_src_out_arr,
src_out_arr => src_out_arr
);
END GENERATE;
-----------------------------------------------------------------------------
-- g_nof_unfolds=1, so this is the last stage. Wire up the outputs.
-----------------------------------------------------------------------------
gen_src_out_arr: IF g_nof_unfolds=1 GENERATE
gen_output_align : IF g_output_align=TRUE GENERATE
dp_pipeline_snk_in_arr <= demux_src_out_arr;
-----------------------------------------------------------------------------
-- Pipeline to re-align the unfolder output
-----------------------------------------------------------------------------
gen_dp_pipeline : FOR i IN 0 TO c_nof_outputs-1 GENERATE
u_dp_pipeline : ENTITY dp_lib.dp_pipeline
GENERIC MAP (
g_pipeline => 0 + (pow2(g_nof_unfolds) - i REM pow2(g_nof_unfolds)-1)
)
PORT MAP (
rst => rst,
clk => clk,
snk_in => dp_pipeline_snk_in_arr(i),
src_out => dp_block_gen_snk_in_arr(i)
);
END GENERATE;
END GENERATE;
no_output_align : IF g_output_align=FALSE GENERATE
dp_block_gen_snk_in_arr <= demux_src_out_arr;
END GENERATE;
-----------------------------------------------------------------------------
-- Add SOP and EOP to the outputs
-----------------------------------------------------------------------------
gen_ctrl : IF g_output_block_size>0 GENERATE
gen_dp_block_gen : FOR i IN 0 TO c_nof_outputs-1 GENERATE
u_dp_block_gen : ENTITY work.dp_block_gen
GENERIC MAP (
g_use_src_in => FALSE,
g_nof_data => g_output_block_size,
g_preserve_sync => TRUE,
g_preserve_bsn => TRUE
)
PORT MAP(
rst => rst,
clk => clk,
snk_in => dp_block_gen_snk_in_arr(i),
src_out => dp_block_gen_src_out_arr(i)
);
END GENERATE;
END GENERATE;
no_ctrl : IF g_output_block_size=0 GENERATE
dp_block_gen_src_out_arr <= dp_block_gen_snk_in_arr;
END GENERATE;
-----------------------------------------------------------------------------
-- Re-add input sync + BSN to all output streams
-----------------------------------------------------------------------------
gen_sync_bsn : IF g_fwd_sync_bsn = TRUE GENERATE
gen_dp_fifo_info: FOR i IN 0 TO c_nof_outputs-1 GENERATE
u_dp_fifo_info : ENTITY work.dp_fifo_info
GENERIC MAP (
g_use_sync => TRUE,
g_use_bsn => TRUE
)
PORT MAP (
rst => rst,
clk => clk,
data_snk_in => dp_block_gen_src_out_arr(i), -- delayed snk_in data
info_snk_in => snk_in_arr(0), -- original snk_in info
src_in => c_dp_siso_rdy,
src_out => src_out_arr(i)
);
END GENERATE;
END GENERATE;
no_sync_bsn : IF g_fwd_sync_bsn = FALSE GENERATE
src_out_arr <= dp_block_gen_src_out_arr;
END GENERATE;
END GENERATE;
END GENERATE;
-----------------------------------------------------------------------------
-- Wire output to input if g_nof_unfolds=0
-----------------------------------------------------------------------------
gen_wire_out_to_in: IF g_nof_unfolds=0 GENERATE
dp_block_gen_snk_in_arr <= snk_in_arr;
END GENERATE;
END str;
-------------------------------------------------------------------------------
--
-- Copyright (C) 2016
-- 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/>.
--
-------------------------------------------------------------------------------
-- Author
-- . Daniel van der Schuur
-- Purpose
-- . Verify stream through dp_unfolder->dp_folder stages
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_mem_pkg.ALL;
USE common_lib.tb_common_pkg.ALL;
USE work.dp_stream_pkg.ALL;
USE work.tb_dp_pkg.ALL;
ENTITY tb_dp_folder IS
END tb_dp_folder;
ARCHITECTURE tb OF tb_dp_folder IS
CONSTANT c_nof_inputs : NATURAL := 1;
CONSTANT c_nof_unfolds : NATURAL := 1; -- 5 folds = 1->2->4->8->16->32 unfolded streams
CONSTANT c_nof_unfolded_streams : NATURAL := c_nof_inputs*pow2(c_nof_unfolds);
CONSTANT c_data_w : NATURAL := 32;
CONSTANT c_nof_packets : NATURAL := 10;
CONSTANT c_packet_len : NATURAL := 20;
CONSTANT c_packet_gap : NATURAL := 0;
CONSTANT c_clk_period : TIME := 5 ns; -- 200 MHz
CONSTANT c_mm_clk_period : TIME := 20 ns; -- 50 MHz
SIGNAL clk : STD_LOGIC := '1';
SIGNAL rst : STD_LOGIC;
SIGNAL proc_dp_gen_block_data_in_en : STD_LOGIC := '1';
SIGNAL proc_dp_gen_block_data_src_in : t_dp_siso := c_dp_siso_rdy;
SIGNAL proc_dp_gen_block_data_src_out : t_dp_sosi;
SIGNAL dp_unfolder_snk_in_arr : t_dp_sosi_arr(c_nof_inputs-1 DOWNTO 0);
SIGNAL dp_folder_snk_in_arr : t_dp_sosi_arr(c_nof_unfolded_streams-1 DOWNTO 0);
SIGNAL dp_folder_src_out_arr : t_dp_sosi_arr(c_nof_inputs-1 DOWNTO 0);
BEGIN
-----------------------------------------------------------------------------
-- Clock,reset generation
-----------------------------------------------------------------------------
clk <= NOT clk AFTER c_clk_period/2;
rst <= '1', '0' AFTER c_clk_period*7;
-----------------------------------------------------------------------------
-- Generate packet stream
-----------------------------------------------------------------------------
p_generate_packets : PROCESS
BEGIN
proc_dp_gen_block_data_src_out <= c_dp_sosi_rst;
proc_common_wait_until_low(clk, rst);
proc_common_wait_some_cycles(clk, 5);
FOR i IN 0 TO c_nof_packets-1 LOOP
-- Generate single packet
proc_dp_gen_block_data(c_data_w, 0, c_packet_len, 0, 0, '0', "0", clk, proc_dp_gen_block_data_in_en, proc_dp_gen_block_data_src_in, proc_dp_gen_block_data_src_out);
-- Insert optional gap between the packets
proc_common_wait_some_cycles(clk, c_packet_gap);
END LOOP;
WAIT;
END PROCESS;
-----------------------------------------------------------------------------
-- Unfold the single stream into multiple streams, the fold it back into one again
-----------------------------------------------------------------------------
dp_unfolder_snk_in_arr(0) <= proc_dp_gen_block_data_src_out;
u_dp_unfolder : ENTITY work.dp_unfolder
GENERIC MAP (
g_nof_inputs => c_nof_inputs,
g_nof_unfolds => c_nof_unfolds,
g_output_align => FALSE -- We're going to fold these outputs again, so don't align them!
)
PORT MAP (
clk => clk,
rst => rst,
snk_in_arr => dp_unfolder_snk_in_arr,
src_out_arr => dp_folder_snk_in_arr
);
u_dp_folder : ENTITY work.dp_folder
GENERIC MAP (
g_nof_inputs => c_nof_unfolded_streams,
g_nof_folds => -1 -- Fold until 1 output remains,
-- g_output_block_size => c_packet_len
)
PORT MAP (
clk => clk,
rst => rst,
snk_in_arr => dp_folder_snk_in_arr,
src_out_arr => dp_folder_src_out_arr
);
END tb;
-------------------------------------------------------------------------------
--
-- Copyright (C) 2016
-- 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/>.
--
-------------------------------------------------------------------------------
-- Author
-- . Daniel van der Schuur
-- Purpose
-- . Generate input streams for dp_switch, verify by eye in wave window.
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_mem_pkg.ALL;
USE common_lib.tb_common_pkg.ALL;
USE common_lib.tb_common_mem_pkg.ALL;
USE work.dp_stream_pkg.ALL;
USE work.tb_dp_pkg.ALL;
ENTITY tb_dp_switch IS
END tb_dp_switch;
ARCHITECTURE tb OF tb_dp_switch IS
CONSTANT c_nof_inputs : NATURAL := 3;
CONSTANT c_data_w : NATURAL := 32;
CONSTANT c_nof_packets : NATURAL := 10;
CONSTANT c_packet_len : NATURAL := 20;
CONSTANT c_packet_gap : NATURAL := 1; --NOTE: dp_mux requires a minimum gap of 1 to select a new input!
CONSTANT c_dp_clk_period : TIME := 5 ns; -- 200 MHz
CONSTANT c_mm_clk_period : TIME := 20 ns; -- 50 MHz
SIGNAL dp_clk : STD_LOGIC := '1';
SIGNAL dp_rst : STD_LOGIC;
SIGNAL mm_clk : STD_LOGIC := '1';
SIGNAL mm_rst : STD_LOGIC;
SIGNAL proc_dp_gen_block_data_in_en : STD_LOGIC := '1';
SIGNAL proc_dp_gen_block_data_src_in : t_dp_siso := c_dp_siso_rdy;
SIGNAL proc_dp_gen_block_data_src_out_arr : t_dp_sosi_arr(c_nof_inputs-1 DOWNTO 0);
SIGNAL dp_switch_snk_in_arr : t_dp_sosi_arr(c_nof_inputs-1 DOWNTO 0);
SIGNAL dp_switch_src_out : t_dp_sosi;
SIGNAL reg_dp_switch_mosi : t_mem_mosi := c_mem_mosi_rst;
SIGNAL reg_dp_switch_miso : t_mem_miso;
BEGIN
-----------------------------------------------------------------------------
-- Clock,reset generation
-----------------------------------------------------------------------------
dp_clk <= NOT dp_clk AFTER c_dp_clk_period/2;
dp_rst <= '1', '0' AFTER c_dp_clk_period*7;
mm_clk <= NOT mm_clk AFTER c_mm_clk_period/2;
mm_rst <= '1', '0' AFTER c_mm_clk_period*7;
-----------------------------------------------------------------------------
-- Generate packet streams
-----------------------------------------------------------------------------
gen_generate_packets : FOR i IN 0 TO c_nof_inputs-1 GENERATE
p_generate_packets : PROCESS
BEGIN
proc_dp_gen_block_data_src_out_arr(i) <= c_dp_sosi_rst;
proc_common_wait_until_low(dp_clk, dp_rst);
proc_common_wait_some_cycles(dp_clk, 5);
FOR j IN 0 TO c_nof_packets-1 LOOP
-- Generate single packet
proc_dp_gen_block_data(c_data_w, i*1000, c_packet_len, 0, 0, '0', "0", dp_clk, proc_dp_gen_block_data_in_en, proc_dp_gen_block_data_src_in, proc_dp_gen_block_data_src_out_arr(i));
-- Insert optional gap between the packets
proc_common_wait_some_cycles(dp_clk, c_packet_gap);
END LOOP;
WAIT;
END PROCESS;
END GENERATE;
-----------------------------------------------------------------------------
-- MM write different input selections
-----------------------------------------------------------------------------
p_generate_packets : PROCESS
BEGIN
reg_dp_switch_mosi <= c_mem_mosi_rst;
proc_common_wait_until_low(mm_clk, mm_rst);
proc_common_wait_some_cycles(mm_clk, 15);
proc_mem_mm_bus_wr(0, 1, mm_clk, reg_dp_switch_mosi);
WAIT;
END PROCESS;
-----------------------------------------------------------------------------
-- dp_switch forwards either stream 0 or stream 1
-- . Both inputs carry the same generated stream
-----------------------------------------------------------------------------
gen_dp_switch_snk_in_arr : FOR i IN 0 TO c_nof_inputs-1 GENERATE
dp_switch_snk_in_arr(i) <= proc_dp_gen_block_data_src_out_arr(i);
END GENERATE;
u_dp_switch : ENTITY work.dp_switch
GENERIC MAP (
g_nof_inputs => c_nof_inputs,
g_default_enabled => 2
)
PORT MAP (
dp_clk => dp_clk,
dp_rst => dp_rst,
mm_clk => mm_clk,
mm_rst => mm_rst,
snk_in_arr => dp_switch_snk_in_arr,
src_out => dp_switch_src_out,
reg_mosi => reg_dp_switch_mosi,
reg_miso => reg_dp_switch_miso
);
END tb;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment