Commit ecccdb6d authored by Maciej Lipinski's avatar Maciej Lipinski Committed by Tomasz Wlostowski

Added WR Streamers developed by Tomasz Wlostowski (VHDL, testbenches, spec_top, sythesis) .

The added code is based on the one provided for White Rabbit Core Hands-on
Training (http://www.ohwr.org/projects/wr-cores/wiki/Handson_training). The
code has been only adapted to
- fit the structure of wr-cores repository
- work with the newest wrpc-v3.0
parent 1d048108
......@@ -13,5 +13,6 @@ modules = {"local" :
"modules/wr_eca",
"modules/wr_tlu",
"modules/wrc_core",
"modules/wr_streamers",
"platform"]
}
files = ["streamers_pkg.vhd", "xtx_streamer.vhd", "tx_streamer.vhd", "xrx_streamer.vhd", "rx_streamer.vhd", "gc_escape_inserter.vhd", "gc_escape_detector.vhd", "dropping_buffer.vhd"]
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.genram_pkg.all;
entity dropping_buffer is
generic (
g_size : integer;
g_data_width : integer);
port
(
clk_i : in std_logic;
rst_n_i : in std_logic;
d_i : in std_logic_vector(g_data_width-1 downto 0);
d_req_o : out std_logic;
d_drop_i : in std_logic;
d_accept_i : in std_logic;
d_valid_i : in std_logic;
d_o : out std_logic_vector(g_data_width-1 downto 0);
d_valid_o : out std_logic;
d_req_i : in std_logic);
end dropping_buffer;
architecture behavioral of dropping_buffer is
type t_mem_array is array(0 to g_size-1) of std_logic_vector(g_data_width-1 downto 0);
subtype t_counter is unsigned(f_log2_size(g_size)-1 downto 0);
signal wr_ptr, rd_ptr, boundary : t_counter := (others => '0');
signal full, empty_comb : std_logic;
signal empty_reg : std_logic := '0';
signal mem : t_mem_array;
begin -- behavioral
p_counters : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
wr_ptr <= (others => '0');
rd_ptr <= (others => '0');
boundary <= (others => '0');
else
if(d_accept_i = '1') then
boundary <= wr_ptr;
end if;
if(d_drop_i = '1') then
wr_ptr <= boundary;
elsif(d_valid_i = '1' and full = '0') then
wr_ptr <= wr_ptr + 1;
end if;
if (d_req_i = '1' and empty_reg = '0' and empty_comb = '0') then
rd_ptr <= rd_ptr + 1;
end if;
end if;
end if;
end process;
empty_comb <= '1' when (boundary = rd_ptr) else '0';
full <= '1' when (wr_ptr + 1 = rd_ptr) else '0';
d_req_o <= not full;
p_empty_reg : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
empty_reg <= '1';
else
empty_reg <= empty_comb;
end if;
end if;
end process;
p_mem_read : process(clk_i)
begin
if rising_edge(clk_i) then
if(d_req_i = '1' and empty_reg = '0' and empty_comb = '0') then
d_o <= mem(to_integer(rd_ptr));
d_valid_o <= '1';
else
d_valid_o <= '0';
end if;
end if;
end process;
p_mem_write : process(clk_i)
begin
if rising_edge(clk_i) then
if(d_valid_i = '1') then
mem(to_integer(wr_ptr)) <= d_i;
end if;
end if;
end process;
end behavioral;
library ieee;
use ieee.std_logic_1164.all;
entity escape_detector is
generic(
g_data_width : integer;
g_escape_code : std_logic_vector
);
port(
clk_i : in std_logic;
rst_n_i : in std_logic;
d_i : in std_logic_vector(g_data_width-1 downto 0);
d_detect_enable_i : in std_logic;
d_valid_i : in std_logic;
d_req_o : out std_logic;
d_o : out std_logic_vector(g_data_width-1 downto 0);
d_escape_o : out std_logic;
d_valid_o : out std_logic;
d_req_i : in std_logic
);
end escape_detector;
architecture behavioral of escape_detector is
type t_state is (IDLE, CHECK_ESCAPE);
signal state : t_state;
signal is_escape_code : std_logic;
begin -- behavioral
d_req_o <= d_req_i;
is_escape_code <= '1' when (d_detect_enable_i = '1' and state = IDLE and d_valid_i = '1' and d_i = g_escape_code) else '0';
d_o <= g_escape_code when (state = CHECK_ESCAPE and d_i = x"0000") else d_i;
d_valid_o <= d_valid_i and not is_escape_code;
d_escape_o <= '1' when (state = CHECK_ESCAPE and d_i /= x"0000") else '0';
p_fsm : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' or d_detect_enable_i = '0' then
state <= IDLE;
else
case state is
when IDLE =>
if(d_i = g_escape_code and d_valid_i = '1') then
state <= CHECK_ESCAPE;
end if;
when CHECK_ESCAPE =>
if(d_valid_i = '1') then
state <= IDLE;
end if;
end case;
end if;
end if;
end process;
end behavioral;
-------------------------------------------------------------------------------
-- Title : Escape insertion unit
-- Project : General cores library
-------------------------------------------------------------------------------
-- File : gc_escape_inserter.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-CO-HT
-- Created : 2012-10-01
-- Last update: 2012-10-10
-- Platform : FPGA-generic
-- Standard : VHDL '93
------------------------------------------------------------------------------
-- Description: Unit for inserting escaped codes in a continuous data stream.
-- Allows for insertion of easily distinguishable control codes, such as start-
-- or end-of-frame markers. Given an input tuple (E[d_escape_i], D[d_i]), the
-- output (d_o) is:
-- - D when E == 0 and D != g_escape_code
-- - g_escape_code followed by 0 when E == 0 and D == g_escape_code
-- - g_escape_code followed by D when E == 1.
-- Note: When E == 1, D must not be 0.
------------------------------------------------------------------------------
--
-- Copyright (c) 2012 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
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity gc_escape_inserter is
generic(
-- data path width
g_data_width : integer;
-- unique escape character (of g_data_width bits), must not be 0.
g_escape_code : std_logic_vector
);
port(
clk_i : in std_logic;
rst_n_i : in std_logic;
-- data input (unescaped)
d_i : in std_logic_vector(g_data_width-1 downto 0);
-- when 1, escape insertion logic is enabled (i.e. if d_i == g_escape_code,
-- it's translated to g_escape_code followed by 0 instead of just being passed
-- through
d_insert_enable_i : in std_logic;
-- when 1, d_i is treated as a escaped character
d_escape_i : in std_logic;
-- when 1, d_i and d_escape_i contain valid character
d_valid_i : in std_logic;
-- when 1, module can accept data in the following clock cycle.
d_req_o : out std_logic;
-- data output
d_o : out std_logic_vector (g_data_width-1 downto 0);
-- when 1, d_o contains a valid character
d_valid_o : out std_logic;
-- when 1, d_o/d_valid_o may output a character in the next clock cycle.
d_req_i : in std_logic
);
end gc_escape_inserter;
architecture behavioral of gc_escape_inserter is
type t_state is (IDLE, INSERT_ESCAPE);
signal d_prev : std_logic_vector(g_data_width-1 downto 0);
signal d_req_prev : std_logic;
signal state : t_state;
signal match_esc_code : std_logic;
begin -- behavioral
match_esc_code <= '1' when d_i = g_escape_code else '0';
-- stop the traffic if we need to insert an escaped sequence. This
-- can happen when
-- - the input character is an escape code (d_escape_i = '1')
-- - the input character is not to be escaped, but it's equal to g_escape_code
d_req_o <= d_req_i and not (d_valid_i and (d_escape_i or match_esc_code));
d_o <= d_prev when (state = INSERT_ESCAPE) else
d_i when d_escape_i = '0' else
g_escape_code;
d_valid_o <= d_valid_i when (state = IDLE) else
d_req_prev;
p_fsm : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' or d_insert_enable_i = '0' then
state <= IDLE;
d_req_prev <= '0';
else
d_req_prev <= d_req_i;
case state is
when IDLE =>
-- case 1: escape the escape character sent as normal character
if(d_i = g_escape_code and d_valid_i = '1' and d_escape_i = '0') then
state <= INSERT_ESCAPE;
d_prev <= x"0000";
-- case 2: send an escaped character
elsif(d_escape_i = '1' and d_valid_i = '1') then
state <= INSERT_ESCAPE;
d_prev <= d_i;
end if;
when INSERT_ESCAPE =>
if(d_req_prev = '1') then
state <= IDLE;
end if;
end case;
end if;
end if;
end process;
end behavioral;
-- see xrx_streamer.vhd for port documentation
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
use work.wr_fabric_pkg.all;
entity rx_streamer is
generic (
g_data_width : integer := 32;
g_buffer_size : integer := 128;
g_filter_remote_mac : boolean := false
);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-- Endpoint/WRC interface
snk_dat_i : in std_logic_vector(15 downto 0);
snk_adr_i : in std_logic_vector(1 downto 0);
snk_sel_i : in std_logic_vector(1 downto 0);
snk_cyc_i : in std_logic;
snk_stb_i : in std_logic;
snk_we_i : in std_logic;
snk_stall_o : out std_logic;
snk_ack_o : out std_logic;
snk_err_o : out std_logic;
snk_rty_o : out std_logic;
clk_ref_i : in std_logic := '0';
tm_time_valid_i : in std_logic := '0';
tm_tai_i : in std_logic_vector(39 downto 0) := x"0000000000";
tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000";
rx_first_o : out std_logic;
rx_last_o : out std_logic;
rx_data_o : out std_logic_vector(g_data_width-1 downto 0);
rx_valid_o : out std_logic;
rx_dreq_i : in std_logic;
rx_lost_o : out std_logic := '0';
rx_latency_o : out std_logic_vector(27 downto 0);
rx_latency_valid_o : out std_logic;
cfg_mac_local_i : in std_logic_vector(47 downto 0);
cfg_mac_remote_i : in std_logic_vector(47 downto 0);
cfg_ethertype_i : in std_logic_vector(15 downto 0) := x"dbff";
cfg_accept_broadcasts_i : in std_logic := '1'
);
end rx_streamer;
architecture wrapper of rx_streamer is
component xrx_streamer
generic (
g_data_width : integer;
g_buffer_size : integer;
g_filter_remote_mac : boolean);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
clk_ref_i : in std_logic := '0';
tm_time_valid_i : in std_logic := '0';
tm_tai_i : in std_logic_vector(39 downto 0) := x"0000000000";
tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000";
rx_first_o : out std_logic;
rx_last_o : out std_logic;
rx_data_o : out std_logic_vector(g_data_width-1 downto 0);
rx_valid_o : out std_logic;
rx_dreq_i : in std_logic;
rx_lost_o : out std_logic := '0';
rx_latency_o : out std_logic_vector(27 downto 0);
rx_latency_valid_o : out std_logic;
cfg_mac_local_i : in std_logic_vector(47 downto 0);
cfg_mac_remote_i : in std_logic_vector(47 downto 0);
cfg_ethertype_i : in std_logic_vector(15 downto 0) := x"dbff";
cfg_accept_broadcasts_i : in std_logic := '1');
end component;
signal snk_in : t_wrf_sink_in;
signal snk_out : t_wrf_sink_out;
begin -- rtl
U_Wrapped_Streamer : xrx_streamer
generic map (
g_data_width => g_data_width,
g_filter_remote_mac => g_filter_remote_mac,
g_buffer_size => g_buffer_size)
port map (
clk_sys_i => clk_sys_i,
clk_ref_i => clk_ref_i,
tm_tai_i => tm_tai_i,
tm_time_valid_i => tm_time_valid_i,
tm_cycles_i => tm_cycles_i,
rst_n_i => rst_n_i,
snk_i => snk_in,
snk_o => snk_out,
rx_data_o => rx_data_o,
rx_valid_o => rx_valid_o,
rx_dreq_i => rx_dreq_i,
rx_lost_o => rx_lost_o,
rx_first_o => rx_first_o,
rx_last_o => rx_last_o,
rx_latency_valid_o => rx_latency_valid_o,
rx_latency_o => rx_latency_o,
cfg_mac_local_i => cfg_mac_local_i,
cfg_mac_remote_i => cfg_mac_remote_i,
cfg_ethertype_i => cfg_ethertype_i,
cfg_accept_broadcasts_i => cfg_accept_broadcasts_i);
snk_in.dat <= snk_dat_i;
snk_in.adr <= snk_adr_i;
snk_in.sel <= snk_sel_i;
snk_in.cyc <= snk_cyc_i;
snk_in.stb <= snk_stb_i;
snk_in.we <= snk_we_i;
snk_stall_o <= snk_out.stall;
snk_ack_o <= snk_out.ack;
snk_err_o <= snk_out.err;
snk_rty_o <= snk_out.rty;
end wrapper;
library ieee;
use ieee.std_logic_1164.all;
use work.wr_fabric_pkg.all;
package streamers_pkg is
component xtx_streamer
generic (
g_data_width : integer := 32;
g_tx_threshold : integer := 16;
g_tx_max_words_per_frame : integer := 128;
g_tx_timeout : integer := 128);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
src_i : in t_wrf_source_in;
src_o : out t_wrf_source_out;
clk_ref_i : in std_logic := '0';
tm_time_valid_i : in std_logic := '0';
tm_tai_i : in std_logic_vector(39 downto 0) := x"0000000000";
tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000";
tx_data_i : in std_logic_vector(g_data_width-1 downto 0);
tx_valid_i : in std_logic;
tx_dreq_o : out std_logic;
tx_last_i : in std_logic := '1';
tx_flush_i : in std_logic := '0';
tx_reset_seq_i : in std_logic := '0';
cfg_mac_local_i : in std_logic_vector(47 downto 0) := x"000000000000";
cfg_mac_target_i : in std_logic_vector(47 downto 0);
cfg_ethertype_i : in std_logic_vector(15 downto 0) := x"dbff");
end component;
component xrx_streamer
generic (
g_data_width : integer := 32;
g_buffer_size : integer := 16;
g_filter_remote_mac : boolean := false);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
clk_ref_i : in std_logic := '0';
tm_time_valid_i : in std_logic := '0';
tm_tai_i : in std_logic_vector(39 downto 0) := x"0000000000";
tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000";
rx_first_o : out std_logic;
rx_last_o : out std_logic;
rx_data_o : out std_logic_vector(g_data_width-1 downto 0);
rx_valid_o : out std_logic;
rx_dreq_i : in std_logic;
rx_lost_o : out std_logic := '0';
rx_latency_o : out std_logic_vector(27 downto 0);
rx_latency_valid_o : out std_logic;
cfg_mac_local_i : in std_logic_vector(47 downto 0) := x"000000000000";
cfg_mac_remote_i : in std_logic_vector(47 downto 0) := x"000000000000";
cfg_ethertype_i : in std_logic_vector(15 downto 0) := x"dbff";
cfg_accept_broadcasts_i : in std_logic := '1');
end component;
end streamers_pkg;
-- see xtx_streamer.vhd for comments
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
use work.wr_fabric_pkg.all;
use work.streamers_pkg.all;
entity tx_streamer is
generic (
g_data_width : integer := 32;
g_tx_threshold : integer := 16;
g_tx_max_words_per_frame : integer := 128;
g_tx_timeout : integer := 1024
);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-- Endpoint/WRC interface
src_dat_o : out std_logic_vector(15 downto 0);
src_adr_o : out std_logic_vector(1 downto 0);
src_sel_o : out std_logic_vector(1 downto 0);
src_cyc_o : out std_logic;
src_stb_o : out std_logic;
src_we_o : out std_logic;
src_stall_i : in std_logic;
src_ack_i : in std_logic;
src_err_i : in std_logic;
clk_ref_i : in std_logic := '0';
tm_time_valid_i : in std_logic := '0';
tm_tai_i : in std_logic_vector(39 downto 0) := x"0000000000";
tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000";
tx_flush_i : in std_logic := '0';
tx_last_i : in std_logic := '1';
tx_data_i : in std_logic_vector(g_data_width-1 downto 0);
tx_reset_seq_i : in std_logic := '0';
tx_valid_i : in std_logic;
tx_dreq_o : out std_logic;
-- MAC address
cfg_mac_local_i : in std_logic_vector(47 downto 0) := x"000000000000";
cfg_mac_target_i : in std_logic_vector(47 downto 0) := x"ffffffffffff";
cfg_ethertype_i : in std_logic_vector(15 downto 0) := x"dbff"
);
end tx_streamer;
architecture rtl of tx_streamer is
signal src_in : t_wrf_source_in;
signal src_out : t_wrf_source_out;
begin -- rtl
U_Wrapped_Streamer : xtx_streamer
generic map (
g_data_width => g_data_width,
g_tx_threshold => g_tx_threshold,
g_tx_max_words_per_frame => g_tx_max_words_per_frame,
g_tx_timeout => g_tx_timeout)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
src_i => src_in,
src_o => src_out,
tx_last_i => tx_last_i,
tx_data_i => tx_data_i,
tx_reset_seq_i => tx_reset_seq_i,
tx_valid_i => tx_valid_i,
tx_dreq_o => tx_dreq_o,
tx_flush_i => tx_flush_i,
clk_ref_i => clk_ref_i,
tm_time_valid_i => tm_time_valid_i,
tm_tai_i => tm_tai_i,
tm_cycles_i => tm_cycles_i,
cfg_mac_local_i => cfg_mac_local_i,
cfg_mac_target_i => cfg_mac_target_i,
cfg_ethertype_i => cfg_ethertype_i);
src_adr_o <= src_out.adr;
src_dat_o <= src_out.dat;
src_sel_o <= src_out.sel;
src_stb_o <= src_out.stb;
src_we_o <= src_out.we;
src_cyc_o <= src_out.cyc;
src_in.ack <= src_ack_i;
src_in.stall <= src_stall_i;
src_in.err <= src_err_i;
end rtl;
-------------------------------------------------------------------------------
-- Title : Simple Ethernet Data Streamer
-- Project : White Rabbit Hands-On Course
-------------------------------------------------------------------------------
-- File : xrx_streamer.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-CO-HT
-- Created : 2012-11-02
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description: A simple core demonstrating how to encapsulate a continuous
-- stream of data words into Ethernet frames, in a format that is accepted by
-- the White Rabbit PTP core. This core decodes Ethernet frames encoded by
-- xtx_streamer. More info in the documentation.
-------------------------------------------------------------------------------
-- Copyright (c) 2013 CERN BE-CO-HT.
-- Licensed under LGPL 2.1.
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
use work.wr_fabric_pkg.all;
use work.gencores_pkg.all;
use work.genram_pkg.all;
entity xrx_streamer is
generic (
-- Width of the data words. Must be same as in the TX streamer.
g_data_width : integer := 32;
-- Size of RX buffer, in data words.
g_buffer_size : integer := 16;
-- When true, receives only packets whose destination MAC equals
-- cfg_mac_remote_i. When false. accepts all incoming packets.
g_filter_remote_mac : boolean := false
);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-- Endpoint/WRC interface
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
---------------------------------------------------------------------------
-- WRC Timing interface, used for latency measurement
-- Caution: uses clk_ref_i clock domain!
---------------------------------------------------------------------------
-- White Rabbit reference clock
clk_ref_i : in std_logic := '0';
-- Time valid flag
tm_time_valid_i : in std_logic := '0';
-- TAI seconds
tm_tai_i : in std_logic_vector(39 downto 0) := x"0000000000";
-- Fractional part of the second (in clk_ref_i cycles)
tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000";
---------------------------------------------------------------------------
-- User interface
---------------------------------------------------------------------------
-- 1 indicates the 1st word of the data block on rx_data_o.
rx_first_o : out std_logic;
-- 1 indicates the last word of the data block on rx_data_o.
rx_last_o : out std_logic;
-- Received data.
rx_data_o : out std_logic_vector(g_data_width-1 downto 0);
-- 1 indicted that rx_data_o is outputting a valid data word.
rx_valid_o : out std_logic;
-- Synchronous data request input: when 1, the streamer may output another
-- data word in the subsequent clock cycle.
rx_dreq_i : in std_logic;
-- Lost output: 1 indicates that one or more of frames have been lost.
rx_lost_o : out std_logic := '0';
-- Latency measurement output: indicates the transport latency (between the
-- TX streamer in remote device and this streamer), in clk_ref_i clock cycles.
rx_latency_o : out std_logic_vector(27 downto 0);
-- 1 when the latency on rx_latency_o is valid.
rx_latency_valid_o : out std_logic;
-- MAC address
cfg_mac_local_i : in std_logic_vector(47 downto 0);
cfg_mac_remote_i : in std_logic_vector(47 downto 0);
cfg_ethertype_i : in std_logic_vector(15 downto 0) := x"dbff";
-- 1: accept all broadcast packets
-- 0: accept only unicasts
cfg_accept_broadcasts_i : in std_logic := '1'
);
end xrx_streamer;
architecture rtl of xrx_streamer is
type t_pipe is record
dvalid : std_logic;
dreq : std_logic;
sof : std_logic;
eof : std_logic;
error : std_logic;
data : std_logic_vector(15 downto 0);
addr : std_logic_vector(1 downto 0);
bytesel : std_logic;
end record;
component escape_detector
generic (
g_data_width : integer;
g_escape_code : std_logic_vector);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
d_i : in std_logic_vector(g_data_width-1 downto 0);
d_detect_enable_i : in std_logic;
d_valid_i : in std_logic;
d_req_o : out std_logic;
d_o : out std_logic_vector(g_data_width-1 downto 0);
d_escape_o : out std_logic;
d_valid_o : out std_logic;
d_req_i : in std_logic);
end component;
component dropping_buffer
generic (
g_size : integer;
g_data_width : integer);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
d_i : in std_logic_vector(g_data_width-1 downto 0);
d_req_o : out std_logic;
d_drop_i : in std_logic;
d_accept_i : in std_logic;
d_valid_i : in std_logic;
d_o : out std_logic_vector(g_data_width-1 downto 0);
d_valid_o : out std_logic;
d_req_i : in std_logic);
end component;
component pulse_stamper
port (
clk_ref_i : in std_logic;
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
pulse_a_i : in std_logic;
tm_time_valid_i : in std_logic;
tm_tai_i : in std_logic_vector(39 downto 0);
tm_cycles_i : in std_logic_vector(27 downto 0);
tag_tai_o : out std_logic_vector(39 downto 0);
tag_cycles_o : out std_logic_vector(27 downto 0);
tag_valid_o : out std_logic);
end component;
component xwb_fabric_sink
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
addr_o : out std_logic_vector(1 downto 0);
data_o : out std_logic_vector(15 downto 0);
dvalid_o : out std_logic;
sof_o : out std_logic;
eof_o : out std_logic;
error_o : out std_logic;
bytesel_o : out std_logic;
dreq_i : in std_logic);
end component;
type t_rx_state is (IDLE, HEADER, PAYLOAD, SUBFRAME_HEADER, EOF);
signal fab, fsm_in : t_pipe;
signal state : t_rx_state;
signal count, ser_count : unsigned(3 downto 0);
signal seq_no, seq_new : unsigned(14 downto 0);
signal crc_match, crc_en, crc_en_masked, crc_restart : std_logic;
signal detect_escapes, is_escape : std_logic;
signal rx_pending : std_logic;
signal pack_data, fifo_data : std_logic_vector(g_data_width-1 downto 0);
signal fifo_drop, fifo_accept, fifo_accept_d0, fifo_dvalid : std_logic;
signal fifo_sync, fifo_last, fifo_lost : std_logic;
signal fifo_dout, fifo_din : std_logic_vector(g_data_width + 2 downto 0);
signal pending_write, fab_dvalid_pre : std_logic;
signal tx_tag_cycles, rx_tag_cycles : std_logic_vector(27 downto 0);
signal tx_tag_valid, rx_tag_valid : std_logic;
signal got_next_subframe : std_logic;
begin -- rtl
U_rx_crc_generator : gc_crc_gen
generic map (
g_polynomial => x"1021",
g_init_value => x"ffff",
g_residue => x"470f",
g_data_width => 16,
g_sync_reset => 1,
g_dual_width => 0,
g_registered_match_output => true)
port map (
clk_i => clk_sys_i,
rst_i => '0',
restart_i => crc_restart,
en_i => crc_en_masked,
data_i => fsm_in.data,
half_i => '0',
match_o => crc_match);
crc_en_masked <= crc_en and fsm_in.dvalid;
U_Fabric_Sink : xwb_fabric_sink
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_i,
snk_i => snk_i,
snk_o => snk_o,
addr_o => fab.addr,
data_o => fab.data,
dvalid_o => fab_dvalid_pre,
sof_o => fab.sof,
eof_o => fab.eof,
error_o => fab.error,
bytesel_o => fab.bytesel,
dreq_i => fab.dreq);
fab.dvalid <= '1' when fab_dvalid_pre = '1' and fab.addr = c_WRF_DATA and fab.bytesel = '0' else '0';
U_Escape_Detect : escape_detector
generic map (
g_data_width => 16,
g_escape_code => x"cafe")
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_i,
d_i => fab.data,
d_detect_enable_i => detect_escapes,
d_valid_i => fab.dvalid,
d_req_o => fab.dreq,
d_o => fsm_in.data,
d_escape_o => is_escape,
d_valid_o => fsm_in.dvalid,
d_req_i => fsm_in.dreq);
fsm_in.eof <= fab.eof or fab.error;
fsm_in.sof <= fab.sof;
U_Output_FIFO : dropping_buffer
generic map (
g_size => g_buffer_size,
g_data_width => g_data_width + 3)
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_i,
d_i => fifo_din,
d_req_o => fsm_in.dreq,
d_drop_i => fifo_drop,
d_accept_i => fifo_accept_d0,
d_valid_i => fifo_dvalid,
d_o => fifo_dout,
d_valid_o => rx_valid_o,
d_req_i => rx_dreq_i);
fifo_din(g_data_width+1) <= fifo_sync;
fifo_din(g_data_width) <= fifo_last;
fifo_din(g_data_width-1 downto 0) <= fifo_data;
rx_data_o <= fifo_dout(g_data_width-1 downto 0);
rx_first_o <= fifo_dout(g_data_width+1);
rx_last_o <= fifo_dout(g_data_width);
U_RX_Timestamper : pulse_stamper
port map (
clk_ref_i => clk_ref_i,
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
pulse_a_i => fsm_in.sof,
tm_time_valid_i => tm_time_valid_i,
tm_tai_i => tm_tai_i,
tm_cycles_i => tm_cycles_i,
tag_cycles_o => rx_tag_cycles);
p_fsm : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
state <= IDLE;
count <= (others => '0');
seq_no <= (others => '0');
else
case state is
when IDLE =>
detect_escapes <= '0';
crc_en <= '0';
count <= (others => '0');
fifo_accept <= '0';
fifo_drop <= '0';
fifo_dvalid <= '0';
pending_write <= '0';
rx_latency_valid_o <= '0';
tx_tag_valid <= '0';
if(fsm_in.sof = '1') then
state <= HEADER;
end if;
when HEADER =>
if(fsm_in.eof = '1') then
state <= IDLE;
elsif(fsm_in.dvalid = '1') then
case count is
when x"0" =>
if(fsm_in.data /= cfg_mac_local_i(47 downto 32) nor (cfg_accept_broadcasts_i = '1' and fsm_in.data /= x"ffff")) then
state <= IDLE;
end if;
when x"1" =>
if(fsm_in.data /= cfg_mac_local_i(31 downto 16) nor (cfg_accept_broadcasts_i = '1' and fsm_in.data /= x"ffff")) then
state <= IDLE;
end if;
when x"2" =>
if(fsm_in.data /= cfg_mac_local_i(15 downto 0) nor (cfg_accept_broadcasts_i = '1' and fsm_in.data /= x"ffff")) then
state <= IDLE;
end if;
when x"3" =>
if(fsm_in.data /= cfg_mac_remote_i(47 downto 32) and g_filter_remote_mac) then
state <= IDLE;
end if;
when x"4" =>
if(fsm_in.data /= cfg_mac_remote_i(31 downto 16) and g_filter_remote_mac) then
state <= IDLE;
end if;
when x"5" =>
if(fsm_in.data /= cfg_mac_remote_i(15 downto 0) and g_filter_remote_mac) then
state <= IDLE;
end if;
when x"6" =>
if(fsm_in.data /= cfg_ethertype_i) then
state <= IDLE;
end if;
when x"7" =>
tx_tag_valid <= fsm_in.data(15);
tx_tag_cycles(27 downto 16) <= fsm_in.data(11 downto 0);
when x"8" =>
tx_tag_cycles(15 downto 0) <= fsm_in.data;
crc_en <= '1';
detect_escapes <= '1';
state <= SUBFRAME_HEADER;
when others => null;
end case;
count <= count + 1;
end if;
when SUBFRAME_HEADER =>
fifo_drop <= '0';
fifo_accept <= '0';
ser_count <= (others => '0');
if(tx_tag_valid = '1') then
rx_latency_valid_o <= '1';
if(unsigned(tx_tag_cycles) > unsigned(rx_tag_cycles)) then
rx_latency_o <= std_logic_vector(unsigned(rx_tag_cycles) - unsigned(tx_tag_cycles) + to_unsigned(125000000, 28));
else
rx_latency_o <= std_logic_vector(unsigned(rx_tag_cycles) - unsigned(tx_tag_cycles));
end if;
tx_tag_valid <= '0';
else
rx_latency_valid_o <= '0';
end if;
if(fsm_in.eof = '1') then
state <= IDLE;
elsif (fsm_in.dvalid = '1' and is_escape = '1') then
got_next_subframe <= '1';
if(std_logic_vector(seq_no) /= fsm_in.data(14 downto 0)) then
seq_no <= unsigned(fsm_in.data(14 downto 0));
fifo_lost <= '1';
else
seq_no <= unsigned(seq_no + 1);
fifo_lost <= '0';
end if;
state <= PAYLOAD;
end if;
when PAYLOAD =>
fifo_sync <= got_next_subframe;
if(fsm_in.eof = '1') then
state <= IDLE;
fifo_drop <= '1';
fifo_accept <= '0';
got_next_subframe <= '0';
elsif(fsm_in.dvalid = '1') then
if(is_escape = '1') then
ser_count <= (others => '0');
fifo_last <= '1';
got_next_subframe <= '1';
if(fsm_in.data(15) = '1') then
if(std_logic_vector(seq_no) /= fsm_in.data(14 downto 0)) then
seq_no <= unsigned(fsm_in.data(14 downto 0));
fifo_lost <= '1';
else
seq_no <= unsigned(seq_no + 1);
fifo_lost <= '0';
end if;
state <= PAYLOAD;
fifo_accept <= crc_match; --_latched;
fifo_drop <= not crc_match; --_latched;
fifo_dvalid <= pending_write and not fifo_dvalid;
pending_write <= '0';
elsif fsm_in.data = x"0bad" then
state <= EOF;
fifo_accept <= crc_match; --_latched;
fifo_drop <= not crc_match; --_latched;
fifo_dvalid <= pending_write and not fifo_dvalid;
else
state <= EOF;
fifo_drop <= '1';
fifo_accept <= '0';
end if;
-- fifo_dvalid <= '0';
else
fifo_last <= '0';
fifo_accept <= '0';
fifo_drop <= '0';
pack_data(to_integer(ser_count) * 16 + 15 downto to_integer(ser_count) * 16) <= fsm_in.data;
if(ser_count = g_data_width/16 - 1) then
ser_count <= (others => '0');
pending_write <= '1';
fifo_data(g_data_width-16-1 downto 0) <= pack_data(g_data_width-16-1 downto 0);
fifo_data(g_data_width-1 downto g_data_width-16) <= fsm_in.data;
fifo_dvalid <= '0';
elsif(ser_count = g_data_width/16-2 and pending_write = '1') then
pending_write <= '0';
ser_count <= ser_count + 1;
fifo_dvalid <= '1';
fifo_sync <= got_next_subframe;
got_next_subframe <= '0';
else
ser_count <= ser_count + 1;
fifo_dvalid <= '0';
end if;
end if;
else
fifo_dvalid <= '0';
end if;
if(fifo_dvalid = '1') then
fifo_sync <= '0';
end if;
when EOF =>
fifo_dvalid <= '0';
fifo_drop <= '0';
fifo_accept <= '0';
state <= IDLE;
end case;
end if;
end if;
end process;
p_delay_fifo_accept : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
fifo_accept_d0 <= fifo_accept;
end if;
end process;
-- fifo_data <= pack_data;
crc_restart <= '1' when (is_escape = '1' and fsm_in.data(15) = '1') else '0';
end rtl;
-------------------------------------------------------------------------------
-- Title : Simple Ethernet Data Streamer
-- Project : White Rabbit Hands-On Course
-------------------------------------------------------------------------------
-- File : xtx_streamer.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-CO-HT
-- Created : 2012-11-02
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description: A simple core demonstrating how to encapsulate a continuous
-- stream of data words into Ethernet frames, in a format that is accepted by
-- the White Rabbit PTP core. More info in the documentation.
-------------------------------------------------------------------------------
-- Copyright (c) 2013 CERN BE-CO-HT.
-- Licensed under LGPL 2.1.
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
use work.wr_fabric_pkg.all;
use work.gencores_pkg.all;
use work.genram_pkg.all;
entity xtx_streamer is
generic (
-- Width of data words on tx_data_i.
g_data_width : integer := 32;
-- Minimum number of data words in the TX buffer that will trigger transmission of an
-- Ethernet frame. Also defines the buffer size (2 * g_tx_threshold). Note
-- that in order for a frame to be transmitted, the buffer must conatain at
-- least one complete block.
g_tx_threshold : integer := 128;
-- Maximum number of data words in a single Ethernet frame. It also defines
-- the maximum block size (since blocks can't be currently split across
-- multiple frames).
g_tx_max_words_per_frame : integer := 128;
-- Transmission timeout (in clk_sys_i cycles), after which the contents
-- of TX buffer are sent regardless of the amount of data that is currently
-- stored in the buffer, so that data in the buffer does not get stuck.
g_tx_timeout : integer := 1024
);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-- Endpoint/WRC interface - packet source
src_i : in t_wrf_source_in;
src_o : out t_wrf_source_out;
---------------------------------------------------------------------------
-- WRC Timing interface, used for latency measurement
-- Caution: uses clk_ref_i clock domain!
---------------------------------------------------------------------------
-- White Rabbit reference clock
clk_ref_i : in std_logic := '0';
-- Time valid flag
tm_time_valid_i : in std_logic := '0';
-- TAI seconds
tm_tai_i : in std_logic_vector(39 downto 0) := x"0000000000";
-- Fractional part of the second (in clk_ref_i cycles)
tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000";
---------------------------------------------------------------------------
-- User interface
---------------------------------------------------------------------------
-- Data word to be sent.
tx_data_i : in std_logic_vector(g_data_width-1 downto 0);
-- 1 indicates that the tx_data_i contains a valid data word.
tx_valid_i : in std_logic;
-- Synchronous data request: if active, the user may send a data word in
-- the following clock cycle.
tx_dreq_o : out std_logic;
-- Last signal. Can be used to indicate the last data word in a larger
-- block of samples (see documentation for more details).
tx_last_i : in std_logic := '1';
-- Flush input. When asserted, the streamer will immediatly send out all
-- the data that is stored in its TX buffer, ignoring g_tx_timeout.
tx_flush_i : in std_logic := '0';
-- Reset sequence number. When asserted, the internal sequence number
-- generator used to detect loss of frames is reset to 0. Advanced feature.
tx_reset_seq_i : in std_logic := '0';
---------------------------------------------------------------------------
-- Configuration
---------------------------------------------------------------------------
-- Local MAC address. Leave at 0 when using with the WR MAC/Core, it will
-- insert its own source MAC.
cfg_mac_local_i : in std_logic_vector(47 downto 0) := x"000000000000";
-- Destination MAC address.
cfg_mac_target_i : in std_logic_vector(47 downto 0);
-- Ethertype of our frames. Default value is accepted by standard
-- configuration of the WR PTP Core
cfg_ethertype_i : in std_logic_vector(15 downto 0) := x"dbff"
);
end xtx_streamer;
architecture rtl of xtx_streamer is
type t_pipe is record
dvalid : std_logic;
dreq : std_logic;
sof : std_logic;
eof : std_logic;
error : std_logic;
data : std_logic_vector(15 downto 0);
end record;
component xwb_fabric_source
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
src_i : in t_wrf_source_in;
src_o : out t_wrf_source_out;
addr_i : in std_logic_vector(1 downto 0);
data_i : in std_logic_vector(15 downto 0);
dvalid_i : in std_logic;
sof_i : in std_logic;
eof_i : in std_logic;
error_i : in std_logic;
bytesel_i : in std_logic;
dreq_o : out std_logic);
end component;
component gc_escape_inserter
generic (
g_data_width : integer;
g_escape_code : std_logic_vector);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
d_i : in std_logic_vector(g_data_width-1 downto 0);
d_insert_enable_i : in std_logic;
d_escape_i : in std_logic;
d_valid_i : in std_logic;
d_req_o : out std_logic;
d_o : out std_logic_vector (g_data_width-1 downto 0);
d_valid_o : out std_logic;
d_req_i : in std_logic);
end component;
component pulse_stamper
port (
clk_ref_i : in std_logic;
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
pulse_a_i : in std_logic;
tm_time_valid_i : in std_logic;
tm_tai_i : in std_logic_vector(39 downto 0);
tm_cycles_i : in std_logic_vector(27 downto 0);
tag_tai_o : out std_logic_vector(39 downto 0);
tag_cycles_o : out std_logic_vector(27 downto 0);
tag_valid_o : out std_logic);
end component;
type t_tx_state is (IDLE, SOF, ETH_HEADER, SUBFRAME_HEADER, PAYLOAD, CRC_WORD, PADDING, EOF);
constant c_min_packet_size : integer := 32;
signal tx_threshold_hit : std_logic;
signal tx_timeout_hit : std_logic;
signal tx_flush_latched : std_logic;
signal tx_fifo_last, tx_fifo_we, tx_fifo_full, tx_fifo_empty, tx_fifo_rd : std_logic;
signal tx_fifo_q, tx_fifo_d : std_logic_vector(g_data_width downto 0);
signal tx_fifo_valid : std_logic;
signal state : t_tx_state;
signal seq_no : unsigned(14 downto 0);
signal count, ser_count : unsigned(7 downto 0);
signal total_words : unsigned(10 downto 0);
signal timeout_counter : unsigned(11 downto 0);
signal pack_data : std_logic_vector(15 downto 0);
signal fsm_out, escaper, fab_src : t_pipe;
signal fsm_escape, fsm_escape_enable : std_logic;
signal crc_en, crc_en_masked, crc_reset : std_logic;
signal crc_value : std_logic_vector(15 downto 0);
signal tx_almost_empty, tx_almost_full : std_logic;
signal buf_frame_count : unsigned(5 downto 0) := (others => '0');
signal tag_cycles : std_logic_vector(27 downto 0);
signal tag_valid, tag_valid_latched : std_logic;
signal reset_dly : std_logic;
begin -- rtl
U_tx_crc_generator : gc_crc_gen
generic map (
g_polynomial => x"1021",
g_init_value => x"ffff",
g_residue => x"0000",
g_data_width => 16,
g_sync_reset => 1,
g_dual_width => 0,
g_registered_match_output => false,
g_registered_crc_output => false)
port map (
clk_i => clk_sys_i,
rst_i => crc_reset,
en_i => crc_en_masked,
data_i => fsm_out.data,
half_i => '0',
crc_o => crc_value);
crc_en_masked <= crc_en and fsm_out.dvalid;
U_Fab_Source : xwb_fabric_source
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_i,
src_i => src_i,
src_o => src_o,
addr_i => c_WRF_DATA,
data_i => fab_src.data,
dvalid_i => fab_src.dvalid,
sof_i => fab_src.sof,
eof_i => fab_src.eof,
error_i => '0',
bytesel_i => '0',
dreq_o => fab_src.dreq);
fab_src.sof <= fsm_out.sof;
fab_src.eof <= fsm_out.eof;
U_Insert_Escape : gc_escape_inserter
generic map (
g_data_width => 16,
g_escape_code => x"cafe")
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_i,
d_i => fsm_out.data,
d_insert_enable_i => fsm_escape_enable,
d_escape_i => fsm_escape,
d_valid_i => fsm_out.dvalid,
d_req_o => fsm_out.dreq,
d_o => fab_src.data,
d_valid_o => fab_src.dvalid,
d_req_i => fab_src.dreq);
tx_fifo_we <= tx_valid_i and not tx_fifo_full;
tx_fifo_d <= tx_last_i & tx_data_i;
U_TX_Buffer : generic_sync_fifo
generic map (
g_data_width => g_data_width + 1,
g_size => 2 * g_tx_threshold,
g_with_almost_full => true,
g_with_almost_empty => true,
g_almost_empty_threshold => g_tx_threshold,
g_almost_full_threshold => 2*g_tx_threshold - 2,
g_show_ahead => true)
port map (
rst_n_i => rst_n_i,
clk_i => clk_sys_i,
d_i => tx_fifo_d,
we_i => tx_fifo_we,
q_o => tx_fifo_q,
rd_i => tx_fifo_rd,
empty_o => tx_fifo_empty,
full_o => tx_fifo_full,
almost_empty_o => tx_almost_empty,
almost_full_o => tx_almost_full
);
tx_threshold_hit <= '1' when tx_almost_empty = '0' and (buf_frame_count /= 0) else '0';
tx_fifo_last <= tx_fifo_q(g_data_width);
U_Timestamper : pulse_stamper
port map (
clk_ref_i => clk_ref_i,
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
pulse_a_i => fsm_out.sof,
tm_time_valid_i => tm_time_valid_i,
tm_tai_i => tm_tai_i,
tm_cycles_i => tm_cycles_i,
tag_tai_o => open,
tag_cycles_o => tag_cycles,
tag_valid_o => tag_valid);
p_latch_tx_tag : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' or state = IDLE then
tag_valid_latched <= '0';
elsif(tag_valid = '1') then
tag_valid_latched <= '1';
end if;
end if;
end process;
p_frame_counter : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
buf_frame_count <= (others => '0');
else
if(tx_fifo_we = '1' and tx_last_i = '1' and (tx_fifo_rd = '0' or tx_fifo_last = '0')) then
buf_frame_count <= buf_frame_count+ 1;
elsif((tx_fifo_we = '0' or tx_last_i = '0') and (tx_fifo_rd = '1' and tx_fifo_last = '1')) then
buf_frame_count <= buf_frame_count - 1;
end if;
end if;
end if;
end process;
p_tx_fifo_valid : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
tx_fifo_valid <= '0';
else
tx_fifo_valid <= tx_fifo_rd and not tx_fifo_empty;
end if;
end if;
end process;
p_tx_timeout : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
timeout_counter <= (others => '0');
tx_timeout_hit <= '0';
else
if(tx_fifo_empty = '0' and tx_threshold_hit = '0') then
timeout_counter <= timeout_counter + 1;
else
timeout_counter <= (others => '0');
end if;
if(timeout_counter = g_tx_timeout) then
tx_timeout_hit <= '1';
else
tx_timeout_hit <= '0';
end if;
end if;
end if;
end process;
p_latch_tx_flush : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
tx_flush_latched <= '0';
else
if(state = IDLE) then
tx_flush_latched <= tx_flush_i or tx_timeout_hit;
else
tx_flush_latched <= '0';
end if;
end if;
end if;
end process;
p_fsm : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
state <= IDLE;
fsm_out.sof <= '0';
fsm_out.eof <= '0';
fsm_out.dvalid <= '0';
count <= (others => '0');
seq_no <= (others => '0');
-- tx_fifo_rd <= '0';
crc_reset <= '1';
else
if(tx_reset_seq_i = '1') then
seq_no <= (others => '0');
end if;
case state is
when IDLE =>
crc_en <= '0';
crc_reset <= '0';
fsm_out.eof <= '0';
if(fsm_out.dreq = '1' and (tx_flush_latched = '1' or tx_flush_i = '1' or tx_threshold_hit = '1')) then
state <= SOF;
fsm_out.sof <= '1';
end if;
fsm_escape_enable <= '0';
fsm_escape <= '0';
when SOF =>
fsm_out.sof <= '0';
ser_count <= (others => '0');
state <= ETH_HEADER;
count <= (others => '0');
when ETH_HEADER =>
if(fsm_out.dreq = '1') then
case count is
when x"00" =>
fsm_out.data <= cfg_mac_target_i(47 downto 32);
count <= count + 1;
when x"01" =>
fsm_out.data <= cfg_mac_target_i(31 downto 16);
count <= count + 1;
when x"02" =>
fsm_out.data <= cfg_mac_target_i(15 downto 0);
count <= count + 1;
when x"03" =>
fsm_out.data <= cfg_mac_local_i(47 downto 32);
count <= count + 1;
when x"04" =>
fsm_out.data <= cfg_mac_local_i(31 downto 16);
count <= count + 1;
when x"05" =>
fsm_out.data <= cfg_mac_local_i(15 downto 0);
count <= count + 1;
when x"06" =>
fsm_out.data <= cfg_ethertype_i;
count <= count + 1;
when x"07" =>
fsm_out.data <= tag_valid_latched & "000" & tag_cycles(27 downto 16);
count <= count + 1;
when x"08" =>
fsm_out.data <= tag_cycles(15 downto 0);
count <= (others => '0');
state <= SUBFRAME_HEADER;
when others =>
fsm_out.data <= (others => 'X');
count <= (others => 'X');
end case;
fsm_out.dvalid <= '1';
else
fsm_out.dvalid <= '0';
end if;
when SUBFRAME_HEADER =>
crc_en <= '1';
crc_reset <= '0';
if(fsm_out.dreq = '1') then
fsm_out.dvalid <= '1';
fsm_escape <= '1';
fsm_escape_enable <= '1';
fsm_out.data <= '1' & std_logic_vector(seq_no);
seq_no <= seq_no + 1;
state <= PAYLOAD;
else
fsm_out.dvalid <= '0';
fsm_out.data <= (others => 'X');
end if;
when PAYLOAD =>
fsm_escape <= '0';
if(fsm_out.dreq = '1') then
-- next subframe?
if(tx_fifo_empty = '1' or (ser_count = g_data_width/16-1 and tx_fifo_last = '1')) then
state <= CRC_WORD;
end if;
if(ser_count = g_data_width/16-1) then
count <= count + 1;
ser_count <= (others => '0');
else
ser_count <= ser_count + 1;
end if;
fsm_out.data <= tx_fifo_q((to_integer(ser_count) + 1)* 16 -1 downto to_integer(ser_count) * 16);
fsm_out.dvalid <= not tx_fifo_empty;
else
fsm_out.data <= (others => 'X');
fsm_out.dvalid <= '0';
end if;
when CRC_WORD =>
crc_en <= '0';
ser_count <= (others => '0');
if(fsm_out.dreq = '1') then
fsm_out.dvalid <= '1';
fsm_out.data <= crc_value;
crc_reset <= '1';
if(tx_fifo_empty = '1' or count >= g_tx_max_words_per_frame) then
state <= PADDING;
else
state <= SUBFRAME_HEADER;
end if;
end if;
when PADDING =>
if(fsm_out.dreq = '1') then
fsm_escape <= '1';
fsm_out.dvalid <= '1';
fsm_out.data <= x"0bad";
if(total_words >= c_min_packet_size) then
state <= EOF;
end if;
else
fsm_out.dvalid <= '0';
fsm_out.data <= (others => 'X');
end if;
when EOF =>
fsm_out.dvalid <= '0';
if(fsm_out.dreq = '1') then
fsm_out.eof <= '1';
state <= IDLE;
end if;
end case;
end if;
end if;
end process;
p_count_words : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if fsm_out.sof = '1' then
total_words <= (others => '0');
elsif fsm_out.dvalid = '1' then
total_words <= total_words +1;
end if;
end if;
end process;
p_comb_fx_fifo_read : process(state, fsm_out, ser_count)
begin
if(state = PAYLOAD and ser_count = g_data_width/16-1 and fsm_out.dreq = '1' and tx_fifo_empty = '0') then
tx_fifo_rd <= '1';
else
tx_fifo_rd <= '0';
end if;
end process;
p_delay_reset: process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
reset_dly <= rst_n_i;
end if;
end process;
tx_dreq_o <= (not tx_almost_full) and reset_dly;
end rtl;
action= "simulation"
target= "xilinx"
syn_device="xc6slx45t"
sim_tool="modelsim"
top_module="main"
fetchto="../../ip_cores"
vlog_opt="+incdir+../../../sim +incdir"
modules = { "local" : ["../../..",
"../../../modules/wr_streamers",
"../../../top/spec_1_1/wr_streamers_demo",
"../../../ip_cores/general-cores"]}
files = ["main.sv"]
//
// White Rabbit Core Hands-On Course
//
// Lesson 04a: Trivial streamer demo
//
// Objectives:
// - Demonstrate pulse distribution example on a simulation
//
// Brief description:
// Testbench instantiates two SPEC cards connected to each other via a Gigabit
// Ethernet link. SPEC A sends input trigger pulses to SPEC B, which reproduces them with
// fixed, 20us delay.
`timescale 10fs/10fs // need very fine timestep to correctly simulate the GTP.
module main;
// Parameters
// Reference clock period.
parameter g_ref_clock_period = 8ns;
reg clk_20m = 0, clk_ref = 0;
wire uart_txd;
wire [7:0] uart_data;
wire uart_data_valid;
// Generate the reference clock
always #(g_ref_clock_period / 2) clk_ref <= ~clk_ref;
// Generate the 20 MHz VCXO clock
always #(50ns / 2) clk_20m <= ~clk_20m;
reg pulse_in = 0;
wire pulse_out;
wire [4:0] dio_out_b;
// This time we have two SPECs talking to each other in the same testbench
spec_top
#(
.g_simulation (1)
) SPEC_A (
.clk_125m_pllref_p_i (clk_ref),
.clk_125m_pllref_n_i (~clk_ref),
.fpga_pll_ref_clk_101_p_i (clk_ref),
.fpga_pll_ref_clk_101_n_i (~clk_ref),
.clk_20m_vcxo_i(clk_20m),
// Connect the gigabit output of one SPEC with the RX input of the other,
// and vice-versa.
.sfp_txp_o(a_to_b_p),
.sfp_txn_o(a_to_b_n),
.sfp_rxp_i(b_to_a_p),
.sfp_rxn_i(b_to_a_n),
.dio_p_i( {3'b0, pulse_in, 1'b0} ),
.dio_n_i( {3'b1, ~pulse_in, 1'b1} )
);
spec_top
#(
.g_simulation (1)
) SPEC_B (
.clk_125m_pllref_p_i (clk_ref),
.clk_125m_pllref_n_i (~clk_ref),
.fpga_pll_ref_clk_101_p_i (clk_ref),
.fpga_pll_ref_clk_101_n_i (~clk_ref),
.clk_20m_vcxo_i(clk_20m),
// Connect the gigabit output of one SPEC with the RX input of the other,
// and vice-versa.
.sfp_txp_o(b_to_a_p),
.sfp_txn_o(b_to_a_n),
.sfp_rxp_i(a_to_b_p),
.sfp_rxn_i(a_to_b_n),
.dio_p_o ( dio_out_b )
);
assign pulse_out = dio_out_b[2];
// observe the link LEDs on both sides, and tell us when the link is ready.
wire link_up_a = SPEC_A.U_The_WR_Core.led_link_o;
wire link_up_b = SPEC_B.U_The_WR_Core.led_link_o;
initial begin
// wait until both SPECs see the Ethernet link. Otherwise the packet we're going
// to send might end up in void...
wait(link_up_a == 1'b1 && link_up_b == 1'b1);
forever begin // send a pulse every 30 us;
pulse_in = 1;
#1us;
pulse_in = 0;
#30us;
end
end
endmodule // main
make -f Makefile > /dev/null 2>&1
vsim -L unisim -L secureip work.main -voptargs="+acc" -suppress 8684,8683
set NumericStdNoWarnings 1
set StdArithNoWarnings 1
do wave.do
run 400us
wave zoomfull
radix -hex
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate -divider {SPEC A-common}
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/clk_ref_i
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/clk_sys_i
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/rst_n_i
add wave -noupdate -divider {SPEC A - WR timing}
add wave -noupdate /main/SPEC_A/dio_p_i(1)
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/tm_time_valid_i
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/tm_tai_i
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/tm_cycles_i
add wave -noupdate -divider {SPEC A - pulse stamper}
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/tag_tai_o
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/tag_cycles_o
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/tag_valid_o
add wave -noupdate -divider {SPEC A - TX Streamer}
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_TX_Streamer/tx_data_i
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_TX_Streamer/tx_valid_i
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_TX_Streamer/tx_dreq_o
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_TX_Streamer/src_i
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_TX_Streamer/src_o
add wave -noupdate -divider {SPEC A - PHY}
add wave -noupdate -radix hexadecimal /main/SPEC_A/phy_tx_data
add wave -noupdate -radix hexadecimal /main/SPEC_A/phy_tx_k
add wave -noupdate -radix hexadecimal /main/SPEC_A/phy_tx_disparity
add wave -noupdate -radix hexadecimal /main/SPEC_A/phy_tx_enc_err
add wave -noupdate -divider {SPEC B - PHY}
add wave -noupdate -radix hexadecimal /main/SPEC_B/phy_rx_data
add wave -noupdate -radix hexadecimal /main/SPEC_B/phy_rx_rbclk
add wave -noupdate -radix hexadecimal /main/SPEC_B/phy_rx_k
add wave -noupdate -radix hexadecimal /main/SPEC_B/phy_rx_enc_err
add wave -noupdate -divider {SPEC B - WR timing}
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Stamper/tm_time_valid_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Stamper/tm_tai_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Stamper/tm_cycles_i
add wave -noupdate -divider {SPEC B - RX streamer}
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_RX_Streamer/snk_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_RX_Streamer/snk_o
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_RX_Streamer/rx_data_o
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_RX_Streamer/rx_valid_o
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_RX_Streamer/rx_dreq_i
add wave -noupdate -divider {SPEC B - Timestamp adder}
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/valid_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/a_tai_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/a_cycles_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/b_tai_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/b_cycles_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/q_tai_o
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/q_cycles_o
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/valid_o
add wave -noupdate -divider {SPEC B - pulse generator}
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Generator/trig_tai_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Generator/trig_cycles_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Generator/trig_valid_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Generator/trig_ready_o
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Generator/pulse_o
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {98492029160 fs} 0}
configure wave -namecolwidth 150
configure wave -valuecolwidth 152
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 fs} {210 us}
write 0 98000000
write 1 D0000000
write 2 D0200000
write 3 78010000
write 4 38210000
write 5 D0E10000
write 6 98000000
write 7 781C0000
write 8 3B9C0FFC
write 9 781A0000
write a 3B5A84F0
write b F80000E2
write c 78030000
write d 38630448
write e 28610000
write f 3802C49C
write 10 58220004
write 11 C3A00000
write 12 78030000
write 13 38630448
write 14 28620000
write 15 28430000
write 16 20630001
write 17 5C60FFFE
write 18 78030000
write 19 38630448
write 1a 28620000
write 1b 58410008
write 1c C3A00000
write 1d 379CFFF8
write 1e 5B8B0008
write 1f 5B9D0004
write 20 B8205800
write 21 E0000002
write 22 FBFFFFF0
write 23 41610000
write 24 356B0001
write 25 5C20FFFD
write 26 2B9D0004
write 27 2B8B0008
write 28 379C0008
write 29 C3A00000
write 2a 78010000
write 2b 382104F8
write 2c 28210000
write 2d 78030000
write 2e 3863044C
write 2f 28620000
write 30 58200014
write 31 58200018
write 32 78040000
write 33 58220014
write 34 38840450
write 35 3402000B
write 36 58220018
write 37 28820000
write 38 78030000
write 39 38630454
write 3a 58220014
write 3b 34020088
write 3c 58220018
write 3d 28620000
write 3e 78040000
write 3f 38840458
write 40 58220014
write 41 34020108
write 42 58220018
write 43 28820000
write 44 78030000
write 45 3863045C
write 46 58220014
write 47 34020013
write 48 58220018
write 49 28620000
write 4a 78040000
write 4b 38840460
write 4c 58220014
write 4d 34020090
write 4e 58220018
write 4f 28820000
write 50 78030000
write 51 38630464
write 52 58220014
write 53 34020110
write 54 58220018
write 55 28620000
write 56 78040000
write 57 38840468
write 58 58220014
write 59 3402001B
write 5a 58220018
write 5b 28820000
write 5c 78030000
write 5d 3863046C
write 5e 58220014
write 5f 34020098
write 60 58220018
write 61 28620000
write 62 78040000
write 63 38840470
write 64 58220014
write 65 34020118
write 66 58220018
write 67 28820000
write 68 78030000
write 69 38630474
write 6a 58220014
write 6b 34020323
write 6c 58220018
write 6d 28620000
write 6e 78040000
write 6f 38840478
write 70 58220014
write 71 3402032B
write 72 58220018
write 73 28820000
write 74 78030000
write 75 3863047C
write 76 58220014
write 77 34020333
write 78 58220018
write 79 28620000
write 7a 78040000
write 7b 38840480
write 7c 58220014
write 7d 3402034B
write 7e 58220018
write 7f 28820000
write 80 78030000
write 81 38630484
write 82 58220014
write 83 340205BB
write 84 58220018
write 85 28620000
write 86 78040000
write 87 38840488
write 88 58220014
write 89 340205C3
write 8a 58220018
write 8b 28820000
write 8c 78030000
write 8d 3863048C
write 8e 58220014
write 8f 34020351
write 90 58220018
write 91 28620000
write 92 78040000
write 93 38840490
write 94 58220014
write 95 34020159
write 96 58220018
write 97 28820000
write 98 78030000
write 99 38630494
write 9a 58220014
write 9b 34020170
write 9c 58220018
write 9d 28620000
write 9e 78040000
write 9f 38840498
write a0 58220014
write a1 34020A78
write a2 58220018
write a3 28820000
write a4 78030000
write a5 3863049C
write a6 58220014
write a7 34020973
write a8 58220018
write a9 28620000
write aa 78040000
write ab 388404A0
write ac 58220014
write ad 34020E70
write ae 58220018
write af 28820000
write b0 78030000
write b1 386304A4
write b2 58220014
write b3 34020E79
write b4 58220018
write b5 28620000
write b6 78040000
write b7 388404A8
write b8 58220014
write b9 34020BA0
write ba 58220018
write bb 28820000
write bc 78030000
write bd 386304AC
write be 58220014
write bf 340204B9
write c0 58220018
write c1 28620000
write c2 78040000
write c3 388404B0
write c4 58220014
write c5 34020BF8
write c6 58220018
write c7 28820000
write c8 78030000
write c9 386304B4
write ca 58220014
write cb 340201F0
write cc 58220018
write cd 28620000
write ce 78040000
write cf 388404B8
write d0 58220014
write d1 34020FC3
write d2 58220018
write d3 28820000
write d4 78030000
write d5 386304BC
write d6 58220014
write d7 28620000
write d8 58200018
write d9 78040000
write da 58220014
write db 388404C0
write dc 34020080
write dd 58220014
write de 28830000
write df 58200000
write e0 34020003
write e1 5822000C
write e2 58230008
write e3 78030000
write e4 386304C4
write e5 58220004
write e6 28620000
write e7 58220028
write e8 34021122
write e9 58220024
write ea 340200E0
write eb 58220000
write ec C3A00000
write ed 379CFFFC
write ee 5B9D0004
write ef 78020000
write f0 384204C8
write f1 78040000
write f2 28410000
write f3 388404CC
write f4 28830000
write f5 34020012
write f6 78040000
write f7 58220000
write f8 388404D0
write f9 58600000
write fa 28830000
write fb 78040000
write fc 388404D4
write fd 58600000
write fe 28830000
write ff 58600000
write 100 3403001A
write 101 58230000
write 102 78030000
write 103 386304D8
write 104 58220000
write 105 28610000
write 106 34020004
write 107 58220000
write 108 FBFFFF22
write 109 78040000
write 10a 38840448
write 10b 28810000
write 10c 3802C49C
write 10d 58220004
write 10e 78010000
write 10f 382104DC
write 110 FBFFFF0D
write 111 E0000000
write 112 00020500
write 113 40000040
write 114 1FFFFE41
write 115 1FFFFE42
write 116 1FFFFE43
write 117 1E023644
write 118 1E320045
write 119 1E000046
write 11a 1E224447
write 11b 1E668848
write 11c 1EAACC49
write 11d 1E10004A
write 11e 1F11EE4B
write 11f 1E100C4C
write 120 1FB7FE4D
write 121 0600024E
write 122 0600224F
write 123 40010050
write 124 40010651
write 125 40094C52
write 126 400B8E53
write 127 1E008854
write 128 4002D055
write 129 40181E56
write 12a 400BD057
write 12b 40381358
write 12c 40181059
write 12d 4018125A
write 12e 4018005B
write 12f 8000005C
write 130 005EE000
write 131 33445566
write 132 00020300
write 133 00020314
write 134 00020318
write 135 00020310
write 136 0002031C
write 137 54686520
write 138 57522043
write 139 6F726520
write 13a 73617973
write 13b 2068656C
write 13c 6C6F210A
write 13d 00000000
write 13e 00020100
write 13f 00020100
write 140 00000000
write 141 00000000
write 142 00000000
write 143 00000000
write 144 00000000
write 145 00000000
write 146 00000000
write 147 00000000
write 148 00000000
write 149 00000000
write 14a 00000000
write 14b 00000000
write 14c 00000000
write 14d 00000000
write 14e 00000000
write 14f 00000000
write 150 00000000
write 151 00000000
write 152 00000000
write 153 00000000
write 154 00000000
write 155 00000000
write 156 00000000
write 157 00000000
write 158 00000000
write 159 00000000
write 15a 00000000
write 15b 00000000
write 15c 00000000
write 15d 00000000
write 15e 00000000
write 15f 00000000
write 160 00000000
write 161 00000000
write 162 00000000
write 163 00000000
write 164 00000000
write 165 00000000
write 166 00000000
write 167 00000000
write 168 00000000
write 169 00000000
write 16a 00000000
write 16b 00000000
write 16c 00000000
write 16d 00000000
write 16e 00000000
write 16f 00000000
write 170 00000000
write 171 00000000
write 172 00000000
write 173 00000000
write 174 00000000
write 175 00000000
write 176 00000000
write 177 00000000
write 178 00000000
write 179 00000000
write 17a 00000000
write 17b 00000000
write 17c 00000000
write 17d 00000000
write 17e 00000000
write 17f 00000000
write 180 00000000
write 181 00000000
write 182 00000000
write 183 00000000
write 184 00000000
write 185 00000000
write 186 00000000
write 187 00000000
write 188 00000000
write 189 00000000
write 18a 00000000
write 18b 00000000
write 18c 00000000
write 18d 00000000
write 18e 00000000
write 18f 00000000
write 190 00000000
write 191 00000000
write 192 00000000
write 193 00000000
write 194 00000000
write 195 00000000
write 196 00000000
write 197 00000000
write 198 00000000
write 199 00000000
write 19a 00000000
write 19b 00000000
write 19c 00000000
write 19d 00000000
write 19e 00000000
write 19f 00000000
write 1a0 00000000
write 1a1 00000000
write 1a2 00000000
write 1a3 00000000
write 1a4 00000000
write 1a5 00000000
write 1a6 00000000
write 1a7 00000000
write 1a8 00000000
write 1a9 00000000
write 1aa 00000000
write 1ab 00000000
write 1ac 00000000
write 1ad 00000000
write 1ae 00000000
write 1af 00000000
write 1b0 00000000
write 1b1 00000000
write 1b2 00000000
write 1b3 00000000
write 1b4 00000000
write 1b5 00000000
write 1b6 00000000
write 1b7 00000000
write 1b8 00000000
write 1b9 00000000
write 1ba 00000000
write 1bb 00000000
write 1bc 00000000
write 1bd 00000000
write 1be 00000000
write 1bf 00000000
write 1c0 00000000
write 1c1 00000000
write 1c2 00000000
write 1c3 00000000
write 1c4 00000000
write 1c5 00000000
write 1c6 00000000
write 1c7 00000000
write 1c8 00000000
write 1c9 00000000
write 1ca 00000000
write 1cb 00000000
write 1cc 00000000
write 1cd 00000000
write 1ce 00000000
write 1cf 00000000
write 1d0 00000000
write 1d1 00000000
write 1d2 00000000
write 1d3 00000000
write 1d4 00000000
write 1d5 00000000
write 1d6 00000000
write 1d7 00000000
write 1d8 00000000
write 1d9 00000000
write 1da 00000000
write 1db 00000000
write 1dc 00000000
write 1dd 00000000
write 1de 00000000
write 1df 00000000
write 1e0 00000000
write 1e1 00000000
write 1e2 00000000
write 1e3 00000000
write 1e4 00000000
write 1e5 00000000
write 1e6 00000000
write 1e7 00000000
write 1e8 00000000
write 1e9 00000000
write 1ea 00000000
write 1eb 00000000
write 1ec 00000000
write 1ed 00000000
write 1ee 00000000
write 1ef 00000000
write 1f0 00000000
write 1f1 00000000
write 1f2 00000000
write 1f3 00000000
write 1f4 00000000
write 1f5 00000000
write 1f6 00000000
write 1f7 00000000
write 1f8 00000000
write 1f9 00000000
write 1fa 00000000
write 1fb 00000000
write 1fc 00000000
write 1fd 00000000
write 1fe 00000000
write 1ff 00000000
write 200 00000000
write 201 00000000
write 202 00000000
write 203 00000000
write 204 00000000
write 205 00000000
write 206 00000000
write 207 00000000
write 208 00000000
write 209 00000000
write 20a 00000000
write 20b 00000000
write 20c 00000000
write 20d 00000000
write 20e 00000000
write 20f 00000000
write 210 00000000
write 211 00000000
write 212 00000000
write 213 00000000
write 214 00000000
write 215 00000000
write 216 00000000
write 217 00000000
write 218 00000000
write 219 00000000
write 21a 00000000
write 21b 00000000
write 21c 00000000
write 21d 00000000
write 21e 00000000
write 21f 00000000
write 220 00000000
write 221 00000000
write 222 00000000
write 223 00000000
write 224 00000000
write 225 00000000
write 226 00000000
write 227 00000000
write 228 00000000
write 229 00000000
write 22a 00000000
write 22b 00000000
write 22c 00000000
write 22d 00000000
write 22e 00000000
write 22f 00000000
write 230 00000000
write 231 00000000
write 232 00000000
write 233 00000000
write 234 00000000
write 235 00000000
write 236 00000000
write 237 00000000
write 238 00000000
write 239 00000000
write 23a 00000000
write 23b 00000000
write 23c 00000000
write 23d 00000000
write 23e 00000000
write 23f 00000000
write 240 00000000
write 241 00000000
write 242 00000000
write 243 00000000
write 244 00000000
write 245 00000000
write 246 00000000
write 247 00000000
write 248 00000000
write 249 00000000
write 24a 00000000
write 24b 00000000
write 24c 00000000
write 24d 00000000
write 24e 00000000
write 24f 00000000
write 250 00000000
write 251 00000000
write 252 00000000
write 253 00000000
write 254 00000000
write 255 00000000
write 256 00000000
write 257 00000000
write 258 00000000
write 259 00000000
write 25a 00000000
write 25b 00000000
write 25c 00000000
write 25d 00000000
write 25e 00000000
write 25f 00000000
write 260 00000000
write 261 00000000
write 262 00000000
write 263 00000000
write 264 00000000
write 265 00000000
write 266 00000000
write 267 00000000
write 268 00000000
write 269 00000000
write 26a 00000000
write 26b 00000000
write 26c 00000000
write 26d 00000000
write 26e 00000000
write 26f 00000000
write 270 00000000
write 271 00000000
write 272 00000000
write 273 00000000
write 274 00000000
write 275 00000000
write 276 00000000
write 277 00000000
write 278 00000000
write 279 00000000
write 27a 00000000
write 27b 00000000
write 27c 00000000
write 27d 00000000
write 27e 00000000
write 27f 00000000
write 280 00000000
write 281 00000000
write 282 00000000
write 283 00000000
write 284 00000000
write 285 00000000
write 286 00000000
write 287 00000000
write 288 00000000
write 289 00000000
write 28a 00000000
write 28b 00000000
write 28c 00000000
write 28d 00000000
write 28e 00000000
write 28f 00000000
write 290 00000000
write 291 00000000
write 292 00000000
write 293 00000000
write 294 00000000
write 295 00000000
write 296 00000000
write 297 00000000
write 298 00000000
write 299 00000000
write 29a 00000000
write 29b 00000000
write 29c 00000000
write 29d 00000000
write 29e 00000000
write 29f 00000000
write 2a0 00000000
write 2a1 00000000
write 2a2 00000000
write 2a3 00000000
write 2a4 00000000
write 2a5 00000000
write 2a6 00000000
write 2a7 00000000
write 2a8 00000000
write 2a9 00000000
write 2aa 00000000
write 2ab 00000000
write 2ac 00000000
write 2ad 00000000
write 2ae 00000000
write 2af 00000000
write 2b0 00000000
write 2b1 00000000
write 2b2 00000000
write 2b3 00000000
write 2b4 00000000
write 2b5 00000000
write 2b6 00000000
write 2b7 00000000
write 2b8 00000000
write 2b9 00000000
write 2ba 00000000
write 2bb 00000000
write 2bc 00000000
write 2bd 00000000
write 2be 00000000
write 2bf 00000000
write 2c0 00000000
write 2c1 00000000
write 2c2 00000000
write 2c3 00000000
write 2c4 00000000
write 2c5 00000000
write 2c6 00000000
write 2c7 00000000
write 2c8 00000000
write 2c9 00000000
write 2ca 00000000
write 2cb 00000000
write 2cc 00000000
write 2cd 00000000
write 2ce 00000000
write 2cf 00000000
write 2d0 00000000
write 2d1 00000000
write 2d2 00000000
write 2d3 00000000
write 2d4 00000000
write 2d5 00000000
write 2d6 00000000
write 2d7 00000000
write 2d8 00000000
write 2d9 00000000
write 2da 00000000
write 2db 00000000
write 2dc 00000000
write 2dd 00000000
write 2de 00000000
write 2df 00000000
write 2e0 00000000
write 2e1 00000000
write 2e2 00000000
write 2e3 00000000
write 2e4 00000000
write 2e5 00000000
write 2e6 00000000
write 2e7 00000000
write 2e8 00000000
write 2e9 00000000
write 2ea 00000000
write 2eb 00000000
write 2ec 00000000
write 2ed 00000000
write 2ee 00000000
write 2ef 00000000
write 2f0 00000000
write 2f1 00000000
write 2f2 00000000
write 2f3 00000000
write 2f4 00000000
write 2f5 00000000
write 2f6 00000000
write 2f7 00000000
write 2f8 00000000
write 2f9 00000000
write 2fa 00000000
write 2fb 00000000
write 2fc 00000000
write 2fd 00000000
write 2fe 00000000
write 2ff 00000000
write 300 00000000
write 301 00000000
write 302 00000000
write 303 00000000
write 304 00000000
write 305 00000000
write 306 00000000
write 307 00000000
write 308 00000000
write 309 00000000
write 30a 00000000
write 30b 00000000
write 30c 00000000
write 30d 00000000
write 30e 00000000
write 30f 00000000
write 310 00000000
write 311 00000000
write 312 00000000
write 313 00000000
write 314 00000000
write 315 00000000
write 316 00000000
write 317 00000000
write 318 00000000
write 319 00000000
write 31a 00000000
write 31b 00000000
write 31c 00000000
write 31d 00000000
write 31e 00000000
write 31f 00000000
write 320 00000000
write 321 00000000
write 322 00000000
write 323 00000000
write 324 00000000
write 325 00000000
write 326 00000000
write 327 00000000
write 328 00000000
write 329 00000000
write 32a 00000000
write 32b 00000000
write 32c 00000000
write 32d 00000000
write 32e 00000000
write 32f 00000000
write 330 00000000
write 331 00000000
write 332 00000000
write 333 00000000
write 334 00000000
write 335 00000000
write 336 00000000
write 337 00000000
write 338 00000000
write 339 00000000
write 33a 00000000
write 33b 00000000
write 33c 00000000
write 33d 00000000
write 33e 00000000
write 33f 00000000
write 340 00000000
write 341 00000000
write 342 00000000
write 343 00000000
write 344 00000000
write 345 00000000
write 346 00000000
write 347 00000000
write 348 00000000
write 349 00000000
write 34a 00000000
write 34b 00000000
write 34c 00000000
write 34d 00000000
write 34e 00000000
write 34f 00000000
write 350 00000000
write 351 00000000
write 352 00000000
write 353 00000000
write 354 00000000
write 355 00000000
write 356 00000000
write 357 00000000
write 358 00000000
write 359 00000000
write 35a 00000000
write 35b 00000000
write 35c 00000000
write 35d 00000000
write 35e 00000000
write 35f 00000000
write 360 00000000
write 361 00000000
write 362 00000000
write 363 00000000
write 364 00000000
write 365 00000000
write 366 00000000
write 367 00000000
write 368 00000000
write 369 00000000
write 36a 00000000
write 36b 00000000
write 36c 00000000
write 36d 00000000
write 36e 00000000
write 36f 00000000
write 370 00000000
write 371 00000000
write 372 00000000
write 373 00000000
write 374 00000000
write 375 00000000
write 376 00000000
write 377 00000000
write 378 00000000
write 379 00000000
write 37a 00000000
write 37b 00000000
write 37c 00000000
write 37d 00000000
write 37e 00000000
write 37f 00000000
write 380 00000000
write 381 00000000
write 382 00000000
write 383 00000000
write 384 00000000
write 385 00000000
write 386 00000000
write 387 00000000
write 388 00000000
write 389 00000000
write 38a 00000000
write 38b 00000000
write 38c 00000000
write 38d 00000000
write 38e 00000000
write 38f 00000000
write 390 00000000
write 391 00000000
write 392 00000000
write 393 00000000
write 394 00000000
write 395 00000000
write 396 00000000
write 397 00000000
write 398 00000000
write 399 00000000
write 39a 00000000
write 39b 00000000
write 39c 00000000
write 39d 00000000
write 39e 00000000
write 39f 00000000
write 3a0 00000000
write 3a1 00000000
write 3a2 00000000
write 3a3 00000000
write 3a4 00000000
write 3a5 00000000
write 3a6 00000000
write 3a7 00000000
write 3a8 00000000
write 3a9 00000000
write 3aa 00000000
write 3ab 00000000
write 3ac 00000000
write 3ad 00000000
write 3ae 00000000
write 3af 00000000
write 3b0 00000000
write 3b1 00000000
write 3b2 00000000
write 3b3 00000000
write 3b4 00000000
write 3b5 00000000
write 3b6 00000000
write 3b7 00000000
write 3b8 00000000
write 3b9 00000000
write 3ba 00000000
write 3bb 00000000
write 3bc 00000000
write 3bd 00000000
write 3be 00000000
write 3bf 00000000
write 3c0 00000000
write 3c1 00000000
write 3c2 00000000
write 3c3 00000000
write 3c4 00000000
write 3c5 00000000
write 3c6 00000000
write 3c7 00000000
write 3c8 00000000
write 3c9 00000000
write 3ca 00000000
write 3cb 00000000
write 3cc 00000000
write 3cd 00000000
write 3ce 00000000
write 3cf 00000000
write 3d0 00000000
write 3d1 00000000
write 3d2 00000000
write 3d3 00000000
write 3d4 00000000
write 3d5 00000000
write 3d6 00000000
write 3d7 00000000
write 3d8 00000000
write 3d9 00000000
write 3da 00000000
write 3db 00000000
write 3dc 00000000
write 3dd 00000000
write 3de 00000000
write 3df 00000000
write 3e0 00000000
write 3e1 00000000
write 3e2 00000000
write 3e3 00000000
write 3e4 00000000
write 3e5 00000000
write 3e6 00000000
write 3e7 00000000
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"]
//
// White Rabbit Core Hands-On Course
//
// Lesson 04: Simulating the streamers
//
// Objectives:
// - demonstrate packet transfers in WR Core MAC interface
// - demonstrate the user interface of tx_streamer/rx_streamer modules.
// - demonstrate latency measurement feature of the streamers
//
// Brief description:
// A continuous sequence of 64-bit numbers (counting up from 0) is streamed
// via the TX streamer, sent as Ethernet packets over WR MAC interface and decoded
// in the RX streamer module.
//
`include "../../../sim/if_wb_link.svh"
`timescale 1ns/1ns
module main;
// Parameters
// Size of data record to be used by the streamers - in our case, a 64-bit
// word.
parameter g_record_size = 64;
// 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 our streamer frames
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();
// Clock & reset
reg clk = 0;
reg rst = 0;
// TX Streamer signals
reg tx_streamer_dvalid = 0;
reg [g_record_size-1:0] tx_streamer_data = 0;
wire tx_streamer_dreq;
// RX Streamer signals
reg rx_streamer_dreq = 0;
wire [g_record_size-1:0] rx_streamer_data;
wire rx_streamer_dvalid;
wire rx_streamer_lost;
wire [27:0] rx_latency;
wire rx_latency_valid;
// Fake White Rabbit reference clock (125 MHz) and cycle counte (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 = 0;
initial #100 rst = 1;
always #10 clk <= ~clk;
// transfer queue. Used to pass sent data to the verification process.
logic [g_record_size-1:0] queue[$];
always #4ns clk_ref <= ~clk_ref; //generate 125 MHz WR Clock
always@(posedge clk_ref)
tm_cycle_counter <= tm_cycle_counter + 1;
// TX data stream generation.
always@(posedge clk)
if(!rst)
begin
tx_streamer_dvalid <= 0;
tx_counter <= 0;
end else begin
// TX streamer is fed with a subsequent data word at random intervals (you can
// change the probability in the contition below). New value is sent only when
// the streamer can accept it (i.e. its tx_dreq_o output is active)
if({$random} % 100 < 50 && tx_streamer_dreq) begin
queue.push_back(tx_counter);
tx_streamer_data <= tx_counter;
tx_streamer_dvalid <= 1;
tx_counter++;
end else
tx_streamer_dvalid <= 0;
end // if (rst)
// Instantiation of the streamers. The TX streamer will assemble packets
// containing max. 8 records, or flush the buffer after 512 clk cycles if
// it contains less than 8 records to prevent latency buildup.
tx_streamer
#(
.g_data_width (g_record_size),
.g_tx_threshold (8),
.g_tx_timeout (512)
)
U_TX_Streamer
(
.clk_sys_i(clk),
.rst_n_i (rst),
.src_dat_o (mac.dat_i),
.src_adr_o (mac.adr),
.src_sel_o (mac.sel),
.src_cyc_o (mac.cyc),
.src_stb_o (mac.stb),
.src_we_o (mac.we),
.src_stall_i(mac.stall),
.src_err_i (mac.err),
.src_ack_i (mac.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),
.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_record_size)
)
U_RX_Streamer
(
.clk_sys_i (clk),
.rst_n_i (rst),
.snk_dat_i (mac.dat_i),
.snk_adr_i (mac.adr),
.snk_sel_i (mac.sel),
.snk_cyc_i (mac.cyc),
.snk_stb_i (mac.stb),
.snk_we_i (mac.we),
.snk_stall_o (mac.stall),
.snk_ack_o (mac.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_data_o (rx_streamer_data),
.rx_valid_o (rx_streamer_dvalid),
.rx_dreq_i (rx_streamer_dreq),
.rx_latency_o (rx_latency),
.rx_latency_valid_o(rx_latency_valid),
.cfg_mac_local_i (g_mac_rx),
.cfg_mac_remote_i (g_mac_tx),
.cfg_ethertype_i (g_ethertype)
);
// Client-side reception logic. Compares the received records with their copies
// stored in the queue.
always@(posedge clk)
if(!rst)
begin
rx_streamer_dreq <= 0;
end else begin
// throttle the RX path a little bit
rx_streamer_dreq <= {$random}%100 < 80;
if(rx_streamer_dvalid)
begin
// Got a record? Compare it against the copy stored in queue.
automatic logic [g_record_size-1:0] d = queue.pop_front();
$display("Received value: %d", rx_streamer_data);
if(rx_streamer_data != d)
begin
$display("Failure: Got %d, should be: %d\n", rx_streamer_data, d);
$stop;
end
end // if (rx_streamer_dvalid)
end // else: !if(!rst)
// Show the latency value when a new frame arrives
always@(posedge clk)
if(rst && rx_latency_valid)
$display("This frame's latency: %.3f microseconds\n", real'(rx_latency) * 0.008);
endmodule // main
make -f Makefile > /dev/null 2>&1
vsim -L unisim work.main -voptargs="+acc" -suppress 8684,8683
set NumericStdNoWarnings 1
set StdArithNoWarnings 1
do wave.do
run 10us
wave zoomfull
radix -hex
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /main/U_TX_Streamer/clk_sys_i
add wave -noupdate /main/U_TX_Streamer/rst_n_i
add wave -noupdate -divider {TX streamer - User side}
add wave -noupdate /main/U_TX_Streamer/tx_flush_i
add wave -noupdate /main/U_TX_Streamer/tx_last_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 -noupdate -divider Wishbone
add wave -noupdate /main/mac/g_data_width
add wave -noupdate /main/mac/g_addr_width
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 -divider {RX streamer - user side}
add wave -noupdate /main/U_RX_Streamer/rx_first_o
add wave -noupdate /main/U_RX_Streamer/rx_last_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_o
add wave -noupdate /main/U_RX_Streamer/rx_latency_o
add wave -noupdate /main/U_RX_Streamer/rx_latency_valid_o
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {1370 ns} 0}
configure wave -namecolwidth 150
configure wave -valuecolwidth 152
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} {10500 ns}
action= "simulation"
target= "xilinx"
syn_device="xc6slx45t"
sim_tool="modelsim"
top_module="main"
fetchto="../../ip_cores"
vlog_opt="+incdir+../../../sim +incdir"
modules = { "local" : ["../../..",
"../../../modules/wr_streamers",
"../../../top/spec_1_1/wr_streamers_demo",
"../../../ip_cores/general-cores"]}
files = ["main.sv"]
//
// White Rabbit Core Hands-On Course
//
// Lesson 04b: Multiword transfers
//
// Objectives:
// - demonstrate multiword transfers using tx_last, rx_first and rx_last lines.
//
//
`include "../../../sim/if_wb_link.svh"
`timescale 1ns/1ns
module main;
// Parameters
// Size of data record to be used by the streamers - in our case, a 64-bit
// word.
parameter g_word_width = 64;
parameter g_block_size_min = 1;
parameter g_block_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 our streamer frames
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();
// 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;
reg tx_streamer_last = 0;
wire tx_streamer_dreq;
// 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;
wire rx_streamer_first;
wire rx_streamer_last;
wire [27:0] rx_latency;
wire rx_latency_valid;
// 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 = 0;
initial #100 rst_n = 1;
always #10 clk <= ~clk;
typedef struct
{
bit[g_word_width-1:0] data[$];
} block_t;
// transfer queue. Used to pass sent data to the verification process.
block_t queue[$];
always #4ns clk_ref <= ~clk_ref; //generate 125 MHz WR Clock
always@(posedge clk_ref)
tm_cycle_counter <= tm_cycle_counter + 1;
int count = 0;
int seed = 0;
// 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++)
blk.data.push_back(count++);
endtask // generate_block
// 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.data.size());
while(i < blk.data.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.data.size() - 1)) ? 1 : 0;
tx_streamer_data <= blk.data[i];
tx_streamer_dvalid <= 1;
i++;
end else
tx_streamer_dvalid <= 0;
@(posedge clk);
end // while (i < blk.data.size())
tx_streamer_dvalid <= 0;
tx_streamer_last <= 0;
@(posedge clk);
endtask // send_block
// 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 done);
// drive dreq line permanently to 1 to make the testbench a bit clearer
rx_streamer_dreq <= 1;
if(rx_streamer_dvalid)
begin
if(rx_streamer_first)
blk.data = {};
blk.data.push_back(rx_streamer_data);
if(rx_streamer_last)
begin
done = 1;
end
else
done = 0;
end
endtask // receive_block
// TX block stream generation
initial forever begin
block_t blk;
blk.data={};
generate_block(blk);
queue.push_back(blk);
send_block(blk);
end
// Instantiation of the streamers. The TX streamer will assemble packets
// containing max. 8 records, or flush the buffer after 512 clk cycles if
// it contains less than 8 records to prevent latency buildup.
tx_streamer
#(
.g_data_width (g_word_width),
.g_tx_threshold (8),
.g_tx_timeout (128)
)
U_TX_Streamer
(
.clk_sys_i(clk),
.rst_n_i (rst_n),
.src_dat_o (mac.dat_i),
.src_adr_o (mac.adr),
.src_sel_o (mac.sel),
.src_cyc_o (mac.cyc),
.src_stb_o (mac.stb),
.src_we_o (mac.we),
.src_stall_i(mac.stall),
.src_err_i (mac.err),
.src_ack_i (mac.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_i (tx_streamer_last),
.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 (mac.dat_i),
.snk_adr_i (mac.adr),
.snk_sel_i (mac.sel),
.snk_cyc_i (mac.cyc),
.snk_stb_i (mac.stb),
.snk_we_i (mac.we),
.snk_stall_o (mac.stall),
.snk_ack_o (mac.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_data_o (rx_streamer_data),
.rx_valid_o (rx_streamer_dvalid),
.rx_dreq_i (rx_streamer_dreq),
.rx_first_o (rx_streamer_first),
.rx_last_o (rx_streamer_last),
.rx_latency_o (rx_latency),
.rx_latency_valid_o(rx_latency_valid),
.cfg_mac_local_i (g_mac_rx),
.cfg_mac_remote_i (g_mac_tx),
.cfg_ethertype_i (g_ethertype)
);
// Client-side reception logic. Compares the received records with their copies
// stored in the queue.
always@(posedge clk)
if(rst_n)
begin
block_t rblk;
automatic int done = 0;
receive_block(rblk, done);
if(done)
begin
automatic block_t tblk = queue.pop_front();
$display("Received block of %d words.\n", rblk.data.size());
if(tblk.data != rblk.data)
begin
$error("Sent block does not match received block\n");
$stop;
end
end
end // else: !if(!rst_n)
// always@(posedge clk)
// if(rst && rx_latency_valid)
// $display("This frame's latency: %.3f microseconds\n", real'(rx_latency) * 0.008);
endmodule // main
make -f Makefile
vsim -L unisim work.main -voptargs="+acc" -suppress 8684,8683
set NumericStdNoWarnings 1
set StdArithNoWarnings 1
do wave.do
run 10us
wave zoomfull
radix -hex
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /main/U_TX_Streamer/tx_flush_i
add wave -noupdate /main/U_TX_Streamer/tx_last_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 -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_o
add wave -noupdate /main/U_RX_Streamer/rx_last_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_o
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}
files = ["spec_top.vhd", "spec_top.ucf", "spec_reset_gen.vhd","timestamp_adder.vhd" ]
modules = { "local" : ["../../../", "../../../platform/xilinx/chipscope"] }
\ No newline at end of file
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.NUMERIC_STD.all;
use work.gencores_pkg.all;
entity spec_reset_gen is
port (
clk_sys_i : in std_logic;
rst_pcie_n_a_i : in std_logic;
rst_button_n_a_i : in std_logic;
rst_n_o : out std_logic
);
end spec_reset_gen;
architecture behavioral of spec_reset_gen is
signal powerup_cnt : unsigned(7 downto 0) := x"00";
signal button_synced_n : std_logic;
signal pcie_synced_n : std_logic;
signal powerup_n : std_logic := '0';
begin -- behavioral
U_EdgeDet_PCIe : gc_sync_ffs port map (
clk_i => clk_sys_i,
rst_n_i => '1',
data_i => rst_pcie_n_a_i,
ppulse_o => pcie_synced_n);
U_Sync_Button : gc_sync_ffs port map (
clk_i => clk_sys_i,
rst_n_i => '1',
data_i => rst_button_n_a_i,
synced_o => button_synced_n);
p_powerup_reset : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if(powerup_cnt /= x"ff") then
powerup_cnt <= powerup_cnt + 1;
powerup_n <= '0';
else
powerup_n <= '1';
end if;
end if;
end process;
rst_n_o <= powerup_n and button_synced_n and (not pcie_synced_n);
end behavioral;
#####################
# Clocks, buttons, reset
#####################
NET "clk_125m_pllref_n_i" LOC = F10;
NET "clk_125m_pllref_n_i" IOSTANDARD = "LVDS_25";
NET "clk_125m_pllref_p_i" LOC = G9;
NET "clk_125m_pllref_p_i" IOSTANDARD = "LVDS_25";
NET "fpga_pll_ref_clk_101_n_i" LOC = D11;
NET "fpga_pll_ref_clk_101_n_i" IOSTANDARD = "LVDS_25";
NET "fpga_pll_ref_clk_101_p_i" LOC = C11;
NET "fpga_pll_ref_clk_101_p_i" IOSTANDARD = "LVDS_25";
NET "clk_20m_vcxo_i" LOC = H12;
NET "clk_20m_vcxo_i" IOSTANDARD = "LVCMOS25";
NET "l_rst_n" LOC = N20;
NET "l_rst_n" IOSTANDARD = "LVCMOS18";
NET "button1_n_i" LOC = C22;
NET "button1_n_i" IOSTANDARD = "LVCMOS18";
######################
# SFP Pins
######################
NET "sfp_txp_o" LOC= B16;
NET "sfp_txn_o" LOC= A16;
NET "sfp_rxp_i" LOC= D15;
NET "sfp_rxn_i" LOC= C15;
NET "sfp_det_i" LOC = G15;
NET "sfp_det_i" IOSTANDARD = "LVCMOS25";
NET "sfp_scl_b" LOC = C17;
NET "sfp_scl_b" IOSTANDARD = "LVCMOS25";
NET "sfp_sda_b" LOC = G16;
NET "sfp_sda_b" IOSTANDARD = "LVCMOS25";
NET "sfp_rate_select_b" LOC = H14;
NET "sfp_rate_select_b" IOSTANDARD = "LVCMOS25";
NET "sfp_tx_fault_i" LOC = A17;
NET "sfp_tx_fault_i" IOSTANDARD = "LVCMOS25";
NET "sfp_tx_disable_o" LOC = F17;
NET "sfp_tx_disable_o" IOSTANDARD = "LVCMOS25";
NET "sfp_los_i" LOC = D18;
NET "sfp_los_i" IOSTANDARD = "LVCMOS25";
NET "sfp_led_green_o" LOC = E5;
NET "sfp_led_green_o" IOSTANDARD = "LVCMOS25";
NET "sfp_led_red_o" LOC = D5;
NET "sfp_led_red_o" IOSTANDARD = "LVCMOS25";
#################
# Oscillator control
#################
NET "dac_sclk_o" LOC = A4;
NET "dac_sclk_o" IOSTANDARD = "LVCMOS25";
NET "dac_din_o" LOC = C4;
NET "dac_din_o" IOSTANDARD = "LVCMOS25";
NET "dac_cs1_n_o" LOC = A3;
NET "dac_cs1_n_o" IOSTANDARD = "LVCMOS25";
NET "dac_cs2_n_o" LOC = B3;
NET "dac_cs2_n_o" IOSTANDARD = "LVCMOS25";
#################
# Misc pins
#################
NET "fmc_scl_b" LOC = F7;
NET "fmc_scl_b" IOSTANDARD = "LVCMOS25";
NET "fmc_sda_b" LOC = F8;
NET "fmc_sda_b" IOSTANDARD = "LVCMOS25";
NET "thermo_id_b" LOC = D4;
NET "thermo_id_b" IOSTANDARD = "LVCMOS25";
NET "uart_txd_o" LOC= B2;
NET "uart_txd_o" IOSTANDARD=LVCMOS25;
NET "uart_rxd_i" LOC= A2;
NET "uart_rxd_i" IOSTANDARD=LVCMOS25;
########################################################
## Pin definitions for FmcDio5chttl + SPEC v1.1/2.0 ##
########################################################
# DIO outputs
NET "dio_p_o[4]" LOC= T8;
NET "dio_n_o[4]" LOC= U8;
NET "dio_p_o[4]" IOSTANDARD=LVDS_25;
NET "dio_n_o[4]" IOSTANDARD=LVDS_25;
NET "dio_p_o[3]" LOC= U9;
NET "dio_n_o[3]" LOC= V9;
NET "dio_p_o[3]" IOSTANDARD=LVDS_25;
NET "dio_n_o[3]" IOSTANDARD=LVDS_25;
NET "dio_p_o[2]" LOC= R9;
NET "dio_n_o[2]" LOC= R8;
NET "dio_p_o[2]" IOSTANDARD=LVDS_25;
NET "dio_n_o[2]" IOSTANDARD=LVDS_25;
NET "dio_p_o[1]" LOC= Y16;
NET "dio_n_o[1]" LOC= W15;
NET "dio_p_o[1]" IOSTANDARD=LVDS_25;
NET "dio_n_o[1]" IOSTANDARD=LVDS_25;
NET "dio_p_o[0]" LOC= W17;
NET "dio_n_o[0]" LOC= Y18;
NET "dio_p_o[0]" IOSTANDARD=LVDS_25;
NET "dio_n_o[0]" IOSTANDARD=LVDS_25;
# DIO output enable/termination enable
NET "dio_oe_n_o[4]" LOC= AA6;
NET "dio_oe_n_o[3]" LOC= W10;
NET "dio_oe_n_o[2]" LOC= W11;
NET "dio_oe_n_o[1]" LOC= Y14;
NET "dio_oe_n_o[0]" LOC= V17;
NET "dio_oe_n_o[4]" IOSTANDARD=LVCMOS25;
NET "dio_oe_n_o[3]" IOSTANDARD=LVCMOS25;
NET "dio_oe_n_o[2]" IOSTANDARD=LVCMOS25;
NET "dio_oe_n_o[1]" IOSTANDARD=LVCMOS25;
NET "dio_oe_n_o[0]" IOSTANDARD=LVCMOS25;
NET "dio_term_en_o[4]" LOC=AB7;
NET "dio_term_en_o[3]" LOC=Y7;
NET "dio_term_en_o[2]" LOC=AB6;
NET "dio_term_en_o[1]" LOC=AB5;
NET "dio_term_en_o[0]" LOC=W18;
NET "dio_term_en_o[4]" IOSTANDARD=LVCMOS25;
NET "dio_term_en_o[3]" IOSTANDARD=LVCMOS25;
NET "dio_term_en_o[2]" IOSTANDARD=LVCMOS25;
NET "dio_term_en_o[1]" IOSTANDARD=LVCMOS25;
NET "dio_term_en_o[0]" IOSTANDARD=LVCMOS25;
# DIO inputs
NET "dio_p_i[4]" LOC =Y11;
NET "dio_p_i[4]" IOSTANDARD=LVDS_25;
NET "dio_n_i[4]" LOC =AB11;
NET "dio_n_i[4]" IOSTANDARD=LVDS_25;
NET "dio_p_i[3]" LOC =V7;
NET "dio_p_i[3]" IOSTANDARD=LVDS_25;
NET "dio_n_i[3]" LOC =W8;
NET "dio_n_i[3]" IOSTANDARD=LVDS_25;
NET "dio_p_i[2]" LOC =W12;
NET "dio_p_i[2]" IOSTANDARD=LVDS_25;
NET "dio_n_i[2]" LOC =Y12;
NET "dio_n_i[2]" IOSTANDARD=LVDS_25;
NET "dio_p_i[1]" LOC =R11;
NET "dio_p_i[1]" IOSTANDARD=LVDS_25;
NET "dio_n_i[1]" LOC =T11;
NET "dio_n_i[1]" IOSTANDARD=LVDS_25;
NET "dio_p_i[0]" LOC =C19;
NET "dio_p_i[0]" IOSTANDARD=LVDS_25;
NET "dio_n_i[0]" LOC =A19;
NET "dio_n_i[0]" IOSTANDARD=LVDS_25;
NET "dio_led_top_o" LOC= AA12;
NET "dio_led_top_o" IOSTANDARD=LVCMOS25;
NET "dio_led_bot_o" LOC= AB12;
NET "dio_led_bot_o" IOSTANDARD=LVCMOS25;
##Created by Constraints Editor (xc6slx45t-fgg484-3) - 2012/08/07
#ML: INST "U_The_WR_Core/WRPC/U_SOFTPLL/U_Wrapped_Softpll/gen_feedback_dmtds[0].DMTD_FB/clk_in" TNM = skew_limit;
#ML: INST "U_The_WR_Core/WRPC/U_SOFTPLL/U_Wrapped_Softpll/gen_feedback_dmtds[1].DMTD_FB/clk_in" TNM = skew_limit;
#ML: INST "U_The_WR_Core/WRPC/U_SOFTPLL/U_Wrapped_Softpll/gen_ref_dmtds[0].DMTD_REF/clk_in" TNM = skew_limit;
INST "*/U_SOFTPLL/U_Wrapped_Softpll/gen_feedback_dmtds*/clk_in" TNM = skew_limit;
INST "*/U_SOFTPLL/U_Wrapped_Softpll/gen_ref_dmtds*/clk_in" TNM = skew_limit;
TIMESPEC TS_ = FROM "skew_limit" TO "FFS" 1 ns DATAPATHONLY;
#Created by Constraints Editor (xc6slx45t-fgg484-3) - 2012/08/08
INST "U_The_WR_Core/WRPC/U_Endpoint/U_Wrapped_Endpoint/U_PCS_1000BASEX/gen_8bit.U_RX_PCS/timestamp_trigger_p_a_o" TNM = rx_ts_trig;
TIMESPEC TS_RXTS = FROM "rx_ts_trig" TO "FFS" 1 ns DATAPATHONLY;
#Created by Constraints Editor (xc6slx45t-fgg484-3) - 2013/03/14
NET "clk_20m_vcxo_i" TNM_NET = clk_20m_vcxo_i;
TIMESPEC TS_clk_20m_vcxo_i = PERIOD "clk_20m_vcxo_i" 50 ns HIGH 50%;
NET "clk_125m_pllref_p_i" TNM_NET = clk_125m_pllref_p_i;
TIMESPEC TS_clk_125m_pllref_p_i = PERIOD "clk_125m_pllref_p_i" 8 ns HIGH 50%;
NET "fpga_pll_ref_clk_101_n_i" TNM_NET = fpga_pll_ref_clk_101_n_i;
TIMESPEC TS_fpga_pll_ref_clk_101_n_i = PERIOD "fpga_pll_ref_clk_101_n_i" 8 ns HIGH 50%;
NET "clk_125m_pllref_n_i" TNM_NET = clk_125m_pllref_n_i;
TIMESPEC TS_clk_125m_pllref_n_i = PERIOD "clk_125m_pllref_n_i" 8 ns HIGH 50%;
NET "fpga_pll_ref_clk_101_p_i" TNM_NET = fpga_pll_ref_clk_101_p_i;
TIMESPEC TS_fpga_pll_ref_clk_101_p_i = PERIOD "fpga_pll_ref_clk_101_p_i" 8 ns HIGH 50%;
NET "U_GTP/ch1_gtp_clkout_int<1>" TNM_NET = U_GTP/ch1_gtp_clkout_int<1>;
TIMESPEC TS_U_GTP_ch1_gtp_clkout_int_1_ = PERIOD "U_GTP/ch1_gtp_clkout_int<1>" 8 ns HIGH 50%;
--
-- White Rabbit Core Hands-On Course
--
-- Lesson 04a: Trivial streamer demo
--
-- Objectives:
-- - Show how to use streamer cores and WR timing interface.
-- - Measure packet latency
--
-- Brief description:
-- This firmware demonstrates a simple trigger distribution system. A pulse coming
-- to one of the cards is time tagged, the time tag is sent over WR network and
-- used by the receiver to reproduce the pulse with fixed delay.
--
-- DIO Mezzanine connector assignment is:
-- I/O 1 - PPS output
-- I/O 2 - trigger pulse input
-- I/O 3 - recovered pulse output
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- Use library UNISIM for PLL_BASE, IBUFGDS and BUFG simulation components.
library UNISIM;
use UNISIM.vcomponents.all;
-- Use the WR Core package, with xwr_core component defined inside.
use work.wrcore_pkg.all;
-- Use the General Cores package (for gc_extend_pulse)
use work.gencores_pkg.all;
-- Use the Xilinx White Rabbit platform-specific package (for wr_gtp_phy_spartan6)
use work.wr_xilinx_pkg.all;
-- Use the WR Fabric interface package For WR Fabric interface type definitions
use work.wr_fabric_pkg.all;
-- Use the streamers package for streamer component declarations
use work.streamers_pkg.all;
-- -- needed for c_etherbone_sdb
-- use work.etherbone_pkg.all;
-- needed for PIPELINED
use work.wishbone_pkg.all;
entity spec_top is
generic (
-- Simulation mode enable parameter. Set by default (synthesis) to 0, and
-- changed to non-zero in the instantiation of the top level DUT in the testbench.
-- Its purpose is to reduce some internal counters/timeouts to speed up simulations.
g_simulation : integer := 0
);
port (
---------------------------------------------------------------------------
-- Clock signals
---------------------------------------------------------------------------
-- Clock input: 125 MHz LVDS reference clock, coming from the CDCM61004
-- PLL. The reference oscillator is a 25 MHz VCTCXO (VM53S), tunable by the
-- DAC connected to CS0 SPI line (dac_main output of the WR Core).
clk_125m_pllref_p_i : in std_logic;
clk_125m_pllref_n_i : in std_logic;
-- Dedicated clock for the Xilinx GTP transceiver. Same physical clock as
-- clk_125m_pllref, just coming from another output of CDCM61004 PLL.
fpga_pll_ref_clk_101_p_i : in std_logic;
fpga_pll_ref_clk_101_n_i : in std_logic;
-- Clock input, used to derive the DDMTD clock (check out the general presentation
-- of WR for explanation of its purpose). The clock is produced by the
-- other VCXO, tuned by the second AD5662 DAC, (which is connected to
-- dac_helper output of the WR Core)
clk_20m_vcxo_i : in std_logic;
-- Reset input, active low. Comes from the Gennum PCI-Express bridge.
l_rst_n : in std_logic := 'H';
-- Button 1 on the SPEC card. In our case, used as an external reset trigger.
button1_n_i : in std_logic := 'H';
-------------------------------------------------------------------------
-- SFP pins
-------------------------------------------------------------------------
-- TX gigabit output
sfp_txp_o : out std_logic;
sfp_txn_o : out std_logic;
-- RX gigabit input
sfp_rxp_i : in std_logic;
sfp_rxn_i : in std_logic;
-- SFP MOD_DEF0 pin (used as a tied-to-ground SFP insertion detect line)
sfp_det_i : in std_logic;
-- SFP MOD_DEF1 pin (SCL line of the I2C EEPROM inside the SFP)
sfp_scl_b : inout std_logic;
-- SFP MOD_DEF1 pin (SDA line of the I2C EEPROM inside the SFP)
sfp_sda_b : inout std_logic;
-- SFP RATE_SELECT pin. Unused for most SFPs, in our case tied to 0.
sfp_rate_select_b : inout std_logic;
-- SFP laser fault detection pin. Unused in our design.
sfp_tx_fault_i : in std_logic;
-- SFP laser disable line. In our case, tied to GND.
sfp_tx_disable_o : out std_logic;
-- SFP-provided loss-of-link detection. We don't use it as Ethernet PCS
-- has its own loss-of-sync detection mechanism.
sfp_los_i : in std_logic;
-- Green LED next to the SFP: indicates if the link is up.
sfp_led_green_o : out std_logic;
-- Red LED next to the SFP: blinking indicates that packets are being
-- transferred.
sfp_led_red_o : out std_logic;
---------------------------------------------------------------------------
-- Oscillator control pins
---------------------------------------------------------------------------
-- A typical SPI bus shared betwen two AD5662 DACs. The first one (CS1) tunes
-- the clk_ref oscillator, the second (CS2) - the clk_dmtd VCXO.
dac_sclk_o : out std_logic;
dac_din_o : out std_logic;
dac_cs1_n_o : out std_logic;
dac_cs2_n_o : out std_logic;
---------------------------------------------------------------------------
-- Miscellanous WR Core pins
---------------------------------------------------------------------------
-- I2C bus connected to the EEPROM on the DIO mezzanine. This EEPROM is used
-- for storing WR Core's configuration parameters.
fmc_scl_b : inout std_logic;
fmc_sda_b : inout std_logic;
-- One-wire interface to DS18B20 temperature sensor, which also provides an
-- unique serial number, that WRPC uses to assign itself a unique MAC address.
thermo_id_b : inout std_logic;
-- UART pins (connected to the mini-USB port)
uart_txd_o : out std_logic;
uart_rxd_i : in std_logic;
-------------------------------------------------------------------------
-- Necessary Digital I/O mezzanine pins
-------------------------------------------------------------------------
-- Differential inputs, dio_p_i(N) inputs the current state of I/O (N+1) on
-- the mezzanine front panel.
dio_n_i : in std_logic_vector(4 downto 0);
dio_p_i : in std_logic_vector(4 downto 0);
-- Differential outputs. When the I/O (N+1) is configured as output (i.e. when
-- dio_oe_n_o(N) = 0), the value of dio_p_o(N) determines the logic state
-- of I/O (N+1) on the front panel of the mezzanine
dio_n_o : out std_logic_vector(4 downto 0);
dio_p_o : out std_logic_vector(4 downto 0);
-- Output enable. When dio_oe_n_o(N) is 0, connector (N+1) on the front
-- panel is configured as an output.
dio_oe_n_o : out std_logic_vector(4 downto 0);
-- Termination enable. When dio_term_en_o(N) is 1, connector (N+1) on the front
-- panel is 50-ohm terminated
dio_term_en_o : out std_logic_vector(4 downto 0);
-- Two LEDs on the mezzanine panel
dio_led_top_o : out std_logic;
dio_led_bot_o : out std_logic
);
end spec_top;
architecture rtl of spec_top is
-----------------------------------------------------------------------------
-- Constants
-----------------------------------------------------------------------------
-- Ethertype we are going to use for the streamer protocol. Value 0xdbff
-- is default for standard WR Core CPU firmware. Other values need re-configuring
-- the WR Core packet filter.
constant c_STREAMER_ETHERTYPE : std_logic_vector(15 downto 0) := x"dbff";
-- Trigger-to-output value, in 8 ns ticks. Set by default to 20us to work
-- for 10km+ fibers.
constant c_PULSE_DELAY : integer := 30000/8;
-----------------------------------------------------------------------------
-- Component declarations
-----------------------------------------------------------------------------
component spec_reset_gen
port (
clk_sys_i : in std_logic;
rst_pcie_n_a_i : in std_logic;
rst_button_n_a_i : in std_logic;
rst_n_o : out std_logic);
end component;
component pulse_stamper
generic (
g_ref_clk_rate : integer);
port (
clk_ref_i : in std_logic;
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
pulse_a_i : in std_logic;
tm_time_valid_i : in std_logic;
tm_tai_i : in std_logic_vector(39 downto 0);
tm_cycles_i : in std_logic_vector(27 downto 0);
tag_tai_o : out std_logic_vector(39 downto 0);
tag_cycles_o : out std_logic_vector(27 downto 0);
tag_valid_o : out std_logic);
end component;
component pulse_gen
generic (
g_ref_clk_rate : integer);
port (
clk_ref_i : in std_logic;
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
pulse_o : out std_logic;
tm_time_valid_i : in std_logic;
tm_tai_i : in std_logic_vector(39 downto 0);
tm_cycles_i : in std_logic_vector(27 downto 0);
trig_ready_o : out std_logic;
trig_tai_i : in std_logic_vector(39 downto 0);
trig_cycles_i : in std_logic_vector(27 downto 0);
trig_valid_i : in std_logic);
end component;
component timestamp_adder
generic (
g_ref_clk_rate : integer);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
valid_i : in std_logic;
a_tai_i : in std_logic_vector(39 downto 0);
a_cycles_i : in std_logic_vector(27 downto 0);
b_tai_i : in std_logic_vector(39 downto 0);
b_cycles_i : in std_logic_vector(27 downto 0);
valid_o : out std_logic;
q_tai_o : out std_logic_vector(39 downto 0);
q_cycles_o : out std_logic_vector(27 downto 0));
end component;
-----------------------------------------------------------------------------
-- Signals declarations
-----------------------------------------------------------------------------
-- System reset
signal rst_n : std_logic;
-- System clock (62.5 MHz)
signal clk_sys : std_logic;
-- White Rabbit reference clock (125 MHz)
signal clk_ref : std_logic;
-- White Rabbit DDMTD helper clock (62.5-and-something MHz)
signal clk_dmtd : std_logic;
-- 125 MHz GTP clock coming from a dedicated input pin (same as clk_ref)
signal clk_gtp : std_logic;
-- PLL & clock buffer wiring
signal clk_20m_vcxo_buf : std_logic;
signal pllout_clk_sys : std_logic;
signal pllout_clk_fb_pllref : std_logic;
signal pllout_clk_dmtd : std_logic;
signal pllout_clk_fb_dmtd : std_logic;
-- Oscillator control DAC wiring
signal dac_hpll_load_p1 : std_logic;
signal dac_dpll_load_p1 : std_logic;
signal dac_hpll_data : std_logic_vector(15 downto 0);
signal dac_dpll_data : std_logic_vector(15 downto 0);
-- PHY wiring
signal phy_tx_data : std_logic_vector(7 downto 0);
signal phy_tx_k : std_logic_vector(0 downto 0);
signal phy_tx_disparity : std_logic;
signal phy_tx_enc_err : std_logic;
signal phy_rx_data : std_logic_vector(7 downto 0);
signal phy_rx_rbclk : std_logic;
signal phy_rx_k : std_logic_vector(0 downto 0);
signal phy_rx_enc_err : std_logic;
signal phy_rx_bitslide : std_logic_vector(3 downto 0);
signal phy_rst : std_logic;
signal phy_loopen : std_logic;
-- Timing interface
signal tm_time_valid : std_logic;
signal tm_tai : std_logic_vector(39 downto 0);
signal tm_cycles : std_logic_vector(27 downto 0);
-- TX streamer signals
signal tx_tag_tai : std_logic_vector(39 downto 0);
signal tx_tag_cycles : std_logic_vector(27 downto 0);
signal tx_tag_valid : std_logic;
signal tx_data : std_logic_vector(79 downto 0);
signal tx_valid, tx_dreq, tx_dreq_d0 : std_logic;
-- RX streamer signals
signal rx_data : std_logic_vector(79 downto 0);
signal rx_valid : std_logic;
-- Trigger timestamp adjusted with delay
signal adjusted_ts_valid : std_logic;
signal adjusted_ts_tai : std_logic_vector(39 downto 0);
signal adjusted_ts_cycles : std_logic_vector(27 downto 0);
-- Digital I/O mezzanine wiring
signal dio_in : std_logic_vector(4 downto 0);
signal dio_out : std_logic_vector(4 downto 0);
-- Misc signals
signal pps_p, pps_long : std_logic;
signal sfp_scl_out, sfp_sda_out : std_logic;
signal fmc_scl_out, fmc_sda_out : std_logic;
signal owr_enable, owr_in : std_logic_vector(1 downto 0);
signal pulse_out, pulse_in_synced : std_logic;
-- Fabric interface signals, passing packets between the WR Core and the streamers
signal wrcore_snk_out : t_wrf_sink_out;
signal wrcore_snk_in : t_wrf_sink_in;
signal wrcore_src_out : t_wrf_source_out;
signal wrcore_src_in : t_wrf_source_in;
-- ChipScope for histogram readout/debugging
component chipscope_icon
port (
CONTROL0 : inout std_logic_vector(35 downto 0));
end component;
component chipscope_ila
port (
CONTROL : inout std_logic_vector(35 downto 0);
CLK : in std_logic;
TRIG0 : in std_logic_vector(31 downto 0);
TRIG1 : in std_logic_vector(31 downto 0);
TRIG2 : in std_logic_vector(31 downto 0);
TRIG3 : in std_logic_vector(31 downto 0));
end component;
signal control0 : std_logic_vector(35 downto 0);
signal trig0, trig1, trig2, trig3 : std_logic_vector(31 downto 0);
signal rx_latency : std_logic_vector(27 downto 0);
signal rx_latency_valid : std_logic;
begin
-----------------------------------------------------------------------------
-- System/reference clock buffers and PLL
-----------------------------------------------------------------------------
-- Input differential buffer on the 125 MHz reference clock
U_Reference_Clock_Buffer : IBUFGDS
generic map (
DIFF_TERM => true, -- Differential Termination
IBUF_LOW_PWR => true, -- Low power (TRUE) vs. performance (FALSE)
IOSTANDARD => "DEFAULT") -- take the I/O standard from the UCF file
port map (
O => clk_ref, -- Buffer output
I => clk_125m_pllref_p_i, -- Diff_p buffer input (connect directly to top-level port)
IB => clk_125m_pllref_n_i -- Diff_n buffer input (connect directly to top-level port)
);
-- ... and the PLL that derives 62.5 MHz system clock from the 125 MHz reference
U_System_Clock_PLL : PLL_BASE
generic map (
BANDWIDTH => "OPTIMIZED",
CLK_FEEDBACK => "CLKFBOUT",
COMPENSATION => "INTERNAL",
DIVCLK_DIVIDE => 1,
CLKFBOUT_MULT => 8,
CLKFBOUT_PHASE => 0.000,
CLKOUT0_DIVIDE => 16, -- Output 0: 125 MHz * 8 / 16 = 62.5 MHz
CLKOUT0_PHASE => 0.000,
CLKOUT0_DUTY_CYCLE => 0.500,
CLKOUT1_DIVIDE => 16,
CLKOUT1_PHASE => 0.000,
CLKOUT1_DUTY_CYCLE => 0.500,
CLKOUT2_DIVIDE => 16,
CLKOUT2_PHASE => 0.000,
CLKOUT2_DUTY_CYCLE => 0.500,
CLKIN_PERIOD => 8.0,
REF_JITTER => 0.016)
port map (
CLKFBOUT => pllout_clk_fb_pllref,
CLKOUT0 => pllout_clk_sys,
CLKOUT1 => open,
CLKOUT2 => open,
CLKOUT3 => open,
CLKOUT4 => open,
CLKOUT5 => open,
LOCKED => open,
RST => '0',
CLKFBIN => pllout_clk_fb_pllref,
CLKIN => clk_ref);
-- A buffer to drive system clock generated by the PLL above as a global
-- clock net.
U_System_Clock_Buffer : BUFG
port map (
O => clk_sys,
I => pllout_clk_sys);
-----------------------------------------------------------------------------
-- DMTD clock buffers and PLL
-----------------------------------------------------------------------------
-- A global clock buffer to drive the PLL input pin from the 20 MHz VCXO clock
-- input pin on the FPGA
U_DMTD_VCXO_Clock_Buffer : BUFG
port map (
O => clk_20m_vcxo_buf,
I => clk_20m_vcxo_i);
-- The PLL that multiplies the 20 MHz VCXO input to obtain the DDMTD
-- clock, that is sligthly offset in frequency wrs to the reference 125 MHz clock.
-- The WR core additionally requires the DDMTD clock frequency to be divided
-- by 2 (so instead of 125-point-something MHz we get 62.5-point-something
-- MHz). This is to improve internal DDMTD phase detector timing.
U_DMTD_Clock_PLL : PLL_BASE
generic map (
BANDWIDTH => "OPTIMIZED",
CLK_FEEDBACK => "CLKFBOUT",
COMPENSATION => "INTERNAL",
DIVCLK_DIVIDE => 1,
CLKFBOUT_MULT => 50,
CLKFBOUT_PHASE => 0.000,
CLKOUT0_DIVIDE => 16, -- 62.5 MHz
CLKOUT0_PHASE => 0.000,
CLKOUT0_DUTY_CYCLE => 0.500,
CLKOUT1_DIVIDE => 16, -- 62.5 MHz
CLKOUT1_PHASE => 0.000,
CLKOUT1_DUTY_CYCLE => 0.500,
CLKOUT2_DIVIDE => 8,
CLKOUT2_PHASE => 0.000,
CLKOUT2_DUTY_CYCLE => 0.500,
CLKIN_PERIOD => 50.0,
REF_JITTER => 0.016)
port map (
CLKFBOUT => pllout_clk_fb_dmtd,
CLKOUT0 => pllout_clk_dmtd,
CLKOUT1 => open,
CLKOUT2 => open,
CLKOUT3 => open,
CLKOUT4 => open,
CLKOUT5 => open,
LOCKED => open,
RST => '0',
CLKFBIN => pllout_clk_fb_dmtd,
CLKIN => clk_20m_vcxo_buf);
-- A buffer to drive system clock generated by the PLL above as a global
-- clock net.
U_DMTD_Clock_Buffer : BUFG
port map (
O => clk_dmtd,
I => pllout_clk_dmtd);
------------------------------------------------------------------------------
-- Dedicated clock for GTP
------------------------------------------------------------------------------
U_Dedicated_GTP_Clock_Buffer : IBUFGDS
generic map(
DIFF_TERM => true,
IBUF_LOW_PWR => true,
IOSTANDARD => "DEFAULT")
port map (
O => clk_gtp,
I => fpga_pll_ref_clk_101_p_i,
IB => fpga_pll_ref_clk_101_n_i
);
-----------------------------------------------------------------------------
-- Reset signal generator
-----------------------------------------------------------------------------
-- Produces a clean reset signal upon the following
-- conditions:
-- - device is powered up
-- - a PCI-Express bus reset is requested
-- - button 1 is pressed.
U_Reset_Gen : spec_reset_gen
port map (
clk_sys_i => clk_sys,
rst_pcie_n_a_i => L_RST_N,
rst_button_n_a_i => button1_n_i,
rst_n_o => rst_n);
-----------------------------------------------------------------------------
-- The WR Core part. The simplest functional instantiation.
-----------------------------------------------------------------------------
U_The_WR_Core : xwr_core
generic map (
g_simulation => 0,
g_with_external_clock_input => true,
--
g_phys_uart => true,
g_virtual_uart => true,
g_aux_clks => 0,
g_ep_rxbuf_size => 1024,
g_tx_runt_padding => true,
g_pcs_16bit => false,
g_dpram_initf => "wrc.ram",
-- g_aux_sdb => c_etherbone_sdb, --ML
g_dpram_size => 131072/4,
g_interface_mode => PIPELINED,
g_address_granularity => BYTE)
port map (
-- Clocks & resets connections
clk_sys_i => clk_sys,
clk_ref_i => clk_ref,
clk_dmtd_i => clk_dmtd,
rst_n_i => rst_n,
-- Fabric interface pins
wrf_snk_i => wrcore_snk_in,
wrf_snk_o => wrcore_snk_out,
wrf_src_i => wrcore_src_in,
wrf_src_o => wrcore_src_out,
-- Timing interface pins
tm_time_valid_o => tm_time_valid,
tm_tai_o => tm_tai,
tm_cycles_o => tm_cycles,
-- PHY connections
phy_ref_clk_i => clk_ref,
phy_tx_data_o => phy_tx_data,
phy_tx_k_o => phy_tx_k,
phy_tx_disparity_i => phy_tx_disparity,
phy_tx_enc_err_i => phy_tx_enc_err,
phy_rx_data_i => phy_rx_data,
phy_rx_rbclk_i => phy_rx_rbclk,
phy_rx_k_i => phy_rx_k,
phy_rx_enc_err_i => phy_rx_enc_err,
phy_rx_bitslide_i => phy_rx_bitslide,
phy_rst_o => phy_rst,
phy_loopen_o => phy_loopen,
-- Oscillator control DACs connections
dac_hpll_load_p1_o => dac_hpll_load_p1,
dac_hpll_data_o => dac_hpll_data,
dac_dpll_load_p1_o => dac_dpll_load_p1,
dac_dpll_data_o => dac_dpll_data,
-- Miscellanous pins
uart_rxd_i => uart_rxd_i,
uart_txd_o => uart_txd_o,
scl_o => fmc_scl_out,
scl_i => fmc_scl_b,
sda_o => fmc_sda_out,
sda_i => fmc_sda_b,
sfp_scl_o => sfp_scl_out,
sfp_scl_i => sfp_scl_b,
sfp_sda_o => sfp_sda_out,
sfp_sda_i => sfp_sda_b,
sfp_det_i => sfp_det_i,
led_link_o => sfp_led_green_o,
led_act_o => sfp_led_red_o,
owr_en_o => owr_enable,
owr_i => owr_in,
-- The PPS output, which we'll drive to the DIO mezzanine channel 1.
pps_p_o => pps_p
);
-----------------------------------------------------------------------------
-- Dual channel SPI DAC driver
-----------------------------------------------------------------------------
U_DAC_ARB : spec_serial_dac_arb
generic map (
g_invert_sclk => false, -- configured for 2xAD5662. Don't
-- change the parameters.
g_num_extra_bits => 8)
port map (
clk_i => clk_sys,
rst_n_i => rst_n,
-- DAC 1 controls the main (clk_ref) oscillator
val1_i => dac_dpll_data,
load1_i => dac_dpll_load_p1,
-- DAC 2 controls the helper (clk_ddmtd) oscillator
val2_i => dac_hpll_data,
load2_i => dac_hpll_load_p1,
dac_cs_n_o(0) => dac_cs1_n_o,
dac_cs_n_o(1) => dac_cs2_n_o,
dac_sclk_o => dac_sclk_o,
dac_din_o => dac_din_o);
-----------------------------------------------------------------------------
-- Gigabit Ethernet PHY using Spartan-6 GTP transceviver.
-----------------------------------------------------------------------------
U_GTP : wr_gtp_phy_spartan6
generic map (
g_enable_ch0 => 0,
-- each GTP has two channels, so does the PHY module.
-- The SFP on the SPEC is connected to the 2nd channel.
g_enable_ch1 => 1,
g_simulation => g_simulation)
port map (
gtp_clk_i => clk_gtp,
ch1_ref_clk_i => clk_ref,
-- TX code stream
ch1_tx_data_i => phy_tx_data,
-- TX control/data select
ch1_tx_k_i => phy_tx_k(0),
-- TX disparity of the previous symbol
ch1_tx_disparity_o => phy_tx_disparity,
-- TX encoding error
ch1_tx_enc_err_o => phy_tx_enc_err,
-- RX recovered byte clock
ch1_rx_rbclk_o => phy_rx_rbclk,
-- RX data stream
ch1_rx_data_o => phy_rx_data,
-- RX control/data select
ch1_rx_k_o => phy_rx_k(0),
-- RX encoding error detection
ch1_rx_enc_err_o => phy_rx_enc_err,
-- RX path comma alignment bit slide delay (crucial for accuracy!)
ch1_rx_bitslide_o => phy_rx_bitslide,
-- Channel reset
ch1_rst_i => phy_rst,
-- Loopback mode enable
ch1_loopen_i => phy_loopen,
pad_txn1_o => sfp_txn_o,
pad_txp1_o => sfp_txp_o,
pad_rxn1_i => sfp_rxn_i,
pad_rxp1_i => sfp_rxp_i);
-- pps_p signal from the WR core is 8ns- (single clk_ref cycle) wide. This is
-- too short to drive outputs such as LEDs. Let's extend its length to some
-- human-noticeable value
U_Extend_PPS : gc_extend_pulse
generic map (
g_width => 10000000) -- output length: 10000000x8ns = 80 ms.
port map (
clk_i => clk_ref,
rst_n_i => rst_n,
pulse_i => pps_p,
extended_o => pps_long);
-----------------------------------------------------------------------------
-- Trigger distribution stuff - timestamping & packet transmission part
-----------------------------------------------------------------------------
U_Pulse_Stamper : pulse_stamper
generic map (
g_ref_clk_rate => 125000000)
port map (
clk_ref_i => clk_ref,
clk_sys_i => clk_sys,
rst_n_i => rst_n,
pulse_a_i => dio_in(1), -- I/O 2 = our pulse input
tm_time_valid_i => tm_time_valid, -- timing ports of the WR Core
tm_tai_i => tm_tai,
tm_cycles_i => tm_cycles,
tag_tai_o => tx_tag_tai, -- time tag of the latest pulse
tag_cycles_o => tx_tag_cycles,
tag_valid_o => tx_tag_valid);
-- Streamer instantiation.
U_TX_Streamer : xtx_streamer
generic map (
-- We send each timestamp (40 TAI bits + 28
-- cycle bits) as a single parallel data word of 68 bits. Since data width
-- must be a multiple of 16 bits, we round it up to 80 bits).
g_data_width => 80,
-- TX threshold = 4 data words. (it's anyway ignored because of
-- g_tx_timeout setting below)
g_tx_threshold => 4,
-- minimum timeout: sends packets asap to minimize latency (but it's not
-- good for large amounts of data due to encapsulation overhead)
g_tx_timeout => 1)
port map (
clk_sys_i => clk_sys,
rst_n_i => rst_n,
-- Wire the packet source of the streamer to the packet sink of the WR Core
src_i => wrcore_snk_out,
src_o => wrcore_snk_in,
clk_ref_i => clk_ref,
tm_time_valid_i => tm_time_valid,
tm_tai_i => tm_tai,
tm_cycles_i => tm_cycles,
tx_data_i => tx_data,
tx_valid_i => tx_valid,
tx_dreq_o => tx_dreq,
-- every data word we send is the last one, as a single transfer in our
-- case contains only one 80-bit data word.
tx_last_i => '1',
-- send broadcast packets, so that many receivers can use triggers sent
-- by us.
cfg_mac_target_i => x"ffffffffffff",
cfg_ethertype_i => c_STREAMER_ETHERTYPE);
-- Pack the time stamp into a 80-bit data word for the streamer
tx_data(27 downto 0) <= tx_tag_cycles;
tx_data(32 + 39 downto 32) <= tx_tag_tai;
-- avoid Xes (this may break simulations)
tx_data(31 downto 28) <= (others => '0');
tx_data(79 downto 32+40) <= (others => '0');
-- Data valid signal: simply drop the timestamp if the streamer can't accept
-- data for the moment.
tx_valid <= tx_dreq_d0 and tx_tag_valid;
-- tx_dreq_o output of the streamer is asserted one clock cycle in advance,
-- while the line above drives the valid signal combinatorially. We need a delay.
process(clk_sys)
begin
if rising_edge(clk_sys) then
tx_dreq_d0 <= tx_dreq;
end if;
end process;
-----------------------------------------------------------------------------
-- Trigger distribution stuff - packet reception and pulse generation
-----------------------------------------------------------------------------
-- Streamer instantiation
U_RX_Streamer : xrx_streamer
generic map (
-- data width must be identical as in the TX streamer - otherwise, we'll be receiving
-- rubbish
g_data_width => 80,
-- we don't care where our triggers come from. Just blindly accept them all
-- without checking source addresses.
g_filter_remote_mac => false)
port map (
clk_sys_i => clk_sys,
rst_n_i => rst_n,
-- Wire the packet sink of the streamer to the packet source of the WR Core
snk_i => wrcore_src_out,
snk_o => wrcore_src_in,
clk_ref_i => clk_ref,
tm_time_valid_i => tm_time_valid,
tm_tai_i => tm_tai,
tm_cycles_i => tm_cycles,
rx_data_o => rx_data,
rx_valid_o => rx_valid,
rx_dreq_i => '1',
rx_latency_o => rx_latency,
rx_latency_valid_o => rx_latency_valid,
cfg_ethertype_i => c_STREAMER_ETHERTYPE,
cfg_accept_broadcasts_i => '1');
-- Add a fixed delay to the reveived trigger timestamp
U_Add_Delay1 : timestamp_adder
generic map (
g_ref_clk_rate => 125000000)
port map (
clk_i => clk_sys,
rst_n_i => rst_n,
valid_i => rx_valid,
a_tai_i => rx_data(32 + 39 downto 32),
a_cycles_i => rx_data(27 downto 0),
b_tai_i => (others => '0'),
b_cycles_i => std_logic_vector(to_unsigned(c_PULSE_DELAY, 28)),
valid_o => adjusted_ts_valid,
q_tai_o => adjusted_ts_tai,
q_cycles_o => adjusted_ts_cycles);
-- And a pulse generator that produces a pulse at a time received by the
-- streamer above adjusted with the delay
U_Pulse_Generator : pulse_gen
generic map (
g_ref_clk_rate => 125000000)
port map (
clk_ref_i => clk_ref,
clk_sys_i => clk_sys,
rst_n_i => rst_n,
pulse_o => pulse_out,
tm_time_valid_i => tm_time_valid,
tm_tai_i => tm_tai,
tm_cycles_i => tm_cycles,
trig_tai_i => adjusted_ts_tai,
trig_cycles_i => adjusted_ts_cycles,
trig_valid_i => adjusted_ts_valid);
-- pulse_gen above generates pulses that are single-cycle long. This is too
-- short to observe on a scope, particularly with slower time base (to see 2
-- pulses simulatenously). Let's extend it a bit:
U_Extend_Output_Pulse : gc_extend_pulse
generic map (
-- 1000 * 8ns = 8 us
g_width => 1000)
port map (
clk_i => clk_ref,
rst_n_i => rst_n,
pulse_i => pulse_out,
extended_o => dio_out(2));
-----------------------------------------------------------------------------
-- Differential buffers for the Digital I/O Mezzanine
-----------------------------------------------------------------------------
gen_dio_iobufs : for i in 0 to 4 generate
U_Input_Buffer : IBUFDS
generic map (
DIFF_TERM => true)
port map (
O => dio_in(i),
I => dio_p_i(i),
IB => dio_n_i(i)
);
U_Output_Buffer : OBUFDS
port map (
I => dio_out(i),
O => dio_p_o(i),
OB => dio_n_o(i)
);
end generate gen_dio_iobufs;
-----------------------------------------------------------------------------
-- Combinatorial pins, tristate buffers, etc.
-----------------------------------------------------------------------------
-- The SFP is permanently enabled
sfp_tx_disable_o <= '0';
sfp_rate_select_b <= '0';
-- Open-drain driver for the Onewire bus
thermo_id_b <= '0' when owr_enable(0) = '1' else 'Z';
owr_in(0) <= thermo_id_b;
-- Open-drain drivers for the I2C busses
fmc_scl_b <= '0' when fmc_scl_out = '0' else 'Z';
fmc_sda_b <= '0' when fmc_sda_out = '0' else 'Z';
sfp_scl_b <= '0' when sfp_scl_out = '0' else 'Z';
sfp_sda_b <= '0' when sfp_sda_out = '0' else 'Z';
-- Connect the PPS output to the I/O 1 of the Digital I/O mezzanine
dio_out(0) <= pps_long;
-- Drive unused DIO outputs to 0.
dio_out(4) <= dio_out(2);
dio_out(3) <= dio_out(2);
dio_out(1) <= '0';
-- all DIO connectors except I/O 2 (trigger input) are outputs
dio_oe_n_o(0) <= '0';
dio_oe_n_o(1) <= '1';
dio_oe_n_o(4 downto 2) <= (others => '0');
-- terminate only the trigger input
dio_oe_n_o(0) <= '0';
dio_oe_n_o(1) <= '1';
dio_oe_n_o(4 downto 2) <= (others => '0');
dio_term_en_o(1) <= '1';
dio_term_en_o(0) <= '0';
dio_term_en_o(4 downto 2) <= (others => '0');
-- Drive one of the LEDs on the mezzanine with out PPS signal (pps_led is a
-- longer version that can be used to directly drive a LED)
dio_led_top_o <= pps_long;
-- The other LED on the DIO serves as an indicator of incoming trigger pulses.
U_Sync_Trigger_Pulse : gc_sync_ffs
port map (
clk_i => clk_ref,
rst_n_i => rst_n,
data_i => dio_in(1),
synced_o => pulse_in_synced);
U_Extend_Trigger_Pulse : gc_extend_pulse
generic map (
-- 1000 * 8ns = 8 us
g_width => 1000)
port map (
clk_i => clk_ref,
rst_n_i => rst_n,
pulse_i => pulse_in_synced,
extended_o => dio_led_bot_o);
CS_ICON : chipscope_icon
port map (
CONTROL0 => CONTROL0);
CS_ILA : chipscope_ila
port map (
CONTROL => CONTROL0,
CLK => clk_sys,
TRIG0 => TRIG0,
TRIG1 => TRIG1,
TRIG2 => TRIG2,
TRIG3 => TRIG3);
trig0(27 downto 0) <= rx_latency;
trig0(31) <= rx_latency_valid;
trig1(31) <= tm_time_valid;
trig1(27 downto 0) <= tm_cycles;
trig1(30 downto 28) <= tm_tai(2 downto 0);
trig2(31) <= adjusted_ts_valid;
trig2(27 downto 0) <= adjusted_ts_cycles;
trig2(30 downto 28) <= adjusted_ts_tai(2 downto 0);
trig3(31) <= rx_valid;
trig3(27 downto 0) <= rx_data(27 downto 0);
trig3(30 downto 28) <= rx_data(32 + 2 downto 32);
end rtl;
-------------------------------------------------------------------------------
-- Title : Pipelined timestamp adder with normalization
-- Project : Fine Delay Core (FmcDelay1ns4cha)
-------------------------------------------------------------------------------
-- File : fd_ts_adder.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN
-- Created : 2011-08-29
-- Last update: 2013-03-13
-- Platform : FPGA-generic
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: Pipelined timestamp adder with re-normalization of the result.
-- Adds a to b, producing normalized timestamp q. A timestmap is normalized when
-- the 0 <= frac < 2**g_frac_bits, 0 <= coarse <= g_coarse_range-1 and utc >= 0.
-- For correct operation of renormalizer, input timestamps must meet the
-- following constraints:
-- 1. 0 <= (a/b)_frac_i <= 2**g_frac_bits-1
-- 2. -g_coarse_range+1 <= (a_coarse_i + b_coarse_i) <= 3*g_coarse_range-1
-------------------------------------------------------------------------------
--
-- Copyright (c) 2011 CERN / BE-CO-HT
-- 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
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2011-08-29 1.0 twlostow Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity timestamp_adder is
generic
(
-- sizes of the respective bitfields of the input/output timestamps
g_frac_bits : integer := 12;
g_cycles_bits : integer := 28;
g_tai_bits : integer := 40;
-- upper bound of the coarse part
g_ref_clk_rate: integer := 125000000
);
port(
clk_i : in std_logic;
rst_n_i : in std_logic;
valid_i : in std_logic; -- when HI, a_* and b_* contain valid timestamps
enable_i : in std_logic := '1'; -- pipeline enable
-- Input timestamps
a_tai_i : in std_logic_vector(g_tai_bits-1 downto 0);
a_cycles_i : in std_logic_vector(g_cycles_bits-1 downto 0);
a_frac_i : in std_logic_vector(g_frac_bits-1 downto 0) := (others => '0');
b_tai_i : in std_logic_vector(g_tai_bits-1 downto 0);
b_cycles_i : in std_logic_vector(g_cycles_bits-1 downto 0);
b_frac_i : in std_logic_vector(g_frac_bits-1 downto 0) := (others => '0');
-- Normalized sum output (valid when valid_o == 1)
valid_o : out std_logic;
q_tai_o : out std_logic_vector(g_tai_bits-1 downto 0);
q_cycles_o : out std_logic_vector(g_cycles_bits-1 downto 0);
q_frac_o : out std_logic_vector(g_frac_bits-1 downto 0)
);
end timestamp_adder;
architecture rtl of timestamp_adder is
constant c_NUM_PIPELINE_STAGES : integer := 4;
type t_internal_sum is record
utc : signed(g_tai_bits-1 downto 0);
coarse : signed(g_cycles_bits+1 downto 0);
frac : signed(g_frac_bits+1 downto 0);
end record;
type t_internal_sum_array is array (integer range <>) of t_internal_sum;
signal pipe : std_logic_vector(c_NUM_PIPELINE_STAGES-1 downto 0);
signal sums : t_internal_sum_array(0 to c_NUM_PIPELINE_STAGES-1);
signal ovf_frac : std_logic;
signal ovf_coarse : std_logic_vector(1 downto 0);
signal unf_coarse : std_logic;
begin -- rtl
-- Pipeline stage 0: just add the two timestamps field by field
p_stage0 : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
pipe(0) <= '0';
elsif(enable_i = '1') then
pipe(0) <= valid_i;
sums(0).frac <= signed("00" & a_frac_i) + signed("00" & b_frac_i);
sums(0).coarse <= resize(signed(a_cycles_i), sums(0).coarse'length) +
resize(signed(b_cycles_i), sums(0).coarse'length);
sums(0).utc <= signed(a_tai_i) + signed(b_tai_i);
else
pipe(0) <= '0';
end if;
end if;
end process;
ovf_frac <= std_logic(sums(0).frac(g_frac_bits));
-- Pipeline stage 1: check the fractional sum for overflow and eventually adjust
-- the coarse sum
p_stage1 : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
pipe(1) <= '0';
else
pipe(1) <= pipe(0);
if(ovf_frac = '1') then
sums(1).frac <= sums(0).frac - 2**g_frac_bits;
sums(1).coarse <= sums(0).coarse + 1;
else
sums(1).frac <= sums(0).frac;
sums(1).coarse <= sums(0).coarse;
end if;
sums(1).utc <= sums(0).utc;
end if;
end if;
end process;
-- Pipeline stage 2: check the coarse sum for under/overflows
p_stage2 : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
pipe(2) <= '0';
else
sums(2) <= sums(1);
pipe(2) <= pipe(1);
if(sums(1).coarse < 0) then
unf_coarse <= '1';
ovf_coarse <= "00";
elsif(sums(1).coarse >= 2 * g_ref_clk_rate) then
ovf_coarse <= "10";
unf_coarse <= '0';
elsif(sums(1).coarse >= g_ref_clk_rate) then
ovf_coarse <= "01";
unf_coarse <= '0';
else
ovf_coarse <= "00";
unf_coarse <= '0';
end if;
end if;
end if;
end process;
-- Pipeline stage 3: adjust the coarse & UTC sums according to normalize the
-- previously detected under/overflows
p_stage3 : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
pipe(3) <= '0';
else
pipe(3) <= pipe(2);
if(unf_coarse = '1') then
sums(3).coarse <= sums(2).coarse + g_ref_clk_rate;
sums(3).utc <= sums(2).utc - 1;
elsif(ovf_coarse = "10") then
sums(3).coarse <= sums(2).coarse - (2*g_ref_clk_rate);
sums(3).utc <= sums(2).utc + 2;
elsif(ovf_coarse = "01") then
sums(3).coarse <= sums(2).coarse - g_ref_clk_rate;
sums(3).utc <= sums(2).utc + 1;
else
sums(3).coarse <= sums(2).coarse;
sums(3).utc <= sums(2).utc;
end if;
sums(3).frac <= sums(2).frac;
end if;
end if;
end process;
-- clip the extra bits and output the result
valid_o <= pipe(c_NUM_PIPELINE_STAGES-1);
q_tai_o <= std_logic_vector(sums(c_NUM_PIPELINE_STAGES-1).utc(g_tai_bits-1 downto 0));
q_cycles_o <= std_logic_vector(sums(c_NUM_PIPELINE_STAGES-1).coarse(g_cycles_bits-1 downto 0));
q_frac_o <= std_logic_vector(sums(c_NUM_PIPELINE_STAGES-1).frac(g_frac_bits-1 downto 0));
end rtl;
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