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;
This diff is collapsed.
This diff is collapsed.
......@@ -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