1//
2// Copyright 2011 Ettus Research LLC
3// Copyright 2018 Ettus Research, a National Instruments Company
4//
5// SPDX-License-Identifier: LGPL-3.0-or-later
6//
7
8
9
10
11module simple_gemac_rx
12  (input reset,
13   input GMII_RX_CLK, input GMII_RX_DV, input GMII_RX_ER, input [7:0] GMII_RXD,
14   output rx_clk, output [7:0] rx_data, output reg rx_valid, output rx_error, output reg rx_ack,
15   input [47:0] ucast_addr, input [47:0] mcast_addr,
16   input pass_ucast, input pass_mcast, input pass_bcast, input pass_pause, input pass_all,
17   output reg [15:0] pause_quanta_rcvd, output pause_rcvd,
18   output [31:0] debug );
19
20   localparam RX_IDLE 		  = 0;
21   localparam RX_PREAMBLE 	  = 1;
22   localparam RX_FRAME 		  = 2;
23   localparam RX_GOODFRAME 	  = 3;
24   localparam RX_DO_PAUSE 	  = 4;
25   localparam RX_ERROR 		  = 5;
26   localparam RX_DROP 		  = 6;
27
28   localparam RX_PAUSE 		  = 16;
29   localparam RX_PAUSE_CHK88 	  = RX_PAUSE + 5;
30   localparam RX_PAUSE_CHK08 	  = RX_PAUSE_CHK88 + 1;
31   localparam RX_PAUSE_CHK00 	  = RX_PAUSE_CHK08 + 1;
32   localparam RX_PAUSE_CHK01 	  = RX_PAUSE_CHK00 + 1;
33   localparam RX_PAUSE_STORE_MSB  = RX_PAUSE_CHK01 + 1;
34   localparam RX_PAUSE_STORE_LSB  = RX_PAUSE_STORE_MSB + 1;
35   localparam RX_PAUSE_WAIT_CRC   = RX_PAUSE_STORE_LSB + 1;
36
37   reg [7:0] 	     rxd_d1;
38   reg rx_dv_d1, rx_er_d1;
39   assign rx_clk     = GMII_RX_CLK;
40
41   always @(posedge rx_clk)
42     begin
43	rx_dv_d1    <= GMII_RX_DV;
44	rx_er_d1    <= GMII_RX_ER;
45	rxd_d1 	    <= GMII_RXD;
46     end
47
48   reg [7:0] rx_state;
49   wire [7:0] rxd_del;
50   wire rx_dv_del, rx_er_del;
51   reg go_filt;
52
53   wire match_crc;
54   wire clear_crc 	 = rx_state == RX_IDLE;
55   wire calc_crc 	 = (rx_state == RX_FRAME) | rx_state[7:4]==4'h1;
56
57   localparam DELAY  = 6;
58   delay_line #(.WIDTH(10)) rx_delay
59     (.clk(rx_clk), .delay(DELAY), .din({rx_dv_d1,rx_er_d1,rxd_d1}),.dout({rx_dv_del,rx_er_del,rxd_del}));
60
61   always @(posedge rx_clk)
62     if(reset)
63       rx_ack 	   <= 0;
64     else
65       rx_ack <= (rx_state == RX_GOODFRAME);
66
67   wire is_ucast, is_bcast, is_mcast, is_pause, is_any_ucast;
68   wire keep_packet  = (pass_all & is_any_ucast) | (pass_ucast & is_ucast) | (pass_mcast & is_mcast) |
69	(pass_bcast & is_bcast) | (pass_pause & is_pause);
70
71   assign rx_data   = rxd_del;
72   assign rx_error  = (rx_state == RX_ERROR);
73
74   always @(posedge rx_clk)
75     if(reset)
76       rx_valid <= 0;
77     else if(keep_packet)
78       rx_valid <= 1;
79     else if((rx_state == RX_IDLE)|(rx_state == RX_ERROR))
80       rx_valid <= 0;
81
82   address_filter af_ucast (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
83			    .address(ucast_addr), .match(is_ucast), .done());
84   address_filter af_mcast (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
85			    .address(mcast_addr), .match(is_mcast), .done());
86   address_filter af_bcast (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
87			    .address(48'hFFFF_FFFF_FFFF), .match(is_bcast), .done());
88   address_filter af_pause (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
89			    .address(48'h0180_c200_0001), .match(is_pause), .done());
90   address_filter_promisc af_promisc (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
91				      .match(is_any_ucast), .done());
92
93   always @(posedge rx_clk)
94     go_filt 			 <= (rx_state==RX_PREAMBLE) & (rxd_d1 == 8'hD5);
95
96   reg [15:0] pkt_len_ctr;
97   always @(posedge rx_clk)
98     if(reset |(rx_state == RX_IDLE))
99       pkt_len_ctr 	<= 0;
100     else
101       pkt_len_ctr 	<= pkt_len_ctr + 1;
102
103   localparam MIN_PAUSE_LEN = 71;  // 6
104   wire pkt_long_enough  = (pkt_len_ctr >= MIN_PAUSE_LEN);
105   always @(posedge rx_clk)
106     if(reset)
107       rx_state 	<= RX_IDLE;
108     else
109       if(rx_er_d1 & ~((rxd_d1==8'h0F)&(~rx_dv_d1)))  //Handle odd-length pkts from Xilinx IP.
110	 rx_state 	<= RX_ERROR;
111       else
112	 case(rx_state)
113	   RX_IDLE :
114	     if(rx_dv_d1)
115	       if(rxd_d1 == 8'h55)
116		 rx_state   <= RX_PREAMBLE;
117	       else
118		 rx_state   <= RX_ERROR;
119	   RX_PREAMBLE :
120	     if(~rx_dv_d1)
121	       rx_state   <= RX_ERROR;
122	     else if(rxd_d1 == 8'hD5)
123	       rx_state   <= RX_FRAME;
124	     else if(rxd_d1 != 8'h55)
125	       rx_state   <= RX_ERROR;
126	   RX_FRAME :
127	     if(is_pause)
128	       rx_state <= RX_PAUSE;
129	     else if(~rx_dv_d1)
130	       if(match_crc)
131		 rx_state <= RX_GOODFRAME;
132	       else
133		 rx_state <= RX_ERROR;
134	   RX_PAUSE_CHK88 :
135	     if(rxd_d1 != 8'h88)
136	       rx_state <= RX_DROP;
137	     else
138	       rx_state <= RX_PAUSE_CHK08;
139	   RX_PAUSE_CHK08 :
140	     if(rxd_d1 != 8'h08)
141	       rx_state <= RX_DROP;
142	     else
143	       rx_state <= RX_PAUSE_CHK00;
144	   RX_PAUSE_CHK00 :
145	     if(rxd_d1 != 8'h00)
146	       rx_state <= RX_DROP;
147	     else
148	       rx_state <= RX_PAUSE_CHK01;
149	   RX_PAUSE_CHK01 :
150	     if(rxd_d1 != 8'h01)
151	       rx_state <= RX_DROP;
152	     else
153	       rx_state <= RX_PAUSE_STORE_MSB;
154	   RX_PAUSE_WAIT_CRC :
155	     if(pkt_long_enough)
156	       if(match_crc)
157		 rx_state <= RX_DO_PAUSE;
158	       else
159		 rx_state <= RX_DROP;
160	   RX_DO_PAUSE :
161	     rx_state <= RX_IDLE;
162	   RX_GOODFRAME :
163	     rx_state <= RX_IDLE;
164	   RX_DROP, RX_ERROR :
165	     if(~rx_dv_d1)
166	       rx_state <= RX_IDLE;
167	   default
168	     rx_state <= rx_state + 1;
169	 endcase // case (rx_state)
170
171   assign pause_rcvd = (rx_state == RX_DO_PAUSE);
172   crc crc_check(.clk(rx_clk),.reset(reset),.clear(clear_crc),
173		 .data(rxd_d1),.calc(calc_crc),.crc_out(),.match(match_crc));
174
175   always @(posedge rx_clk)
176     if(reset)
177       pause_quanta_rcvd <= 0;
178     else if(rx_state == RX_PAUSE_STORE_MSB)
179       pause_quanta_rcvd[15:8] <= rxd_d1;
180     else if(rx_state == RX_PAUSE_STORE_LSB)
181       pause_quanta_rcvd[7:0] <= rxd_d1;
182
183   assign debug = rx_state;
184
185endmodule // simple_gemac_rx
186