]>
Commit | Line | Data |
---|---|---|
1 | ////////////////////////////////////////////////////////////////////// | |
2 | //// //// | |
3 | //// eth_miim.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_miim.v,v $ | |
44 | // Revision 1.1 2007-03-20 17:50:56 sithglan | |
45 | // add shit | |
46 | // | |
47 | // Revision 1.7 2005/03/21 20:07:18 igorm | |
48 | // Some small fixes + some troubles fixed. | |
49 | // | |
50 | // Revision 1.6 2005/02/21 12:48:07 igorm | |
51 | // Warning fixes. | |
52 | // | |
53 | // Revision 1.5 2003/05/16 10:08:27 mohor | |
54 | // Busy was set 2 cycles too late. Reported by Dennis Scott. | |
55 | // | |
56 | // Revision 1.4 2002/08/14 18:32:10 mohor | |
57 | // - Busy signal was not set on time when scan status operation was performed | |
58 | // and clock was divided with more than 2. | |
59 | // - Nvalid remains valid two more clocks (was previously cleared too soon). | |
60 | // | |
61 | // Revision 1.3 2002/01/23 10:28:16 mohor | |
62 | // Link in the header changed. | |
63 | // | |
64 | // Revision 1.2 2001/10/19 08:43:51 mohor | |
65 | // eth_timescale.v changed to timescale.v This is done because of the | |
66 | // simulation of the few cores in a one joined project. | |
67 | // | |
68 | // Revision 1.1 2001/08/06 14:44:29 mohor | |
69 | // A define FPGA added to select between Artisan RAM (for ASIC) and Block Ram (For Virtex). | |
70 | // Include files fixed to contain no path. | |
71 | // File names and module names changed ta have a eth_ prologue in the name. | |
72 | // File eth_timescale.v is used to define timescale | |
73 | // All pin names on the top module are changed to contain _I, _O or _OE at the end. | |
74 | // Bidirectional signal MDIO is changed to three signals (Mdc_O, Mdi_I, Mdo_O | |
75 | // and Mdo_OE. The bidirectional signal must be created on the top level. This | |
76 | // is done due to the ASIC tools. | |
77 | // | |
78 | // Revision 1.2 2001/08/02 09:25:31 mohor | |
79 | // Unconnected signals are now connected. | |
80 | // | |
81 | // Revision 1.1 2001/07/30 21:23:42 mohor | |
82 | // Directory structure changed. Files checked and joind together. | |
83 | // | |
84 | // Revision 1.3 2001/06/01 22:28:56 mohor | |
85 | // This files (MIIM) are fully working. They were thoroughly tested. The testbench is not updated. | |
86 | // | |
87 | // | |
88 | ||
89 | `include "timescale.v" | |
90 | ||
91 | ||
92 | module eth_miim | |
93 | ( | |
94 | Clk, | |
95 | Reset, | |
96 | Divider, | |
97 | NoPre, | |
98 | CtrlData, | |
99 | Rgad, | |
100 | Fiad, | |
101 | WCtrlData, | |
102 | RStat, | |
103 | ScanStat, | |
104 | Mdi, | |
105 | Mdo, | |
106 | MdoEn, | |
107 | Mdc, | |
108 | Busy, | |
109 | Prsd, | |
110 | LinkFail, | |
111 | Nvalid, | |
112 | WCtrlDataStart, | |
113 | RStatStart, | |
114 | UpdateMIIRX_DATAReg | |
115 | ); | |
116 | ||
117 | ||
118 | ||
119 | input Clk; // Host Clock | |
120 | input Reset; // General Reset | |
121 | input [7:0] Divider; // Divider for the host clock | |
122 | input [15:0] CtrlData; // Control Data (to be written to the PHY reg.) | |
123 | input [4:0] Rgad; // Register Address (within the PHY) | |
124 | input [4:0] Fiad; // PHY Address | |
125 | input NoPre; // No Preamble (no 32-bit preamble) | |
126 | input WCtrlData; // Write Control Data operation | |
127 | input RStat; // Read Status operation | |
128 | input ScanStat; // Scan Status operation | |
129 | input Mdi; // MII Management Data In | |
130 | ||
131 | output Mdc; // MII Management Data Clock | |
132 | output Mdo; // MII Management Data Output | |
133 | output MdoEn; // MII Management Data Output Enable | |
134 | output Busy; // Busy Signal | |
135 | output LinkFail; // Link Integrity Signal | |
136 | output Nvalid; // Invalid Status (qualifier for the valid scan result) | |
137 | ||
138 | output [15:0] Prsd; // Read Status Data (data read from the PHY) | |
139 | ||
140 | output WCtrlDataStart; // This signals resets the WCTRLDATA bit in the MIIM Command register | |
141 | output RStatStart; // This signal resets the RSTAT BIT in the MIIM Command register | |
142 | output UpdateMIIRX_DATAReg;// Updates MII RX_DATA register with read data | |
143 | ||
144 | parameter Tp = 1; | |
145 | ||
146 | ||
147 | reg Nvalid; | |
148 | reg EndBusy_d; // Pre-end Busy signal | |
149 | reg EndBusy; // End Busy signal (stops the operation in progress) | |
150 | ||
151 | reg WCtrlData_q1; // Write Control Data operation delayed 1 Clk cycle | |
152 | reg WCtrlData_q2; // Write Control Data operation delayed 2 Clk cycles | |
153 | reg WCtrlData_q3; // Write Control Data operation delayed 3 Clk cycles | |
154 | reg WCtrlDataStart; // Start Write Control Data Command (positive edge detected) | |
155 | reg WCtrlDataStart_q; | |
156 | reg WCtrlDataStart_q1; // Start Write Control Data Command delayed 1 Mdc cycle | |
157 | reg WCtrlDataStart_q2; // Start Write Control Data Command delayed 2 Mdc cycles | |
158 | ||
159 | reg RStat_q1; // Read Status operation delayed 1 Clk cycle | |
160 | reg RStat_q2; // Read Status operation delayed 2 Clk cycles | |
161 | reg RStat_q3; // Read Status operation delayed 3 Clk cycles | |
162 | reg RStatStart; // Start Read Status Command (positive edge detected) | |
163 | reg RStatStart_q1; // Start Read Status Command delayed 1 Mdc cycle | |
164 | reg RStatStart_q2; // Start Read Status Command delayed 2 Mdc cycles | |
165 | ||
166 | reg ScanStat_q1; // Scan Status operation delayed 1 cycle | |
167 | reg ScanStat_q2; // Scan Status operation delayed 2 cycles | |
168 | reg SyncStatMdcEn; // Scan Status operation delayed at least cycles and synchronized to MdcEn | |
169 | ||
170 | wire WriteDataOp; // Write Data Operation (positive edge detected) | |
171 | wire ReadStatusOp; // Read Status Operation (positive edge detected) | |
172 | wire ScanStatusOp; // Scan Status Operation (positive edge detected) | |
173 | wire StartOp; // Start Operation (start of any of the preceding operations) | |
174 | wire EndOp; // End of Operation | |
175 | ||
176 | reg InProgress; // Operation in progress | |
177 | reg InProgress_q1; // Operation in progress delayed 1 Mdc cycle | |
178 | reg InProgress_q2; // Operation in progress delayed 2 Mdc cycles | |
179 | reg InProgress_q3; // Operation in progress delayed 3 Mdc cycles | |
180 | ||
181 | reg WriteOp; // Write Operation Latch (When asserted, write operation is in progress) | |
182 | reg [6:0] BitCounter; // Bit Counter | |
183 | ||
184 | ||
185 | wire [3:0] ByteSelect; // Byte Select defines which byte (preamble, data, operation, etc.) is loaded and shifted through the shift register. | |
186 | wire MdcEn; // MII Management Data Clock Enable signal is asserted for one Clk period before Mdc rises. | |
187 | wire ShiftedBit; // This bit is output of the shift register and is connected to the Mdo signal | |
188 | wire MdcEn_n; | |
189 | ||
190 | wire LatchByte1_d2; | |
191 | wire LatchByte0_d2; | |
192 | reg LatchByte1_d; | |
193 | reg LatchByte0_d; | |
194 | reg [1:0] LatchByte; // Latch Byte selects which part of Read Status Data is updated from the shift register | |
195 | ||
196 | reg UpdateMIIRX_DATAReg;// Updates MII RX_DATA register with read data | |
197 | ||
198 | ||
199 | ||
200 | ||
201 | ||
202 | // Generation of the EndBusy signal. It is used for ending the MII Management operation. | |
203 | always @ (posedge Clk or posedge Reset) | |
204 | begin | |
205 | if(Reset) | |
206 | begin | |
207 | EndBusy_d <= #Tp 1'b0; | |
208 | EndBusy <= #Tp 1'b0; | |
209 | end | |
210 | else | |
211 | begin | |
212 | EndBusy_d <= #Tp ~InProgress_q2 & InProgress_q3; | |
213 | EndBusy <= #Tp EndBusy_d; | |
214 | end | |
215 | end | |
216 | ||
217 | ||
218 | // Update MII RX_DATA register | |
219 | always @ (posedge Clk or posedge Reset) | |
220 | begin | |
221 | if(Reset) | |
222 | UpdateMIIRX_DATAReg <= #Tp 0; | |
223 | else | |
224 | if(EndBusy & ~WCtrlDataStart_q) | |
225 | UpdateMIIRX_DATAReg <= #Tp 1; | |
226 | else | |
227 | UpdateMIIRX_DATAReg <= #Tp 0; | |
228 | end | |
229 | ||
230 | ||
231 | ||
232 | // Generation of the delayed signals used for positive edge triggering. | |
233 | always @ (posedge Clk or posedge Reset) | |
234 | begin | |
235 | if(Reset) | |
236 | begin | |
237 | WCtrlData_q1 <= #Tp 1'b0; | |
238 | WCtrlData_q2 <= #Tp 1'b0; | |
239 | WCtrlData_q3 <= #Tp 1'b0; | |
240 | ||
241 | RStat_q1 <= #Tp 1'b0; | |
242 | RStat_q2 <= #Tp 1'b0; | |
243 | RStat_q3 <= #Tp 1'b0; | |
244 | ||
245 | ScanStat_q1 <= #Tp 1'b0; | |
246 | ScanStat_q2 <= #Tp 1'b0; | |
247 | SyncStatMdcEn <= #Tp 1'b0; | |
248 | end | |
249 | else | |
250 | begin | |
251 | WCtrlData_q1 <= #Tp WCtrlData; | |
252 | WCtrlData_q2 <= #Tp WCtrlData_q1; | |
253 | WCtrlData_q3 <= #Tp WCtrlData_q2; | |
254 | ||
255 | RStat_q1 <= #Tp RStat; | |
256 | RStat_q2 <= #Tp RStat_q1; | |
257 | RStat_q3 <= #Tp RStat_q2; | |
258 | ||
259 | ScanStat_q1 <= #Tp ScanStat; | |
260 | ScanStat_q2 <= #Tp ScanStat_q1; | |
261 | if(MdcEn) | |
262 | SyncStatMdcEn <= #Tp ScanStat_q2; | |
263 | end | |
264 | end | |
265 | ||
266 | ||
267 | // Generation of the Start Commands (Write Control Data or Read Status) | |
268 | always @ (posedge Clk or posedge Reset) | |
269 | begin | |
270 | if(Reset) | |
271 | begin | |
272 | WCtrlDataStart <= #Tp 1'b0; | |
273 | WCtrlDataStart_q <= #Tp 1'b0; | |
274 | RStatStart <= #Tp 1'b0; | |
275 | end | |
276 | else | |
277 | begin | |
278 | if(EndBusy) | |
279 | begin | |
280 | WCtrlDataStart <= #Tp 1'b0; | |
281 | RStatStart <= #Tp 1'b0; | |
282 | end | |
283 | else | |
284 | begin | |
285 | if(WCtrlData_q2 & ~WCtrlData_q3) | |
286 | WCtrlDataStart <= #Tp 1'b1; | |
287 | if(RStat_q2 & ~RStat_q3) | |
288 | RStatStart <= #Tp 1'b1; | |
289 | WCtrlDataStart_q <= #Tp WCtrlDataStart; | |
290 | end | |
291 | end | |
292 | end | |
293 | ||
294 | ||
295 | // Generation of the Nvalid signal (indicates when the status is invalid) | |
296 | always @ (posedge Clk or posedge Reset) | |
297 | begin | |
298 | if(Reset) | |
299 | Nvalid <= #Tp 1'b0; | |
300 | else | |
301 | begin | |
302 | if(~InProgress_q2 & InProgress_q3) | |
303 | begin | |
304 | Nvalid <= #Tp 1'b0; | |
305 | end | |
306 | else | |
307 | begin | |
308 | if(ScanStat_q2 & ~SyncStatMdcEn) | |
309 | Nvalid <= #Tp 1'b1; | |
310 | end | |
311 | end | |
312 | end | |
313 | ||
314 | // Signals used for the generation of the Operation signals (positive edge) | |
315 | always @ (posedge Clk or posedge Reset) | |
316 | begin | |
317 | if(Reset) | |
318 | begin | |
319 | WCtrlDataStart_q1 <= #Tp 1'b0; | |
320 | WCtrlDataStart_q2 <= #Tp 1'b0; | |
321 | ||
322 | RStatStart_q1 <= #Tp 1'b0; | |
323 | RStatStart_q2 <= #Tp 1'b0; | |
324 | ||
325 | InProgress_q1 <= #Tp 1'b0; | |
326 | InProgress_q2 <= #Tp 1'b0; | |
327 | InProgress_q3 <= #Tp 1'b0; | |
328 | ||
329 | LatchByte0_d <= #Tp 1'b0; | |
330 | LatchByte1_d <= #Tp 1'b0; | |
331 | ||
332 | LatchByte <= #Tp 2'b00; | |
333 | end | |
334 | else | |
335 | begin | |
336 | if(MdcEn) | |
337 | begin | |
338 | WCtrlDataStart_q1 <= #Tp WCtrlDataStart; | |
339 | WCtrlDataStart_q2 <= #Tp WCtrlDataStart_q1; | |
340 | ||
341 | RStatStart_q1 <= #Tp RStatStart; | |
342 | RStatStart_q2 <= #Tp RStatStart_q1; | |
343 | ||
344 | LatchByte[0] <= #Tp LatchByte0_d; | |
345 | LatchByte[1] <= #Tp LatchByte1_d; | |
346 | ||
347 | LatchByte0_d <= #Tp LatchByte0_d2; | |
348 | LatchByte1_d <= #Tp LatchByte1_d2; | |
349 | ||
350 | InProgress_q1 <= #Tp InProgress; | |
351 | InProgress_q2 <= #Tp InProgress_q1; | |
352 | InProgress_q3 <= #Tp InProgress_q2; | |
353 | end | |
354 | end | |
355 | end | |
356 | ||
357 | ||
358 | // Generation of the Operation signals | |
359 | assign WriteDataOp = WCtrlDataStart_q1 & ~WCtrlDataStart_q2; | |
360 | assign ReadStatusOp = RStatStart_q1 & ~RStatStart_q2; | |
361 | assign ScanStatusOp = SyncStatMdcEn & ~InProgress & ~InProgress_q1 & ~InProgress_q2; | |
362 | assign StartOp = WriteDataOp | ReadStatusOp | ScanStatusOp; | |
363 | ||
364 | // Busy | |
365 | assign Busy = WCtrlData | WCtrlDataStart | RStat | RStatStart | SyncStatMdcEn | EndBusy | InProgress | InProgress_q3 | Nvalid; | |
366 | ||
367 | ||
368 | // Generation of the InProgress signal (indicates when an operation is in progress) | |
369 | // Generation of the WriteOp signal (indicates when a write is in progress) | |
370 | always @ (posedge Clk or posedge Reset) | |
371 | begin | |
372 | if(Reset) | |
373 | begin | |
374 | InProgress <= #Tp 1'b0; | |
375 | WriteOp <= #Tp 1'b0; | |
376 | end | |
377 | else | |
378 | begin | |
379 | if(MdcEn) | |
380 | begin | |
381 | if(StartOp) | |
382 | begin | |
383 | if(~InProgress) | |
384 | WriteOp <= #Tp WriteDataOp; | |
385 | InProgress <= #Tp 1'b1; | |
386 | end | |
387 | else | |
388 | begin | |
389 | if(EndOp) | |
390 | begin | |
391 | InProgress <= #Tp 1'b0; | |
392 | WriteOp <= #Tp 1'b0; | |
393 | end | |
394 | end | |
395 | end | |
396 | end | |
397 | end | |
398 | ||
399 | ||
400 | ||
401 | // Bit Counter counts from 0 to 63 (from 32 to 63 when NoPre is asserted) | |
402 | always @ (posedge Clk or posedge Reset) | |
403 | begin | |
404 | if(Reset) | |
405 | BitCounter[6:0] <= #Tp 7'h0; | |
406 | else | |
407 | begin | |
408 | if(MdcEn) | |
409 | begin | |
410 | if(InProgress) | |
411 | begin | |
412 | if(NoPre & ( BitCounter == 7'h0 )) | |
413 | BitCounter[6:0] <= #Tp 7'h21; | |
414 | else | |
415 | BitCounter[6:0] <= #Tp BitCounter[6:0] + 1'b1; | |
416 | end | |
417 | else | |
418 | BitCounter[6:0] <= #Tp 7'h0; | |
419 | end | |
420 | end | |
421 | end | |
422 | ||
423 | ||
424 | // Operation ends when the Bit Counter reaches 63 | |
425 | assign EndOp = BitCounter==63; | |
426 | ||
427 | assign ByteSelect[0] = InProgress & ((NoPre & (BitCounter == 7'h0)) | (~NoPre & (BitCounter == 7'h20))); | |
428 | assign ByteSelect[1] = InProgress & (BitCounter == 7'h28); | |
429 | assign ByteSelect[2] = InProgress & WriteOp & (BitCounter == 7'h30); | |
430 | assign ByteSelect[3] = InProgress & WriteOp & (BitCounter == 7'h38); | |
431 | ||
432 | ||
433 | // Latch Byte selects which part of Read Status Data is updated from the shift register | |
434 | assign LatchByte1_d2 = InProgress & ~WriteOp & BitCounter == 7'h37; | |
435 | assign LatchByte0_d2 = InProgress & ~WriteOp & BitCounter == 7'h3F; | |
436 | ||
437 | ||
438 | // Connecting the Clock Generator Module | |
439 | eth_clockgen clkgen(.Clk(Clk), .Reset(Reset), .Divider(Divider[7:0]), .MdcEn(MdcEn), .MdcEn_n(MdcEn_n), .Mdc(Mdc) | |
440 | ); | |
441 | ||
442 | // Connecting the Shift Register Module | |
443 | eth_shiftreg shftrg(.Clk(Clk), .Reset(Reset), .MdcEn_n(MdcEn_n), .Mdi(Mdi), .Fiad(Fiad), .Rgad(Rgad), | |
444 | .CtrlData(CtrlData), .WriteOp(WriteOp), .ByteSelect(ByteSelect), .LatchByte(LatchByte), | |
445 | .ShiftedBit(ShiftedBit), .Prsd(Prsd), .LinkFail(LinkFail) | |
446 | ); | |
447 | ||
448 | // Connecting the Output Control Module | |
449 | eth_outputcontrol outctrl(.Clk(Clk), .Reset(Reset), .MdcEn_n(MdcEn_n), .InProgress(InProgress), | |
450 | .ShiftedBit(ShiftedBit), .BitCounter(BitCounter), .WriteOp(WriteOp), .NoPre(NoPre), | |
451 | .Mdo(Mdo), .MdoEn(MdoEn) | |
452 | ); | |
453 | ||
454 | endmodule |