OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [orpsocv2/] [bench/] [verilog/] [smii_phy.v] - Blame information for rev 51

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 44 julius
//////////////////////////////////////////////////////////////////////
2
////                                                              ////
3
////  SMII Receiver/Decoder (usually at PHY end)                  ////
4
////                                                              ////
5
////  Description                                                 ////
6
////  Low pin count serial MII ethernet interface                 ////
7
////                                                              ////
8
////  To Do:                                                      ////
9
////   -                                                          ////
10
////                                                              ////
11
////  Author(s):                                                  ////
12
////      - Michael Unneback, unneback@opencores.org              ////
13
////        ORSoC AB          michael.unneback@orsoc.se           ////
14
////      - Julius Baxter, jb@orsoc.se                            ////
15
////                                                              ////
16
//////////////////////////////////////////////////////////////////////
17
////                                                              ////
18
//// Copyright (C) 2009 Authors and OPENCORES.ORG                 ////
19
////                                                              ////
20
//// This source file may be used and distributed without         ////
21
//// restriction provided that this copyright statement is not    ////
22
//// removed from the file and that any derivative work contains  ////
23
//// the original copyright notice and the associated disclaimer. ////
24
////                                                              ////
25
//// This source file is free software; you can redistribute it   ////
26
//// and/or modify it under the terms of the GNU Lesser General   ////
27
//// Public License as published by the Free Software Foundation; ////
28
//// either version 2.1 of the License, or (at your option) any   ////
29
//// later version.                                               ////
30
////                                                              ////
31
//// This source is distributed in the hope that it will be       ////
32
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
33
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
34
//// PURPOSE.  See the GNU Lesser General Public License for more ////
35
//// details.                                                     ////
36
////                                                              ////
37
//// You should have received a copy of the GNU Lesser General    ////
38
//// Public License along with this source; if not, download it   ////
39
//// from http://www.opencores.org/lgpl.shtml                     ////
40
////                                                              ////
41
//////////////////////////////////////////////////////////////////////
42
module smii_phy
43
  (
44
   // SMII
45
    input     smii_tx,
46
    input     smii_sync,
47 49 julius
    output reg    smii_rx,
48 44 julius
 
49
   // MII
50
   // TX
51
   /* ALL I/Os swapped compared to SMII on MAC end MAC - jb */
52
    output reg [3:0] ethphy_mii_tx_d,
53
    output reg       ethphy_mii_tx_en,
54
    output reg       ethphy_mii_tx_err,
55
    input            ethphy_mii_tx_clk,
56
   // RX
57
    input [3:0]      ethphy_mii_rx_d,
58
    input            ethphy_mii_rx_dv,
59
    input            ethphy_mii_rx_err,
60
    input            ethphy_mii_rx_clk,
61
    input            ethphy_mii_mcoll,
62
    input            ethphy_mii_crs,
63
 
64
    input            fast_ethernet,
65
    input            duplex,
66
    input            link,
67
 
68
   // internal
69
    //input [10:1] state,
70
   // clock and reset
71
    input        clk, /* Global reference clock for both SMII modules */
72
    input        rst_n
73
   );
74
 
75
   reg [3:0]      rx_tmp;
76
 
77
   reg           jabber = 0;
78
 
79
   reg           mtx_clk_tmp, mrx_clk_tmp;
80
 
81
   reg [3:0]      tx_cnt;
82
   reg [3:0]      rx_cnt;
83
 
84
 
85
/**************************************************************************/
86
/* Counters */
87
/**************************************************************************/
88
 
89
   /* Generate the state counter, based on incoming sync signal */
90
   /* 10-bit shift register, indicating where we are */
91
   reg [10:1]    state_shiftreg;
92 49 julius
 
93
   /* A wire hooked up from bit 0 with the last byte of the state counter/shiftreg */
94
   wire [7:0] state_shiftreg_top_byte;
95
   assign state_shiftreg_top_byte[7:0] = state_shiftreg[10:3];
