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

Subversion Repositories ethmac

[/] [ethmac/] [tags/] [rel_11/] [bench/] [verilog/] [eth_phy.v] - Blame information for rev 177

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

Line No. Rev Author Line
1 169 mohor
//////////////////////////////////////////////////////////////////////
2
////                                                              ////
3
////  File name: eth_phy.v                                        ////
4
////                                                              ////
5 170 mohor
////  This file is part of the Ethernet IP core project           ////
6 169 mohor
////  http://www.opencores.org/projects/ethmac/                   ////
7
////                                                              ////
8
////  Author(s):                                                  ////
9
////      - Tadej Markovic, tadej@opencores.org                   ////
10
////                                                              ////
11
////  All additional information is available in the README.txt   ////
12
////  file.                                                       ////
13
////                                                              ////
14
//////////////////////////////////////////////////////////////////////
15
////                                                              ////
16 170 mohor
//// Copyright (C) 2002  Authors                                  ////
17 169 mohor
////                                                              ////
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 177 mohor
// Revision 1.2  2002/09/13 12:29:14  mohor
45
// Headers changed.
46
//
47 170 mohor
// Revision 1.1  2002/09/13 11:57:20  mohor
48
// New testbench. Thanks to Tadej M - "The Spammer".
49 169 mohor
//
50
//
51 170 mohor
//
52 169 mohor
 
53
`include "timescale.v"
54
`include "eth_phy_defines.v"
55
`include "tb_eth_defines.v"
56
module eth_phy // This PHY model simulate simplified Intel LXT971A PHY
57
(
58
        // COMMON
59
        m_rst_n_i,
60
 
61
        // MAC TX
62
        mtx_clk_o,
63
        mtxd_i,
64
        mtxen_i,
65
        mtxerr_i,
66
 
67
        // MAC RX
68
        mrx_clk_o,
69
        mrxd_o,
70
        mrxdv_o,
71
        mrxerr_o,
72
 
73
        mcoll_o,
74
        mcrs_o,
75
 
76
        // MIIM
77
        mdc_i,
78
        md_io,
79
 
80
        // SYSTEM
81
        phy_log
82
);
83
 
84
//////////////////////////////////////////////////////////////////////
85
//
86
// Input/output signals
87
//
88
//////////////////////////////////////////////////////////////////////
89
 
90
// MAC miscellaneous signals
91
input           m_rst_n_i;
92
// MAC TX signals
93
output          mtx_clk_o;
94
input   [3:0]   mtxd_i;
95
input           mtxen_i;
96
input           mtxerr_i;
97
// MAC RX signals
98
output          mrx_clk_o;
99
output  [3:0]   mrxd_o;
100
output          mrxdv_o;
101
output          mrxerr_o;
102
// MAC common signals
103
output          mcoll_o;
104
output          mcrs_o;
105
// MAC management signals
106
input           mdc_i;
107
inout           md_io;
108
// SYSTEM
109
input   [31:0]  phy_log;
110
 
111
 
112
//////////////////////////////////////////////////////////////////////
113
//
114
// PHY management (MIIM) REGISTER definitions
115
//
116
//////////////////////////////////////////////////////////////////////
117
//
118
//   Supported registers:
119
//
120
// Addr | Register Name
121
//--------------------------------------------------------------------
122
//   0  | Control reg.     |
123
//   1  | Status reg. #1   |--> normal operation
124
//   2  | PHY ID reg. 1    |
125
//   3  | PHY ID reg. 2    |
126
//----------------------
127
// Addr | Data MEMORY      |-->  for testing
128
//
129
//--------------------------------------------------------------------
130
//
131
// Control register
132
reg            control_bit15; // self clearing bit
133
reg    [14:10] control_bit14_10;
134
reg            control_bit9; // self clearing bit
135
reg    [8:0]   control_bit8_0;
136
// Status register
137
wire   [15:9]  status_bit15_9 = `SUPPORTED_SPEED_AND_PORT;
138
wire           status_bit8    = `EXTENDED_STATUS;
139
wire           status_bit7    = 1'b0; // reserved
140
reg    [6:0]   status_bit6_0;
141
// PHY ID register 1
142
wire   [15:0]  phy_id1        = `PHY_ID1;
143
// PHY ID register 2
144
wire   [15:0]  phy_id2        = {`PHY_ID2, `MAN_MODEL_NUM, `MAN_REVISION_NUM};
145
//--------------------------------------------------------------------
146
//
147
// Data MEMORY
148
reg    [15:0]  data_mem [0:31]; // 32 locations of 16-bit data width
149
//
150
//////////////////////////////////////////////////////////////////////
151
 
152
 
153
//////////////////////////////////////////////////////////////////////
154
//
155
// PHY clocks - RX & TX
156
//
157
//////////////////////////////////////////////////////////////////////
158
 
159
reg       mtx_clk_o;
160
reg       mrx_clk_o;
161
 
162
// random generator for a RX period when link is down
163
real      rx_link_down_halfperiod;
164
 
165
always@(status_bit6_0[2])
166
begin
167
  if (!status_bit6_0[2]) // Link is down
168
  begin
169
    #1 rx_link_down_halfperiod = ({$random} % 243) + 13;
170
    `ifdef VERBOSE
171
    #1 $fdisplay(phy_log, "   (%0t)(%m)MAC RX clock is %f MHz while ethernet link is down!",
172
                 $time, (1000/(rx_link_down_halfperiod*2)) );
173
    `endif
174
  end
175
end
176
 
177
`ifdef VERBOSE
178
always@(status_bit6_0[2])
179
begin
180
  if (!status_bit6_0[2]) // Link is down
181
    #1 $fdisplay(phy_log, "   (%0t)(%m)Ethernet link is down!", $time);
182
  else
183
    #1 $fdisplay(phy_log, "   (%0t)(%m)Ethernet link is up!", $time);
