1-------------------------------------------------------------------------------
2-- Title      : Transmission Streamer
3-- Project    : WR Streamers
4-- URL        : http://www.ohwr.org/projects/wr-cores/wiki/WR_Streamers
5-------------------------------------------------------------------------------
6-- File       : xrx_streamer.vhd
7-- Author     : Tomasz Wlostowski
8-- Company    : CERN BE-CO-HT
9-- Created    : 2012-11-02
10-- Platform   : FPGA-generic
11-- Standard   : VHDL
12-------------------------------------------------------------------------------
13-- Description: A simple core demonstrating how to encapsulate a continuous
14-- stream of data words into Ethernet frames, in a format that is accepted by
15-- the White Rabbit PTP core. This core decodes Ethernet frames encoded by
16-- xtx_streamer. More info in the documentation.
17-------------------------------------------------------------------------------
18-- Copyright (c) 2012-2017 CERN/BE-CO-HT
19--
20-- This source file is free software; you can redistribute it
21-- and/or modify it under the terms of the GNU Lesser General
22-- Public License as published by the Free Software Foundation;
23-- either version 2.1 of the License, or (at your option) any
24-- later version.
25--
26-- This source is distributed in the hope that it will be
27-- useful, but WITHOUT ANY WARRANTY; without even the implied
28-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
29-- PURPOSE.  See the GNU Lesser General Public License for more
30-- details.
31--
32-- You should have received a copy of the GNU Lesser General
33-- Public License along with this source; if not, download it
34-- from http://www.gnu.org/licenses/lgpl-2.1.html
35-------------------------------------------------------------------------------
36
37library ieee;
38use ieee.std_logic_1164.all;
39use ieee.numeric_std.all;
40
41use work.wishbone_pkg.all;
42use work.wr_fabric_pkg.all;
43use work.gencores_pkg.all;
44use work.genram_pkg.all;
45use work.streamers_priv_pkg.all;
46use work.streamers_pkg.all;
47
48entity xrx_streamer is
49
50  generic (
51    -- Width of the data words, must be multiple of 16 bits. This value set to this generic
52    -- on the receviving device must be the same as the value of g_tx_data_width set on the
53    -- transmitting node. The g_rx_data_width and g_tx_data_width can be set to different
54    -- values in the same device (i.e. instantiation of xwr_transmission entity). It is the
55    -- responsibility of a network designer to make sure these parameters are properly set
56    -- in the network.
57    g_data_width        : integer := 32;
58
59    -- Size of RX buffer, in data words.
60    g_buffer_size       : integer := 256;
61
62    -- DO NOT USE unless you know what you are doing
63    -- legacy: the streamers that were initially used in Btrain did not check/insert
64    -- the escape code. This is justified if only one block of a known number of words is
65    -- sent/expected.
66    g_escape_code_disable : boolean := FALSE;
67
68    -- DO NOT USE unless you know what you are doing
69    -- legacy: the streamers that were initially used in Btrain accepted only a fixed
70    -- number of words, regardless of the frame content. If this generic is set to number
71    -- other than zero, only a fixed number of words is accepted.
72    -- In combination with the g_escape_code_disable generic set to TRUE, the behaviour of
73    -- the "Btrain streamers" can be recreated.
74    g_expected_words_number : integer := 0
75    );
76
77  port (
78    clk_sys_i : in std_logic;
79    rst_n_i   : in std_logic;
80
81    -- Endpoint/WRC interface
82    snk_i : in  t_wrf_sink_in;
83    snk_o : out t_wrf_sink_out;
84
85    ---------------------------------------------------------------------------
86    -- WRC Timing interface, used for latency measurement
87    -- Caution: uses clk_ref_i clock domain!
88    ---------------------------------------------------------------------------
89
90    -- White Rabbit reference clock
91    clk_ref_i : in std_logic := '0';
92
93    -- Time valid flag
94    tm_time_valid_i : in std_logic := '0';
95
96    -- TAI seconds
97    tm_tai_i : in std_logic_vector(39 downto 0) := x"0000000000";
98
99    -- Fractional part of the second (in clk_ref_i cycles)
100    tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000";
101
102    ---------------------------------------------------------------------------
103    -- User interface
104    ---------------------------------------------------------------------------
105
106    -- 1 indicates the 1st word of the data block on rx_data_o.
107    rx_first_p1_o         : out std_logic;
108    -- 1 indicates the last word of the data block on rx_data_o.
109    rx_last_p1_o          : out std_logic;
110    -- Received data.
111    rx_data_o          : out std_logic_vector(g_data_width-1 downto 0);
112    -- 1 indicted that rx_data_o is outputting a valid data word.
113    rx_valid_o         : out std_logic;
114    -- Synchronous data request input: when 1, the streamer may output another
115    -- data word in the subsequent clock cycle.
116    rx_dreq_i          : in  std_logic;
117    -- Lost output: 1 indicates that one or more frames or blocks have been lost
118    -- (left for backward compatibility).
119    rx_lost_p1_o          : out std_logic := '0';
120    -- indicates that one or more blocks within frame are missing
121    rx_lost_blocks_p1_o    :  out std_logic := '0';
122    -- indicates that one or more frames are missing, the number of frames is provied
123    rx_lost_frames_p1_o    :  out std_logic := '0';
124    --number of lost frames, the 0xF...F means that counter overflew
125    rx_lost_frames_cnt_o : out std_logic_vector(14 downto 0);
126    -- Latency measurement output: indicates the transport latency (between the
127    -- TX streamer in remote device and this streamer), in clk_ref_i clock cycles.
128    rx_latency_o       : out std_logic_vector(27 downto 0);
129    -- 1 when the latency on rx_latency_o is valid.
130    rx_latency_valid_o : out std_logic;
131    -- received 	streamer frame (counts all frames, corrupted and not)
132    rx_frame_p1_o         : out std_logic;
133    -- configuration
134    rx_streamer_cfg_i     : in t_rx_streamer_cfg := c_rx_streamer_cfg_default
135    );
136
137end xrx_streamer;
138
139architecture rtl of xrx_streamer is
140
141  type t_rx_state is (IDLE, HEADER, FRAME_SEQ_ID, PAYLOAD, SUBFRAME_HEADER, EOF);
142
143  signal fab, fsm_in : t_pipe;
144
145  signal state : t_rx_state;
146
147  signal ser_count : unsigned(7 downto 0);
148  signal seq_no, seq_new,count  : unsigned(14 downto 0);
149
150  signal crc_match, crc_en, crc_en_masked, crc_restart : std_logic;
151
152  signal detect_escapes, is_escape : std_logic;
153  signal rx_pending                : std_logic;
154
155  signal pack_data, fifo_data : std_logic_vector(g_data_width-1 downto 0);
156
157  signal fifo_drop, fifo_accept, fifo_accept_d0, fifo_dvalid : std_logic;
158  signal fifo_sync, fifo_last, frames_lost, blocks_lost      : std_logic;
159  signal fifo_dout, fifo_din                                 : std_logic_vector(g_data_width + 1 downto 0);
160
161  signal pending_write, fab_dvalid_pre : std_logic;
162
163
164  signal tx_tag_cycles, rx_tag_cycles : std_logic_vector(27 downto 0);
165  signal tx_tag_valid, rx_tag_valid   : std_logic;
166
167  signal got_next_subframe : std_logic;
168  signal is_frame_seq_id : std_logic;
169  signal word_count                                                        : unsigned(11 downto 0);
170  signal sync_seq_no : std_logic;
171
172  -- fixed latency signals
173  type   t_rx_delay_state is (DISABLED, DELAY, ALLOW);
174  signal timestamped        : std_logic;
175  signal delay_cnt          : unsigned(27 downto 0);
176  signal rx_dreq_allow      : std_logic;
177  signal rx_latency         : unsigned(27 downto 0);
178  signal rx_latency_stored  : unsigned(27 downto 0);
179  signal rx_latency_valid   : std_logic;
180  signal delay_state        : t_rx_delay_state;
181  signal rx_dreq            : std_logic;
182  signal is_vlan            : std_logic;
183
184  constant c_fixed_latency_zero : unsigned(27 downto 0) := (others => '0');
185  constant c_timestamper_delay  : unsigned(27 downto 0) := to_unsigned(12, 28); -- cycles
186
187begin  -- rtl
188
189  U_rx_crc_generator : gc_crc_gen
190    generic map (
191      g_polynomial              => x"1021",
192      g_init_value              => x"ffff",
193      g_residue                 => x"470f",
194      g_data_width              => 16,
195      g_sync_reset              => 1,
196      g_dual_width              => 0,
197      g_registered_match_output => true)
198    port map (
199      clk_i     => clk_sys_i,
200      rst_i     => '0',
201      restart_i => crc_restart,
202      en_i      => crc_en_masked,
203      data_i    => fsm_in.data,
204      half_i    => '0',
205      match_o   => crc_match);
206
207  crc_en_masked <= crc_en and fsm_in.dvalid;
208
209  U_Fabric_Sink : xwb_fabric_sink
210    port map (
211      clk_i     => clk_sys_i,
212      rst_n_i   => rst_n_i,
213      snk_i     => snk_i,
214      snk_o     => snk_o,
215      addr_o    => fab.addr,
216      data_o    => fab.data,
217      dvalid_o  => fab_dvalid_pre,
218      sof_o     => fab.sof,
219      eof_o     => fab.eof,
220      error_o   => fab.error,
221      bytesel_o => fab.bytesel,
222      dreq_i    => fab.dreq);
223
224  fab.dvalid <= '1' when fab_dvalid_pre = '1' and fab.addr = c_WRF_DATA and fab.bytesel = '0' else '0';
225  gen_escape: if (g_escape_code_disable = FALSE) generate
226    U_Escape_Detect : escape_detector
227      generic map (
228        g_data_width  => 16,
229        g_escape_code => x"cafe")
230      port map (
231        clk_i             => clk_sys_i,
232        rst_n_i           => rst_n_i,
233        d_i               => fab.data,
234        d_detect_enable_i => detect_escapes,
235        d_valid_i         => fab.dvalid,
236        d_req_o           => fab.dreq,
237        d_o               => fsm_in.data,
238        d_escape_o        => is_escape,
239        d_valid_o         => fsm_in.dvalid,
240        d_req_i           => fsm_in.dreq);
241  end generate gen_escape;
242  gen_no_escape: if (g_escape_code_disable = TRUE) generate
243    fsm_in.dvalid <= fab.dvalid;
244    fsm_in.data   <= fab.data;
245    fab.dreq      <= fsm_in.dreq;
246    is_escape     <= '0';
247  end generate gen_no_escape;
248  fsm_in.eof <= fab.eof or fab.error;
249  fsm_in.sof <= fab.sof;
250
251
252  U_Output_FIFO : dropping_buffer
253    generic map (
254      g_size       => g_buffer_size,
255      g_data_width => g_data_width + 2)
256    port map (
257      clk_i      => clk_sys_i,
258      rst_n_i    => rst_n_i,
259      d_i        => fifo_din,
260      d_req_o    => fsm_in.dreq,
261      d_drop_i   => fifo_drop,
262      d_accept_i => fifo_accept_d0,
263      d_valid_i  => fifo_dvalid,
264      d_o        => fifo_dout,
265      d_valid_o  => rx_valid_o,
266      d_req_i    => rx_dreq);
267
268  fifo_din(g_data_width+1)          <= fifo_sync;
269  fifo_din(g_data_width)            <= fifo_last or
270                                        ((not pending_write) and is_escape); -- when word is 16 bits
271  fifo_din(g_data_width-1 downto 0) <= fifo_data;
272
273  rx_data_o  <= fifo_dout(g_data_width-1 downto 0);
274  rx_first_p1_o <= fifo_dout(g_data_width+1);
275  rx_last_p1_o  <= fifo_dout(g_data_width);
276
277  U_RX_Timestamper : pulse_stamper
278    port map (
279      clk_ref_i       => clk_ref_i,
280      clk_sys_i       => clk_sys_i,
281      rst_n_i         => rst_n_i,
282      pulse_a_i       => fsm_in.sof,
283      tm_time_valid_i => tm_time_valid_i,
284      tm_tai_i        => tm_tai_i,
285      tm_cycles_i     => tm_cycles_i,
286      tag_cycles_o    => rx_tag_cycles);
287
288  -------------------------------------------------------------------------------------------
289  -- fixed latency implementation
290  -------------------------------------------------------------------------------------------
291
292  -- mask rx_dreq to prevent reception
293  rx_dreq                           <= rx_dreq_i and rx_dreq_allow;
294  -- produce a pulse when SOF is timestamped, this pulse starts counter in clk_sys clock
295  -- domain
296  U_sync_with_clk : gc_sync_ffs
297    port map (
298      clk_i          => clk_sys_i,
299      rst_n_i        => rst_n_i,
300      data_i         => fsm_in.sof,
301      synced_o       => timestamped);
302
303  -- introduce fixed latency, if configured to do so
304  p_fixed_latency_fsm : process(clk_sys_i)
305  begin
306    if rising_edge(clk_sys_i) then
307      if rst_n_i = '0' then
308        delay_state        <= DISABLED;
309        rx_latency_stored  <= (others=>'0');
310        rx_dreq_allow      <= '1';
311        delay_cnt          <= c_timestamper_delay;
312      else
313        case delay_state is
314          when DISABLED =>
315            if unsigned(rx_streamer_cfg_i.fixed_latency) /= c_fixed_latency_zero then
316              delay_state        <= ALLOW;
317            end if;
318            rx_latency_stored  <= (others=>'0');
319            delay_cnt          <= c_timestamper_delay;
320            rx_dreq_allow      <= '1';
321          when ALLOW =>
322            if unsigned(rx_streamer_cfg_i.fixed_latency) = c_fixed_latency_zero then
323              delay_state        <= DISABLED;
324            elsif(rx_latency_valid ='1') then
325              rx_dreq_allow     <= '0';
326              rx_latency_stored <= rx_latency;
327              delay_state       <= DELAY;
328            end if;
329            if(timestamped = '1') then
330              delay_cnt         <= c_timestamper_delay;
331            else
332              delay_cnt <= delay_cnt + 2;
333            end if;
334          when DELAY =>
335            if unsigned(rx_streamer_cfg_i.fixed_latency) <= delay_cnt + rx_latency_stored then
336              rx_latency_stored  <= (others=>'0');
337              rx_dreq_allow      <= '1';
338              delay_state        <= ALLOW;
339            else
340              delay_cnt <= delay_cnt + 2;
341            end if;
342        end case;
343      end if;
344    end if;
345  end process;
346
347  -------------------------------------------------------------------------------------------
348  -- end of fixed latency implementation
349  -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
350
351  p_fsm : process(clk_sys_i)
352  begin
353    if rising_edge(clk_sys_i) then
354      if rst_n_i = '0' then
355        state                  <= IDLE;
356        count                  <= (others => '0');
357        seq_no                 <= (others => '1');
358        detect_escapes         <= '0';
359        crc_en                 <= '0';
360        fifo_accept            <= '0';
361        fifo_drop              <= '0';
362        fifo_dvalid            <= '0';
363        pending_write          <= '0';
364        got_next_subframe      <= '0';
365        fifo_sync              <= '0';
366        fifo_last              <= '0';
367        tx_tag_valid           <= '0';
368        ser_count              <= (others => '0');
369        word_count             <= (others => '0');
370        sync_seq_no            <= '1';
371        rx_frame_p1_o          <= '0';
372        rx_lost_frames_cnt_o   <= (others => '0');
373        frames_lost            <= '0';
374        rx_latency             <= (others=>'0');
375        rx_latency_valid       <= '0';
376        blocks_lost            <= '0';
377        pack_data              <= (others=>'0');
378        is_vlan                <= '0';
379      else
380        case state is
381          when IDLE =>
382            detect_escapes     <= '0';
383            crc_en             <= '0';
384            count              <= (others => '0');
385            fifo_accept        <= '0';
386            fifo_drop          <= '0';
387            fifo_dvalid        <= '0';
388            pending_write      <= '0';
389            got_next_subframe  <='0';
390            ser_count          <= (others => '0');
391            fifo_sync          <='0';
392            fifo_last          <= '0';
393            word_count         <= (others => '0');
394            tx_tag_valid       <= '0';
395            rx_frame_p1_o      <= '0';
396            rx_lost_frames_cnt_o <= (others => '0');
397            frames_lost          <= '0';
398            blocks_lost          <= '0';
399            rx_latency           <= (others=>'0');
400            rx_latency_valid     <= '0';
401            is_vlan              <= '0';
402
403            if(fsm_in.sof = '1') then
404              state            <= HEADER;
405            end if;
406
407          when HEADER =>
408            if(fsm_in.eof = '1') then
409              state <= IDLE;
410            elsif(fsm_in.dvalid = '1') then
411              case count(7 downto 0) is
412                when x"00" =>
413                  if(fsm_in.data /= rx_streamer_cfg_i.mac_local(47 downto 32) nor (rx_streamer_cfg_i.accept_broadcasts = '1' and fsm_in.data /= x"ffff")) then
414                    state <= IDLE;
415                  end if;
416                  count <= count + 1;
417                when x"01" =>
418                  if(fsm_in.data /= rx_streamer_cfg_i.mac_local(31 downto 16) nor (rx_streamer_cfg_i.accept_broadcasts = '1' and fsm_in.data /= x"ffff")) then
419                    state <= IDLE;
420                  end if;
421                  count <= count + 1;
422                when x"02" =>
423                  if(fsm_in.data /= rx_streamer_cfg_i.mac_local(15 downto 0) nor (rx_streamer_cfg_i.accept_broadcasts = '1' and fsm_in.data /= x"ffff")) then
424                    state <= IDLE;
425                  end if;
426                  count <= count + 1;
427                when x"03" =>
428                  if(fsm_in.data /= rx_streamer_cfg_i.mac_remote(47 downto 32) and rx_streamer_cfg_i.filter_remote ='1') then
429                    state <= IDLE;
430                  end if;
431                  count <= count + 1;
432                when x"04" =>
433                  if(fsm_in.data /= rx_streamer_cfg_i.mac_remote(31 downto 16) and rx_streamer_cfg_i.filter_remote ='1') then
434                    state <= IDLE;
435                  end if;
436                  count <= count + 1;
437                when x"05" =>
438                  if(fsm_in.data /= rx_streamer_cfg_i.mac_remote(15 downto 0) and rx_streamer_cfg_i.filter_remote ='1') then
439                    state <= IDLE;
440                  end if;
441                  count <= count + 1;
442                when x"06" =>
443                  if(fsm_in.data = x"8100") then
444                    is_vlan <='1';
445                  elsif(fsm_in.data /= rx_streamer_cfg_i.ethertype) then
446                    state   <= IDLE;
447                    is_vlan <='0';
448                  end if;
449                  count <= count + 1;
450                when x"07" =>
451                  if(is_vlan = '0') then
452                    tx_tag_valid               <= fsm_in.data(15);
453                    tx_tag_cycles(27 downto 16)<= fsm_in.data(11 downto 0);
454                  end if;
455                  count <= count + 1;
456                when x"08" =>
457                  if(is_vlan = '0') then
458                    tx_tag_cycles(15 downto 0) <= fsm_in.data;
459                    count                      <= count + 1;
460                    crc_en                     <= '1';
461                    detect_escapes             <= '1';
462                    state                      <= FRAME_SEQ_ID;
463                    rx_frame_p1_o              <= '1';
464                  elsif(fsm_in.data /= rx_streamer_cfg_i.ethertype) then
465                    state <= IDLE;
466                  end if;
467                  count <= count + 1;
468                when x"09" =>
469                  tx_tag_valid               <= fsm_in.data(15);
470                  tx_tag_cycles(27 downto 16)<= fsm_in.data(11 downto 0);
471                   count <= count + 1;
472                when x"0A" =>
473                  tx_tag_cycles(15 downto 0) <= fsm_in.data;
474                  count                      <= count + 1;
475                  crc_en                     <= '1';
476                  detect_escapes             <= '1';
477                  state                      <= FRAME_SEQ_ID;
478                  rx_frame_p1_o              <= '1';
479                  count <= count + 1;
480                when others => null;
481              end case;
482            end if;
483
484          when FRAME_SEQ_ID =>
485            rx_frame_p1_o            <= '0';
486            if(fsm_in.eof = '1') then
487              state <= IDLE;
488            elsif(fsm_in.dvalid = '1') then
489              count               <= "000" & x"001"; -- use as subframe seq_no
490              state               <= PAYLOAD;
491              fifo_drop           <= '0';
492              fifo_accept         <= '0';
493              ser_count           <= (others => '0');
494              word_count          <= word_count + 1; -- count words, increment in advance
495              got_next_subframe   <= '1';
496              if(tx_tag_valid = '1') then
497                rx_latency_valid <= '1';
498                if(unsigned(tx_tag_cycles) > unsigned(rx_tag_cycles)) then
499                  rx_latency <= unsigned(rx_tag_cycles) - unsigned(tx_tag_cycles) + to_unsigned(125000000, 28);
500                else
501                  rx_latency <= unsigned(rx_tag_cycles) - unsigned(tx_tag_cycles);
502                end if;
503                tx_tag_valid <= '0';
504              else
505                rx_latency_valid <= '0';
506              end if;
507
508              if(std_logic_vector(seq_no) /= fsm_in.data(14 downto 0)) then
509                seq_no    <= unsigned(fsm_in.data(14 downto 0))+1;
510                if (sync_seq_no = '1') then -- sync to the first received seq_no
511                  sync_seq_no <= '0';
512                  frames_lost   <= '0';
513                  rx_lost_frames_cnt_o <= (others => '0');
514                else
515                  rx_lost_frames_cnt_o <= std_logic_vector(unsigned(fsm_in.data(14 downto 0)) - seq_no);
516                  frames_lost     <= '1';
517                end if;
518              else
519                seq_no    <= unsigned(seq_no + 1);
520                frames_lost <= '0';
521                rx_lost_frames_cnt_o <= (others => '0');
522              end if;
523            end if;
524
525          when SUBFRAME_HEADER =>
526            fifo_drop   <= '0';
527            fifo_accept <= '0';
528            ser_count <= (others => '0');
529
530            if(fsm_in.eof = '1') then
531              state <= IDLE;
532              got_next_subframe <= '0';
533              blocks_lost <= '0';
534            elsif (fsm_in.dvalid = '1' and is_escape = '1') then
535              got_next_subframe <= '1';
536
537              if(std_logic_vector(count) /= fsm_in.data(14 downto 0)) then
538                count     <= unsigned(fsm_in.data(14 downto 0))+1;
539                blocks_lost <= '1';
540              else
541                count    <= count + 1;
542                blocks_lost <= '0';
543              end if;
544              state <= PAYLOAD;
545            end if;
546
547          when PAYLOAD =>
548            frames_lost <= '0';
549            rx_lost_frames_cnt_o <= (others => '0');
550            rx_latency_valid <= '0';
551            fifo_sync <= got_next_subframe;
552
553            if(fsm_in.eof = '1') then
554              state       <= IDLE;
555              fifo_drop   <= '1';
556              fifo_accept <= '0';
557              got_next_subframe <= '0';
558
559            elsif(fsm_in.dvalid = '1') then
560
561
562
563              if(is_escape = '1') then
564                ser_count <= (others => '0');
565                fifo_last <= '1';
566
567                got_next_subframe <= '1';
568
569                if(fsm_in.data(15) = '1') then
570
571                  if(std_logic_vector(count) /= fsm_in.data(14 downto 0)) then
572                    count     <= unsigned(fsm_in.data(14 downto 0));
573                    blocks_lost <= '1';
574                  else
575                    count     <= unsigned(count + 1);
576                    blocks_lost <= '0';
577                  end if;
578
579                  state <= PAYLOAD;
580
581                  fifo_accept   <= crc_match;      --_latched;
582                  fifo_drop     <= not crc_match;  --_latched;
583                  fifo_dvalid   <= pending_write and not fifo_dvalid;
584                  pending_write <= '0';
585
586                elsif fsm_in.data = x"0bad" then
587                  blocks_lost   <= '0';
588                  state       <= EOF;
589                  fifo_accept <= crc_match;      --_latched;
590                  fifo_drop   <= not crc_match;  --_latched;
591                  fifo_dvalid <= pending_write and not fifo_dvalid;
592                else
593                  blocks_lost   <= '0';
594                  state       <= EOF;
595                  fifo_drop   <= '1';
596                  fifo_accept <= '0';
597                end if;
598
599              else --of:  if(is_escape = '1' or word_count = g_expected_words_number) then
600
601                fifo_last   <= '0';
602                fifo_accept <= '0';
603                fifo_drop   <= '0';
604                blocks_lost   <= '0';
605
606                pack_data(to_integer(ser_count) * 16 + 15 downto to_integer(ser_count) * 16) <= fsm_in.data;
607
608                if(ser_count = g_data_width/16 - 1) then
609                  ser_count                                        <= (others => '0');
610
611                  if (ser_count = x"00") then -- ML: the case when g_data_width == 16
612                     fifo_sync <= got_next_subframe;
613                     fifo_data(g_data_width-1 downto 0)            <= pack_data(g_data_width-1 downto 0);
614                     fifo_dvalid <= not is_escape;
615                     pending_write <= '0';
616                  else
617                    ser_count                                        <= (others => '0');
618                    fifo_data(g_data_width-16-1 downto 0)            <= pack_data(g_data_width-16-1 downto 0);
619                    fifo_data(g_data_width-1 downto g_data_width-16) <= fsm_in.data;
620                    fifo_dvalid                                      <= '0';
621                    pending_write                                    <= '1';
622                  end if;
623                  if(word_count = g_expected_words_number) then
624                    state       <= EOF;
625                    fifo_accept <= '1';
626                    fifo_drop   <= '0';
627                    fifo_dvalid <= '1';
628                  else
629                    word_count <= word_count + 1;
630                  end if;
631                elsif(ser_count = g_data_width/16-2 and pending_write = '1') then
632                  pending_write <= '0';
633                  ser_count     <= ser_count + 1;
634                  fifo_dvalid   <= '1';
635                  fifo_sync <= got_next_subframe;
636                  got_next_subframe <= '0';
637                else
638                  ser_count   <= ser_count + 1;
639                  fifo_dvalid <= '0';
640                end if;
641
642              end if;
643            else --of:  elsif(fsm_in.dvalid = '1') then
644              fifo_dvalid <= '0';
645            end if;
646
647            if(fifo_dvalid = '1') then
648              fifo_sync <= '0';
649            end if;
650
651
652          when EOF =>
653            fifo_dvalid <= '0';
654            fifo_drop   <= '0';
655            fifo_accept <= '0';
656            state       <= IDLE;
657
658        end case;
659      end if;
660    end if;
661  end process;
662
663  p_delay_fifo_accept : process(clk_sys_i)
664  begin
665    if rising_edge(clk_sys_i) then
666      fifo_accept_d0 <= fifo_accept;
667    end if;
668  end process;
669
670  rx_lost_p1_o        <= frames_lost or blocks_lost;
671  rx_lost_blocks_p1_o <= blocks_lost;
672  rx_lost_frames_p1_o <= frames_lost;
673  rx_latency_o        <= std_logic_vector(rx_latency);
674  rx_latency_valid_o  <= rx_latency_valid;
675  crc_restart <= '1' when (state = FRAME_SEQ_ID or (is_escape = '1' and fsm_in.data(15) = '1')) else not rst_n_i;
676
677end rtl;
678