1 | ////////////////////////////////////////////////////////////////////// |
---|
2 | //// //// |
---|
3 | //// eth_receivecontrol.v //// |
---|
4 | //// //// |
---|
5 | //// This file is part of the Ethernet IP core project //// |
---|
6 | //// http://www.opencores.org/projects/ethmac/ //// |
---|
7 | //// //// |
---|
8 | //// Author(s): //// |
---|
9 | //// - Igor Mohor ([email protected]) //// |
---|
10 | //// //// |
---|
11 | //// All additional information is avaliable in the Readme.txt //// |
---|
12 | //// file. //// |
---|
13 | //// //// |
---|
14 | ////////////////////////////////////////////////////////////////////// |
---|
15 | //// //// |
---|
16 | //// Copyright (C) 2001 Authors //// |
---|
17 | //// //// |
---|
18 | //// This source file may be used and distributed without //// |
---|
19 | //// restriction provided that this copyright statement is not //// |
---|
20 | //// removed from the file and that any derivative work contains //// |
---|
21 | //// the original copyright notice and the associated disclaimer. //// |
---|
22 | //// //// |
---|
23 | //// This source file is free software; you can redistribute it //// |
---|
24 | //// and/or modify it under the terms of the GNU Lesser General //// |
---|
25 | //// Public License as published by the Free Software Foundation; //// |
---|
26 | //// either version 2.1 of the License, or (at your option) any //// |
---|
27 | //// later version. //// |
---|
28 | //// //// |
---|
29 | //// This source is distributed in the hope that it will be //// |
---|
30 | //// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
---|
31 | //// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
---|
32 | //// PURPOSE. See the GNU Lesser General Public License for more //// |
---|
33 | //// details. //// |
---|
34 | //// //// |
---|
35 | //// You should have received a copy of the GNU Lesser General //// |
---|
36 | //// Public License along with this source; if not, download it //// |
---|
37 | //// from http://www.opencores.org/lgpl.shtml //// |
---|
38 | //// //// |
---|
39 | ////////////////////////////////////////////////////////////////////// |
---|
40 | // |
---|
41 | // CVS Revision History |
---|
42 | // |
---|
43 | // $Log: not supported by cvs2svn $ |
---|
44 | // Revision 1.4 2002/11/22 01:57:06 mohor |
---|
45 | // Rx Flow control fixed. CF flag added to the RX buffer descriptor. RxAbort |
---|
46 | // synchronized. |
---|
47 | // |
---|
48 | // Revision 1.3 2002/01/23 10:28:16 mohor |
---|
49 | // Link in the header changed. |
---|
50 | // |
---|
51 | // Revision 1.2 2001/10/19 08:43:51 mohor |
---|
52 | // eth_timescale.v changed to timescale.v This is done because of the |
---|
53 | // simulation of the few cores in a one joined project. |
---|
54 | // |
---|
55 | // Revision 1.1 2001/08/06 14:44:29 mohor |
---|
56 | // A define FPGA added to select between Artisan RAM (for ASIC) and Block Ram (For Virtex). |
---|
57 | // Include files fixed to contain no path. |
---|
58 | // File names and module names changed ta have a eth_ prologue in the name. |
---|
59 | // File eth_timescale.v is used to define timescale |
---|
60 | // All pin names on the top module are changed to contain _I, _O or _OE at the end. |
---|
61 | // Bidirectional signal MDIO is changed to three signals (Mdc_O, Mdi_I, Mdo_O |
---|
62 | // and Mdo_OE. The bidirectional signal must be created on the top level. This |
---|
63 | // is done due to the ASIC tools. |
---|
64 | // |
---|
65 | // Revision 1.1 2001/07/30 21:23:42 mohor |
---|
66 | // Directory structure changed. Files checked and joind together. |
---|
67 | // |
---|
68 | // Revision 1.1 2001/07/03 12:51:54 mohor |
---|
69 | // Initial release of the MAC Control module. |
---|
70 | // |
---|
71 | // |
---|
72 | // |
---|
73 | // |
---|
74 | // |
---|
75 | |
---|
76 | |
---|
77 | `include "timescale.v" |
---|
78 | |
---|
79 | |
---|
80 | module eth_receivecontrol (MTxClk, MRxClk, TxReset, RxReset, RxData, RxValid, RxStartFrm, |
---|
81 | RxEndFrm, RxFlow, ReceiveEnd, MAC, DlyCrcEn, TxDoneIn, |
---|
82 | TxAbortIn, TxStartFrmOut, ReceivedLengthOK, ReceivedPacketGood, |
---|
83 | TxUsedDataOutDetected, Pause, ReceivedPauseFrm, AddressOK, |
---|
84 | RxStatusWriteLatched_sync2, r_PassAll, SetPauseTimer |
---|
85 | ); |
---|
86 | |
---|
87 | parameter Tp = 1; |
---|
88 | |
---|
89 | |
---|
90 | input MTxClk; |
---|
91 | input MRxClk; |
---|
92 | input TxReset; |
---|
93 | input RxReset; |
---|
94 | input [7:0] RxData; |
---|
95 | input RxValid; |
---|
96 | input RxStartFrm; |
---|
97 | input RxEndFrm; |
---|
98 | input RxFlow; |
---|
99 | input ReceiveEnd; |
---|
100 | input [47:0]MAC; |
---|
101 | input DlyCrcEn; |
---|
102 | input TxDoneIn; |
---|
103 | input TxAbortIn; |
---|
104 | input TxStartFrmOut; |
---|
105 | input ReceivedLengthOK; |
---|
106 | input ReceivedPacketGood; |
---|
107 | input TxUsedDataOutDetected; |
---|
108 | input RxStatusWriteLatched_sync2; |
---|
109 | input r_PassAll; |
---|
110 | |
---|
111 | output Pause; |
---|
112 | output ReceivedPauseFrm; |
---|
113 | output AddressOK; |
---|
114 | output SetPauseTimer; |
---|
115 | |
---|
116 | |
---|
117 | reg Pause; |
---|
118 | reg AddressOK; // Multicast or unicast address detected |
---|
119 | reg TypeLengthOK; // Type/Length field contains 0x8808 |
---|
120 | reg DetectionWindow; // Detection of the PAUSE frame is possible within this window |
---|
121 | reg OpCodeOK; // PAUSE opcode detected (0x0001) |
---|
122 | reg [2:0] DlyCrcCnt; |
---|
123 | reg [4:0] ByteCnt; |
---|
124 | reg [15:0] AssembledTimerValue; |
---|
125 | reg [15:0] LatchedTimerValue; |
---|
126 | reg ReceivedPauseFrm; |
---|
127 | reg ReceivedPauseFrmWAddr; |
---|
128 | reg PauseTimerEq0_sync1; |
---|
129 | reg PauseTimerEq0_sync2; |
---|
130 | reg [15:0] PauseTimer; |
---|
131 | reg Divider2; |
---|
132 | reg [5:0] SlotTimer; |
---|
133 | |
---|
134 | wire [47:0] ReservedMulticast; // 0x0180C2000001 |
---|
135 | wire [15:0] TypeLength; // 0x8808 |
---|
136 | wire ResetByteCnt; // |
---|
137 | wire IncrementByteCnt; // |
---|
138 | wire ByteCntEq0; // ByteCnt = 0 |
---|
139 | wire ByteCntEq1; // ByteCnt = 1 |
---|
140 | wire ByteCntEq2; // ByteCnt = 2 |
---|
141 | wire ByteCntEq3; // ByteCnt = 3 |
---|
142 | wire ByteCntEq4; // ByteCnt = 4 |
---|
143 | wire ByteCntEq5; // ByteCnt = 5 |
---|
144 | wire ByteCntEq12; // ByteCnt = 12 |
---|
145 | wire ByteCntEq13; // ByteCnt = 13 |
---|
146 | wire ByteCntEq14; // ByteCnt = 14 |
---|
147 | wire ByteCntEq15; // ByteCnt = 15 |
---|
148 | wire ByteCntEq16; // ByteCnt = 16 |
---|
149 | wire ByteCntEq17; // ByteCnt = 17 |
---|
150 | wire ByteCntEq18; // ByteCnt = 18 |
---|
151 | wire DecrementPauseTimer; // |
---|
152 | wire PauseTimerEq0; // |
---|
153 | wire ResetSlotTimer; // |
---|
154 | wire IncrementSlotTimer; // |
---|
155 | wire SlotFinished; // |
---|
156 | |
---|
157 | |
---|
158 | |
---|
159 | // Reserved multicast address and Type/Length for PAUSE control |
---|
160 | assign ReservedMulticast = 48'h0180C2000001; |
---|
161 | assign TypeLength = 16'h8808; |
---|
162 | |
---|
163 | |
---|
164 | // Address Detection (Multicast or unicast) |
---|
165 | always @ (posedge MRxClk or posedge RxReset) |
---|
166 | begin |
---|
167 | if(RxReset) |
---|
168 | AddressOK <= #Tp 1'b0; |
---|
169 | else |
---|
170 | if(DetectionWindow & ByteCntEq0) |
---|
171 | AddressOK <= #Tp RxData[7:0] == ReservedMulticast[47:40] | RxData[7:0] == MAC[47:40]; |
---|
172 | else |
---|
173 | if(DetectionWindow & ByteCntEq1) |
---|
174 | AddressOK <= #Tp (RxData[7:0] == ReservedMulticast[39:32] | RxData[7:0] == MAC[39:32]) & AddressOK; |
---|
175 | else |
---|
176 | if(DetectionWindow & ByteCntEq2) |
---|
177 | AddressOK <= #Tp (RxData[7:0] == ReservedMulticast[31:24] | RxData[7:0] == MAC[31:24]) & AddressOK; |
---|
178 | else |
---|
179 | if(DetectionWindow & ByteCntEq3) |
---|
180 | AddressOK <= #Tp (RxData[7:0] == ReservedMulticast[23:16] | RxData[7:0] == MAC[23:16]) & AddressOK; |
---|
181 | else |
---|
182 | if(DetectionWindow & ByteCntEq4) |
---|
183 | AddressOK <= #Tp (RxData[7:0] == ReservedMulticast[15:8] | RxData[7:0] == MAC[15:8]) & AddressOK; |
---|
184 | else |
---|
185 | if(DetectionWindow & ByteCntEq5) |
---|
186 | AddressOK <= #Tp (RxData[7:0] == ReservedMulticast[7:0] | RxData[7:0] == MAC[7:0]) & AddressOK; |
---|
187 | else |
---|
188 | if(ReceiveEnd) |
---|
189 | AddressOK <= #Tp 1'b0; |
---|
190 | end |
---|
191 | |
---|
192 | |
---|
193 | |
---|
194 | // TypeLengthOK (Type/Length Control frame detected) |
---|
195 | always @ (posedge MRxClk or posedge RxReset ) |
---|
196 | begin |
---|
197 | if(RxReset) |
---|
198 | TypeLengthOK <= #Tp 1'b0; |
---|
199 | else |
---|
200 | if(DetectionWindow & ByteCntEq12) |
---|
201 | TypeLengthOK <= #Tp ByteCntEq12 & (RxData[7:0] == TypeLength[15:8]); |
---|
202 | else |
---|
203 | if(DetectionWindow & ByteCntEq13) |
---|
204 | TypeLengthOK <= #Tp ByteCntEq13 & (RxData[7:0] == TypeLength[7:0]) & TypeLengthOK; |
---|
205 | else |
---|
206 | if(ReceiveEnd) |
---|
207 | TypeLengthOK <= #Tp 1'b0; |
---|
208 | end |
---|
209 | |
---|
210 | |
---|
211 | |
---|
212 | // Latch Control Frame Opcode |
---|
213 | always @ (posedge MRxClk or posedge RxReset ) |
---|
214 | begin |
---|
215 | if(RxReset) |
---|
216 | OpCodeOK <= #Tp 1'b0; |
---|
217 | else |
---|
218 | if(ByteCntEq16) |
---|
219 | OpCodeOK <= #Tp 1'b0; |
---|
220 | else |
---|
221 | begin |
---|
222 | if(DetectionWindow & ByteCntEq14) |
---|
223 | OpCodeOK <= #Tp ByteCntEq14 & RxData[7:0] == 8'h00; |
---|
224 | |
---|
225 | if(DetectionWindow & ByteCntEq15) |
---|
226 | OpCodeOK <= #Tp ByteCntEq15 & RxData[7:0] == 8'h01 & OpCodeOK; |
---|
227 | end |
---|
228 | end |
---|
229 | |
---|
230 | |
---|
231 | // ReceivedPauseFrmWAddr (+Address Check) |
---|
232 | always @ (posedge MRxClk or posedge RxReset ) |
---|
233 | begin |
---|
234 | if(RxReset) |
---|
235 | ReceivedPauseFrmWAddr <= #Tp 1'b0; |
---|
236 | else |
---|
237 | if(ReceiveEnd) |
---|
238 | ReceivedPauseFrmWAddr <= #Tp 1'b0; |
---|
239 | else |
---|
240 | if(ByteCntEq16 & TypeLengthOK & OpCodeOK & AddressOK) |
---|
241 | ReceivedPauseFrmWAddr <= #Tp 1'b1; |
---|
242 | end |
---|
243 | |
---|
244 | |
---|
245 | |
---|
246 | // Assembling 16-bit timer value from two 8-bit data |
---|
247 | always @ (posedge MRxClk or posedge RxReset ) |
---|
248 | begin |
---|
249 | if(RxReset) |
---|
250 | AssembledTimerValue[15:0] <= #Tp 16'h0; |
---|
251 | else |
---|
252 | if(RxStartFrm) |
---|
253 | AssembledTimerValue[15:0] <= #Tp 16'h0; |
---|
254 | else |
---|
255 | begin |
---|
256 | if(DetectionWindow & ByteCntEq16) |
---|
257 | AssembledTimerValue[15:8] <= #Tp RxData[7:0]; |
---|
258 | if(DetectionWindow & ByteCntEq17) |
---|
259 | AssembledTimerValue[7:0] <= #Tp RxData[7:0]; |
---|
260 | end |
---|
261 | end |
---|
262 | |
---|
263 | |
---|
264 | // Detection window (while PAUSE detection is possible) |
---|
265 | always @ (posedge MRxClk or posedge RxReset ) |
---|
266 | begin |
---|
267 | if(RxReset) |
---|
268 | DetectionWindow <= #Tp 1'b1; |
---|
269 | else |
---|
270 | if(ByteCntEq18) |
---|
271 | DetectionWindow <= #Tp 1'b0; |
---|
272 | else |
---|
273 | if(ReceiveEnd) |
---|
274 | DetectionWindow <= #Tp 1'b1; |
---|
275 | end |
---|
276 | |
---|
277 | |
---|
278 | |
---|
279 | // Latching Timer Value |
---|
280 | always @ (posedge MRxClk or posedge RxReset ) |
---|
281 | begin |
---|
282 | if(RxReset) |
---|
283 | LatchedTimerValue[15:0] <= #Tp 16'h0; |
---|
284 | else |
---|
285 | if(DetectionWindow & ReceivedPauseFrmWAddr & ByteCntEq18) |
---|
286 | LatchedTimerValue[15:0] <= #Tp AssembledTimerValue[15:0]; |
---|
287 | else |
---|
288 | if(ReceiveEnd) |
---|
289 | LatchedTimerValue[15:0] <= #Tp 16'h0; |
---|
290 | end |
---|
291 | |
---|
292 | |
---|
293 | |
---|
294 | // Delayed CEC counter |
---|
295 | always @ (posedge MRxClk or posedge RxReset) |
---|
296 | begin |
---|
297 | if(RxReset) |
---|
298 | DlyCrcCnt <= #Tp 3'h0; |
---|
299 | else |
---|
300 | if(RxValid & RxEndFrm) |
---|
301 | DlyCrcCnt <= #Tp 3'h0; |
---|
302 | else |
---|
303 | if(RxValid & ~RxEndFrm & ~DlyCrcCnt[2]) |
---|
304 | DlyCrcCnt <= #Tp DlyCrcCnt + 1'b1; |
---|
305 | end |
---|
306 | |
---|
307 | |
---|
308 | assign ResetByteCnt = RxEndFrm; |
---|
309 | assign IncrementByteCnt = RxValid & DetectionWindow & ~ByteCntEq18 & (~DlyCrcEn | DlyCrcEn & DlyCrcCnt[2]); |
---|
310 | |
---|
311 | |
---|
312 | // Byte counter |
---|
313 | always @ (posedge MRxClk or posedge RxReset) |
---|
314 | begin |
---|
315 | if(RxReset) |
---|
316 | ByteCnt[4:0] <= #Tp 5'h0; |
---|
317 | else |
---|
318 | if(ResetByteCnt) |
---|
319 | ByteCnt[4:0] <= #Tp 5'h0; |
---|
320 | else |
---|
321 | if(IncrementByteCnt) |
---|
322 | ByteCnt[4:0] <= #Tp ByteCnt[4:0] + 1'b1; |
---|
323 | end |
---|
324 | |
---|
325 | |
---|
326 | assign ByteCntEq0 = RxValid & ByteCnt[4:0] == 5'h0; |
---|
327 | assign ByteCntEq1 = RxValid & ByteCnt[4:0] == 5'h1; |
---|
328 | assign ByteCntEq2 = RxValid & ByteCnt[4:0] == 5'h2; |
---|
329 | assign ByteCntEq3 = RxValid & ByteCnt[4:0] == 5'h3; |
---|
330 | assign ByteCntEq4 = RxValid & ByteCnt[4:0] == 5'h4; |
---|
331 | assign ByteCntEq5 = RxValid & ByteCnt[4:0] == 5'h5; |
---|
332 | assign ByteCntEq12 = RxValid & ByteCnt[4:0] == 5'h0C; |
---|
333 | assign ByteCntEq13 = RxValid & ByteCnt[4:0] == 5'h0D; |
---|
334 | assign ByteCntEq14 = RxValid & ByteCnt[4:0] == 5'h0E; |
---|
335 | assign ByteCntEq15 = RxValid & ByteCnt[4:0] == 5'h0F; |
---|
336 | assign ByteCntEq16 = RxValid & ByteCnt[4:0] == 5'h10; |
---|
337 | assign ByteCntEq17 = RxValid & ByteCnt[4:0] == 5'h11; |
---|
338 | assign ByteCntEq18 = RxValid & ByteCnt[4:0] == 5'h12 & DetectionWindow; |
---|
339 | |
---|
340 | |
---|
341 | assign SetPauseTimer = ReceiveEnd & ReceivedPauseFrmWAddr & ReceivedPacketGood & ReceivedLengthOK & RxFlow; |
---|
342 | assign DecrementPauseTimer = SlotFinished & |PauseTimer; |
---|
343 | |
---|
344 | |
---|
345 | // PauseTimer[15:0] |
---|
346 | always @ (posedge MRxClk or posedge RxReset) |
---|
347 | begin |
---|
348 | if(RxReset) |
---|
349 | PauseTimer[15:0] <= #Tp 16'h0; |
---|
350 | else |
---|
351 | if(SetPauseTimer) |
---|
352 | PauseTimer[15:0] <= #Tp LatchedTimerValue[15:0]; |
---|
353 | else |
---|
354 | if(DecrementPauseTimer) |
---|
355 | PauseTimer[15:0] <= #Tp PauseTimer[15:0] - 1'b1; |
---|
356 | end |
---|
357 | |
---|
358 | assign PauseTimerEq0 = ~(|PauseTimer[15:0]); |
---|
359 | |
---|
360 | |
---|
361 | |
---|
362 | // Synchronization of the pause timer |
---|
363 | always @ (posedge MTxClk or posedge TxReset) |
---|
364 | begin |
---|
365 | if(TxReset) |
---|
366 | begin |
---|
367 | PauseTimerEq0_sync1 <= #Tp 1'b1; |
---|
368 | PauseTimerEq0_sync2 <= #Tp 1'b1; |
---|
369 | end |
---|
370 | else |
---|
371 | begin |
---|
372 | PauseTimerEq0_sync1 <= #Tp PauseTimerEq0; |
---|
373 | PauseTimerEq0_sync2 <= #Tp PauseTimerEq0_sync1; |
---|
374 | end |
---|
375 | end |
---|
376 | |
---|
377 | |
---|
378 | // Pause signal generation |
---|
379 | always @ (posedge MTxClk or posedge TxReset) |
---|
380 | begin |
---|
381 | if(TxReset) |
---|
382 | Pause <= #Tp 1'b0; |
---|
383 | else |
---|
384 | if((TxDoneIn | TxAbortIn | ~TxUsedDataOutDetected) & ~TxStartFrmOut) |
---|
385 | Pause <= #Tp RxFlow & ~PauseTimerEq0_sync2; |
---|
386 | end |
---|
387 | |
---|
388 | |
---|
389 | // Divider2 is used for incrementing the Slot timer every other clock |
---|
390 | always @ (posedge MRxClk or posedge RxReset) |
---|
391 | begin |
---|
392 | if(RxReset) |
---|
393 | Divider2 <= #Tp 1'b0; |
---|
394 | else |
---|
395 | if(|PauseTimer[15:0] & RxFlow) |
---|
396 | Divider2 <= #Tp ~Divider2; |
---|
397 | else |
---|
398 | Divider2 <= #Tp 1'b0; |
---|
399 | end |
---|
400 | |
---|
401 | |
---|
402 | assign ResetSlotTimer = RxReset; |
---|
403 | assign IncrementSlotTimer = Pause & RxFlow & Divider2; |
---|
404 | |
---|
405 | |
---|
406 | // SlotTimer |
---|
407 | always @ (posedge MRxClk or posedge RxReset) |
---|
408 | begin |
---|
409 | if(RxReset) |
---|
410 | SlotTimer[5:0] <= #Tp 6'h0; |
---|
411 | else |
---|
412 | if(ResetSlotTimer) |
---|
413 | SlotTimer[5:0] <= #Tp 6'h0; |
---|
414 | else |
---|
415 | if(IncrementSlotTimer) |
---|
416 | SlotTimer[5:0] <= #Tp SlotTimer[5:0] + 1'b1; |
---|
417 | end |
---|
418 | |
---|
419 | |
---|
420 | assign SlotFinished = &SlotTimer[5:0] & IncrementSlotTimer; // Slot is 512 bits (64 bytes) |
---|
421 | |
---|
422 | |
---|
423 | |
---|
424 | // Pause Frame received |
---|
425 | always @ (posedge MRxClk or posedge RxReset) |
---|
426 | begin |
---|
427 | if(RxReset) |
---|
428 | ReceivedPauseFrm <=#Tp 1'b0; |
---|
429 | else |
---|
430 | if(RxStatusWriteLatched_sync2 & r_PassAll | ReceivedPauseFrm & (~r_PassAll)) |
---|
431 | ReceivedPauseFrm <=#Tp 1'b0; |
---|
432 | else |
---|
433 | if(ByteCntEq16 & TypeLengthOK & OpCodeOK) |
---|
434 | ReceivedPauseFrm <=#Tp 1'b1; |
---|
435 | end |
---|
436 | |
---|
437 | |
---|
438 | endmodule |
---|