96 44 julius
 
97
   always @(posedge clk)
98
     begin
99
        if (!rst_n)
100
          begin
101
             state_shiftreg <= 10'b0000000001;
102
          end
103
        else
104
          begin
105
             if (smii_sync) /* sync signal from MAC */
106
               state_shiftreg <= 10'b0000000010;
107
             else if (state_shiftreg[10])
108
               state_shiftreg <= 10'b0000000001;
109
             else
110
               state_shiftreg[10:2] <= state_shiftreg[9:1];
111
          end // else: !if(!rst_n)      
112
     end // always @ (posedge clk)
113
 
114
 
115
   /* counter from 0 to 9, counting the 10-bit segments we'll transmit
116
    via SMII*/
117
   reg [3:0] segment_ctr;
118
 
119
   always @(posedge clk)
120
     begin
121
        if(!rst_n)
122
          segment_ctr <= 4'h0;
123
        else
124
          begin
125
             if(fast_ethernet) /* If using 100Mbs, then each segment is
126
                            different, we don't count the repeats */
127
               segment_ctr <= 4'h0;
128
             else if (state_shiftreg[10])
129
               if (segment_ctr == 4'h9) /* Wrap */
130
                 segment_ctr <= 4'h0;
131
               else /* Increment */
132
                 segment_ctr <= segment_ctr + 1'b1;
133
          end
134 49 julius
     end // always @ (posedge clk)
135
 
136
 
137 44 julius
/**************************************************************************/
138
/* RX path logic PHY->(MII->SMII)->MAC */
139
/**************************************************************************/
140
 
141
   reg rx_nibble_sel, rx_byte_valid;
142 49 julius
   reg [7:0] rx_data_byte_rx_clk;
143 44 julius
 
144 49 julius
   reg [4:0] rx_dv_nib_0;
145
   reg       rx_nib_first,rx_nib_first_r;  // if high, nib_0 contains the "first" of the pair of nibs
146
   reg [3:0] rx_segment_begin_num;
147
 
148
   // Allow us to check if RX DV has been low for a while
149
   reg [3:0] rx_dv_long_low_sr;
150 51 julius
   wire      rx_dv_long_low;
151 49 julius
   always @(posedge ethphy_mii_rx_clk)
152
     rx_dv_long_low_sr[3:0] <= {rx_dv_long_low_sr[2:0], ethphy_mii_rx_dv};
153 51 julius
   assign rx_dv_long_low = ~(|rx_dv_long_low_sr[3:0]);
154 49 julius
   reg      rx_dv;
155
   wire [8:0] rx_fifo_out;
156
   wire       rx_fifo_empty,rx_fifo_almost_empty;
157
   reg        rx_fifo_pop;
158
 
159 44 julius
   always @(posedge ethphy_mii_rx_clk or negedge rst_n)
160
     begin
161
        if(!rst_n)
162
          begin
163 49 julius
             rx_dv_nib_0 <= 0;
164
             rx_nib_first <= 0;
165
             rx_nib_first_r <= 0;
166 44 julius
          end
167
        else
168
          begin
169 49 julius
             if (!rx_nib_first)
170
               rx_dv_nib_0 <= {ethphy_mii_rx_dv,ethphy_mii_rx_d};
171
             if(ethphy_mii_rx_dv)
172
               rx_nib_first <= ~rx_nib_first;
173 44 julius
 
174 49 julius
             rx_nib_first_r <= rx_nib_first;
175
 
176
          end
177
     end // always @ (posedge ethphy_mii_rx_clk or negedge rst_n)
178 44 julius
 
179 49 julius
     always @(posedge clk or negedge rst_n)
180
       begin
181
          if (!rst_n) rx_fifo_pop <= 0;
182
          else rx_fifo_pop <= (rx_fifo_almost_empty) ? (rx_fifo_pop ? ~rx_fifo_empty : rx_fifo_pop) : 1;
183 44 julius
 
184 49 julius
          rx_dv <= (state_shiftreg[10] & (((rx_segment_begin_num == (segment_ctr-1)) && !fast_ethernet)| fast_ethernet)) ? (rx_fifo_pop) : rx_dv;
185
       end
186 44 julius
 
187
   always @(posedge clk)
188
     begin
189 49 julius
        /* remember which counter value we were at when rx enable/valid
190
         went high.
191
         This is only useful when not doing fast ethernet*/
192
 
193
        /* rx en has gone high - remember the sequence number we're in */
194
        if ((rx_segment_begin_num == 4'hf) & (~rx_dv_long_low))
195
          rx_segment_begin_num <= segment_ctr;
196
 
197
        /* If rx enable goes low again, reset the segment number */
198
        if (rx_dv_long_low)
199
             /* reset to 0xf */
200
             rx_segment_begin_num <= 4'hf;
201
     end
202 44 julius
 
203 49 julius
 
204
 
205
     /* A fifo, storing RX bytes coming from the PHY interface */
206
   generic_fifo #(9, 64) rx_fifo
207
     (
208
      // Outputs
209
      .psh_full                         (),
210
      .pop_q                            (rx_fifo_out),
211
      .pop_empty                        (rx_fifo_empty),
212
      .almost_empty                     (rx_fifo_almost_empty),
213
      // Inputs
214
      .async_rst_n                      (rst_n),
215
      .psh_clk                          (ethphy_mii_rx_clk),
216
      .psh_we                           (rx_nib_first_r),
217
      .psh_d                            ({ethphy_mii_rx_err,ethphy_mii_rx_d,rx_dv_nib_0[3:0]}),
218
      .pop_clk                          (clk),
219
      .pop_re                           ((state_shiftreg[1] & rx_fifo_pop)&(((rx_segment_begin_num == segment_ctr) && !fast_ethernet)| fast_ethernet)));
220
 
221
 
222
  `ifdef RX_SYNC_1
223
 
224
    /* Assign the rx line out */
225
   always @(posedge clk)
226
    smii_rx <= state_shiftreg[1] ? ethphy_mii_crs : /* 1st bit is MII CRS */
227
                    state_shiftreg[2] ? ((rx_dv & (segment_ctr==4'h0) & !fast_ethernet) |
228
                                         rx_dv) :
229
               // inter-frame status byte or data byte
230
               state_shiftreg[3] ? (rx_dv ?  (rx_fifo_out[0]) : ethphy_mii_rx_err) :
231
               state_shiftreg[4] ? (rx_dv ?  (rx_fifo_out[1]) : fast_ethernet) :
232
               state_shiftreg[5] ? (rx_dv ?  (rx_fifo_out[2]) : duplex) :
233
               state_shiftreg[6] ? (rx_dv ?  (rx_fifo_out[3]) : link) :
234
               state_shiftreg[7] ? (rx_dv ?  (rx_fifo_out[4]) : jabber) :
235
               state_shiftreg[8] ? (rx_dv ?  (rx_fifo_out[5]) : 1) :
236
               state_shiftreg[9] ? (rx_dv ?  (rx_fifo_out[6]) : 0) :
237
               state_shiftreg[10] ? (rx_dv ?  (rx_fifo_out[7]) : 1) : 0;
238
 
239
  `else // !`ifdef RX_SYNC_1
240
 
241
       /* Assign the rx line out */
242
   always @(posedge clk)
243
    smii_rx <= state_shiftreg[10] ? ethphy_mii_crs : /* 1st bit is MII CRS */
244
                    state_shiftreg[1] ? ((rx_dv & (segment_ctr==4'h0) & !fast_ethernet) |
245
                                         rx_dv) :
246
               // inter-frame status byte or data byte
247
               state_shiftreg[2] ? (rx_dv ?  (rx_fifo_out[0]) : ethphy_mii_rx_err) :
248
               state_shiftreg[3] ? (rx_dv ?  (rx_fifo_out[1]) : fast_ethernet) :
249
               state_shiftreg[4] ? (rx_dv ?  (rx_fifo_out[2]) : duplex) :
250
               state_shiftreg[5] ? (rx_dv ?  (rx_fifo_out[3]) : link) :
251
               state_shiftreg[6] ? (rx_dv ?  (rx_fifo_out[4]) : jabber) :
252
               state_shiftreg[7] ? (rx_dv ?  (rx_fifo_out[5]) : 1) :
253
               state_shiftreg[8] ? (rx_dv ?  (rx_fifo_out[6]) : 0) :
254
               state_shiftreg[9] ? (rx_dv ?  (rx_fifo_out[7]) : 1) : 0;
255
  `endif // !`ifdef RX_SYNC_1
256
 
257
 
258 44 julius
   /* Status seq.: CRS, DV, ER, Speed, Duplex, Link, Jabber, UPV, FCD, 1 */
259 49 julius
   //    {1'b1,1'b0,1'b1,jabber,link,duplex,,ethphy_mii_rx_err});
260
 
261 44 julius
 
262
/**************************************************************************/
263
/* TX path logic MAC->(SMII->MII)->PHY */
264
/**************************************************************************/
265
 
266
   /* We ignore the data when TX_EN bit is not high -
267
    it's only used in MAC to MAC comms*/
268
 
269
 
270
   /* Register the sequence appropriately as it comes in */
271
   reg tx_er_seqbit_scratch;
272
   reg tx_en_seqbit_scratch;
273
   reg [7:0] tx_data_byte_scratch;
274
 
275 49 julius
   reg [2:0] tx_byte_to_phy; /* PHY sourced TX_CLK domain */
276 44 julius
 
277 49 julius
   wire      tx_fifo_empty, tx_fifo_almost_empty;
278 44 julius
   wire      tx_fifo_full;
279
   wire [7:0] tx_fifo_q_dat;
280
   wire       tx_fifo_q_err;
281
   reg        tx_fifo_pop;
282 49 julius
   reg [3:0]  tx_segment_begin_num;
283
   wire [3:0] tx_segment_load_num;
284 44 julius
 
285 49 julius
   assign tx_segment_load_num = (tx_segment_begin_num == 0) ? 4'h9 : tx_segment_begin_num - 1;
286
 
287 44 julius
   /* Signal to tell us an appropriate time to copy the values out of the
288
    temp regs we put the incoming TX line into when we've received a
289
    sequence off the SMII TX line that has TX_EN high */
290
   wire      tx_seqbits_copy;
291 49 julius
   assign tx_seqbits_copy = (
292
                             (
293
                              ((!fast_ethernet) & (segment_ctr == tx_segment_load_num)) |
294
                              fast_ethernet
295
                             )
296
                             & tx_en_seqbit_scratch & state_shiftreg[1]
297
                            );
298 44 julius
 
299
   always @(posedge clk)
300
     begin
301 49 julius
        /* remember which counter value we were at when tx enable/valid
302
         went high.
303
         This is only useful when not doing fast ethernet*/
304
 
305
        /* tx en has gone high - remember the sequence number we're in */
306
        if ((tx_segment_begin_num == 4'hf) & (tx_en_seqbit_scratch))
307
          tx_segment_begin_num <= segment_ctr;
308
 
309
        /* If tx enable goes low again, reset the segment number */
310
        if (!tx_en_seqbit_scratch)
311
             /* reset to 0xf */
312
             tx_segment_begin_num <= 4'hf;
313
     end
314
 
315
 
316
   always @(posedge clk)
317
     begin
318 44 julius
        if (!rst_n)
319
          begin
320
             tx_er_seqbit_scratch <= 0;
321
             tx_en_seqbit_scratch <= 0;
322
             tx_data_byte_scratch <= 0;
323
          end
324
        else
325
          begin
326 49 julius
             if(state_shiftreg[1])
327
               tx_er_seqbit_scratch <= smii_tx;
328
 
329
             if(state_shiftreg[2])
330
               tx_en_seqbit_scratch <= smii_tx;
331
 
332
             /* Preserve all but current bit of interest, as indicated
333
              by state vector bit (reversed, becuase we get MSbit
334
              first) and OR in the current smii_tx line value at this
335
              position*/
336
             if((|state_shiftreg[10:3]) & tx_en_seqbit_scratch)
337
               tx_data_byte_scratch <= (tx_data_byte_scratch & ~state_shiftreg_top_byte) |
338
                                       ({8{smii_tx}} & state_shiftreg_top_byte);
339
 
340 44 julius
          end
341
     end // always @ (posedge clk)
342 49 julius
 
343
   reg [3:0] nib;
344
 
345
 
346
 
347 44 julius
   /* In the event we have a valid byte frame then get it to the
348
    PHY as quickly as possible - this is TX_CLK domain */
349
   always @(posedge ethphy_mii_tx_clk or negedge rst_n)
350
     begin
351
        if(!rst_n)
352
          begin
353
             tx_byte_to_phy <= 0;
354
             tx_fifo_pop <= 1'b0;
355
             /* Output MII registers to the PHY */
356
             ethphy_mii_tx_d <= 0;
357
             ethphy_mii_tx_en <= 0;
358
             ethphy_mii_tx_err <= 0;
359
 
360
          end
361
        else
362
          begin
363 49 julius
             /* If fast_ethernet/100mbs we wait until the FIFO is full
364
              otherwise, we push out the byte each time we get one */
365
             //if((!tx_fifo_empty && !fast_ethernet) ||
366
             //(tx_fifo_full && fast_ethernet))
367
             if (!tx_fifo_almost_empty)
368 44 julius
               begin
369 49 julius
                  if(tx_byte_to_phy == 0)
370 44 julius
                    begin
371 49 julius
                       tx_byte_to_phy <= 1;
372 44 julius
                       tx_fifo_pop <= 1;
373
                    end
374
               end
375 49 julius
 
376 44 julius
             /* FIFO control loop */
377 49 julius
             if (tx_byte_to_phy == 1)/* Output bits 3-0 (bottom nibble ) */
378 44 julius
               begin
379 49 julius
 
380
                  ethphy_mii_tx_en <= 1;
381
 
382
                  tx_fifo_pop <= 0;
383
 
384
                  tx_byte_to_phy <= 2;
385
 
386 44 julius
                  ethphy_mii_tx_d <= tx_fifo_q_dat[3:0];
387 49 julius
                  nib <= tx_fifo_q_dat[7:4];
388 44 julius
                  ethphy_mii_tx_err <= tx_fifo_q_err;
389 49 julius
 
390 44 julius
               end
391 49 julius
             else if (tx_byte_to_phy == 2) /* Output bits 7-4 (top nibble) */
392 44 julius
               begin
393 49 julius
                  //ethphy_mii_tx_d <= tx_fifo_q_dat[7:4];
394
 
395
                  ethphy_mii_tx_d <= nib;
396
 
397 44 julius
                  if(!tx_fifo_empty) /* Check if more in FIFO */
398
                    begin
399 49 julius
                       tx_fifo_pop <= 1;
400
                       tx_byte_to_phy <= 1;
401 44 julius
                    end
402
                  else /* Finish up */
403
                    begin
404 49 julius
                       tx_byte_to_phy <= 3;
405
                       ethphy_mii_tx_en <= 0;
406 44 julius
                    end
407
               end
408 49 julius
             else if (tx_byte_to_phy == 3) /* De-assert TX_EN */
409 44 julius
               begin
410
                  tx_byte_to_phy <= 2'b00;
411
               end
412
          end // else: !if(!rst_n)
413
     end // always @ (posedge ethphy_mii_tx_clk or negedge rst_n)
414
 
415
   /* A fifo, storing TX bytes coming from the SMII interface */
416
   generic_fifo #(9, 64) tx_fifo
417
     (
418
      // Outputs
419
      .psh_full                         (tx_fifo_full),
420
      .pop_q                            ({tx_fifo_q_err,tx_fifo_q_dat}),
421
      .pop_empty                        (tx_fifo_empty),
422 49 julius
      .almost_empty                     (tx_fifo_almost_empty),
423 44 julius
      // Inputs
424
      .async_rst_n                      (rst_n),
425
      .psh_clk                          (clk),
426
      .psh_we                           (tx_seqbits_copy),
427
      .psh_d                            ({tx_er_seqbit_scratch,tx_data_byte_scratch}),
428 49 julius
      .pop_clk                          (ethphy_mii_tx_clk),
429 44 julius
      .pop_re                           (tx_fifo_pop));
430
 
431
 
432
   //assign mcoll = mcrs & mtxen;
433
 
434
endmodule // smii_top
435
 
436
 
437
 
438
/* Generic fifo - this is bad, should probably be done some other way */
439 49 julius
module generic_fifo (async_rst_n, psh_clk, psh_we, psh_d, psh_full, pop_clk, pop_re, pop_q, pop_empty, almost_empty);
440 44 julius
 
441
   parameter dw = 8;
442 49 julius
   parameter size = 16;
443
   parameter size_log_2 = 4;
444
 
445 44 julius
   /* Asynch. reset, active low */
446
   input async_rst_n;
447
 
448
   /* Push side signals */
449
   input psh_clk;
450
   input psh_we;
451
   input [dw-1:0] psh_d;
452
   output         psh_full;
453
 
454
   /* Pop side signals */
455
   input          pop_clk;
456
   input          pop_re;
457 49 julius
   //output reg [dw-1:0] pop_q;
458 44 julius
   output reg [dw-1:0] pop_q;
459
   output              pop_empty;
460 49 julius
   output wire         almost_empty;
461
 
462 44 julius
 
463
   /* Actual FIFO memory */
464
   reg [dw-1:0]   fifo_mem [0:size-1];
465
 
466
 
467 49 julius
   /* FIFO position ptr regs */
468
   reg [size_log_2 - 1 : 0 ]   wr_ptr, rd_ptr, ctr;
469 44 julius
 
470 49 julius
   integer     i;
471
 
472
 
473 44 julius
   /* FIFO full signal for push side */
474 49 julius
   //assign psh_full = (ptr == size-1) ? 1 : 0;
475
   /* This full logic means we all but one slot in the FIFO */
476
   assign psh_full = ctr == size;
477
 
478 44 julius
   /* FIFO empty signal for pop side */
479 49 julius
   //assign pop_empty = (ptr == 0) ? 1 : 0;
480
   //assign pop_empty = ctr==0;
481
   assign pop_empty = rd_ptr == wr_ptr;
482
 
483
   assign almost_empty = ctr < 2;
484 44 julius
 
485 49 julius
   always @(posedge pop_re or negedge async_rst_n)
486
     begin
487
        if (!async_rst_n)
488
          rd_ptr <= 0;
489
        else
490
          begin
491
             pop_q = fifo_mem[rd_ptr];
492
             rd_ptr <= rd_ptr + 1;
493
             ctr <= ctr - 1;
494
          end
495
     end
496 44 julius
 
497 49 julius
   always @(posedge psh_we or negedge async_rst_n)
498 44 julius
     begin
499
        if (!async_rst_n)
500
          begin
501
             for (i=0;i<size;i=i+1) fifo_mem[i] <= 0;
502 49 julius
             wr_ptr <= 0;
503
             ctr <= 0;
504 44 julius
          end
505 49 julius
        else
506 44 julius
          begin
507 49 julius
             fifo_mem[wr_ptr] <= psh_d;
508
             wr_ptr <= #1 wr_ptr + 1;
509
             ctr <= ctr + 1;
510
          end
511
     end
512 44 julius
 
513 49 julius
 
514 44 julius
endmodule // generic_fifo
515
 
516
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.