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

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

added gc_async_counter_diff to general-cores, thus
updating the submodules
parent 23991f9b
Subproject commit 4e5f7badf0b72f51bdb01c63fcdc6d69afb4b750
Subproject commit e071a1065e0db20983a6f44f818c1a0111431b6d
......@@ -12,5 +12,8 @@ files = ["streamers_pkg.vhd",
"wr_streamers_wb.vhd",
"streamers_priv_pkg.vhd",
"xtx_streamers_stats.vhd",
"xrx_streamers_stats.vhd"
]
"xrx_streamers_stats.vhd",
"fixed_latency_delay.vhd",
"fixed_latency_ts_match.vhd",
"fifo_showahead_adapter.vhd"
];
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;
......@@ -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;
......@@ -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';
......@@ -161,33 +163,32 @@ 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;
constant c_fixed_latency_zero : unsigned(27 downto 0) := (others => '0');
constant c_timestamper_delay : unsigned(27 downto 0) := to_unsigned(12, 28); -- cycles
signal fifo_last_int : std_logic;
begin -- rtl
......@@ -253,35 +254,9 @@ begin -- rtl
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 +265,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
......@@ -383,6 +376,7 @@ begin -- rtl
blocks_lost <= '0';
pack_data <= (others=>'0');
is_vlan <= '0';
rx_tag_valid_stored <= '0';
else
case state is
when IDLE =>
......@@ -406,7 +400,7 @@ begin -- rtl
rx_latency <= (others=>'0');
rx_latency_valid <= '0';
is_vlan <= '0';
rx_tag_valid_stored <= '0';
if(fsm_in.sof = '1') then
state <= HEADER;
end if;
......@@ -500,7 +494,18 @@ begin -- rtl
ser_count <= (others => '0');
word_count <= word_count + 1; -- count words, increment in advance
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';
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,6 +516,8 @@ 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;
......@@ -530,6 +537,10 @@ begin -- rtl
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');
......@@ -552,6 +563,10 @@ begin -- rtl
end if;
when PAYLOAD =>
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';
......
......@@ -83,11 +83,19 @@ entity xtx_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;
-- 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;
-- White Rabbit reference clock
clk_ref_i : in std_logic := '0';
rst_n_i : in std_logic;
-- Endpoint/WRC interface - packet source
......@@ -99,8 +107,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';
......@@ -127,6 +133,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';
......@@ -155,8 +165,12 @@ 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);
......@@ -176,6 +190,9 @@ architecture rtl of xtx_streamer is
signal tx_almost_empty, tx_almost_full : std_logic;
signal buf_frame_count_inc_ref : std_logic;
signal buf_frame_count_dec_sys : std_logic;
signal buf_frame_count : unsigned(5 downto 0) := (others => '0');
......@@ -183,6 +200,15 @@ architecture rtl of xtx_streamer is
signal tag_valid, tag_valid_latched : std_logic;
signal link_ok_delay_cnt : unsigned(25 downto 0);
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);
......@@ -258,7 +284,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,6 +293,8 @@ begin -- rtl
tx_fifo_we <= tx_valid_i and not tx_fifo_full;
tx_fifo_d <= tx_last_p1_i & tx_data_i;
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,
......@@ -288,10 +316,102 @@ begin -- rtl
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';
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
......@@ -301,7 +421,7 @@ begin -- rtl
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 +429,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: 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,6 +467,18 @@ 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
......@@ -401,6 +534,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);
......@@ -429,11 +564,18 @@ begin -- rtl
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);
......@@ -443,8 +585,13 @@ begin -- rtl
end if;
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 +600,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,7 +615,7 @@ begin -- rtl
crc_reset <= '0';
state <= PAYLOAD;
else
fsm_out.dvalid <= '0';
fsm_out.dvalid <= '0';
end if;
when SUBFRAME_HEADER =>
......@@ -589,16 +735,52 @@ begin -- rtl
else
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 if;
end process;
tx_dreq_o <= '0' when (link_ok_delay_cnt > 0) else
(not tx_almost_full) and link_ok_i;
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;
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