Select Git revision
dp_offload_tx_legacy.vhd
-
Eric Kooistra authored
SVN copied data and hex directories so that they can be referred to from $RADIOHDL instead of from $UNB. SVN copied python, doc, matlab sub directories in tb or src to $RADIOHDL as well. Only common/hdllib.cfg still refers to $UNB because some low level components (multipliers) are not technology independent yet.
Eric Kooistra authoredSVN copied data and hex directories so that they can be referred to from $RADIOHDL instead of from $UNB. SVN copied python, doc, matlab sub directories in tb or src to $RADIOHDL as well. Only common/hdllib.cfg still refers to $UNB because some low level components (multipliers) are not technology independent yet.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
dp_offload_tx_legacy.vhd 14.72 KiB
-------------------------------------------------------------------------------
--
-- Copyright (C) 2012
-- 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, work;
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 work.dp_stream_pkg.ALL;
ENTITY dp_offload_tx_legacy IS
GENERIC (
g_nof_streams : NATURAL := 1;
g_data_w : NATURAL;
g_block_size : NATURAL := 256; -- The number of words per input block
g_block_nof_sel_words : NATURAL := 20; -- The maximum number of words we select from each input block.
g_nof_words_per_pkt : NATURAL := 360; -- The maximum number of words per output Tx packet
g_hdr_nof_words : NATURAL; -- The number of words (of width g_data_w) to be added as header for each TX packet, e.g. c_eth_total_header_nof_words
g_use_complex : BOOLEAN := FALSE; -- TRUE uses re(0..g_data_w/2 -1) & im(0..g_data_w/2-1) as input instead of data(0..g_data_w-1).
g_use_input_fifo : BOOLEAN := FALSE; -- TRUE instantiates a shallow input FIFO, e.g. in case source has no flow control
g_use_output_fifo : BOOLEAN := TRUE; -- TRUE to instantiate an output FIFO that buffers an entire packet
g_input_fifo_bsn_w : NATURAL := c_dp_stream_bsn_w;
g_input_fifo_empty_w : NATURAL := c_dp_stream_empty_w;
g_input_fifo_channel_w : NATURAL := c_dp_stream_channel_w;
g_input_fifo_error_w : NATURAL := c_dp_stream_error_w;
g_input_fifo_use_bsn : BOOLEAN := TRUE;
g_input_fifo_use_empty : BOOLEAN := TRUE;
g_input_fifo_use_channel : BOOLEAN := TRUE;
g_input_fifo_use_error : BOOLEAN := TRUE;
g_input_fifo_use_sync : BOOLEAN := TRUE
);
PORT (
mm_rst : IN STD_LOGIC;
mm_clk : IN STD_LOGIC;
st_rst : IN STD_LOGIC;
st_clk : IN STD_LOGIC;
-- MM registers
reg_hdr_insert_mosi : IN t_mem_mosi;
ram_hdr_insert_mosi : IN t_mem_mosi;
reg_dp_split_mosi : IN t_mem_mosi;
reg_dp_split_miso : OUT t_mem_miso;
reg_dp_pkt_merge_mosi : IN t_mem_mosi;
reg_dp_pkt_merge_miso : OUT t_mem_miso;
dp_sosi_arr : IN t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
dp_siso_arr : OUT t_dp_siso_arr(g_nof_streams-1 DOWNTO 0);
tx_sosi_arr : OUT t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
tx_siso_arr : IN t_dp_siso_arr(g_nof_streams-1 DOWNTO 0)
);
END dp_offload_tx_legacy;
ARCHITECTURE str OF dp_offload_tx_legacy IS
CONSTANT c_fifo_margin : NATURAL := 10;
CONSTANT c_dp_pkt_overhead_nof_words : NATURAL := 4+1;
CONSTANT c_hdr_insert_reg_addr_w : NATURAL := 1; -- Only 1 register used. A width of 1 still yields 2 addresses/instance though.
CONSTANT c_hdr_insert_ram_addr_w : NATURAL := ceil_log2( g_hdr_nof_words * (g_data_w/c_word_w) );
-- In case of an uninterruptable stream, the dp_hdr_insert's ready deassertion (during header insertion)
-- has to be compensated with this input FIFO buffer:
CONSTANT c_input_fifo_size : NATURAL := g_hdr_nof_words + c_dp_pkt_overhead_nof_words + c_fifo_margin;
CONSTANT c_output_fifo_fill : NATURAL := g_hdr_nof_words + c_dp_pkt_overhead_nof_words + g_nof_words_per_pkt;
CONSTANT c_output_fifo_size : NATURAL := c_output_fifo_fill + c_fifo_margin;
SIGNAL dp_sel_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL dp_to_split_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL dp_to_split_siso_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL dp_from_split_sosi_2arr : t_dp_sosi_2arr_2(g_nof_streams-1 DOWNTO 0);
SIGNAL dp_from_split_siso_2arr : t_dp_siso_2arr_2(g_nof_streams-1 DOWNTO 0);
SIGNAL dp_to_pkt_merge_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL dp_to_pkt_merge_siso_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL dp_merged_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL dp_merged_siso_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL udp_tx_pkt_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL udp_tx_pkt_siso_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL udp_tx_hdr_pkt_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL udp_tx_hdr_pkt_siso_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL udp_tx_hdr_pkt_fifo_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL udp_tx_hdr_pkt_fifo_siso_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL reg_hdr_insert_mosi_arr : t_mem_mosi_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL ram_hdr_insert_mosi_arr : t_mem_mosi_arr(g_nof_streams-1 DOWNTO 0);
BEGIN
u_common_mem_mux_hdr_reg : ENTITY common_lib.common_mem_mux
GENERIC MAP (
g_nof_mosi => g_nof_streams,
g_mult_addr_w => c_hdr_insert_reg_addr_w
)
PORT MAP (
mosi => reg_hdr_insert_mosi,
mosi_arr => reg_hdr_insert_mosi_arr
);
u_common_mem_mux_hdr_ram : ENTITY common_lib.common_mem_mux
GENERIC MAP (
g_nof_mosi => g_nof_streams,
g_mult_addr_w => c_hdr_insert_ram_addr_w
)
PORT MAP (
mosi => ram_hdr_insert_mosi,
mosi_arr => ram_hdr_insert_mosi_arr
);
gen_nof_streams0: FOR i IN 0 TO g_nof_streams-1 GENERATE
---------------------------------------------------------------------------------------
-- Select complex input if required
---------------------------------------------------------------------------------------
gen_complex_in : IF g_use_complex = TRUE GENERATE
p_connect : PROCESS(dp_sosi_arr(i))
BEGIN
dp_sel_sosi_arr(i) <= dp_sosi_arr(i);
dp_sel_sosi_arr(i).data(g_data_w-1 DOWNTO 0) <= dp_sosi_arr(i).re(g_data_w/2-1 DOWNTO 0) & dp_sosi_arr(i).im(g_data_w/2-1 DOWNTO 0);
END PROCESS;
END GENERATE;
gen_data_in : IF g_use_complex = FALSE GENERATE
dp_sel_sosi_arr(i) <= dp_sosi_arr(i);
END GENERATE;
---------------------------------------------------------------------------------------
-- Use a FIFO to buffer only 1 word
-- Required as dp_split needs to deassert its ready signal periodically
---------------------------------------------------------------------------------------
gen_input_buffer : IF g_use_input_fifo = TRUE GENERATE
u_buf : ENTITY work.dp_fifo_sc
GENERIC MAP (
g_data_w => g_data_w,
g_bsn_w => g_input_fifo_bsn_w,
g_empty_w => g_input_fifo_empty_w,
g_channel_w => g_input_fifo_channel_w,
g_error_w => g_input_fifo_error_w,
g_use_bsn => g_input_fifo_use_bsn,
g_use_empty => g_input_fifo_use_empty,
g_use_channel => g_input_fifo_use_channel,
g_use_error => g_input_fifo_use_error,
g_use_sync => g_input_fifo_use_sync,
g_use_ctrl => TRUE,
g_fifo_size => 10 -- Use 10 as there's a FIFO margin
)
PORT MAP (
rst => st_rst,
clk => st_clk,
snk_out => dp_siso_arr(i),
snk_in => dp_sel_sosi_arr(i),
src_in => dp_to_split_siso_arr(i),
src_out => dp_to_split_sosi_arr(i)
);
END GENERATE;
END GENERATE;
---------------------------------------------------------------------------------------
-- Throw away words 0..g_block_nof_sel_words-1 of block (0..g_block_size-1)
---------------------------------------------------------------------------------------
u_mms_dp_split : ENTITY work.mms_dp_split
GENERIC MAP (
g_nof_streams => g_nof_streams,
g_data_w => g_data_w,
g_symbol_w => g_data_w,
g_nof_symbols_max => g_block_nof_sel_words * (g_data_w / c_byte_w)
)
PORT MAP (
mm_rst => mm_rst,
mm_clk => mm_clk,
dp_rst => st_rst,
dp_clk => st_clk,
snk_out_arr => dp_to_split_siso_arr,
snk_in_arr => dp_to_split_sosi_arr,
src_in_2arr => dp_from_split_siso_2arr,
src_out_2arr => dp_from_split_sosi_2arr,
reg_mosi => reg_dp_split_mosi,
reg_miso => reg_dp_split_miso
);
gen_nof_streams1: FOR i IN 0 TO g_nof_streams-1 GENERATE
dp_from_split_siso_2arr(i)(0) <= c_dp_siso_rdy;
END GENERATE;
gen_nof_streams2: FOR i IN 0 TO g_nof_streams-1 GENERATE
---------------------------------------------------------------------------------------
-- Use a FIFO when source is uninterrupable: we need to buffer the input during packet
-- encoding and header insertion
---------------------------------------------------------------------------------------
gen_input_fifo : IF g_use_input_fifo = TRUE GENERATE
u_input_fifo : ENTITY work.dp_fifo_sc
GENERIC MAP (
g_data_w => g_data_w,
g_bsn_w => g_input_fifo_bsn_w,
g_empty_w => g_input_fifo_empty_w,
g_channel_w => g_input_fifo_channel_w,
g_error_w => g_input_fifo_error_w,
g_use_bsn => g_input_fifo_use_bsn,
g_use_empty => g_input_fifo_use_empty,
g_use_channel => g_input_fifo_use_channel,
g_use_error => g_input_fifo_use_error,
g_use_sync => g_input_fifo_use_sync,
g_use_ctrl => TRUE,
g_fifo_size => c_input_fifo_size
)
PORT MAP (
rst => st_rst,
clk => st_clk,
snk_out => dp_from_split_siso_2arr(i)(1),
snk_in => dp_from_split_sosi_2arr(i)(1),
src_in => dp_to_pkt_merge_siso_arr(i),
src_out => dp_to_pkt_merge_sosi_arr(i)
);
END GENERATE;
no_input_fifo : IF g_use_input_fifo = FALSE GENERATE
dp_to_pkt_merge_sosi_arr(i) <= dp_from_split_sosi_2arr(i)(1);
dp_siso_arr(i) <= dp_to_pkt_merge_siso_arr(i);
END GENERATE;
END GENERATE;
---------------------------------------------------------------------------------------
-- The packet rate has to be brought down to what the targeted sink can handle.
-- (e.g. PC; ~80k per second max.)
-- G_nof_pkt packets are merged into 1.
---------------------------------------------------------------------------------------
u_dp_packet_merge : ENTITY work.mms_dp_packet_merge
GENERIC MAP (
g_nof_streams => g_nof_streams,
g_nof_pkt => g_nof_words_per_pkt -- Support merging 360*1 word
)
PORT MAP (
mm_rst => mm_rst,
mm_clk => mm_clk,
dp_rst => st_rst,
dp_clk => st_clk,
snk_out_arr => dp_to_pkt_merge_siso_arr,
snk_in_arr => dp_to_pkt_merge_sosi_arr,
src_in_arr => dp_merged_siso_arr,
src_out_arr => dp_merged_sosi_arr,
reg_mosi => reg_dp_pkt_merge_mosi,
reg_miso => reg_dp_pkt_merge_miso
);
gen_nof_streams3: FOR i IN 0 TO g_nof_streams-1 GENERATE
---------------------------------------------------------------------------------------
-- Convert DP to packetized DP
---------------------------------------------------------------------------------------
u_dp_packet_enc : ENTITY work.dp_packet_enc
GENERIC MAP (
g_data_w => g_data_w
)
PORT MAP (
rst => st_rst,
clk => st_clk,
snk_out => dp_merged_siso_arr(i),
snk_in => dp_merged_sosi_arr(i),
src_in => udp_tx_pkt_siso_arr(i),
src_out => udp_tx_pkt_sosi_arr(i)
);
---------------------------------------------------------------------------------------
-- Add header to DP packet
---------------------------------------------------------------------------------------
u_hdr_insert : ENTITY work.dp_hdr_insert
GENERIC MAP (
g_data_w => g_data_w,
g_symbol_w => c_byte_w,
g_hdr_nof_words => g_hdr_nof_words
)
PORT MAP (
mm_rst => mm_rst,
mm_clk => mm_clk,
st_rst => st_rst,
st_clk => st_clk,
reg_mosi => reg_hdr_insert_mosi_arr(i),
ram_mosi => ram_hdr_insert_mosi_arr(i),
snk_out => udp_tx_pkt_siso_arr(i),
snk_in => udp_tx_pkt_sosi_arr(i),
src_in => udp_tx_hdr_pkt_siso_arr(i),
src_out => udp_tx_hdr_pkt_sosi_arr(i)
);
---------------------------------------------------------------------------------------
-- FIFO so we can deliver packets to the ETH module fast enough
---------------------------------------------------------------------------------------
gen_output_fifo: IF g_use_output_fifo = TRUE GENERATE
u_dp_fifo_fill : ENTITY work.dp_fifo_fill
GENERIC MAP (
g_data_w => g_data_w,
g_bsn_w => 0,
g_empty_w => 0,
g_channel_w => 0,
g_error_w => 0,
g_use_bsn => FALSE, -- Don't forward these as all have been encoded by dp_packet_enc
g_use_empty => FALSE,
g_use_channel => FALSE,
g_use_error => FALSE,
g_use_sync => FALSE,
g_fifo_fill => c_output_fifo_fill, --Release packet only when available
g_fifo_size => c_output_fifo_size,
g_fifo_rl => 1
)
PORT MAP (
rst => st_rst,
clk => st_clk,
snk_out => udp_tx_hdr_pkt_siso_arr(i),
snk_in => udp_tx_hdr_pkt_sosi_arr(i),
src_in => udp_tx_hdr_pkt_fifo_siso_arr(i),
src_out => udp_tx_hdr_pkt_fifo_sosi_arr(i)
);
udp_tx_hdr_pkt_fifo_siso_arr(i) <= tx_siso_arr(i);
tx_sosi_arr(i) <= udp_tx_hdr_pkt_fifo_sosi_arr(i);
END GENERATE;
gen_no_output_fifo: IF g_use_output_fifo = FALSE GENERATE
udp_tx_hdr_pkt_siso_arr(i) <= tx_siso_arr(i);
tx_sosi_arr(i) <= udp_tx_hdr_pkt_sosi_arr(i);
END GENERATE;
END GENERATE;
END str;