Commit d116d6b1 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

wr_streamers: async data path option for Tx streamer [wip]

parent 1254a4f7
...@@ -12,5 +12,9 @@ files = ["streamers_pkg.vhd", ...@@ -12,5 +12,9 @@ files = ["streamers_pkg.vhd",
"wr_streamers_wb.vhd", "wr_streamers_wb.vhd",
"streamers_priv_pkg.vhd", "streamers_priv_pkg.vhd",
"xtx_streamers_stats.vhd", "xtx_streamers_stats.vhd",
"xrx_streamers_stats.vhd" "xrx_streamers_stats.vhd",
] "gc_async_counter_diff.vhd",
"fixed_latency_delay.vhd",
"fixed_latency_ts_match.vhd",
"fifo_showahead_adapter.vhd"
];
File mode changed from 100755 to 100644
library ieee;
use ieee.std_logic_1164.all;
entity fifo_showahead_adapter is
generic (
g_width : integer);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
fifo_q_i : in std_logic_vector(g_width-1 downto 0);
fifo_empty_i : in std_logic;
fifo_rd_o : out std_logic;
q_o : out std_logic_vector(g_width-1 downto 0);
valid_o : out std_logic;
rd_i : in std_logic
);
end fifo_showahead_adapter;
architecture rtl of fifo_showahead_adapter is
signal rd, rd_d : std_logic;
signal valid_int : std_logic;
begin
process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
rd_d <= '0';
valid_int <= '0';
else
rd_d <= rd;
if rd = '1' then
valid_int <= '1';
elsif rd_i = '1' then
valid_int <= not fifo_empty_i;
end if;
end if;
end if;
end process;
rd <= not fifo_empty_i when valid_int = '0' else rd_i and not fifo_empty_i;
q_o <= fifo_q_i;
fifo_rd_o <= rd;
valid_o <= valid_int;
end rtl;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.gencores_pkg.all;
use work.genram_pkg.all;
use work.streamers_priv_pkg.all;
use work.streamers_pkg.all;
entity fixed_latency_delay is
generic(
g_data_width : integer;
g_buffer_size : integer;
g_use_ref_clock_for_data : integer;
g_clk_ref_rate : integer
);
port(
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
clk_ref_i : in std_logic;
-- timing I/F, clk_ref_i clock domain
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);
-- input i/f (dropping buffer)
d_data_i : in std_logic_vector(g_data_width-1 downto 0);
d_last_i : in std_logic;
d_sync_i : in std_logic;
d_target_ts_en_i : in std_logic;
d_target_ts_i : in std_logic_vector(27 downto 0);
d_valid_i : in std_logic;
d_drop_i : in std_logic;
d_accept_i : in std_logic;
d_req_o : out std_logic;
-- output data path (clk_ref_i/clk_sys_i clock domain for
-- g_use_ref_clock_for_data = 1/0 respectively)
rx_first_p1_o : out std_logic;
rx_last_p1_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_streamer_cfg_i : in t_rx_streamer_cfg
);
end entity;
architecture rtl of fixed_latency_delay is
type t_state is (IDLE, WAIT_TS_MATCH, SEND);
signal State: t_state;
signal clk_data : std_logic;
signal rst_n_data : std_logic;
signal rst_n_ref : std_logic;
signal wr_full : std_logic;
constant c_datapath_width : integer := g_data_width + 2 + 28 + 1;
signal fifo_rd : std_logic;
signal dbuf_d : std_logic_vector(c_datapath_width-1 downto 0);
signal dbuf_q : std_logic_vector(c_datapath_width-1 downto 0);
signal fifo_d : std_logic_vector(c_datapath_width-1 downto 0);
signal fifo_q : std_logic_vector(c_datapath_width-1 downto 0);
signal dbuf_q_valid : std_logic;
signal dbuf_req : std_logic;
signal fifo_q_int : std_logic_vector(c_datapath_width-1 downto 0);
signal fifo_rd_int, fifo_empty_int, fifo_q_valid : std_logic;
signal fifo_data : std_logic_vector(g_data_width-1 downto 0);
signal fifo_sync, fifo_last, fifo_target_ts_en : std_logic;
signal fifo_target_ts : std_logic_vector(27 downto 0);
signal fifo_we : std_logic;
signal delay_arm : std_logic;
signal delay_match : std_logic;
signal delay_miss : std_logic;
begin
U_SyncReset_to_RefClk : gc_sync_ffs
port map (
clk_i => clk_ref_i,
rst_n_i => '1',
data_i => rst_n_i,
synced_o => rst_n_ref);
clk_data <= clk_sys_i when g_use_ref_clock_for_data = 0 else clk_ref_i;
rst_n_data <= rst_n_i when g_use_ref_clock_for_data = 0 else rst_n_ref;
dbuf_d(g_data_width-1 downto 0) <= d_data_i;
dbuf_d(g_data_width) <= d_last_i;
dbuf_d(g_data_width+1) <= d_sync_i;
dbuf_d(g_data_width+2) <= d_target_ts_en_i;
dbuf_d(g_data_width+3+27 downto g_data_width+3) <= d_target_ts_i;
U_DropBuffer : entity work.dropping_buffer
generic map (
g_size => g_buffer_size,
g_data_width => c_datapath_width)
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_i,
d_i => dbuf_d,
d_req_o => d_req_o,
d_drop_i => d_drop_i,
d_accept_i => d_accept_i,
d_valid_i => d_valid_i,
d_o => dbuf_q,
d_valid_o => dbuf_q_valid,
d_req_i => dbuf_req);
dbuf_req <= not wr_full;
fifo_we <= dbuf_q_valid and not wr_full;
U_ClockSyncFifo : generic_async_fifo
generic map (
g_data_width => c_datapath_width,
g_size => 16,
g_show_ahead => false)
port map (
rst_n_i => rst_n_i,
clk_wr_i => clk_sys_i,
d_i => dbuf_q,
we_i => dbuf_q_valid,
wr_full_o => wr_full,
clk_rd_i => clk_data,
q_o => fifo_q_int,
rd_i => fifo_rd_int,
rd_empty_o => fifo_empty_int);
U_ShowaheadForFIFO : entity work.fifo_showahead_adapter
generic map (
g_width => c_datapath_width)
port map (
clk_i => clk_data,
rst_n_i => rst_n_data,
fifo_q_i => fifo_q_int,
fifo_empty_i => fifo_empty_int,
fifo_rd_o => fifo_rd_int,
q_o => fifo_q,
valid_o => fifo_q_valid,
rd_i => fifo_rd);
process(clk_data)
begin
if rising_edge(clk_data) then
if rst_n_data = '0' then
state <= IDLE;
else
case state is
when IDLE =>
if fifo_q_valid = '1' then
if fifo_target_ts_en = '1' then
state <= WAIT_TS_MATCH;
else
state <= SEND;
end if;
end if;
when WAIT_TS_MATCH =>
if delay_miss = '1' then
state <= IDLE;
elsif delay_match = '1' then
state <= SEND;
end if;
when SEND =>
if fifo_last = '1' then
state <= IDLE;
end if;
end case;
end if;
end if;
end process;
U_Compare: entity work.fixed_latency_ts_match
generic map (
g_clk_ref_rate => g_clk_ref_rate)
port map (
clk_i => clk_ref_i,
rst_n_i => rst_n_ref,
arm_i => delay_arm,
ts_origin_i => fifo_target_ts,
ts_latency_i => rx_streamer_cfg_i.fixed_latency,
tm_time_valid_i => tm_time_valid_i,
tm_tai_i => tm_tai_i,
tm_cycles_i => tm_cycles_i,
match_o => delay_match,
miss_o => delay_miss);
process(state, rx_dreq_i, delay_match, fifo_target_ts_en, fifo_q_valid)
begin
case state is
when IDLE =>
fifo_rd <= fifo_q_valid and rx_dreq_i and not fifo_target_ts_en;
delay_arm <= fifo_q_valid and fifo_target_ts_en;
rx_valid_o <= fifo_q_valid and not fifo_target_ts_en;
rx_first_p1_o <= fifo_sync and not fifo_target_ts_en;
rx_last_p1_o <= fifo_last and not fifo_target_ts_en;
when WAIT_TS_MATCH =>
fifo_rd <= '0';
delay_arm <= '0';
rx_valid_o <= '0';
rx_first_p1_o <= '0';
rx_last_p1_o <= '0';
when SEND =>
fifo_rd <= rx_dreq_i;
delay_arm <= '0';
rx_first_p1_o <= fifo_sync;
rx_last_p1_o <= fifo_last;
rx_valid_o <= fifo_q_valid;
end case;
end process;
fifo_data <= fifo_q(g_data_width-1 downto 0);
fifo_last <= fifo_q(g_data_width);
fifo_sync <= fifo_q(g_data_width+1);
fifo_target_ts_en <= fifo_q(g_data_width+2);
fifo_target_ts <= fifo_q(g_data_width + 3 + 27 downto g_data_width + 3);
rx_data_o <= fifo_data;
end rtl;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity fixed_latency_ts_match is
generic
(g_clk_ref_rate : integer);
port
(
clk_i : in std_logic;
rst_n_i : in std_logic;
arm_i : in std_logic;
ts_origin_i : in std_logic_vector(27 downto 0);
ts_latency_i : in std_logic_vector(27 downto 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";
match_o : out std_logic;
miss_o : out std_logic
);
end entity;
architecture rtl of fixed_latency_ts_match is
constant c_unwrap_threshold : integer := 62500000;
signal ts_adjusted : unsigned(28 downto 0);
signal target_cycles : unsigned(28 downto 0);
signal delta : signed(28 downto 0);
signal arm_d : std_logic_vector(2 downto 0);
signal armed : std_logic;
signal tm_cycles_scaled : unsigned(28 downto 0);
begin
process(tm_cycles_i)
begin
if g_clk_ref_rate = 62500000 then
tm_cycles_scaled <= unsigned(tm_cycles_i & '0');
elsif g_clk_ref_rate = 125000000 then
tm_cycles_scaled <= unsigned('0' & tm_cycles_i);
else
report "Unsupported g_clk_ref_rate (62.5 / 125 MHz)" severity failure;
end if;
end process;
process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
arm_d <= (others => '0');
miss_o <= '0';
else
arm_d <= arm_d(1 downto 0) & arm_i;
if arm_i = '1' then
match_o <= '0';
miss_o <= '0';
ts_adjusted <= resize(unsigned(ts_origin_i) + unsigned(ts_latency_i), 29);
delta <= signed('0'&ts_origin_i) + signed('0'&ts_latency_i) - signed('0'&tm_cycles_i);
end if;
if delta < -c_unwrap_threshold or delta > c_unwrap_threshold then
ts_adjusted <= ts_adjusted + 125000000;
target_cycles <= tm_cycles_scaled + 125000000;
else
target_cycles <= tm_cycles_scaled;
end if;
if (arm_d(1) = '1') then
if ts_adjusted < target_cycles then
miss_o <= '1';
else
armed <= '1';
end if;
end if;
if armed = '1' and ts_adjusted = target_cycles then
match_o <= '1';
armed <= '0';
else
match_o <= '0';
end if;
end if;
end if;
end process;
end rtl;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.gencores_pkg.all;
entity gc_async_counter_diff is
generic (
g_bits : integer := 8;
g_output_clock : string := "inc"
);
port
(
-- reset (g_output_clock clock domain)
rst_n_i : in std_logic;
-- increment clock
clk_inc_i : in std_logic;
-- decrement clock
clk_dec_i : in std_logic;
-- increment enable (clk_inc_i clock domain)
inc_i : in std_logic;
-- decrement enable (clk_inc_i clock domain)
dec_i : in std_logic;
-- current counter value, signed (g_output_clock clock domain)
counter_o : out std_logic_vector(g_bits downto 0)
);
end gc_async_counter_diff;
architecture rtl of gc_async_counter_diff is
signal cnt1_bin, cnt2_bin : unsigned(g_bits downto 0);
signal cnt1_gray, cnt2_gray : std_logic_vector(g_bits downto 0);
signal cnt1_gray_out : std_logic_vector(g_bits downto 0);
signal cnt2_gray_out : std_logic_vector(g_bits downto 0);
signal rst_n_inc, rst_n_dec : std_logic;
begin
U_SyncReset_to_IncClk : gc_sync_ffs
port map (
clk_i => clk_inc_i,
rst_n_i => '1',
data_i => rst_n_i,
synced_o => rst_n_inc);
U_SyncReset_to_DecClk : gc_sync_ffs
port map (
clk_i => clk_dec_i,
rst_n_i => '1',
data_i => rst_n_i,
synced_o => rst_n_dec);
p_count_up : process(clk_inc_i)
begin
if rising_edge(clk_inc_i) then
if rst_n_inc = '0' then
cnt1_bin <= (others => '0');
cnt1_gray <= (others => '0');
else
if inc_i = '1' then
cnt1_bin <= cnt1_bin + 1;
end if;
cnt1_gray <= f_gray_encode(std_logic_vector(cnt1_bin));
end if;
end if;
end process;
p_count_down : process(clk_dec_i)
begin
if rising_edge(clk_dec_i) then
if rst_n_dec = '0' then
cnt2_bin <= (others => '0');
cnt2_gray <= (others => '0');
else
if dec_i = '1' then
cnt2_bin <= cnt2_bin + 1;
end if;
cnt2_gray <= f_gray_encode(std_logic_vector(cnt2_bin));
end if;
end if;
end process;
gen_out_clock_is_inc : if g_output_clock = "inc" generate
cnt1_gray_out <= cnt1_gray;
U_Sync : gc_sync_register
generic map (
g_width => g_bits+1)
port map (
clk_i => clk_inc_i,
rst_n_a_i => rst_n_i,
d_i => cnt2_gray,
q_o => cnt2_gray_out);
end generate gen_out_clock_is_inc;
gen_out_clock_is_dec : if g_output_clock = "dec" generate
cnt2_gray_out <= cnt2_gray;
U_Sync : gc_sync_register
generic map (
g_width => g_bits+1)
port map (
clk_i => clk_dec_i,
rst_n_a_i => rst_n_i,
d_i => cnt1_gray,
q_o => cnt1_gray_out);
end generate gen_out_clock_is_dec;
counter_o <= std_logic_vector(unsigned(cnt2_gray_out) - unsigned(cnt1_gray_out));
end rtl;
...@@ -184,13 +184,14 @@ package streamers_pkg is ...@@ -184,13 +184,14 @@ package streamers_pkg is
g_escape_code_disable : boolean := FALSE; g_escape_code_disable : boolean := FALSE;
g_simulation : integer := 0; g_simulation : integer := 0;
g_sim_startup_cnt : integer := 6250;--100us g_sim_startup_cnt : integer := 6250;--100us
g_clk_ref_rate : integer := 125000000); g_clk_ref_rate : integer := 125000000;
g_use_ref_clock_for_data : integer := 0);
port ( port (
clk_sys_i : in std_logic; clk_sys_i : in std_logic;
clk_ref_i : in std_logic := '0';
rst_n_i : in std_logic; rst_n_i : in std_logic;
src_i : in t_wrf_source_in; src_i : in t_wrf_source_in;
src_o : out t_wrf_source_out; src_o : out t_wrf_source_out;
clk_ref_i : in std_logic := '0';
tm_time_valid_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_tai_i : in std_logic_vector(39 downto 0) := x"0000000000";
tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000"; tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000";
...@@ -294,7 +295,8 @@ package streamers_pkg is ...@@ -294,7 +295,8 @@ package streamers_pkg is
-- WB i/f -- WB i/f
g_slave_mode : t_wishbone_interface_mode := CLASSIC; g_slave_mode : t_wishbone_interface_mode := CLASSIC;
g_slave_granularity : t_wishbone_address_granularity := BYTE; g_slave_granularity : t_wishbone_address_granularity := BYTE;
g_simulation : integer := 0 g_simulation : integer := 0;
g_use_ref_clock_for_data : integer := 0
); );
port ( port (
...@@ -333,4 +335,4 @@ package streamers_pkg is ...@@ -333,4 +335,4 @@ package streamers_pkg is
); );
end component; end component;
end streamers_pkg; end streamers_pkg;
\ No newline at end of file
...@@ -46,7 +46,7 @@ use work.streamers_priv_pkg.all; ...@@ -46,7 +46,7 @@ use work.streamers_priv_pkg.all;
use work.streamers_pkg.all; use work.streamers_pkg.all;
entity xrx_streamer is entity xrx_streamer is
generic ( generic (
-- Width of the data words, must be multiple of 16 bits. This value set to this generic -- Width of the data words, must be multiple of 16 bits. This value set to this generic
-- on the receviving device must be the same as the value of g_tx_data_width set on the -- on the receviving device must be the same as the value of g_tx_data_width set on the
...@@ -54,16 +54,16 @@ entity xrx_streamer is ...@@ -54,16 +54,16 @@ entity xrx_streamer is
-- values in the same device (i.e. instantiation of xwr_transmission entity). It is the -- values in the same device (i.e. instantiation of xwr_transmission entity). It is the
-- responsibility of a network designer to make sure these parameters are properly set -- responsibility of a network designer to make sure these parameters are properly set
-- in the network. -- in the network.
g_data_width : integer := 32; g_data_width : integer := 32;
-- Size of RX buffer, in data words. -- Size of RX buffer, in data words.
g_buffer_size : integer := 256; g_buffer_size : integer := 256;
-- DO NOT USE unless you know what you are doing -- DO NOT USE unless you know what you are doing
-- legacy: the streamers that were initially used in Btrain did not check/insert -- legacy: the streamers that were initially used in Btrain did not check/insert
-- the escape code. This is justified if only one block of a known number of words is -- the escape code. This is justified if only one block of a known number of words is
-- sent/expected. -- sent/expected.
g_escape_code_disable : boolean := FALSE; g_escape_code_disable : boolean := false;
-- DO NOT USE unless you know what you are doing -- DO NOT USE unless you know what you are doing
-- legacy: the streamers that were initially used in Btrain accepted only a fixed -- legacy: the streamers that were initially used in Btrain accepted only a fixed
...@@ -76,11 +76,15 @@ entity xrx_streamer is ...@@ -76,11 +76,15 @@ entity xrx_streamer is
-- rate fo the White Rabbit referene clock. By default, this clock is -- rate fo the White Rabbit referene clock. By default, this clock is
-- 125MHz for WR Nodes. There are some WR Nodes that work with 62.5MHz. -- 125MHz for WR Nodes. There are some WR Nodes that work with 62.5MHz.
-- in the future, more frequences might be supported.. -- in the future, more frequences might be supported..
g_clk_ref_rate : integer := 125000000 g_clk_ref_rate : integer := 125000000;
g_use_ref_clock_for_data : integer := 0
); );
port ( port (
clk_sys_i : in std_logic; clk_sys_i : in std_logic;
-- White Rabbit reference clock
clk_ref_i : in std_logic := '0';
rst_n_i : in std_logic; rst_n_i : in std_logic;
-- Endpoint/WRC interface -- Endpoint/WRC interface
...@@ -92,8 +96,6 @@ entity xrx_streamer is ...@@ -92,8 +96,6 @@ entity xrx_streamer is
-- Caution: uses clk_ref_i clock domain! -- Caution: uses clk_ref_i clock domain!
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- White Rabbit reference clock
clk_ref_i : in std_logic := '0';
-- Time valid flag -- Time valid flag
tm_time_valid_i : in std_logic := '0'; tm_time_valid_i : in std_logic := '0';
...@@ -109,34 +111,34 @@ entity xrx_streamer is ...@@ -109,34 +111,34 @@ entity xrx_streamer is
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- 1 indicates the 1st word of the data block on rx_data_o. -- 1 indicates the 1st word of the data block on rx_data_o.
rx_first_p1_o : out std_logic; rx_first_p1_o : out std_logic;
-- 1 indicates the last word of the data block on rx_data_o. -- 1 indicates the last word of the data block on rx_data_o.
rx_last_p1_o : out std_logic; rx_last_p1_o : out std_logic;
-- Received data. -- Received data.
rx_data_o : out std_logic_vector(g_data_width-1 downto 0); 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. -- 1 indicted that rx_data_o is outputting a valid data word.
rx_valid_o : out std_logic; rx_valid_o : out std_logic;
-- Synchronous data request input: when 1, the streamer may output another -- Synchronous data request input: when 1, the streamer may output another
-- data word in the subsequent clock cycle. -- data word in the subsequent clock cycle.
rx_dreq_i : in std_logic; rx_dreq_i : in std_logic;
-- Lost output: 1 indicates that one or more frames or blocks have been lost -- Lost output: 1 indicates that one or more frames or blocks have been lost
-- (left for backward compatibility). -- (left for backward compatibility).
rx_lost_p1_o : out std_logic := '0'; rx_lost_p1_o : out std_logic := '0';
-- indicates that one or more blocks within frame are missing -- indicates that one or more blocks within frame are missing
rx_lost_blocks_p1_o : out std_logic := '0'; rx_lost_blocks_p1_o : out std_logic := '0';
-- indicates that one or more frames are missing, the number of frames is provied -- indicates that one or more frames are missing, the number of frames is provied
rx_lost_frames_p1_o : out std_logic := '0'; rx_lost_frames_p1_o : out std_logic := '0';
--number of lost frames, the 0xF...F means that counter overflew --number of lost frames, the 0xF...F means that counter overflew
rx_lost_frames_cnt_o : out std_logic_vector(14 downto 0); rx_lost_frames_cnt_o : out std_logic_vector(14 downto 0);
-- Latency measurement output: indicates the transport latency (between the -- Latency measurement output: indicates the transport latency (between the
-- TX streamer in remote device and this streamer), in clk_ref_i clock cycles. -- TX streamer in remote device and this streamer), in clk_ref_i clock cycles.
rx_latency_o : out std_logic_vector(27 downto 0); rx_latency_o : out std_logic_vector(27 downto 0);
-- 1 when the latency on rx_latency_o is valid. -- 1 when the latency on rx_latency_o is valid.
rx_latency_valid_o : out std_logic; rx_latency_valid_o : out std_logic;
-- received streamer frame (counts all frames, corrupted and not) -- received streamer frame (counts all frames, corrupted and not)
rx_frame_p1_o : out std_logic; rx_frame_p1_o : out std_logic;
-- configuration -- configuration
rx_streamer_cfg_i : in t_rx_streamer_cfg := c_rx_streamer_cfg_default rx_streamer_cfg_i : in t_rx_streamer_cfg := c_rx_streamer_cfg_default
); );
end xrx_streamer; end xrx_streamer;
...@@ -149,8 +151,8 @@ architecture rtl of xrx_streamer is ...@@ -149,8 +151,8 @@ architecture rtl of xrx_streamer is
signal state : t_rx_state; signal state : t_rx_state;
signal ser_count : unsigned(7 downto 0); signal ser_count : unsigned(7 downto 0);
signal seq_no, seq_new,count : unsigned(14 downto 0); signal seq_no, seq_new, count : unsigned(14 downto 0);
signal crc_match, crc_en, crc_en_masked, crc_restart : std_logic; signal crc_match, crc_en, crc_en_masked, crc_restart : std_logic;
...@@ -161,34 +163,34 @@ architecture rtl of xrx_streamer is ...@@ -161,34 +163,34 @@ architecture rtl of xrx_streamer is
signal fifo_drop, fifo_accept, fifo_accept_d0, fifo_dvalid : std_logic; signal fifo_drop, fifo_accept, fifo_accept_d0, fifo_dvalid : std_logic;
signal fifo_sync, fifo_last, frames_lost, blocks_lost : std_logic; signal fifo_sync, fifo_last, frames_lost, blocks_lost : std_logic;
signal fifo_dout, fifo_din : std_logic_vector(g_data_width + 1 downto 0); signal fifo_dout, fifo_din : std_logic_vector(g_data_width + 1 + 28 + 1 downto 0);
signal fifo_target_ts_en : std_logic;
signal fifo_target_ts : unsigned(27 downto 0);
signal pending_write, fab_dvalid_pre : std_logic; signal pending_write, fab_dvalid_pre : std_logic;
signal tx_tag_cycles, rx_tag_cycles : std_logic_vector(27 downto 0); signal tx_tag_cycles, rx_tag_cycles : std_logic_vector(27 downto 0);
signal tx_tag_valid, rx_tag_valid : std_logic; signal tx_tag_valid, rx_tag_valid : std_logic;
signal rx_tag_valid_stored : std_logic;
signal got_next_subframe : std_logic; signal got_next_subframe : std_logic;
signal is_frame_seq_id : std_logic; signal is_frame_seq_id : std_logic;
signal word_count : unsigned(11 downto 0); signal word_count : unsigned(11 downto 0);
signal sync_seq_no : std_logic; signal sync_seq_no : std_logic;
-- fixed latency signals signal rx_latency : unsigned(27 downto 0);
type t_rx_delay_state is (DISABLED, DELAY, ALLOW); signal rx_latency_stored : unsigned(27 downto 0);
signal timestamped : std_logic; signal rx_latency_valid : std_logic;
signal delay_cnt : unsigned(27 downto 0); signal is_vlan : std_logic;
signal rx_dreq_allow : std_logic;
signal rx_latency : unsigned(27 downto 0);
signal rx_latency_stored : unsigned(27 downto 0);
signal rx_latency_valid : std_logic;
signal delay_state : t_rx_delay_state;
signal rx_dreq : std_logic;
signal is_vlan : std_logic;
constant c_fixed_latency_zero : unsigned(27 downto 0) := (others => '0'); constant c_fixed_latency_zero : unsigned(27 downto 0) := (others => '0');
constant c_timestamper_delay : unsigned(27 downto 0) := to_unsigned(12, 28); -- cycles constant c_timestamper_delay : unsigned(27 downto 0) := to_unsigned(12, 28); -- cycles
signal fifo_last_int : std_logic;
begin -- rtl begin -- rtl
U_rx_crc_generator : gc_crc_gen U_rx_crc_generator : gc_crc_gen
...@@ -227,7 +229,7 @@ begin -- rtl ...@@ -227,7 +229,7 @@ begin -- rtl
dreq_i => fab.dreq); dreq_i => fab.dreq);
fab.dvalid <= '1' when fab_dvalid_pre = '1' and fab.addr = c_WRF_DATA and fab.bytesel = '0' else '0'; fab.dvalid <= '1' when fab_dvalid_pre = '1' and fab.addr = c_WRF_DATA and fab.bytesel = '0' else '0';
gen_escape: if (g_escape_code_disable = FALSE) generate gen_escape : if (g_escape_code_disable = false) generate
U_Escape_Detect : escape_detector U_Escape_Detect : escape_detector
generic map ( generic map (
g_data_width => 16, g_data_width => 16,
...@@ -244,44 +246,19 @@ begin -- rtl ...@@ -244,44 +246,19 @@ begin -- rtl
d_valid_o => fsm_in.dvalid, d_valid_o => fsm_in.dvalid,
d_req_i => fsm_in.dreq); d_req_i => fsm_in.dreq);
end generate gen_escape; end generate gen_escape;
gen_no_escape: if (g_escape_code_disable = TRUE) generate gen_no_escape : if (g_escape_code_disable = true) generate
fsm_in.dvalid <= fab.dvalid; fsm_in.dvalid <= fab.dvalid;
fsm_in.data <= fab.data; fsm_in.data <= fab.data;
fab.dreq <= fsm_in.dreq; fab.dreq <= fsm_in.dreq;
is_escape <= '0'; is_escape <= '0';
end generate gen_no_escape; end generate gen_no_escape;
fsm_in.eof <= fab.eof or fab.error; fsm_in.eof <= fab.eof or fab.error;
fsm_in.sof <= fab.sof; fsm_in.sof <= fab.sof;
U_Output_FIFO : dropping_buffer
generic map (
g_size => g_buffer_size,
g_data_width => g_data_width + 2)
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);
fifo_din(g_data_width+1) <= fifo_sync;
fifo_din(g_data_width) <= fifo_last or
((not pending_write) and is_escape); -- when word is 16 bits
fifo_din(g_data_width-1 downto 0) <= fifo_data;
rx_data_o <= fifo_dout(g_data_width-1 downto 0);
rx_first_p1_o <= fifo_dout(g_data_width+1);
rx_last_p1_o <= fifo_dout(g_data_width);
U_RX_Timestamper : pulse_stamper U_RX_Timestamper : pulse_stamper
generic map( generic map(
g_ref_clk_rate => g_clk_ref_rate) g_ref_clk_rate => g_clk_ref_rate)
port map ( port map (
clk_ref_i => clk_ref_i, clk_ref_i => clk_ref_i,
clk_sys_i => clk_sys_i, clk_sys_i => clk_sys_i,
...@@ -290,66 +267,84 @@ begin -- rtl ...@@ -290,66 +267,84 @@ begin -- rtl
tm_time_valid_i => tm_time_valid_i, tm_time_valid_i => tm_time_valid_i,
tm_tai_i => tm_tai_i, tm_tai_i => tm_tai_i,
tm_cycles_i => tm_cycles_i, tm_cycles_i => tm_cycles_i,
tag_cycles_o => rx_tag_cycles); tag_cycles_o => rx_tag_cycles,
tag_valid_o => rx_tag_valid);
------------------------------------------------------------------------------------------- fifo_last_int <= fifo_last or ((not pending_write) and is_escape); -- when word is 16 bit
-- fixed latency implementation
-------------------------------------------------------------------------------------------
-- mask rx_dreq to prevent reception U_FixLatencyDelay : entity work.fixed_latency_delay
rx_dreq <= rx_dreq_i and rx_dreq_allow; generic map (
-- produce a pulse when SOF is timestamped, this pulse starts counter in clk_sys clock g_data_width => g_data_width,
-- domain g_buffer_size => 32,
U_sync_with_clk : gc_sync_ffs g_use_ref_clock_for_data => g_use_ref_clock_for_data,
g_clk_ref_rate => g_clk_ref_rate)
port map ( port map (
clk_i => clk_sys_i, rst_n_i => rst_n_i,
rst_n_i => rst_n_i, clk_sys_i => clk_sys_i,
data_i => fsm_in.sof, clk_ref_i => clk_ref_i,
synced_o => timestamped); tm_time_valid_i => tm_time_valid_i,
tm_tai_i => tm_tai_i,
-- introduce fixed latency, if configured to do so tm_cycles_i => tm_cycles_i,
p_fixed_latency_fsm : process(clk_sys_i) d_data_i => fifo_data,
begin d_last_i => fifo_last_int,
if rising_edge(clk_sys_i) then d_sync_i => fifo_sync,
if rst_n_i = '0' then d_target_ts_en_i => fifo_target_ts_en,
delay_state <= DISABLED; d_target_ts_i => std_logic_vector(fifo_target_ts),
rx_latency_stored <= (others=>'0'); d_valid_i => fifo_dvalid,
rx_dreq_allow <= '1'; d_drop_i => fifo_drop,
delay_cnt <= c_timestamper_delay; d_accept_i => fifo_accept_d0,
else d_req_o => fsm_in.dreq,
case delay_state is rx_first_p1_o => rx_first_p1_o,
when DISABLED => rx_last_p1_o => rx_last_p1_o,
if unsigned(rx_streamer_cfg_i.fixed_latency) /= c_fixed_latency_zero then rx_data_o => rx_data_o,
delay_state <= ALLOW; rx_valid_o => rx_valid_o,
end if; rx_dreq_i => rx_dreq_i,
rx_latency_stored <= (others=>'0'); rx_streamer_cfg_i => rx_streamer_cfg_i);
delay_cnt <= c_timestamper_delay;
rx_dreq_allow <= '1'; -- introduce fixed latency, if configured to do so
when ALLOW => -- p_fixed_latency_fsm : process(clk_sys_i)
if unsigned(rx_streamer_cfg_i.fixed_latency) = c_fixed_latency_zero then -- begin
delay_state <= DISABLED; -- if rising_edge(clk_sys_i) then
elsif(rx_latency_valid ='1') then -- if rst_n_i = '0' then
rx_dreq_allow <= '0'; -- delay_state <= DISABLED;
rx_latency_stored <= rx_latency; -- rx_latency_stored <= (others => '0');
delay_state <= DELAY; -- rx_dreq_allow <= '1';
end if; -- delay_cnt <= c_timestamper_delay;
if(timestamped = '1') then -- else
delay_cnt <= c_timestamper_delay; -- case delay_state is
else -- when DISABLED =>
delay_cnt <= delay_cnt + 2; -- if unsigned(rx_streamer_cfg_i.fixed_latency) /= c_fixed_latency_zero then
end if; -- delay_state <= ALLOW;
when DELAY => -- end if;
if unsigned(rx_streamer_cfg_i.fixed_latency) <= delay_cnt + rx_latency_stored then -- rx_latency_stored <= (others => '0');
rx_latency_stored <= (others=>'0'); -- delay_cnt <= c_timestamper_delay;
rx_dreq_allow <= '1'; -- rx_dreq_allow <= '1';
delay_state <= ALLOW; -- when ALLOW =>
else -- if unsigned(rx_streamer_cfg_i.fixed_latency) = c_fixed_latency_zero then
delay_cnt <= delay_cnt + 2; -- delay_state <= DISABLED;
end if; -- elsif(rx_latency_valid = '1') then
end case; -- rx_dreq_allow <= '0';
end if; -- rx_latency_stored <= rx_latency;
end if; -- delay_state <= DELAY;
end process; -- end if;
-- if(timestamped = '1') then
-- if(rx_tag_valid= '1') then
-- delay_cnt <= c_timestamper_delay;
-- else
-- delay_cnt <= delay_cnt + 2;
-- end if;
-- when DELAY =>
-- if unsigned(rx_streamer_cfg_i.fixed_latency) <= delay_cnt + rx_latency_stored then
-- rx_latency_stored <= (others => '0');
-- rx_dreq_allow <= '1';
-- delay_state <= ALLOW;
-- else
-- delay_cnt <= delay_cnt + 2;
-- end if;
-- end case;
-- end if;
-- end if;
-- end process;
------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------
-- end of fixed latency implementation -- end of fixed latency implementation
...@@ -359,56 +354,57 @@ begin -- rtl ...@@ -359,56 +354,57 @@ begin -- rtl
begin begin
if rising_edge(clk_sys_i) then if rising_edge(clk_sys_i) then
if rst_n_i = '0' then if rst_n_i = '0' then
state <= IDLE; state <= IDLE;
count <= (others => '0'); count <= (others => '0');
seq_no <= (others => '1'); seq_no <= (others => '1');
detect_escapes <= '0'; detect_escapes <= '0';
crc_en <= '0'; crc_en <= '0';
fifo_accept <= '0'; fifo_accept <= '0';
fifo_drop <= '0'; fifo_drop <= '0';
fifo_dvalid <= '0'; fifo_dvalid <= '0';
pending_write <= '0'; pending_write <= '0';
got_next_subframe <= '0'; got_next_subframe <= '0';
fifo_sync <= '0'; fifo_sync <= '0';
fifo_last <= '0'; fifo_last <= '0';
tx_tag_valid <= '0'; tx_tag_valid <= '0';
ser_count <= (others => '0'); ser_count <= (others => '0');
word_count <= (others => '0'); word_count <= (others => '0');
sync_seq_no <= '1'; sync_seq_no <= '1';
rx_frame_p1_o <= '0'; rx_frame_p1_o <= '0';
rx_lost_frames_cnt_o <= (others => '0'); rx_lost_frames_cnt_o <= (others => '0');
frames_lost <= '0'; frames_lost <= '0';
rx_latency <= (others=>'0'); rx_latency <= (others => '0');
rx_latency_valid <= '0'; rx_latency_valid <= '0';
blocks_lost <= '0'; blocks_lost <= '0';
pack_data <= (others=>'0'); pack_data <= (others => '0');
is_vlan <= '0'; is_vlan <= '0';
rx_tag_valid_stored <= '0';
else else
case state is case state is
when IDLE => when IDLE =>
detect_escapes <= '0'; detect_escapes <= '0';
crc_en <= '0'; crc_en <= '0';
count <= (others => '0'); count <= (others => '0');
fifo_accept <= '0'; fifo_accept <= '0';
fifo_drop <= '0'; fifo_drop <= '0';
fifo_dvalid <= '0'; fifo_dvalid <= '0';
pending_write <= '0'; pending_write <= '0';
got_next_subframe <='0'; got_next_subframe <= '0';
ser_count <= (others => '0'); ser_count <= (others => '0');
fifo_sync <='0'; fifo_sync <= '0';
fifo_last <= '0'; fifo_last <= '0';
word_count <= (others => '0'); word_count <= (others => '0');
tx_tag_valid <= '0'; tx_tag_valid <= '0';
rx_frame_p1_o <= '0'; rx_frame_p1_o <= '0';
rx_lost_frames_cnt_o <= (others => '0'); rx_lost_frames_cnt_o <= (others => '0');
frames_lost <= '0'; frames_lost <= '0';
blocks_lost <= '0'; blocks_lost <= '0';
rx_latency <= (others=>'0'); rx_latency <= (others => '0');
rx_latency_valid <= '0'; rx_latency_valid <= '0';
is_vlan <= '0'; is_vlan <= '0';
rx_tag_valid_stored <= '0';
if(fsm_in.sof = '1') then if(fsm_in.sof = '1') then
state <= HEADER; state <= HEADER;
end if; end if;
when HEADER => when HEADER =>
...@@ -432,32 +428,32 @@ begin -- rtl ...@@ -432,32 +428,32 @@ begin -- rtl
end if; end if;
count <= count + 1; count <= count + 1;
when x"03" => when x"03" =>
if(fsm_in.data /= rx_streamer_cfg_i.mac_remote(47 downto 32) and rx_streamer_cfg_i.filter_remote ='1') then if(fsm_in.data /= rx_streamer_cfg_i.mac_remote(47 downto 32) and rx_streamer_cfg_i.filter_remote = '1') then
state <= IDLE; state <= IDLE;
end if; end if;
count <= count + 1; count <= count + 1;
when x"04" => when x"04" =>
if(fsm_in.data /= rx_streamer_cfg_i.mac_remote(31 downto 16) and rx_streamer_cfg_i.filter_remote ='1') then if(fsm_in.data /= rx_streamer_cfg_i.mac_remote(31 downto 16) and rx_streamer_cfg_i.filter_remote = '1') then
state <= IDLE; state <= IDLE;
end if; end if;
count <= count + 1; count <= count + 1;
when x"05" => when x"05" =>
if(fsm_in.data /= rx_streamer_cfg_i.mac_remote(15 downto 0) and rx_streamer_cfg_i.filter_remote ='1') then if(fsm_in.data /= rx_streamer_cfg_i.mac_remote(15 downto 0) and rx_streamer_cfg_i.filter_remote = '1') then
state <= IDLE; state <= IDLE;
end if; end if;
count <= count + 1; count <= count + 1;
when x"06" => when x"06" =>
if(fsm_in.data = x"8100") then if(fsm_in.data = x"8100") then
is_vlan <='1'; is_vlan <= '1';
elsif(fsm_in.data /= rx_streamer_cfg_i.ethertype) then elsif(fsm_in.data /= rx_streamer_cfg_i.ethertype) then
state <= IDLE; state <= IDLE;
is_vlan <='0'; is_vlan <= '0';
end if; end if;
count <= count + 1; count <= count + 1;
when x"07" => when x"07" =>
if(is_vlan = '0') then if(is_vlan = '0') then
tx_tag_valid <= fsm_in.data(15); tx_tag_valid <= fsm_in.data(15);
tx_tag_cycles(27 downto 16)<= fsm_in.data(11 downto 0); tx_tag_cycles(27 downto 16) <= fsm_in.data(11 downto 0);
end if; end if;
count <= count + 1; count <= count + 1;
when x"08" => when x"08" =>
...@@ -473,9 +469,9 @@ begin -- rtl ...@@ -473,9 +469,9 @@ begin -- rtl
end if; end if;
count <= count + 1; count <= count + 1;
when x"09" => when x"09" =>
tx_tag_valid <= fsm_in.data(15); tx_tag_valid <= fsm_in.data(15);
tx_tag_cycles(27 downto 16)<= fsm_in.data(11 downto 0); tx_tag_cycles(27 downto 16) <= fsm_in.data(11 downto 0);
count <= count + 1; count <= count + 1;
when x"0A" => when x"0A" =>
tx_tag_cycles(15 downto 0) <= fsm_in.data; tx_tag_cycles(15 downto 0) <= fsm_in.data;
count <= count + 1; count <= count + 1;
...@@ -483,24 +479,35 @@ begin -- rtl ...@@ -483,24 +479,35 @@ begin -- rtl
detect_escapes <= '1'; detect_escapes <= '1';
state <= FRAME_SEQ_ID; state <= FRAME_SEQ_ID;
rx_frame_p1_o <= '1'; rx_frame_p1_o <= '1';
count <= count + 1; count <= count + 1;
when others => null; when others => null;
end case; end case;
end if; end if;
when FRAME_SEQ_ID => when FRAME_SEQ_ID =>
rx_frame_p1_o <= '0'; rx_frame_p1_o <= '0';
if(fsm_in.eof = '1') then if(fsm_in.eof = '1') then
state <= IDLE; state <= IDLE;
elsif(fsm_in.dvalid = '1') then elsif(fsm_in.dvalid = '1') then
count <= "000" & x"001"; -- use as subframe seq_no count <= "000" & x"001"; -- use as subframe seq_no
state <= PAYLOAD; state <= PAYLOAD;
fifo_drop <= '0'; fifo_drop <= '0';
fifo_accept <= '0'; fifo_accept <= '0';
ser_count <= (others => '0'); ser_count <= (others => '0');
word_count <= word_count + 1; -- count words, increment in advance word_count <= word_count + 1; -- count words, increment in advance
got_next_subframe <= '1'; got_next_subframe <= '1';
if(tx_tag_valid = '1') then fifo_target_ts_en <= '0';
fifo_target_ts <= unsigned(tx_tag_cycles);
if(tx_tag_valid = '1' and unsigned(rx_streamer_cfg_i.fixed_latency) /= 0) then
fifo_target_ts_en <= '1';
end if;
-- latency measurement
if(tx_tag_valid = '1' and rx_tag_valid_stored = '1') then
rx_latency_valid <= '1'; rx_latency_valid <= '1';
if(unsigned(tx_tag_cycles) > unsigned(rx_tag_cycles)) then if(unsigned(tx_tag_cycles) > unsigned(rx_tag_cycles)) then
rx_latency <= unsigned(rx_tag_cycles) - unsigned(tx_tag_cycles) + to_unsigned(125000000, 28); rx_latency <= unsigned(rx_tag_cycles) - unsigned(tx_tag_cycles) + to_unsigned(125000000, 28);
...@@ -511,62 +518,72 @@ begin -- rtl ...@@ -511,62 +518,72 @@ begin -- rtl
else else
rx_latency_valid <= '0'; rx_latency_valid <= '0';
end if; end if;
rx_tag_valid_stored <= '0';
if(std_logic_vector(seq_no) /= fsm_in.data(14 downto 0)) then if(std_logic_vector(seq_no) /= fsm_in.data(14 downto 0)) then
seq_no <= unsigned(fsm_in.data(14 downto 0))+1; seq_no <= unsigned(fsm_in.data(14 downto 0))+1;
if (sync_seq_no = '1') then -- sync to the first received seq_no if (sync_seq_no = '1') then -- sync to the first received seq_no
sync_seq_no <= '0'; sync_seq_no <= '0';
frames_lost <= '0'; frames_lost <= '0';
rx_lost_frames_cnt_o <= (others => '0'); rx_lost_frames_cnt_o <= (others => '0');
else else
rx_lost_frames_cnt_o <= std_logic_vector(unsigned(fsm_in.data(14 downto 0)) - seq_no); rx_lost_frames_cnt_o <= std_logic_vector(unsigned(fsm_in.data(14 downto 0)) - seq_no);
frames_lost <= '1'; frames_lost <= '1';
end if; end if;
else else
seq_no <= unsigned(seq_no + 1); seq_no <= unsigned(seq_no + 1);
frames_lost <= '0'; frames_lost <= '0';
rx_lost_frames_cnt_o <= (others => '0'); rx_lost_frames_cnt_o <= (others => '0');
end if; end if;
end if; end if;
when SUBFRAME_HEADER => when SUBFRAME_HEADER =>
if fifo_dvalid = '1' then
fifo_target_ts_en <= '0';
end if;
fifo_drop <= '0'; fifo_drop <= '0';
fifo_accept <= '0'; fifo_accept <= '0';
ser_count <= (others => '0'); ser_count <= (others => '0');
if(fsm_in.eof = '1') then if(fsm_in.eof = '1') then
state <= IDLE; state <= IDLE;
got_next_subframe <= '0'; got_next_subframe <= '0';
blocks_lost <= '0'; blocks_lost <= '0';
elsif (fsm_in.dvalid = '1' and is_escape = '1') then elsif (fsm_in.dvalid = '1' and is_escape = '1') then
got_next_subframe <= '1'; got_next_subframe <= '1';
if(std_logic_vector(count) /= fsm_in.data(14 downto 0)) then if(std_logic_vector(count) /= fsm_in.data(14 downto 0)) then
count <= unsigned(fsm_in.data(14 downto 0))+1; count <= unsigned(fsm_in.data(14 downto 0))+1;
blocks_lost <= '1'; blocks_lost <= '1';
else else
count <= count + 1; count <= count + 1;
blocks_lost <= '0'; blocks_lost <= '0';
end if; end if;
state <= PAYLOAD; state <= PAYLOAD;
end if; end if;
when PAYLOAD => when PAYLOAD =>
frames_lost <= '0'; if fifo_dvalid = '1' then
fifo_target_ts_en <= '0';
end if;
frames_lost <= '0';
rx_lost_frames_cnt_o <= (others => '0'); rx_lost_frames_cnt_o <= (others => '0');
rx_latency_valid <= '0'; rx_latency_valid <= '0';
fifo_sync <= got_next_subframe; fifo_sync <= got_next_subframe;
if(fsm_in.eof = '1') then if(fsm_in.eof = '1') then
state <= IDLE; state <= IDLE;
fifo_drop <= '1'; fifo_drop <= '1';
fifo_accept <= '0'; fifo_accept <= '0';
got_next_subframe <= '0'; got_next_subframe <= '0';
elsif(fsm_in.dvalid = '1') then elsif(fsm_in.dvalid = '1') then
if(is_escape = '1') then if(is_escape = '1') then
ser_count <= (others => '0'); ser_count <= (others => '0');
fifo_last <= '1'; fifo_last <= '1';
...@@ -574,99 +591,107 @@ begin -- rtl ...@@ -574,99 +591,107 @@ begin -- rtl
got_next_subframe <= '1'; got_next_subframe <= '1';
if(fsm_in.data(15) = '1') then if(fsm_in.data(15) = '1') then
if(std_logic_vector(count) /= fsm_in.data(14 downto 0)) then if(std_logic_vector(count) /= fsm_in.data(14 downto 0)) then
count <= unsigned(fsm_in.data(14 downto 0)); count <= unsigned(fsm_in.data(14 downto 0));
blocks_lost <= '1'; blocks_lost <= '1';
else else
count <= unsigned(count + 1); count <= unsigned(count + 1);
blocks_lost <= '0'; blocks_lost <= '0';
end if; end if;
state <= PAYLOAD; state <= PAYLOAD;
fifo_accept <= crc_match; --_latched; fifo_accept <= crc_match; --_latched;
fifo_drop <= not crc_match; --_latched; fifo_drop <= not crc_match; --_latched;
fifo_dvalid <= pending_write and not fifo_dvalid; fifo_dvalid <= pending_write and not fifo_dvalid;
pending_write <= '0';
pending_write <= '0';
elsif fsm_in.data = x"0bad" then elsif fsm_in.data = x"0bad" then
blocks_lost <= '0'; blocks_lost <= '0';
state <= EOF; state <= EOF;
fifo_accept <= crc_match; --_latched; fifo_accept <= crc_match; --_latched;
fifo_drop <= not crc_match; --_latched; fifo_drop <= not crc_match; --_latched;
fifo_dvalid <= pending_write and not fifo_dvalid; fifo_dvalid <= pending_write and not fifo_dvalid;
else else
blocks_lost <= '0'; blocks_lost <= '0';
state <= EOF; state <= EOF;
fifo_drop <= '1'; fifo_drop <= '1';
fifo_accept <= '0'; fifo_accept <= '0';
end if; end if;
else --of: if(is_escape = '1' or word_count = g_expected_words_number) then else --of: if(is_escape = '1' or word_count = g_expected_words_number) then
fifo_last <= '0'; fifo_last <= '0';
fifo_accept <= '0'; fifo_accept <= '0';
fifo_drop <= '0'; fifo_drop <= '0';
blocks_lost <= '0'; blocks_lost <= '0';
pack_data(to_integer(ser_count) * 16 + 15 downto to_integer(ser_count) * 16) <= fsm_in.data; 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 if(ser_count = g_data_width/16 - 1) then
ser_count <= (others => '0'); ser_count <= (others => '0');
if (ser_count = x"00") then -- ML: the case when g_data_width == 16 if (ser_count = x"00") then -- ML: the case when g_data_width == 16
fifo_sync <= got_next_subframe; fifo_sync <= got_next_subframe;
fifo_data(g_data_width-1 downto 0) <= pack_data(g_data_width-1 downto 0); fifo_data(g_data_width-1 downto 0) <= pack_data(g_data_width-1 downto 0);
fifo_dvalid <= not is_escape; fifo_dvalid <= not is_escape;
pending_write <= '0'; pending_write <= '0';
else else
ser_count <= (others => '0'); ser_count <= (others => '0');
fifo_data(g_data_width-16-1 downto 0) <= pack_data(g_data_width-16-1 downto 0); 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_data(g_data_width-1 downto g_data_width-16) <= fsm_in.data;
fifo_dvalid <= '0'; fifo_dvalid <= '0';
pending_write <= '1'; pending_write <= '1';
end if; end if;
if(word_count = g_expected_words_number) then if(word_count = g_expected_words_number) then
state <= EOF; state <= EOF;
fifo_accept <= '1'; fifo_accept <= '1';
fifo_drop <= '0'; fifo_drop <= '0';
fifo_dvalid <= '1'; fifo_dvalid <= '1';
else else
word_count <= word_count + 1; word_count <= word_count + 1;
end if; end if;
elsif(ser_count = g_data_width/16-2 and pending_write = '1') then elsif(ser_count = g_data_width/16-2 and pending_write = '1') then
pending_write <= '0'; pending_write <= '0';
ser_count <= ser_count + 1; ser_count <= ser_count + 1;
fifo_dvalid <= '1'; fifo_dvalid <= '1';
fifo_sync <= got_next_subframe; fifo_sync <= got_next_subframe;
got_next_subframe <= '0'; got_next_subframe <= '0';
else else
ser_count <= ser_count + 1; ser_count <= ser_count + 1;
fifo_dvalid <= '0'; fifo_dvalid <= '0';
end if; end if;
end if; end if;
else --of: elsif(fsm_in.dvalid = '1') then else --of: elsif(fsm_in.dvalid = '1') then
fifo_dvalid <= '0'; fifo_dvalid <= '0';
end if; end if;
if(fifo_dvalid = '1') then if(fifo_dvalid = '1') then
fifo_sync <= '0'; fifo_sync <= '0';
end if; end if;
when EOF => when EOF =>
fifo_dvalid <= '0'; fifo_dvalid <= '0';
fifo_drop <= '0'; fifo_drop <= '0';
fifo_accept <= '0'; fifo_accept <= '0';
state <= IDLE; state <= IDLE;
end case; end case;
end if; end if;
end if; end if;
end process; end process;
p_delay_fifo_accept : process(clk_sys_i) p_delay_fifo_accept : process(clk_sys_i)
begin begin
if rising_edge(clk_sys_i) then if rising_edge(clk_sys_i) then
...@@ -679,6 +704,6 @@ begin -- rtl ...@@ -679,6 +704,6 @@ begin -- rtl
rx_lost_frames_p1_o <= frames_lost; rx_lost_frames_p1_o <= frames_lost;
rx_latency_o <= std_logic_vector(rx_latency); rx_latency_o <= std_logic_vector(rx_latency);
rx_latency_valid_o <= rx_latency_valid; rx_latency_valid_o <= rx_latency_valid;
crc_restart <= '1' when (state = FRAME_SEQ_ID or (is_escape = '1' and fsm_in.data(15) = '1')) else not rst_n_i; crc_restart <= '1' when (state = FRAME_SEQ_ID or (is_escape = '1' and fsm_in.data(15) = '1')) else not rst_n_i;
end rtl; end rtl;
...@@ -76,19 +76,28 @@ entity xtx_streamer is ...@@ -76,19 +76,28 @@ entity xtx_streamer is
-- simulation mode: it is set to override the startaup-timer, the value with which -- simulation mode: it is set to override the startaup-timer, the value with which
-- the timer is overriden is set in the second generic -- the timer is overriden is set in the second generic
g_simulation : integer :=0; g_simulation : integer := 0;
-- startup counter, used only in simulatin mode (value in 16ns cycles) -- startup counter, used only in simulatin mode (value in 16ns cycles)
g_sim_startup_cnt : integer := 6250;-- 100us; g_sim_startup_cnt : integer := 6250; -- 100us;
-- rate fo the White Rabbit referene clock. By default, this clock is -- rate fo the White Rabbit referene clock. By default, this clock is
-- 125MHz for WR Nodes. There are some WR Nodes that work with 62.5MHz. -- 125MHz for WR Nodes. There are some WR Nodes that work with 62.5MHz.
-- in the future, more frequences might be supported.. -- in the future, more frequences might be supported..
g_clk_ref_rate : integer := 125000000 g_clk_ref_rate : integer := 125000000;
-- when non-zero, the datapath (tx_/rx_ ports) are in the clk_ref_i clock
-- domain instead of clk_sys_i. This is a must for fixed latency mode if
-- clk_sys_i is asynchronous (i.e. not locked) to the WR timing.
g_use_ref_clock_for_data : integer := 0
); );
port ( port (
clk_sys_i : in std_logic; clk_sys_i : in std_logic;
rst_n_i : in std_logic; -- White Rabbit reference clock
clk_ref_i : in std_logic := '0';
rst_n_i : in std_logic;
-- Endpoint/WRC interface - packet source -- Endpoint/WRC interface - packet source
src_i : in t_wrf_source_in; src_i : in t_wrf_source_in;
...@@ -99,8 +108,6 @@ entity xtx_streamer is ...@@ -99,8 +108,6 @@ entity xtx_streamer is
-- Caution: uses clk_ref_i clock domain! -- Caution: uses clk_ref_i clock domain!
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- White Rabbit reference clock
clk_ref_i : in std_logic := '0';
-- Time valid flag -- Time valid flag
tm_time_valid_i : in std_logic := '0'; tm_time_valid_i : in std_logic := '0';
...@@ -112,9 +119,10 @@ entity xtx_streamer is ...@@ -112,9 +119,10 @@ entity xtx_streamer is
tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000"; tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000";
-- status of the link, in principle the tx can be done only if link is oK -- status of the link, in principle the tx can be done only if link is oK
link_ok_i : in std_logic := '1'; link_ok_i : in std_logic := '1';
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- User interface -- User interface
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- Data word to be sent. -- Data word to be sent.
...@@ -127,6 +135,10 @@ entity xtx_streamer is ...@@ -127,6 +135,10 @@ entity xtx_streamer is
-- the following clock cycle. -- the following clock cycle.
tx_dreq_o : out std_logic; tx_dreq_o : out std_logic;
-- sync signal, allowing to align transmission of the frames to the
-- least supported WR reference clock frequency. Used in fixed latency mode.
tx_sync_o : out std_logic;
-- Last signal. Can be used to indicate the last data word in a larger -- Last signal. Can be used to indicate the last data word in a larger
-- block of samples (see documentation for more details). -- block of samples (see documentation for more details).
tx_last_p1_i : in std_logic := '1'; tx_last_p1_i : in std_logic := '1';
...@@ -137,11 +149,11 @@ entity xtx_streamer is ...@@ -137,11 +149,11 @@ entity xtx_streamer is
-- Reset sequence number. When asserted, the internal sequence number -- Reset sequence number. When asserted, the internal sequence number
-- generator used to detect loss of frames is reset to 0. Advanced feature. -- generator used to detect loss of frames is reset to 0. Advanced feature.
tx_reset_seq_i : in std_logic := '0'; tx_reset_seq_i : in std_logic := '0';
-- successfully sent streamer frame -- successfully sent streamer frame
tx_frame_p1_o : out std_logic; tx_frame_p1_o : out std_logic;
-- Configuration -- Configuration
tx_streamer_cfg_i : in t_tx_streamer_cfg := c_tx_streamer_cfg_default tx_streamer_cfg_i : in t_tx_streamer_cfg := c_tx_streamer_cfg_default
); );
end xtx_streamer; end xtx_streamer;
...@@ -155,13 +167,17 @@ architecture rtl of xtx_streamer is ...@@ -155,13 +167,17 @@ architecture rtl of xtx_streamer is
signal tx_threshold_hit : std_logic; signal tx_threshold_hit : std_logic;
signal tx_timeout_hit : std_logic; signal tx_timeout_hit : std_logic;
signal tx_flush_latched : std_logic; signal tx_flush_latched : std_logic;
signal tx_idle : std_logic;
signal tx_fifo_last, tx_fifo_we, tx_fifo_full, tx_fifo_empty, tx_fifo_rd : std_logic; signal tx_fifo_last, tx_fifo_we, tx_fifo_full, tx_fifo_empty, tx_fifo_rd : std_logic;
signal tx_fifo_empty_int, tx_fifo_rd_int, tx_fifo_rd_int_d : std_logic;
signal tx_fifo_q_int, tx_fifo_q_reg : std_logic_vector(g_data_width downto 0);
signal tx_fifo_q_valid : std_logic;
signal tx_fifo_q, tx_fifo_d : std_logic_vector(g_data_width downto 0); signal tx_fifo_q, tx_fifo_d : std_logic_vector(g_data_width downto 0);
signal state : t_tx_state; signal state : t_tx_state;
signal seq_no, count : unsigned(14 downto 0); signal seq_no, count : unsigned(14 downto 0);
signal ser_count : unsigned(7 downto 0); signal ser_count : unsigned(7 downto 0);
signal word_count : unsigned(11 downto 0); --2^12 = 4096*2 bytes (can accommodate jambo frame) signal word_count : unsigned(11 downto 0); --2^12 = 4096*2 bytes (can accommodate jambo frame)
signal total_words : unsigned(10 downto 0); signal total_words : unsigned(10 downto 0);
signal timeout_counter : unsigned(11 downto 0); signal timeout_counter : unsigned(11 downto 0);
...@@ -176,14 +192,26 @@ architecture rtl of xtx_streamer is ...@@ -176,14 +192,26 @@ architecture rtl of xtx_streamer is
signal tx_almost_empty, tx_almost_full : std_logic; signal tx_almost_empty, tx_almost_full : std_logic;
signal buf_frame_count : unsigned(5 downto 0) := (others => '0'); signal buf_frame_count_inc_ref : std_logic;
signal buf_frame_count_dec_sys : std_logic;
signal buf_frame_count : std_logic_vector(5 downto 0);
signal tag_cycles : std_logic_vector(27 downto 0); signal tag_cycles : std_logic_vector(27 downto 0);
signal tag_valid, tag_valid_latched : std_logic; signal tag_valid, tag_valid_latched : std_logic;
signal link_ok_delay_cnt : unsigned(25 downto 0); signal link_ok_delay_cnt : unsigned(25 downto 0);
constant c_link_ok_rst_delay : unsigned(25 downto 0) := to_unsigned(62500000, 26);-- 1s signal link_ok_delay_expired : std_logic;
signal link_ok_delay_expired_ref : std_logic;
signal link_ok_ref : std_logic;
signal clk_data : std_logic;
signal rst_n_ref : std_logic;
signal stamper_pulse_a : std_logic;
constant c_link_ok_rst_delay : unsigned(25 downto 0) := to_unsigned(62500000, 26); -- 1s
constant c_link_ok_rst_delay_sim : unsigned(25 downto 0) := to_unsigned(g_sim_startup_cnt, 26); constant c_link_ok_rst_delay_sim : unsigned(25 downto 0) := to_unsigned(g_sim_startup_cnt, 26);
begin -- rtl begin -- rtl
...@@ -193,11 +221,11 @@ begin -- rtl ...@@ -193,11 +221,11 @@ begin -- rtl
------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------
assert g_tx_buffer_size >= g_tx_threshold assert g_tx_buffer_size >= g_tx_threshold
report "The size of the tx buffer must be greater or equal the tx threashold" report "The size of the tx buffer must be greater or equal the tx threashold"
severity FAILURE; severity failure;
assert g_tx_buffer_size >= g_tx_max_words_per_frame assert g_tx_buffer_size >= g_tx_max_words_per_frame
report "The size of tx buffer must be greater or equal the max number of words in frame" report "The size of tx buffer must be greater or equal the max number of words in frame"
severity FAILURE; severity failure;
------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------
U_tx_crc_generator : gc_crc_gen U_tx_crc_generator : gc_crc_gen
...@@ -239,8 +267,8 @@ begin -- rtl ...@@ -239,8 +267,8 @@ begin -- rtl
fab_src.sof <= fsm_out.sof; fab_src.sof <= fsm_out.sof;
fab_src.eof <= fsm_out.eof; fab_src.eof <= fsm_out.eof;
gen_escape: if (g_escape_code_disable = FALSE) generate gen_escape : if (g_escape_code_disable = false) generate
U_Insert_Escape : gc_escape_inserter U_Insert_Escape : gc_escape_inserter
generic map ( generic map (
g_data_width => 16, g_data_width => 16,
...@@ -258,7 +286,7 @@ begin -- rtl ...@@ -258,7 +286,7 @@ begin -- rtl
d_valid_o => fab_src.dvalid, d_valid_o => fab_src.dvalid,
d_req_i => fab_src.dreq); d_req_i => fab_src.dreq);
end generate gen_escape; end generate gen_escape;
gen_no_escape: if (g_escape_code_disable = TRUE) generate gen_no_escape : if (g_escape_code_disable = true) generate
fab_src.data <= fsm_out.data; fab_src.data <= fsm_out.data;
fab_src.dvalid <= fsm_out.dvalid; fab_src.dvalid <= fsm_out.dvalid;
fsm_out.dreq <= fab_src.dreq; fsm_out.dreq <= fab_src.dreq;
...@@ -267,41 +295,135 @@ begin -- rtl ...@@ -267,41 +295,135 @@ begin -- rtl
tx_fifo_we <= tx_valid_i and not tx_fifo_full; tx_fifo_we <= tx_valid_i and not tx_fifo_full;
tx_fifo_d <= tx_last_p1_i & tx_data_i; tx_fifo_d <= tx_last_p1_i & tx_data_i;
U_TX_Buffer : generic_sync_fifo gen_use_sys_clock_for_data : if g_use_ref_clock_for_data = 0 generate
generic map (
g_data_width => g_data_width + 1, U_TX_Buffer : generic_sync_fifo
g_size => g_tx_buffer_size, generic map (
g_with_almost_full => true, g_data_width => g_data_width + 1,
g_with_almost_empty => true, g_size => g_tx_buffer_size,
g_almost_empty_threshold => g_tx_threshold, g_with_almost_full => true,
g_almost_full_threshold => g_tx_buffer_size - 2, g_with_almost_empty => true,
g_show_ahead => true) g_almost_empty_threshold => g_tx_threshold,
port map ( g_almost_full_threshold => g_tx_buffer_size - 2,
rst_n_i => rst_n_i, g_show_ahead => true)
clk_i => clk_sys_i, port map (
d_i => tx_fifo_d, rst_n_i => rst_n_i,
we_i => tx_fifo_we, clk_i => clk_sys_i,
q_o => tx_fifo_q, d_i => tx_fifo_d,
rd_i => tx_fifo_rd, we_i => tx_fifo_we,
empty_o => tx_fifo_empty, q_o => tx_fifo_q,
full_o => tx_fifo_full, rd_i => tx_fifo_rd,
almost_empty_o => tx_almost_empty, empty_o => tx_fifo_empty,
almost_full_o => tx_almost_full full_o => tx_fifo_full,
); almost_empty_o => tx_almost_empty,
tx_fifo_rd <= '1' when (state = PAYLOAD and ser_count = g_data_width/16-1 and almost_full_o => tx_almost_full
fsm_out.dreq = '1' and tx_fifo_empty = '0') else );
'0';
tx_threshold_hit <= '1' when tx_almost_empty = '0' and (buf_frame_count /= 0) else '0'; clk_data <= clk_sys_i;
stamper_pulse_a <= fsm_out.sof;
end generate gen_use_sys_clock_for_data;
gen_use_ref_clock_for_data : if g_use_ref_clock_for_data /= 0 generate
U_TX_Buffer : generic_async_fifo
generic map (
g_data_width => g_data_width + 1,
g_size => g_tx_buffer_size,
g_with_rd_empty => true,
g_with_wr_full => true,
g_with_wr_almost_full => true,
g_with_rd_almost_empty => true,
g_almost_empty_threshold => g_tx_threshold,
g_almost_full_threshold => g_tx_buffer_size - 2,
g_show_ahead => true)
port map (
rst_n_i => rst_n_i,
clk_wr_i => clk_ref_i,
clk_rd_i => clk_sys_i,
d_i => tx_fifo_d,
we_i => tx_fifo_we,
q_o => tx_fifo_q_int,
rd_i => tx_fifo_rd_int,
rd_empty_o => tx_fifo_empty_int,
wr_full_o => tx_fifo_full,
rd_almost_empty_o => tx_almost_empty,
wr_almost_full_o => tx_almost_full
);
-- emulate show-ahead mode, not supported by async fifos in the
-- general-cores library.
tx_fifo_rd_int <= not tx_fifo_empty_int when tx_fifo_q_valid = '0' else tx_fifo_rd;
tx_fifo_q <= tx_fifo_q_int when tx_fifo_rd_int_d = '1' else tx_fifo_q_reg;
p_show_ahead : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
tx_fifo_empty <= '0';
tx_fifo_q_valid <= '0';
else
if tx_fifo_rd_int = '1' then
tx_fifo_q_valid <= '1';
tx_fifo_empty <= '0';
elsif tx_fifo_rd = '1' then
tx_fifo_q_valid <= not tx_fifo_empty_int;
tx_fifo_empty <= not tx_fifo_q_valid;
end if;
if tx_fifo_rd_int_d = '1' then
tx_fifo_q_reg <= tx_fifo_q;
end if;
tx_fifo_rd_int_d <= tx_fifo_rd_int;
end if;
end if;
end process;
clk_data <= clk_ref_i;
p_detect_sof : process(clk_ref_i)
begin
if rising_edge(clk_ref_i) then
if rst_n_ref = '0' then
tx_idle <= '1';
stamper_pulse_a <= '0';
else
if tx_last_p1_i = '1' and tx_valid_i = '1' then
tx_idle <= '1';
elsif tx_valid_i = '1' then
tx_idle <= '0';
end if;
stamper_pulse_a <= tx_valid_i and tx_idle;
end if;
end if;
end process;
end generate gen_use_ref_clock_for_data;
-- sys clock domain
tx_fifo_rd <= '1' when (state = PAYLOAD and ser_count = g_data_width/16-1 and
fsm_out.dreq = '1' and tx_fifo_empty = '0') else
'0';
-- sys clock domain
tx_threshold_hit <= '1' when tx_almost_empty = '0' and (signed(buf_frame_count) > 0) else '0';
tx_fifo_last <= tx_fifo_q(g_data_width); tx_fifo_last <= tx_fifo_q(g_data_width);
U_Timestamper : pulse_stamper U_Timestamper : pulse_stamper
generic map( generic map(
g_ref_clk_rate => g_clk_ref_rate) g_ref_clk_rate => g_clk_ref_rate)
port map ( port map (
clk_ref_i => clk_ref_i, clk_ref_i => clk_ref_i,
clk_sys_i => clk_sys_i, clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i, rst_n_i => rst_n_i,
pulse_a_i => fsm_out.sof, pulse_a_i => stamper_pulse_a,
tm_time_valid_i => tm_time_valid_i, tm_time_valid_i => tm_time_valid_i,
tm_tai_i => tm_tai_i, tm_tai_i => tm_tai_i,
tm_cycles_i => tm_cycles_i, tm_cycles_i => tm_cycles_i,
...@@ -309,20 +431,21 @@ begin -- rtl ...@@ -309,20 +431,21 @@ begin -- rtl
tag_cycles_o => tag_cycles, tag_cycles_o => tag_cycles,
tag_valid_o => tag_valid); tag_valid_o => tag_valid);
p_frame_counter : process(clk_sys_i) buf_frame_count_inc_ref <= tx_fifo_we and tx_last_p1_i;
begin buf_frame_count_dec_sys <= tx_fifo_rd and tx_fifo_last;
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then U_FrameCounter: entity work.gc_async_counter_diff
buf_frame_count <= (others => '0'); generic map (
else g_bits => 5,
if(tx_fifo_we = '1' and tx_last_p1_i = '1' and (tx_fifo_rd = '0' or tx_fifo_last = '0')) then g_output_clock => "dec")
buf_frame_count <= buf_frame_count+ 1; port map (
elsif((tx_fifo_we = '0' or tx_last_p1_i = '0') and (tx_fifo_rd = '1' and tx_fifo_last = '1')) then rst_n_i => rst_n_i,
buf_frame_count <= buf_frame_count - 1; clk_inc_i => clk_data,
end if; clk_dec_i => clk_sys_i,
end if; inc_i => buf_frame_count_inc_ref,
end if; dec_i => buf_frame_count_dec_sys,
end process; counter_o => buf_frame_count);
p_tx_timeout : process(clk_sys_i) p_tx_timeout : process(clk_sys_i)
begin begin
...@@ -346,20 +469,32 @@ begin -- rtl ...@@ -346,20 +469,32 @@ begin -- rtl
end if; end if;
end process; end process;
p_latch_timestamp : 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_fsm : process(clk_sys_i) p_fsm : process(clk_sys_i)
begin begin
if rising_edge(clk_sys_i) then if rising_edge(clk_sys_i) then
if rst_n_i = '0' then if rst_n_i = '0' then
state <= IDLE; state <= IDLE;
fsm_out.sof <= '0'; fsm_out.sof <= '0';
fsm_out.eof <= '0'; fsm_out.eof <= '0';
fsm_out.dvalid <= '0'; fsm_out.dvalid <= '0';
fsm_out.data <= (others => '0'); fsm_out.data <= (others => '0');
count <= (others => '0'); count <= (others => '0');
seq_no <= (others => '0'); seq_no <= (others => '0');
word_count <= (others => '0'); word_count <= (others => '0');
crc_en <= '0'; crc_en <= '0';
crc_reset <= '1'; crc_reset <= '1';
tx_frame_p1_o <= '0'; tx_frame_p1_o <= '0';
tag_valid_latched <= '0'; tag_valid_latched <= '0';
tx_flush_latched <= '0'; tx_flush_latched <= '0';
...@@ -370,19 +505,19 @@ begin -- rtl ...@@ -370,19 +505,19 @@ begin -- rtl
if(tx_reset_seq_i = '1') then if(tx_reset_seq_i = '1') then
seq_no <= (others => '0'); seq_no <= (others => '0');
end if; end if;
if(tag_valid = '1') then if(tag_valid = '1') then
tag_valid_latched <= '1'; -- overriden in IDLE tag_valid_latched <= '1'; -- overriden in IDLE
end if; end if;
tx_flush_latched <= '0';-- overriden in IDLE tx_flush_latched <= '0'; -- overriden in IDLE
case state is case state is
when IDLE => when IDLE =>
tag_valid_latched <= '0'; tag_valid_latched <= '0';
tx_flush_latched <= tx_flush_p1_i or tx_timeout_hit; tx_flush_latched <= tx_flush_p1_i or tx_timeout_hit;
crc_en <= '0'; crc_en <= '0';
crc_reset <= '0'; crc_reset <= '0';
fsm_out.eof <= '0'; fsm_out.eof <= '0';
tx_frame_p1_o <= '0'; tx_frame_p1_o <= '0';
if(fsm_out.dreq = '1' and (tx_flush_latched = '1' or tx_flush_p1_i = '1' or tx_threshold_hit = '1')) then if(fsm_out.dreq = '1' and (tx_flush_latched = '1' or tx_flush_p1_i = '1' or tx_threshold_hit = '1')) then
state <= SOF; state <= SOF;
...@@ -401,6 +536,8 @@ begin -- rtl ...@@ -401,6 +536,8 @@ begin -- rtl
when ETH_HEADER => when ETH_HEADER =>
if(fsm_out.dreq = '1') then if(fsm_out.dreq = '1') then
fsm_out.dvalid <= '1';
case count(7 downto 0) is case count(7 downto 0) is
when x"00" => when x"00" =>
fsm_out.data <= tx_streamer_cfg_i.mac_target(47 downto 32); fsm_out.data <= tx_streamer_cfg_i.mac_target(47 downto 32);
...@@ -416,6 +553,7 @@ begin -- rtl ...@@ -416,6 +553,7 @@ begin -- rtl
count <= count + 1; count <= count + 1;
when x"04" => when x"04" =>
fsm_out.data <= tx_streamer_cfg_i.mac_local(31 downto 16); fsm_out.data <= tx_streamer_cfg_i.mac_local(31 downto 16);
count <= count + 1; count <= count + 1;
when x"05" => when x"05" =>
fsm_out.data <= tx_streamer_cfg_i.mac_local(15 downto 0); fsm_out.data <= tx_streamer_cfg_i.mac_local(15 downto 0);
...@@ -426,14 +564,21 @@ begin -- rtl ...@@ -426,14 +564,21 @@ begin -- rtl
else else
fsm_out.data <= x"8100"; fsm_out.data <= x"8100";
end if; end if;
count <= count + 1; count <= count + 1;
when x"07" => when x"07" =>
if(tx_streamer_cfg_i.qtag_ena = '0') then if(tx_streamer_cfg_i.qtag_ena = '0') then
fsm_out.data <= tag_valid_latched & "000" & tag_cycles(27 downto 16);
fsm_out.data <= "1000" & tag_cycles(27 downto 16);
if tag_valid_latched = '1' then
count <= count + 1;
fsm_out.dvalid <= '1';
else
fsm_out.dvalid <= '0';
end if;
else else
fsm_out.data <= tx_streamer_cfg_i.qtag_prio & '0' & tx_streamer_cfg_i.qtag_vid; fsm_out.data <= tx_streamer_cfg_i.qtag_prio & '0' & tx_streamer_cfg_i.qtag_vid;
count <= count + 1;
end if; end if;
count <= count + 1;
when x"08" => when x"08" =>
if(tx_streamer_cfg_i.qtag_ena = '0') then if(tx_streamer_cfg_i.qtag_ena = '0') then
fsm_out.data <= tag_cycles(15 downto 0); fsm_out.data <= tag_cycles(15 downto 0);
...@@ -441,10 +586,15 @@ begin -- rtl ...@@ -441,10 +586,15 @@ begin -- rtl
else else
fsm_out.data <= tx_streamer_cfg_i.ethertype; fsm_out.data <= tx_streamer_cfg_i.ethertype;
end if; end if;
count <= count + 1; count <= count + 1;
when x"09" => when x"09" =>
fsm_out.data <= tag_valid_latched & "000" & tag_cycles(27 downto 16); if tag_valid_latched = '1' then
count <= count + 1; count <= count + 1;
fsm_out.dvalid <= '1';
else
fsm_out.dvalid <= '0';
end if;
fsm_out.data <= "1000" & tag_cycles(27 downto 16);
when x"0A" => when x"0A" =>
fsm_out.data <= tag_cycles(15 downto 0); fsm_out.data <= tag_cycles(15 downto 0);
state <= FRAME_SEQ_ID; state <= FRAME_SEQ_ID;
...@@ -453,7 +603,6 @@ begin -- rtl ...@@ -453,7 +603,6 @@ begin -- rtl
fsm_out.data <= (others => 'X'); fsm_out.data <= (others => 'X');
count <= (others => 'X'); count <= (others => 'X');
end case; end case;
fsm_out.dvalid <= '1';
else else
fsm_out.dvalid <= '0'; fsm_out.dvalid <= '0';
end if; end if;
...@@ -469,9 +618,9 @@ begin -- rtl ...@@ -469,9 +618,9 @@ begin -- rtl
crc_reset <= '0'; crc_reset <= '0';
state <= PAYLOAD; state <= PAYLOAD;
else else
fsm_out.dvalid <= '0'; fsm_out.dvalid <= '0';
end if; end if;
when SUBFRAME_HEADER => when SUBFRAME_HEADER =>
crc_en <= '1'; crc_en <= '1';
crc_reset <= '0'; crc_reset <= '0';
...@@ -498,10 +647,10 @@ begin -- rtl ...@@ -498,10 +647,10 @@ begin -- rtl
end if; end if;
if(ser_count = g_data_width/16-1) then if(ser_count = g_data_width/16-1) then
word_count <= word_count + 1; word_count <= word_count + 1;
ser_count <= (others => '0'); ser_count <= (others => '0');
else else
ser_count <= ser_count + 1; ser_count <= ser_count + 1;
end if; end if;
fsm_out.data <= tx_fifo_q((to_integer(ser_count) + 1)* 16 -1 downto to_integer(ser_count) * 16); fsm_out.data <= tx_fifo_q((to_integer(ser_count) + 1)* 16 -1 downto to_integer(ser_count) * 16);
...@@ -535,7 +684,7 @@ begin -- rtl ...@@ -535,7 +684,7 @@ begin -- rtl
if(fsm_out.dreq = '1') then if(fsm_out.dreq = '1') then
fsm_escape <= '1'; fsm_escape <= '1';
fsm_out.dvalid <= '1'; fsm_out.dvalid <= '1';
fsm_out.data <= x"0bad"; fsm_out.data <= x"0bad";
if(total_words >= c_min_packet_size) then if(total_words >= c_min_packet_size) then
state <= EOF; state <= EOF;
end if; end if;
...@@ -544,13 +693,13 @@ begin -- rtl ...@@ -544,13 +693,13 @@ begin -- rtl
fsm_out.dvalid <= '0'; fsm_out.dvalid <= '0';
fsm_out.data <= (others => 'X'); fsm_out.data <= (others => 'X');
end if; end if;
when EOF => when EOF =>
fsm_out.dvalid <= '0'; fsm_out.dvalid <= '0';
if(fsm_out.dreq = '1') then if(fsm_out.dreq = '1') then
fsm_out.eof <= '1'; fsm_out.eof <= '1';
tx_frame_p1_o <= '1'; tx_frame_p1_o <= '1';
state <= IDLE; state <= IDLE;
end if; end if;
end case; end case;
end if; end if;
...@@ -580,25 +729,64 @@ begin -- rtl ...@@ -580,25 +729,64 @@ begin -- rtl
-- link_ok, i.e. we do not accept requests when link_ok is false. -- link_ok, i.e. we do not accept requests when link_ok is false.
-- During operation (i.e. after start-up/reset, the behaviour of link_ok -- During operation (i.e. after start-up/reset, the behaviour of link_ok
-- signal is satisfactory -- signal is satisfactory
p_delay_reset: process(clk_sys_i) p_delay_reset : process(clk_sys_i)
begin begin
if rising_edge(clk_sys_i) then if rising_edge(clk_sys_i) then
if rst_n_i = '0' then if rst_n_i = '0' then
if(g_simulation = 1) then if(g_simulation = 1) then
link_ok_delay_cnt <= c_link_ok_rst_delay_sim; link_ok_delay_cnt <= c_link_ok_rst_delay_sim;
else
link_ok_delay_cnt <= c_link_ok_rst_delay;
end if;
else else
-- first initial moments of link_ok_i high are ignored link_ok_delay_cnt <= c_link_ok_rst_delay;
if(link_ok_i = '1' and link_ok_delay_cnt > 0) then
link_ok_delay_cnt <= link_ok_delay_cnt-1;
end if;
end if; end if;
link_ok_delay_expired <= '0';
else
-- first initial moments of link_ok_i high are ignored
if(link_ok_i = '1' and link_ok_delay_cnt > 0) then
link_ok_delay_cnt <= link_ok_delay_cnt-1;
end if;
if link_ok_delay_cnt > 0 then
link_ok_delay_expired <= '0';
else
link_ok_delay_expired <= '1';
end if;
end if; end if;
end process; end if;
end process;
U_SyncReset_to_RefClk : gc_sync_ffs
port map (
clk_i => clk_ref_i,
rst_n_i => '1',
data_i => rst_n_i,
synced_o => rst_n_ref);
U_SyncLinkOK_to_RefClk : gc_sync_ffs
port map (
clk_i => clk_ref_i,
rst_n_i => rst_n_ref,
data_i => link_ok_i,
synced_o => link_ok_ref);
U_SyncLinkDelayExpired_to_RefClk : gc_sync_ffs
port map (
clk_i => clk_ref_i,
rst_n_i => rst_n_ref,
data_i => link_ok_delay_expired,
synced_o => link_ok_delay_expired_ref);
p_tx_dreq_gen : process(link_ok_delay_expired_ref, tx_almost_full, link_ok_ref)
begin
if link_ok_delay_expired_ref = '0' then
tx_dreq_o <= '0';
else
tx_dreq_o <= not tx_almost_full and link_ok_ref;
end if;
end process;
tx_dreq_o <= '0' when (link_ok_delay_cnt > 0) else
(not tx_almost_full) and link_ok_i;
end rtl; end rtl;
...@@ -75,6 +75,12 @@ entity xwr_streamers is ...@@ -75,6 +75,12 @@ entity xwr_streamers is
-- 125MHz for WR Nodes. There are some WR Nodes that work with 62.5MHz. -- 125MHz for WR Nodes. There are some WR Nodes that work with 62.5MHz.
-- in the future, more frequences might be supported.. -- in the future, more frequences might be supported..
g_clk_ref_rate : integer := 125000000; g_clk_ref_rate : integer := 125000000;
-- when non-zero, the datapath (tx_/rx_ ports) are in the clk_ref_i clock
-- domain instead of clk_sys_i. This is a must for fixed latency mode if
-- clk_sys_i is asynchronous (i.e. not locked) to the WR timing.
g_use_ref_clock_for_data : integer := 0;
----------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------
-- Transmission/reception parameters -- Transmission/reception parameters
----------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------
...@@ -97,11 +103,22 @@ entity xwr_streamers is ...@@ -97,11 +103,22 @@ entity xwr_streamers is
); );
port ( port (
---------------------------------------------------------------------------
-- Clocks & Resets
---------------------------------------------------------------------------
-- System clock. Used always for the WR fabric interface (src/snk) and
-- for the data path (tx_/rx_ ports) if g_use_ref_clock_for_data = 0.
clk_sys_i : in std_logic; clk_sys_i : in std_logic;
-- WR Reference clock, 62.5 or 125 MHz. Frequency must match g_ref_clk_rate
-- generic. Used for latency measurement and timestamping (tm_ ports).
-- It also clocks Tx_/rx_ interfaces if g_use_ref_clock_for_data != 0.
clk_ref_i : in std_logic := '0';
rst_n_i : in std_logic; rst_n_i : in std_logic;
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- WR tx/rx interface -- WR tx/rx interface (clk_sys clock domain)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- Tx -- Tx
src_i : in t_wrf_source_in; src_i : in t_wrf_source_in;
...@@ -110,8 +127,9 @@ entity xwr_streamers is ...@@ -110,8 +127,9 @@ entity xwr_streamers is
snk_i : in t_wrf_sink_in; snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out; snk_o : out t_wrf_sink_out;
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- User tx interface -- User tx interface (clk_data clock domain)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- Data word to be sent. -- Data word to be sent.
tx_data_i : in std_logic_vector(g_tx_streamer_params.data_width-1 downto 0); tx_data_i : in std_logic_vector(g_tx_streamer_params.data_width-1 downto 0);
...@@ -146,8 +164,6 @@ entity xwr_streamers is ...@@ -146,8 +164,6 @@ entity xwr_streamers is
-- WRC Timing interface, used for latency measurement -- WRC Timing interface, used for latency measurement
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- White Rabbit reference clock
clk_ref_i : in std_logic := '0';
-- Time valid flag -- Time valid flag
tm_time_valid_i : in std_logic := '0'; tm_time_valid_i : in std_logic := '0';
-- TAI seconds -- TAI seconds
...@@ -220,13 +236,14 @@ begin ...@@ -220,13 +236,14 @@ begin
g_tx_timeout => g_tx_streamer_params.timeout, g_tx_timeout => g_tx_streamer_params.timeout,
g_escape_code_disable => g_tx_streamer_params.escape_code_disable, g_escape_code_disable => g_tx_streamer_params.escape_code_disable,
g_simulation => g_simulation, g_simulation => g_simulation,
g_clk_ref_rate => g_clk_ref_rate) g_clk_ref_rate => g_clk_ref_rate,
g_use_ref_clock_for_data => g_use_ref_clock_for_data)
port map( port map(
clk_sys_i => clk_sys_i, clk_sys_i => clk_sys_i,
clk_ref_i => clk_ref_i,
rst_n_i => rst_n_i, rst_n_i => rst_n_i,
src_i => src_i, src_i => src_i,
src_o => src_o, src_o => src_o,
clk_ref_i => clk_ref_i,
tm_time_valid_i => tm_time_valid_i, tm_time_valid_i => tm_time_valid_i,
tm_tai_i => tm_tai_i, tm_tai_i => tm_tai_i,
tm_cycles_i => tm_cycles_i, tm_cycles_i => tm_cycles_i,
...@@ -471,4 +488,4 @@ begin ...@@ -471,4 +488,4 @@ begin
rx_streamer_cfg_i.filter_remote; rx_streamer_cfg_i.filter_remote;
rx_streamer_cfg.fixed_latency <= from_wb.rx_cfg5_fixed_latency_o when (from_wb.cfg_or_rx_fix_lat_o='1') else rx_streamer_cfg.fixed_latency <= from_wb.rx_cfg5_fixed_latency_o when (from_wb.cfg_or_rx_fix_lat_o='1') else
rx_streamer_cfg_i.fixed_latency; rx_streamer_cfg_i.fixed_latency;
end rtl; end rtl;
\ No newline at end of file
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