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