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

Subversion Repositories ethmac

[/] [ethmac/] [trunk/] [bench/] [verilog/] [eth_phy.v] - Blame information for rev 169

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

powered by: WebSVN 2.1.0

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