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

Subversion Repositories ethmac

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

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

powered by: WebSVN 2.1.0

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