184
end
185
`endif
186
 
187
// speed selection signal eth_speed: 1'b1 - 100 Mbps, 1'b0 - 10 Mbps
188
wire      eth_speed;
189
 
190
assign eth_speed = ( (control_bit14_10[13]) && !((`LED_CFG1) && (`LED_CFG2)) );
191
 
192
`ifdef VERBOSE
193
always@(eth_speed)
194
begin
195
  if (eth_speed)
196
    #1 $fdisplay(phy_log, "   (%0t)(%m)PHY configured to 100 Mbps!", $time);
197
  else
198
    #1 $fdisplay(phy_log, "   (%0t)(%m)PHY configured tp 10 Mbps!", $time);
199
end
200
`endif
201
 
202
// different clock calculation between RX and TX, so that there is alsways a litle difference
203
always
204
begin
205
  mtx_clk_o = 0;
206
  #7;
207
  forever
208
  begin
209
    if (eth_speed) // 100 Mbps - 25 MHz, 40 ns
210
    begin
211
      #20 mtx_clk_o = ~mtx_clk_o;
212
    end
213
    else // 10 Mbps - 2.5 MHz, 400 ns
214
    begin
215
      #200 mtx_clk_o = ~mtx_clk_o;
216
    end
217
  end
218
end
219
 
220
always
221
begin
222
  mrx_clk_o = 1;
223
  #3;
224
  forever
225
  begin
226
    if (status_bit6_0[2]) // Link is UP
227
    begin
228
      if (eth_speed) // 100 Mbps - 25 MHz, 40 ns
229
      begin
230
        //#(((1/0.025001)/2)) 
231
        #19.99 mrx_clk_o = ~mrx_clk_o; // period is calculated from frequency in GHz
232
      end
233
      else // 10 Mbps - 2.5 MHz, 400 ns
234
      begin
235
        //#(((1/0.0024999)/2)) 
236
        #200.01 mrx_clk_o = ~mrx_clk_o; // period is calculated from frequency in GHz
237
      end
238
    end
239
    else // Link is down
240
    begin
241
      #(rx_link_down_halfperiod) mrx_clk_o = ~mrx_clk_o; // random frequency between 2 MHz and 40 MHz
242
    end
243
  end
244
end
245
 
246
//////////////////////////////////////////////////////////////////////
247
//
248
// PHY management (MIIM) interface
249
//
250
//////////////////////////////////////////////////////////////////////
251
reg             respond_to_all_phy_addr; // PHY will respond to all phy addresses
252
reg             no_preamble; // PHY responds to frames without preamble
253
 
254
integer         md_transfer_cnt; // counter countes the value of whole data transfer
255
reg             md_transfer_cnt_reset; // for reseting the counter
256
reg             md_io_reg; // registered input
257
reg             md_io_output; // registered output
258
reg             md_io_rd_wr;  // op-code latched (read or write)
259
reg             md_io_enable; // output enable
260
reg     [4:0]   phy_address; // address of PHY device
261
reg     [4:0]   reg_address; // address of a register
262
reg             md_get_phy_address; // for shifting PHY address in
263
reg             md_get_reg_address; // for shifting register address in
264
reg     [15:0]  reg_data_in; // data to be written in a register
265
reg             md_get_reg_data_in; // for shifting data in
266
reg             md_put_reg_data_in; // for storing data into a selected register
267
reg     [15:0]  reg_data_out; // data to be read from a register
268
reg             md_put_reg_data_out; // for registering data from a selected register
269
 
270
wire    [15:0]  register_bus_in; // data bus to a selected register
271
reg     [15:0]  register_bus_out; // data bus from a selected register
272
 
273
initial
274
begin
275
  md_io_enable = 1'b0;
276
  respond_to_all_phy_addr = 1'b0;
277
  no_preamble = 1'b0;
278
end
279
 
280
// tristate output
281
assign #1 md_io = (m_rst_n_i && md_io_enable) ? md_io_output : 1'bz ;
282
 
283
// registering input
284
always@(posedge mdc_i or negedge m_rst_n_i)
285
begin
286
  if (!m_rst_n_i)
287
    md_io_reg <= #1 0;
288
  else
289
    md_io_reg <= #1 md_io;
290
end
291
 
292
// getting (shifting) PHY address, Register address and Data in
293
// putting Data out and shifting
294
always@(posedge mdc_i or negedge m_rst_n_i)
295
begin
296
  if (!m_rst_n_i)
297
  begin
298
    phy_address <= 0;
299
    reg_address <= 0;
300
    reg_data_in <= 0;
301
    reg_data_out <= 0;
302
    md_io_output <= 0;
303
  end
304
  else
305
  begin
306
    if (md_get_phy_address)
307
    begin
308
      phy_address[4:1] <= phy_address[3:0]; // correct address is `ETH_PHY_ADDR
309
      phy_address[0]   <= md_io;
310
    end
311
    if (md_get_reg_address)
312
    begin
313
      reg_address[4:1] <= reg_address[3:0];
314
      reg_address[0]   <= md_io;
315
    end
316
    if (md_get_reg_data_in)
317
    begin
318
      reg_data_in[15:1] <= reg_data_in[14:0];
319
      reg_data_in[0]    <= md_io;
320
    end
321
    if (md_put_reg_data_out)
322
    begin
323
      reg_data_out <= register_bus_out;
324
    end
325
    if (md_io_enable)
326
    begin
327
      md_io_output       <= reg_data_out[15];
328
      reg_data_out[15:1] <= reg_data_out[14:0];
329
      reg_data_out[0]    <= 1'b0;
330
    end
331
  end
332
end
333
 
334
assign #1 register_bus_in = reg_data_in; // md_put_reg_data_in - allows writing to a selected register
335
 
336
// counter for transfer to and from MIIM
337
always@(posedge mdc_i or negedge m_rst_n_i)
338
begin
339
  if (!m_rst_n_i)
340
  begin
341
    if (no_preamble)
342
      md_transfer_cnt <= 33;
343
    else
344
      md_transfer_cnt <= 1;
345
  end
346
  else
347
  begin
348
    if (md_transfer_cnt_reset)
349
    begin
350
      if (no_preamble)
351
        md_transfer_cnt <= 33;
352
      else
353
        md_transfer_cnt <= 1;
354
    end
355
    else if (md_transfer_cnt < 64)
356
    begin
357
      md_transfer_cnt <= md_transfer_cnt + 1'b1;
358
    end
359
    else
360
    begin
361
      if (no_preamble)
362
        md_transfer_cnt <= 33;
363
      else
364
        md_transfer_cnt <= 1;
365
    end
366
  end
367
end
368
 
369
// MIIM transfer control
370
always@(m_rst_n_i or md_transfer_cnt or md_io_reg or md_io_rd_wr or
371
        phy_address or respond_to_all_phy_addr or no_preamble)
372
begin
373
  #1;
374
  while ((m_rst_n_i) && (md_transfer_cnt <= 64))
375
  begin
376
    // reset the signal - put registered data in the register (when write)
377
    // check preamble
378
    if (md_transfer_cnt < 33)
379
    begin
380
      #4 md_put_reg_data_in = 1'b0;
381
      if (md_io_reg !== 1'b1)
382
      begin
383
        #1 md_transfer_cnt_reset = 1'b1;
384
      end
385
      else
386
      begin
387
        #1 md_transfer_cnt_reset = 1'b0;
388
      end
389
    end
390
 
391
    // check start bits
392
    else if (md_transfer_cnt == 33)
393
    begin
394
      if (no_preamble)
395
      begin
396
        #4 md_put_reg_data_in = 1'b0;
397
        if (md_io_reg === 1'b0)
398
        begin
399
          #1 md_transfer_cnt_reset = 1'b0;
400
        end
401
        else
402
        begin
403
          #1 md_transfer_cnt_reset = 1'b1;
404
          //if ((md_io_reg !== 1'bz) && (md_io_reg !== 1'b1))
405
          if (md_io_reg !== 1'bz)
406
          begin
407
            // ERROR - start !
408
            `ifdef VERBOSE
409
            $fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong first start bit (without preamble)", $time);
410
            `endif
411
            #10 $stop;
412
          end
413
        end
414
      end
415
      else // with preamble
416
      begin
417 177 mohor
        #4 ;
418 169 mohor
        `ifdef VERBOSE
419 177 mohor
        $fdisplay(phy_log, "   (%0t)(%m)MIIM - 32-bit preamble received", $time);
420 169 mohor
        `endif
421
        if (md_io_reg !== 1'b0)
422
        begin
423
          // ERROR - start !
424
          `ifdef VERBOSE
425
          $fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong first start bit", $time);
426
          `endif
427
          #10 $stop;
428
        end
429
      end
430
    end
431
 
432
    else if (md_transfer_cnt == 34)
433
    begin
434
      #4;
435
      if (md_io_reg !== 1'b1)
436
      begin
437
        // ERROR - start !
438
        #1;
439
        `ifdef VERBOSE
440
        if (no_preamble)
441
          $fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong second start bit (without preamble)", $time);
442
        else
443
          $fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong second start bit", $time);
444
        `endif
445
        #10 $stop;
446
      end
447
      else
448
      begin
449
        `ifdef VERBOSE
450
        if (no_preamble)
451
          #1 $fdisplay(phy_log, "   (%0t)(%m)MIIM - 2 start bits received (without preamble)", $time);
452
        else
453
          #1 $fdisplay(phy_log, "   (%0t)(%m)MIIM - 2 start bits received", $time);
454
        `endif
455
      end
456
    end
457
 
458
    // register the op-code (rd / wr)
459
    else if (md_transfer_cnt == 35)
460
    begin
461
      #4;
462
      if (md_io_reg === 1'b1)
463
      begin
464
        #1 md_io_rd_wr = 1'b1;
465
      end
466
      else
467
      begin
468
        #1 md_io_rd_wr = 1'b0;
469
      end
470
    end
471
 
472
    else if (md_transfer_cnt == 36)
473
    begin
474
      #4;
475
      if ((md_io_reg === 1'b0) && (md_io_rd_wr == 1'b1))
476
      begin
477
        #1 md_io_rd_wr = 1'b1; // reading from PHY registers
478
        `ifdef VERBOSE
479
        $fdisplay(phy_log, "   (%0t)(%m)MIIM - op-code for READING from registers", $time);
480
        `endif
481
      end
482
      else if ((md_io_reg === 1'b1) && (md_io_rd_wr == 1'b0))
483
      begin
484
        #1 md_io_rd_wr = 1'b0; // writing to PHY registers
485
        `ifdef VERBOSE
486
        $fdisplay(phy_log, "   (%0t)(%m)MIIM - op-code for WRITING to registers", $time);
487
        `endif
488
      end
489
      else
490
      begin
491
        // ERROR - wrong opcode !
492
        `ifdef VERBOSE
493
        #1 $fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong OP-CODE", $time);
494
        `endif
495
        #10 $stop;
496
      end
497
    // set the signal - get PHY address
498
      begin
499
        #1 md_get_phy_address = 1'b1;
500
      end
501
    end
502
 
503
    // reset the signal - get PHY address
504
    else if (md_transfer_cnt == 41)
505
    begin
506
      #4 md_get_phy_address = 1'b0;
507
    // set the signal - get register address
508
      #1 md_get_reg_address = 1'b1;
509
    end
510
 
511
    // reset the signal - get register address
512
    // set the signal - put register data to output register
513
    else if (md_transfer_cnt == 46)
514
    begin
515
      #4 md_get_reg_address = 1'b0;
516
      #1 md_put_reg_data_out = 1'b1;
517
    end
518
 
519
    // reset the signal - put register data to output register
520
    // set the signal - enable md_io as output when read
521
    else if (md_transfer_cnt == 47)
522
    begin
523
      #4 md_put_reg_data_out = 1'b0;
524
      if (md_io_rd_wr) //read
525
      begin
526
        if (md_io_reg !== 1'bz)
527
        begin
528
          // ERROR - turn around !
529
          `ifdef VERBOSE
530
          #1 $fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong turn-around cycle before reading data out", $time);
531
          `endif
532
          #10 $stop;
533
        end
534
        if ((phy_address === `ETH_PHY_ADDR) || respond_to_all_phy_addr) // check the PHY address
535
        begin
536
          #1 md_io_enable = 1'b1;
537
          `ifdef VERBOSE
538
          $fdisplay(phy_log, "   (%0t)(%m)MIIM - received correct PHY ADDRESS: %x", $time, phy_address);
539
          `endif
540
        end
541
        else
542
        begin
543
          `ifdef VERBOSE
544
          #1 $fdisplay(phy_log, "*W (%0t)(%m)MIIM - received different PHY ADDRESS: %x", $time, phy_address);
545
          `endif
546
        end
547
      end
548
      else // write
549
      begin
550
        #1 md_io_enable = 1'b0;
551
    // check turn around cycle when write on clock 47
552
        if (md_io_reg !== 1'b1)
553
        begin
554
          // ERROR - turn around !
555
          `ifdef VERBOSE
556
          #1 $fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong 1. turn-around cycle before writing data in",
557
                       $time);
558
          `endif
559
          #10 $stop;
560
        end
561
      end
562
    end
563
 
564
    // set the signal - get register data in when write
565
    else if (md_transfer_cnt == 48)
566
    begin
567
      #4;
568
      if (!md_io_rd_wr) // write
569
      begin
570
        #1 md_get_reg_data_in = 1'b1;
571
    // check turn around cycle when write on clock 48
572
        if (md_io_reg !== 1'b0)
573
        begin
574
          // ERROR - turn around !
575
          `ifdef VERBOSE
576
          #1 $fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong 2. turn-around cycle before writing data in",
577
                       $time);
578
          `endif
579
          #10 $stop;
580
        end
581
      end
582
      else // read
583
      begin
584
        #1 md_get_reg_data_in = 1'b0;
585
      end
586
    end
587
 
588
    // reset the signal - enable md_io as output when read
589
    // reset the signal - get register data in when write
590
    // set the signal - put registered data in the register when write
591
    else if (md_transfer_cnt == 64)
592
    begin
593
      #1 md_io_enable = 1'b0;
594
      #4 md_get_reg_data_in = 1'b0;
595
      if (!md_io_rd_wr) // write
596
      begin
597
        if ((phy_address === `ETH_PHY_ADDR) || respond_to_all_phy_addr) // check the PHY address
598
        begin
599
          #1 md_put_reg_data_in = 1'b1;
600
          `ifdef VERBOSE
601
          $fdisplay(phy_log, "   (%0t)(%m)MIIM - received correct PHY ADDRESS: %x", $time, phy_address);
602
          $fdisplay(phy_log, "   (%0t)(%m)MIIM - WRITING to register %x COMPLETED!", $time, reg_address);
603
          `endif
604
        end
605
        else
606
        begin
607
          `ifdef VERBOSE
608
          #1 $fdisplay(phy_log, "*W (%0t)(%m)MIIM - received different PHY ADDRESS: %x", $time, phy_address);
609
          $fdisplay(phy_log, "*W (%0t)(%m)MIIM - NO WRITING to register %x !", $time, reg_address);
610
          `endif
611
        end
612
      end
613
      else // read
614
      begin
615
        `ifdef VERBOSE
616
        if ((phy_address === `ETH_PHY_ADDR) || respond_to_all_phy_addr) // check the PHY address
617
          #1 $fdisplay(phy_log, "   (%0t)(%m)MIIM - READING from register %x COMPLETED!",
618
                       $time, reg_address);
619
        else
620
          #1 $fdisplay(phy_log, "*W (%0t)(%m)MIIM - NO READING from register %x !", $time, reg_address);
621
        `endif
622
      end
623
    end
624
 
625
    // wait for one clock period
626
    @(posedge mdc_i)
627
      #1;
628
  end
629
end
630
 
631
//====================================================================
632
//
633
// PHY management (MIIM) REGISTERS
634
//
635
//====================================================================
636
//
637
//   Supported registers (normal operation):
638
//
639
// Addr | Register Name 
640
//--------------------------------------------------------------------
641
//   0  | Control reg.  
642
//   1  | Status reg. #1 
643
//   2  | PHY ID reg. 1 
644
//   3  | PHY ID reg. 2 
645
//----------------------
646
// Addr | Data MEMORY      |-->  for testing
647
//
648
//--------------------------------------------------------------------
649
//
650
// Control register
651
//  reg            control_bit15; // self clearing bit
652
//  reg    [14:10] control_bit14_10;
653
//  reg            control_bit9; // self clearing bit
654
//  reg    [8:0]   control_bit8_0;
655
// Status register
656
//  wire   [15:9]  status_bit15_9 = `SUPPORTED_SPEED_AND_PORT;
657
//  wire           status_bit8    = `EXTENDED_STATUS;
658
//  wire           status_bit7    = 1'b0; // reserved
659
//  reg    [6:0]   status_bit6_0  = `DEFAULT_STATUS;
660
// PHY ID register 1
661
//  wire   [15:0]  phy_id1        = `PHY_ID1;
662
// PHY ID register 2
663
//  wire   [15:0]  phy_id2        = {`PHY_ID2, `MAN_MODEL_NUM, `MAN_REVISION_NUM};
664
//--------------------------------------------------------------------
665
//
666
// Data MEMORY
667
//  reg    [15:0]  data_mem [0:31]; // 32 locations of 16-bit data width
668
//
669
//====================================================================
670
 
671
//////////////////////////////////////////////////////////////////////
672
//
673
// PHY management (MIIM) REGISTER control
674
//
675
//////////////////////////////////////////////////////////////////////
676
 
677
// wholy writable registers for walking ONE's on data, phy and reg. addresses
678
reg     registers_addr_data_test_operation;
679
 
680
// Non writable status registers
681
always
682
begin
683
  #1 status_bit6_0[6] = no_preamble;
684
  status_bit6_0[5] = 1'b0;
685
  status_bit6_0[3] = 1'b1;
686
  status_bit6_0[0] = 1'b1;
687
end
688
always@(posedge mrx_clk_o)
689
begin
690
  status_bit6_0[4] <= #1 1'b0;
691
  status_bit6_0[1] <= #1 1'b0;
692
end
693
initial
694
begin
695
  status_bit6_0[2] = 1'b1;
696
  registers_addr_data_test_operation = 0;
697
end
698
 
699
// Reading from a selected registers
700
always@(reg_address or registers_addr_data_test_operation or md_put_reg_data_out or
701
        control_bit15 or control_bit14_10 or control_bit9 or control_bit8_0 or
702
        status_bit15_9 or status_bit8 or status_bit7 or status_bit6_0 or
703
        phy_id1 or phy_id2)
704
begin
705
  if (registers_addr_data_test_operation) // test operation
706
  begin
707
    if (md_put_reg_data_out) // read enable
708
    begin
709
      register_bus_out = #1 data_mem[reg_address];
710
    end
711
  end
712
  else // normal operation
713
  begin
714
    if (md_put_reg_data_out) // read enable
715
    begin
716
      case (reg_address)
717
      5'h0:    register_bus_out = #1 {control_bit15, control_bit14_10, control_bit9, control_bit8_0};
718
      5'h1:    register_bus_out = #1 {status_bit15_9, status_bit8, status_bit7, status_bit6_0};
719
      5'h2:    register_bus_out = #1 phy_id1;
720
      5'h3:    register_bus_out = #1 phy_id2;
721
      default: register_bus_out = #1 16'hDEAD;
722
      endcase
723
    end
724
  end
725
end
726
 
727
// Self clear control signals
728
reg    self_clear_d0;
729
reg    self_clear_d1;
730
reg    self_clear_d2;
731
reg    self_clear_d3;
732
// Self clearing control
733
always@(posedge mdc_i or negedge m_rst_n_i)
734
begin
735
  if (!m_rst_n_i)
736
  begin
737
    self_clear_d0    <= #1 0;
738
    self_clear_d1    <= #1 0;
739
    self_clear_d2    <= #1 0;
740
    self_clear_d3    <= #1 0;
741
  end
742
  else
743
  begin
744
    self_clear_d0    <= #1 md_put_reg_data_in;
745
    self_clear_d1    <= #1 self_clear_d0;
746
    self_clear_d2    <= #1 self_clear_d1;
747
    self_clear_d3    <= #1 self_clear_d2;
748
  end
749
end
750
 
751
// Writing to a selected register
752
always@(posedge mdc_i or negedge m_rst_n_i)
753
begin
754
  if ((!m_rst_n_i) || (control_bit15))
755
  begin
756
    if (!registers_addr_data_test_operation) // normal operation
757
    begin
758
      control_bit15    <= #1 0;
759
      control_bit14_10 <= #1 {1'b0, (`LED_CFG1 || `LED_CFG2), `LED_CFG1, 2'b0};
760
      control_bit9     <= #1 0;
761
      control_bit8_0   <= #1 {`LED_CFG3, 8'b0};
762
    end
763
  end
764
  else
765
  begin
766
    if (registers_addr_data_test_operation) // test operation
767
    begin
768
      if (md_put_reg_data_in)
769
      begin
770
        data_mem[reg_address] <= #1 register_bus_in[15:0];
771
      end
772
    end
773
    else // normal operation
774
    begin
775
      // bits that are normaly written
776
      if (md_put_reg_data_in)
777
      begin
778
        case (reg_address)
779
        5'h0:
780
        begin
781
          control_bit14_10 <= #1 register_bus_in[14:10];
782
          control_bit8_0   <= #1 register_bus_in[8:0];
783
        end
784
        default:
785
        begin
786
        end
787
        endcase
788
      end
789
      // self cleared bits written
790
      if ((md_put_reg_data_in) && (reg_address == 5'h0))
791
      begin
792
        control_bit15 <= #1 register_bus_in[15];
793
        control_bit9  <= #1 register_bus_in[9];
794
      end
795
      else if (self_clear_d3) // self cleared bits cleared
796
      begin
797
        control_bit15 <= #1 1'b0;
798
        control_bit9  <= #1 1'b0;
799
      end
800
    end
801
  end
802
end
803
 
804
//////////////////////////////////////////////////////////////////////
805
//
806
// PHY <-> MAC control (RX and TX clocks are at the begining)
807
//
808
//////////////////////////////////////////////////////////////////////
809
 
810
// CARRIER SENSE & COLLISION
811
 
812
// MAC common signals
813
reg             mcoll_o;
814
reg             mcrs_o;
815
// Internal signals controling Carrier sense & Collision
816
  // MAC common signals generated when appropriate transfer
817
reg             mcrs_rx;
818
reg             mcrs_tx;
819
  // delayed mtxen_i signal for generating delayed tx carrier sense
820
reg             mtxen_d;
821
  // collision signal set or rest within task for controling collision
822
reg             task_mcoll;
823
  // carrier sense signal set or rest within task for controling carrier sense
824
reg             task_mcrs;
825
  // generate collision in full-duplex mode also - not normal operation
826
reg             collision_in_full_duplex;
827
  // generate carrier sense during TX in full-duplex mode also - not normal operation
828
reg             carrier_sense_in_tx_full_duplex;
829
  // on RX: delay after carrier sense signal; on TX: carrier sense delayed (delay is one clock period)
830
reg             real_carrier_sense;
831
 
832
initial
833
begin
834
  mcrs_rx = 0;
835
  mcrs_tx = 0;
836
  task_mcoll = 0;
837
  task_mcrs = 0;
838
  collision_in_full_duplex = 0;
839
  carrier_sense_in_tx_full_duplex = 0;
840
  real_carrier_sense = 0;
841
end
842
 
843
// Collision
844
always@(m_rst_n_i or control_bit8_0 or collision_in_full_duplex or
845
        mcrs_rx or mcrs_tx or task_mcoll
846
        )
847
begin
848
  if (!m_rst_n_i)
849
    mcoll_o = 0;
850
  else
851
  begin
852
    if (control_bit8_0[8]) // full duplex
853
    begin
854
      if (collision_in_full_duplex) // collision is usually not asserted in full duplex
855
      begin
856
        mcoll_o = (mcrs_rx && mcrs_tx) || task_mcoll;
857
        `ifdef VERBOSE
858
        if (mcrs_rx && mcrs_tx)
859
          $fdisplay(phy_log, "   (%0t)(%m) Collision set in FullDuplex!", $time);
860
        if (task_mcoll)
861
          $fdisplay(phy_log, "   (%0t)(%m) Collision set in FullDuplex from TASK!", $time);
862
        `endif
863
      end
864
      else
865
      begin
866
        mcoll_o = task_mcoll;
867
        `ifdef VERBOSE
868
        if (task_mcoll)
869
          $fdisplay(phy_log, "   (%0t)(%m) Collision set in FullDuplex from TASK!", $time);
870
        `endif
871
      end
872
    end
873
    else // half duplex
874
    begin
875
      mcoll_o = (mcrs_rx && mcrs_tx) || task_mcoll;
876
      `ifdef VERBOSE
877
      if (mcrs_rx && mcrs_tx)
878
        $fdisplay(phy_log, "   (%0t)(%m) Collision set in HalfDuplex!", $time);
879
      if (task_mcoll)
880
        $fdisplay(phy_log, "   (%0t)(%m) Collision set in HalfDuplex from TASK!", $time);
881
      `endif
882
    end
883
  end
884
end
885
 
886
// Carrier sense
887
always@(m_rst_n_i or control_bit8_0 or carrier_sense_in_tx_full_duplex or
888
        mcrs_rx or mcrs_tx or task_mcrs
889
        )
890
begin
891
  if (!m_rst_n_i)
892
    mcrs_o = 0;
893
  else
894
  begin
895
    if (control_bit8_0[8]) // full duplex
896
    begin
897
      if (carrier_sense_in_tx_full_duplex) // carrier sense is usually not asserted during TX in full duplex
898
        mcrs_o = mcrs_rx || mcrs_tx || task_mcrs;
899
      else
900
        mcrs_o = mcrs_rx || task_mcrs;
901
    end
902
    else // half duplex
903
    begin
904
      mcrs_o = mcrs_rx || mcrs_tx || task_mcrs;
905
    end
906
  end
907
end
908
 
909
// MAC TX CONTROL (RECEIVING AT PHY)
910
 
911
// storage memory for TX data received from MAC
912
reg     [7:0]  tx_mem [0:4194303]; // 4194304 locations (22 address lines) of 8-bit data width
913
reg    [31:0]  tx_mem_addr_in; // address for storing to TX memory
914
reg     [7:0]  tx_mem_data_in; // data for storing to TX memory
915
reg    [31:0]  tx_cnt; // counts nibbles
916
 
917
// control data of a TX packet for upper layer of testbench
918
reg            tx_preamble_ok;
919
reg            tx_sfd_ok;
920
// if there is a drible nibble, then tx packet is not byte aligned!
921
reg            tx_byte_aligned_ok;
922
// complete length of TX packet (Bytes) received (without preamble and SFD)
923
reg    [31:0]  tx_len;
924
 
925
// TX control
926
always@(posedge mtx_clk_o)
927
begin
928
  // storing data and basic checking of frame
929
  if (!m_rst_n_i)
930
  begin
931
    tx_cnt <= 0;
932
    tx_preamble_ok <= 0;
933
    tx_sfd_ok <= 0;
934
    tx_len <= 0;
935
  end
936
  else
937
  begin
938
    if (!mtxen_i)
939
    begin
940
      tx_cnt <= 0;
941
    end
942
    else
943
    begin
944
      // tx nibble counter
945
      tx_cnt <= tx_cnt + 1;
946
      // set initial values and check first preamble nibble
947
      if (tx_cnt == 0)
948
      begin
949
        `ifdef VERBOSE
950
        $fdisplay(phy_log, "   (%0t)(%m) TX frame started with tx_en set!", $time);
951
        `endif
952
        if (mtxd_i == 4'h5)
953
          tx_preamble_ok <= 1;
954
        else
955
          tx_preamble_ok <= 0;
956
        tx_sfd_ok <= 0;
957
        tx_byte_aligned_ok <= 0;
958
        tx_len <= 0;
959
//        tx_mem_addr_in <= 0;
960
      end
961
 
962
      // check preamble
963
      if ((tx_cnt > 0) && (tx_cnt <= 13))
964
      begin
965
        if ((tx_preamble_ok != 1) || (mtxd_i != 4'h5))
966
          tx_preamble_ok <= 0;
967
      end
968
      // check SFD
969
      if (tx_cnt == 14)
970
      begin
971
        `ifdef VERBOSE
972
        if (tx_preamble_ok == 1)
973
          $fdisplay(phy_log, "   (%0t)(%m) TX frame preamble OK!", $time);
974
        else
975
          $fdisplay(phy_log, "*E (%0t)(%m) TX frame preamble NOT OK!", $time);
976
        `endif
977
        if (mtxd_i == 4'h5)
978
          tx_sfd_ok <= 1;
979
        else
980
          tx_sfd_ok <= 0;
981
      end
982
      if (tx_cnt == 15)
983
      begin
984
        if ((tx_sfd_ok != 1) || (mtxd_i != 4'hD))
985
          tx_sfd_ok <= 0;
986
      end
987
 
988
      // control for storing addresses, type/length, data and FCS to TX memory
989
      if (tx_cnt > 15)
990
      begin
991
        if (tx_cnt == 16)
992
        begin
993
          `ifdef VERBOSE
994
          if (tx_sfd_ok == 1)
995
            $fdisplay(phy_log, "   (%0t)(%m) TX frame SFD OK!", $time);
996
          else
997
            $fdisplay(phy_log, "*E (%0t)(%m) TX frame SFD NOT OK!", $time);
998
          `endif
999
        end
1000
 
1001
        if (tx_cnt[0] == 0)
1002
        begin
1003
          tx_mem_data_in[3:0] <= mtxd_i; // storing LSB nibble
1004
          tx_byte_aligned_ok <= 0; // if transfer will stop after this, then there was drible nibble
1005
        end
1006
        else
1007
        begin
1008
          tx_mem[tx_mem_addr_in[21:0]] <= {mtxd_i, tx_mem_data_in[3:0]}; // storing data into tx memory
1009
          tx_len <= tx_len + 1; // enlarge byte length counter
1010
          tx_byte_aligned_ok <= 1; // if transfer will stop after this, then transfer is byte alligned
1011
          tx_mem_addr_in <= tx_mem_addr_in + 1'b1;
1012
        end
1013
      end
1014
    end
1015
  end
1016
 
1017
  // generating CARRIER SENSE for TX with or without delay
1018
  if (!m_rst_n_i)
1019
  begin
1020
    mcrs_tx <= 0;
1021
    mtxen_d <= 0;
1022
  end
1023
  else
1024
  begin
1025
    if (!real_carrier_sense)
1026
    begin
1027
      mtxen_d <= mtxen_i;
1028
      mcrs_tx <= mtxen_i;
1029
    end
1030
    else
1031
    begin
1032
      mtxen_d <= mtxen_i;
1033
      mcrs_tx <= mtxen_d;
1034
    end
1035
  end
1036
end
1037
 
1038
`ifdef VERBOSE
1039
reg             frame_started;
1040
 
1041
initial
1042
begin
1043
  frame_started = 0;
1044
end
1045
always@(posedge mtxen_i)
1046
begin
1047
  frame_started <= 1;
1048
end
1049
always@(negedge mtxen_i)
1050
begin
1051
  if (frame_started)
1052
  begin
1053
    $fdisplay(phy_log, "   (%0t)(%m) TX frame ended with tx_en reset!", $time);
1054
    frame_started <= 0;
1055
  end
1056
end
1057
 
1058
always@(posedge mrxerr_o)
1059
begin
1060
  $fdisplay(phy_log, "   (%0t)(%m) RX frame ERROR signal was set!", $time);
1061
end
1062
`endif
1063
 
1064
//////////////////////////////////////////////////////////////////////
1065
// 
1066
// Tasks for PHY <-> MAC transactions
1067
// 
1068
//////////////////////////////////////////////////////////////////////
1069
 
1070
initial
1071
begin
1072
  tx_mem_addr_in = 0;
1073
end
1074
 
1075
// setting the address of tx_mem, to set the starting point of tx packet
1076
task set_tx_mem_addr;
1077
  input [31:0] tx_mem_address;
1078
begin
1079
  #1 tx_mem_addr_in = tx_mem_address;
1080
end
1081
endtask // set_tx_mem_addr
1082
 
1083
// storage memory for RX data to be transmited to MAC
1084
reg     [7:0]  rx_mem [0:4194303]; // 4194304 locations (22 address lines) of 8-bit data width
1085
 
1086
// MAC RX signals
1087
reg     [3:0]   mrxd_o;
1088
reg             mrxdv_o;
1089
reg             mrxerr_o;
1090
 
1091
initial
1092
begin
1093
  mrxd_o = 0;
1094
  mrxdv_o = 0;
1095
  mrxerr_o = 0;
1096
  mcrs_rx = 0;
1097
end
1098
 
1099
task send_rx_packet;
1100
  input  [(8*32)-1:0] preamble_data; // preamble data to be sent
1101
  input   [3:0] preamble_len; // length of preamble - max is 8
1102
  input   [7:0] sfd_data; // SFD data to be sent
1103
  input  [31:0] start_addr; // start address
1104
  input  [31:0] len; // length of frame in Bytes (without preamble and SFD)
1105
  input         plus_drible_nibble; // if length is longer for one nibble
1106
  integer       rx_cnt;
1107
  reg    [31:0] rx_mem_addr_in; // address for reading from RX memory       
1108
  reg     [7:0] rx_mem_data_out; // data for reading from RX memory
1109
begin
1110
  @(posedge mrx_clk_o);
1111
  // generating CARRIER SENSE for TX with or without delay
1112
  if (real_carrier_sense)
1113
    #1 mcrs_rx = 1;
1114
  else
1115
    #1 mcrs_rx = 0;
1116
  @(posedge mrx_clk_o);
1117
  #1 mcrs_rx = 1;
1118
  #1 mrxdv_o = 1;
1119
  `ifdef VERBOSE
1120
  $fdisplay(phy_log, "   (%0t)(%m) RX frame started with rx_dv set!", $time);
1121
  `endif
1122
  // set initial rx memory address
1123
  rx_mem_addr_in = start_addr;
1124
 
1125
  // send preamble
1126
  for (rx_cnt = 0; (rx_cnt < preamble_len) || (rx_cnt < 8); rx_cnt = rx_cnt + 1)
1127
  begin
1128
    #1 mrxd_o = preamble_data[3:0];
1129
    #1 preamble_data = preamble_data >> 4;
1130
    @(posedge mrx_clk_o);
1131
  end
1132
 
1133
  // send SFD
1134
  for (rx_cnt = 0; rx_cnt < 2; rx_cnt = rx_cnt + 1)
1135
  begin
1136
    #1 mrxd_o = sfd_data[3:0];
1137
    #1 sfd_data = sfd_data >> 4;
1138
    @(posedge mrx_clk_o);
1139
  end
1140
  `ifdef VERBOSE
1141
  $fdisplay(phy_log, "   (%0t)(%m) RX frame preamble and SFD sent!", $time);
1142
  `endif
1143
  // send packet's addresses, type/length, data and FCS
1144
  for (rx_cnt = 0; rx_cnt < len; rx_cnt = rx_cnt + 1)
1145
  begin
1146
    @(posedge mrx_clk_o);
1147
    #1;
1148
    rx_mem_data_out = rx_mem[rx_mem_addr_in[21:0]];
1149
    mrxd_o = rx_mem_data_out[3:0];
1150
    @(posedge mrx_clk_o);
1151
    #1;
1152
    mrxd_o = rx_mem_data_out[7:4];
1153
    rx_mem_addr_in = rx_mem_addr_in + 1;
1154
    #1;
1155
  end
1156
  if (plus_drible_nibble)
1157
  begin
1158
    @(posedge mrx_clk_o);
1159
    #1;
1160
    rx_mem_data_out = rx_mem[rx_mem_addr_in[21:0]];
1161
    mrxd_o = rx_mem_data_out[3:0];
1162
  end
1163
  `ifdef VERBOSE
1164
  $fdisplay(phy_log, "   (%0t)(%m) RX frame addresses, type/length, data and FCS sent!", $time);
1165
  `endif
1166
  @(posedge mrx_clk_o);
1167
  #1 mcrs_rx = 0;
1168
  #1 mrxdv_o = 0;
1169
  `ifdef VERBOSE
1170
  $fdisplay(phy_log, "   (%0t)(%m) RX frame ended with rx_dv reset!", $time);
1171
  `endif
1172
end
1173
endtask // send_rx_packet
1174
 
1175
 
1176
 
1177
task GetDataOnMRxD;
1178
  input [15:0] Len;
1179
  input [31:0] TransferType;
1180
  integer tt;
1181
 
1182
  begin
1183
    @ (posedge mrx_clk_o);
1184
    #1 mrxdv_o=1'b1;
1185
 
1186
    for(tt=0; tt<15; tt=tt+1)
1187
    begin
1188
      mrxd_o=4'h5;              // preamble
1189
      @ (posedge mrx_clk_o);
1190
      #1;
1191
    end
1192
 
1193
    mrxd_o=4'hd;                // SFD
1194
 
1195
    for(tt=1; tt<(Len+1); tt=tt+1)
1196
    begin
1197
      @ (posedge mrx_clk_o);
1198
      #1;
1199
      if(TransferType == `UNICAST_XFR && tt == 1)
1200
        mrxd_o = 4'h0;   // Unicast transfer
1201
      else if(TransferType == `BROADCAST_XFR && tt < 7)
1202
        mrxd_o = 4'hf;
1203
      else
1204
        mrxd_o = tt[3:0]; // Multicast transfer
1205
 
1206
      @ (posedge mrx_clk_o);
1207
      #1;
1208
 
1209
      if(TransferType == `BROADCAST_XFR && tt == 6)
1210
        mrxd_o = 4'he;
1211
      else
1212
 
1213
      if(TransferType == `BROADCAST_XFR && tt < 7)
1214
        mrxd_o = 4'hf;
1215
      else
1216
        mrxd_o = tt[7:4];
1217
    end
1218
 
1219
    @ (posedge mrx_clk_o);
1220
    #1;
1221
    mrxdv_o = 1'b0;
1222
  end
1223
endtask // GetDataOnMRxD
1224
 
1225
 
1226
//////////////////////////////////////////////////////////////////////
1227
//
1228
// Tastks for controling PHY statuses and rx error
1229
//
1230
//////////////////////////////////////////////////////////////////////
1231
 
1232
// Link control tasks
1233
task link_up_down;
1234
  input   test_op;
1235
begin
1236
  #1 status_bit6_0[2] = test_op; // 1 - link up; 0 - link down
1237
end
1238
endtask
1239
 
1240
// RX error
1241
task rx_err;
1242
  input   test_op;
1243
begin
1244
  #1 mrxerr_o = test_op; // 1 - RX error set; 0 - RX error reset
1245
end
1246
endtask
1247
 
1248
//////////////////////////////////////////////////////////////////////
1249
//
1250
// Tastks for controling PHY carrier sense and collision
1251
//
1252
//////////////////////////////////////////////////////////////////////
1253
 
1254
// Collision
1255
task collision;
1256
  input   test_op;
1257
begin
1258
  #1 task_mcoll = test_op;
1259
end
1260
endtask
1261
 
1262
// Carrier sense
1263
task carrier_sense;
1264
  input   test_op;
1265
begin
1266
  #1 task_mcrs = test_op;
1267
end
1268
endtask
1269
 
1270
// Collision detection in full duplex also
1271
task collision_fd_detect;
1272
  input   test_op;
1273
begin
1274
  #1 collision_in_full_duplex = test_op;
1275
end
1276
endtask
1277
 
1278
// Carrier sense detection at TX in full duplex also
1279
task carrier_sense_tx_fd_detect;
1280
  input   test_op;
1281
begin
1282
  #1 carrier_sense_in_tx_full_duplex = test_op;
1283
end
1284
endtask
1285
 
1286
// Set real delay on carrier sense signal
1287
task carrier_sense_real_delay;
1288
  input   test_op;
1289
begin
1290
  #1 real_carrier_sense = test_op;
1291
end
1292
endtask
1293
 
1294
//////////////////////////////////////////////////////////////////////
1295
//
1296
// Tastks for controling PHY management test operation
1297
//
1298
//////////////////////////////////////////////////////////////////////
1299
 
1300
// Set registers to test operation and respond to all phy addresses
1301
task test_regs;
1302
  input   test_op;
1303
begin
1304
  #1 registers_addr_data_test_operation = test_op;
1305
  respond_to_all_phy_addr = test_op;
1306
end
1307
endtask
1308
 
1309
// Clears data memory for testing the MII
1310
task clear_test_regs;
1311
  integer i;
1312
begin
1313
  for (i = 0; i < 32; i = i + 1)
1314
  begin
1315
    #1 data_mem[i] = 16'h0;
1316
  end
1317
end
1318
endtask
1319
 
1320
// Accept frames with preamble suppresed
1321
task preamble_suppresed;
1322
  input   test_op;
1323
begin
1324
  #1 no_preamble = test_op;
1325
  md_transfer_cnt_reset = 1'b1;
1326
  @(posedge mdc_i);
1327
  #1 md_transfer_cnt_reset = 1'b0;
1328
end
1329
endtask
1330
 
1331
 
1332
 
1333
 
1334
 
1335
endmodule
1336
 

powered by: WebSVN 2.1.0

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