Skip to content
Snippets Groups Projects
Commit 9c4d63e6 authored by Kenneth Hiemstra's avatar Kenneth Hiemstra
Browse files

New eth for 1GbE and M&C

parent 7a70e024
No related branches found
No related tags found
No related merge requests found
hdl_lib_name = eth1g
hdl_library_clause_name = eth1g_lib
hdl_lib_uses_synth = dp common eth
hdl_lib_uses_sim =
hdl_lib_technology =
synth_files =
src/vhdl/eth1g.vhd
test_bench_files =
tb/vhdl/tb_eth1g.vhd
tb/vhdl/tb_tb_eth1g.vhd
regression_test_vhdl =
# tb/vhdl/tb_eth_checksum.vhd
# tb/vhdl/tb_eth_crc_ctrl.vhd
# tb/vhdl/tb_eth_hdr.vhd
# tb/vhdl/tb_eth_udp_offload.vhd
# tb/vhdl/tb_eth_ihl_to_20.vhd
# tb/vhdl/tb_tb_eth.vhd
[modelsim_project_file]
[quartus_project_file]
-------------------------------------------------------------------------------
--
-- 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/>.
--
-------------------------------------------------------------------------------
-- Purpose:
-- Provide Ethernet control access to a node and some UDP ports for streaming
-- data.
-- Description:
-- Connect the 1GbE TSE to the microprocessor and to streaming UDP ports. The
-- packets for the streaming channels are directed based on the UDP port
-- number and all other packets are transfered to the default control channel.
LIBRARY IEEE, common_lib, technology_lib, dp_lib, eth_lib, tech_tse_lib;
USE IEEE.std_logic_1164.ALL;
USE common_lib.common_pkg.ALL;
USE common_lib.common_mem_pkg.ALL;
USE common_lib.common_network_layers_pkg.ALL;
USE common_lib.common_network_total_header_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;
USE tech_tse_lib.tech_tse_pkg.ALL;
USE eth_lib.eth_pkg.ALL;
USE technology_lib.technology_select_pkg.ALL;
ENTITY eth1g IS
GENERIC (
g_technology : NATURAL := c_tech_select_default;
g_init_ip_address : STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0) := X"00000000"; -- 0.0.0.0
g_cross_clock_domain : BOOLEAN := TRUE; -- use FALSE when mm_clk and st_clk are the same, else use TRUE to cross the clock domain
g_ETH_PHY : STRING := "LVDS"; -- "LVDS" (default): uses LVDS IOs for ctrl_unb_common, "XCVR": uses tranceiver PHY
g_ihl20 : BOOLEAN := FALSE;
g_frm_discard_en : BOOLEAN := FALSE -- when TRUE discard frame types that would otherwise have to be discarded by the Nios MM master
);
PORT (
-- Clocks and reset
mm_rst : IN STD_LOGIC; -- reset synchronous with mm_clk
mm_clk : IN STD_LOGIC; -- memory-mapped bus clock
eth_clk : IN STD_LOGIC; -- ethernet phy reference clock
st_rst : IN STD_LOGIC; -- reset synchronous with st_clk
st_clk : IN STD_LOGIC; -- packet stream clock
cal_rec_clk : IN STD_LOGIC := '0'; -- Calibration & reconfig clock when using XCVR
-- UDP transmit interface
udp_tx_snk_in_arr : IN t_dp_sosi_arr(c_eth_nof_udp_ports-1 DOWNTO 0) := (OTHERS=> c_dp_sosi_rst); -- ST sinks, default not valid if not used
udp_tx_snk_out_arr : OUT t_dp_siso_arr(c_eth_nof_udp_ports-1 DOWNTO 0);
-- UDP receive interface
udp_rx_src_in_arr : IN t_dp_siso_arr(c_eth_nof_udp_ports-1 DOWNTO 0) := (OTHERS=> c_dp_siso_rdy); -- ST sources, default ready if not used
udp_rx_src_out_arr : OUT t_dp_sosi_arr(c_eth_nof_udp_ports-1 DOWNTO 0);
-- Memory Mapped Slaves
tse_sla_in : IN t_mem_mosi; -- ETH TSE MAC registers
tse_sla_out : OUT t_mem_miso;
reg_sla_in : IN t_mem_mosi; -- ETH control and status registers
reg_sla_out : OUT t_mem_miso;
reg_sla_interrupt : OUT STD_LOGIC; -- Interrupt
ram_sla_in : IN t_mem_mosi; -- ETH rx frame and tx frame memory
ram_sla_out : OUT t_mem_miso;
-- Monitoring
rx_flushed_frm_cnt : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); -- only used in simulation, because it will get optimized away in synthesis
-- PHY interface
eth_txp : OUT STD_LOGIC;
eth_rxp : IN STD_LOGIC;
-- LED interface
tse_led : OUT t_tech_tse_led
);
END eth1g;
ARCHITECTURE str OF eth1g IS
------------------------------------------------------------------------------
-- ETH Rx packet buffer and Tx packet buffer
------------------------------------------------------------------------------
-- Use MM bus data width = c_word_w = 32
CONSTANT c_mm_ram : t_c_mem := (latency => c_mem_ram_rd_latency,
adr_w => c_eth_ram_addr_w,
dat_w => c_word_w,
nof_dat => c_eth_ram_nof_words,
init_sl => '0');
SIGNAL mem_in : t_mem_mosi; -- big endian on ST and TSE MAC network side
SIGNAL mem_out : t_mem_miso; -- big endian on ST and TSE MAC network side
SIGNAL mem_in_endian : t_mem_mosi; -- keep big endian on MM side
SIGNAL mem_out_endian : t_mem_miso; -- keep big endian on MM side
------------------------------------------------------------------------------
-- ETH stream
------------------------------------------------------------------------------
-- Multiplex - demultiplex
CONSTANT c_mux_nof_ports : NATURAL := 1 + c_eth_nof_udp_ports; -- One for control + nof UDP ports
CONSTANT c_demux_nof_ports : NATURAL := c_mux_nof_ports;
CONSTANT c_demux_combined : BOOLEAN := FALSE; -- when TRUE then all downstream sinks must be ready, when FALSE then only the
-- selected sink needs to be ready (see dp_demux for more explanation).
-- All Rx (so UDP off-load and other ETH traffic)
SIGNAL rx_adapt_siso : t_dp_siso;
SIGNAL rx_adapt_sosi : t_dp_sosi;
SIGNAL rx_crc_siso : t_dp_siso;
SIGNAL rx_crc_sosi : t_dp_sosi;
SIGNAL rx_ihl20_siso : t_dp_siso;
SIGNAL rx_ihl20_sosi : t_dp_sosi;
SIGNAL rx_hdr_siso : t_dp_siso;
SIGNAL rx_hdr_sosi : t_dp_sosi;
SIGNAL rx_hdr_status : t_eth_hdr_status;
SIGNAL rx_hdr_status_complete : STD_LOGIC;
-- Rx demux
SIGNAL rx_channel_siso : t_dp_siso;
SIGNAL rx_channel_sosi : t_dp_sosi;
SIGNAL demux_siso_arr : t_dp_siso_arr(0 TO c_mux_nof_ports-1);
SIGNAL demux_sosi_arr : t_dp_sosi_arr(0 TO c_mux_nof_ports-1);
-- ETH Rx
SIGNAL eth_rx_siso : t_dp_siso;
SIGNAL eth_rx_sosi : t_dp_sosi;
SIGNAL rx_frm_discard : STD_LOGIC;
SIGNAL rx_frm_discard_val : STD_LOGIC;
SIGNAL rx_eth_discard : STD_LOGIC;
SIGNAL rx_eth_discard_val : STD_LOGIC;
SIGNAL rx_frame_rd : STD_LOGIC;
SIGNAL rx_frame_ack : STD_LOGIC;
SIGNAL rx_frame_done : STD_LOGIC;
SIGNAL rx_frame_sosi : t_dp_sosi;
SIGNAL rx_frame_hdr_words_arr : t_network_total_header_32b_arr;
SIGNAL rx_frame_hdr_fields : t_network_total_header;
SIGNAL rx_frame_hdr_status : t_eth_hdr_status;
SIGNAL rx_frame_crc_word : STD_LOGIC_VECTOR(c_eth_data_w-1 DOWNTO 0);
-- ETH Tx
SIGNAL eth_tx_siso : t_dp_siso;
SIGNAL eth_tx_sosi : t_dp_sosi;
-- Tx mux
SIGNAL mux_siso_arr : t_dp_siso_arr(0 TO c_mux_nof_ports-1);
SIGNAL mux_sosi_arr : t_dp_sosi_arr(0 TO c_mux_nof_ports-1);
-- All Tx (so UDP off-load and other ETH traffic)
SIGNAL tx_mux_siso : t_dp_siso;
SIGNAL tx_mux_sosi : t_dp_sosi;
SIGNAL tx_hdr_siso : t_dp_siso;
SIGNAL tx_hdr_sosi : t_dp_sosi;
------------------------------------------------------------------------------
-- MM registers (in st_clk domain)
------------------------------------------------------------------------------
-- . write/read back
SIGNAL reg_demux : t_eth_mm_reg_demux;
SIGNAL reg_config : t_eth_mm_reg_config;
SIGNAL reg_control : t_eth_mm_reg_control;
SIGNAL reg_continue_wr : STD_LOGIC;
-- . read only
SIGNAL reg_frame : t_eth_mm_reg_frame;
SIGNAL reg_status : t_eth_mm_reg_status;
SIGNAL reg_status_wr : STD_LOGIC;
------------------------------------------------------------------------------
-- TSE MAC
------------------------------------------------------------------------------
-- . MAC Transmit Stream
SIGNAL tse_tx_siso : t_dp_siso;
SIGNAL tse_tx_sosi : t_dp_sosi;
-- . MAC specific
SIGNAL tse_tx_mac_in : t_tech_tse_tx_mac;
SIGNAL tse_tx_mac_out : t_tech_tse_tx_mac;
-- . MAC Receive Stream
SIGNAL tse_rx_sosi : t_dp_sosi;
SIGNAL tse_rx_siso : t_dp_siso;
-- . MAC specific
SIGNAL tse_rx_mac_out : t_tech_tse_rx_mac;
BEGIN
------------------------------------------------------------------------------
-- MM registers
------------------------------------------------------------------------------
u_mm_registers : ENTITY eth_lib.eth_mm_registers
GENERIC MAP (
g_cross_clock_domain => g_cross_clock_domain,
g_init_ip_address => g_init_ip_address
)
PORT MAP (
-- Clocks and reset
mm_rst => mm_rst,
mm_clk => mm_clk,
st_rst => st_rst,
st_clk => st_clk,
-- Memory Mapped Slave
sla_in => reg_sla_in,
sla_out => reg_sla_out,
sla_interrupt => reg_sla_interrupt,
-- MM registers in st_clk domain
-- . write/read back
st_reg_demux => reg_demux,
st_reg_config => reg_config,
st_reg_control => reg_control,
st_reg_continue_wr => reg_continue_wr,
-- . read only
st_reg_frame => reg_frame,
st_reg_status => reg_status,
st_reg_status_wr => reg_status_wr
);
-- Packet buffer
u_mm_ram : ENTITY common_lib.common_ram_crw_crw
GENERIC MAP (
g_technology => g_technology,
g_ram => c_mm_ram
)
PORT MAP (
rst_a => mm_rst,
clk_a => mm_clk,
wr_en_a => ram_sla_in.wr,
adr_a => ram_sla_in.address(c_mm_ram.adr_w-1 DOWNTO 0),
wr_dat_a => ram_sla_in.wrdata(c_mm_ram.dat_w-1 DOWNTO 0),
rd_en_a => ram_sla_in.rd,
rd_dat_a => ram_sla_out.rddata(c_mm_ram.dat_w-1 DOWNTO 0),
rd_val_a => ram_sla_out.rdval,
rst_b => st_rst,
clk_b => st_clk,
wr_en_b => mem_in_endian.wr,
adr_b => mem_in_endian.address(c_mm_ram.adr_w-1 DOWNTO 0),
wr_dat_b => mem_in_endian.wrdata(c_mm_ram.dat_w-1 DOWNTO 0),
rd_en_b => mem_in_endian.rd,
rd_dat_b => mem_out_endian.rddata(c_mm_ram.dat_w-1 DOWNTO 0),
rd_val_b => mem_out_endian.rdval
);
-- The Rx, Tx packet buffer is big-endian
mem_in_endian <= func_mem_swap_endianess(mem_in, c_word_sz);
mem_out <= func_mem_swap_endianess(mem_out_endian, c_word_sz);
------------------------------------------------------------------------------
-- RX : Adapt the TSE RX source ready latency from 2 to 1
------------------------------------------------------------------------------
u_adapt : ENTITY dp_lib.dp_latency_adapter
GENERIC MAP (
g_in_latency => c_eth_rx_ready_latency, -- = 2
g_out_latency => c_eth_ready_latency -- = 1
)
PORT MAP (
rst => st_rst,
clk => st_clk,
-- ST sink
snk_out => tse_rx_siso,
snk_in => tse_rx_sosi,
-- ST source
src_in => rx_adapt_siso,
src_out => rx_adapt_sosi
);
------------------------------------------------------------------------------
-- RX : Replace the CRC word with the stream error field from the TSE MAC
------------------------------------------------------------------------------
u_crc_ctrl : ENTITY eth_lib.eth_crc_ctrl
PORT MAP (
rst => st_rst,
clk => st_clk,
-- Streaming Sink
snk_in_err => rx_adapt_sosi.err(c_tech_tse_error_w-1 DOWNTO 0), -- preserve error field from TSE MAC stream
snk_in => rx_adapt_sosi,
snk_out => rx_adapt_siso,
-- Streaming Source
src_in => rx_crc_siso,
src_out => rx_crc_sosi, -- replaced CRC word by snk_in_err, so CRC word /=0 indicates any TSE error
src_out_err => OPEN -- flag snk_in_err/=0 at src_out.eop
);
------------------------------------------------------------------------------
-- RX : Strip the option words from the IPv4 header
------------------------------------------------------------------------------
gen_ihl20: IF g_ihl20 GENERATE
u_ihl20 : ENTITY eth_lib.eth_ihl_to_20
PORT MAP (
rst => st_rst,
clk => st_clk,
-- Streaming Sink
snk_in => rx_crc_sosi,
snk_out => rx_crc_siso,
-- Streaming Source
src_in => rx_ihl20_siso,
src_out => rx_ihl20_sosi
);
END GENERATE;
no_ihl20: IF not g_ihl20 GENERATE
rx_ihl20_sosi <= rx_crc_sosi;
rx_crc_siso <= rx_ihl20_siso;
END GENERATE;
------------------------------------------------------------------------------
-- RX : For IP verify IP header checksum
------------------------------------------------------------------------------
u_rx_frame : ENTITY eth_lib.eth_hdr
GENERIC MAP (
g_header_store_and_forward => TRUE,
g_ip_header_checksum_calculate => TRUE
)
PORT MAP (
-- Clocks and reset
rst => st_rst,
clk => st_clk,
-- Streaming Sink
snk_in => rx_ihl20_sosi,
snk_out => rx_ihl20_siso,
-- Streaming Source
src_in => rx_hdr_siso,
src_out => rx_hdr_sosi,
-- Frame control
frm_discard => rx_eth_discard,
frm_discard_val => rx_eth_discard_val,
-- Header info
hdr_status => rx_hdr_status,
hdr_status_complete => rx_hdr_status_complete
);
rx_eth_discard <= rx_frm_discard WHEN g_frm_discard_en=TRUE ELSE '0';
rx_eth_discard_val <= rx_frm_discard_val WHEN g_frm_discard_en=TRUE ELSE '1';
u_frm_discard : ENTITY eth_lib.eth_frm_discard
GENERIC MAP (
g_support_dhcp => TRUE,
g_support_udp_onload => FALSE
)
PORT MAP (
-- Clocks and reset
rst => st_rst,
clk => st_clk,
-- MM control
reg_config => reg_config,
reg_demux => reg_demux,
-- ST info
hdr_status => rx_hdr_status,
hdr_status_complete => rx_hdr_status_complete,
-- Frame discard decision
frm_discard => rx_frm_discard,
frm_discard_val => rx_frm_discard_val
);
------------------------------------------------------------------------------
-- Demux the UDP off-load traffic and the keep the other ETH traffic
------------------------------------------------------------------------------
-- Put UDP off-load traffic on channel > 0
-- Put other ETH traffic on channel = 0 for further internal processing
u_udp_channel : ENTITY eth_lib.eth_udp_channel
PORT MAP (
-- Clocks and reset
rst => st_rst,
clk => st_clk,
-- Streaming Sink
snk_in => rx_hdr_sosi,
snk_out => rx_hdr_siso,
-- Streaming Source with channel field
src_in => rx_channel_siso,
src_out => rx_channel_sosi,
-- Demux control
reg_demux => reg_demux,
hdr_status => rx_hdr_status
);
-- Demultiplex channel 0 for internal handling and the other channels > 0 for external UDP off-load.
u_rx_demux : ENTITY dp_lib.dp_demux
GENERIC MAP (
g_nof_output => c_demux_nof_ports,
g_combined => c_demux_combined
)
PORT MAP (
rst => st_rst,
clk => st_clk,
-- ST sinks
snk_out => rx_channel_siso,
snk_in => rx_channel_sosi,
-- ST source
src_in_arr => demux_siso_arr,
src_out_arr => demux_sosi_arr
);
-- Fixed local ETH port
eth_rx_sosi <= demux_sosi_arr(0);
demux_siso_arr(0) <= eth_rx_siso;
-- UDP offload ports
gen_udp_rx_demux : FOR i IN 1 TO c_eth_nof_udp_ports GENERATE
udp_rx_src_out_arr(i-1) <= demux_sosi_arr(i);
demux_siso_arr(i) <= udp_rx_src_in_arr(i-1);
END GENERATE;
------------------------------------------------------------------------------
-- ETH RX frame buffer
------------------------------------------------------------------------------
u_rx_buffer : ENTITY eth_lib.eth_buffer
GENERIC MAP (
g_technology => g_technology
)
PORT MAP (
-- Clocks and reset
rst => st_rst,
clk => st_clk,
-- Streaming Sink
snk_in => eth_rx_sosi,
snk_out => eth_rx_siso,
-- Streaming Source
-- . The src_rd, src_ack and src_done act instead of src_in.ready to have src_in ready per frame instead of per data word
src_rd => rx_frame_rd, -- request frame pulse
src_ack => rx_frame_ack, -- acknowledge request
src_done => rx_frame_done, -- signal frame received
src_out => rx_frame_sosi,
-- Monitoring
flushed_frm_cnt => rx_flushed_frm_cnt
);
------------------------------------------------------------------------------
-- ETH RX frame monitor
------------------------------------------------------------------------------
-- Extract total header
u_rx_hdr_info : ENTITY eth_lib.eth_hdr
GENERIC MAP (
g_header_store_and_forward => FALSE,
g_ip_header_checksum_calculate => FALSE
)
PORT MAP (
-- Clocks and reset
rst => st_rst,
clk => st_clk,
-- Streaming Sink
snk_in => rx_frame_sosi,
-- Header info
hdr_words_arr => rx_frame_hdr_words_arr,
hdr_fields => rx_frame_hdr_fields,
hdr_status => rx_frame_hdr_status
);
-- Extract CRC word (enumerate: 0=OK, >0 AND odd = Error)
u_rx_crc_word : ENTITY eth_lib.eth_crc_word
PORT MAP (
rst => st_rst,
clk => st_clk,
-- Streaming Sink
snk_in => rx_frame_sosi,
-- CRC word
crc_word => rx_frame_crc_word,
crc_word_val => OPEN
);
u_mm_reg_frame : ENTITY eth_lib.eth_mm_reg_frame
PORT MAP (
-- Clocks and reset
rst => st_rst,
clk => st_clk,
-- Inputs need for the frame register
hdr_fields => rx_frame_hdr_fields,
hdr_status => rx_frame_hdr_status,
erc_word => rx_frame_crc_word,
reg_config => reg_config,
-- Frame register
reg_frame => reg_frame
);
------------------------------------------------------------------------------
-- ETH Control
------------------------------------------------------------------------------
u_control : ENTITY eth_lib.eth_control
PORT MAP (
-- Clocks and reset
rst => st_rst,
clk => st_clk,
-- Control register
reg_config => reg_config,
reg_control => reg_control,
reg_continue_wr => reg_continue_wr,
reg_status => reg_status,
reg_status_wr => reg_status_wr,
-- Streaming sink Rx frame
rcv_rd => rx_frame_rd,
rcv_ack => rx_frame_ack,
rcv_done => rx_frame_done,
rcv_in => rx_frame_sosi,
rcv_hdr_words_arr => rx_frame_hdr_words_arr,
rcv_hdr_status => rx_frame_hdr_status,
-- Streaming source Tx frame
xmt_in => eth_tx_siso,
xmt_out => eth_tx_sosi,
-- MM frame memory
mem_in => mem_in,
mem_out => mem_out
);
------------------------------------------------------------------------------
-- TX : Mux UDP
------------------------------------------------------------------------------
-- Fixed local ETH
eth_tx_siso <= mux_siso_arr(0);
mux_sosi_arr(0) <= eth_tx_sosi;
-- UDP offload ports
gen_udp_tx_mux : FOR i IN 1 TO c_eth_nof_udp_ports GENERATE
udp_tx_snk_out_arr(i-1) <= mux_siso_arr(i);
mux_sosi_arr(i) <= udp_tx_snk_in_arr(i-1);
END GENERATE;
-- Multiplex the two input streams on to the single ETH stream
u_tx_mux : ENTITY dp_lib.dp_mux
GENERIC MAP (
g_technology => g_technology,
g_data_w => c_eth_data_w,
g_empty_w => c_eth_empty_w,
g_in_channel_w => 1,
g_error_w => 1,
g_use_empty => TRUE,
g_use_in_channel => FALSE,
g_use_error => FALSE,
g_nof_input => c_mux_nof_ports,
g_use_fifo => FALSE,
g_fifo_size => array_init(1024, c_mux_nof_ports), -- input FIFOs are not used, but generic must match g_nof_input
g_fifo_fill => array_init( 0, c_mux_nof_ports) -- input FIFOs are not used, but generic must match g_nof_input
)
PORT MAP (
rst => st_rst,
clk => st_clk,
-- ST sinks
snk_out_arr => mux_siso_arr, -- OUT = request to upstream ST source
snk_in_arr => mux_sosi_arr,
-- ST source
src_in => tx_mux_siso, -- IN = request from downstream ST sink
src_out => tx_mux_sosi
);
------------------------------------------------------------------------------
-- TX : For IP insert IP header checksum
------------------------------------------------------------------------------
u_tx_frame : ENTITY eth_lib.eth_hdr
GENERIC MAP (
g_header_store_and_forward => TRUE,
g_ip_header_checksum_calculate => TRUE
)
PORT MAP (
-- Clocks and reset
rst => st_rst,
clk => st_clk,
-- Streaming Sink
snk_in => tx_mux_sosi,
snk_out => tx_mux_siso,
-- Streaming Source
src_in => tx_hdr_siso,
src_out => tx_hdr_sosi
);
------------------------------------------------------------------------------
-- TSE MAC
------------------------------------------------------------------------------
tx_hdr_siso <= tse_tx_siso;
tse_tx_sosi <= func_dp_stream_error_set(tx_hdr_sosi, 0); -- set err field (value 0 for OK)
tse_tx_mac_in.crc_fwd <= '0'; -- when '0' then TSE MAC generates the TX CRC field
u_tech_tse : ENTITY tech_tse_lib.tech_tse
GENERIC MAP (
g_technology => g_technology,
g_ETH_PHY => g_ETH_PHY
)
PORT MAP (
-- Clocks and reset
mm_rst => mm_rst,
mm_clk => mm_clk,
eth_clk => eth_clk,
tx_snk_clk => st_clk,
rx_src_clk => st_clk,
cal_rec_clk => cal_rec_clk,
-- Memory Mapped Slave
mm_sla_in => tse_sla_in,
mm_sla_out => tse_sla_out,
-- MAC transmit interface
-- . ST sink
tx_snk_in => tse_tx_sosi,
tx_snk_out => tse_tx_siso,
-- . MAC specific
tx_mac_in => tse_tx_mac_in,
tx_mac_out => tse_tx_mac_out, -- OPEN
-- MAC receive interface
-- . ST Source
rx_src_in => tse_rx_siso,
rx_src_out => tse_rx_sosi,
-- . MAC specific
rx_mac_out => tse_rx_mac_out,
-- PHY interface
eth_txp => eth_txp,
eth_rxp => eth_rxp,
-- LED interface
tse_led => tse_led
);
END str;
-------------------------------------------------------------------------------
--
-- 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/>.
--
-------------------------------------------------------------------------------
-- Purpose: Testbench for eth1g
-- Description:
--
-- The p_lcu_transmitter transmits packets and the p_eth_control loops them
-- back to p_lcu_receiver:
--
-- ------- -------
-- /---| |<---| |<--- p_lcu_transmitter
-- p_eth_control | | DUT | | LCU |
-- \-->|(ETH)|--->|(TSE)|---> p_lcu_receiver
-- ------- -------
--
-- The tb is self checking based on:
-- . proc_tech_tse_rx_packet() for expected header and data type
-- . tx_pkt_cnt=rx_pkt_cnt > 0 must be true at the tb_end.
-- Usage:
-- > as 10
-- > run -all
LIBRARY IEEE, common_lib, dp_lib, technology_lib, eth_lib, tech_tse_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_mem_pkg.ALL;
USE common_lib.common_network_layers_pkg.ALL;
USE common_lib.common_network_total_header_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;
USE technology_lib.technology_pkg.ALL;
USE technology_lib.technology_select_pkg.ALL;
USE tech_tse_lib.tech_tse_pkg.ALL;
USE tech_tse_lib.tb_tech_tse_pkg.ALL;
USE eth_lib.eth_pkg.ALL;
ENTITY tb_eth1g IS
-- Test bench control parameters
GENERIC (
g_technology_dut : NATURAL := c_tech_select_default;
g_technology_lcu : NATURAL := c_tech_select_default;
g_frm_discard_en : BOOLEAN := FALSE; -- when TRUE discard frame types that would otherwise have to be discarded by the Nios MM master
g_flush_test_en : BOOLEAN := FALSE; -- when TRUE send many large frames to enforce flush in eth_buffer
g_tb_end : BOOLEAN := TRUE; -- when TRUE then tb_end ends this simulation, else a higher multi-testbench will end the simulation
-- g_data_type = c_tb_tech_tse_data_type_symbols = 0
-- g_data_type = c_tb_tech_tse_data_type_counter = 1
-- g_data_type = c_tb_tech_tse_data_type_arp = 2
-- g_data_type = c_tb_tech_tse_data_type_ping = 3
-- g_data_type = c_tb_tech_tse_data_type_udp = 4
g_data_type : NATURAL := c_tb_tech_tse_data_type_udp
);
PORT (
tb_end : OUT STD_LOGIC
);
END tb_eth1g;
ARCHITECTURE tb OF tb_eth1g IS
CONSTANT sys_clk_period : TIME := 10 ns; -- 100 MHz
CONSTANT eth_clk_period : TIME := 8 ns; -- 125 MHz
CONSTANT cable_delay : TIME := 12 ns;
CONSTANT c_cross_clock_domain : BOOLEAN := TRUE; -- use FALSE when mm_clk and st_clk are the same, else use TRUE to cross the clock domain
-- TSE constants
CONSTANT c_promis_en : BOOLEAN := FALSE;
CONSTANT c_tx_ready_latency : NATURAL := c_tech_tse_tx_ready_latency; -- 0, 1 are supported, must match TSE MAC c_tech_tse_tx_ready_latency
CONSTANT c_nof_tx_not_valid : NATURAL := 0; -- when > 0 then pull tx valid low for c_nof_tx_not_valid beats during tx
-- Payload user data
CONSTANT c_tb_nof_data : NATURAL := 0; -- nof UDP user data, nof ping padding data
CONSTANT c_tb_ip_nof_data : NATURAL := c_network_udp_header_len + c_tb_nof_data; -- nof IP data,
-- also suits ICMP, because c_network_icmp_header_len = c_network_udp_header_len
CONSTANT c_tb_reply_payload : BOOLEAN := TRUE; -- TRUE copy rx payload into response payload, else header only (e.g. for ARP)
-- Packet headers
-- . Ethernet header
CONSTANT c_lcu_src_mac : STD_LOGIC_VECTOR(c_network_eth_mac_slv'RANGE) := X"10FA01020300";
CONSTANT c_dut_src_mac : STD_LOGIC_VECTOR(c_network_eth_mac_slv'RANGE) := X"123456789ABC"; -- = 12-34-56-78-9A-BC
CONSTANT c_dut_src_mac_hi : NATURAL := TO_UINT(c_dut_src_mac(c_network_eth_mac_addr_w-1 DOWNTO c_word_w));
CONSTANT c_dut_src_mac_lo : NATURAL := TO_UINT(c_dut_src_mac( c_word_w-1 DOWNTO 0));
-- support only ARP and IPv4 over ETH
-- symbols counter ARP=0x806 IP=0x800 IP=0x800
CONSTANT c_dut_ethertype : NATURAL := sel_n(g_data_type, 16#07F0#, 16#07F1#, c_network_eth_type_arp, c_network_eth_type_ip, c_network_eth_type_ip);
CONSTANT c_tx_eth_header : t_network_eth_header := (dst_mac => c_dut_src_mac,
src_mac => c_lcu_src_mac,
eth_type => TO_UVEC(c_dut_ethertype, c_network_eth_type_w));
CONSTANT c_discard_eth_header : t_network_eth_header := (dst_mac => c_dut_src_mac,
src_mac => c_lcu_src_mac,
eth_type => TO_UVEC(16#07F0#, c_network_eth_type_w));
CONSTANT c_exp_eth_header : t_network_eth_header := (dst_mac => c_tx_eth_header.src_mac, -- \/
src_mac => c_tx_eth_header.dst_mac, -- /\
eth_type => c_tx_eth_header.eth_type); -- =
-- . IP header
CONSTANT c_lcu_ip_addr : NATURAL := 16#05060708#; -- = 05:06:07:08
CONSTANT c_dut_ip_addr : NATURAL := 16#01020304#;
CONSTANT c_tb_ip_total_length : NATURAL := c_network_ip_total_length + c_tb_ip_nof_data;
-- support only ping protocol or UDP protocol over IP
-- symbols counter ARP ping=1 UDP=17
CONSTANT c_tb_ip_protocol : NATURAL := sel_n(g_data_type, 13, 14, 15, c_network_ip_protocol_icmp, c_network_ip_protocol_udp);
CONSTANT c_tx_ip_header : t_network_ip_header := (version => TO_UVEC(c_network_ip_version, c_network_ip_version_w),
header_length => TO_UVEC(c_network_ip_header_length, c_network_ip_header_length_w),
services => TO_UVEC(c_network_ip_services, c_network_ip_services_w),
total_length => TO_UVEC(c_tb_ip_total_length, c_network_ip_total_length_w),
identification => TO_UVEC(c_network_ip_identification, c_network_ip_identification_w),
flags => TO_UVEC(c_network_ip_flags, c_network_ip_flags_w),
fragment_offset => TO_UVEC(c_network_ip_fragment_offset, c_network_ip_fragment_offset_w),
time_to_live => TO_UVEC(c_network_ip_time_to_live, c_network_ip_time_to_live_w),
protocol => TO_UVEC(c_tb_ip_protocol, c_network_ip_protocol_w),
header_checksum => TO_UVEC(c_network_ip_header_checksum, c_network_ip_header_checksum_w), -- init value (or try 0xEBBD = 60349)
src_ip_addr => TO_UVEC(c_lcu_ip_addr, c_network_ip_addr_w),
dst_ip_addr => TO_UVEC(c_dut_ip_addr, c_network_ip_addr_w));
CONSTANT c_exp_ip_header : t_network_ip_header := (version => c_tx_ip_header.version, -- =
header_length => c_tx_ip_header.header_length, -- =
services => c_tx_ip_header.services, -- =
total_length => c_tx_ip_header.total_length, -- =
identification => c_tx_ip_header.identification, -- =
flags => c_tx_ip_header.flags, -- =
fragment_offset => c_tx_ip_header.fragment_offset, -- =
time_to_live => c_tx_ip_header.time_to_live, -- =
protocol => c_tx_ip_header.protocol, -- =
header_checksum => c_tx_ip_header.header_checksum, -- init value
src_ip_addr => c_tx_ip_header.dst_ip_addr, -- \/
dst_ip_addr => c_tx_ip_header.src_ip_addr); -- /\
-- . ARP packet
CONSTANT c_tx_arp_packet : t_network_arp_packet := (htype => TO_UVEC(c_network_arp_htype, c_network_arp_htype_w),
ptype => TO_UVEC(c_network_arp_ptype, c_network_arp_ptype_w),
hlen => TO_UVEC(c_network_arp_hlen, c_network_arp_hlen_w),
plen => TO_UVEC(c_network_arp_plen, c_network_arp_plen_w),
oper => TO_UVEC(c_network_arp_oper_request, c_network_arp_oper_w),
sha => c_lcu_src_mac,
spa => TO_UVEC(c_lcu_ip_addr, c_network_ip_addr_w),
tha => c_dut_src_mac,
tpa => TO_UVEC(c_dut_ip_addr, c_network_ip_addr_w));
CONSTANT c_exp_arp_packet : t_network_arp_packet := (htype => c_tx_arp_packet.htype,
ptype => c_tx_arp_packet.ptype,
hlen => c_tx_arp_packet.hlen,
plen => c_tx_arp_packet.plen,
oper => TO_UVEC(c_network_arp_oper_reply, c_network_arp_oper_w), -- reply
sha => c_tx_arp_packet.tha, -- \/
spa => c_tx_arp_packet.tpa, -- /\ \/
tha => c_tx_arp_packet.sha, -- / \ /\
tpa => c_tx_arp_packet.spa); -- / \
-- . ICMP header
CONSTANT c_tx_icmp_header : t_network_icmp_header := (msg_type => TO_UVEC(c_network_icmp_msg_type_request, c_network_icmp_msg_type_w), -- ping request
code => TO_UVEC(c_network_icmp_code, c_network_icmp_code_w),
checksum => TO_UVEC(c_network_icmp_checksum, c_network_icmp_checksum_w), -- init value
id => TO_UVEC(c_network_icmp_id, c_network_icmp_id_w),
sequence => TO_UVEC(c_network_icmp_sequence, c_network_icmp_sequence_w));
CONSTANT c_exp_icmp_header : t_network_icmp_header := (msg_type => TO_UVEC(c_network_icmp_msg_type_reply, c_network_icmp_msg_type_w), -- ping reply
code => c_tx_icmp_header.code,
checksum => c_tx_icmp_header.checksum, -- init value
id => c_tx_icmp_header.id,
sequence => c_tx_icmp_header.sequence);
-- . UDP header
CONSTANT c_dut_udp_port_ctrl : NATURAL := 11; -- ETH demux UDP for control
CONSTANT c_dut_udp_port_st0 : NATURAL := 57; -- ETH demux UDP port 0
CONSTANT c_dut_udp_port_st1 : NATURAL := 58; -- ETH demux UDP port 1
CONSTANT c_dut_udp_port_st2 : NATURAL := 59; -- ETH demux UDP port 2
CONSTANT c_dut_udp_port_en : NATURAL := 16#10000#; -- ETH demux UDP port enable bit 16
CONSTANT c_lcu_udp_port : NATURAL := 10; -- UDP port used for src_port
CONSTANT c_dut_udp_port_st : NATURAL := c_dut_udp_port_st0; -- UDP port used for dst_port
CONSTANT c_tb_udp_total_length : NATURAL := c_network_udp_total_length + c_tb_nof_data;
CONSTANT c_tx_udp_header : t_network_udp_header := (src_port => TO_UVEC(c_lcu_udp_port, c_network_udp_port_w),
dst_port => TO_UVEC(c_dut_udp_port_ctrl, c_network_udp_port_w), -- or use c_dut_udp_port_st#
total_length => TO_UVEC(c_tb_udp_total_length, c_network_udp_total_length_w),
checksum => TO_UVEC(c_network_udp_checksum, c_network_udp_checksum_w)); -- init value
CONSTANT c_exp_udp_header : t_network_udp_header := (src_port => c_tx_udp_header.dst_port, -- \/
dst_port => c_tx_udp_header.src_port, -- /\
total_length => c_tx_udp_header.total_length, -- =
checksum => c_tx_udp_header.checksum); -- init value
SIGNAL tx_total_header : t_network_total_header; -- transmitted packet header
SIGNAL discard_total_header: t_network_total_header; -- transmitted packet header for to be discarded packet
SIGNAL exp_total_header : t_network_total_header; -- expected received packet header
-- ETH control
CONSTANT c_dut_control_rx_en : NATURAL := 2**c_eth_mm_reg_control_bi.rx_en;
CONSTANT c_dut_control_tx_en : NATURAL := 2**c_eth_mm_reg_control_bi.tx_en;
-- Clocks and reset
SIGNAL eth_clk : STD_LOGIC := '0'; -- tse reference clock
SIGNAL sys_clk : STD_LOGIC := '0'; -- system clock
SIGNAL st_clk : STD_LOGIC; -- stream clock
SIGNAL st_rst : STD_LOGIC := '1'; -- reset synchronous with st_clk
SIGNAL mm_clk : STD_LOGIC; -- memory-mapped bus clock
SIGNAL mm_rst : STD_LOGIC := '1'; -- reset synchronous with mm_clk
-- ETH TSE interface
SIGNAL dut_tse_init : STD_LOGIC := '1';
SIGNAL dut_eth_init : STD_LOGIC := '1';
SIGNAL eth_tse_miso : t_mem_miso;
SIGNAL eth_tse_mosi : t_mem_mosi;
SIGNAL eth_psc_access : STD_LOGIC;
SIGNAL eth_txp : STD_LOGIC;
SIGNAL eth_rxp : STD_LOGIC;
SIGNAL eth_led : t_tech_tse_led;
-- ETH MM registers interface
SIGNAL eth_reg_miso : t_mem_miso;
SIGNAL eth_reg_mosi : t_mem_mosi;
SIGNAL eth_reg_interrupt : STD_LOGIC;
SIGNAL eth_mm_reg_control : t_eth_mm_reg_control;
SIGNAL eth_mm_reg_status : t_eth_mm_reg_status;
SIGNAL eth_ram_miso : t_mem_miso;
SIGNAL eth_ram_mosi : t_mem_mosi;
-- ETH UDP data path interface
SIGNAL udp_tx_sosi_arr : t_dp_sosi_arr(c_eth_nof_udp_ports-1 DOWNTO 0);
SIGNAL udp_tx_siso_arr : t_dp_siso_arr(c_eth_nof_udp_ports-1 DOWNTO 0);
SIGNAL udp_rx_siso_arr : t_dp_siso_arr(c_eth_nof_udp_ports-1 DOWNTO 0);
SIGNAL udp_rx_sosi_arr : t_dp_sosi_arr(c_eth_nof_udp_ports-1 DOWNTO 0);
-- LCU TSE interface
SIGNAL lcu_init : STD_LOGIC := '1';
SIGNAL lcu_tse_miso : t_mem_miso;
SIGNAL lcu_tse_mosi : t_mem_mosi;
SIGNAL lcu_psc_access : STD_LOGIC;
SIGNAL lcu_tx_en : STD_LOGIC := '1';
SIGNAL lcu_tx_siso : t_dp_siso;
SIGNAL lcu_tx_sosi : t_dp_sosi;
SIGNAL lcu_tx_mac_in : t_tech_tse_tx_mac;
SIGNAL lcu_tx_mac_out : t_tech_tse_tx_mac;
SIGNAL lcu_rx_sosi : t_dp_sosi;
SIGNAL lcu_rx_siso : t_dp_siso;
SIGNAL lcu_rx_mac_out : t_tech_tse_rx_mac;
SIGNAL lcu_txp : STD_LOGIC;
SIGNAL lcu_rxp : STD_LOGIC;
SIGNAL lcu_led : t_tech_tse_led;
-- Verification
SIGNAL tx_end : STD_LOGIC := '0';
SIGNAL rx_end : STD_LOGIC := '0';
SIGNAL rx_timeout : NATURAL := 0;
SIGNAL tx_pkt_cnt : NATURAL := 0;
SIGNAL rx_pkt_cnt : NATURAL := 0;
SIGNAL rx_pkt_discarded_cnt: NATURAL := 0;
SIGNAL rx_pkt_flushed_cnt : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
BEGIN
-- run 50 us
eth_clk <= NOT eth_clk AFTER eth_clk_period/2; -- TSE reference clock
sys_clk <= NOT sys_clk AFTER sys_clk_period/2; -- System clock
mm_clk <= sys_clk;
st_clk <= sys_clk;
p_reset : PROCESS
BEGIN
-- reset release
st_rst <= '1';
mm_rst <= '1';
FOR I IN 0 TO 9 LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP;
mm_rst <= '0';
WAIT UNTIL rising_edge(st_clk);
st_rst <= '0';
FOR I IN 0 TO 9 LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP;
WAIT;
END PROCESS;
-- Use signal to leave unused fields 'X'
tx_total_header.eth <= c_tx_eth_header;
tx_total_header.arp <= c_tx_arp_packet;
tx_total_header.ip <= c_tx_ip_header;
tx_total_header.icmp <= c_tx_icmp_header;
tx_total_header.udp <= c_tx_udp_header;
discard_total_header.eth <= c_discard_eth_header;
discard_total_header.arp <= c_tx_arp_packet;
discard_total_header.ip <= c_tx_ip_header;
discard_total_header.icmp <= c_tx_icmp_header;
discard_total_header.udp <= c_tx_udp_header;
exp_total_header.eth <= c_exp_eth_header;
exp_total_header.arp <= c_exp_arp_packet;
exp_total_header.ip <= c_exp_ip_header;
exp_total_header.icmp <= c_exp_icmp_header;
exp_total_header.udp <= c_exp_udp_header;
------------------------------------------------------------------------------
-- DUT
------------------------------------------------------------------------------
p_tse_setup : PROCESS
BEGIN
dut_tse_init <= '1';
eth_tse_mosi.wr <= '0';
eth_tse_mosi.rd <= '0';
-- Wait for ETH init
WHILE dut_eth_init='1' LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP;
-- Setup the TSE MAC
proc_tech_tse_setup(g_technology_dut,
c_promis_en, c_tech_tse_tx_fifo_depth, c_tech_tse_rx_fifo_depth, c_tx_ready_latency,
c_dut_src_mac, eth_psc_access,
mm_clk, eth_tse_miso, eth_tse_mosi);
dut_tse_init <= '0';
WAIT;
END PROCESS;
p_eth_control : PROCESS
VARIABLE v_eth_control_word : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
BEGIN
-- ETH setup
dut_eth_init <= '1';
eth_reg_mosi.wr <= '0';
eth_reg_mosi.rd <= '0';
eth_ram_mosi.address <= (OTHERS=>'0');
eth_ram_mosi.wr <= '0';
eth_ram_mosi.rd <= '0';
-- Wait for reset release
WHILE mm_rst='1' LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP;
-- Setup the DEMUX UDP
proc_mem_mm_bus_wr(c_eth_reg_demux_wi+0, c_dut_udp_port_en+c_dut_udp_port_st0, mm_clk, eth_reg_miso, eth_reg_mosi); -- UDP port stream 0
proc_mem_mm_bus_wr(c_eth_reg_demux_wi+1, c_dut_udp_port_en+c_dut_udp_port_st1, mm_clk, eth_reg_miso, eth_reg_mosi); -- UDP port stream 1
proc_mem_mm_bus_wr(c_eth_reg_demux_wi+2, c_dut_udp_port_en+c_dut_udp_port_st2, mm_clk, eth_reg_miso, eth_reg_mosi); -- UDP port stream 2
proc_mem_mm_bus_rd(c_eth_reg_demux_wi+0, mm_clk, eth_reg_miso, eth_reg_mosi);
proc_mem_mm_bus_rd(c_eth_reg_demux_wi+1, mm_clk, eth_reg_miso, eth_reg_mosi);
proc_mem_mm_bus_rd(c_eth_reg_demux_wi+2, mm_clk, eth_reg_miso, eth_reg_mosi);
-- Setup the RX config
proc_mem_mm_bus_wr(c_eth_reg_config_wi+0, c_dut_src_mac_lo, mm_clk, eth_reg_miso, eth_reg_mosi); -- control MAC address lo word
proc_mem_mm_bus_wr(c_eth_reg_config_wi+1, c_dut_src_mac_hi, mm_clk, eth_reg_miso, eth_reg_mosi); -- control MAC address hi halfword
proc_mem_mm_bus_wr(c_eth_reg_config_wi+2, c_dut_ip_addr, mm_clk, eth_reg_miso, eth_reg_mosi); -- control IP address
proc_mem_mm_bus_wr(c_eth_reg_config_wi+3, c_dut_udp_port_ctrl, mm_clk, eth_reg_miso, eth_reg_mosi); -- control UDP port
-- Enable RX
proc_mem_mm_bus_wr(c_eth_reg_control_wi+0, c_dut_control_rx_en, mm_clk, eth_reg_miso, eth_reg_mosi); -- control rx en
dut_eth_init <= '0';
-- Wait for TSE init
WHILE dut_tse_init='1' LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP;
-- Response control
WHILE TRUE LOOP
eth_mm_reg_status <= c_eth_mm_reg_status_rst;
eth_mm_reg_control <= c_eth_mm_reg_control_rst;
-- wait for rx_avail interrupt
IF eth_reg_interrupt='1' THEN
-- read status register to read the status
proc_mem_mm_bus_rd(c_eth_reg_status_wi+0, mm_clk, eth_reg_miso, eth_reg_mosi); -- read result available in eth_mm_reg_status
proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk);
eth_mm_reg_status <= func_eth_mm_reg_status(eth_reg_miso.rddata);
WAIT UNTIL rising_edge(mm_clk);
-- write status register to acknowledge the interrupt
proc_mem_mm_bus_wr(c_eth_reg_status_wi+0, 0, mm_clk, eth_reg_miso, eth_reg_mosi); -- void value
-- prepare control register for response
IF c_tb_reply_payload=TRUE THEN
eth_mm_reg_control.tx_nof_words <= INCR_UVEC(eth_mm_reg_status.rx_nof_words, -1); -- -1 to skip the CRC word for the response
eth_mm_reg_control.tx_empty <= eth_mm_reg_status.rx_empty;
ELSE
eth_mm_reg_control.tx_nof_words <= TO_UVEC(c_network_total_header_32b_nof_words, c_eth_max_frame_nof_words_w);
eth_mm_reg_control.tx_empty <= TO_UVEC(0, c_eth_empty_w);
END IF;
eth_mm_reg_control.tx_en <= '1';
eth_mm_reg_control.rx_en <= '1';
WAIT UNTIL rising_edge(mm_clk);
-- wait for interrupt removal due to status register read access
WHILE eth_reg_interrupt='1' LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP;
-- write control register to enable tx
IF c_tb_reply_payload=TRUE THEN
-- . copy the received payload to the response payload (overwrite part of the default response header in case of raw ETH)
FOR I IN func_tech_tse_header_size(g_data_type) TO TO_UINT(eth_mm_reg_control.tx_nof_words)-1 LOOP
proc_mem_mm_bus_rd(c_eth_ram_rx_offset+I, mm_clk, eth_ram_miso, eth_ram_mosi);
proc_mem_mm_bus_rd_latency(c_mem_ram_rd_latency, mm_clk);
proc_mem_mm_bus_wr(c_eth_ram_tx_offset+I, TO_SINT(eth_ram_miso.rddata(c_word_w-1 DOWNTO 0)), mm_clk, eth_ram_miso, eth_ram_mosi);
END LOOP;
--ELSE
-- . only reply header
END IF;
v_eth_control_word := func_eth_mm_reg_control(eth_mm_reg_control);
proc_mem_mm_bus_wr(c_eth_reg_control_wi+0, TO_UINT(v_eth_control_word), mm_clk, eth_reg_miso, eth_reg_mosi);
-- write continue register to make the ETH module continue
proc_mem_mm_bus_wr(c_eth_reg_continue_wi, 0, mm_clk, eth_reg_miso, eth_reg_mosi); -- void value
END IF;
WAIT UNTIL rising_edge(mm_clk);
END LOOP;
WAIT;
END PROCESS;
------------------------------------------------------------------------------
-- LCU
------------------------------------------------------------------------------
p_lcu_setup : PROCESS
BEGIN
lcu_init <= '1';
lcu_tse_mosi.wr <= '0';
lcu_tse_mosi.rd <= '0';
-- Wait for reset release
WHILE mm_rst='1' LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP;
-- Setup the LCU TSE MAC
proc_tech_tse_setup(g_technology_lcu,
c_promis_en, c_tech_tse_tx_fifo_depth, c_tech_tse_rx_fifo_depth, c_tx_ready_latency,
c_lcu_src_mac, lcu_psc_access,
mm_clk, lcu_tse_miso, lcu_tse_mosi);
-- Wait for DUT init done
WHILE dut_tse_init/='0' LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP;
lcu_init <= '0';
WAIT;
END PROCESS;
p_lcu_transmitter : PROCESS
BEGIN
-- . Avalon ST
lcu_tx_sosi.data <= (OTHERS=>'0');
lcu_tx_sosi.valid <= '0';
lcu_tx_sosi.sop <= '0';
lcu_tx_sosi.eop <= '0';
lcu_tx_sosi.empty <= (OTHERS=>'0');
lcu_tx_sosi.err <= (OTHERS=>'0');
-- . MAC specific
lcu_tx_mac_in.crc_fwd <= '0'; -- when '0' then TSE MAC generates the TX CRC field
WHILE lcu_init/='0' LOOP WAIT UNTIL rising_edge(st_clk); END LOOP;
FOR I IN 0 TO 9 LOOP WAIT UNTIL rising_edge(st_clk); END LOOP;
FOR I IN 0 TO 40 LOOP
proc_tech_tse_tx_packet(tx_total_header, I, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
--FOR J IN 0 TO 9 LOOP WAIT UNTIL rising_edge(st_clk); END LOOP;
END LOOP;
IF g_frm_discard_en=TRUE THEN
-- Insert a counter data packet that should be discarded
proc_tech_tse_tx_packet(discard_total_header, 13, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
rx_pkt_discarded_cnt <= rx_pkt_discarded_cnt + 1;
-- Send another packet that should be received
proc_tech_tse_tx_packet(tx_total_header, 14, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
END IF;
IF g_flush_test_en=TRUE THEN
proc_tech_tse_tx_packet(tx_total_header, 1496, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
proc_tech_tse_tx_packet(tx_total_header, 1497, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
proc_tech_tse_tx_packet(tx_total_header, 1498, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
proc_tech_tse_tx_packet(tx_total_header, 1499, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
proc_tech_tse_tx_packet(tx_total_header, 1500, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
proc_tech_tse_tx_packet(tx_total_header, 1500, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
proc_tech_tse_tx_packet(tx_total_header, 1500, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
proc_tech_tse_tx_packet(tx_total_header, 1500, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
proc_tech_tse_tx_packet(tx_total_header, 1500, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
proc_tech_tse_tx_packet(tx_total_header, 1500, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
proc_tech_tse_tx_packet(tx_total_header, 1500, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
proc_tech_tse_tx_packet(tx_total_header, 1500, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
proc_tech_tse_tx_packet(tx_total_header, 1500, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
proc_tech_tse_tx_packet(tx_total_header, 0, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
proc_tech_tse_tx_packet(tx_total_header, 1, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
proc_tech_tse_tx_packet(tx_total_header, 2, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
END IF;
-- proc_tech_tse_tx_packet(tx_total_header, 104, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
-- proc_tech_tse_tx_packet(tx_total_header, 105, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
-- proc_tech_tse_tx_packet(tx_total_header, 1472, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
-- proc_tech_tse_tx_packet(tx_total_header, 1500, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
-- proc_tech_tse_tx_packet(tx_total_header, 101, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
-- proc_tech_tse_tx_packet(tx_total_header, 1000, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
-- proc_tech_tse_tx_packet(tx_total_header, 102, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
-- proc_tech_tse_tx_packet(tx_total_header, 1000, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
-- proc_tech_tse_tx_packet(tx_total_header, 103, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
-- proc_tech_tse_tx_packet(tx_total_header, 104, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
-- proc_tech_tse_tx_packet(tx_total_header, 105, g_data_type, c_tx_ready_latency, c_nof_tx_not_valid, st_clk, lcu_tx_en, lcu_tx_siso, lcu_tx_sosi);
tx_end <= '1';
WAIT;
END PROCESS;
p_lcu_receiver : PROCESS
BEGIN
-- . Avalon ST
lcu_rx_siso <= c_dp_siso_hold;
WHILE lcu_init/='0' LOOP WAIT UNTIL rising_edge(st_clk); END LOOP;
-- Verification of multiple rx packets is only supported when all packets
-- are of the same g_data_type, because the rx process can only support
-- one expected result. The proc_tech_tse_rx_packet does not (yet) interpret the
-- actually received packet, it relies on the preset expected total_header.
-- Receive forever
WHILE TRUE LOOP
proc_tech_tse_rx_packet(exp_total_header, g_data_type, st_clk, lcu_rx_sosi, lcu_rx_siso);
END LOOP;
WAIT;
END PROCESS;
-- Wire ethernet cable between lcu and dut
eth_rxp <= TRANSPORT lcu_txp AFTER cable_delay;
lcu_rxp <= TRANSPORT eth_txp AFTER cable_delay;
gen_udp_rx_siso_rdy: FOR i IN 0 TO c_eth_nof_udp_ports-1 GENERATE
udp_rx_siso_arr(i).ready <= '1';
END GENERATE;
dut : ENTITY eth_lib.eth
GENERIC MAP (
g_technology => g_technology_dut,
g_cross_clock_domain => c_cross_clock_domain,
g_frm_discard_en => g_frm_discard_en
)
PORT MAP (
-- Clocks and reset
mm_rst => mm_rst,
mm_clk => mm_clk,
eth_clk => eth_clk,
st_rst => st_rst,
st_clk => st_clk,
-- UDP transmit interfaceg_frm_discard_en
-- . ST sink
udp_tx_snk_in_arr => udp_tx_sosi_arr,
udp_tx_snk_out_arr => udp_tx_siso_arr,
-- UDP receive interface
-- . ST source
udp_rx_src_in_arr => udp_rx_siso_arr,
udp_rx_src_out_arr => udp_rx_sosi_arr,
-- Control Memory Mapped Slaves
tse_sla_in => eth_tse_mosi,
tse_sla_out => eth_tse_miso,
reg_sla_in => eth_reg_mosi,
reg_sla_out => eth_reg_miso,
reg_sla_interrupt => eth_reg_interrupt,
ram_sla_in => eth_ram_mosi,
ram_sla_out => eth_ram_miso,
-- Monitoring
rx_flushed_frm_cnt => rx_pkt_flushed_cnt,
-- PHY interface
eth_txp => eth_txp,
eth_rxp => eth_rxp,
-- LED interface
tse_led => eth_led
);
lcu : ENTITY tech_tse_lib.tech_tse
PORT MAP (
-- Clocks and reset
mm_rst => mm_rst,
mm_clk => mm_clk,
eth_clk => eth_clk,
tx_snk_clk => st_clk,
rx_src_clk => st_clk,
-- Memory Mapped Slave
mm_sla_in => lcu_tse_mosi,
mm_sla_out => lcu_tse_miso,
-- MAC transmit interface
-- . ST sink
tx_snk_in => lcu_tx_sosi,
tx_snk_out => lcu_tx_siso,
-- . MAC specific
tx_mac_in => lcu_tx_mac_in,
tx_mac_out => lcu_tx_mac_out,
-- MAC receive interface
-- . ST Source
rx_src_in => lcu_rx_siso,
rx_src_out => lcu_rx_sosi,
-- . MAC specific
rx_mac_out => lcu_rx_mac_out,
-- PHY interface
eth_txp => lcu_txp,
eth_rxp => lcu_rxp,
tse_led => lcu_led
);
-- Verification
tx_pkt_cnt <= tx_pkt_cnt + 1 WHEN lcu_tx_sosi.sop='1' AND rising_edge(st_clk);
rx_pkt_cnt <= rx_pkt_cnt + 1 WHEN lcu_rx_sosi.eop='1' AND rising_edge(st_clk);
p_rx_end : PROCESS
BEGIN
rx_end <= '0';
WAIT UNTIL tx_end='1';
-- use timeout since tx_end or last received packet to determine rx_end
rx_timeout <= 0;
WHILE rx_end='0' LOOP
rx_timeout <= rx_timeout + 1;
IF lcu_rx_sosi.valid='1' THEN
rx_timeout <= 0;
ELSIF rx_timeout>5000 THEN -- sufficiently large value determined by trial
rx_end <= '1';
END IF;
WAIT UNTIL rising_edge(st_clk);
END LOOP;
--WAIT FOR 10 us;
--rx_end <= '1';
WAIT;
END PROCESS;
p_tb_end : PROCESS
BEGIN
tb_end <= '0';
WAIT UNTIL rx_end='1';
-- Verify that all transmitted packets have been received
IF tx_pkt_cnt=0 THEN
REPORT "No packets were transmitted." SEVERITY ERROR;
ELSIF rx_pkt_cnt=0 THEN
REPORT "No packets were received." SEVERITY ERROR;
ELSIF tx_pkt_cnt/=rx_pkt_cnt + rx_pkt_discarded_cnt + TO_UINT(rx_pkt_flushed_cnt) THEN
REPORT "Not all transmitted packets were received." SEVERITY ERROR;
END IF;
WAIT FOR 1 us;
tb_end <= '1';
IF g_tb_end=FALSE THEN
REPORT "Tb simulation finished." SEVERITY NOTE;
ELSE
REPORT "Tb simulation finished." SEVERITY FAILURE;
END IF;
WAIT;
END PROCESS;
END tb;
-------------------------------------------------------------------------------
--
-- 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/>.
--
-------------------------------------------------------------------------------
-- Purpose: Multi-testbench for eth1g
-- Description:
-- Verify eth1g for different data types
-- Usage:
-- > as 3
-- > run -all
LIBRARY IEEE, technology_lib, tech_tse_lib;
USE IEEE.std_logic_1164.ALL;
USE technology_lib.technology_pkg.ALL;
USE technology_lib.technology_select_pkg.ALL;
USE tech_tse_lib.tb_tech_tse_pkg.ALL;
ENTITY tb_tb_eth1g IS
GENERIC (
g_technology_dut : NATURAL := c_tech_select_default
);
END tb_tb_eth1g;
ARCHITECTURE tb OF tb_tb_eth1g IS
CONSTANT c_technology_lcu : NATURAL := c_tech_select_default;
CONSTANT c_tb_end_vec : STD_LOGIC_VECTOR(15 DOWNTO 0) := (OTHERS=>'1');
SIGNAL tb_end_vec : STD_LOGIC_VECTOR(15 DOWNTO 0) := c_tb_end_vec; -- sufficiently long to fit all tb instances
SIGNAL tb_end : STD_LOGIC := '0';
BEGIN
-- g_technology_dut : NATURAL := c_tech_select_default;
-- g_technology_lcu : NATURAL := c_tech_select_default;
-- g_frm_discard_en : BOOLEAN := TRUE; -- when TRUE discard frame types that would otherwise have to be discarded by the Nios MM master
-- g_flush_test_en : BOOLEAN := FALSE; -- when TRUE send many large frames to enforce flush in eth_buffer
-- g_tb_end : BOOLEAN := TRUE; -- when TRUE then tb_end ends this simulation, else a higher multi-testbench will end the simulation
-- -- g_data_type = c_tb_tech_tse_data_type_symbols = 0
-- -- g_data_type = c_tb_tech_tse_data_type_counter = 1
-- -- g_data_type = c_tb_tech_tse_data_type_arp = 2
-- -- g_data_type = c_tb_tech_tse_data_type_ping = 3
-- -- g_data_type = c_tb_tech_tse_data_type_udp = 4
-- g_data_type : NATURAL := c_tb_tech_tse_data_type_udp
u_use_symbols : ENTITY work.tb_eth1g GENERIC MAP (g_technology_dut, c_technology_lcu, FALSE, FALSE, FALSE, c_tb_tech_tse_data_type_symbols) PORT MAP (tb_end_vec(0));
u_use_counter : ENTITY work.tb_eth1g GENERIC MAP (g_technology_dut, c_technology_lcu, FALSE, FALSE, FALSE, c_tb_tech_tse_data_type_counter) PORT MAP (tb_end_vec(1));
u_use_arp : ENTITY work.tb_eth1g GENERIC MAP (g_technology_dut, c_technology_lcu, TRUE, FALSE, FALSE, c_tb_tech_tse_data_type_arp ) PORT MAP (tb_end_vec(2));
u_use_ping : ENTITY work.tb_eth1g GENERIC MAP (g_technology_dut, c_technology_lcu, TRUE, FALSE, FALSE, c_tb_tech_tse_data_type_ping ) PORT MAP (tb_end_vec(3));
u_use_udp : ENTITY work.tb_eth1g GENERIC MAP (g_technology_dut, c_technology_lcu, TRUE, FALSE, FALSE, c_tb_tech_tse_data_type_udp ) PORT MAP (tb_end_vec(4));
u_use_udp_flush : ENTITY work.tb_eth1g GENERIC MAP (g_technology_dut, c_technology_lcu, TRUE, TRUE, FALSE, c_tb_tech_tse_data_type_udp ) PORT MAP (tb_end_vec(5));
tb_end <= '1' WHEN tb_end_vec=c_tb_end_vec ELSE '0';
p_tb_end : PROCESS
BEGIN
WAIT UNTIL tb_end='1';
WAIT FOR 1 ns;
REPORT "Multi tb simulation finished." SEVERITY FAILURE;
WAIT;
END PROCESS;
END tb;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment