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

Subversion Repositories openrisc

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

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
    output    smii_rx,
48
 
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
 
93
   always @(posedge clk)
94
     begin
95
        if (!rst_n)
96
          begin
97
             state_shiftreg <= 10'b0000000001;
98
          end
99
        else
100
          begin
101
             if (smii_sync) /* sync signal from MAC */
102
               state_shiftreg <= 10'b0000000010;
103
             else if (state_shiftreg[10])
104
               state_shiftreg <= 10'b0000000001;
105
             else
106
               state_shiftreg[10:2] <= state_shiftreg[9:1];
107
          end // else: !if(!rst_n)      
108
     end // always @ (posedge clk)
109
 
110
 
111
   /* counter from 0 to 9, counting the 10-bit segments we'll transmit
112
    via SMII*/
113
   reg [3:0] segment_ctr;
114
 
115
   always @(posedge clk)
116
     begin
117
        if(!rst_n)
118
          segment_ctr <= 4'h0;
119
        else
120
          begin
121
             if(fast_ethernet) /* If using 100Mbs, then each segment is
122
                            different, we don't count the repeats */
123
               segment_ctr <= 4'h0;
124
             else if (state_shiftreg[10])
125
               if (segment_ctr == 4'h9) /* Wrap */
126
                 segment_ctr <= 4'h0;
127
               else /* Increment */
128
                 segment_ctr <= segment_ctr + 1'b1;
129
          end
130
     end
131
 
132
/**************************************************************************/
133
/* RX path logic PHY->(MII->SMII)->MAC */
134
/**************************************************************************/
135
 
136
   reg rx_nibble_sel, rx_byte_valid;
137
   reg [7:0] rx_data_byte_rx_clk;
138
 
139
   /* Receive the RX data from the PHY and serialise it */
140
   /* If RX data valid goes high, then it's the beginning of a
141
    proper data segment*/
142
   always @(posedge ethphy_mii_rx_clk or negedge rst_n)
143
     begin
144
        if(!rst_n)
145
          begin
146
             rx_nibble_sel <= 0; /* start with low nibble receiving */
147
             rx_data_byte_rx_clk <= 0;
148
             rx_byte_valid <= 0;
149
          end
150
        else
151
          begin
152
             /* Half way through, and at the end of each 10-bit section
153
              and whenever we should load a new segment (each time for
154
              fast ethernet, else once every 10 times; whenever segment_ctr
155
              is 0)*/
156
             //if ((state_shiftreg[6] | state_shiftreg[10]) & (segment_ctr==4'h0))
157
             //  begin
158
                  /* Alternate the nibble we're selecting when RX_dv */
159
                  if(!ethphy_mii_rx_dv) /* data on rx line is not valid */
160
                    rx_nibble_sel <= 0;
161
                  else
162
                    rx_nibble_sel <= ~rx_nibble_sel;
163
 
164
                  if (!ethphy_mii_rx_dv & !rx_nibble_sel)
165
                    rx_byte_valid <= 0;
166
                  else if (rx_nibble_sel) /* sampled high nibble, byte OK*/
167
                    rx_byte_valid <= 1;
168
 
169
                  if (ethphy_mii_rx_dv & !rx_nibble_sel)
170
                    /* Sampling low nibble */
171
                    rx_data_byte_rx_clk[3:0] <= ethphy_mii_rx_d;
172
                  else if (ethphy_mii_rx_dv & rx_nibble_sel)
173
                    /* Sample high nibble */
174
                    rx_data_byte_rx_clk[7:4] <= ethphy_mii_rx_d;
175
 
176
               //end // if ((state_shiftreg[4] | state_shiftreg[9]) & (segment_ctr==4'h0))           
177
          end // else: !if(!rst_n)
178
     end // always @ (posedge clk)'
179
 
180
   /* SMII domain RX signals */
181
   reg [7:0] rx_data_byte;
182
   reg rx_line_rx_dv; /* Reg for second bit of SMII RX sequence, RX_DV */
183
 
184
   /* A wire hooked up from bit 0 with the last byte of the state counter/shiftreg */
185
   wire [7:0] state_shiftreg_top_byte;
186
   assign state_shiftreg_top_byte[7:0] = state_shiftreg[10:3];
187
 
188
   /* Move RX's DV and data into SMII clk domain */
189
   always @(posedge clk)
190
     begin
191
        if(!rst_n)
192
          begin
193
             rx_line_rx_dv <= 0;
194
          end
195
        else
196
          begin
197
             /* When we're at the beginning of a new 10-bit sequence and
198
              the beginning of the 10-segment loop load the valid bit */
199
             if(state_shiftreg[1] & (segment_ctr==4'h0))
200
               begin
201
                  rx_line_rx_dv <= rx_byte_valid;
202
                  rx_data_byte <= rx_data_byte_rx_clk;
203
               end
204
          end // else: !if(!rst_n)
205
     end // always @ (posedge clk)
206
 
207
   /* Assign the rx line out */
208
   assign smii_rx = state_shiftreg[1] ? ethphy_mii_crs : /* 1st bit is MII CRS */
209
                    /* next is RX_DV bit */
210
                    state_shiftreg[2] ? ((rx_byte_valid & (segment_ctr==4'h0)) |
211
                                         rx_line_rx_dv) :
212
                    /* Depending on RX_DV, output the status byte or data byte */
213
                    rx_line_rx_dv ? |(state_shiftreg_top_byte & rx_data_byte) :
214
                    /* Output status byte */
215
                    |(state_shiftreg_top_byte &
216
   /* Status seq.: CRS, DV, ER, Speed, Duplex, Link, Jabber, UPV, FCD, 1 */
217
       {1'b1,1'b0,1'b1,jabber,link,duplex,fast_ethernet,ethphy_mii_rx_err});
218
 
219
/**************************************************************************/
220
/* TX path logic MAC->(SMII->MII)->PHY */
221
/**************************************************************************/
222
 
223
   /* We ignore the data when TX_EN bit is not high -
224
    it's only used in MAC to MAC comms*/
225
 
226
 
227
   /* Register the sequence appropriately as it comes in */
228
   reg tx_er_seqbit_scratch;
229
   reg tx_en_seqbit_scratch;
230
   reg [7:0] tx_data_byte_scratch;
231
 
232
   reg [1:0] tx_byte_to_phy; /* PHY sourced TX_CLK domain */
233
 
234
   wire      tx_fifo_empty;
235
   wire      tx_fifo_full;
236
   wire [7:0] tx_fifo_q_dat;
237
   wire       tx_fifo_q_err;
238
   reg        tx_fifo_pop;
239
 
240
 
241
   /* Signal to tell us an appropriate time to copy the values out of the
242
    temp regs we put the incoming TX line into when we've received a
243
    sequence off the SMII TX line that has TX_EN high */
244
   wire      tx_seqbits_copy;
245
   assign tx_seqbits_copy = ((((!fast_ethernet) & (segment_ctr==4'h1)) |
246
                              ((fast_ethernet) & (state_shiftreg[1])))
247
                             & tx_en_seqbit_scratch);
248
 
249
   always @(posedge clk)
250
     begin
251
        if (!rst_n)
252
          begin
253
             tx_er_seqbit_scratch <= 0;
254
             tx_en_seqbit_scratch <= 0;
255
             tx_data_byte_scratch <= 0;
256
          end
257
        else
258
          begin
259
             if (segment_ctr==4'h0)
260
               begin
261
                  if(state_shiftreg[1])
262
                    tx_er_seqbit_scratch <= smii_tx;
263
 
264
                  if(state_shiftreg[2])
265
                    tx_en_seqbit_scratch <= smii_tx;
266
 
267
                  /* Preserve all but current bit of interest, as indicated
268
                   by state vector bit (reversed, becuase we get MSbit
269
                   first) and OR in the current smii_tx line value at this
270
                   position*/
271
                  if((|state_shiftreg[10:3]) & tx_en_seqbit_scratch)
272
                    tx_data_byte_scratch <= (tx_data_byte_scratch & ~state_shiftreg_top_byte) |
273
                                            ({8{smii_tx}} & state_shiftreg_top_byte);
274
 
275
               end // if (segment_ctr==4'h0)
276
 
277
             /* If we've just received a sequence with TX_EN then put
278
              these values in the proper regs at the appropriate time,
279
              depending on the speed , ready for transmission to the PHY */
280
             if (tx_seqbits_copy)
281
               begin
282
 
283
                  /* Now clear the tx_en scratch bit so we don't do
284
                   this again */
285
                  tx_en_seqbit_scratch <= 0;
286
 
287
               end // if (tx_seqbits_copy)
288
          end
289
     end // always @ (posedge clk)
290
 
291
 
292
   /* In the event we have a valid byte frame then get it to the
293
    PHY as quickly as possible - this is TX_CLK domain */
294
   always @(posedge ethphy_mii_tx_clk or negedge rst_n)
295
     begin
296
        if(!rst_n)
297
          begin
298
             tx_byte_to_phy <= 0;
299
             tx_fifo_pop <= 1'b0;
300
             /* Output MII registers to the PHY */
301
             ethphy_mii_tx_d <= 0;
302
             ethphy_mii_tx_en <= 0;
303
             ethphy_mii_tx_err <= 0;
304
 
305
          end
306
        else
307
          begin
308
 
309
             if(!tx_fifo_empty) /* A byte ready to go to the MAC */
310
               begin
311
                  if(tx_byte_to_phy == 2'b00)
312
                    begin
313
                       /* Pop */
314
                       tx_fifo_pop <= 1;
315
                       tx_byte_to_phy <= 2'b01;
316
                    end
317
               end
318
 
319
             /* FIFO control loop */
320
             if (tx_byte_to_phy == 2'b01) /* Output bits 3-0 (bottom nibble ) */
321
               begin
322
                  ethphy_mii_tx_d <= tx_fifo_q_dat[3:0];
323
                  ethphy_mii_tx_en <= 1;
324
                  ethphy_mii_tx_err <= tx_fifo_q_err;
325
                  tx_fifo_pop <= 0;
326
                  tx_byte_to_phy <= 2'b10;
327
               end
328
             else if (tx_byte_to_phy == 2'b10) /* Output bits 7-4 (top nibble) */
329
               begin
330
                  ethphy_mii_tx_d <= tx_fifo_q_dat[7:4];
331
                  if(!tx_fifo_empty) /* Check if more in FIFO */
332
                    begin
333
                       tx_fifo_pop <= 1; /* Pop again */
334
                       tx_byte_to_phy <= 2'b01;
335
                    end
336
                  else /* Finish up */
337
                    begin
338
                       tx_byte_to_phy <= 2'b11;
339
                    end
340
               end
341
             else if (tx_byte_to_phy == 2'b11) /* De-assert TX_EN */
342
               begin
343
                  ethphy_mii_tx_en <= 0;
344
                  tx_byte_to_phy <= 2'b00;
345
               end
346
          end // else: !if(!rst_n)
347
     end // always @ (posedge ethphy_mii_tx_clk or negedge rst_n)
348
 
349
   /* A fifo, storing TX bytes coming from the SMII interface */
350
   generic_fifo #(9, 64) tx_fifo
351
     (
352
      // Outputs
353
      .psh_full                         (tx_fifo_full),
354
      .pop_q                            ({tx_fifo_q_err,tx_fifo_q_dat}),
355
      .pop_empty                        (tx_fifo_empty),
356
      // Inputs
357
      .async_rst_n                      (rst_n),
358
      .psh_clk                          (clk),
359
      .psh_we                           (tx_seqbits_copy),
360
      .psh_d                            ({tx_er_seqbit_scratch,tx_data_byte_scratch}),
361
      .pop_clk                          (),
362
      .pop_re                           (tx_fifo_pop));
363
 
364
 
365
   //assign mcoll = mcrs & mtxen;
366
 
367
endmodule // smii_top
368
 
369
 
370
 
371
/* Generic fifo - this is bad, should probably be done some other way */
372
module generic_fifo (async_rst_n, psh_clk, psh_we, psh_d, psh_full, pop_clk, pop_re, pop_q, pop_empty);
373
 
374
   parameter dw = 8;
375
   parameter size = 64;
376
 
377
   /* Asynch. reset, active low */
378
   input async_rst_n;
379
 
380
   /* Push side signals */
381
   input psh_clk;
382
   input psh_we;
383
   input [dw-1:0] psh_d;
384
   output         psh_full;
385
 
386
   /* Pop side signals */
387
   input          pop_clk;
388
   input          pop_re;
389
   output reg [dw-1:0] pop_q;
390
   output              pop_empty;
391
 
392
   /* Actual FIFO memory */
393
   reg [dw-1:0]   fifo_mem [0:size-1];
394
 
395
   /* Poorly defined pointer logic -- will need to be changed if the size paramter is too big - Verilog needs some log base 2 thing */
396
   reg [7:0]   ptr; /* Only 8 bits, so max size of 255 of fifo! */
397
 
398
 
399
   /* FIFO full signal for push side */
400
   assign psh_full = (ptr == size-1) ? 1 : 0;
401
   /* FIFO empty signal for pop side */
402
   assign pop_empty = (ptr == 0) ? 1 : 0;
403
 
404
 
405
   /* This will work if pushing side is a lot faster than popping side */
406
   reg         pop_re_psh_clk;
407
   wire       pop_re_risingedge_psh_clk; /* Signal to help push side see when
408
                                            there's been a pop_re rising edge,
409
                                            sampled on push clock */
410
 
411
   /* Detect edge of signal in pop domain for psh domain */
412
   assign pop_re_risingedge_psh_clk = (pop_re & !pop_re_psh_clk);
413
 
414
 
415
   integer    i;
416
   always @(posedge psh_clk or negedge async_rst_n)
417
     begin
418
        if (!async_rst_n)
419
          begin
420
             ptr <= 0;
421
 
422
 
423
             for (i=0;i<size;i=i+1) fifo_mem[i] <= 0;
424
 
425
             pop_re_psh_clk <= 0;
426
 
427
          end
428
        else
429
          begin
430
 
431
             pop_re_psh_clk <= pop_re; /* Register pop command in psh domain */
432
 
433
             if (psh_we) /* Push into FIFO */
434
               begin
435
                  if (!pop_re_psh_clk) /* If no pop at the same time, simple */
436
                    begin
437
                       fifo_mem[ptr] <= psh_d;
438
                       ptr <= ptr + 1'b1;
439
                    end
440
                  else /* Pop at same edge */
441
                    begin
442
                       /* Shift fifo contents */
443
                       for(i=1;i<size;i=i+1)
444
                         fifo_mem[i-1] <= fifo_mem[i];
445
                       fifo_mem[size-1] <= 0;
446
                       pop_q <= fifo_mem[0];
447
                       fifo_mem[ptr] <= psh_d;
448
                       /* ptr remains unchanged */
449
                    end // else: !if!(pop_re_psh_clk)
450
               end // if (psh_we)
451
             else /* No push, see if there's a pop */
452
               begin
453
                  if (pop_re_risingedge_psh_clk) /* Detected a pop */
454
                    begin
455
                       for(i=1;i<size;i=i+1)
456
                         fifo_mem[i-1] <= fifo_mem[i];
457
                       fifo_mem[size-1] <= 0;
458
                       pop_q <= fifo_mem[0];
459
                       ptr <= ptr - 1'b1;
460
                    end
461
               end // else: !if(psh_we)      
462
          end // else: !if(!async_rst_n)
463
     end // always @ (posedge psh_clk or negedge async_rst_n)
464
 
465
 
466
endmodule // generic_fifo
467
 
468
 

powered by: WebSVN 2.1.0

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