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