Commit 41e05c0a authored by Grzegorz Daniluk's avatar Grzegorz Daniluk

Merge branch 'proposed_master-ML-BTrain-dev' into proposed_master

parents cbdaa3df e7ba8d5f
......@@ -3,7 +3,8 @@
---------------------------------------------------------------------------------------
-- File : wr_streamers_wb.vhd
-- Author : auto-generated by wbgen2 from wr_streamers_wb.wb
-- Created : Tue May 16 18:11:13 2017
-- Created : Tue Jun 20 08:53:54 2017
-- Version : 0x00000001
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wr_streamers_wb.wb
......@@ -37,6 +38,7 @@ end wr_streamers_wb;
architecture syn of wr_streamers_wb is
signal wr_streamers_ver_id_int : std_logic_vector(31 downto 0);
signal wr_streamers_sscr1_rst_stats_dly0 : std_logic ;
signal wr_streamers_sscr1_rst_stats_int : std_logic ;
signal wr_streamers_sscr1_rst_seq_id_dly0 : std_logic ;
......@@ -73,22 +75,12 @@ signal wr_streamers_dbg_ctrl_start_byte_int : std_logic_vector(7 downto 0);
signal ack_sreg : std_logic_vector(9 downto 0);
signal rddata_reg : std_logic_vector(31 downto 0);
signal wrdata_reg : std_logic_vector(31 downto 0);
signal bwsel_reg : std_logic_vector(3 downto 0);
signal rwaddr_reg : std_logic_vector(5 downto 0);
signal ack_in_progress : std_logic ;
signal wr_int : std_logic ;
signal rd_int : std_logic ;
signal allones : std_logic_vector(31 downto 0);
signal allzeros : std_logic_vector(31 downto 0);
begin
-- Some internal signals assignments. For (foreseen) compatibility with other bus standards.
-- Some internal signals assignments
wrdata_reg <= wb_dat_i;
bwsel_reg <= wb_sel_i;
rd_int <= wb_cyc_i and (wb_stb_i and (not wb_we_i));
wr_int <= wb_cyc_i and (wb_stb_i and wb_we_i);
allones <= (others => '1');
allzeros <= (others => '0');
--
-- Main register bank access process.
process (clk_sys_i, rst_n_i)
......@@ -97,6 +89,7 @@ begin
ack_sreg <= "0000000000";
ack_in_progress <= '0';
rddata_reg <= "00000000000000000000000000000000";
wr_streamers_ver_id_int <= "00000000000000000000000000000001";
wr_streamers_sscr1_rst_stats_int <= '0';
wr_streamers_sscr1_rst_seq_id_int <= '0';
wr_streamers_sscr1_snapshot_stats_int <= '0';
......@@ -143,6 +136,13 @@ begin
if ((wb_cyc_i = '1') and (wb_stb_i = '1')) then
case rwaddr_reg(5 downto 0) is
when "000000" =>
if (wb_we_i = '1') then
wr_streamers_ver_id_int <= wrdata_reg(31 downto 0);
end if;
rddata_reg(31 downto 0) <= wr_streamers_ver_id_int;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "000001" =>
if (wb_we_i = '1') then
wr_streamers_sscr1_rst_stats_int <= wrdata_reg(0);
wr_streamers_sscr1_rst_seq_id_int <= wrdata_reg(1);
......@@ -155,13 +155,13 @@ begin
rddata_reg(31 downto 4) <= regs_i.sscr1_rst_ts_cyc_i;
ack_sreg(2) <= '1';
ack_in_progress <= '1';
when "000001" =>
when "000010" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.sscr2_rst_ts_tai_lsb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "000010" =>
when "000011" =>
if (wb_we_i = '1') then
end if;
rddata_reg(7 downto 0) <= regs_i.sscr3_rst_ts_tai_msb_i;
......@@ -191,7 +191,7 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "000011" =>
when "000100" =>
if (wb_we_i = '1') then
end if;
rddata_reg(27 downto 0) <= regs_i.rx_stat0_rx_latency_max_i;
......@@ -201,7 +201,7 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "000100" =>
when "000101" =>
if (wb_we_i = '1') then
end if;
rddata_reg(27 downto 0) <= regs_i.rx_stat1_rx_latency_min_i;
......@@ -211,79 +211,79 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "000101" =>
when "000110" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.tx_stat2_tx_sent_cnt_lsb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "000110" =>
when "000111" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.tx_stat3_tx_sent_cnt_msb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "000111" =>
when "001000" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.rx_stat4_rx_rcvd_cnt_lsb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "001000" =>
when "001001" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.rx_stat5_rx_rcvd_cnt_msb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "001001" =>
when "001010" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.rx_stat6_rx_loss_cnt_lsb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "001010" =>
when "001011" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.rx_stat7_rx_loss_cnt_msb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "001011" =>
when "001100" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.rx_stat8_rx_lost_block_cnt_lsb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "001100" =>
when "001101" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.rx_stat9_rx_lost_block_cnt_msb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "001101" =>
when "001110" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.rx_stat10_rx_latency_acc_lsb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "001110" =>
when "001111" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.rx_stat11_rx_latency_acc_msb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "001111" =>
when "010000" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.rx_stat12_rx_latency_acc_cnt_lsb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "010000" =>
when "010001" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.rx_stat13_rx_latency_acc_cnt_msb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "010001" =>
when "010010" =>
if (wb_we_i = '1') then
wr_streamers_tx_cfg0_ethertype_int <= wrdata_reg(15 downto 0);
end if;
......@@ -306,14 +306,14 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "010010" =>
when "010011" =>
if (wb_we_i = '1') then
wr_streamers_tx_cfg1_mac_local_lsb_int <= wrdata_reg(31 downto 0);
end if;
rddata_reg(31 downto 0) <= wr_streamers_tx_cfg1_mac_local_lsb_int;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "010011" =>
when "010100" =>
if (wb_we_i = '1') then
wr_streamers_tx_cfg2_mac_local_msb_int <= wrdata_reg(15 downto 0);
end if;
......@@ -336,14 +336,14 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "010100" =>
when "010101" =>
if (wb_we_i = '1') then
wr_streamers_tx_cfg3_mac_target_lsb_int <= wrdata_reg(31 downto 0);
end if;
rddata_reg(31 downto 0) <= wr_streamers_tx_cfg3_mac_target_lsb_int;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "010101" =>
when "010110" =>
if (wb_we_i = '1') then
wr_streamers_tx_cfg4_mac_target_msb_int <= wrdata_reg(15 downto 0);
end if;
......@@ -366,7 +366,7 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "010110" =>
when "010111" =>
if (wb_we_i = '1') then
wr_streamers_tx_cfg5_qtag_ena_int <= wrdata_reg(0);
wr_streamers_tx_cfg5_qtag_vid_int <= wrdata_reg(19 downto 8);
......@@ -393,7 +393,7 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "010111" =>
when "011000" =>
if (wb_we_i = '1') then
wr_streamers_rx_cfg0_ethertype_int <= wrdata_reg(15 downto 0);
wr_streamers_rx_cfg0_accept_broadcast_int <= wrdata_reg(16);
......@@ -418,14 +418,14 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "011000" =>
when "011001" =>
if (wb_we_i = '1') then
wr_streamers_rx_cfg1_mac_local_lsb_int <= wrdata_reg(31 downto 0);
end if;
rddata_reg(31 downto 0) <= wr_streamers_rx_cfg1_mac_local_lsb_int;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "011001" =>
when "011010" =>
if (wb_we_i = '1') then
wr_streamers_rx_cfg2_mac_local_msb_int <= wrdata_reg(15 downto 0);
end if;
......@@ -448,14 +448,14 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "011010" =>
when "011011" =>
if (wb_we_i = '1') then
wr_streamers_rx_cfg3_mac_remote_lsb_int <= wrdata_reg(31 downto 0);
end if;
rddata_reg(31 downto 0) <= wr_streamers_rx_cfg3_mac_remote_lsb_int;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "011011" =>
when "011100" =>
if (wb_we_i = '1') then
wr_streamers_rx_cfg4_mac_remote_msb_int <= wrdata_reg(15 downto 0);
end if;
......@@ -478,7 +478,7 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "011100" =>
when "011101" =>
if (wb_we_i = '1') then
wr_streamers_rx_cfg5_fixed_latency_int <= wrdata_reg(27 downto 0);
end if;
......@@ -489,7 +489,7 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "011101" =>
when "011110" =>
if (wb_we_i = '1') then
wr_streamers_cfg_or_tx_ethtype_int <= wrdata_reg(0);
wr_streamers_cfg_or_tx_mac_loc_int <= wrdata_reg(1);
......@@ -536,7 +536,7 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "011110" =>
when "011111" =>
if (wb_we_i = '1') then
wr_streamers_dbg_ctrl_mux_int <= wrdata_reg(0);
wr_streamers_dbg_ctrl_start_byte_int <= wrdata_reg(15 downto 8);
......@@ -568,13 +568,13 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "011111" =>
when "100000" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.dbg_data_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "100000" =>
when "100001" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.dummy_dummy_i;
......@@ -593,6 +593,8 @@ begin
-- Drive the data output bus
wb_dat_o <= rddata_reg;
-- Version identifier
regs_o.ver_id_o <= wr_streamers_ver_id_int;
-- Reset statistics
process (clk_sys_i, rst_n_i)
begin
......
......@@ -28,6 +28,7 @@ peripheral {
-----------------------------------------------------------------";
prefix = "wr_streamers";
hdl_entity = "wr_streamers_wb";
version= 1;
reg {
name = "Statistics status and ctrl register";
......
......@@ -3,7 +3,8 @@
---------------------------------------------------------------------------------------
-- File : wr_streamers_wbgen2_pkg.vhd
-- Author : auto-generated by wbgen2 from wr_streamers_wb.wb
-- Created : Tue May 16 18:11:13 2017
-- Created : Tue Jun 20 08:53:54 2017
-- Version : 0x00000001
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wr_streamers_wb.wb
......@@ -68,6 +69,7 @@ package wr_streamers_wbgen2_pkg is
-- Output registers (WB slave -> user design)
type t_wr_streamers_out_registers is record
ver_id_o : std_logic_vector(31 downto 0);
sscr1_rst_stats_o : std_logic;
sscr1_rst_seq_id_o : std_logic;
sscr1_snapshot_stats_o : std_logic;
......@@ -102,6 +104,7 @@ package wr_streamers_wbgen2_pkg is
end record;
constant c_wr_streamers_out_registers_init_value: t_wr_streamers_out_registers := (
ver_id_o => (others => '0'),
sscr1_rst_stats_o => '0',
sscr1_rst_seq_id_o => '0',
sscr1_snapshot_stats_o => '0',
......
......@@ -182,7 +182,7 @@ architecture rtl of xrx_streamer is
signal is_vlan : std_logic;
constant c_fixed_latency_zero : unsigned(27 downto 0) := (others => '0');
constant c_timestamper_delay : unsigned(27 downto 0) := to_unsigned(3, 28); -- cycles
constant c_timestamper_delay : unsigned(27 downto 0) := to_unsigned(12, 28); -- cycles
begin -- rtl
......
......@@ -3,7 +3,8 @@
---------------------------------------------------------------------------------------
-- File : wrc_diags_pkg.vhd
-- Author : auto-generated by wbgen2 from wrc_diags_wb.wb
-- Created : Tue Apr 25 12:14:42 2017
-- Created : Tue Jun 20 09:59:03 2017
-- Version : 0x00000001
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wrc_diags_wb.wb
......@@ -70,10 +71,12 @@ package wrc_diags_wbgen2_pkg is
-- Output registers (WB slave -> user design)
type t_wrc_diags_out_registers is record
ver_id_o : std_logic_vector(31 downto 0);
ctrl_data_snapshot_o : std_logic;
end record;
constant c_wrc_diags_out_registers_init_value: t_wrc_diags_out_registers := (
ver_id_o => (others => '0'),
ctrl_data_snapshot_o => '0'
);
function "or" (left, right: t_wrc_diags_in_registers) return t_wrc_diags_in_registers;
......
......@@ -3,7 +3,8 @@
---------------------------------------------------------------------------------------
-- File : wrc_diags_wb.vhd
-- Author : auto-generated by wbgen2 from wrc_diags_wb.wb
-- Created : Tue Apr 25 12:14:42 2017
-- Created : Tue Jun 20 09:59:03 2017
-- Version : 0x00000001
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wrc_diags_wb.wb
......@@ -37,26 +38,17 @@ end wrc_diags_wb;
architecture syn of wrc_diags_wb is
signal wrc_diags_ver_id_int : std_logic_vector(31 downto 0);
signal wrc_diags_ctrl_data_snapshot_int : std_logic ;
signal ack_sreg : std_logic_vector(9 downto 0);
signal rddata_reg : std_logic_vector(31 downto 0);
signal wrdata_reg : std_logic_vector(31 downto 0);
signal bwsel_reg : std_logic_vector(3 downto 0);
signal rwaddr_reg : std_logic_vector(4 downto 0);
signal ack_in_progress : std_logic ;
signal wr_int : std_logic ;
signal rd_int : std_logic ;
signal allones : std_logic_vector(31 downto 0);
signal allzeros : std_logic_vector(31 downto 0);
begin
-- Some internal signals assignments. For (foreseen) compatibility with other bus standards.
-- Some internal signals assignments
wrdata_reg <= wb_dat_i;
bwsel_reg <= wb_sel_i;
rd_int <= wb_cyc_i and (wb_stb_i and (not wb_we_i));
wr_int <= wb_cyc_i and (wb_stb_i and wb_we_i);
allones <= (others => '1');
allzeros <= (others => '0');
--
-- Main register bank access process.
process (clk_sys_i, rst_n_i)
......@@ -65,6 +57,7 @@ begin
ack_sreg <= "0000000000";
ack_in_progress <= '0';
rddata_reg <= "00000000000000000000000000000000";
wrc_diags_ver_id_int <= "00000000000000000000000000000001";
wrc_diags_ctrl_data_snapshot_int <= '0';
elsif rising_edge(clk_sys_i) then
-- advance the ACK generator shift register
......@@ -79,6 +72,13 @@ begin
if ((wb_cyc_i = '1') and (wb_stb_i = '1')) then
case rwaddr_reg(4 downto 0) is
when "00000" =>
if (wb_we_i = '1') then
wrc_diags_ver_id_int <= wrdata_reg(31 downto 0);
end if;
rddata_reg(31 downto 0) <= wrc_diags_ver_id_int;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "00001" =>
if (wb_we_i = '1') then
wrc_diags_ctrl_data_snapshot_int <= wrdata_reg(8);
end if;
......@@ -116,7 +116,7 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "00001" =>
when "00010" =>
if (wb_we_i = '1') then
end if;
rddata_reg(0) <= regs_i.wdiag_sstat_wr_mode_i;
......@@ -150,7 +150,7 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "00010" =>
when "00011" =>
if (wb_we_i = '1') then
end if;
rddata_reg(0) <= regs_i.wdiag_pstat_link_i;
......@@ -187,7 +187,7 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "00011" =>
when "00100" =>
if (wb_we_i = '1') then
end if;
rddata_reg(7 downto 0) <= regs_i.wdiag_ptpstat_ptpstate_i;
......@@ -217,7 +217,7 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "00100" =>
when "00101" =>
if (wb_we_i = '1') then
end if;
rddata_reg(7 downto 0) <= regs_i.wdiag_astat_aux_i;
......@@ -247,85 +247,85 @@ begin
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "00101" =>
when "00110" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.wdiag_txfcnt_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "00110" =>
when "00111" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.wdiag_rxfcnt_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "00111" =>
when "01000" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.wdiag_sec_msb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "01000" =>
when "01001" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.wdiag_sec_lsb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "01001" =>
when "01010" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.wdiag_ns_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "01010" =>
when "01011" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.wdiag_mu_msb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "01011" =>
when "01100" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.wdiag_mu_lsb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "01100" =>
when "01101" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.wdiag_dms_msb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "01101" =>
when "01110" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.wdiag_dms_lsb_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "01110" =>
when "01111" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.wdiag_asym_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "01111" =>
when "10000" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.wdiag_cko_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "10000" =>
when "10001" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.wdiag_setp_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "10001" =>
when "10010" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.wdiag_ucnt_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "10010" =>
when "10011" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.wdiag_temp_i;
......@@ -344,6 +344,8 @@ begin
-- Drive the data output bus
wb_dat_o <= rddata_reg;
-- Version identifier
regs_o.ver_id_o <= wrc_diags_ver_id_int;
-- WR DIAG data valid
-- WR DIAG data snapshot
regs_o.ctrl_data_snapshot_o <= wrc_diags_ctrl_data_snapshot_int;
......
......@@ -5,6 +5,7 @@ peripheral {
description = "Diagnostics information accessible via WR";
prefix = "wrc_diags";
hdl_entity = "wrc_diags_wb";
version = 1;
reg {
name = "Ctrl";
......
`define ADDR_WR_STREAMERS_SSCR1 8'h0
`define WBGEN2_WR_STREAMERS_VERSION 32'h00000001
`define ADDR_WR_STREAMERS_VER 8'h0
`define WR_STREAMERS_VER_ID_OFFSET 0
`define WR_STREAMERS_VER_ID 32'hffffffff
`define ADDR_WR_STREAMERS_SSCR1 8'h4
`define WR_STREAMERS_SSCR1_RST_STATS_OFFSET 0
`define WR_STREAMERS_SSCR1_RST_STATS 32'h00000001
`define WR_STREAMERS_SSCR1_RST_SEQ_ID_OFFSET 1
......@@ -9,99 +13,99 @@
`define WR_STREAMERS_SSCR1_RX_LATENCY_ACC_OVERFLOW 32'h00000008
`define WR_STREAMERS_SSCR1_RST_TS_CYC_OFFSET 4
`define WR_STREAMERS_SSCR1_RST_TS_CYC 32'hfffffff0
`define ADDR_WR_STREAMERS_SSCR2 8'h4
`define ADDR_WR_STREAMERS_SSCR2 8'h8
`define WR_STREAMERS_SSCR2_RST_TS_TAI_LSB_OFFSET 0
`define WR_STREAMERS_SSCR2_RST_TS_TAI_LSB 32'hffffffff
`define ADDR_WR_STREAMERS_SSCR3 8'h8
`define ADDR_WR_STREAMERS_SSCR3 8'hc
`define WR_STREAMERS_SSCR3_RST_TS_TAI_MSB_OFFSET 0
`define WR_STREAMERS_SSCR3_RST_TS_TAI_MSB 32'h000000ff
`define ADDR_WR_STREAMERS_RX_STAT0 8'hc
`define ADDR_WR_STREAMERS_RX_STAT0 8'h10
`define WR_STREAMERS_RX_STAT0_RX_LATENCY_MAX_OFFSET 0
`define WR_STREAMERS_RX_STAT0_RX_LATENCY_MAX 32'h0fffffff
`define ADDR_WR_STREAMERS_RX_STAT1 8'h10
`define ADDR_WR_STREAMERS_RX_STAT1 8'h14
`define WR_STREAMERS_RX_STAT1_RX_LATENCY_MIN_OFFSET 0
`define WR_STREAMERS_RX_STAT1_RX_LATENCY_MIN 32'h0fffffff
`define ADDR_WR_STREAMERS_TX_STAT2 8'h14
`define ADDR_WR_STREAMERS_TX_STAT2 8'h18
`define WR_STREAMERS_TX_STAT2_TX_SENT_CNT_LSB_OFFSET 0
`define WR_STREAMERS_TX_STAT2_TX_SENT_CNT_LSB 32'hffffffff
`define ADDR_WR_STREAMERS_TX_STAT3 8'h18
`define ADDR_WR_STREAMERS_TX_STAT3 8'h1c
`define WR_STREAMERS_TX_STAT3_TX_SENT_CNT_MSB_OFFSET 0
`define WR_STREAMERS_TX_STAT3_TX_SENT_CNT_MSB 32'hffffffff
`define ADDR_WR_STREAMERS_RX_STAT4 8'h1c
`define ADDR_WR_STREAMERS_RX_STAT4 8'h20
`define WR_STREAMERS_RX_STAT4_RX_RCVD_CNT_LSB_OFFSET 0
`define WR_STREAMERS_RX_STAT4_RX_RCVD_CNT_LSB 32'hffffffff
`define ADDR_WR_STREAMERS_RX_STAT5 8'h20
`define ADDR_WR_STREAMERS_RX_STAT5 8'h24
`define WR_STREAMERS_RX_STAT5_RX_RCVD_CNT_MSB_OFFSET 0
`define WR_STREAMERS_RX_STAT5_RX_RCVD_CNT_MSB 32'hffffffff
`define ADDR_WR_STREAMERS_RX_STAT6 8'h24
`define ADDR_WR_STREAMERS_RX_STAT6 8'h28
`define WR_STREAMERS_RX_STAT6_RX_LOSS_CNT_LSB_OFFSET 0
`define WR_STREAMERS_RX_STAT6_RX_LOSS_CNT_LSB 32'hffffffff
`define ADDR_WR_STREAMERS_RX_STAT7 8'h28
`define ADDR_WR_STREAMERS_RX_STAT7 8'h2c
`define WR_STREAMERS_RX_STAT7_RX_LOSS_CNT_MSB_OFFSET 0
`define WR_STREAMERS_RX_STAT7_RX_LOSS_CNT_MSB 32'hffffffff
`define ADDR_WR_STREAMERS_RX_STAT8 8'h2c
`define ADDR_WR_STREAMERS_RX_STAT8 8'h30
`define WR_STREAMERS_RX_STAT8_RX_LOST_BLOCK_CNT_LSB_OFFSET 0
`define WR_STREAMERS_RX_STAT8_RX_LOST_BLOCK_CNT_LSB 32'hffffffff
`define ADDR_WR_STREAMERS_RX_STAT9 8'h30
`define ADDR_WR_STREAMERS_RX_STAT9 8'h34
`define WR_STREAMERS_RX_STAT9_RX_LOST_BLOCK_CNT_MSB_OFFSET 0
`define WR_STREAMERS_RX_STAT9_RX_LOST_BLOCK_CNT_MSB 32'hffffffff
`define ADDR_WR_STREAMERS_RX_STAT10 8'h34
`define ADDR_WR_STREAMERS_RX_STAT10 8'h38
`define WR_STREAMERS_RX_STAT10_RX_LATENCY_ACC_LSB_OFFSET 0
`define WR_STREAMERS_RX_STAT10_RX_LATENCY_ACC_LSB 32'hffffffff
`define ADDR_WR_STREAMERS_RX_STAT11 8'h38
`define ADDR_WR_STREAMERS_RX_STAT11 8'h3c
`define WR_STREAMERS_RX_STAT11_RX_LATENCY_ACC_MSB_OFFSET 0
`define WR_STREAMERS_RX_STAT11_RX_LATENCY_ACC_MSB 32'hffffffff
`define ADDR_WR_STREAMERS_RX_STAT12 8'h3c
`define ADDR_WR_STREAMERS_RX_STAT12 8'h40
`define WR_STREAMERS_RX_STAT12_RX_LATENCY_ACC_CNT_LSB_OFFSET 0
`define WR_STREAMERS_RX_STAT12_RX_LATENCY_ACC_CNT_LSB 32'hffffffff
`define ADDR_WR_STREAMERS_RX_STAT13 8'h40
`define ADDR_WR_STREAMERS_RX_STAT13 8'h44
`define WR_STREAMERS_RX_STAT13_RX_LATENCY_ACC_CNT_MSB_OFFSET 0
`define WR_STREAMERS_RX_STAT13_RX_LATENCY_ACC_CNT_MSB 32'hffffffff
`define ADDR_WR_STREAMERS_TX_CFG0 8'h44
`define ADDR_WR_STREAMERS_TX_CFG0 8'h48
`define WR_STREAMERS_TX_CFG0_ETHERTYPE_OFFSET 0
`define WR_STREAMERS_TX_CFG0_ETHERTYPE 32'h0000ffff
`define ADDR_WR_STREAMERS_TX_CFG1 8'h48
`define ADDR_WR_STREAMERS_TX_CFG1 8'h4c
`define WR_STREAMERS_TX_CFG1_MAC_LOCAL_LSB_OFFSET 0
`define WR_STREAMERS_TX_CFG1_MAC_LOCAL_LSB 32'hffffffff
`define ADDR_WR_STREAMERS_TX_CFG2 8'h4c
`define ADDR_WR_STREAMERS_TX_CFG2 8'h50
`define WR_STREAMERS_TX_CFG2_MAC_LOCAL_MSB_OFFSET 0
`define WR_STREAMERS_TX_CFG2_MAC_LOCAL_MSB 32'h0000ffff
`define ADDR_WR_STREAMERS_TX_CFG3 8'h50
`define ADDR_WR_STREAMERS_TX_CFG3 8'h54
`define WR_STREAMERS_TX_CFG3_MAC_TARGET_LSB_OFFSET 0
`define WR_STREAMERS_TX_CFG3_MAC_TARGET_LSB 32'hffffffff
`define ADDR_WR_STREAMERS_TX_CFG4 8'h54
`define ADDR_WR_STREAMERS_TX_CFG4 8'h58
`define WR_STREAMERS_TX_CFG4_MAC_TARGET_MSB_OFFSET 0
`define WR_STREAMERS_TX_CFG4_MAC_TARGET_MSB 32'h0000ffff
`define ADDR_WR_STREAMERS_TX_CFG5 8'h58
`define ADDR_WR_STREAMERS_TX_CFG5 8'h5c
`define WR_STREAMERS_TX_CFG5_QTAG_ENA_OFFSET 0
`define WR_STREAMERS_TX_CFG5_QTAG_ENA 32'h00000001
`define WR_STREAMERS_TX_CFG5_QTAG_VID_OFFSET 8
`define WR_STREAMERS_TX_CFG5_QTAG_VID 32'h000fff00
`define WR_STREAMERS_TX_CFG5_QTAG_PRIO_OFFSET 24
`define WR_STREAMERS_TX_CFG5_QTAG_PRIO 32'h07000000
`define ADDR_WR_STREAMERS_RX_CFG0 8'h5c
`define ADDR_WR_STREAMERS_RX_CFG0 8'h60
`define WR_STREAMERS_RX_CFG0_ETHERTYPE_OFFSET 0
`define WR_STREAMERS_RX_CFG0_ETHERTYPE 32'h0000ffff
`define WR_STREAMERS_RX_CFG0_ACCEPT_BROADCAST_OFFSET 16
`define WR_STREAMERS_RX_CFG0_ACCEPT_BROADCAST 32'h00010000
`define WR_STREAMERS_RX_CFG0_FILTER_REMOTE_OFFSET 17
`define WR_STREAMERS_RX_CFG0_FILTER_REMOTE 32'h00020000
`define ADDR_WR_STREAMERS_RX_CFG1 8'h60
`define ADDR_WR_STREAMERS_RX_CFG1 8'h64
`define WR_STREAMERS_RX_CFG1_MAC_LOCAL_LSB_OFFSET 0
`define WR_STREAMERS_RX_CFG1_MAC_LOCAL_LSB 32'hffffffff
`define ADDR_WR_STREAMERS_RX_CFG2 8'h64
`define ADDR_WR_STREAMERS_RX_CFG2 8'h68
`define WR_STREAMERS_RX_CFG2_MAC_LOCAL_MSB_OFFSET 0
`define WR_STREAMERS_RX_CFG2_MAC_LOCAL_MSB 32'h0000ffff
`define ADDR_WR_STREAMERS_RX_CFG3 8'h68
`define ADDR_WR_STREAMERS_RX_CFG3 8'h6c
`define WR_STREAMERS_RX_CFG3_MAC_REMOTE_LSB_OFFSET 0
`define WR_STREAMERS_RX_CFG3_MAC_REMOTE_LSB 32'hffffffff
`define ADDR_WR_STREAMERS_RX_CFG4 8'h6c
`define ADDR_WR_STREAMERS_RX_CFG4 8'h70
`define WR_STREAMERS_RX_CFG4_MAC_REMOTE_MSB_OFFSET 0
`define WR_STREAMERS_RX_CFG4_MAC_REMOTE_MSB 32'h0000ffff
`define ADDR_WR_STREAMERS_RX_CFG5 8'h70
`define ADDR_WR_STREAMERS_RX_CFG5 8'h74
`define WR_STREAMERS_RX_CFG5_FIXED_LATENCY_OFFSET 0
`define WR_STREAMERS_RX_CFG5_FIXED_LATENCY 32'h0fffffff
`define ADDR_WR_STREAMERS_CFG 8'h74
`define ADDR_WR_STREAMERS_CFG 8'h78
`define WR_STREAMERS_CFG_OR_TX_ETHTYPE_OFFSET 0
`define WR_STREAMERS_CFG_OR_TX_ETHTYPE 32'h00000001
`define WR_STREAMERS_CFG_OR_TX_MAC_LOC_OFFSET 1
......@@ -122,12 +126,12 @@
`define WR_STREAMERS_CFG_OR_RX_FTR_REMOTE 32'h00100000
`define WR_STREAMERS_CFG_OR_RX_FIX_LAT_OFFSET 21
`define WR_STREAMERS_CFG_OR_RX_FIX_LAT 32'h00200000
`define ADDR_WR_STREAMERS_DBG_CTRL 8'h78
`define ADDR_WR_STREAMERS_DBG_CTRL 8'h7c
`define WR_STREAMERS_DBG_CTRL_MUX_OFFSET 0
`define WR_STREAMERS_DBG_CTRL_MUX 32'h00000001
`define WR_STREAMERS_DBG_CTRL_START_BYTE_OFFSET 8
`define WR_STREAMERS_DBG_CTRL_START_BYTE 32'h0000ff00
`define ADDR_WR_STREAMERS_DBG_DATA 8'h7c
`define ADDR_WR_STREAMERS_DUMMY 8'h80
`define ADDR_WR_STREAMERS_DBG_DATA 8'h80
`define ADDR_WR_STREAMERS_DUMMY 8'h84
`define WR_STREAMERS_DUMMY_DUMMY_OFFSET 0
`define WR_STREAMERS_DUMMY_DUMMY 32'hffffffff
`define ADDR_WRC_DIAGS_CTRL 7'h0
`define WBGEN2_WRC_DIAGS_VERSION 32'h00000001
`define ADDR_WRC_DIAGS_VER 7'h0
`define WRC_DIAGS_VER_ID_OFFSET 0
`define WRC_DIAGS_VER_ID 32'hffffffff
`define ADDR_WRC_DIAGS_CTRL 7'h4
`define WRC_DIAGS_CTRL_DATA_VALID_OFFSET 0
`define WRC_DIAGS_CTRL_DATA_VALID 32'h00000001
`define WRC_DIAGS_CTRL_DATA_SNAPSHOT_OFFSET 8
`define WRC_DIAGS_CTRL_DATA_SNAPSHOT 32'h00000100
`define ADDR_WRC_DIAGS_WDIAG_SSTAT 7'h4
`define ADDR_WRC_DIAGS_WDIAG_SSTAT 7'h8
`define WRC_DIAGS_WDIAG_SSTAT_WR_MODE_OFFSET 0
`define WRC_DIAGS_WDIAG_SSTAT_WR_MODE 32'h00000001
`define WRC_DIAGS_WDIAG_SSTAT_SERVOSTATE_OFFSET 8
`define WRC_DIAGS_WDIAG_SSTAT_SERVOSTATE 32'h00000f00
`define ADDR_WRC_DIAGS_WDIAG_PSTAT 7'h8
`define ADDR_WRC_DIAGS_WDIAG_PSTAT 7'hc
`define WRC_DIAGS_WDIAG_PSTAT_LINK_OFFSET 0
`define WRC_DIAGS_WDIAG_PSTAT_LINK 32'h00000001
`define WRC_DIAGS_WDIAG_PSTAT_LOCKED_OFFSET 1
`define WRC_DIAGS_WDIAG_PSTAT_LOCKED 32'h00000002
`define ADDR_WRC_DIAGS_WDIAG_PTPSTAT 7'hc
`define ADDR_WRC_DIAGS_WDIAG_PTPSTAT 7'h10
`define WRC_DIAGS_WDIAG_PTPSTAT_PTPSTATE_OFFSET 0
`define WRC_DIAGS_WDIAG_PTPSTAT_PTPSTATE 32'h000000ff
`define ADDR_WRC_DIAGS_WDIAG_ASTAT 7'h10
`define ADDR_WRC_DIAGS_WDIAG_ASTAT 7'h14
`define WRC_DIAGS_WDIAG_ASTAT_AUX_OFFSET 0
`define WRC_DIAGS_WDIAG_ASTAT_AUX 32'h000000ff
`define ADDR_WRC_DIAGS_WDIAG_TXFCNT 7'h14
`define ADDR_WRC_DIAGS_WDIAG_RXFCNT 7'h18
`define ADDR_WRC_DIAGS_WDIAG_SEC_MSB 7'h1c
`define ADDR_WRC_DIAGS_WDIAG_SEC_LSB 7'h20
`define ADDR_WRC_DIAGS_WDIAG_NS 7'h24
`define ADDR_WRC_DIAGS_WDIAG_MU_MSB 7'h28
`define ADDR_WRC_DIAGS_WDIAG_MU_LSB 7'h2c
`define ADDR_WRC_DIAGS_WDIAG_DMS_MSB 7'h30
`define ADDR_WRC_DIAGS_WDIAG_DMS_LSB 7'h34
`define ADDR_WRC_DIAGS_WDIAG_ASYM 7'h38
`define ADDR_WRC_DIAGS_WDIAG_CKO 7'h3c
`define ADDR_WRC_DIAGS_WDIAG_SETP 7'h40
`define ADDR_WRC_DIAGS_WDIAG_UCNT 7'h44
`define ADDR_WRC_DIAGS_WDIAG_TEMP 7'h48
`define ADDR_WRC_DIAGS_WDIAG_TXFCNT 7'h18
`define ADDR_WRC_DIAGS_WDIAG_RXFCNT 7'h1c
`define ADDR_WRC_DIAGS_WDIAG_SEC_MSB 7'h20
`define ADDR_WRC_DIAGS_WDIAG_SEC_LSB 7'h24
`define ADDR_WRC_DIAGS_WDIAG_NS 7'h28
`define ADDR_WRC_DIAGS_WDIAG_MU_MSB 7'h2c
`define ADDR_WRC_DIAGS_WDIAG_MU_LSB 7'h30
`define ADDR_WRC_DIAGS_WDIAG_DMS_MSB 7'h34
`define ADDR_WRC_DIAGS_WDIAG_DMS_LSB 7'h38
`define ADDR_WRC_DIAGS_WDIAG_ASYM 7'h3c
`define ADDR_WRC_DIAGS_WDIAG_CKO 7'h40
`define ADDR_WRC_DIAGS_WDIAG_SETP 7'h44
`define ADDR_WRC_DIAGS_WDIAG_UCNT 7'h48
`define ADDR_WRC_DIAGS_WDIAG_TEMP 7'h4c
......@@ -3,6 +3,8 @@
TB_DIRS=wr_minic
TB_DIRS+=wrc_core
TB_DIRS+=wr_streamers/streamers_multi_test
test_results_xml=test_results.xml
.PHONY: $(TB_DIRS)
......
interface IWishboneLink;
parameter g_data_width = 32;
parameter g_addr_width = 32;
wire [g_addr_width - 1 : 0] adr;
wire [g_data_width - 1 : 0] dat_o;
wire [g_data_width - 1 : 0] dat_i;
wire [(g_data_width/8)-1 : 0] sel;
wire ack;
wire stall;
wire err;
wire rty;
wire cyc;
wire stb;
wire we;
modport slave
(
output adr,
output dat_o,
input dat_i,
output sel,
output cyc,
output stb,
output we,
input ack,
input stall,
input err,
input rty
);
modport master
(
input adr,
input dat_o,
output dat_i,
input sel,
input cyc,
input stb,
input we,
output ack,
output stall,
output err,
output rty
);
endinterface // IWishboneLink
//-----------------------------------------------------------------------------
// Title : WR streamers testbench
// Project : White Rabbit Cores
// URL : http://www.ohwr.org/projects/wr-cores/wiki/WR_Streamers
//-----------------------------------------------------------------------------
// File : main.sv
// Author(s) : Tomasz Wlostosky,
// Extended by Denia Bouhired <denia.bouhired@cern.ch>
// Company : CERN (BE-CO-HT)
// Created : 2017-04-28
//-----------------------------------------------------------------------------
// Description:
//
//
//-----------------------------------------------------------------------------
//
// Copyright (c) 2017 CERN
//
// This source file is free software; you can redistribute it
// and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any
// later version.
//
// This source 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 Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General
// Public License along with this source; if not, download it
// from http://www.gnu.org/licenses/lgpl-2.1.html
//
//-----------------------------------------------------------------------------
`include "../../../sim/if_wb_link.svh"
// `include "./tb_wr_fabric_link_control.sv"
`timescale 1ns/1ns
module main;
/////////////////////////////////////////////////////////////////////////////
// Parameters
/////////////////////////////////////////////////////////////////////////////
// Size of data record to be used by the streamers.
// In this case, a 64-bit word.
parameter g_word_width = 64;
// Min and max block size
parameter g_block_size_min = 1;
parameter g_block_size_max = 5;
// Min and max frame size
parameter g_frame_size_min = 1;
parameter g_frame_size_max = 3;
// MAC address of the TX side
parameter bit [47:0] g_mac_tx = 48'h112233445566;
// MAC address of the RX side
parameter bit [47:0] g_mac_rx = 48'hcafebabedead;
// Ethertype for distinguishing streamer frames. Default accepted by WRPC core.
parameter bit [15:0] g_ethertype = 16'hdbff;
// 16-bit data, 2-bit address Wishbone bus that connects the WR MAC interfaces
// of both streamers
IWishboneLink #(16, 2) mac();
logic [1 : 0] adr_d1;
logic [1 : 0] sel_d1 ;
logic cyc_d1;
logic stb_d1;
logic we_d1 ;
logic [1 : 0] adr;
logic [1 : 0] sel ;
logic cyc;
logic stb;
logic we;
// Clock & reset
reg clk = 0;
reg rst_n = 0;
// TX Streamer signals
reg tx_streamer_dvalid = 0;
reg [g_word_width-1:0] tx_streamer_data = 0;
//wire[15:0] data_from_tx= 0;
reg tx_streamer_last = 0;
reg tx_flush = 0;
wire tx_streamer_dreq;
wire tx_frame_sent;
// RX Streamer signals
reg rx_streamer_dreq = 0;
wire [g_word_width-1:0] rx_streamer_data;
wire rx_streamer_dvalid;
wire rx_streamer_lost_blks;
wire rx_streamer_lost_frm;
wire [14:0] rx_streamer_lost_frm_cnt;
wire rx_streamer_first;
wire rx_streamer_last;
wire [27:0] rx_latency;
wire rx_latency_valid;
wire rx_frame_received;
// Fake White Rabbit reference clock (125 MHz) and cycle counter (we don't use
// TAI counter as the latency never exceeds 1 second...)
reg clk_ref = 0;
reg [27:0] tm_cycle_counter = 0;
// Currently transmitted counter value
integer tx_counter_val = 10;
//Seed for random generator
int seed = 0;
// Wishbone link interface
bit [15 : 0] data_from_tx;
logic [15 : 0] data_to_rx ;
logic tx_wb_cyc, rx_wb_cyc;
logic tx_wb_stb, rx_wb_stb;
logic tx_wb_ack;
logic tx_wb_stall;
wire rx_wb_stall;
wire rx_wb_ack;
/////////////////////////////////////////////////////////////////////////////
// Initialise and set, reset, clocks and clk counter
/////////////////////////////////////////////////////////////////////////////
initial
begin
#100 rst_n = 1;
end;
always #10 clk <= ~clk;
always #4ns clk_ref <= ~clk_ref; //generate 125 MHz WR Clock
always@(posedge clk_ref) tm_cycle_counter <= tm_cycle_counter + 1;
/////////////////////////////////////////////////////////////////////////////
// Struct definition
/////////////////////////////////////////////////////////////////////////////
typedef struct{ bit[g_word_width-1:0] words[$];
int wrd_cnt[$];
bit[g_word_width-1:0] first_wrd;
bit[g_word_width-1:0] last_wrd;
bit dropped;
} block_t; //block is a number of words with info about first
// and last
typedef struct{ block_t blocks[$];
} streamer_frame_t; //frame contains a collection of blocks
// Transfer queue. Used to pass sent data to the verification process.
block_t tx_blk_queue[$];
streamer_frame_t tx_frm_queue[$]; /////////////////////////////////////////////////////////////////////////////
// Task definitions
/////////////////////////////////////////////////////////////////////////////
// Generate a block of data words of random size, containing subsequent
// numbers
/////////////////////////////////////////////////////////////////////////////
task automatic generate_block(ref block_t blk);
int size = $dist_uniform(seed, g_block_size_min, g_block_size_max);
int i;
for(i = 0; i<size; i++)
begin
if (i == 0)
blk.first_wrd = tx_counter_val; // Copy first word
if (i == size-1)
blk.last_wrd = tx_counter_val; // Copy last word
blk.words.push_back(tx_counter_val++); //
if (i == 0 || i==size-1)
blk.wrd_cnt.push_back(i+1);// first or last words
else
blk.wrd_cnt.push_back(0); // All other words
end //for loop
endtask // generate_block
////////////////////////////////////////////////////////
task automatic generate_frame(ref streamer_frame_t frm);
int size = $dist_uniform(seed, g_frame_size_min, g_frame_size_max);
int i;
block_t blk;
for(i = 0; i<size; i++)
begin
blk.words = {};
blk.wrd_cnt = {};
generate_block(blk);
frm.blocks.push_back(blk);
end
endtask
// Sends out a data block (blk) by driving TX_(DVALID, DATA, LAST) lines
// of the TX streamer
/////////////////////////////////////////////////////////////////////////////
task automatic send_block(ref block_t blk);
int i = 0;
////$display("Sending block of %d words...", blk.words.data.size());
while(i < blk.words.size())
begin
if(tx_streamer_dreq) begin
// assert the TX_LAST line on the last word in the current block
tx_streamer_last <= (i == (blk.words.size() - 1)) ? 1 : 0;
tx_streamer_data <= blk.words[i];
//$display("Data to be sent is %d*****\n", tx_streamer_data);
tx_streamer_dvalid <= 1;
i++;
end else
tx_streamer_dvalid <= 0;
@(posedge clk);
end // while (i < blk.words.data.size())
tx_streamer_dvalid <= 0;
tx_streamer_last <= 0;
endtask // send_block
///////////////////////////////////////////////////////////////////
task automatic send_frame(ref streamer_frame_t frm);
int i = 0;
while (i < frm.blocks.size()) begin
send_block(frm.blocks[i]);
i++;
end
tx_flush <= 1;
@(posedge clk);
tx_flush <= 0;
endtask
///////////////////////////////////////////////////////////////////
// WISHBONE LINK CONTROL
///////////////////////////////////////////////////////////////////
//Continuous assignements to WR fabric signals
logic [ 15 : 0] corrupt_mask = 16'h0000;
logic drop_frm = 0;
logic link_ok= 1;
logic delay_link= 0;
task automatic link_good ();
int frm_counter = 0;
link_ok = 1;
corrupt_mask = 16'h0000;
drop_frm = 0;
delay_link= 0;
frm_counter=0;
while (frm_counter < 3 ) begin
@(posedge tx_wb_cyc) //at every new frame
frm_counter ++;
end
endtask;
task automatic corrupt_data ();
int i, j, n;
int frm_counter = 0;
corrupt_mask = 16'h0000;
link_ok= 0;
n={$random} % 2; //number of frames to be corrupted
//corrupt = ({$random} % 1000 < 500) ? 1 : 0;
// break_bit = ({$random} % 100 <1) ? 1 : 0;
// while (frm_counter < 3 )
// begin
j = {$random} % 15;
$display("=====BIT FLIP================");
@(negedge rx_frame_received)
corrupt_mask [j] = ~corrupt_mask [j];
@(negedge rx_wb_ack) link_good ();
// end
endtask //corrupt_data
task automatic drop_frame ();
int n, i;
link_ok= 0;
n={$random} % 5; //number of frames to be dropped
// drop_or_delay = 0;// {$random} % 1;
for (i=0; i<n; i++)
begin
@(negedge tx_wb_cyc)
drop_frm = 1;
end
@(negedge tx_wb_cyc)
drop_frm = 0;
endtask //drop_frame
// end
task automatic delay_frame ();
link_ok= 0;
delay_link = 0;
// fork begin
wait (rx_wb_stall == 1) //to avoid changes at startup
//----------Random stall asserted------------------------------
// delay_link = ({$random} % 10 < 2) ? 1 : 0;
// delay_link = delay_link & tx_wb_stb;
// #150;
// delay_link = 0;//-----------------------------------------------------------
// @(negedge rx_wb_stall)
@(negedge tx_wb_cyc)
delay_link = 1;
#10000;
delay_link = 0;
// end
// begin
// @(negedge rx_wb_ack);
// delay_link = 1;
// #1000;
// delay_link = 0;
// join
// end
endtask //delay_frame
//always @(posedge clk)
//if (data_to_rx != 16'b0)
assign data_to_rx = data_from_tx ^ corrupt_mask;
assign rx_wb_stb = tx_wb_stb & ~drop_frm;
assign rx_wb_cyc = tx_wb_cyc & ~drop_frm;
// assign tx_wb_stall = delay_link; //extend pulse
assign tx_wb_stall = rx_wb_stall | delay_link; //extend pulse
// assign tx_wb_stall = ~rx_wb_cyc ? (1'b0 | delay_link) : (~rx_wb_ack | delay_link);
assign tx_wb_ack = rx_wb_ack;// & ~delay_link;
/////////////////////////////
time delay=0;
// task automatic add_latency();
// delay = ({$random}%10);
// tx_wb_stall = 1;
// tx_wb_ack = 1;
// #100;
// tx_wb_stall = rx_wb_stall;
// tx_wb_ack = rx_wb_ack;
// $display("Added latency %t \n", delay);
// endtask //add_latency
///////////////////////////////////////////////////////////////////
//RECEPTION LOGIC//
// Receives a data block from the RX streamer and puts it in (blk).
// Returns non-zero done value when blk contains a complete block
/////////////////////////////////////////////////////////////////////////////
task automatic receive_block(ref block_t blk, ref int new_block, ref int done);
bit[g_word_width-1:0] wrd[$];
bit[g_word_width-1:0] word1;
bit[g_word_width-1:0] wordn;
wrd= blk.words;
word1=blk.first_wrd;
wordn=blk.last_wrd;
if(rx_streamer_dvalid)
begin
if(rx_streamer_first && new_block == 1)
begin
new_block = 0;
wrd = {};
blk.wrd_cnt = {};
blk.wrd_cnt.push_back(1);
word1 = rx_streamer_data;
end
else if (!rx_streamer_last && !rx_streamer_first)
begin
blk.wrd_cnt.push_back(0);
end
wrd.push_back(rx_streamer_data);
if (rx_streamer_last && new_block == 0)
begin
wordn = rx_streamer_data;
if (wrd.size() > 1)
blk.wrd_cnt.push_back(wrd.size()); //Last word in block
done = 1;
end
else
begin
done = 0;
end
blk.words=wrd;
blk.first_wrd = word1;
blk.last_wrd = wordn;
end
endtask // receive_block
// TX block stream generation
initial forever
begin
//int i;
streamer_frame_t frm;
frm.blocks = {};
generate_frame(frm);
for (int i=0; i < frm.blocks.size(); i++) begin
frm.blocks[i].dropped = drop_frm;
tx_blk_queue.push_back(frm.blocks[i]);
end
tx_frm_queue.push_back(frm);
send_frame(frm);
$display("PUSH FRAME Tx q are %p\n#########", tx_frm_queue);
rx_streamer_dreq <= 1;//({$random} % 100 < 90) ? 1 : 0;
$display ("Time is %d\n", $time);
end
initial forever
begin
randcase
10 : drop_frame ();
//10 : corrupt_data ();
10 : link_good ();
10 : delay_frame ();
endcase;
end
// Instantiation of the streamers. The TX streamer will assemble packets
// containing max. 8 records, or flush the buffer after 128 clk cycles if
// it contains less than 8 records to prevent latency buildup.
tx_streamer
#(
.g_data_width (g_word_width),
.g_tx_threshold (4),
.g_tx_timeout (128)
)
U_TX_Streamer
(
.clk_sys_i(clk),
.rst_n_i (rst_n),
.src_dat_o (data_from_tx),// (mac.dat_i),
.src_adr_o (mac.adr),
.src_sel_o (mac.sel),
.src_cyc_o (tx_wb_cyc),
.src_stb_o (tx_wb_stb),
.src_we_o (mac.we),
.src_stall_i(tx_wb_stall),
.src_err_i (mac.err),
.src_ack_i (tx_wb_ack),
.clk_ref_i(clk_ref), // fake WR time
.tm_time_valid_i(1'b1),
.tm_cycles_i(tm_cycle_counter),
.tx_data_i (tx_streamer_data),
.tx_valid_i (tx_streamer_dvalid),
.tx_dreq_o (tx_streamer_dreq),
.tx_last_p1_i (tx_streamer_last),
.tx_flush_p1_i (tx_flush),
.tx_reset_seq_i (),
.tx_frame_p1_o (tx_frame_sent),
.cfg_mac_local_i (g_mac_tx),
.cfg_mac_target_i (g_mac_rx),
.cfg_ethertype_i (g_ethertype)
);
rx_streamer
#(
.g_data_width (g_word_width)
)
U_RX_Streamer
(
.clk_sys_i (clk),
.rst_n_i (rst_n),
.snk_dat_i (data_to_rx),
.snk_adr_i (mac.adr),
.snk_sel_i (mac.sel),
.snk_cyc_i (rx_wb_cyc),
.snk_stb_i (rx_wb_stb),
.snk_we_i (mac.we),
.snk_stall_o (rx_wb_stall),
.snk_ack_o (rx_wb_ack),
.snk_err_o (mac.err),
.snk_rty_o (mac.rty),
.clk_ref_i(clk_ref), // fake WR time
.tm_time_valid_i(1'b1),
.tm_cycles_i(tm_cycle_counter),
.rx_first_p1_o (rx_streamer_first),
.rx_last_p1_o (rx_streamer_last),
.rx_data_o (rx_streamer_data),
.rx_valid_o (rx_streamer_dvalid),
.rx_dreq_i (rx_streamer_dreq),
//.rx_lost_p1_o (rx_streamer_lost),
.rx_lost_blocks_p1_o (rx_streamer_lost_blks),
.rx_lost_frames_p1_o (rx_streamer_lost_frm),
.rx_lost_frames_cnt_o (rx_streamer_lost_frm_cnt),
.rx_latency_o (rx_latency),
.rx_latency_valid_o (rx_latency_valid),
.rx_frame_p1_o (rx_frame_received),
.cfg_mac_local_i (g_mac_rx),
.cfg_mac_remote_i (g_mac_tx),
.cfg_ethertype_i (g_ethertype)
);
// TESTBENCH VERIFICATION
// Client-side reception logic. Compares the received records with their copies
// stored in the transfer queue.
int new_block = 1;
int no_curr_req = 0;
always@(posedge clk)
if(rst_n)
begin
block_t rblk;
streamer_frame_t tfrm;
automatic int done = 0;
if (rx_streamer_lost_frm == 1)
begin
int i, n_lost_frames;
n_lost_frames = rx_streamer_lost_frm_cnt;
for (i = 0; i < n_lost_frames; i++) begin
tfrm = tx_frm_queue.pop_front();
$display ("%d have been lost, frame %p is POPPED\n=====", n_lost_frames, tfrm );
end
$display ("%d have been lost, the new Tx queue is %p\n=====", n_lost_frames, tx_frm_queue );
end
receive_block(rblk, new_block, done);
if(done)
begin
//automatic streamer_frame_t frm ;
automatic block_t tblk;
//automatic int tblk_size = tblk.words.size();
$display(" frame OUT is %p \n********", tx_blk_queue);
//if (tx_blk_queue.size() != 0)
//else begin
tblk = tx_blk_queue.pop_front(); $display(" OLD TBLK is %p \n********", tblk);
$display(" FRAME size is %d \n%%%%%%%%%%%%", tfrm.blocks.size());
if (tfrm.blocks.size() == 0) begin
tfrm = tx_frm_queue.pop_front();
$display(" FRAME is %p \n%%%%%%%%%%%%", tfrm); end
tblk = tfrm.blocks.pop_front(); $display(" NEW TBLK is %p \n********", tblk);
$display(" FRAME AFTER POP is %p \n%%%%%%%%%%%%", tfrm);
$display(" QUEUE is %p \n%%%%%%%%%%%%", tx_blk_queue);
//end
$display(" block OUT is %p \n********", tblk);
//$display("Received block of %d words....\n", tblk_size);
new_block = 1;
// ===============================================================
// TEST : Check that no frames have been lost:
// ===============================================================
// TEST 1: Check Txed and Rxed blocks match
if(tblk.words != rblk.words)
begin
$error("TEST 1 ---> FAILED\n####Sent block does not match received block\n");
$display("Txed is %p, Rxed equals %p", tblk, rblk);
$stop;
end else begin
$display("****\nTEST 1 ---> PASSED\n****Correct words received\n");
end
// ================================================================
// TEST 2: Check number of Received words in block is correct
if (tblk.words.size() != rblk.words.size())
begin
$error("TEST 2 ---> FAILED\n####Sent and received blocks do not have the same number of words\n");
$stop;
end else
$display("****\nTEST 2 ---> PASSED\n****Correct number of words received\n");
// ================================================================
// TEST 3: Check that first word is asserted correctly at first word
// if (tblk.first_wrd != rblk.first_wrd)
if (tblk.wrd_cnt != rblk.wrd_cnt)
begin
$error("TEST 3 ---> FAILED: First word pulse incorrect.\n");
//$display("Txed is %p, Rxed equals %p", tblk, rblk);
$stop;
end else
$display("****\nTEST 3 ---> PASSED\n****First word signalled correctly\n");
// =================================================================
// TEST 4: Check that first word is asserted correctly at first word
// if (tblk.last_wrd != rblk.last_wrd)
if (tblk.wrd_cnt != rblk.wrd_cnt)
begin
//$display("test4 txed equals %p, rxed %p", tblk, rblk);
$error("TEST 4 ---> FAILED: Last word pulse incorrect.\n");
$stop;
end else
$display("test4 txed equals %p, rxed %p", tblk, rblk);
$display("****\nTEST 4 ---> PASSED\n****Last word signalled correctly\n");
// =================================================================
// TEST 5: Check that when rx_dreq is not asserted data stops at the next clk cycle
if (rx_streamer_dreq == 1)
no_curr_req = 0;
else if (rx_streamer_dreq == 0 && no_curr_req == 0)
no_curr_req = 1;
else if (no_curr_req == 1 && rx_streamer_dvalid == 1)
begin
$error("TEST 5 ---> FAILED\n####Pulse rx_request is not asserted should not receive data.\n");
$stop;
end
else begin
$display("****\nTEST 5 ---> PASSED\n****No data output when Rx_request is not asserted\n");
end
end
end // else: !if(!rst_n)
always@(posedge clk)
if(rst_n && rx_latency_valid)
$display("*************This frame's latency: %.3f microseconds*************************************************\n", real'(rx_latency) * 0.008);
endmodule // main
//-----------------------------------------------------------------------------
// Title : WR streamers testbench
// Project : White Rabbit Cores
// URL : http://www.ohwr.org/projects/wr-cores/wiki/WR_Streamers
//-----------------------------------------------------------------------------
// File : main.sv
// Author(s) : Tomasz Wlostosky,
// Extended by Denia Bouhired <denia.bouhired@cern.ch>
// Company : CERN (BE-CO-HT)
// Created : 2017-04-28
//-----------------------------------------------------------------------------
// Description:
//
//
//-----------------------------------------------------------------------------
//
// Copyright (c) 2017 CERN
//
// This source file is free software; you can redistribute it
// and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any
// later version.
//
// This source 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 Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General
// Public License along with this source; if not, download it
// from http://www.gnu.org/licenses/lgpl-2.1.html
//
//-----------------------------------------------------------------------------
`include "../../../sim/if_wb_link.svh"
// `include "./tb_wr_fabric_link_control.sv"
`timescale 1ns/1ns
module main;
/////////////////////////////////////////////////////////////////////////////
// Parameters
/////////////////////////////////////////////////////////////////////////////
// Size of data record to be used by the streamers.
// In this case, a 64-bit word.
parameter g_word_width = 64;
// Min and max block size
parameter g_block_size_min = 1;
parameter g_block_size_max = 5;
// Min and max frame size
parameter g_frame_size_min = 1;
parameter g_frame_size_max = 3;
// MAC address of the TX side
parameter bit [47:0] g_mac_tx = 48'h112233445566;
// MAC address of the RX side
parameter bit [47:0] g_mac_rx = 48'hcafebabedead;
// Ethertype for distinguishing streamer frames. Default accepted by WRPC core.
parameter bit [15:0] g_ethertype = 16'hdbff;
// 16-bit data, 2-bit address Wishbone bus that connects the WR MAC interfaces
// of both streamers
IWishboneLink #(16, 2) mac();
logic [1 : 0] adr_d1;
logic [1 : 0] sel_d1 ;
logic cyc_d1;
logic stb_d1;
logic we_d1 ;
logic [1 : 0] adr;
logic [1 : 0] sel ;
logic cyc;
logic stb;
logic we;
// Clock & reset
reg clk = 0;
reg rst_n = 0;
// TX Streamer signals
reg tx_streamer_dvalid = 0;
reg [g_word_width-1:0] tx_streamer_data = 0;
//wire[15:0] data_from_tx= 0;
reg tx_streamer_last = 0;
wire tx_streamer_dreq;
wire tx_frame_sent;
// RX Streamer signals
reg rx_streamer_dreq = 0;
wire [g_word_width-1:0] rx_streamer_data;
wire rx_streamer_dvalid;
wire rx_streamer_lost_blks;
wire rx_streamer_lost_frm;
wire [14:0] rx_streamer_lost_frm_cnt;
wire rx_streamer_first;
wire rx_streamer_last;
wire [27:0] rx_latency;
wire rx_latency_valid;
wire rx_frame_received;
// Fake White Rabbit reference clock (125 MHz) and cycle counter (we don't use
// TAI counter as the latency never exceeds 1 second...)
reg clk_ref = 0;
reg [27:0] tm_cycle_counter = 0;
// Currently transmitted counter value
integer tx_counter_val = 10;
//Seed for random generator
int seed = 0;
bit [15 : 0] data_from_tx;
bit [15 : 0] data_to_rx ;
bit tx_wb_cyc, rx_wb_cyc;
bit tx_wb_stb, rx_wb_stb;
wire rx_wb_stall;
bit tx_wb_stall;
wire rx_wb_ack;
bit tx_wb_ack;
/////////////////////////////////////////////////////////////////////////////
// Initialise and set, reset, clocks and clk counter
/////////////////////////////////////////////////////////////////////////////
initial
begin
#100 rst_n = 1;
end;
always #10 clk <= ~clk;
always #4ns clk_ref <= ~clk_ref; //generate 125 MHz WR Clock
always@(posedge clk_ref)
tm_cycle_counter <= tm_cycle_counter + 1;
/////////////////////////////////////////////////////////////////////////////
// Struct definition
/////////////////////////////////////////////////////////////////////////////
typedef struct{
bit[g_word_width-1:0] words[$];
int wrd_cnt[$];
bit[g_word_width-1:0] first_wrd;
bit[g_word_width-1:0] last_wrd;
} block_t;
typedef struct{
block_t blocks[$];
} streamer_frame_t;
// Transfer queue. Used to pass sent data to the verification process.
block_t tx_queue[$];
/////////////////////////////////////////////////////////////////////////////
// Task definitions
/////////////////////////////////////////////////////////////////////////////
// Generate a block of data words of random size, containing subsequent
// numbers
/////////////////////////////////////////////////////////////////////////////
task automatic generate_block(ref block_t blk);
int size = $dist_uniform(seed, g_block_size_min, g_block_size_max);
int i;
for(i = 0; i<size; i++)
begin
if (i == 0) blk.first_wrd = tx_counter_val;
if (i == size-1) blk.last_wrd = tx_counter_val;
blk.words.push_back(tx_counter_val++);
if (i == 0 || i==size-1)
blk.wrd_cnt.push_back(i+1);
else
blk.wrd_cnt.push_back(0);
end
//$display("BLOCK size is %d: \n", size);
//$display ("Current block is %p \n", blk.words );
endtask // generate_block
////////////////////////////////////////////////////////
task automatic generate_frame(ref streamer_frame_t frm);
int size = $dist_uniform(seed, g_frame_size_min, g_frame_size_max);
block_t blk;
int i;
//$display("Frame size is %d: \n", size);
for(i = 0; i<size; i++)
begin
blk.words = {};
blk.wrd_cnt = {};
generate_block(blk);
//$display("generated block was %p \n********", blk.words);
frm.blocks.push_back(blk);
end //$display("generated frame is %p \n********", frm.blocks);
endtask
// Sends out a data block (blk) by driving TX_(DVALID, DATA, LAST) lines
// of the TX streamer
/////////////////////////////////////////////////////////////////////////////
task automatic send_block(ref block_t blk);
int i = 0;
////$display("Sending block of %d words...", blk.words.data.size());
while(i < blk.words.size())
begin
if(tx_streamer_dreq) begin
// assert the TX_LAST line on the last word in the current block
tx_streamer_last <= (i == (blk.words.size() - 1)) ? 1 : 0;
tx_streamer_data <= blk.words[i];
//$display("Data to be sent is %d*****\n", tx_streamer_data);
tx_streamer_dvalid <= 1;
i++;
end else
tx_streamer_dvalid <= 0;
@(posedge clk);
end // while (i < blk.words.data.size())
tx_streamer_dvalid <= 0;
tx_streamer_last <= 0;
@(posedge clk);
endtask // send_block
///////////////////////////////////////////////////////////////////
task automatic send_frame(ref streamer_frame_t frm);
int i = 0;
while (i < frm.blocks.size()) begin
send_block(frm.blocks[i]);
i++;
end
endtask
///////////////////////////////////////////////////////////////////
// WISHBONE LINK CONTROL
///////////////////////////////////////////////////////////////////
//Continuous assignements to WR fabric signals
logic [ 15 : 0] corrupt_mask = 16'h0000;
logic drop_frm = 0;
logic link_ok= 1;
logic delay_link= 0;
int corrupt=0;
task automatic disrupt_link() ;
randcase
10 : drop_frame ();
10 : begin link_ok = 0; corrupt_data ();end
10 : link_ok = 1;
10 : delay_frame ();
endcase;
endtask // disrupt_link
task automatic link_good ();
int frm_counter = 0;
link_ok = 1;
corrupt_mask = 16'h0000;
drop_frm = 0;
delay_link= 0;
frm_counter=0;
while (frm_counter < 3 ) begin
@(posedge tx_wb_cyc) //at every new frame
frm_counter ++;
end
endtask;
task automatic corrupt_data ();
int i, j, n;
int frm_counter = 0;
corrupt_mask = 16'h0000;
link_ok= 0;
n={$random} % 2; //number of frames to be corrupted
//corrupt = ({$random} % 1000 < 500) ? 1 : 0;
// break_bit = ({$random} % 100 <1) ? 1 : 0;
// while (frm_counter < 3 )
// begin
j = {$random} % 15;
$display("=====BIT FLIP================");
@(negedge rx_frame_received)
corrupt_mask [j] = ~corrupt_mask [j];
@(negedge rx_wb_ack) link_good ();
// end
endtask //corrupt_data
task automatic drop_frame ();
int n, i;
link_ok= 0;
n={$random} % 5; //number of frames to be dropped
// drop_or_delay = 0;// {$random} % 1;
for (i=0; i<n; i++)
begin
@(negedge tx_wb_cyc)
drop_frm = 1;
end
@(negedge tx_wb_cyc)
drop_frm = 0;
endtask //drop_frame
// end
task automatic delay_frame ();
link_ok= 0;
delay_link = 0;
// fork begin
wait (rx_wb_stall == 1) //to avoid changes at startup
//----------Random stall asserted------------------------------
// delay_link = ({$random} % 10 < 2) ? 1 : 0;
// delay_link = delay_link & tx_wb_stb;
// #150;
// delay_link = 0;//-----------------------------------------------------------
// @(negedge rx_wb_stall)
@(negedge tx_wb_cyc)
delay_link = 1;
#10000;
delay_link = 0;
// end
// begin
// @(negedge rx_wb_ack);
// delay_link = 1;
// #1000;
// delay_link = 0;
// join
// end
endtask //delay_frame
always @(posedge clk)
//if (data_to_rx != 16'b0)
assign data_to_rx = data_from_tx ^ corrupt_mask;
assign rx_wb_stb = tx_wb_stb & ~drop_frm;
assign rx_wb_cyc = tx_wb_cyc & ~drop_frm;
// assign tx_wb_stall = delay_link; //extend pulse
assign tx_wb_stall = rx_wb_stall | delay_link; //extend pulse
// assign tx_wb_stall = ~rx_wb_cyc ? (1'b0 | delay_link) : (~rx_wb_ack | delay_link);
assign tx_wb_ack = rx_wb_ack;// & ~delay_link;
/////////////////////////////
time delay=0;
// task automatic add_latency();
// delay = ({$random}%10);
// tx_wb_stall = 1;
// tx_wb_ack = 1;
// #100;
// tx_wb_stall = rx_wb_stall;
// tx_wb_ack = rx_wb_ack;
// $display("Added latency %t \n", delay);
// endtask //add_latency
///////////////////////////////////////////////////////////////////
//RECEPTION LOGIC//
// Receives a data block from the RX streamer and puts it in (blk).
// Returns non-zero done value when blk contains a complete block
/////////////////////////////////////////////////////////////////////////////
task automatic receive_block(ref block_t blk, ref int new_block, ref int done);
bit[g_word_width-1:0] wrd[$];
bit[g_word_width-1:0] word1;
bit[g_word_width-1:0] wordn;
wrd= blk.words;
word1=blk.first_wrd;
wordn=blk.last_wrd;
//////$display("CURRENT WORD in block %p \n", wrd);
if(rx_streamer_dvalid)
begin
//$display("VALID word\n");
if(rx_streamer_first && new_block == 1)
begin
new_block = 0;
wrd = {};
blk.wrd_cnt = {};
blk.wrd_cnt.push_back(1);
/////$display("first word received\n");
/////$display("*****NEW_BLOCK %d\n", new_block);
word1 = rx_streamer_data;
/////$display("*****first word %d\n", word1);
end
else if (!rx_streamer_last && !rx_streamer_first)
begin
blk.wrd_cnt.push_back(0);
end
wrd.push_back(rx_streamer_data);
//$display("BEFORE LAST words in block %p \n", wrd);
if (rx_streamer_last && new_block == 0)
begin
wordn = rx_streamer_data;
if (wrd.size() > 1) blk.wrd_cnt.push_back(wrd.size()); //Last word in block
////$display("HERE**************SIZE is %d *****************\n", wrd.data.size());
////$display("words in block %p \n", wrd.data);
done = 1;
//// $display("last word received, done is %d\n", done);
//// $display("words in block %p \n", wrd);
//// $display("IF rx_streamer_last is %d \n",rx_streamer_last);
end
else begin
////$display("ELSE rx_streamer_last is %b \n",rx_streamer_last);
done = 0;
////$display("ZERO done");
end
blk.words=wrd;
blk.first_wrd = word1;
blk.last_wrd = wordn;
//// $display("words in block %p \n", blk.words);
end
endtask // receive_block
// TX block stream generation
initial forever
begin
//int i;
streamer_frame_t frm;
frm.blocks = {};
generate_frame(frm);
send_frame(frm);
for (int i=0; i < frm.blocks.size(); i++) begin
tx_queue.push_back(frm.blocks[i]);
end
rx_streamer_dreq <= 1;//({$random} % 100 < 90) ? 1 : 0;
$display ("Time is %d\n", $time);
end
initial forever
begin
randcase
//10 : drop_frame ();
10 : corrupt_data ();
10 : link_good ();
// 10 : delay_frame ();
endcase;
end
// Instantiation of the streamers. The TX streamer will assemble packets
// containing max. 8 records, or flush the buffer after 128 clk cycles if
// it contains less than 8 records to prevent latency buildup.
tx_streamer
#(
.g_data_width (g_word_width),
.g_tx_threshold (4),
.g_tx_timeout (128)
)
U_TX_Streamer
(
.clk_sys_i(clk),
.rst_n_i (rst_n),
.src_dat_o (data_from_tx),// (mac.dat_i),
.src_adr_o (mac.adr),
.src_sel_o (mac.sel),
.src_cyc_o (tx_wb_cyc),
.src_stb_o (tx_wb_stb),
.src_we_o (mac.we),
.src_stall_i(tx_wb_stall),
.src_err_i (mac.err),
.src_ack_i (tx_wb_ack),
.clk_ref_i(clk_ref), // fake WR time
.tm_time_valid_i(1'b1),
.tm_cycles_i(tm_cycle_counter),
.tx_data_i (tx_streamer_data),
.tx_valid_i (tx_streamer_dvalid),
.tx_dreq_o (tx_streamer_dreq),
.tx_last_p1_i (tx_streamer_last),
.tx_reset_seq_i (),
.tx_frame_p1_o (tx_frame_sent),
.cfg_mac_local_i (g_mac_tx),
.cfg_mac_target_i (g_mac_rx),
.cfg_ethertype_i (g_ethertype)
);
rx_streamer
#(
.g_data_width (g_word_width)
)
U_RX_Streamer
(
.clk_sys_i (clk),
.rst_n_i (rst_n),
.snk_dat_i (data_to_rx),
.snk_adr_i (mac.adr),
.snk_sel_i (mac.sel),
.snk_cyc_i (rx_wb_cyc),
.snk_stb_i (rx_wb_stb),
.snk_we_i (mac.we),
.snk_stall_o (rx_wb_stall),
.snk_ack_o (rx_wb_ack),
.snk_err_o (mac.err),
.snk_rty_o (mac.rty),
.clk_ref_i(clk_ref), // fake WR time
.tm_time_valid_i(1'b1),
.tm_cycles_i(tm_cycle_counter),
.rx_first_p1_o (rx_streamer_first),
.rx_last_p1_o (rx_streamer_last),
.rx_data_o (rx_streamer_data),
.rx_valid_o (rx_streamer_dvalid),
.rx_dreq_i (rx_streamer_dreq),
//.rx_lost_p1_o (rx_streamer_lost),
.rx_lost_blocks_p1_o (rx_streamer_lost_blks),
.rx_lost_frames_p1_o (rx_streamer_lost_frm),
.rx_lost_frames_cnt_o (rx_streamer_lost_frm_cnt),
.rx_latency_o (rx_latency),
.rx_latency_valid_o (rx_latency_valid),
.rx_frame_p1_o (rx_frame_received),
.cfg_mac_local_i (g_mac_rx),
.cfg_mac_remote_i (g_mac_tx),
.cfg_ethertype_i (g_ethertype)
);
// TESTBENCH VERIFICATION
// Client-side reception logic. Compares the received records with their copies
// stored in the transfer queue.
int new_block = 1;
int no_curr_req = 0;
always@(posedge clk)
if(rst_n)
begin
block_t rblk;
automatic int done = 0;
receive_block(rblk, new_block, done);
if(done)
begin
//automatic streamer_frame_t frm ;
automatic block_t tblk;
automatic int tblk_size = tblk.words.size();
$display(" frame OUT is %p \n********", tx_queue);
if (tx_queue.size() != 0)
tblk = tx_queue.pop_front();
else break;
$display(" block OUT is %p \n********", tblk);
new_block = 1;
$display("Received block of %d words....\n", tblk_size);
// ===============================================================
// TEST 1: Check Txed and Rxed blocks match
if(tblk.words != rblk.words)
begin
$error("TEST 1 ---> FAILED\n####Sent block does not match received block\n");
$display("Txed is %p, Rxed equals %p", tblk, rblk);
$stop;
end else begin
$display("****\nTEST 1 ---> PASSED\n****Correct words received\n");
end
// ================================================================
// TEST 2: Check number of Received words in block is correct
if (tblk.words.size() != rblk.words.size())
begin
$error("TEST 2 ---> FAILED\n####Sent and received blocks do not have the same number of words\n");
$stop;
end else
$display("****\nTEST 2 ---> PASSED\n****Correct number of words received\n");
// ================================================================
// TEST 3: Check that first word is asserted correctly at first word
// if (tblk.first_wrd != rblk.first_wrd)
if (tblk.wrd_cnt != rblk.wrd_cnt)
begin
$error("TEST 3 ---> FAILED: First word pulse incorrect.\n");
//$display("Txed is %p, Rxed equals %p", tblk, rblk);
$stop;
end else
$display("****\nTEST 3 ---> PASSED\n****First word signalled correctly\n");
// =================================================================
// TEST 4: Check that first word is asserted correctly at first word
// if (tblk.last_wrd != rblk.last_wrd)
if (tblk.wrd_cnt != rblk.wrd_cnt)
begin
//$display("test4 txed equals %p, rxed %p", tblk, rblk);
$error("TEST 4 ---> FAILED: Last word pulse incorrect.\n");
$stop;
end else
$display("test4 txed equals %p, rxed %p", tblk, rblk);
$display("****\nTEST 4 ---> PASSED\n****Last word signalled correctly\n");
// =================================================================
// TEST 5: Check that when rx_dreq is not asserted data stops at the next clk cycle
if (rx_streamer_dreq == 1)
no_curr_req = 0;
else if (rx_streamer_dreq == 0 && no_curr_req == 0)
no_curr_req = 1;
else if (no_curr_req == 1 && rx_streamer_dvalid == 1)
begin
$error("TEST 5 ---> FAILED\n####Pulse rx_request is not asserted should not receive data.\n");
$stop;
end
else begin
$display("****\nTEST 5 ---> PASSED\n****No data output when Rx_request is not asserted\n");
end
end
end // else: !if(!rst_n)
always@(posedge clk)
if(rst_n && rx_latency_valid)
$display("*************This frame's latency: %.3f microseconds*************************************************\n", real'(rx_latency) * 0.008);
endmodule // main
class CGENERATE_AND_SEND
// Generate a block of data words of random size, containing subsequent
// numbers
/////////////////////////////////////////////////////////////////////////////
task automatic generate_block(ref block_t blk);
int size = $dist_uniform(seed, g_block_size_min, g_block_size_max);
int i;
for(i = 0; i<size; i++)
begin
if (i == 0)
blk.first_wrd = tx_counter_val; // Copy first word
if (i == size-1)
blk.last_wrd = tx_counter_val; // Copy last word
blk.words.push_back(tx_counter_val++); //
if (i == 0 || i==size-1)
blk.wrd_cnt.push_back(i+1);// first or last words
else
blk.wrd_cnt.push_back(0); // All other words
end //for loop
endtask // generate_block
////////////////////////////////////////////////////////
task automatic generate_frame(ref streamer_frame_t frm);
int size = $dist_uniform(seed, g_frame_size_min, g_frame_size_max);
int i;
block_t blk;
for(i = 0; i<size; i++)
begin
blk.words = {};
blk.wrd_cnt = {};
generate_block(blk);
frm.blocks.push_back(blk);
end
endtask
// Sends out a data block (blk) by driving TX_(DVALID, DATA, LAST) lines
// of the TX streamer
/////////////////////////////////////////////////////////////////////////////
task automatic send_block(ref block_t blk);
int i = 0;
////$display("Sending block of %d words...", blk.words.data.size());
while(i < blk.words.size())
begin
if(tx_streamer_dreq) begin
// assert the TX_LAST line on the last word in the current block
tx_streamer_last <= (i == (blk.words.size() - 1)) ? 1 : 0;
tx_streamer_data <= blk.words[i];
//$display("Data to be sent is %d*****\n", tx_streamer_data);
tx_streamer_dvalid <= 1;
i++;
end else
tx_streamer_dvalid <= 0;
@(posedge clk);
end // while (i < blk.words.data.size())
tx_streamer_dvalid <= 0;
tx_streamer_last <= 0;
@(posedge clk);
endtask // send_block
///////////////////////////////////////////////////////////////////
task automatic send_frame(ref streamer_frame_t frm);
int i = 0;
while (i < frm.blocks.size()) begin
send_block(frm.blocks[i]);
i++;
end
endtask
endclass
\ No newline at end of file
//-----------------------------------------------------------------------------
// Title : Definitions for WR streamers testbench
// Project : White Rabbit Cores
// URL : http://www.ohwr.org/projects/wr-cores/wiki/WR_Streamers
//-----------------------------------------------------------------------------
// File : wr-streamers-tb-class.sv
// Author(s) : Denia Bouhired <denia.bouhired@cern.ch>
// Company : CERN (BE-CO-HT)
// Created : 2017-04-28
//-----------------------------------------------------------------------------
// Description:
//
// SystemVerilog package with all definitions, interfaces, etc. necessary
// for the wr streamers testbench.
//
//-----------------------------------------------------------------------------
//
// Copyright (c) 2017 CERN
//
// This source file is free software; you can redistribute it
// and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any
// later version.
//
// This source 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 Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General
// Public License along with this source; if not, download it
// from http://www.gnu.org/licenses/lgpl-2.1.html
//
//-----------------------------------------------------------------------------
//`include "../../../sim/if_wb_link.svh"
class CWRFABRIC_LINK_CTRL;
int data_width, addr_width;
IWishboneLink in;
IWishboneLink out;
//Class constructor
function new ();
// this.out() = this.in();
// this.in.g_data_width = data_width;
// this.in.g_addr_width = addr_width;
// this.out.g_data_width = data_width;
// this.out.g_addr_width = addr_width;
endfunction //new
//
function corrupt_data ();
in();
out();
endfunction
function drop_frames ();
in();
out();
endfunction //drop_frames
function break_link ();
in();
out();
endfunction //break_link
endclass;
// Transmitter class
// class CWRSTREAMERS_TX extends CWRSTREAMERS;
// function
// endclass;
// Receiver class
// class CWRSTREAMERS_RX extends CWRSTREAMERS;
// endclass;
//-----------------------------------------------------------------------------
// Title : WR streamers testbench
// Project : White Rabbit Cores
// URL : http://www.ohwr.org/projects/wr-cores/wiki/WR_Streamers
//-----------------------------------------------------------------------------
// File : main.sv
// Author(s) : Tomasz Wlostosky,
// Extended by Denia Bouhired <denia.bouhired@cern.ch>
// Company : CERN (BE-CO-HT)
// Created : 2017-04-28
//-----------------------------------------------------------------------------
// Description:
//
//
//-----------------------------------------------------------------------------
//
// Copyright (c) 2017 CERN
//
// This source file is free software; you can redistribute it
// and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any
// later version.
//
// This source 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 Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General
// Public License along with this source; if not, download it
// from http://www.gnu.org/licenses/lgpl-2.1.html
//
//-----------------------------------------------------------------------------
`include "../../../sim/if_wb_link.svh"
// `include "./tb_wr_fabric_link_control.sv"
`timescale 1ns/1ns
module main;
/////////////////////////////////////////////////////////////////////////////
// Parameters
/////////////////////////////////////////////////////////////////////////////
// Size of data record to be used by the streamers.
// In this case, a 64-bit word.
parameter g_word_width = 64;
parameter g_tx_thr = 16;
parameter g_tx_tm_out = 128;
parameter g_max_wrds_pr_frm = 16;
// Min and max block size
parameter g_block_size_min = 1;
parameter g_block_size_max = 5;
// Min and max frame size
parameter g_frame_size_min = 1;
parameter g_frame_size_max = 3;
// MAC address of the TX side
parameter bit [47:0] g_mac_tx = 48'h112233445566;
// MAC address of the RX side
parameter bit [47:0] g_mac_rx = 48'hcafebabedead;
// Ethertype for distinguishing streamer frames. Default accepted by WRPC core.
parameter bit [15:0] g_ethertype = 16'hdbff;
// 16-bit data, 2-bit address Wishbone bus that connects the WR MAC interfaces
// of both streamers
IWishboneLink #(16, 2) mac();
logic [1 : 0] adr_d1;
logic [1 : 0] sel_d1 ;
logic cyc_d1;
logic stb_d1;
logic we_d1 ;
logic [1 : 0] adr;
logic [1 : 0] sel ;
logic cyc;
logic stb;
logic we;
// Clock & reset
reg clk = 0;
reg rst_n = 0;
reg [27:0] clk_cycle_counter = 0;
int clk_cycle_counter_before = 0;
int clk_cycle_counter_after = 0;
// TX Streamer signals
reg tx_streamer_dvalid = 0;
reg [g_word_width-1:0] tx_streamer_data = 0;
//wire[15:0] data_from_tx= 0;
reg tx_streamer_last = 0;
reg tx_flush = 0;
wire tx_streamer_dreq;
wire tx_frame_sent;
// RX Streamer signals
reg rx_streamer_dreq = 0;
wire [g_word_width-1:0] rx_streamer_data;
wire rx_streamer_dvalid;
wire rx_streamer_lost_blks;
wire rx_streamer_lost_frm;
wire [14:0] rx_streamer_lost_frm_cnt;
wire rx_streamer_first;
wire rx_streamer_last;
wire [27:0] rx_latency;
wire rx_latency_valid;
wire rx_frame_received;
//Fixed latency
reg [27:0] fixed_latency = 28'h0;
// Fake White Rabbit reference clock (125 MHz) and cycle counter (we don't use
// TAI counter as the latency never exceeds 1 second...)
reg clk_ref = 0;
reg [27:0] tm_cycle_counter = 0;
// Currently transmitted counter value
integer tx_counter_val = 10;
//Seed for random generator
int seed = 0;
// Wishbone link interface
bit [15 : 0] data_from_tx;
logic [15 : 0] data_to_rx ;
logic tx_wb_cyc, rx_wb_cyc;
logic tx_wb_stb, rx_wb_stb;
logic tx_wb_ack;
logic tx_wb_stall;
wire rx_wb_stall;
wire rx_wb_ack;
/////////////////////////////////////////////////////////////////////////////
// Initialise and set, reset, clocks and clk counter
/////////////////////////////////////////////////////////////////////////////
initial
begin
#100 rst_n = 1;
end;
always #10 clk <= ~clk;
always #4ns clk_ref <= ~clk_ref; //generate 125 MHz WR Clock
always@(posedge clk_ref) tm_cycle_counter <= tm_cycle_counter + 1;
always@(posedge clk) clk_cycle_counter <= clk_cycle_counter + 1;
always@(posedge tx_frame_sent) clk_cycle_counter_before = clk_cycle_counter;
always@(posedge rx_frame_received) clk_cycle_counter_after = clk_cycle_counter;
/////////////////////////////////////////////////////////////////////////////
// Struct definition
/////////////////////////////////////////////////////////////////////////////
typedef struct{ bit[g_word_width-1:0] words[$];
int wrd_cnt[$];
bit[g_word_width-1:0] first_wrd;
bit[g_word_width-1:0] last_wrd;
bit dropped;
} block_t; //block is a number of words with info about first
// and last
typedef struct{ block_t blocks[$];
} streamer_frame_t; //frame contains a collection of blocks
// Transfer queue. Used to pass sent data to the verification process.
block_t tx_blk_queue[$];
streamer_frame_t tx_frm_queue[$];
// Instantiation of the streamers. The TX streamer will assemble packets
// containing max. 8 records, or flush the buffer after 128 clk cycles if
// it contains less than 8 records to prevent latency buildup.
tx_streamer
#(
.g_data_width (g_word_width),
.g_tx_buffer_size(2*g_tx_thr),
.g_tx_threshold (g_tx_thr),
.g_tx_timeout (g_tx_tm_out),
.g_tx_max_words_per_frame (g_max_wrds_pr_frm),
.g_simulation(1),
.g_sim_startup_cnt(0)
)
//
U_TX_Streamer
(
.clk_sys_i(clk),
.rst_n_i (rst_n),
.src_dat_o (data_from_tx),// (mac.dat_i),
.src_adr_o (mac.adr),
.src_sel_o (mac.sel),
.src_cyc_o (tx_wb_cyc),
.src_stb_o (tx_wb_stb),
.src_we_o (mac.we),
.src_stall_i(tx_wb_stall),
.src_err_i (mac.err),
.src_ack_i (tx_wb_ack),
.clk_ref_i(clk_ref), // fake WR time
.tm_time_valid_i(1'b1),
.tm_cycles_i(tm_cycle_counter),
.tx_data_i (tx_streamer_data),
.tx_valid_i (tx_streamer_dvalid),
.tx_dreq_o (tx_streamer_dreq),
.tx_last_p1_i (tx_streamer_last),
.tx_flush_p1_i (tx_flush),
.tx_reset_seq_i (),
.tx_frame_p1_o (tx_frame_sent),
.cfg_mac_local_i (g_mac_tx),
.cfg_mac_target_i (g_mac_rx),
.cfg_ethertype_i (g_ethertype)
);
rx_streamer
#(
.g_data_width (g_word_width)
)
U_RX_Streamer
(
.clk_sys_i (clk),
.rst_n_i (rst_n),
.snk_dat_i (data_to_rx),
.snk_adr_i (mac.adr),
.snk_sel_i (mac.sel),
.snk_cyc_i (rx_wb_cyc),
.snk_stb_i (rx_wb_stb),
.snk_we_i (mac.we),
.snk_stall_o (rx_wb_stall),
.snk_ack_o (rx_wb_ack),
.snk_err_o (mac.err),
.snk_rty_o (mac.rty),
.clk_ref_i(clk_ref), // fake WR time
.tm_time_valid_i(1'b1),
.tm_cycles_i(tm_cycle_counter),
.rx_first_p1_o (rx_streamer_first),
.rx_last_p1_o (rx_streamer_last),
.rx_data_o (rx_streamer_data),
.rx_valid_o (rx_streamer_dvalid),
.rx_dreq_i (rx_streamer_dreq),
//.rx_lost_p1_o (rx_streamer_lost),
.rx_lost_blocks_p1_o (rx_streamer_lost_blks),
.rx_lost_frames_p1_o (rx_streamer_lost_frm),
.rx_lost_frames_cnt_o (rx_streamer_lost_frm_cnt),
.rx_latency_o (rx_latency),
.rx_latency_valid_o (rx_latency_valid),
.rx_frame_p1_o (rx_frame_received),
.cfg_mac_local_i (g_mac_rx),
.cfg_mac_remote_i (g_mac_tx),
.cfg_ethertype_i (g_ethertype),
.cfg_accept_broadcasts_i (),
.cfg_filter_remote_i (),
.cfg_fixed_latency_i (fixed_latency) //(28'd2000)
);
/////////////////////////////////////////////////////////////////////////////
// Task definitions
/////////////////////////////////////////////////////////////////////////////
// Generate a block of data words of random size, containing subsequent
// numbers
/////////////////////////////////////////////////////////////////////////////
task automatic generate_block(ref block_t blk);
int size = $dist_uniform(seed, g_block_size_min, g_block_size_max);
int i;
for(i = 0; i<size; i++)
begin
if (i == 0)
blk.first_wrd = tx_counter_val; // Copy first word
if (i == size-1)
blk.last_wrd = tx_counter_val; // Copy last word
blk.words.push_back(tx_counter_val++); //
if (i == 0 || i==size-1)
blk.wrd_cnt.push_back(i+1);// first or last words
else
blk.wrd_cnt.push_back(0); // All other words
end //for loop
endtask // generate_block
////////////////////////////////////////////////////////
task automatic generate_frame(ref streamer_frame_t frm);
int size = $dist_uniform(seed, g_frame_size_min, g_frame_size_max);
int i;
block_t blk;
for(i = 0; i<size; i++)
begin
blk.words = {};
blk.wrd_cnt = {};
generate_block(blk);
frm.blocks.push_back(blk);
end
endtask
// Sends out a data block (blk) by driving TX_(DVALID, DATA, LAST) lines
// of the TX streamer
/////////////////////////////////////////////////////////////////////////////
task automatic send_block(ref block_t blk);
int i = 0;
////$display("Sending block of %d words...", blk.words.data.size());
while(i < blk.words.size())
begin
if(tx_streamer_dreq) begin
// assert the TX_LAST line on the last word in the current block
tx_streamer_last <= (i == (blk.words.size() - 1)) ? 1 : 0;
tx_streamer_data <= blk.words[i];
//$display("Data to be sent is %d*****\n", tx_streamer_data);
tx_streamer_dvalid <= 1;
i++;
end else
tx_streamer_dvalid <= 0;
@(posedge clk);
end // while (i < blk.words.data.size())
tx_streamer_dvalid <= 0;
tx_streamer_last <= 0;
endtask // send_block
///////////////////////////////////////////////////////////////////
task automatic send_frame(ref streamer_frame_t frm);
int i = 0;
while (i < frm.blocks.size()) begin
send_block(frm.blocks[i]);
i++;
end
endtask
///////////////////////////////////////////////////////////////////
// WISHBONE LINK CONTROL
///////////////////////////////////////////////////////////////////
//Continuous assignements to WR fabric signals
logic [ 15 : 0] corrupt_mask = 16'h0000;
logic drop_frm = 0;
logic link_ok= 1;
logic delay_link= 0;
task automatic link_good ();
int frm_counter = 0;
//$display ("LINKOK---------");
@(posedge tx_frame_sent) link_ok = 1;
corrupt_mask = 16'h0000;
drop_frm = 0;
delay_link= 0;
frm_counter=0;
while (frm_counter < 3 ) begin
@(posedge tx_wb_cyc) //at every new frame
frm_counter ++;
end
endtask;
task automatic corrupt_data ();
int i, j, n;
int frm_counter = 0;
corrupt_mask = 16'h0000;
link_ok= 0;
n={$random} % 2; //number of frames to be corrupted
j = {$random} % 15;
$display("=====BIT FLIP================");
@(negedge rx_frame_received)
corrupt_mask [j] = ~corrupt_mask [j];
@(negedge rx_wb_ack) link_good ();
endtask //corrupt_data
task automatic drop_frame ();
int n, i;
link_ok= 0;
n={$random} % 5; //number of frames to be dropped
for (i=0; i<n; i++)
begin
@(negedge tx_wb_cyc)
drop_frm = 1;
end
@(negedge tx_wb_cyc)
drop_frm = 0;
endtask //drop_frame
task automatic delay_frame ();
link_ok= 0;
delay_link = 0;
wait (rx_wb_stall == 1) //to avoid changes at startup
// @(negedge rx_wb_stall)
@(posedge tx_frame_sent)
delay_link = 1;
#10000;
delay_link = 0;
link_good ();
endtask //delay_frame
assign data_to_rx = data_from_tx ^ corrupt_mask;
assign rx_wb_stb = tx_wb_stb & ~drop_frm;
assign rx_wb_cyc = tx_wb_cyc & ~drop_frm;
assign tx_wb_stall = rx_wb_stall | delay_link; //extend pulse
assign tx_wb_ack = rx_wb_ack;// & ~delay_link;
// assign tx_wb_stall = delay_link; //extend pulse
// assign tx_wb_stall = ~rx_wb_cyc ? (1'b0 | delay_link) : (~rx_wb_ack | delay_link);
///////////////////////////////////////////////////////////////////
//RECEPTION LOGIC//
// Receives a data block from the RX streamer and puts it in (blk).
// Returns non-zero done value when blk contains a complete block
/////////////////////////////////////////////////////////////////////////////
task automatic receive_block(ref block_t blk, ref int new_block, ref int done);
bit[g_word_width-1:0] wrd[$];
bit[g_word_width-1:0] word1;
bit[g_word_width-1:0] wordn;
wrd= blk.words;
word1=blk.first_wrd;
wordn=blk.last_wrd;
//$display("BEFORE valid streamer block--------");
if(rx_streamer_dvalid)
begin
//$display("valid streamer block--------");
if(rx_streamer_first && new_block == 1)
begin
$display("streamer first---------");
new_block = 0;
wrd = {};
blk.wrd_cnt = {};
blk.wrd_cnt.push_back(1);
word1 = rx_streamer_data;
end
else if (!rx_streamer_last && !rx_streamer_first)
begin
blk.wrd_cnt.push_back(0);
end
wrd.push_back(rx_streamer_data);
if (rx_streamer_last && new_block == 0)
begin
//$display(" streamer last-------------");
wordn = rx_streamer_data;
if (wrd.size() > 1)
blk.wrd_cnt.push_back(wrd.size()); //Last word in block
done = 1;
end
else
begin
done = 0;
end
blk.words=wrd;
blk.first_wrd = word1;
blk.last_wrd = wordn;
end
endtask // receive_block
// TX block stream generation
initial forever
begin
//int i;
streamer_frame_t frm;
frm.blocks = {};
wait(rst_n == 1'b1);
rx_streamer_dreq <= 1;//({$random} % 100 < 90) ? 1 : 0;
//Rx Test1 fixed latency test
//fixed_latency <= 28'h200;
generate_frame(frm);
for (int i=0; i < frm.blocks.size(); i++) begin
frm.blocks[i].dropped = drop_frm;
tx_blk_queue.push_back(frm.blocks[i]);
end
send_frame(frm);
@(posedge clk) tx_flush = 1;
@(posedge clk) tx_flush = 0;
tx_frm_queue.push_back(frm);
wait(tx_frame_sent);
//wait (rx_latency_valid) $display("Latency received is %d---\n", rx_latency);
end
/* initial forever
begin
//randcase
//10 : drop_frame ();
//10 : corrupt_data ();
// link_good ();
//10 : delay_frame ();
//endcase;
end */
// TESTBENCH VERIFICATION
// Client-side reception logic. Compares the received records with their copies
// stored in the transfer queue.
int new_block = 1;
int no_curr_req = 0;
always@(posedge clk)
if(rst_n)
begin
block_t rblk;
streamer_frame_t tfrm, l_tfrm;
automatic int done = 0;
if (rx_streamer_lost_frm == 1)
begin
int i, n_lost_frames;
n_lost_frames = rx_streamer_lost_frm_cnt;
for (i = 0; i < n_lost_frames; i++) begin
l_tfrm = tx_frm_queue.pop_front();
//$display ("%d have been lost, frame %p is POPPED\n=====", n_lost_frames, l_tfrm );
end
//$display ("%d have been lost, the new Tx queue is %p\n=====", n_lost_frames, tx_frm_queue );
end
receive_block(rblk, new_block, done);
if(done)
begin
automatic block_t tblk;
//$display(" frame OUT is %p \n********", tx_blk_queue);
//if (tx_blk_queue.size() != 0)
//else begin
tblk = tx_blk_queue.pop_front(); // $display(" OLD TBLK is %p \n********", tblk);
//$display(" FRAME size is %d \n%%%%%%%%%%%%", tfrm.blocks.size());
if (tfrm.blocks.size() == 0) begin
tfrm = tx_frm_queue.pop_front();
//$display(" FRAME is %p \n%%%%%%%%%%%%", tfrm); end
tblk = tfrm.blocks.pop_front(); //$display(" NEW TBLK is %p \n********", tblk);
//$display(" FRAME AFTER POP is %p \n%%%%%%%%%%%%", tfrm);
// $display(" QUEUE is %p \n%%%%%%%%%%%%", tx_blk_queue);
//end
// $display(" block OUT is %p \n********", tblk);
//$display("Received block of %d words....\n", tblk_size);
new_block = 1;
// ===============================================================
// TEST 1: Check Txed and Rxed blocks match, first and last word are signalled correctly
if(tblk.words != rblk.words)
begin
$error("TEST 1 ---> FAILED\n####Sent block does not match received block\n");
$display("Txed is %p, Rxed equals %p", tblk, rblk);
$stop;
end else begin
$display("****\nTEST 1 ---> PASSED\n****Correct words received\n");
end
// TEST 5: Check that when rx_dreq is not asserted data stops at the next clk cycle
if (rx_streamer_dreq == 1)
no_curr_req = 0;
else if (rx_streamer_dreq == 0 && no_curr_req == 0)
no_curr_req = 1;
else if (no_curr_req == 1 && rx_streamer_dvalid == 1)
begin
$error("TEST 5 ---> FAILED\n####Pulse rx_request is not asserted should not receive data.\n");
$stop;
end
else begin
$display("****\nTEST 5 ---> PASSED\n****No data output when Rx_request is not asserted\n");
end
end
end // else: !if(!rst_n)
end
always@(posedge clk)
if (delay_link == 0)
begin
if(rst_n && rx_latency_valid)
begin
wait (rx_frame_received)
$display ("Latency calculated %d\n", clk_cycle_counter_before-clk_cycle_counter_after);
$display("*************This frame's latency: %.3f microseconds*************************************************\n", (rx_latency));
end
end
endmodule // main
Wed May 03 16:18:04 W. Europe Daylight Time 2017
Trace back: invalid command name ""
while executing
"$tree expandeditems -worm"
(procedure "_resetTree" line 6)
invoked from within
"_resetTree $w"
(procedure "QObjects::sort" line 4)
invoked from within
"QObjects::sort .main_pane.objects 0 ascending"
("eval" body line 1)
invoked from within
"eval $itk_option(-sortcommand) $column $dir"
(object "::.main_pane.objects.interior.cs.body.tree" method "::vsimwidgets::Hierarchy::sort" body line 26)
invoked from within
"sort $sortIdx $dir"
(object "::.main_pane.objects.interior.cs.body.tree" method "::vsimwidgets::Hierarchy::_initializeSortColumn" body line 10)
invoked from within
"::.main_pane.objects.interior.cs.body.tree _initializeSortColumn"
(in namespace inscope "::vsimwidgets::Hierarchy" script line 1)
invoked from within
"namespace inscope ::vsimwidgets::Hierarchy {::.main_pane.objects.interior.cs.body.tree _initializeSortColumn}"
("after" script)
<2: ::tkerror {invalid command name ""}
<1: ::bgerror {invalid command name ""}
Wed May 24 15:41:46 W. Europe Daylight Time 2017
Trace back: invalid command name ""
while executing
"$tree expandeditems -worm"
(procedure "_resetTree" line 6)
invoked from within
"_resetTree $w"
(procedure "QObjects::sort" line 4)
invoked from within
"QObjects::sort .main_pane.objects 0 ascending"
("eval" body line 1)
invoked from within
"eval $itk_option(-sortcommand) $column $dir"
(object "::.main_pane.objects.interior.cs.body.tree" method "::vsimwidgets::Hierarchy::sort" body line 26)
invoked from within
"sort $sortIdx $dir"
(object "::.main_pane.objects.interior.cs.body.tree" method "::vsimwidgets::Hierarchy::_initializeSortColumn" body line 10)
invoked from within
"::.main_pane.objects.interior.cs.body.tree _initializeSortColumn"
(in namespace inscope "::vsimwidgets::Hierarchy" script line 1)
invoked from within
"namespace inscope ::vsimwidgets::Hierarchy {::.main_pane.objects.interior.cs.body.tree _initializeSortColumn}"
("after" script)
<2: ::tkerror {invalid command name ""}
<1: ::bgerror {invalid command name ""}
......@@ -109,7 +109,10 @@ module main;
#(
.g_data_width (g_record_size),
.g_tx_threshold (8),
.g_tx_timeout (512)
.g_tx_buffer_size(16),
.g_tx_max_words_per_frame(16),
.g_tx_timeout (512),
.g_simulation(1)
)
U_TX_Streamer
(
......@@ -141,7 +144,8 @@ module main;
rx_streamer
#(
.g_data_width (g_record_size)
.g_data_width (g_record_size),
.g_simulation(1)
)
U_RX_Streamer
(
......
......@@ -165,7 +165,10 @@ module main;
#(
.g_data_width (g_word_width),
.g_tx_threshold (8),
.g_tx_timeout (128)
.g_tx_buffer_size(16),
.g_tx_max_words_per_frame(16),
.g_tx_timeout (128),
.g_simulation(1)
)
U_TX_Streamer
(
......@@ -198,7 +201,8 @@ module main;
rx_streamer
#(
.g_data_width (g_word_width)
.g_data_width (g_word_width),
.g_simulation(1)
)
U_RX_Streamer
(
......
......@@ -4,7 +4,7 @@
// URL : http://www.ohwr.org/projects/wr-cores/wiki/WR_Streamers
//-----------------------------------------------------------------------------
// File : main.sv
// Author(s) : Tomasz Wlostosky,
// Author(s) : Tomasz Wlostosky ,
// Extended by Denia Bouhired <denia.bouhired@cern.ch>
// Company : CERN (BE-CO-HT)
// Created : 2017-04-28
......@@ -53,16 +53,20 @@ module main;
parameter g_word_width = 64;
parameter g_tx_thr = 16;
parameter g_tx_tm_out = 128;
parameter g_max_wrds_pr_frm = 16;
parameter g_max_wrds_pr_frm = 24;
parameter g_fixed_latency = 28'd1024;
// Min and max block size
parameter g_block_size_min = 1;
parameter g_block_size_max = 5;
parameter block_size_min = 1;
parameter block_size_max = 5;
// Min and max frame size
parameter g_frame_size_min = 1;
parameter g_frame_size_max = 3;
parameter frame_size_min = 1;
parameter frame_size_max = 3;
// Maximum number of frames
parameter max_num_frames = 5;
// MAC address of the TX side
parameter bit [47:0] g_mac_tx = 48'h112233445566;
......@@ -79,19 +83,24 @@ module main;
// Clock & reset
// Fake White Rabbit reference clock (125 MHz) and cycle counter (we don't use
// TAI counter as the latency never exceeds 1 second...)
reg clk_ref = 0;
reg [27:0] tm_cycle_counter = 0;
// System clock & reset
reg clk = 0;
reg rst_n = 0;
reg [27:0] clk_cycle_counter = 0;
int clk_cycle_counter_before = 0;
int clk_cycle_counter_after = 0;
int clk_cycle_ctr_rx_rcvd = 0;
int clk_cycle_ctr_rx_dvalid = 0;
int clk_cycle_tmout_ctr_before = 0;
int clk_cycle_tmout_ctr_after = 0;
int clk_cycle_frm_txed = 0;
int clk_cycle_frm_valid = 0;
// TX Streamer signals
reg tx_streamer_dvalid = 0;
reg [g_word_width-1:0] tx_streamer_data = 0;
//wire[15:0] data_from_tx= 0;
reg tx_streamer_last = 0;
reg tx_flush = 0;
wire tx_streamer_dreq;
......@@ -113,21 +122,16 @@ module main;
//Fixed latency
reg [27:0] fixed_latency = 28'h0;
// Fake White Rabbit reference clock (125 MHz) and cycle counter (we don't use
// TAI counter as the latency never exceeds 1 second...)
reg clk_ref = 0;
reg [27:0] tm_cycle_counter = 0;
// Currently transmitted counter value
integer tx_counter_val = 0;
int tx_counter_val = 0;
//Seed for random generator
int seed = 0;
int seed = 0;
// Wishbone link interface
bit [15 : 0] data_from_tx;
logic [15 : 0] data_to_rx ;
bit [15 : 0] fab_data_from_tx;
logic [15 : 0] fab_data_to_rx ;
logic tx_wb_cyc, rx_wb_cyc;
logic tx_wb_stb, rx_wb_stb;
logic tx_wb_ack;
......@@ -141,24 +145,36 @@ module main;
logic flush_test = 0;
logic timeout_test = 0;
logic max_words_test = 0;
logic min_words_test = 0;
logic flatency_test = 0;
logic link_tests = 0;
/////////////////////////////////////////////////////////////////////////////
// Initialise and set, reset, clocks and clk counter
/////////////////////////////////////////////////////////////////////////////
initial
begin
#100 rst_n = 1;
end;
logic frm_drop_test = 0;
logic comparator_test = 1;
int link_tests = 0;
string current_test = "IDLE";
// Initialise and set, reset, clocks and clk counter
initial
begin
#100 rst_n = 1;
end;
always #8 clk <= ~clk;
// --------------------------------------------------------------------------
//WARNING: As of now, the fixed latency implementation in xrx_streamer assumes
//that ref_clk period is equal to sys_clk period/2.
//This is a bug and should be fixed in future releases
always #8ns clk <= ~clk;
always #4ns clk_ref <= ~clk_ref; //generate 125 MHz WR Clock
// --------------------------------------------------------------------------
//Set counter values for time measurements
always@(posedge clk_ref) tm_cycle_counter <= tm_cycle_counter + 1;
always@(posedge clk) clk_cycle_counter <= clk_cycle_counter + 1;
always@(posedge tx_streamer_last) clk_cycle_counter_before = clk_cycle_counter;
always@(posedge tx_wb_cyc) clk_cycle_counter_after = clk_cycle_counter;
always@(posedge tx_streamer_last) clk_cycle_tmout_ctr_before = clk_cycle_counter;
always@(posedge rx_frame_received) clk_cycle_tmout_ctr_after = clk_cycle_counter;
// Instantiation of the streamers. The TX streamer will assemble packets
// containing max. 8 records, or flush the buffer after 128 clk cycles if
......@@ -179,7 +195,7 @@ module main;
.clk_sys_i(clk),
.rst_n_i (rst_n),
.src_dat_o (data_from_tx),// (mac.dat_i),
.src_dat_o (fab_data_from_tx),
.src_adr_o (mac.adr),
.src_sel_o (mac.sel),
.src_cyc_o (tx_wb_cyc),
......@@ -217,7 +233,7 @@ module main;
.clk_sys_i (clk),
.rst_n_i (rst_n),
.snk_dat_i (data_to_rx),
.snk_dat_i (fab_data_to_rx),
.snk_adr_i (mac.adr),
.snk_sel_i (mac.sel),
.snk_cyc_i (rx_wb_cyc),
......@@ -237,8 +253,6 @@ module main;
.rx_data_o (rx_streamer_data),
.rx_valid_o (rx_streamer_dvalid),
.rx_dreq_i (rx_streamer_dreq),
//.rx_lost_p1_o (rx_streamer_lost),
.rx_lost_blocks_p1_o (rx_streamer_lost_blks),
.rx_lost_frames_p1_o (rx_streamer_lost_frm),
.rx_lost_frames_cnt_o (rx_streamer_lost_frm_cnt),
......@@ -256,19 +270,11 @@ module main;
.cfg_fixed_latency_i (fixed_latency) //(28'd2000)
);
/////////////////////////////////////////////////////////////////////////////
// --------------------------------------------------------------------------
// Struct definition
/////////////////////////////////////////////////////////////////////////////
// --------------------------------------------------------------------------
typedef struct{ bit[g_word_width-1:0] words[$];
int wrd_cnt[$];
bit[g_word_width-1:0] first_wrd;
bit[g_word_width-1:0] last_wrd;
bit dropped;
} block_t; //block is a number of words with info about first
// and last
......@@ -276,71 +282,59 @@ module main;
} streamer_frame_t; //frame contains a collection of blocks
// Transfer queue. Used to pass sent data to the verification process.
block_t tx_blk_queue[$];
streamer_frame_t tx_frm_queue[$]; /////////////////////////////////////////////////////////////////////////////
// Transfer queue. Used to pass sent data to the verification process.
block_t tx_blk_queue[$]; //queue of trasmitted blocks
streamer_frame_t tx_frm_queue[$]; //queue of trasmitted frames
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// Task definitions
/////////////////////////////////////////////////////////////////////////////
// --------------------------------------------------------------------------
// Generate a block of data words of random size, containing subsequent
// numbers
/////////////////////////////////////////////////////////////////////////////
task automatic generate_block(ref block_t blk, int size);
int i;
for(i = 0; i<size; i++)
begin
if (i == 0)
blk.first_wrd = tx_counter_val; // Copy first word
if (i == size-1)
blk.last_wrd = tx_counter_val; // Copy last word
blk.words.push_back(tx_counter_val++); //
if (i == 0 || i==size-1)
blk.wrd_cnt.push_back(i+1);// first or last words
else
blk.wrd_cnt.push_back(0); // All other words
end //for loop
int i;
for(i = 0; i<size; i++)
begin
blk.words.push_back(tx_counter_val++); //
end //for loop
endtask // generate_block
////////////////////////////////////////////////////////
task automatic generate_frame(ref streamer_frame_t frm, int frm_size, int blk_size);
int i;
block_t blk;
for(i = 0; i<frm_size; i++)
begin
blk.words = {};
blk.wrd_cnt = {};
generate_block(blk, blk_size);
frm.blocks.push_back(blk);
end
endtask
// --------------------------------------------------------------------------
// generate a number of blocks each with a number of words
//store blks sent in frame queue
task automatic generate_frame(ref streamer_frame_t frm, int frm_size, int blk_size);
int i;
block_t blk;
for(i = 0; i<frm_size; i++)
begin
blk.words = {};
generate_block(blk, blk_size);
frm.blocks.push_back(blk);
end //for loop
endtask // generate_frame
// -------------------------------------------------------------------------
// Sends out a data block (blk) by driving TX_(DVALID, DATA, LAST) lines
// of the TX streamer
/////////////////////////////////////////////////////////////////////////////
task automatic send_block(ref block_t blk);
int i = 0;
////$display("Sending block of %d words...", blk.words.data.size());
while(i < blk.words.size())
begin
if(tx_streamer_dreq) begin
// assert the TX_LAST line on the last word in the current block
tx_streamer_last <= (i == (blk.words.size() - 1)) ? 1 : 0;
tx_streamer_data <= blk.words[i];
//$display("Data to be sent is %d*****\n", tx_streamer_data);
tx_streamer_dvalid <= 1;
//clk_cycle_counter_before = clk_cycle_counter;
i++;
end else
tx_streamer_dvalid <= 0;
......@@ -351,10 +345,10 @@ module main;
tx_streamer_last <= 0;
endtask // send_block
///////////////////////////////////////////////////////////////////
// -------------------------------------------------------------------------
// send frame of multiple blocks
task automatic send_frame(ref streamer_frame_t frm);
int i = 0;
......@@ -362,334 +356,388 @@ module main;
send_block(frm.blocks[i]);
i++;
end
endtask
endtask // send_block
///////////////////////////////////////////////////////////////////
// WISHBONE LINK CONTROL
///////////////////////////////////////////////////////////////////
// -------------------------------------------------------------------------
//routine to generate and send a frame
task automatic gen_send_frm(ref streamer_frame_t frm, int frm_size, int blk_size);
frm.blocks = {};
generate_frame(frm, frm_size, blk_size);
send_frame(frm);
endtask //gen_send_frm
// -------------------------------------------------------------------------
// WISHBONE LINK CONTROL
// -------------------------------------------------------------------------
logic [ 15 : 0] corrupt_mask = 16'h0000;
logic drop_frm = 0;
logic link_ok= 1;
logic delay_link= 0;
//Continuous assignements to WR fabric signals
assign data_to_rx = data_from_tx ^ corrupt_mask;
assign rx_wb_stb = tx_wb_stb & ~drop_frm;
assign rx_wb_cyc = tx_wb_cyc & ~drop_frm;
logic [ 15 : 0] corrupt_mask = 16'h0000; //to use for corrupted blocks
logic drop_frm = 0;
logic delay_link= 0;
//Continuous assignements to WR fabric signals
assign fab_data_to_rx = fab_data_from_tx ^ corrupt_mask;
assign rx_wb_stb = tx_wb_stb & (~drop_frm);// | ~delay_link);
assign rx_wb_cyc = tx_wb_cyc & (~drop_frm);// | ~delay_link);
assign tx_wb_stall = rx_wb_stall | delay_link;
assign tx_wb_ack = rx_wb_ack;
task automatic drop_frame ();
int n, i;
link_ok= 0;
//n={$random} % 5; //number of frames to be dropped
n=5;
for (i=0; i<n; i++)
begin
@(negedge tx_wb_cyc)
drop_frm = 1;
end
@(negedge tx_wb_cyc)
drop_frm = 0;
assign tx_wb_ack = rx_wb_ack | delay_link;
task automatic drop_frame (int n);
//n={$random} % 5; //number of frames to be dropped
for (int i=0; i<n; i++)
begin
@(posedge tx_wb_cyc) drop_frm = 1;
end
@(negedge tx_wb_cyc) drop_frm = 0;
endtask //drop_frame
task automatic delay_frame ();
link_ok= 0;
//##########################################################################
//Is not being used currently as not fully working
//The latency output is incorrect
//could be that if this delay is triggered at a different point the output
//would be correct
task automatic delay_frame ();
delay_link = 0;
wait (rx_wb_stall == 1) //to avoid changes at startup
//wait (rx_wb_stall == 1) //to avoid changes at startup
// @(negedge rx_wb_stall)
@(posedge tx_frame_sent)
delay_link = 1;
@(posedge rx_wb_stall) delay_link = 1;
#10000;
delay_link = 0;
link_good ();
endtask //delay_frame
task automatic link_good ();
int frm_counter = 0;
//$display ("LINKOK---------");
@(posedge tx_frame_sent) link_ok = 1;
corrupt_mask = 16'h0000;
drop_frm = 0;
delay_link= 0;
frm_counter=0;
while (frm_counter < 3 ) begin
@(posedge tx_wb_cyc) //at every new frame
frm_counter ++;
end
endtask;
@(posedge clk) delay_link = 0;
//link_good ();
endtask //delay_frame
//##########################################################################
///////////////////////////////////////////////////////////////////
//RECEPTION LOGIC//
// -------------------------------------------------------------------------
// RECEIVER LOGIC//
// Receives a data block from the RX streamer and puts it in (blk).
// Returns non-zero done value when blk contains a complete block
/////////////////////////////////////////////////////////////////////////////
// -------------------------------------------------------------------------
task automatic receive_block(ref block_t blk, ref int new_block, ref int done);
bit[g_word_width-1:0] wrd[$];
bit[g_word_width-1:0] word1;
bit[g_word_width-1:0] wordn;
wrd= blk.words;
word1=blk.first_wrd;
wordn=blk.last_wrd;
if(rx_streamer_dvalid)
begin
if(rx_streamer_first && new_block == 1)
begin
new_block = 0;
wrd = {};
blk.wrd_cnt = {};
blk.wrd_cnt.push_back(1);
word1 = rx_streamer_data;
end
else if (!rx_streamer_last && !rx_streamer_first)
begin
blk.wrd_cnt.push_back(0);
end
wrd.push_back(rx_streamer_data);
if (rx_streamer_last && new_block == 0)
begin
wordn = rx_streamer_data;
if (wrd.size() > 1)
blk.wrd_cnt.push_back(wrd.size()); //Last word in block
done = 1;
end
done = 1;
else
begin
done = 0;
end
done = 0;
blk.words=wrd;
blk.first_wrd = word1;
blk.last_wrd = wordn;
end
endtask // receive_block
//Check transmission has been initiated auomatically
// TX block stream generation
// -------------------------------------------------------------------------
// SIMULATION TESTBENCH: Currently setup for 6 tests/use-cases
// -------------------------------------------------------------------------
int rand_blk_size, blk_size, rand_frm_size, frm_size;
int num_frm_dropped;
int test_num;
int test_tm_out;
initial forever
begin
int blk_size;
int frm_size = 1;
streamer_frame_t frm;
block_t blk;
fixed_latency = 28'd0;
wait(rst_n == 1'b1);
rand_frm_size = $urandom_range(block_size_max,block_size_min);
rand_blk_size = $urandom_range(frame_size_max,frame_size_min);
rx_streamer_dreq <= 1;//({$random} % 100 < 90) ? 1 :
//list of tests
max_words_test = 0; // Checks test 1
timeout_test = 0; // Checks test 2
flush_test = 0; // Checks test 3
flatency_test = 0;
flatency_test = 0;
link_tests = 0;
fixed_latency = 28'd0;
wait(rst_n == 1'b1); //make sure reset is not asserted
rx_streamer_dreq <= 1; //({$random} % 100 < 90) ? 1 :
//list of tests
test_tm_out = 10000; //10us
test_num = 1;
flush_test = 0;
timeout_test = 0;
max_words_test = 0;
min_words_test = 0;
flatency_test = 0;
frm_drop_test = 0;
//Tx TEST 1: Check that maximum number of words/frame triggers transmission
//-------------------------------------------------------------------------
frm.blocks = {};
//blk.wrd_cnt = {};
blk_size = g_max_wrds_pr_frm + 10;
// generate_block(blk, blk_size);
generate_frame(frm, frm_size, blk_size);
$display ("Send frame: %p \n", frm);
// send_block(blk);
send_frame(frm);
tx_frm_queue.push_back(frm);
// tx_blk_queue.push_back(blk);
wait (tx_frame_sent) max_words_test = 1;
$display ("Frame transmitted after limit of words/frame is reached\n");
//Tx TEST 1: Check that when tx_flush_i is asserted, current frame is txed
//-------------------------------------------------------------------------
current_test = "Tx FLUSH";
blk_size = rand_blk_size;
frm_size = rand_frm_size;
gen_send_frm(frm, frm_size, blk_size);
@(posedge clk) tx_flush = 1;
@(posedge clk) tx_flush = 0;
tx_frm_queue.push_back(frm);
fork : wait_or_timeout_t1
begin
#test_tm_out;
$display ("[%t ns]: >>> FAILED - TEST %d - %s \n", $time, test_num, current_test );
disable wait_or_timeout_t1;
end
begin
@(posedge rx_frame_received) flush_test = 1;
$display ("[%t ns]: PASSED - TEST %d - %s \n", $time, test_num, current_test );
disable wait_or_timeout_t1;
end
join
wait (rx_frame_received); //make sure frame is sent
wait (tx_frame_sent);
test_num ++;
//Tx TEST 2: Check that when timeout is reached, frame is transmitted
//-------------------------------------------------------------------------
// blk.words = {};
// blk.wrd_cnt = {};
frm.blocks = {};
blk_size = 2; //just 2 words
// generate_block(blk, blk_size);
generate_frame(frm, frm_size, blk_size);
$display ("Send frame: %p \n", frm);
// send_block(blk);
send_frame(frm);
current_test = "Tx TIMEOUT";
blk_size = $urandom_range(g_tx_thr - 2, 1); //send less words than minimum threshold
frm_size = 1 ; //For timeout test no need for multiple blocks
gen_send_frm(frm, frm_size, blk_size);
tx_frm_queue.push_back(frm);
fork : wait_or_timeout_t2
begin
#((g_tx_tm_out* 2) * 16); //time before test fails. wait long enough
$display ("[%t ns]: >>> FAILED - TEST %d - %s \n", $time, test_num, current_test );
disable wait_or_timeout_t2;
end
begin
@(posedge rx_frame_received) timeout_test = 1;
$display ("[%t ns]: PASSED - TEST %d - %s \n", $time, test_num, current_test );
disable wait_or_timeout_t2;
end
join
wait (rx_frame_received);
wait (tx_frame_sent);
test_num ++;
// tx_blk_queue.push_back(blk);
wait(tx_frame_sent)
$display ("Frame transmitted after timeout: %d\n", clk_cycle_counter_after-clk_cycle_counter_before);
//Tx TEST 3: Check that minimum number of words/frame triggers transmission
//-------------------------------------------------------------------------
current_test = "Tx MIN WORDS";
blk_size = g_tx_thr + 2; //Tx 1 more words that the limit
frm_size = 1;
if (g_tx_tm_out == clk_cycle_counter_after-clk_cycle_counter_before - 5)
begin
$display ("Tx timeout test PASSED \n");
timeout_test = 1;
end
else
begin
$error ("Failed timeout test");
$stop;
end
gen_send_frm(frm, frm_size, blk_size); //generate and send a frame
tx_frm_queue.push_back(frm); //push txed frame into Tx Q
//Tx TEST 3: Check that when tx_flush_i is asserted, current frame is txed
//-------------------------------------------------------------------------
// blk.words = {};
// blk.wrd_cnt = {};
frm.blocks = {};
blk_size = 4; //just 4 words
// generate_block(blk, blk_size);
generate_frame(frm, frm_size, blk_size);
fork : wait_or_timeout_t3
begin
#test_tm_out;
$display ("[%t ns]: >>> FAILED - TEST %d - %s \n", $time, test_num, current_test );
disable wait_or_timeout_t3;
end
begin
@(posedge rx_frame_received) min_words_test = 1;
$display ("[%t ns]: PASSED - TEST %d - %s \n", $time, test_num, current_test );
disable wait_or_timeout_t3;
end
join
$display ("Send frame: %p \n", frm);
// send_block(blk);
send_frame(frm);
@(posedge clk) tx_flush = 1;
@(posedge clk) tx_flush = 0;
wait (rx_frame_received);
wait (tx_frame_sent);
test_num ++;
//Tx TEST 4: Check that minimum number of words/frame triggers transmission
//-------------------------------------------------------------------------
current_test = "Tx MAX WORDS";
blk_size = g_max_wrds_pr_frm; //blk_size *frm_size must be int multiple
frm_size = 2; // of g_max_wrds_pr_frm
fork
begin
gen_send_frm(frm, frm_size, blk_size); //generate and send a frame
tx_frm_queue.push_back(frm); //push txed frame into Tx Q
end
fork : wait_or_timeout_t4
begin
#test_tm_out;
$display ("[%t ns]: >>> FAILED - TEST %d - %s \n", $time, test_num, current_test );
disable wait_or_timeout_t4;
end
begin
@(posedge rx_frame_received) max_words_test = 1;
$display ("[%t ns]: PASSED - TEST %d - %s \n", $time, test_num, current_test );
wait (rx_frame_received);
wait (tx_frame_sent);
disable wait_or_timeout_t4;
end
join
begin
for (int i=0; i< (frm_size*blk_size)/g_max_wrds_pr_frm; i++) begin
wait (rx_frame_received);
wait (tx_frame_sent);
end
end
join
// tx_blk_queue.push_back(blk);
tx_frm_queue.push_back(frm);
wait(tx_frame_sent) flush_test = 1;
$display ("Frame transmitted after flush asserted");
test_num ++;
// Rx Test 4: Check the fixed latency is correct
// Rx Test 5: Check the fixed latency is correct
//-----------------------------------------------
// blk.words = {};
// blk.wrd_cnt = {};
frm.blocks = {};
blk_size = 4;
fixed_latency = 28'd1200;
// generate_block(blk, blk_size);
generate_frame(frm, frm_size, blk_size);
$display ("Send frame: %p \n", frm);
// send_block(blk);
send_frame(frm);
// tx_blk_queue.push_back(blk);
#1us // make sure that the previous frame has been received, otherwise
// the testbench might wrongly measure the latency
current_test = "Rx FIXED-LATENCY";
blk_size = rand_blk_size;
frm_size = rand_frm_size;
fixed_latency = g_fixed_latency;
gen_send_frm(frm, frm_size, blk_size);
@(posedge clk) tx_flush = 1;
//clk_cycle_ctr_rx_rcvd = tm_cycle_counter;
@(posedge clk) tx_flush = 0;
tx_frm_queue.push_back(frm);
wait (rx_frame_received) clk_cycle_ctr_rx_rcvd = tm_cycle_counter;
wait (rx_streamer_dvalid) clk_cycle_ctr_rx_dvalid = tm_cycle_counter;
if ((fixed_latency <= clk_cycle_ctr_rx_dvalid - clk_cycle_ctr_rx_rcvd+18) &&
(fixed_latency >= clk_cycle_ctr_rx_dvalid - clk_cycle_ctr_rx_rcvd-18) )
@(posedge U_TX_Streamer.U_Wrapped_Streamer.U_Fab_Source.sof_i) clk_cycle_frm_txed = tm_cycle_counter;
//$display("frame received @ %d, time %t\n", clk_cycle_frm_txed, $time);
@(posedge rx_streamer_first) clk_cycle_frm_valid = tm_cycle_counter;
//$display("frame out valid @ %d, time %t\n", clk_cycle_frm_valid, $time);
//fixed latency value is checked against range since i/o interface
//of streamers does not allow for exact latency measurement without
//probing an internal signal
if ((fixed_latency <= clk_cycle_frm_valid - clk_cycle_frm_txed+24) &&
(fixed_latency >= clk_cycle_frm_valid - clk_cycle_frm_txed-24) )
begin
$display ("Fixed latency test PASSED \n");
$display ("Fixed latency set to %.3f us, Rx output valid @ %.3f us",
real'(fixed_latency) * 0.016, real'(clk_cycle_ctr_rx_dvalid-
clk_cycle_ctr_rx_rcvd) * 0.016);
$display ("[%t ns]: PASSED - TEST %d - %s \n", $time, test_num, current_test );
//$display ("Fixed latency set to %.3f us, Rx output valid @ %.3f us",
//real'(fixed_latency) * 0.008, real'(clk_cycle_frm_valid-
//clk_cycle_frm_txed) * 0.008);
flatency_test = 1;
end
else
begin
$error ("Failed Fixed latency test");
$display ("Fixed latency set to %.3f us, Rx output valid @ %.3f us",
real'(fixed_latency) * 0.016, real'(clk_cycle_ctr_rx_dvalid-
clk_cycle_ctr_rx_rcvd) * 0.016);
$stop;
$display ("[%t ns]: >>> FAILED - TEST %d - %s \n", $time, test_num, current_test );
$display ("Fixed latency set to %.3f us, Rx output latency valid @ %.3f us",
real'(fixed_latency) * 0.008, real'(clk_cycle_frm_valid-
clk_cycle_frm_txed) * 0.008);
// $stop;
end
test_num ++;
// Rx Test 6: Check frames dropped are signalled correctly
// -----------------------------------------------
current_test = "Rx DROP_FRAMES";
assert (flush_test == 1 && timeout_test == 1 && max_words_test == 1 &&
flatency_test == 1)
num_frm_dropped = $urandom_range(max_num_frames - 1,1);
fork
begin
for (int i=0; i < max_num_frames; i++) begin
gen_send_frm(frm, frm_size, blk_size);
tx_frm_queue.push_back(frm);
@(posedge clk) tx_flush = 1;
@(posedge clk) tx_flush = 0;
wait (tx_frame_sent);
end
end
drop_frame(num_frm_dropped);
@(posedge rx_streamer_lost_frm)
begin
if (num_frm_dropped == rx_streamer_lost_frm_cnt)
begin
$display ("[%t ns]: PASSED - TEST %d - %s \n", $time, test_num, current_test );
frm_drop_test = 1;
end
else
$display ("[%t ns]: >>> FAILED - TEST %d - %s \n", $time, test_num, current_test );
end
join;
test_num ++;
//###################
//NOT working
//Test tries to introduce latency on the fabric link
//in order to see change in the output latency
// Rx Test 6: Check frames dropped are signalled correctly
// -----------------------------------------------
// current_test = "Tx DELAY FRAMES";
// blk_size = 4;
// fork
// begin
// gen_send_frm(frm, frm_size, blk_size);
// tx_frm_queue.push_back(frm);
// @(posedge clk) tx_flush = 1;
// @(posedge clk) tx_flush = 0;
// end
// delay_frame();
// join
// wait (tx_frame_sent);
// test_num ++;
assert (flush_test == 1 && timeout_test == 1 && max_words_test == 1 &&
max_words_test == 1 && flatency_test == 1 && frm_drop_test == 1 &&
comparator_test == 1)
else begin
$error(1, "Transmitter implementation contains errors", $time);
end
end
$error("Streamers implementation contains errors", $time);
$fatal;
end
// initial forever
// begin
// wait(rst_n == 1'b1);
// wait (link_tests ==1);
// link_good ();
// drop_frame ();
// 10 : corrupt_data ();
// link_good ();
// delay_frame ();
// end
end
// TESTBENCH VERIFICATION
//---------------------------------------------------------------------------
// DATA MONITOR
// Client-side reception logic. Compares the received records with their copies
// stored in the transfer queue.
int new_block = 1;
int no_curr_req = 0;
always@(posedge clk)
if(rst_n)
begin
block_t rblk;
streamer_frame_t tfrm, l_tfrm;
automatic int done = 0;
automatic int done = 0;
if (rx_streamer_lost_frm == 1)
begin
int i, n_lost_frames;
n_lost_frames = rx_streamer_lost_frm_cnt;
for (i = 0; i < n_lost_frames; i++) begin
begin
int i, n_lost_frames;
n_lost_frames = rx_streamer_lost_frm_cnt;
for (i = 0; i < n_lost_frames; i++)
begin
l_tfrm = tx_frm_queue.pop_front();
//$display ("%d have been lost, frame %p is POPPED\n=====", n_lost_frames, l_tfrm );
end
//$display ("%d have been lost, the new Tx queue is %p\n=====", n_lost_frames, tx_frm_queue );
end
receive_block(rblk, new_block, done);
end
receive_block(rblk, new_block, done);
if(done)
begin
automatic block_t tblk;
if (tfrm.blocks.size() == 0)
tfrm = tx_frm_queue.pop_front();
tblk = tfrm.blocks.pop_front();
new_block = 1;
// ===============================================================
// TEST 1: Check Txed and Rxed blocks match
if(tblk.words != rblk.words)
begin
$error("TEST 1 ---> FAILED\n####Sent block does not match received block\n");
$display("Txed is %p, Rxed equals %p", tblk, rblk);
$stop;
end else begin
$display("****\nTEST 1 ---> PASSED\n****Correct words received\n");
end
end
automatic block_t tblk;
if (tfrm.blocks.size() == 0)
tfrm = tx_frm_queue.pop_front();
tblk = tfrm.blocks.pop_front();
new_block = 1;
if(tblk.words != rblk.words)
begin
$error("[%t ns]: >> FAILED - TEST - DATA MONITOR \n", $time );
//$display("Txed is %p, Rxed equals %p", tblk, rblk);
comparator_test = 0;
end
else $display ("[%t ns]: PASSED - TEST - DATA MONITOR \n", $time );
// end //while (tfrm.blocks.size() > 0)
end // if (done)
end // else: !if(!rst_n)
always@(posedge clk)
if(rst_n && rx_latency_valid)
$display("*************This frame's latency: %.3f microseconds*************************************************\n", real'(rx_latency) * 0.008);
endmodule // main
......@@ -7,5 +7,5 @@ set StdArithNoWarnings 1
do wave.do
run 10us
wave zoomfull
radix -hex
radix -dec
# make -f Makefile > /dev/null 2>&1
# Modelsim run script for continuous integration (with return code)
# execute: vsim -c -do "run_ci.do"
vsim -L unisim work.main -voptargs="+acc" -suppress 8684,8683
set NumericStdNoWarnings 1
set StdArithNoWarnings 1
set NumericStdNoWarnings 1
do wave.do
run 100us
run 100ms
wave zoomfull
radix -hex
coverage save coverage.ucdb
quit -code [coverage attribute -name TESTSTATUS -concise]
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /main/U_TX_Streamer/tx_flush_p1_i
add wave -noupdate /main/U_TX_Streamer/tx_last_p1_i
add wave -noupdate /main/U_TX_Streamer/tx_data_i
add wave -noupdate /main/U_TX_Streamer/tx_reset_seq_i
add wave -position end sim:/main/current_test
add wave -noupdate /main/U_TX_Streamer/tx_valid_i
add wave -noupdate /main/U_TX_Streamer/tx_data_i
add wave -noupdate /main/U_TX_Streamer/tx_last_p1_i
add wave -noupdate /main/U_TX_Streamer/tx_flush_p1_i
add wave -position end sim:/main/U_TX_Streamer/U_Wrapped_Streamer/fab_src.sof
add wave -position end sim:/main/U_TX_Streamer/U_Wrapped_Streamer/fab_src.eof
add wave -noupdate /main/U_TX_Streamer/tx_frame_p1_o
add wave -noupdate /main/U_TX_Streamer/tx_dreq_o
add wave -position 7 sim:/main/data_from_tx
add wave -position 8 sim:/main/data_to_rx
add wave -position 8 sim:/main/rx_streamer_lost_blks
add wave -position 9 sim:/main/rx_streamer_lost_frm
add wave -position 10 sim:/main/rx_streamer_lost_frm_cnt
add wave -noupdate /main/mac/adr
add wave -noupdate /main/mac/dat_o
add wave -noupdate /main/mac/dat_i
add wave -noupdate /main/mac/sel
add wave -noupdate /main/mac/ack
add wave -noupdate /main/mac/stall
add wave -noupdate /main/mac/err
add wave -noupdate /main/mac/rty
add wave -noupdate /main/mac/cyc
add wave -noupdate /main/mac/stb
add wave -noupdate /main/mac/we
#add wave -noupdate /main/U_TX_Streamer/tx_reset_seq_i
add wave -noupdate /main/U_RX_Streamer/rx_frame_p1_o
add wave -noupdate /main/U_RX_Streamer/rx_dreq_i
add wave -noupdate /main/U_RX_Streamer/rx_valid_o
add wave -noupdate /main/U_RX_Streamer/rx_data_o
add wave -noupdate /main/U_RX_Streamer/rx_first_p1_o
add wave -noupdate /main/U_RX_Streamer/rx_last_p1_o
add wave -noupdate /main/U_RX_Streamer/rx_data_o
add wave -noupdate /main/U_RX_Streamer/rx_valid_o
add wave -noupdate /main/U_RX_Streamer/rx_dreq_i
add wave -noupdate /main/U_RX_Streamer/rx_lost_p1_o
add wave -position end sim:/main/break_link
add wave -position end sim:/main/drop_frm
add wave -position end sim:/main/rx_streamer_lost_frm
add wave -position end sim:/main/rx_streamer_lost_frm_cnt
add wave -noupdate /main/U_RX_Streamer/rx_latency_o
add wave -noupdate /main/U_RX_Streamer/rx_latency_valid_o
add wave -position end sim:/main/rx_streamer_lost_blks
add wave -position end sim:/main/fab_data_from_tx
add wave -position end sim:/main/fab_data_to_rx
add wave -noupdate /main/mac/adr
#add wave -noupdate /main/mac/dat_o
#add wave -noupdate /main/mac/dat_i
#add wave -noupdate /main/mac/sel
#add wave -noupdate /main/mac/ack
#add wave -noupdate /main/mac/stall
add wave -noupdate /main/mac/err
add wave -noupdate /main/mac/rty
#add wave -noupdate /main/mac/cyc
#add wave -noupdate /main/mac/stb
#add wave -noupdate /main/mac/we
add wave -position end sim:/main/delay_link
add wave -position end sim:/main/tx_wb_ack
add wave -position end sim:/main/tx_wb_cyc
add wave -position end sim:/main/tx_wb_stall
add wave -position end sim:/main/tx_wb_stb
add wave -position end sim:/main/rx_wb_ack
add wave -position end sim:/main/rx_wb_cyc
add wave -position end sim:/main/tx_wb_ack
add wave -position end sim:/main/rx_wb_ack
add wave -position end sim:/main/rx_wb_stall
add wave -position end sim:/main/tx_wb_stall
add wave -position end sim:/main/tx_wb_stb
add wave -position end sim:/main/rx_wb_stb
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {867 ns} 0}
......
action= "simulation"
target= "xilinx"
syn_device="xc6slx45t"
sim_tool="modelsim"
top_module="main"
fetchto="../../../ip_cores"
vlog_opt="+incdir+../../../sim"
modules = { "local" : ["../../..",
"../../../modules/wr_streamers",
"../../../ip_cores/general-cores"]}
files = ["main.sv"]
interface IWishboneLink;
parameter g_data_width = 32;
parameter g_addr_width = 32;
wire [g_addr_width - 1 : 0] adr;
wire [g_data_width - 1 : 0] dat_o;
wire [g_data_width - 1 : 0] dat_i;
wire [(g_data_width/8)-1 : 0] sel;
wire ack;
wire stall;
wire err;
wire rty;
wire cyc;
wire stb;
wire we;
modport slave
(
output adr,
output dat_o,
input dat_i,
output sel,
output cyc,
output stb,
output we,
input ack,
input stall,
input err,
input rty
);
modport master
(
input adr,
input dat_o,
output dat_i,
input sel,
input cyc,
input stb,
input we,
output ack,
output stall,
output err,
output rty
);
endinterface // IWishboneLink
//-----------------------------------------------------------------------------
// Title : WR streamers testbench
// Project : White Rabbit Cores
// URL : http://www.ohwr.org/projects/wr-cores/wiki/WR_Streamers
//-----------------------------------------------------------------------------
// File : main.sv
// Author(s) : Tomasz Wlostosky,
// Extended by Denia Bouhired <denia.bouhired@cern.ch>
// Company : CERN (BE-CO-HT)
// Created : 2017-04-28
//-----------------------------------------------------------------------------
// Description:
//
//
//-----------------------------------------------------------------------------
//
// Copyright (c) 2017 CERN
//
// This source file is free software; you can redistribute it
// and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any
// later version.
//
// This source 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 Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General
// Public License along with this source; if not, download it
// from http://www.gnu.org/licenses/lgpl-2.1.html
//
//-----------------------------------------------------------------------------
`include "../../../sim/if_wb_link.svh"
// `include "./tb_wr_fabric_link_control.sv"
`timescale 1ns/1ns
module main;
/////////////////////////////////////////////////////////////////////////////
// Parameters
/////////////////////////////////////////////////////////////////////////////
// Size of data record to be used by the streamers.
// In this case, a 64-bit word.
parameter g_word_width = 64;
// Min and max block size
parameter g_block_size_min = 1;
parameter g_block_size_max = 5;
// Min and max frame size
parameter g_frame_size_min = 1;
parameter g_frame_size_max = 3;
// MAC address of the TX side
parameter bit [47:0] g_mac_tx = 48'h112233445566;
// MAC address of the RX side
parameter bit [47:0] g_mac_rx = 48'hcafebabedead;
// Ethertype for distinguishing streamer frames. Default accepted by WRPC core.
parameter bit [15:0] g_ethertype = 16'hdbff;
// 16-bit data, 2-bit address Wishbone bus that connects the WR MAC interfaces
// of both streamers
IWishboneLink #(16, 2) mac();
logic [1 : 0] adr_d1;
logic [1 : 0] sel_d1 ;
logic cyc_d1;
logic stb_d1;
logic we_d1 ;
logic [1 : 0] adr;
logic [1 : 0] sel ;
logic cyc;
logic stb;
logic we;
// Clock & reset
reg clk = 0;
reg rst_n = 0;
// TX Streamer signals
reg tx_streamer_dvalid = 0;
reg [g_word_width-1:0] tx_streamer_data = 0;
//wire[15:0] data_from_tx= 0;
reg tx_streamer_last = 0;
reg tx_flush = 0;
wire tx_streamer_dreq;
wire tx_frame_sent;
// RX Streamer signals
reg rx_streamer_dreq = 0;
wire [g_word_width-1:0] rx_streamer_data;
wire rx_streamer_dvalid;
wire rx_streamer_lost_blks;
wire rx_streamer_lost_frm;
wire [14:0] rx_streamer_lost_frm_cnt;
wire rx_streamer_first;
wire rx_streamer_last;
wire [27:0] rx_latency;
wire rx_latency_valid;
wire rx_frame_received;
// Fake White Rabbit reference clock (125 MHz) and cycle counter (we don't use
// TAI counter as the latency never exceeds 1 second...)
reg clk_ref = 0;
reg [27:0] tm_cycle_counter = 0;
// Currently transmitted counter value
integer tx_counter_val = 10;
//Seed for random generator
int seed = 0;
// Wishbone link interface
bit [15 : 0] data_from_tx;
logic [15 : 0] data_to_rx ;
logic tx_wb_cyc, rx_wb_cyc;
logic tx_wb_stb, rx_wb_stb;
logic tx_wb_ack;
logic tx_wb_stall;
wire rx_wb_stall;
wire rx_wb_ack;
/////////////////////////////////////////////////////////////////////////////
// Initialise and set, reset, clocks and clk counter
/////////////////////////////////////////////////////////////////////////////
initial
begin
#100 rst_n = 1;
end;
always #10 clk <= ~clk;
always #4ns clk_ref <= ~clk_ref; //generate 125 MHz WR Clock
always@(posedge clk_ref) tm_cycle_counter <= tm_cycle_counter + 1;
/////////////////////////////////////////////////////////////////////////////
// Struct definition
/////////////////////////////////////////////////////////////////////////////
typedef struct{ bit[g_word_width-1:0] words[$];
int wrd_cnt[$];
bit[g_word_width-1:0] first_wrd;
bit[g_word_width-1:0] last_wrd;
bit dropped;
} block_t; //block is a number of words with info about first
// and last
typedef struct{ block_t blocks[$];
} streamer_frame_t; //frame contains a collection of blocks
// Transfer queue. Used to pass sent data to the verification process.
block_t tx_blk_queue[$];
streamer_frame_t tx_frm_queue[$]; /////////////////////////////////////////////////////////////////////////////
// Task definitions
/////////////////////////////////////////////////////////////////////////////
// Generate a block of data words of random size, containing subsequent
// numbers
/////////////////////////////////////////////////////////////////////////////
task automatic generate_block(ref block_t blk);
int size = $dist_uniform(seed, g_block_size_min, g_block_size_max);
int i;
for(i = 0; i<size; i++)
begin
if (i == 0)
blk.first_wrd = tx_counter_val; // Copy first word
if (i == size-1)
blk.last_wrd = tx_counter_val; // Copy last word
blk.words.push_back(tx_counter_val++); //
if (i == 0 || i==size-1)
blk.wrd_cnt.push_back(i+1);// first or last words
else
blk.wrd_cnt.push_back(0); // All other words
end //for loop
endtask // generate_block
////////////////////////////////////////////////////////
task automatic generate_frame(ref streamer_frame_t frm);
int size = $dist_uniform(seed, g_frame_size_min, g_frame_size_max);
int i;
block_t blk;
for(i = 0; i<size; i++)
begin
blk.words = {};
blk.wrd_cnt = {};
generate_block(blk);
frm.blocks.push_back(blk);
end
endtask
// Sends out a data block (blk) by driving TX_(DVALID, DATA, LAST) lines
// of the TX streamer
/////////////////////////////////////////////////////////////////////////////
task automatic send_block(ref block_t blk);
int i = 0;
////$display("Sending block of %d words...", blk.words.data.size());
while(i < blk.words.size())
begin
if(tx_streamer_dreq) begin
// assert the TX_LAST line on the last word in the current block
tx_streamer_last <= (i == (blk.words.size() - 1)) ? 1 : 0;
tx_streamer_data <= blk.words[i];
//$display("Data to be sent is %d*****\n", tx_streamer_data);
tx_streamer_dvalid <= 1;
i++;
end else
tx_streamer_dvalid <= 0;
@(posedge clk);
end // while (i < blk.words.data.size())
tx_streamer_dvalid <= 0;
tx_streamer_last <= 0;
endtask // send_block
///////////////////////////////////////////////////////////////////
task automatic send_frame(ref streamer_frame_t frm);
int i = 0;
while (i < frm.blocks.size()) begin
send_block(frm.blocks[i]);
i++;
end
tx_flush <= 1;
@(posedge clk);
tx_flush <= 0;
endtask
///////////////////////////////////////////////////////////////////
// WISHBONE LINK CONTROL
///////////////////////////////////////////////////////////////////
//Continuous assignements to WR fabric signals
logic [ 15 : 0] corrupt_mask = 16'h0000;
logic drop_frm = 0;
logic link_ok= 1;
logic delay_link= 0;
task automatic link_good ();
int frm_counter = 0;
link_ok = 1;
corrupt_mask = 16'h0000;
drop_frm = 0;
delay_link= 0;
frm_counter=0;
while (frm_counter < 3 ) begin
@(posedge tx_wb_cyc) //at every new frame
frm_counter ++;
end
endtask;
task automatic corrupt_data ();
int i, j, n;
int frm_counter = 0;
corrupt_mask = 16'h0000;
link_ok= 0;
n={$random} % 2; //number of frames to be corrupted
//corrupt = ({$random} % 1000 < 500) ? 1 : 0;
// break_bit = ({$random} % 100 <1) ? 1 : 0;
// while (frm_counter < 3 )
// begin
j = {$random} % 15;
$display("=====BIT FLIP================");
@(negedge rx_frame_received)
corrupt_mask [j] = ~corrupt_mask [j];
@(negedge rx_wb_ack) link_good ();
// end
endtask //corrupt_data
task automatic drop_frame ();
int n, i;
link_ok= 0;
n={$random} % 5; //number of frames to be dropped
// drop_or_delay = 0;// {$random} % 1;
for (i=0; i<n; i++)
begin
@(negedge tx_wb_cyc)
drop_frm = 1;
end
@(negedge tx_wb_cyc)
drop_frm = 0;
endtask //drop_frame
// end
task automatic delay_frame ();
link_ok= 0;
delay_link = 0;
// fork begin
wait (rx_wb_stall == 1) //to avoid changes at startup
//----------Random stall asserted------------------------------
// delay_link = ({$random} % 10 < 2) ? 1 : 0;
// delay_link = delay_link & tx_wb_stb;
// #150;
// delay_link = 0;//-----------------------------------------------------------
// @(negedge rx_wb_stall)
@(negedge tx_wb_cyc)
delay_link = 1;
#10000;
delay_link = 0;
// end
// begin
// @(negedge rx_wb_ack);
// delay_link = 1;
// #1000;
// delay_link = 0;
// join
// end
endtask //delay_frame
//always @(posedge clk)
//if (data_to_rx != 16'b0)
assign data_to_rx = data_from_tx ^ corrupt_mask;
assign rx_wb_stb = tx_wb_stb & ~drop_frm;
assign rx_wb_cyc = tx_wb_cyc & ~drop_frm;
// assign tx_wb_stall = delay_link; //extend pulse
assign tx_wb_stall = rx_wb_stall | delay_link; //extend pulse
// assign tx_wb_stall = ~rx_wb_cyc ? (1'b0 | delay_link) : (~rx_wb_ack | delay_link);
assign tx_wb_ack = rx_wb_ack;// & ~delay_link;
/////////////////////////////
time delay=0;
// task automatic add_latency();
// delay = ({$random}%10);
// tx_wb_stall = 1;
// tx_wb_ack = 1;
// #100;
// tx_wb_stall = rx_wb_stall;
// tx_wb_ack = rx_wb_ack;
// $display("Added latency %t \n", delay);
// endtask //add_latency
///////////////////////////////////////////////////////////////////
//RECEPTION LOGIC//
// Receives a data block from the RX streamer and puts it in (blk).
// Returns non-zero done value when blk contains a complete block
/////////////////////////////////////////////////////////////////////////////
task automatic receive_block(ref block_t blk, ref int new_block, ref int done);
bit[g_word_width-1:0] wrd[$];
bit[g_word_width-1:0] word1;
bit[g_word_width-1:0] wordn;
wrd= blk.words;
word1=blk.first_wrd;
wordn=blk.last_wrd;
if(rx_streamer_dvalid)
begin
if(rx_streamer_first && new_block == 1)
begin
new_block = 0;
wrd = {};
blk.wrd_cnt = {};
blk.wrd_cnt.push_back(1);
word1 = rx_streamer_data;
end
else if (!rx_streamer_last && !rx_streamer_first)
begin
blk.wrd_cnt.push_back(0);
end
wrd.push_back(rx_streamer_data);
if (rx_streamer_last && new_block == 0)
begin
wordn = rx_streamer_data;
if (wrd.size() > 1)
blk.wrd_cnt.push_back(wrd.size()); //Last word in block
done = 1;
end
else
begin
done = 0;
end
blk.words=wrd;
blk.first_wrd = word1;
blk.last_wrd = wordn;
end
endtask // receive_block
// TX block stream generation
initial forever
begin
//int i;
streamer_frame_t frm;
frm.blocks = {};
generate_frame(frm);
for (int i=0; i < frm.blocks.size(); i++) begin
frm.blocks[i].dropped = drop_frm;
tx_blk_queue.push_back(frm.blocks[i]);
end
tx_frm_queue.push_back(frm);
send_frame(frm);
$display("PUSH FRAME Tx q are %p\n#########", tx_frm_queue);
rx_streamer_dreq <= 1;//({$random} % 100 < 90) ? 1 : 0;
$display ("Time is %d\n", $time);
end
initial forever
begin
randcase
10 : drop_frame ();
//10 : corrupt_data ();
10 : link_good ();
10 : delay_frame ();
endcase;
end
// Instantiation of the streamers. The TX streamer will assemble packets
// containing max. 8 records, or flush the buffer after 128 clk cycles if
// it contains less than 8 records to prevent latency buildup.
tx_streamer
#(
.g_data_width (g_word_width),
.g_tx_threshold (4),
.g_tx_timeout (128)
)
U_TX_Streamer
(
.clk_sys_i(clk),
.rst_n_i (rst_n),
.src_dat_o (data_from_tx),// (mac.dat_i),
.src_adr_o (mac.adr),
.src_sel_o (mac.sel),
.src_cyc_o (tx_wb_cyc),
.src_stb_o (tx_wb_stb),
.src_we_o (mac.we),
.src_stall_i(tx_wb_stall),
.src_err_i (mac.err),
.src_ack_i (tx_wb_ack),
.clk_ref_i(clk_ref), // fake WR time
.tm_time_valid_i(1'b1),
.tm_cycles_i(tm_cycle_counter),
.tx_data_i (tx_streamer_data),
.tx_valid_i (tx_streamer_dvalid),
.tx_dreq_o (tx_streamer_dreq),
.tx_last_p1_i (tx_streamer_last),
.tx_flush_p1_i (tx_flush),
.tx_reset_seq_i (),
.tx_frame_p1_o (tx_frame_sent),
.cfg_mac_local_i (g_mac_tx),
.cfg_mac_target_i (g_mac_rx),
.cfg_ethertype_i (g_ethertype)
);
rx_streamer
#(
.g_data_width (g_word_width)
)
U_RX_Streamer
(
.clk_sys_i (clk),
.rst_n_i (rst_n),
.snk_dat_i (data_to_rx),
.snk_adr_i (mac.adr),
.snk_sel_i (mac.sel),
.snk_cyc_i (rx_wb_cyc),
.snk_stb_i (rx_wb_stb),
.snk_we_i (mac.we),
.snk_stall_o (rx_wb_stall),
.snk_ack_o (rx_wb_ack),
.snk_err_o (mac.err),
.snk_rty_o (mac.rty),
.clk_ref_i(clk_ref), // fake WR time
.tm_time_valid_i(1'b1),
.tm_cycles_i(tm_cycle_counter),
.rx_first_p1_o (rx_streamer_first),
.rx_last_p1_o (rx_streamer_last),
.rx_data_o (rx_streamer_data),
.rx_valid_o (rx_streamer_dvalid),
.rx_dreq_i (rx_streamer_dreq),
//.rx_lost_p1_o (rx_streamer_lost),
.rx_lost_blocks_p1_o (rx_streamer_lost_blks),
.rx_lost_frames_p1_o (rx_streamer_lost_frm),
.rx_lost_frames_cnt_o (rx_streamer_lost_frm_cnt),
.rx_latency_o (rx_latency),
.rx_latency_valid_o (rx_latency_valid),
.rx_frame_p1_o (rx_frame_received),
.cfg_mac_local_i (g_mac_rx),
.cfg_mac_remote_i (g_mac_tx),
.cfg_ethertype_i (g_ethertype)
);
// TESTBENCH VERIFICATION
// Client-side reception logic. Compares the received records with their copies
// stored in the transfer queue.
int new_block = 1;
int no_curr_req = 0;
always@(posedge clk)
if(rst_n)
begin
block_t rblk;
streamer_frame_t tfrm;
automatic int done = 0;
if (rx_streamer_lost_frm == 1)
begin
int i, n_lost_frames;
n_lost_frames = rx_streamer_lost_frm_cnt;
for (i = 0; i < n_lost_frames; i++) begin
tfrm = tx_frm_queue.pop_front();
$display ("%d have been lost, frame %p is POPPED\n=====", n_lost_frames, tfrm );
end
$display ("%d have been lost, the new Tx queue is %p\n=====", n_lost_frames, tx_frm_queue );
end
receive_block(rblk, new_block, done);
if(done)
begin
//automatic streamer_frame_t frm ;
automatic block_t tblk;
//automatic int tblk_size = tblk.words.size();
$display(" frame OUT is %p \n********", tx_blk_queue);
//if (tx_blk_queue.size() != 0)
//else begin
tblk = tx_blk_queue.pop_front(); $display(" OLD TBLK is %p \n********", tblk);
$display(" FRAME size is %d \n%%%%%%%%%%%%", tfrm.blocks.size());
if (tfrm.blocks.size() == 0) begin
tfrm = tx_frm_queue.pop_front();
$display(" FRAME is %p \n%%%%%%%%%%%%", tfrm); end
tblk = tfrm.blocks.pop_front(); $display(" NEW TBLK is %p \n********", tblk);
$display(" FRAME AFTER POP is %p \n%%%%%%%%%%%%", tfrm);
$display(" QUEUE is %p \n%%%%%%%%%%%%", tx_blk_queue);
//end
$display(" block OUT is %p \n********", tblk);
//$display("Received block of %d words....\n", tblk_size);
new_block = 1;
// ===============================================================
// TEST : Check that no frames have been lost:
// ===============================================================
// TEST 1: Check Txed and Rxed blocks match
if(tblk.words != rblk.words)
begin
$error("TEST 1 ---> FAILED\n####Sent block does not match received block\n");
$display("Txed is %p, Rxed equals %p", tblk, rblk);
$stop;
end else begin
$display("****\nTEST 1 ---> PASSED\n****Correct words received\n");
end
// ================================================================
// TEST 2: Check number of Received words in block is correct
if (tblk.words.size() != rblk.words.size())
begin
$error("TEST 2 ---> FAILED\n####Sent and received blocks do not have the same number of words\n");
$stop;
end else
$display("****\nTEST 2 ---> PASSED\n****Correct number of words received\n");
// ================================================================
// TEST 3: Check that first word is asserted correctly at first word
// if (tblk.first_wrd != rblk.first_wrd)
if (tblk.wrd_cnt != rblk.wrd_cnt)
begin
$error("TEST 3 ---> FAILED: First word pulse incorrect.\n");
//$display("Txed is %p, Rxed equals %p", tblk, rblk);
$stop;
end else
$display("****\nTEST 3 ---> PASSED\n****First word signalled correctly\n");
// =================================================================
// TEST 4: Check that first word is asserted correctly at first word
// if (tblk.last_wrd != rblk.last_wrd)
if (tblk.wrd_cnt != rblk.wrd_cnt)
begin
//$display("test4 txed equals %p, rxed %p", tblk, rblk);
$error("TEST 4 ---> FAILED: Last word pulse incorrect.\n");
$stop;
end else
$display("test4 txed equals %p, rxed %p", tblk, rblk);
$display("****\nTEST 4 ---> PASSED\n****Last word signalled correctly\n");
// =================================================================
// TEST 5: Check that when rx_dreq is not asserted data stops at the next clk cycle
if (rx_streamer_dreq == 1)
no_curr_req = 0;
else if (rx_streamer_dreq == 0 && no_curr_req == 0)
no_curr_req = 1;
else if (no_curr_req == 1 && rx_streamer_dvalid == 1)
begin
$error("TEST 5 ---> FAILED\n####Pulse rx_request is not asserted should not receive data.\n");
$stop;
end
else begin
$display("****\nTEST 5 ---> PASSED\n****No data output when Rx_request is not asserted\n");
end
end
end // else: !if(!rst_n)
always@(posedge clk)
if(rst_n && rx_latency_valid)
$display("*************This frame's latency: %.3f microseconds*************************************************\n", real'(rx_latency) * 0.008);
endmodule // main
//-----------------------------------------------------------------------------
// Title : WR streamers testbench
// Project : White Rabbit Cores
// URL : http://www.ohwr.org/projects/wr-cores/wiki/WR_Streamers
//-----------------------------------------------------------------------------
// File : main.sv
// Author(s) : Tomasz Wlostosky,
// Extended by Denia Bouhired <denia.bouhired@cern.ch>
// Company : CERN (BE-CO-HT)
// Created : 2017-04-28
//-----------------------------------------------------------------------------
// Description:
//
//
//-----------------------------------------------------------------------------
//
// Copyright (c) 2017 CERN
//
// This source file is free software; you can redistribute it
// and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any
// later version.
//
// This source 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 Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General
// Public License along with this source; if not, download it
// from http://www.gnu.org/licenses/lgpl-2.1.html
//
//-----------------------------------------------------------------------------
`include "../../../sim/if_wb_link.svh"
// `include "./tb_wr_fabric_link_control.sv"
`timescale 1ns/1ns
module main;
/////////////////////////////////////////////////////////////////////////////
// Parameters
/////////////////////////////////////////////////////////////////////////////
// Size of data record to be used by the streamers.
// In this case, a 64-bit word.
parameter g_word_width = 64;
// Min and max block size
parameter g_block_size_min = 1;
parameter g_block_size_max = 5;
// Min and max frame size
parameter g_frame_size_min = 1;
parameter g_frame_size_max = 3;
// MAC address of the TX side
parameter bit [47:0] g_mac_tx = 48'h112233445566;
// MAC address of the RX side
parameter bit [47:0] g_mac_rx = 48'hcafebabedead;
// Ethertype for distinguishing streamer frames. Default accepted by WRPC core.
parameter bit [15:0] g_ethertype = 16'hdbff;
// 16-bit data, 2-bit address Wishbone bus that connects the WR MAC interfaces
// of both streamers
IWishboneLink #(16, 2) mac();
logic [1 : 0] adr_d1;
logic [1 : 0] sel_d1 ;
logic cyc_d1;
logic stb_d1;
logic we_d1 ;
logic [1 : 0] adr;
logic [1 : 0] sel ;
logic cyc;
logic stb;
logic we;
// Clock & reset
reg clk = 0;
reg rst_n = 0;
// TX Streamer signals
reg tx_streamer_dvalid = 0;
reg [g_word_width-1:0] tx_streamer_data = 0;
//wire[15:0] data_from_tx= 0;
reg tx_streamer_last = 0;
wire tx_streamer_dreq;
wire tx_frame_sent;
// RX Streamer signals
reg rx_streamer_dreq = 0;
wire [g_word_width-1:0] rx_streamer_data;
wire rx_streamer_dvalid;
wire rx_streamer_lost_blks;
wire rx_streamer_lost_frm;
wire [14:0] rx_streamer_lost_frm_cnt;
wire rx_streamer_first;
wire rx_streamer_last;
wire [27:0] rx_latency;
wire rx_latency_valid;
wire rx_frame_received;
// Fake White Rabbit reference clock (125 MHz) and cycle counter (we don't use
// TAI counter as the latency never exceeds 1 second...)
reg clk_ref = 0;
reg [27:0] tm_cycle_counter = 0;
// Currently transmitted counter value
integer tx_counter_val = 10;
//Seed for random generator
int seed = 0;
bit [15 : 0] data_from_tx;
bit [15 : 0] data_to_rx ;
bit tx_wb_cyc, rx_wb_cyc;
bit tx_wb_stb, rx_wb_stb;
wire rx_wb_stall;
bit tx_wb_stall;
wire rx_wb_ack;
bit tx_wb_ack;
/////////////////////////////////////////////////////////////////////////////
// Initialise and set, reset, clocks and clk counter
/////////////////////////////////////////////////////////////////////////////
initial
begin
#100 rst_n = 1;
end;
always #10 clk <= ~clk;
always #4ns clk_ref <= ~clk_ref; //generate 125 MHz WR Clock
always@(posedge clk_ref)
tm_cycle_counter <= tm_cycle_counter + 1;
/////////////////////////////////////////////////////////////////////////////
// Struct definition
/////////////////////////////////////////////////////////////////////////////
typedef struct{
bit[g_word_width-1:0] words[$];
int wrd_cnt[$];
bit[g_word_width-1:0] first_wrd;
bit[g_word_width-1:0] last_wrd;
} block_t;
typedef struct{
block_t blocks[$];
} streamer_frame_t;
// Transfer queue. Used to pass sent data to the verification process.
block_t tx_queue[$];
/////////////////////////////////////////////////////////////////////////////
// Task definitions
/////////////////////////////////////////////////////////////////////////////
// Generate a block of data words of random size, containing subsequent
// numbers
/////////////////////////////////////////////////////////////////////////////
task automatic generate_block(ref block_t blk);
int size = $dist_uniform(seed, g_block_size_min, g_block_size_max);
int i;
for(i = 0; i<size; i++)
begin
if (i == 0) blk.first_wrd = tx_counter_val;
if (i == size-1) blk.last_wrd = tx_counter_val;
blk.words.push_back(tx_counter_val++);
if (i == 0 || i==size-1)
blk.wrd_cnt.push_back(i+1);
else
blk.wrd_cnt.push_back(0);
end
//$display("BLOCK size is %d: \n", size);
//$display ("Current block is %p \n", blk.words );
endtask // generate_block
////////////////////////////////////////////////////////
task automatic generate_frame(ref streamer_frame_t frm);
int size = $dist_uniform(seed, g_frame_size_min, g_frame_size_max);
block_t blk;
int i;
//$display("Frame size is %d: \n", size);
for(i = 0; i<size; i++)
begin
blk.words = {};
blk.wrd_cnt = {};
generate_block(blk);
//$display("generated block was %p \n********", blk.words);
frm.blocks.push_back(blk);
end //$display("generated frame is %p \n********", frm.blocks);
endtask
// Sends out a data block (blk) by driving TX_(DVALID, DATA, LAST) lines
// of the TX streamer
/////////////////////////////////////////////////////////////////////////////
task automatic send_block(ref block_t blk);
int i = 0;
////$display("Sending block of %d words...", blk.words.data.size());
while(i < blk.words.size())
begin
if(tx_streamer_dreq) begin
// assert the TX_LAST line on the last word in the current block
tx_streamer_last <= (i == (blk.words.size() - 1)) ? 1 : 0;
tx_streamer_data <= blk.words[i];
//$display("Data to be sent is %d*****\n", tx_streamer_data);
tx_streamer_dvalid <= 1;
i++;
end else
tx_streamer_dvalid <= 0;
@(posedge clk);
end // while (i < blk.words.data.size())
tx_streamer_dvalid <= 0;
tx_streamer_last <= 0;
@(posedge clk);
endtask // send_block
///////////////////////////////////////////////////////////////////
task automatic send_frame(ref streamer_frame_t frm);
int i = 0;
while (i < frm.blocks.size()) begin
send_block(frm.blocks[i]);
i++;
end
endtask
///////////////////////////////////////////////////////////////////
// WISHBONE LINK CONTROL
///////////////////////////////////////////////////////////////////
//Continuous assignements to WR fabric signals
logic [ 15 : 0] corrupt_mask = 16'h0000;
logic drop_frm = 0;
logic link_ok= 1;
logic delay_link= 0;
int corrupt=0;
task automatic disrupt_link() ;
randcase
10 : drop_frame ();
10 : begin link_ok = 0; corrupt_data ();end
10 : link_ok = 1;
10 : delay_frame ();
endcase;
endtask // disrupt_link
task automatic link_good ();
int frm_counter = 0;
link_ok = 1;
corrupt_mask = 16'h0000;
drop_frm = 0;
delay_link= 0;
frm_counter=0;
while (frm_counter < 3 ) begin
@(posedge tx_wb_cyc) //at every new frame
frm_counter ++;
end
endtask;
task automatic corrupt_data ();
int i, j, n;
int frm_counter = 0;
corrupt_mask = 16'h0000;
link_ok= 0;
n={$random} % 2; //number of frames to be corrupted
//corrupt = ({$random} % 1000 < 500) ? 1 : 0;
// break_bit = ({$random} % 100 <1) ? 1 : 0;
// while (frm_counter < 3 )
// begin
j = {$random} % 15;
$display("=====BIT FLIP================");
@(negedge rx_frame_received)
corrupt_mask [j] = ~corrupt_mask [j];
@(negedge rx_wb_ack) link_good ();
// end
endtask //corrupt_data
task automatic drop_frame ();
int n, i;
link_ok= 0;
n={$random} % 5; //number of frames to be dropped
// drop_or_delay = 0;// {$random} % 1;
for (i=0; i<n; i++)
begin
@(negedge tx_wb_cyc)
drop_frm = 1;
end
@(negedge tx_wb_cyc)
drop_frm = 0;
endtask //drop_frame
// end
task automatic delay_frame ();
link_ok= 0;
delay_link = 0;
// fork begin
wait (rx_wb_stall == 1) //to avoid changes at startup
//----------Random stall asserted------------------------------
// delay_link = ({$random} % 10 < 2) ? 1 : 0;
// delay_link = delay_link & tx_wb_stb;
// #150;
// delay_link = 0;//-----------------------------------------------------------
// @(negedge rx_wb_stall)
@(negedge tx_wb_cyc)
delay_link = 1;
#10000;
delay_link = 0;
// end
// begin
// @(negedge rx_wb_ack);
// delay_link = 1;
// #1000;
// delay_link = 0;
// join
// end
endtask //delay_frame
always @(posedge clk)
//if (data_to_rx != 16'b0)
assign data_to_rx = data_from_tx ^ corrupt_mask;
assign rx_wb_stb = tx_wb_stb & ~drop_frm;
assign rx_wb_cyc = tx_wb_cyc & ~drop_frm;
// assign tx_wb_stall = delay_link; //extend pulse
assign tx_wb_stall = rx_wb_stall | delay_link; //extend pulse
// assign tx_wb_stall = ~rx_wb_cyc ? (1'b0 | delay_link) : (~rx_wb_ack | delay_link);
assign tx_wb_ack = rx_wb_ack;// & ~delay_link;
/////////////////////////////
time delay=0;
// task automatic add_latency();
// delay = ({$random}%10);
// tx_wb_stall = 1;
// tx_wb_ack = 1;
// #100;
// tx_wb_stall = rx_wb_stall;
// tx_wb_ack = rx_wb_ack;
// $display("Added latency %t \n", delay);
// endtask //add_latency
///////////////////////////////////////////////////////////////////
//RECEPTION LOGIC//
// Receives a data block from the RX streamer and puts it in (blk).
// Returns non-zero done value when blk contains a complete block
/////////////////////////////////////////////////////////////////////////////
task automatic receive_block(ref block_t blk, ref int new_block, ref int done);
bit[g_word_width-1:0] wrd[$];
bit[g_word_width-1:0] word1;
bit[g_word_width-1:0] wordn;
wrd= blk.words;
word1=blk.first_wrd;
wordn=blk.last_wrd;
//////$display("CURRENT WORD in block %p \n", wrd);
if(rx_streamer_dvalid)
begin
//$display("VALID word\n");
if(rx_streamer_first && new_block == 1)
begin
new_block = 0;
wrd = {};
blk.wrd_cnt = {};
blk.wrd_cnt.push_back(1);
/////$display("first word received\n");
/////$display("*****NEW_BLOCK %d\n", new_block);
word1 = rx_streamer_data;
/////$display("*****first word %d\n", word1);
end
else if (!rx_streamer_last && !rx_streamer_first)
begin
blk.wrd_cnt.push_back(0);
end
wrd.push_back(rx_streamer_data);
//$display("BEFORE LAST words in block %p \n", wrd);
if (rx_streamer_last && new_block == 0)
begin
wordn = rx_streamer_data;
if (wrd.size() > 1) blk.wrd_cnt.push_back(wrd.size()); //Last word in block
////$display("HERE**************SIZE is %d *****************\n", wrd.data.size());
////$display("words in block %p \n", wrd.data);
done = 1;
//// $display("last word received, done is %d\n", done);
//// $display("words in block %p \n", wrd);
//// $display("IF rx_streamer_last is %d \n",rx_streamer_last);
end
else begin
////$display("ELSE rx_streamer_last is %b \n",rx_streamer_last);
done = 0;
////$display("ZERO done");
end
blk.words=wrd;
blk.first_wrd = word1;
blk.last_wrd = wordn;
//// $display("words in block %p \n", blk.words);
end
endtask // receive_block
// TX block stream generation
initial forever
begin
//int i;
streamer_frame_t frm;
frm.blocks = {};
generate_frame(frm);
send_frame(frm);
for (int i=0; i < frm.blocks.size(); i++) begin
tx_queue.push_back(frm.blocks[i]);
end
rx_streamer_dreq <= 1;//({$random} % 100 < 90) ? 1 : 0;
$display ("Time is %d\n", $time);
end
initial forever
begin
randcase
//10 : drop_frame ();
10 : corrupt_data ();
10 : link_good ();
// 10 : delay_frame ();
endcase;
end
// Instantiation of the streamers. The TX streamer will assemble packets
// containing max. 8 records, or flush the buffer after 128 clk cycles if
// it contains less than 8 records to prevent latency buildup.
tx_streamer
#(
.g_data_width (g_word_width),
.g_tx_threshold (4),
.g_tx_timeout (128)
)
U_TX_Streamer
(
.clk_sys_i(clk),
.rst_n_i (rst_n),
.src_dat_o (data_from_tx),// (mac.dat_i),
.src_adr_o (mac.adr),
.src_sel_o (mac.sel),
.src_cyc_o (tx_wb_cyc),
.src_stb_o (tx_wb_stb),
.src_we_o (mac.we),
.src_stall_i(tx_wb_stall),
.src_err_i (mac.err),
.src_ack_i (tx_wb_ack),
.clk_ref_i(clk_ref), // fake WR time
.tm_time_valid_i(1'b1),
.tm_cycles_i(tm_cycle_counter),
.tx_data_i (tx_streamer_data),
.tx_valid_i (tx_streamer_dvalid),
.tx_dreq_o (tx_streamer_dreq),
.tx_last_p1_i (tx_streamer_last),
.tx_reset_seq_i (),
.tx_frame_p1_o (tx_frame_sent),
.cfg_mac_local_i (g_mac_tx),
.cfg_mac_target_i (g_mac_rx),
.cfg_ethertype_i (g_ethertype)
);
rx_streamer
#(
.g_data_width (g_word_width)
)
U_RX_Streamer
(
.clk_sys_i (clk),
.rst_n_i (rst_n),
.snk_dat_i (data_to_rx),
.snk_adr_i (mac.adr),
.snk_sel_i (mac.sel),
.snk_cyc_i (rx_wb_cyc),
.snk_stb_i (rx_wb_stb),
.snk_we_i (mac.we),
.snk_stall_o (rx_wb_stall),
.snk_ack_o (rx_wb_ack),
.snk_err_o (mac.err),
.snk_rty_o (mac.rty),
.clk_ref_i(clk_ref), // fake WR time
.tm_time_valid_i(1'b1),
.tm_cycles_i(tm_cycle_counter),
.rx_first_p1_o (rx_streamer_first),
.rx_last_p1_o (rx_streamer_last),
.rx_data_o (rx_streamer_data),
.rx_valid_o (rx_streamer_dvalid),
.rx_dreq_i (rx_streamer_dreq),
//.rx_lost_p1_o (rx_streamer_lost),
.rx_lost_blocks_p1_o (rx_streamer_lost_blks),
.rx_lost_frames_p1_o (rx_streamer_lost_frm),
.rx_lost_frames_cnt_o (rx_streamer_lost_frm_cnt),
.rx_latency_o (rx_latency),
.rx_latency_valid_o (rx_latency_valid),
.rx_frame_p1_o (rx_frame_received),
.cfg_mac_local_i (g_mac_rx),
.cfg_mac_remote_i (g_mac_tx),
.cfg_ethertype_i (g_ethertype)
);
// TESTBENCH VERIFICATION
// Client-side reception logic. Compares the received records with their copies
// stored in the transfer queue.
int new_block = 1;
int no_curr_req = 0;
always@(posedge clk)
if(rst_n)
begin
block_t rblk;
automatic int done = 0;
receive_block(rblk, new_block, done);
if(done)
begin
//automatic streamer_frame_t frm ;
automatic block_t tblk;
automatic int tblk_size = tblk.words.size();
$display(" frame OUT is %p \n********", tx_queue);
if (tx_queue.size() != 0)
tblk = tx_queue.pop_front();
else break;
$display(" block OUT is %p \n********", tblk);
new_block = 1;
$display("Received block of %d words....\n", tblk_size);
// ===============================================================
// TEST 1: Check Txed and Rxed blocks match
if(tblk.words != rblk.words)
begin
$error("TEST 1 ---> FAILED\n####Sent block does not match received block\n");
$display("Txed is %p, Rxed equals %p", tblk, rblk);
$stop;
end else begin
$display("****\nTEST 1 ---> PASSED\n****Correct words received\n");
end
// ================================================================
// TEST 2: Check number of Received words in block is correct
if (tblk.words.size() != rblk.words.size())
begin
$error("TEST 2 ---> FAILED\n####Sent and received blocks do not have the same number of words\n");
$stop;
end else
$display("****\nTEST 2 ---> PASSED\n****Correct number of words received\n");
// ================================================================
// TEST 3: Check that first word is asserted correctly at first word
// if (tblk.first_wrd != rblk.first_wrd)
if (tblk.wrd_cnt != rblk.wrd_cnt)
begin
$error("TEST 3 ---> FAILED: First word pulse incorrect.\n");
//$display("Txed is %p, Rxed equals %p", tblk, rblk);
$stop;
end else
$display("****\nTEST 3 ---> PASSED\n****First word signalled correctly\n");
// =================================================================
// TEST 4: Check that first word is asserted correctly at first word
// if (tblk.last_wrd != rblk.last_wrd)
if (tblk.wrd_cnt != rblk.wrd_cnt)
begin
//$display("test4 txed equals %p, rxed %p", tblk, rblk);
$error("TEST 4 ---> FAILED: Last word pulse incorrect.\n");
$stop;
end else
$display("test4 txed equals %p, rxed %p", tblk, rblk);
$display("****\nTEST 4 ---> PASSED\n****Last word signalled correctly\n");
// =================================================================
// TEST 5: Check that when rx_dreq is not asserted data stops at the next clk cycle
if (rx_streamer_dreq == 1)
no_curr_req = 0;
else if (rx_streamer_dreq == 0 && no_curr_req == 0)
no_curr_req = 1;
else if (no_curr_req == 1 && rx_streamer_dvalid == 1)
begin
$error("TEST 5 ---> FAILED\n####Pulse rx_request is not asserted should not receive data.\n");
$stop;
end
else begin
$display("****\nTEST 5 ---> PASSED\n****No data output when Rx_request is not asserted\n");
end
end
end // else: !if(!rst_n)
always@(posedge clk)
if(rst_n && rx_latency_valid)
$display("*************This frame's latency: %.3f microseconds*************************************************\n", real'(rx_latency) * 0.008);
endmodule // main
class CGENERATE_AND_SEND
// Generate a block of data words of random size, containing subsequent
// numbers
/////////////////////////////////////////////////////////////////////////////
task automatic generate_block(ref block_t blk);
int size = $dist_uniform(seed, g_block_size_min, g_block_size_max);
int i;
for(i = 0; i<size; i++)
begin
if (i == 0)
blk.first_wrd = tx_counter_val; // Copy first word
if (i == size-1)
blk.last_wrd = tx_counter_val; // Copy last word
blk.words.push_back(tx_counter_val++); //
if (i == 0 || i==size-1)
blk.wrd_cnt.push_back(i+1);// first or last words
else
blk.wrd_cnt.push_back(0); // All other words
end //for loop
endtask // generate_block
////////////////////////////////////////////////////////
task automatic generate_frame(ref streamer_frame_t frm);
int size = $dist_uniform(seed, g_frame_size_min, g_frame_size_max);
int i;
block_t blk;
for(i = 0; i<size; i++)
begin
blk.words = {};
blk.wrd_cnt = {};
generate_block(blk);
frm.blocks.push_back(blk);
end
endtask
// Sends out a data block (blk) by driving TX_(DVALID, DATA, LAST) lines
// of the TX streamer
/////////////////////////////////////////////////////////////////////////////
task automatic send_block(ref block_t blk);
int i = 0;
////$display("Sending block of %d words...", blk.words.data.size());
while(i < blk.words.size())
begin
if(tx_streamer_dreq) begin
// assert the TX_LAST line on the last word in the current block
tx_streamer_last <= (i == (blk.words.size() - 1)) ? 1 : 0;
tx_streamer_data <= blk.words[i];
//$display("Data to be sent is %d*****\n", tx_streamer_data);
tx_streamer_dvalid <= 1;
i++;
end else
tx_streamer_dvalid <= 0;
@(posedge clk);
end // while (i < blk.words.data.size())
tx_streamer_dvalid <= 0;
tx_streamer_last <= 0;
@(posedge clk);
endtask // send_block
///////////////////////////////////////////////////////////////////
task automatic send_frame(ref streamer_frame_t frm);
int i = 0;
while (i < frm.blocks.size()) begin
send_block(frm.blocks[i]);
i++;
end
endtask
endclass
\ No newline at end of file
//-----------------------------------------------------------------------------
// Title : Definitions for WR streamers testbench
// Project : White Rabbit Cores
// URL : http://www.ohwr.org/projects/wr-cores/wiki/WR_Streamers
//-----------------------------------------------------------------------------
// File : wr-streamers-tb-class.sv
// Author(s) : Denia Bouhired <denia.bouhired@cern.ch>
// Company : CERN (BE-CO-HT)
// Created : 2017-04-28
//-----------------------------------------------------------------------------
// Description:
//
// SystemVerilog package with all definitions, interfaces, etc. necessary
// for the wr streamers testbench.
//
//-----------------------------------------------------------------------------
//
// Copyright (c) 2017 CERN
//
// This source file is free software; you can redistribute it
// and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any
// later version.
//
// This source 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 Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General
// Public License along with this source; if not, download it
// from http://www.gnu.org/licenses/lgpl-2.1.html
//
//-----------------------------------------------------------------------------
//`include "../../../sim/if_wb_link.svh"
class CWRFABRIC_LINK_CTRL;
int data_width, addr_width;
IWishboneLink in;
IWishboneLink out;
//Class constructor
function new ();
// this.out() = this.in();
// this.in.g_data_width = data_width;
// this.in.g_addr_width = addr_width;
// this.out.g_data_width = data_width;
// this.out.g_addr_width = addr_width;
endfunction //new
//
function corrupt_data ();
in();
out();
endfunction
function drop_frames ();
in();
out();
endfunction //drop_frames
function break_link ();
in();
out();
endfunction //break_link
endclass;
// Transmitter class
// class CWRSTREAMERS_TX extends CWRSTREAMERS;
// function
// endclass;
// Receiver class
// class CWRSTREAMERS_RX extends CWRSTREAMERS;
// endclass;
Wed May 03 16:18:04 W. Europe Daylight Time 2017
Trace back: invalid command name ""
while executing
"$tree expandeditems -worm"
(procedure "_resetTree" line 6)
invoked from within
"_resetTree $w"
(procedure "QObjects::sort" line 4)
invoked from within
"QObjects::sort .main_pane.objects 0 ascending"
("eval" body line 1)
invoked from within
"eval $itk_option(-sortcommand) $column $dir"
(object "::.main_pane.objects.interior.cs.body.tree" method "::vsimwidgets::Hierarchy::sort" body line 26)
invoked from within
"sort $sortIdx $dir"
(object "::.main_pane.objects.interior.cs.body.tree" method "::vsimwidgets::Hierarchy::_initializeSortColumn" body line 10)
invoked from within
"::.main_pane.objects.interior.cs.body.tree _initializeSortColumn"
(in namespace inscope "::vsimwidgets::Hierarchy" script line 1)
invoked from within
"namespace inscope ::vsimwidgets::Hierarchy {::.main_pane.objects.interior.cs.body.tree _initializeSortColumn}"
("after" script)
<2: ::tkerror {invalid command name ""}
<1: ::bgerror {invalid command name ""}
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /main/U_TX_Streamer/tx_flush_p1_i
add wave -noupdate /main/U_TX_Streamer/tx_last_p1_i
add wave -noupdate /main/U_TX_Streamer/tx_data_i
add wave -noupdate /main/U_TX_Streamer/tx_reset_seq_i
add wave -noupdate /main/U_TX_Streamer/tx_valid_i
add wave -noupdate /main/U_TX_Streamer/tx_dreq_o
add wave -position 7 sim:/main/data_from_tx
add wave -position 8 sim:/main/data_to_rx
add wave -position 8 sim:/main/rx_streamer_lost_blks
add wave -position 9 sim:/main/rx_streamer_lost_frm
add wave -position 10 sim:/main/rx_streamer_lost_frm_cnt
add wave -noupdate /main/mac/adr
add wave -noupdate /main/mac/dat_o
add wave -noupdate /main/mac/dat_i
add wave -noupdate /main/mac/sel
add wave -noupdate /main/mac/ack
add wave -noupdate /main/mac/stall
add wave -noupdate /main/mac/err
add wave -noupdate /main/mac/rty
add wave -noupdate /main/mac/cyc
add wave -noupdate /main/mac/stb
add wave -noupdate /main/mac/we
add wave -noupdate /main/U_RX_Streamer/rx_first_p1_o
add wave -noupdate /main/U_RX_Streamer/rx_last_p1_o
add wave -noupdate /main/U_RX_Streamer/rx_data_o
add wave -noupdate /main/U_RX_Streamer/rx_valid_o
add wave -noupdate /main/U_RX_Streamer/rx_dreq_i
add wave -noupdate /main/U_RX_Streamer/rx_lost_p1_o
add wave -position end sim:/main/break_link
add wave -position end sim:/main/delay_link
add wave -position end sim:/main/tx_wb_ack
add wave -position end sim:/main/tx_wb_cyc
add wave -position end sim:/main/tx_wb_stall
add wave -position end sim:/main/tx_wb_stb
add wave -position end sim:/main/rx_wb_ack
add wave -position end sim:/main/rx_wb_cyc
add wave -position end sim:/main/rx_wb_stall
add wave -position end sim:/main/rx_wb_stb
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {867 ns} 0}
configure wave -namecolwidth 150
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -signalnamewidth 1
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
WaveRestoreZoom {0 ns} {915 ns}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment