1-------------------------------------------------------------------------------
2-- Title      : Gigabit Ethernet reception pipeline
3-- Project    : White Rabbit MAC/Endpoint
4-------------------------------------------------------------------------------
5-- File       : ep_rx_path.vhd
6-- Author     : Tomasz Wlostowski
7-- Company    : CERN BE-CO-HT
8-- Created    : 2009-06-22
9-- Last update: 2017-02-02
10-- Platform   : FPGA-generic
11-- Standard   : VHDL'93
12-------------------------------------------------------------------------------
13-- Description: RX path unit:
14-- - provides elastic buffering between RX and system clock
15-- - checks frame CRC and size
16-- - inserts/removes 802.1q headers when necessary
17-- - parses packet headers and generates RTU requests
18-- - performs programmable packet inspection and classifying
19-- - distinguishes between HP and non-HP frames
20-- - issues RTU requests
21-- - embeds RX OOB block with timestamp information
22--
23-------------------------------------------------------------------------------
24--
25-- Copyright (c) 2009-2011 CERN / BE-CO-HT
26--
27-- This source file is free software; you can redistribute it
28-- and/or modify it under the terms of the GNU Lesser General
29-- Public License as published by the Free Software Foundation;
30-- either version 2.1 of the License, or (at your option) any
31-- later version.
32--
33-- This source is distributed in the hope that it will be
34-- useful, but WITHOUT ANY WARRANTY; without even the implied
35-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
36-- PURPOSE.  See the GNU Lesser General Public License for more
37-- details.
38--
39-- You should have received a copy of the GNU Lesser General
40-- Public License along with this source; if not, download it
41-- from http://www.gnu.org/licenses/lgpl-2.1.html
42--
43-------------------------------------------------------------------------------
44-- Revisions  :
45-- Date        Version  Author          Description
46-- 2009-06-22  0.1      twlostow        Created
47-- 2011-10-18  0.5      twlostow        WB rev B4 - compatible data path
48------------------------------------------------------------------------------
49
50
51library ieee;
52use ieee.std_logic_1164.all;
53use ieee.numeric_std.all;
54
55library work;
56use work.gencores_pkg.all;
57use work.genram_pkg.all;
58use work.endpoint_private_pkg.all;
59use work.endpoint_pkg.all;
60use work.ep_wbgen2_pkg.all;
61use work.wr_fabric_pkg.all;
62
63entity ep_rx_path is
64  generic (
65    g_with_vlans          : boolean := true;
66    g_with_dpi_classifier : boolean := true;
67    g_with_rtu            : boolean := true;
68    g_with_rx_buffer      : boolean := true;
69    g_with_early_match    : boolean := false;
70    g_rx_buffer_size      : integer := 1024;
71    g_use_new_crc         :	boolean := false);
72  port (
73    clk_sys_i   : in std_logic;
74    clk_rx_i    : in std_logic;
75    rst_n_sys_i : in std_logic;
76    rst_n_rx_i  : in std_logic;
77
78-- physical coding sublayer (PCS) interface
79    pcs_fab_i             : in  t_ep_internal_fabric;
80    pcs_fifo_almostfull_o : out std_logic;
81    pcs_busy_i            : in  std_logic;
82
83-- Wishbone I/O
84    src_wb_o : out t_wrf_source_out;
85    src_wb_i : in  t_wrf_source_in;
86
87-- flow control signals
88    fc_pause_p_o           : out std_logic;
89    fc_pause_quanta_o      : out std_logic_vector(15 downto 0);
90    fc_pause_prio_mask_o   : out std_logic_vector(7 downto 0);
91    fc_buffer_occupation_o : out std_logic_vector(7 downto 0);
92
93-- RMON/statistic counters signals
94    rmon_o : out t_rmon_triggers;
95    regs_i : in  t_ep_out_registers;
96    regs_o : out t_ep_in_registers;
97
98-- info for TRU module
99    pfilter_pclass_o : out std_logic_vector(7 downto 0);
100    pfilter_drop_o   : out std_logic;
101    pfilter_done_o   : out std_logic;
102
103-------------------------------------------------------------------------------
104-- RTU interface
105-------------------------------------------------------------------------------
106
107    rtu_rq_o       : out t_ep_internal_rtu_request;
108    rtu_full_i     : in  std_logic;
109    rtu_rq_valid_o : out std_logic;
110    rtu_rq_abort_o : out std_logic;
111
112    nice_dbg_o     : out t_dbg_ep_rxpath
113    );
114end ep_rx_path;
115
116architecture behavioral of ep_rx_path is
117
118  type t_rx_deframer_state is (RXF_IDLE, RXF_DATA, RXF_FLUSH_STALL, RXF_FINISH_CYCLE, RXF_THROW_ERROR);
119
120  signal state : t_rx_deframer_state;
121
122  signal gap_cntr : unsigned(3 downto 0);
123
124  -- new sigs
125  signal counter : unsigned(7 downto 0);
126
127  signal rxdata_saved : std_logic_vector(15 downto 0);
128  signal next_hdr     : std_logic;
129  signal is_pause     : std_logic;
130
131  signal data_firstword : std_logic;
132
133
134  signal flush_stall : std_logic;
135  signal stb_int     : std_logic;
136
137  signal fab_int  : t_ep_internal_fabric;
138  signal dreq_int : std_logic;
139
140  signal ack_count   : unsigned(7 downto 0);
141  signal src_out_int : t_wrf_source_out;
142
143  signal tmp_sel : std_logic;
144  signal tmp_dat : std_logic_vector(15 downto 0);
145
146
147  signal fab_pipe  : t_fab_pipe(0 to 9);
148  signal dreq_pipe : std_logic_vector(9 downto 0);
149
150  signal ematch_done     : std_logic;
151  signal ematch_is_hp    : std_logic;
152  signal ematch_is_pause : std_logic;
153  signal fc_pause_p      : std_logic;
154
155  signal pfilter_pclass : std_logic_vector(7 downto 0);
156  signal pfilter_drop   : std_logic;
157  signal pfilter_done   : std_logic;
158
159  signal vlan_tclass    : std_logic_vector(2 downto 0);
160  signal vlan_vid       : std_logic_vector(11 downto 0);
161  signal vlan_tag_done  : std_logic;
162  signal vlan_is_tagged : std_logic;
163
164  signal pcs_fifo_almostfull                                    : std_logic;
165  signal mbuf_rd, mbuf_valid, mbuf_we, mbuf_pf_drop, mbuf_is_hp : std_logic;
166  signal mbuf_is_pause, mbuf_full : std_logic;
167  signal mbuf_pf_class            : std_logic_vector(7 downto 0);
168  signal rtu_rq_valid         : std_logic;
169  signal stat_reg_mbuf_valid  : std_logic;
170
171  signal rxbuf_full       : std_logic;
172  signal rxbuf_dropped    : std_logic;
173
174  signal src_wb_out : t_wrf_source_out;
175  signal src_wb_cyc_d0 : std_logic;
176
177  signal rst_n_rx_match_buff : std_logic;
178
179begin  -- behavioral
180
181  fab_pipe(0) <= pcs_fab_i;
182
183  fc_pause_p_o    <= fc_pause_p;
184  gen_with_early_match : if(g_with_early_match) generate
185    U_early_addr_match : ep_rx_early_address_match
186      port map (
187        clk_sys_i               => clk_sys_i,
188        clk_rx_i                => clk_rx_i,
189        rst_n_sys_i             => rst_n_sys_i,
190        rst_n_rx_i              => rst_n_rx_i,
191        snk_fab_i               => fab_pipe(0),
192        src_fab_o               => fab_pipe(1),
193        match_done_o            => ematch_done,
194        match_is_hp_o           => ematch_is_hp,
195        match_is_pause_o        => ematch_is_pause,
196        match_pause_quanta_o    => fc_pause_quanta_o,
197        match_pause_prio_mask_o => fc_pause_prio_mask_o,
198        match_pause_p_o         => fc_pause_p,
199        regs_i                  => regs_i);
200  end generate gen_with_early_match;
201
202  gen_without_early_match : if(not g_with_early_match) generate
203    fab_pipe(1)          <= fab_pipe(0);
204    ematch_done          <= '0';
205    ematch_is_hp         <= '0';
206    ematch_is_pause      <= '0';
207    fc_pause_quanta_o    <= (others =>'0');
208    fc_pause_prio_mask_o <= (others =>'0');
209    fc_pause_p           <= '0';
210  end generate gen_without_early_match;
211
212  gen_with_packet_filter : if(g_with_dpi_classifier) generate
213    U_packet_filter : ep_packet_filter
214      port map (
215        clk_sys_i   => clk_sys_i,
216        clk_rx_i    => clk_rx_i,
217        rst_n_sys_i => rst_n_sys_i,
218        rst_n_rx_i  => rst_n_rx_i,
219
220        snk_fab_i => fab_pipe(1),
221        src_fab_o => fab_pipe(2),
222        done_o    => pfilter_done,
223        pclass_o  => pfilter_pclass,
224        drop_o    => pfilter_drop,
225        regs_i    => regs_i);
226  end generate gen_with_packet_filter;
227
228  gen_without_packet_filter : if(not g_with_dpi_classifier) generate
229    fab_pipe(2)    <= fab_pipe(1);
230    pfilter_drop   <= '0';
231    pfilter_done   <= '1';
232    pfilter_pclass <= (others => '0');
233  end generate gen_without_packet_filter;
234
235  process(clk_sys_i)
236  begin
237    if rising_edge(clk_sys_i) then
238      if (rst_n_sys_i = '0') then
239        mbuf_we <= '0';
240      -- if rx_buffer has dropped a frame (e.g. because it was full) we
241      -- shouldn't store pfilter decision in the mbuf as well
242      elsif( ((ematch_done='1' and g_with_early_match) or
243              (pfilter_done='1' and g_with_dpi_classifier)) and
244              rxbuf_dropped='0') then
245        mbuf_we <= '1';
246      elsif(mbuf_rd = '1' or mbuf_full = '0') then
247        mbuf_we <= '0';
248      end if;
249    end if;
250  end process;
251
252  gen_with_match_buff: if( g_with_early_match or g_with_dpi_classifier) generate
253    U_Sync_Rst_match_buff : gc_sync_ffs
254      port map (
255        clk_i    => clk_sys_i,
256        rst_n_i  => '1',
257        data_i   => rst_n_rx_i,
258        synced_o => rst_n_rx_match_buff);
259
260    U_match_buffer : generic_shiftreg_fifo
261      generic map (
262        g_data_width => 8 + 1 + 1 + 1,
263        g_size       => 16)
264      port map (
265        rst_n_i           => rst_n_rx_match_buff,
266        clk_i             => clk_sys_i,
267        d_i (0)           => ematch_is_hp,
268        d_i (1)           => ematch_is_pause,
269        d_i (2)           => pfilter_drop,
270        d_i (10 downto 3) => pfilter_pclass,
271
272        we_i              => mbuf_we,
273        q_o (0)           => mbuf_is_hp,
274        q_o (1)           => mbuf_is_pause,
275        q_o (2)           => mbuf_pf_drop,
276        q_o (10 downto 3) => mbuf_pf_class,
277
278        rd_i      => mbuf_rd,
279        full_o    => mbuf_full,
280        q_valid_o => mbuf_valid);
281  end generate;
282
283  gen_without_match_buf: if(not (g_with_early_match or g_with_dpi_classifier)) generate
284    mbuf_is_hp    <= '0';
285    mbuf_is_pause <= '0';
286    mbuf_pf_drop  <= '0';
287    mbuf_pf_class <= (others=>'0');
288    mbuf_full     <= '0';
289    mbuf_valid    <= '1';
290  end generate;
291
292  -- don't block ep_rx_status_reg_insert when pfilter is disabled and early
293  -- match is not used
294  stat_reg_mbuf_valid <= '1' when (not g_with_early_match and g_with_dpi_classifier
295                                   and regs_i.pfcr0_enable_o='0') else
296                         mbuf_valid;
297
298  U_Rx_Clock_Align_FIFO : ep_clock_alignment_fifo
299    generic map (
300      g_size                 => 128,
301      g_almostfull_threshold => 112)
302    port map (
303      rst_n_rd_i       => rst_n_sys_i,
304      rst_n_wr_i       => rst_n_rx_i,
305      clk_wr_i         => clk_rx_i,
306      clk_rd_i         => clk_sys_i,
307      dreq_i           => dreq_pipe(3),
308      fab_i            => fab_pipe(2),
309      fab_o            => fab_pipe(3),
310      full_o           => nice_dbg_o.pcs_fifo_full,
311      empty_o          => nice_dbg_o.pcs_fifo_empty,
312      almostfull_o     => pcs_fifo_almostfull,
313      pass_threshold_i => std_logic_vector(to_unsigned(32, 7)));  -- fixme: add
314                                                                  -- register
315  pcs_fifo_almostfull_o <= pcs_fifo_almostfull;
316
317  U_Insert_OOB : ep_rx_oob_insert
318    port map (
319      clk_sys_i  => clk_sys_i,
320      rst_n_i    => rst_n_sys_i,
321      snk_fab_i  => fab_pipe(3),
322      snk_dreq_o => dreq_pipe(3),
323      src_dreq_i => dreq_pipe(4),
324      src_fab_o  => fab_pipe(4),
325      regs_i     => regs_i);
326
327  U_crc_size_checker : ep_rx_crc_size_check
328    generic map (
329      g_use_new_crc	 => g_use_new_crc)
330    port map (
331      clk_sys_i      => clk_sys_i,
332      rst_n_i        => rst_n_sys_i,
333      snk_fab_i      => fab_pipe(4),
334      snk_dreq_o     => dreq_pipe(4),
335      src_dreq_i     => dreq_pipe(5),
336      src_fab_o      => fab_pipe(5),
337      regs_i         => regs_i,
338      rmon_pcs_err_o => rmon_o.rx_pcs_err,
339      rmon_giant_o   => rmon_o.rx_giant,
340      rmon_runt_o    => rmon_o.rx_runt,
341      rmon_crc_err_o => rmon_o.rx_crc_err);
342
343  gen_with_vlan_unit : if(g_with_vlans) generate
344    U_vlan_unit : ep_rx_vlan_unit
345      port map (
346        clk_sys_i   => clk_sys_i,
347        rst_n_i     => rst_n_sys_i,
348        snk_fab_i   => fab_pipe(5),
349        snk_dreq_o  => dreq_pipe(5),
350        src_fab_o   => fab_pipe(6),
351        src_dreq_i  => dreq_pipe(6),
352        tclass_o    => vlan_tclass,
353        vid_o       => vlan_vid,
354        tag_done_o  => vlan_tag_done,
355        is_tagged_o => vlan_is_tagged,
356        regs_i      => regs_i,
357        regs_o      => regs_o);
358  end generate gen_with_vlan_unit;
359
360
361  gen_without_vlan_unit : if(not g_with_vlans) generate
362    fab_pipe(6)    <= fab_pipe(5);
363    dreq_pipe(5)   <= dreq_pipe(6);
364    vlan_tclass    <= (others => '0');
365    vlan_vid       <= (others => '0');
366    vlan_tag_done  <= '0';
367    vlan_is_tagged <= '0';
368    regs_o         <= c_ep_in_registers_init_value;
369  end generate gen_without_vlan_unit;
370
371  U_RTU_Header_Extract : ep_rtu_header_extract
372    generic map (
373      g_with_rtu => g_with_rtu)
374    port map (
375      clk_sys_i        => clk_sys_i,
376      rst_n_i          => rst_n_sys_i,
377      snk_fab_i        => fab_pipe(6),
378      snk_dreq_o       => dreq_pipe(6),
379      src_fab_o        => fab_pipe(7),
380      src_dreq_i       => dreq_pipe(7),
381      mbuf_is_pause_i  => mbuf_is_pause,  -- this module is in the pipe before ep_rx_status_reg_insert,
382                                          -- however, we know that mbuf_is_pause is valid when it
383                                          -- is used by this module -- this is because blocks the pipe
384                                          -- untill mbuf_valid is HIGH, and rtu_rq_valid_o is inserted HIGH
385                                          -- at the end of the header... (clear ??:)
386      vlan_class_i     => vlan_tclass,
387      vlan_vid_i       => vlan_vid,
388      vlan_tag_done_i  => vlan_tag_done,
389      vlan_is_tagged_i => vlan_is_tagged,
390
391      rmon_drp_at_rtu_full_o => rmon_o.rx_drop_at_rtu_full,
392
393      rtu_rq_o         => rtu_rq_o,
394      rtu_full_i       => rtu_full_i,
395      rtu_rq_abort_o   => rtu_rq_abort_o,
396      rtu_rq_valid_o   => rtu_rq_valid,
397      rxbuf_full_i     => rxbuf_full);
398
399  gen_with_rx_buffer : if g_with_rx_buffer generate
400    U_Rx_Buffer : ep_rx_buffer
401      generic map (
402        g_size    => g_rx_buffer_size,
403        g_with_fc => false)
404      port map (
405        clk_sys_i  => clk_sys_i,
406        rst_n_i    => rst_n_sys_i,
407        snk_fab_i  => fab_pipe(7),
408        snk_dreq_o => dreq_pipe(7),
409        src_fab_o  => fab_pipe(8),
410        src_dreq_i => dreq_pipe(8),
411        level_o    => fc_buffer_occupation_o,
412        full_o     => rxbuf_full,
413        drop_req_i => mbuf_we,  -- if mbuf_we is high that means it waits to be
414                                -- stored in mbuf => mbuf is probably full so we
415                                -- should drop this frame
416        dropped_o  => rxbuf_dropped,
417        regs_i     => regs_i);
418  end generate gen_with_rx_buffer;
419
420  gen_without_rx_buffer : if (not g_with_rx_buffer) generate
421    fab_pipe(8)  <= fab_pipe(7);
422    dreq_pipe(7) <= dreq_pipe(8);
423    rxbuf_full  <= '0';
424  end generate gen_without_rx_buffer;
425
426  U_Gen_Status : ep_rx_status_reg_insert
427    port map (
428      clk_sys_i           => clk_sys_i,
429      rst_n_i             => rst_n_sys_i,
430      snk_fab_i           => fab_pipe(8),
431      snk_dreq_o          => dreq_pipe(8),
432      src_fab_o           => fab_pipe(9),
433      src_dreq_i          => dreq_pipe(9),
434      mbuf_valid_i        => stat_reg_mbuf_valid,
435      mbuf_ack_o          => mbuf_rd,
436      mbuf_drop_i         => mbuf_pf_drop,
437      mbuf_pclass_i       => mbuf_pf_class,
438      mbuf_is_hp_i        => mbuf_is_hp,
439      mbuf_is_pause_i     => mbuf_is_pause,
440      rmon_pfilter_drop_o => rmon_o.rx_pfilter_drop);
441
442  U_RX_Wishbone_Master : ep_rx_wb_master
443    generic map (
444      g_ignore_ack => true)
445    port map (
446      clk_sys_i  => clk_sys_i,
447      rst_n_i    => rst_n_sys_i,
448      snk_fab_i  => fab_pipe(9),
449      snk_dreq_o => dreq_pipe(9),
450      src_wb_i   => src_wb_i,
451      src_wb_o   => src_wb_out
452      );
453
454  src_wb_o <= src_wb_out;
455
456  -- direct output of packet filter data (for TRU)
457  pfilter_pclass_o <= pfilter_pclass;
458  pfilter_drop_o   <= pfilter_drop;
459  pfilter_done_o   <= pfilter_done;
460
461  rtu_rq_valid_o   <= rtu_rq_valid;
462  -----------------------------------------
463  -- RMON events
464  -----------------------------------------
465  rmon_o.rx_pause <= fc_pause_p;
466  GEN_PCLASS_EVT: for i in 0 to 7 generate
467    rmon_o.rx_pclass(i) <= pfilter_pclass(i) and pfilter_done;
468  end generate;
469
470  rmon_o.rx_tclass(0) <= rtu_rq_valid when (vlan_tclass = "000" and vlan_is_tagged = '1') else '0';
471  rmon_o.rx_tclass(1) <= rtu_rq_valid when (vlan_tclass = "001" and vlan_is_tagged = '1') else '0';
472  rmon_o.rx_tclass(2) <= rtu_rq_valid when (vlan_tclass = "010" and vlan_is_tagged = '1') else '0';
473  rmon_o.rx_tclass(3) <= rtu_rq_valid when (vlan_tclass = "011" and vlan_is_tagged = '1') else '0';
474  rmon_o.rx_tclass(4) <= rtu_rq_valid when (vlan_tclass = "100" and vlan_is_tagged = '1') else '0';
475  rmon_o.rx_tclass(5) <= rtu_rq_valid when (vlan_tclass = "101" and vlan_is_tagged = '1') else '0';
476  rmon_o.rx_tclass(6) <= rtu_rq_valid when (vlan_tclass = "110" and vlan_is_tagged = '1') else '0';
477  rmon_o.rx_tclass(7) <= rtu_rq_valid when (vlan_tclass = "111" and vlan_is_tagged = '1') else '0';
478
479  GEN_DBG: for i in 0 to 9 generate
480    nice_dbg_o.fab_pipe(i) <= fab_pipe(i);
481    nice_dbg_o.dreq_pipe(i)<= dreq_pipe(i);
482  end generate GEN_DBG;
483
484  nice_dbg_o.pcs_fifo_afull <= pcs_fifo_almostfull;
485  nice_dbg_o.rxbuf_full <= rxbuf_full;
486
487  process(clk_sys_i)
488  begin
489    if rising_edge(clk_sys_i) then
490      if (rst_n_sys_i = '0') then
491        src_wb_cyc_d0 <= '0';
492      else
493        src_wb_cyc_d0 <= src_wb_out.cyc;
494      end if;
495    end if;
496  end process;
497
498  rmon_o.rx_frame <= '1' when (src_wb_out.cyc = '1' and src_wb_cyc_d0 = '0') else
499                     '0';
500
501  -- drive unused signals and outputs
502  dreq_pipe(2 downto 0)         <= (others => '0');
503  rmon_o.rx_sync_lost           <= '0';
504  rmon_o.rx_invalid_code        <= '0';
505  rmon_o.rx_overrun             <= '0';
506  rmon_o.rx_ok                  <= '0';
507  rmon_o.rx_buffer_overrun      <= '0';
508  rmon_o.rx_rtu_overrun         <= '0';
509  rmon_o.rx_path_timing_failure <= '0';
510  rmon_o.tx_pause               <= '0';
511  rmon_o.tx_underrun            <= '0';
512  rmon_o.tx_frame               <= '0';
513
514end behavioral;
515
516