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",
"wr_streamers_wb.vhd",
"streamers_priv_pkg.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
g_escape_code_disable : boolean := FALSE;
g_simulation : integer := 0;
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 (
clk_sys_i : in std_logic;
clk_ref_i : in std_logic := '0';
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";
......@@ -294,7 +295,8 @@ package streamers_pkg is
-- WB i/f
g_slave_mode : t_wishbone_interface_mode := CLASSIC;
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 (
......@@ -333,4 +335,4 @@ package streamers_pkg is
);
end component;
end streamers_pkg;
\ No newline at end of file
end streamers_pkg;
......@@ -46,7 +46,7 @@ use work.streamers_priv_pkg.all;
use work.streamers_pkg.all;
entity xrx_streamer is
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
......@@ -54,16 +54,16 @@ entity xrx_streamer is
-- 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
-- in the network.
g_data_width : integer := 32;
g_data_width : integer := 32;
-- 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
-- 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
-- sent/expected.
g_escape_code_disable : boolean := FALSE;
g_escape_code_disable : boolean := false;
-- DO NOT USE unless you know what you are doing
-- legacy: the streamers that were initially used in Btrain accepted only a fixed
......@@ -76,11 +76,15 @@ entity xrx_streamer 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.
-- 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 (
clk_sys_i : in std_logic;
-- White Rabbit reference clock
clk_ref_i : in std_logic := '0';
rst_n_i : in std_logic;
-- Endpoint/WRC interface
......@@ -92,8 +96,6 @@ entity xrx_streamer is
-- 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';
......@@ -109,34 +111,34 @@ entity xrx_streamer is
---------------------------------------------------------------------------
-- 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.
rx_last_p1_o : out std_logic;
rx_last_p1_o : out std_logic;
-- 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.
rx_valid_o : out std_logic;
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;
rx_dreq_i : in std_logic;
-- Lost output: 1 indicates that one or more frames or blocks have been lost
-- (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
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
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
rx_lost_frames_cnt_o : out std_logic_vector(14 downto 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);
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;
-- received streamer frame (counts all frames, corrupted and not)
rx_frame_p1_o : out std_logic;
rx_latency_valid_o : out std_logic;
-- received streamer frame (counts all frames, corrupted and not)
rx_frame_p1_o : out std_logic;
-- 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;
......@@ -149,8 +151,8 @@ architecture rtl of xrx_streamer is
signal state : t_rx_state;
signal ser_count : unsigned(7 downto 0);
signal seq_no, seq_new,count : unsigned(14 downto 0);
signal ser_count : unsigned(7 downto 0);
signal seq_no, seq_new, count : unsigned(14 downto 0);
signal crc_match, crc_en, crc_en_masked, crc_restart : std_logic;
......@@ -161,34 +163,34 @@ architecture rtl of xrx_streamer is
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_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 tx_tag_cycles, rx_tag_cycles : std_logic_vector(27 downto 0);
signal tx_tag_valid, rx_tag_valid : std_logic;
signal rx_tag_valid_stored : std_logic;
signal got_next_subframe : std_logic;
signal is_frame_seq_id : std_logic;
signal word_count : unsigned(11 downto 0);
signal sync_seq_no : std_logic;
-- fixed latency signals
type t_rx_delay_state is (DISABLED, DELAY, ALLOW);
signal timestamped : std_logic;
signal delay_cnt : unsigned(27 downto 0);
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;
signal is_frame_seq_id : std_logic;
signal word_count : unsigned(11 downto 0);
signal sync_seq_no : std_logic;
signal rx_latency : unsigned(27 downto 0);
signal rx_latency_stored : unsigned(27 downto 0);
signal rx_latency_valid : std_logic;
signal is_vlan : std_logic;
constant c_fixed_latency_zero : unsigned(27 downto 0) := (others => '0');
constant c_timestamper_delay : unsigned(27 downto 0) := to_unsigned(12, 28); -- cycles
constant c_timestamper_delay : unsigned(27 downto 0) := to_unsigned(12, 28); -- cycles
signal fifo_last_int : std_logic;
begin -- rtl
U_rx_crc_generator : gc_crc_gen
......@@ -227,7 +229,7 @@ begin -- rtl
dreq_i => fab.dreq);
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
generic map (
g_data_width => 16,
......@@ -244,44 +246,19 @@ begin -- rtl
d_valid_o => fsm_in.dvalid,
d_req_i => fsm_in.dreq);
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.data <= fab.data;
fab.dreq <= fsm_in.dreq;
is_escape <= '0';
end generate gen_no_escape;
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 + 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
generic map(
g_ref_clk_rate => g_clk_ref_rate)
g_ref_clk_rate => g_clk_ref_rate)
port map (
clk_ref_i => clk_ref_i,
clk_sys_i => clk_sys_i,
......@@ -290,66 +267,84 @@ begin -- rtl
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);
tag_cycles_o => rx_tag_cycles,
tag_valid_o => rx_tag_valid);
-------------------------------------------------------------------------------------------
-- fixed latency implementation
-------------------------------------------------------------------------------------------
fifo_last_int <= fifo_last or ((not pending_write) and is_escape); -- when word is 16 bit
-- mask rx_dreq to prevent reception
rx_dreq <= rx_dreq_i and rx_dreq_allow;
-- produce a pulse when SOF is timestamped, this pulse starts counter in clk_sys clock
-- domain
U_sync_with_clk : gc_sync_ffs
U_FixLatencyDelay : entity work.fixed_latency_delay
generic map (
g_data_width => g_data_width,
g_buffer_size => 32,
g_use_ref_clock_for_data => g_use_ref_clock_for_data,
g_clk_ref_rate => g_clk_ref_rate)
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_i,
data_i => fsm_in.sof,
synced_o => timestamped);
-- introduce fixed latency, if configured to do so
p_fixed_latency_fsm : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
delay_state <= DISABLED;
rx_latency_stored <= (others=>'0');
rx_dreq_allow <= '1';
delay_cnt <= c_timestamper_delay;
else
case delay_state is
when DISABLED =>
if unsigned(rx_streamer_cfg_i.fixed_latency) /= c_fixed_latency_zero then
delay_state <= ALLOW;
end if;
rx_latency_stored <= (others=>'0');
delay_cnt <= c_timestamper_delay;
rx_dreq_allow <= '1';
when ALLOW =>
if unsigned(rx_streamer_cfg_i.fixed_latency) = c_fixed_latency_zero then
delay_state <= DISABLED;
elsif(rx_latency_valid ='1') then
rx_dreq_allow <= '0';
rx_latency_stored <= rx_latency;
delay_state <= DELAY;
end if;
if(timestamped = '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;
rst_n_i => rst_n_i,
clk_sys_i => clk_sys_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,
d_data_i => fifo_data,
d_last_i => fifo_last_int,
d_sync_i => fifo_sync,
d_target_ts_en_i => fifo_target_ts_en,
d_target_ts_i => std_logic_vector(fifo_target_ts),
d_valid_i => fifo_dvalid,
d_drop_i => fifo_drop,
d_accept_i => fifo_accept_d0,
d_req_o => fsm_in.dreq,
rx_first_p1_o => rx_first_p1_o,
rx_last_p1_o => rx_last_p1_o,
rx_data_o => rx_data_o,
rx_valid_o => rx_valid_o,
rx_dreq_i => rx_dreq_i,
rx_streamer_cfg_i => rx_streamer_cfg_i);
-- introduce fixed latency, if configured to do so
-- p_fixed_latency_fsm : process(clk_sys_i)
-- begin
-- if rising_edge(clk_sys_i) then
-- if rst_n_i = '0' then
-- delay_state <= DISABLED;
-- rx_latency_stored <= (others => '0');
-- rx_dreq_allow <= '1';
-- delay_cnt <= c_timestamper_delay;
-- else
-- case delay_state is
-- when DISABLED =>
-- if unsigned(rx_streamer_cfg_i.fixed_latency) /= c_fixed_latency_zero then
-- delay_state <= ALLOW;
-- end if;
-- rx_latency_stored <= (others => '0');
-- delay_cnt <= c_timestamper_delay;
-- rx_dreq_allow <= '1';
-- when ALLOW =>
-- if unsigned(rx_streamer_cfg_i.fixed_latency) = c_fixed_latency_zero then
-- delay_state <= DISABLED;
-- elsif(rx_latency_valid = '1') then
-- rx_dreq_allow <= '0';
-- rx_latency_stored <= rx_latency;
-- delay_state <= DELAY;
-- 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
......@@ -359,56 +354,57 @@ begin -- rtl
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
state <= IDLE;
count <= (others => '0');
seq_no <= (others => '1');
detect_escapes <= '0';
crc_en <= '0';
fifo_accept <= '0';
fifo_drop <= '0';
fifo_dvalid <= '0';
pending_write <= '0';
got_next_subframe <= '0';
fifo_sync <= '0';
fifo_last <= '0';
tx_tag_valid <= '0';
ser_count <= (others => '0');
word_count <= (others => '0');
sync_seq_no <= '1';
rx_frame_p1_o <= '0';
rx_lost_frames_cnt_o <= (others => '0');
frames_lost <= '0';
rx_latency <= (others=>'0');
rx_latency_valid <= '0';
blocks_lost <= '0';
pack_data <= (others=>'0');
is_vlan <= '0';
state <= IDLE;
count <= (others => '0');
seq_no <= (others => '1');
detect_escapes <= '0';
crc_en <= '0';
fifo_accept <= '0';
fifo_drop <= '0';
fifo_dvalid <= '0';
pending_write <= '0';
got_next_subframe <= '0';
fifo_sync <= '0';
fifo_last <= '0';
tx_tag_valid <= '0';
ser_count <= (others => '0');
word_count <= (others => '0');
sync_seq_no <= '1';
rx_frame_p1_o <= '0';
rx_lost_frames_cnt_o <= (others => '0');
frames_lost <= '0';
rx_latency <= (others => '0');
rx_latency_valid <= '0';
blocks_lost <= '0';
pack_data <= (others => '0');
is_vlan <= '0';
rx_tag_valid_stored <= '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';
got_next_subframe <='0';
ser_count <= (others => '0');
fifo_sync <='0';
fifo_last <= '0';
word_count <= (others => '0');
tx_tag_valid <= '0';
rx_frame_p1_o <= '0';
detect_escapes <= '0';
crc_en <= '0';
count <= (others => '0');
fifo_accept <= '0';
fifo_drop <= '0';
fifo_dvalid <= '0';
pending_write <= '0';
got_next_subframe <= '0';
ser_count <= (others => '0');
fifo_sync <= '0';
fifo_last <= '0';
word_count <= (others => '0');
tx_tag_valid <= '0';
rx_frame_p1_o <= '0';
rx_lost_frames_cnt_o <= (others => '0');
frames_lost <= '0';
blocks_lost <= '0';
rx_latency <= (others=>'0');
rx_latency <= (others => '0');
rx_latency_valid <= '0';
is_vlan <= '0';
rx_tag_valid_stored <= '0';
if(fsm_in.sof = '1') then
state <= HEADER;
state <= HEADER;
end if;
when HEADER =>
......@@ -432,32 +428,32 @@ begin -- rtl
end if;
count <= count + 1;
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;
end if;
count <= count + 1;
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;
end if;
count <= count + 1;
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;
end if;
count <= count + 1;
when x"06" =>
if(fsm_in.data = x"8100") then
is_vlan <='1';
is_vlan <= '1';
elsif(fsm_in.data /= rx_streamer_cfg_i.ethertype) then
state <= IDLE;
is_vlan <='0';
is_vlan <= '0';
end if;
count <= count + 1;
when x"07" =>
if(is_vlan = '0') then
tx_tag_valid <= fsm_in.data(15);
tx_tag_cycles(27 downto 16)<= fsm_in.data(11 downto 0);
tx_tag_valid <= fsm_in.data(15);
tx_tag_cycles(27 downto 16) <= fsm_in.data(11 downto 0);
end if;
count <= count + 1;
when x"08" =>
......@@ -473,9 +469,9 @@ begin -- rtl
end if;
count <= count + 1;
when x"09" =>
tx_tag_valid <= fsm_in.data(15);
tx_tag_cycles(27 downto 16)<= fsm_in.data(11 downto 0);
count <= count + 1;
tx_tag_valid <= fsm_in.data(15);
tx_tag_cycles(27 downto 16) <= fsm_in.data(11 downto 0);
count <= count + 1;
when x"0A" =>
tx_tag_cycles(15 downto 0) <= fsm_in.data;
count <= count + 1;
......@@ -483,24 +479,35 @@ begin -- rtl
detect_escapes <= '1';
state <= FRAME_SEQ_ID;
rx_frame_p1_o <= '1';
count <= count + 1;
count <= count + 1;
when others => null;
end case;
end if;
when FRAME_SEQ_ID =>
rx_frame_p1_o <= '0';
rx_frame_p1_o <= '0';
if(fsm_in.eof = '1') then
state <= IDLE;
elsif(fsm_in.dvalid = '1') then
count <= "000" & x"001"; -- use as subframe seq_no
state <= PAYLOAD;
fifo_drop <= '0';
fifo_accept <= '0';
ser_count <= (others => '0');
word_count <= word_count + 1; -- count words, increment in advance
got_next_subframe <= '1';
if(tx_tag_valid = '1') then
count <= "000" & x"001"; -- use as subframe seq_no
state <= PAYLOAD;
fifo_drop <= '0';
fifo_accept <= '0';
ser_count <= (others => '0');
word_count <= word_count + 1; -- count words, increment in advance
got_next_subframe <= '1';
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';
if(unsigned(tx_tag_cycles) > unsigned(rx_tag_cycles)) then
rx_latency <= unsigned(rx_tag_cycles) - unsigned(tx_tag_cycles) + to_unsigned(125000000, 28);
......@@ -511,62 +518,72 @@ begin -- rtl
else
rx_latency_valid <= '0';
end if;
rx_tag_valid_stored <= '0';
if(std_logic_vector(seq_no) /= fsm_in.data(14 downto 0)) then
seq_no <= unsigned(fsm_in.data(14 downto 0))+1;
if (sync_seq_no = '1') then -- sync to the first received seq_no
sync_seq_no <= '0';
frames_lost <= '0';
seq_no <= unsigned(fsm_in.data(14 downto 0))+1;
if (sync_seq_no = '1') then -- sync to the first received seq_no
sync_seq_no <= '0';
frames_lost <= '0';
rx_lost_frames_cnt_o <= (others => '0');
else
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;
else
seq_no <= unsigned(seq_no + 1);
frames_lost <= '0';
seq_no <= unsigned(seq_no + 1);
frames_lost <= '0';
rx_lost_frames_cnt_o <= (others => '0');
end if;
end if;
when SUBFRAME_HEADER =>
if fifo_dvalid = '1' then
fifo_target_ts_en <= '0';
end if;
fifo_drop <= '0';
fifo_accept <= '0';
ser_count <= (others => '0');
ser_count <= (others => '0');
if(fsm_in.eof = '1') then
state <= IDLE;
state <= IDLE;
got_next_subframe <= '0';
blocks_lost <= '0';
blocks_lost <= '0';
elsif (fsm_in.dvalid = '1' and is_escape = '1') then
got_next_subframe <= '1';
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';
else
count <= count + 1;
count <= count + 1;
blocks_lost <= '0';
end if;
state <= PAYLOAD;
end if;
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_latency_valid <= '0';
fifo_sync <= got_next_subframe;
rx_latency_valid <= '0';
fifo_sync <= got_next_subframe;
if(fsm_in.eof = '1') then
state <= IDLE;
fifo_drop <= '1';
fifo_accept <= '0';
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';
......@@ -574,99 +591,107 @@ begin -- rtl
got_next_subframe <= '1';
if(fsm_in.data(15) = '1') 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';
else
count <= unsigned(count + 1);
count <= unsigned(count + 1);
blocks_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';
pending_write <= '0';
elsif fsm_in.data = x"0bad" then
blocks_lost <= '0';
blocks_lost <= '0';
state <= EOF;
fifo_accept <= crc_match; --_latched;
fifo_drop <= not crc_match; --_latched;
fifo_dvalid <= pending_write and not fifo_dvalid;
else
blocks_lost <= '0';
blocks_lost <= '0';
state <= EOF;
fifo_drop <= '1';
fifo_accept <= '0';
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_accept <= '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;
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
fifo_sync <= got_next_subframe;
fifo_data(g_data_width-1 downto 0) <= pack_data(g_data_width-1 downto 0);
fifo_dvalid <= not is_escape;
pending_write <= '0';
if (ser_count = x"00") then -- ML: the case when g_data_width == 16
fifo_sync <= got_next_subframe;
fifo_data(g_data_width-1 downto 0) <= pack_data(g_data_width-1 downto 0);
fifo_dvalid <= not is_escape;
pending_write <= '0';
else
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-1 downto g_data_width-16) <= fsm_in.data;
fifo_dvalid <= '0';
pending_write <= '1';
end if;
if(word_count = g_expected_words_number) then
state <= EOF;
fifo_accept <= '1';
fifo_drop <= '0';
fifo_accept <= '1';
fifo_drop <= '0';
fifo_dvalid <= '1';
else
word_count <= word_count + 1;
end if;
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;
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 --of: elsif(fsm_in.dvalid = '1') then
else --of: elsif(fsm_in.dvalid = '1') then
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
......@@ -679,6 +704,6 @@ begin -- rtl
rx_lost_frames_p1_o <= frames_lost;
rx_latency_o <= std_logic_vector(rx_latency);
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;
......@@ -76,19 +76,28 @@ entity xtx_streamer is
-- simulation mode: it is set to override the startaup-timer, the value with which
-- 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)
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
-- 125MHz for WR Nodes. There are some WR Nodes that work with 62.5MHz.
-- 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 (
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
src_i : in t_wrf_source_in;
......@@ -99,8 +108,6 @@ entity xtx_streamer is
-- 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';
......@@ -112,9 +119,10 @@ entity xtx_streamer is
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
link_ok_i : in std_logic := '1';
link_ok_i : in std_logic := '1';
---------------------------------------------------------------------------
-- User interface
-- User interface
---------------------------------------------------------------------------
-- Data word to be sent.
......@@ -127,6 +135,10 @@ entity xtx_streamer is
-- the following clock cycle.
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
-- block of samples (see documentation for more details).
tx_last_p1_i : in std_logic := '1';
......@@ -137,11 +149,11 @@ entity xtx_streamer is
-- 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';
tx_reset_seq_i : in std_logic := '0';
-- successfully sent streamer frame
tx_frame_p1_o : out std_logic;
tx_frame_p1_o : out std_logic;
-- 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;
......@@ -155,13 +167,17 @@ architecture rtl of xtx_streamer is
signal tx_threshold_hit : std_logic;
signal tx_timeout_hit : 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_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 state : t_tx_state;
signal seq_no, count : unsigned(14 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 timeout_counter : unsigned(11 downto 0);
......@@ -176,14 +192,26 @@ architecture rtl of xtx_streamer is
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_valid, tag_valid_latched : std_logic;
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);
begin -- rtl
......@@ -193,11 +221,11 @@ begin -- rtl
-------------------------------------------------------------------------------------------
assert g_tx_buffer_size >= g_tx_threshold
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
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
......@@ -239,8 +267,8 @@ begin -- rtl
fab_src.sof <= fsm_out.sof;
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
generic map (
g_data_width => 16,
......@@ -258,7 +286,7 @@ begin -- rtl
d_valid_o => fab_src.dvalid,
d_req_i => fab_src.dreq);
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.dvalid <= fsm_out.dvalid;
fsm_out.dreq <= fab_src.dreq;
......@@ -267,41 +295,135 @@ begin -- rtl
tx_fifo_we <= tx_valid_i and not tx_fifo_full;
tx_fifo_d <= tx_last_p1_i & tx_data_i;
U_TX_Buffer : generic_sync_fifo
generic map (
g_data_width => g_data_width + 1,
g_size => g_tx_buffer_size,
g_with_almost_full => true,
g_with_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_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_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';
tx_threshold_hit <= '1' when tx_almost_empty = '0' and (buf_frame_count /= 0) else '0';
gen_use_sys_clock_for_data : if g_use_ref_clock_for_data = 0 generate
U_TX_Buffer : generic_sync_fifo
generic map (
g_data_width => g_data_width + 1,
g_size => g_tx_buffer_size,
g_with_almost_full => true,
g_with_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_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
);
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);
U_Timestamper : pulse_stamper
generic map(
g_ref_clk_rate => g_clk_ref_rate)
g_ref_clk_rate => g_clk_ref_rate)
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,
pulse_a_i => stamper_pulse_a,
tm_time_valid_i => tm_time_valid_i,
tm_tai_i => tm_tai_i,
tm_cycles_i => tm_cycles_i,
......@@ -309,20 +431,21 @@ begin -- rtl
tag_cycles_o => tag_cycles,
tag_valid_o => tag_valid);
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_p1_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_p1_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;
buf_frame_count_inc_ref <= tx_fifo_we and tx_last_p1_i;
buf_frame_count_dec_sys <= tx_fifo_rd and tx_fifo_last;
U_FrameCounter: entity work.gc_async_counter_diff
generic map (
g_bits => 5,
g_output_clock => "dec")
port map (
rst_n_i => rst_n_i,
clk_inc_i => clk_data,
clk_dec_i => clk_sys_i,
inc_i => buf_frame_count_inc_ref,
dec_i => buf_frame_count_dec_sys,
counter_o => buf_frame_count);
p_tx_timeout : process(clk_sys_i)
begin
......@@ -346,20 +469,32 @@ begin -- rtl
end if;
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)
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';
fsm_out.data <= (others => '0');
count <= (others => '0');
seq_no <= (others => '0');
word_count <= (others => '0');
crc_en <= '0';
crc_reset <= '1';
state <= IDLE;
fsm_out.sof <= '0';
fsm_out.eof <= '0';
fsm_out.dvalid <= '0';
fsm_out.data <= (others => '0');
count <= (others => '0');
seq_no <= (others => '0');
word_count <= (others => '0');
crc_en <= '0';
crc_reset <= '1';
tx_frame_p1_o <= '0';
tag_valid_latched <= '0';
tx_flush_latched <= '0';
......@@ -370,19 +505,19 @@ begin -- rtl
if(tx_reset_seq_i = '1') then
seq_no <= (others => '0');
end if;
if(tag_valid = '1') then
tag_valid_latched <= '1'; -- overriden in IDLE
if(tag_valid = '1') then
tag_valid_latched <= '1'; -- overriden in IDLE
end if;
tx_flush_latched <= '0';-- overriden in IDLE
tx_flush_latched <= '0'; -- overriden in IDLE
case state is
when IDLE =>
tag_valid_latched <= '0';
tx_flush_latched <= tx_flush_p1_i or tx_timeout_hit;
crc_en <= '0';
crc_reset <= '0';
fsm_out.eof <= '0';
tx_frame_p1_o <= '0';
crc_en <= '0';
crc_reset <= '0';
fsm_out.eof <= '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
state <= SOF;
......@@ -401,6 +536,8 @@ begin -- rtl
when ETH_HEADER =>
if(fsm_out.dreq = '1') then
fsm_out.dvalid <= '1';
case count(7 downto 0) is
when x"00" =>
fsm_out.data <= tx_streamer_cfg_i.mac_target(47 downto 32);
......@@ -416,6 +553,7 @@ begin -- rtl
count <= count + 1;
when x"04" =>
fsm_out.data <= tx_streamer_cfg_i.mac_local(31 downto 16);
count <= count + 1;
when x"05" =>
fsm_out.data <= tx_streamer_cfg_i.mac_local(15 downto 0);
......@@ -426,14 +564,21 @@ begin -- rtl
else
fsm_out.data <= x"8100";
end if;
count <= count + 1;
count <= count + 1;
when x"07" =>
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
fsm_out.data <= tx_streamer_cfg_i.qtag_prio & '0' & tx_streamer_cfg_i.qtag_vid;
count <= count + 1;
end if;
count <= count + 1;
when x"08" =>
if(tx_streamer_cfg_i.qtag_ena = '0') then
fsm_out.data <= tag_cycles(15 downto 0);
......@@ -441,10 +586,15 @@ begin -- rtl
else
fsm_out.data <= tx_streamer_cfg_i.ethertype;
end if;
count <= count + 1;
count <= count + 1;
when x"09" =>
fsm_out.data <= tag_valid_latched & "000" & tag_cycles(27 downto 16);
count <= count + 1;
if tag_valid_latched = '1' then
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" =>
fsm_out.data <= tag_cycles(15 downto 0);
state <= FRAME_SEQ_ID;
......@@ -453,7 +603,6 @@ begin -- rtl
fsm_out.data <= (others => 'X');
count <= (others => 'X');
end case;
fsm_out.dvalid <= '1';
else
fsm_out.dvalid <= '0';
end if;
......@@ -469,9 +618,9 @@ begin -- rtl
crc_reset <= '0';
state <= PAYLOAD;
else
fsm_out.dvalid <= '0';
fsm_out.dvalid <= '0';
end if;
when SUBFRAME_HEADER =>
crc_en <= '1';
crc_reset <= '0';
......@@ -498,10 +647,10 @@ begin -- rtl
end if;
if(ser_count = g_data_width/16-1) then
word_count <= word_count + 1;
ser_count <= (others => '0');
word_count <= word_count + 1;
ser_count <= (others => '0');
else
ser_count <= ser_count + 1;
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);
......@@ -535,7 +684,7 @@ begin -- rtl
if(fsm_out.dreq = '1') then
fsm_escape <= '1';
fsm_out.dvalid <= '1';
fsm_out.data <= x"0bad";
fsm_out.data <= x"0bad";
if(total_words >= c_min_packet_size) then
state <= EOF;
end if;
......@@ -544,13 +693,13 @@ begin -- rtl
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';
tx_frame_p1_o <= '1';
state <= IDLE;
fsm_out.eof <= '1';
tx_frame_p1_o <= '1';
state <= IDLE;
end if;
end case;
end if;
......@@ -580,25 +729,64 @@ begin -- rtl
-- 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
-- signal is satisfactory
p_delay_reset: process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
if(g_simulation = 1) then
link_ok_delay_cnt <= c_link_ok_rst_delay_sim;
else
link_ok_delay_cnt <= c_link_ok_rst_delay;
end if;
p_delay_reset : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
if(g_simulation = 1) then
link_ok_delay_cnt <= c_link_ok_rst_delay_sim;
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;
link_ok_delay_cnt <= c_link_ok_rst_delay;
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 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;
......@@ -75,6 +75,12 @@ entity xwr_streamers is
-- 125MHz for WR Nodes. There are some WR Nodes that work with 62.5MHz.
-- in the future, more frequences might be supported..
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
-----------------------------------------------------------------------------------------
......@@ -97,11 +103,22 @@ entity xwr_streamers is
);
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;
-- 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;
---------------------------------------------------------------------------
-- WR tx/rx interface
-- WR tx/rx interface (clk_sys clock domain)
---------------------------------------------------------------------------
-- Tx
src_i : in t_wrf_source_in;
......@@ -110,8 +127,9 @@ entity xwr_streamers is
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
---------------------------------------------------------------------------
-- User tx interface
-- User tx interface (clk_data clock domain)
---------------------------------------------------------------------------
-- Data word to be sent.
tx_data_i : in std_logic_vector(g_tx_streamer_params.data_width-1 downto 0);
......@@ -146,8 +164,6 @@ entity xwr_streamers is
-- WRC Timing interface, used for latency measurement
---------------------------------------------------------------------------
-- White Rabbit reference clock
clk_ref_i : in std_logic := '0';
-- Time valid flag
tm_time_valid_i : in std_logic := '0';
-- TAI seconds
......@@ -220,13 +236,14 @@ begin
g_tx_timeout => g_tx_streamer_params.timeout,
g_escape_code_disable => g_tx_streamer_params.escape_code_disable,
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(
clk_sys_i => clk_sys_i,
clk_ref_i => clk_ref_i,
rst_n_i => rst_n_i,
src_i => src_i,
src_o => src_o,
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,
......@@ -471,4 +488,4 @@ begin
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_i.fixed_latency;
end rtl;
\ No newline at end of file
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