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

Subversion Repositories turbo8051

[/] [turbo8051/] [trunk/] [verif/] [agents/] [ethernet/] [tb_mii.v] - Blame information for rev 76

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 15 dinesha
 
2
 /*------------------------------------------------------------
3
|           Ethernet MAC Traffic Generator Testbench           |
4
|                                                              |
5
 -------------------------------------------------------------*/
6
 
7
/*-----------------------------------------------------------------\
8
|  DESCRIPTION:                                                    |
9
|  tb_mii.v:  MII interface of testbench                           |
10
|                                                                  |
11
|  Instantiated modules: none                                      |
12
|  Included files: tb_conf.v                                       |
13
\-----------------------------------------------------------------*/
14
 
15
 
16
 
17
`include "tb_eth_conf.v"
18
 
19
module tb_mii(
20
                 port_type,   // includes duplex status and speed
21
                 port_tx_enable, // enable port TX
22
                 port_rx_enable, // enable port RX
23
                 // MII signals
24
                 REFCLK,   // Reference clock input
25
                 // Transmit interface of testbench
26
                 RXD,      // Receive data (output)
27
                 CRS,      // Carrier Sense (output)
28
                 RX_DV,    // RX data valid (output)
29
                 COL,      // collision signal (output)
30
                 RX_CLK,   // Receive clock (output) 
31
                 // Receive interface of testbench
32
                 TXD,      // Transmit data (input)
33
                 TX_EN,    // Transmit Enable (input)
34
                 TX_CLK,   // Transmit clock (output)
35
 
36
                 // Packet interface
37
                 transmit_data_valid, // flag to enable transmission
38
                 transmit_complete,   // flag set to indicate end of transmission
39
                 receive_data_valid,  // set to signal valid packet received
40
                 event_file           // Log file descriptor
41
                 );
42
 
43
   input [3:0]                   port_type;
44
   input                        port_tx_enable, port_rx_enable;
45
 
46
   input                        REFCLK;
47
   output [`MII_WIDTH-1:0]      RXD;
48
   output                       CRS,
49
                                RX_DV,
50
                                COL,
51
                                RX_CLK;
52
 
53
   input [`MII_WIDTH-1:0]       TXD;
54
   input                        TX_EN;
55
   output                       TX_CLK;
56
 
57
   input                        transmit_data_valid;
58
   inout                        transmit_complete;
59
   inout                        receive_data_valid;
60
 
61
   input  [31:0]                event_file;
62
 
63
   reg [`MII_WIDTH-1:0]  RXD;
64
   reg                          carrier_sense, RX_DV;
65
 
66
   reg                          local_transmit_complete;
67
   reg                          local_receive_data_valid;
68
 
69
   reg [7:0]                     tx_reg; // transmit data register
70
   reg                          transmit_clk;  // Transmit clock: 50 or 5 MHz
71
   integer                      transmit_clk_count; // counter to generate transmit clk
72
 
73
   integer                      CLK_DIVISOR; //Modulus of transmit clock counter
74
   integer                      PAUSE_COUNTER_MAX; // Modulus of counter to
75
                                                   // generate pause timer clock
76
   reg                          alignment_error;  // Alignment error in received frame
77
 
78
   integer                      collision_counter;
79
   reg                          collision_detect;
80
   reg                          forced_collision_detect;
81
   integer                      forced_col_counter;
82
                                // collision counter for forced collisions
83
   reg                          backoff_complete;
84
   reg                          collision_limit_reached;
85
   reg                          extended_TX_EN;
86
   integer                      transmit_state;  // state of transmit interface
87
   integer                      receive_state; // state of receive interface
88
 
89
   reg                          paused;  // Pause frame received
90
   integer                      pause_parameter; // pause parameter received
91
   reg                          pause_timer_clk; // clock for pause timer
92
   reg [7:0]                    pause_timer_count; // counter to generate clock
93
 
94
   reg [`MAX_PKT_SIZE*8-1:0]     transmit_pkt_reg;
95
   reg [15:0]                   transmit_pkt_size_reg;
96
 
97
   integer                      bytes_sent;
98
 
99
   integer                      first_IFG_cycle; // time at which IFG detected first
100
   integer                      last_IFG; // length of last IFG
101
 
102
   integer                      transmitted_packet_count;      // number of pkts transmitted
103
   integer                      transmitted_packet_byte_count; // number of pkts transmitted
104
 
105
   integer                      receive_packet_count;      // number of pkts received
106
   integer                      receive_packet_byte_count; // number of pkts received
107
   integer                      receive_alignment_err_count;
108
   integer                      receive_undersized_err_count;
109
   integer                      receive_crc_err_count;
110
   integer                      receive_length_err_count;
111
   integer                      receive_pause_frm_count;
112
   //    
113
   // Valid transmit and receive states
114
`define       INACTIVE          0
115
`define       XMIT_IDLE         1
116
`define       RCV_IDLE          1
117
`define       XMIT_BUSY         2
118
`define       RCV_BUSY          2
119
`define       COLLISION         3
120
`define       XMIT_PAUSED       4
121
 
122
`define       FULL_DUPLEX_PORT     port_type[3]
123
`define       SPEED_100Mb          port_type[0]
124
 
125
   // access port parameters from tbench module
126
`define port_idle_count           `TESTBENCH.port_idle_count
127
`define preamble_length           `TESTBENCH.preamble_length
128
`define preamble_reg              `TESTBENCH.preamble_reg
129
`define dribble_bit_count         `TESTBENCH.dribble_bit_count
130
`define carrier_override          `TESTBENCH.carrier_override
131
`define frame_extend_bit_count    `TESTBENCH.frame_extend_bit_count
132
`define frame_extend_reg          `TESTBENCH.frame_extend_reg
133
`define ignore_rcv_pause          `TESTBENCH.ignore_rcv_pause
134
`define pause_increment           `TESTBENCH.pause_increment
135
`define collision_detection_delay `TESTBENCH.collision_detection_delay
136
`define force_collision           `TESTBENCH.force_collision
137
`define collision_offset          `TESTBENCH.collision_offset
138
`define forced_collision_count    `TESTBENCH.forced_collision_count
139
`define force_collision_delay     `TESTBENCH.force_collision_delay
140
`define jam_length                `TESTBENCH.jam_length
141
 
142
`define seq_number_offset         `TESTBENCH.seq_number_offset
143
`define timestamp_offset          `TESTBENCH.timestamp_offset
144
 
145
`define ext_transmit_state        `TESTBENCH.mii_transmit_state
146
`define ext_receive_state         `TESTBENCH.mii_receive_state
147
`define ext_collision_counter     `TESTBENCH.mii_collision_counter
148
`define ext_SFD_received          `TESTBENCH.mii_SFD_received
149
 
150
   assign RX_CLK = transmit_clk;
151
   assign TX_CLK = transmit_clk;
152
   assign  COL = collision_detect | forced_collision_detect;
153
   assign CRS = (carrier_sense | `carrier_override) & port_tx_enable;
154
 
155
   assign transmit_complete = port_tx_enable ? local_transmit_complete :
156
                              1'bz;
157
 
158
   assign receive_data_valid = port_rx_enable ? local_receive_data_valid :
159
                               1'bz;
160
 
161
   initial
162
    begin
163
       transmit_clk_count = 0;
164
       RXD = 4'b0000;
165
       carrier_sense = 0;
166
       RX_DV = 0;
167
       local_transmit_complete = 0;
168
 
169
       local_receive_data_valid = 0;
170
 
171
       tx_reg = 8'h00;
172
       transmit_clk = 0;
173
 
174
       collision_counter = 0;
175
       forced_col_counter = 0;
176
       collision_detect = 0;
177
       forced_collision_detect = 0;
178
       backoff_complete = 0;
179
       collision_limit_reached = 0;
180
       transmit_state = `INACTIVE;
181
       receive_state = `INACTIVE;
182
       `ext_transmit_state = transmit_state;
183
       `ext_receive_state = receive_state;
184
       extended_TX_EN   = 0;
185
 
186
       paused = 0;          // clear paused flag 
187
       pause_parameter = 0;
188
       pause_timer_clk = 0;
189
       pause_timer_count = 0;
190
       // choose modulus of counter to generate pause timer clock
191
       PAUSE_COUNTER_MAX = 63;  // For Full MII
192
       first_IFG_cycle = 0;
193
 
194
       transmitted_packet_count = 0;
195
       transmitted_packet_byte_count = 0;
196
 
197
       receive_packet_count = 0;
198
       receive_packet_byte_count = 0;
199
       receive_alignment_err_count = 0;
200
       receive_undersized_err_count = 0;
201
       receive_crc_err_count = 0;
202
       receive_length_err_count = 0;
203
       receive_pause_frm_count = 0;
204
    end // initial begin
205
 
206
   // state transitions between inactive and idle
207
   always @(posedge port_tx_enable)
208
    if (transmit_state == `INACTIVE)
209
     begin
210
        transmit_state = `XMIT_IDLE;
211
        `ext_transmit_state = transmit_state;
212
     end // if (transmit_state == `INACTIVE)
213
 
214
   always @(negedge port_tx_enable)
215
    if (transmit_state == `XMIT_IDLE)
216
     begin
217
        transmit_state = `INACTIVE;
218
        `ext_transmit_state = transmit_state;
219
     end // if (transmit_state == `XMIT_IDLE)
220
 
221
   always @(posedge port_rx_enable)
222
    if (receive_state == `INACTIVE)
223
     begin
224
        receive_state = `RCV_IDLE;
225
        `ext_receive_state = receive_state;
226
     end // if (receive_state == `INACTIVE)
227
   always @(negedge port_rx_enable)
228
    begin
229
       if (receive_state == `RCV_IDLE)
230
        receive_state = `INACTIVE;
231
       `ext_receive_state = receive_state;
232
    end // always @ (negedge port_rx_enable)
233
 
234
   // export state of collision counter
235
   always @(collision_counter)
236
    if (!`force_collision)
237
     `ext_collision_counter = collision_counter;
238
   always @(forced_col_counter)
239
    if (`force_collision)
240
     `ext_collision_counter = forced_col_counter;
241
 
242
   /* configure transmit clock */
243
   always @(port_type)
244
    if (`SPEED_100Mb)
245
     CLK_DIVISOR = 2;   // Full MII, 100 Mb/s (use REFCLK/2)
246
    else
247
     CLK_DIVISOR = 20;  // Full MII, 10 Mb/s (divide by 20)
248
 
249
   /**********************Transmit Routines ******************************/
250
 
251
   /******* Transmit clock generator ********/
252
   always @(REFCLK)
253
    begin
254
      if (CLK_DIVISOR == 1)
255
        transmit_clk = REFCLK;
256
       else
257
        if (REFCLK == 0) // negative edge
258
         begin
259
            if (transmit_clk_count >= (CLK_DIVISOR/2 -1))
260
             begin
261
                transmit_clk = ~transmit_clk;
262
                transmit_clk_count = 0;
263
             end
264
            else
265
             transmit_clk_count = transmit_clk_count +1;
266
         end // if (REFCLK == 0)
267
    end // always @ (REFCLK)
268
   /*****************************************/
269
 
270
   /* Log clock cycle time into event log */
271
   initial
272
    begin: log_clock_cycle_block
273
       integer clock_period, last_cycle;
274
       wait(port_tx_enable & port_rx_enable);
275
       @(posedge transmit_clk)
276
        last_cycle = $time;
277
       @(posedge transmit_clk)
278
         clock_period = $time - last_cycle;
279
       $write("Clock period configured = %0d ns, data width = %0d\n",
280
              clock_period, `MII_WIDTH);
281
       $fwrite(event_file, "Clock period configured = %0d ns, data width = %0d\n",
282
              clock_period, `MII_WIDTH);
283
    end // block: log_clock_cycle_block
284
 
285
   /******* generate pause timer clk by dividing transmit clock by 512********/
286
   always @(negedge transmit_clk)
287
    begin
288
       if (pause_timer_count >= PAUSE_COUNTER_MAX)
289
        begin
290
           pause_timer_clk = ~pause_timer_clk;
291
           pause_timer_count = 0;
292
        end
293
       else
294
        pause_timer_count = pause_timer_count +1;
295
    end // always @ (negedge transmit_clk)
296
   /**********************************************************************/
297
 
298
   always @(posedge transmit_data_valid) // first transmission of a frame
299
    begin: transmit_block
300
       integer  ttime;
301
 
302
       if ((port_tx_enable) && (`TESTBENCH.transmit_enable))
303
        begin
304
           local_transmit_complete = 0;
305
           collision_limit_reached = 0;
306
           #1
307
            // save packet data in register
308
            transmit_pkt_reg = `TESTBENCH.transmit_pkt;
309
           transmit_pkt_size_reg = `TESTBENCH.transmit_pkt_size;
310
 
311
           if (!`FULL_DUPLEX_PORT)
312
            wait(`force_collision == 0);
313
 
314
           if (!`FULL_DUPLEX_PORT) // wait for end of receive frame
315
            wait(extended_TX_EN == 0); // wait for IFG after TX_EN goes down
316
 
317
           if (`FULL_DUPLEX_PORT)
318
            wait(paused == 0); // if in PAUSED state, wait for puse timer to expire
319
 
320
           bytes_sent = 0;
321
 
322
           // Activate carrier sense
323
           @(negedge transmit_clk);
324
           carrier_sense <= #1 1;
325
           RX_DV <= #2 1;
326
           // insert seqno, timestamp and CRC
327
           insert_seqno_timestamp_crc;
328
 
329
           // copy packet back
330
           `TESTBENCH.transmit_pkt = transmit_pkt_reg;
331
           `TESTBENCH.transmit_pkt_size = transmit_pkt_size_reg;
332
 
333
           transmit_state = `XMIT_BUSY;
334
           `ext_transmit_state = transmit_state;
335
 
336
           if (`port_idle_count != 0)
337
            begin
338
               transmit_idle(`port_idle_count);
339
            end // if (port_idle_count != 0)
340
 
341
           // transmit preamble
342
           if (`preamble_length != 0)
343
            begin
344
               fork
345
                  begin
346
                     transmit_preamble(`preamble_reg, `preamble_length);
347
                     transmit_packet;
348
                  end // if (`preamble_length != 0)
349
                  // log packet
350
                  @(posedge transmit_clk)
351
                  log_transmitted_packet;
352
               join
353
            end
354
           else
355
            begin
356
               fork
357
                  transmit_packet;
358
                  // log packet
359
                  @(posedge transmit_clk)
360
                   log_transmitted_packet;
361
               join
362
            end // else: !if(`preamble_length != 0)
363
 
364
           // Transmit extra bits if required to generate alignment error
365
           if (`frame_extend_bit_count != 0)
366
            begin
367
               @(posedge transmit_clk);
368
               transmit_frame_extend_bits(`frame_extend_reg, `frame_extend_bit_count);
369
            end // if (`frame_extend_bit_count != 0)
370
 
371
           // Turn off carrier sense 
372
           @(posedge transmit_clk);
373
           carrier_sense  <= #1 0;
374
           RX_DV <= #1 0;
375
           RXD  <= #1 4'b0000;
376
           $write("%t ns: Completed packet transmission to MAC\n",
377
                  $time);
378
           $fwrite(event_file, "%t ns: Completed packet transmission to MAC\n",
379
                   $time);
380
           if (port_tx_enable)
381
            transmit_state = `XMIT_IDLE;
382
           else
383
            transmit_state = `INACTIVE;
384
           `ext_transmit_state = transmit_state;
385
           transmit_IFG(`TESTBENCH.port_min_ifg);
386
           local_transmit_complete = 1;
387
           collision_counter = 0;
388
        end // if (port_tx_enable)
389
    end // block: transmit_block
390
 
391
   always @(posedge backoff_complete) // retransmission of a frame
392
    if ((port_tx_enable) && (`TESTBENCH.transmit_enable))
393
     begin: retransmit_block
394
       integer  ttime;
395
       begin
396
          if (collision_limit_reached)
397
           begin
398
              // discard frame
399
              local_transmit_complete = 1;
400
              if (port_tx_enable)
401
               transmit_state = `XMIT_IDLE;
402
              else
403
               transmit_state = `INACTIVE;
404
              `ext_transmit_state = transmit_state;
405
              collision_counter = 0;
406
           end
407
          else
408
           begin
409
              local_transmit_complete = 0;
410
              #1;
411
              if (!`FULL_DUPLEX_PORT)
412
               wait(`force_collision == 0);
413
 
414
              if (!`FULL_DUPLEX_PORT) // wait for end of receive frame
415
               wait(extended_TX_EN == 0); // wait for IFG after TX_EN goes down
416
 
417
              bytes_sent = 0;
418
 
419
              // Activate carrier sense
420
              @(negedge transmit_clk);
421
              carrier_sense  <= #1  1;
422
              RX_DV <= #2 1;
423
 
424
              // insert seqno, timestamp and CRC
425
              insert_seqno_timestamp_crc;
426
 
427
              // copy packet back
428
              `TESTBENCH.transmit_pkt = transmit_pkt_reg;
429
              `TESTBENCH.transmit_pkt_size = transmit_pkt_size_reg;
430
 
431
              // log packet
432
              log_transmitted_packet;
433
 
434
              transmit_state = `XMIT_BUSY;
435
              `ext_transmit_state = transmit_state;
436
 
437
              if (`port_idle_count != 0)
438
               transmit_idle(`port_idle_count);
439
 
440
              // transmit preamble;
441
              if (`preamble_length != 0)
442
               transmit_preamble(`preamble_reg, `preamble_length);
443
 
444
              transmit_packet;
445
 
446
              // Transmit extra bits if required to generate alignment error
447
              if (`frame_extend_bit_count != 0)
448
               begin
449
                  @(posedge transmit_clk);
450
                  transmit_frame_extend_bits(`frame_extend_reg, `frame_extend_bit_count);
451
               end // if (`frame_extend_bit_count != 0)
452
 
453
              // Turn off carrier sense 
454
              @(posedge transmit_clk);
455
              carrier_sense <= #1  0;
456
              RX_DV <= #1 0;
457
              RXD <= #1 4'b0000;
458
              $write("%t ns: Completed packet transmission to MAC\n",
459
                     $time);
460
              $fwrite(event_file, "%t ns: Completed packet transmission to MAC\n",
461
                      $time);
462
 
463
              if (port_tx_enable)
464
               transmit_state = `XMIT_IDLE;
465
              else
466
               transmit_state = `INACTIVE;
467
              `ext_transmit_state = transmit_state;
468
              transmit_IFG(`TESTBENCH.port_min_ifg);
469
              local_transmit_complete = 1;
470
              collision_counter = 0;
471
           end // else: !if(collision_limit_reached)
472
       end
473
    end // block: retransmit_block
474
 
475
   // Pause timer
476
   always @(posedge pause_timer_clk)
477
    if (paused)
478
     begin
479
        if (pause_parameter != 0)
480
         pause_parameter = pause_parameter -1;
481
        if (pause_parameter == 0)
482
         begin
483
            paused = 0;
484
            if (`DEBUG_MII)
485
             $write("%t ns: PAUSE completed\n",
486
                    $time);
487
         end // if (pause_parameter == 0)
488
        else
489
         begin
490
            if (`DEBUG_MII)
491
             $write("%t ns: Pause timer = %0d\n",
492
                    $time, pause_parameter);
493
         end // else: !if(pause_parameter == 0)
494
     end // if (paused)
495
 
496
   task transmit_idle;
497
      input length;
498
      integer length; // in bits
499
      integer i;
500
 
501
      begin
502
         for (i=0; i < length/`MII_WIDTH; i = i+1)
503
          begin
504
             tx_reg = 0;
505
             transmit(tx_reg, 1);
506
          end // for (i=0; i < length/`MII_WIDTH; i = i+1)
507
      end
508
   endtask // transmit_idle
509
 
510
   task transmit_preamble;
511
      input [127:0] pattern;
512
      input length;
513
      integer length; // in bits, including SFD
514
      integer i;
515
      begin
516
         for (i=0; i < length; i = i+`MII_WIDTH)
517
          begin
518
             tx_reg[0] = pattern[i];
519
             tx_reg[1] = pattern[i+1];
520
             tx_reg[2] = pattern[i+2];
521
             tx_reg[3] = pattern[i+3];
522
             transmit(tx_reg, 1);
523
          end // for (i=0; i < length; i = i+1)
524
      end
525
   endtask // transmit_preamble   
526
 
527
   task transmit_IFG;
528
      input length;
529
      integer length; // in bits
530
      integer i, cycles;
531
 
532
      begin
533
         cycles = length/`MII_WIDTH;
534
        // if (`SPEED_100Mb)
535
         for (i=0; i < cycles; i = i+1)
536
          begin
537
             tx_reg = 0;
538
             transmit(tx_reg, 1);
539
          end // for (i=0; i < cycles; i = i+1)
540
      end
541
   endtask // transmit_IFG
542
 
543
   task transmit_packet;
544
 
545
      integer length, i;
546
      reg [`MAX_PKT_SIZE*8-1:0] packet;
547
      integer CRS_active_cycles;
548
 
549
      begin
550
         length = transmit_pkt_size_reg;
551
         packet = transmit_pkt_reg;
552
 
553
         // determine when Carrier Sense is to be deasserted
554
         CRS_active_cycles = (length *8 - `dribble_bit_count)/`MII_WIDTH;
555
         for (i=0; i< length *2; i = i+1)
556
          begin
557
             tx_reg[3:0] = packet[3: 0];
558
             packet[`MAX_PKT_SIZE*8-1:0] =
559
                                          {4'b0000, packet[`MAX_PKT_SIZE*8-1: 4]};
560
             transmit(tx_reg, 1);
561
             if (i[0] == 1)
562
              bytes_sent = bytes_sent +1;
563
 
564
             // Check if it is time to deactivate CRS
565
             if ((`dribble_bit_count != 0) // If CRS is to be deactivated before
566
                                        // end of packet
567
                 && (i < length*2 -1))  // do not modify CRS in last cycle
568
                                        // because calling routine will do it
569
              begin
570
                 @(posedge transmit_clk);
571
                 if (CRS_active_cycles != 0)
572
                  begin
573
                     CRS_active_cycles = CRS_active_cycles -1;
574
                     if (CRS_active_cycles == 0) // deactivate CRS
575
                         carrier_sense = 0;
576
                  end // if (CRS_active_cycles != 0)
577
              end // if ((`dribble_bit_count != 0)...
578
          end // for (i=0; i< length; i = i+1)
579
      end
580
   endtask // transmit_packet
581
 
582
   task transmit_frame_extend_bits;  // transmit dribble bits after normal packet
583
                                // to generate an alignment error at the MAC
584
 
585
      input [31:0] pattern; // data
586
      input length; // length in bits
587
      integer length, i;
588
      begin
589
         for (i=length; i > 0; i = i-`MII_WIDTH)
590
          begin
591
             tx_reg[3] = pattern[i-1];
592
             tx_reg[2] = pattern[i-2];
593
             tx_reg[1] = pattern[i-3];
594
             tx_reg[0] = pattern[i-4];
595
             transmit(tx_reg, 1);
596
          end // for (i=length; i > 0; i = i-`MII_WIDTH)
597
      end
598
   endtask
599
 
600
   task transmit;  // transmit routine 
601
      input [7:0] data; // transmit data
602
      input length;  // number of di-bits to transmit
603
      integer length, i;
604
      begin
605
         for (i=0; i< length; i = i+1)
606
          begin
607
             @(negedge transmit_clk)
608
              begin
609
                 RXD[3:0] = data[3:0];
610
                 data = data >> `MII_WIDTH;
611
              end
612
          end
613
      end
614
   endtask // transmit
615
 
616
   task insert_seqno_timestamp_crc;
617
      // Inserts seqno, timestamp, and CRC in frame
618
      integer  ttime, i, j;
619
      integer position;
620
      reg [1:0] crc_option;
621
      reg [31:0] seqno, crc, good_crc;
622
 
623
      begin
624
         if ((`TESTBENCH.seqno_enable) &&
625
             (!`TESTBENCH.user_frame))
626
          begin
627
             // add sequence number to packet
628
             if (`seq_number_offset < 0)
629
              // insert sequence number at the end of frame before CRC
630
              position = transmit_pkt_size_reg -4 + `seq_number_offset;
631
             else
632
              position = `seq_number_offset;
633
             seqno = `TESTBENCH.packet_seq_no;
634
 
635
             for (i=0; i<4; i=i+1)
636
              for (j = 0; j < 8; j= j+1)
637
               transmit_pkt_reg[(position+i)*8 + j] = seqno[(3-i)*8 + j];
638
          end // if (`TESTBENCH.seqno_enable)
639
 
640
         if ((`TESTBENCH.timestamp_enable) &&
641
             (!`TESTBENCH.user_frame))
642
          begin
643
             // add timestamp to packet
644
             if (`timestamp_offset < 0)
645
              // insert sequence number at the end of frame before CRC
646
              position = transmit_pkt_size_reg -4 + `timestamp_offset;
647
             else
648
              position = `timestamp_offset;
649
             ttime = $time;
650
 
651
             for (i=0; i<4; i=i+1)
652
              for (j = 0; j < 8; j= j+1)
653
               transmit_pkt_reg[(position+i)*8 + j] = ttime[(3-i)*8 + j];
654
          end
655
 
656
         // Add CRC
657
         good_crc = CRC32(transmit_pkt_reg, transmit_pkt_size_reg);
658
         if (!`TESTBENCH.user_frame)
659
          crc_option = `TESTBENCH.flowrec_crc_option;
660
         else
661
          crc_option = `TESTBENCH.user_crc_option;
662
 
663
         case(crc_option)
664
           0: // generate good CRC
665
            begin
666
               crc = good_crc;
667
            end
668
 
669
           1: // generate bad CRC
670
            begin
671
               crc = $random();
672
               if (crc == good_crc)
673
                crc = crc ^ 32'h80000000;
674
            end // case: 1
675
 
676
           3: // Set CRC to user-defined value
677
            begin
678
               if (!`TESTBENCH.user_frame)
679
                crc = `TESTBENCH.flowrec_user_crc;
680
               else
681
                crc = `TESTBENCH.user_crc_value;
682
            end // case: 3
683
         endcase // case(`TESTBENCH.flowrec_crc_option)
684
 
685
         if (crc_option != 2'b10)
686
          // insert CRC in frame
687
          for (i= 0; i < 4; i=i+1)
688
           for (j=0; j<8; j = j+1)
689
            transmit_pkt_reg[(transmit_pkt_size_reg-4+i)*8 +j] =
690
                  crc[8*i +j];
691
 
692
      end
693
   endtask // insert_seqno_timestamp_crc
694
 
695
   task log_transmitted_packet;
696
      integer  ttime, i, j;
697
      reg [31:0] seq_no, timestamp;
698
      reg [47:0] mac_addr;
699
      integer position;
700
      reg [15:0] type_length_field;
701
 
702
      begin
703
         ttime = $time;
704
 
705
         transmitted_packet_count = transmitted_packet_count +1;
706
         transmitted_packet_byte_count = transmitted_packet_byte_count +transmit_pkt_size_reg;
707
 
708
         // get type/length field
709
         type_length_field[15:8] = transmit_pkt_reg[103:96];
710
         type_length_field[7:0]  = transmit_pkt_reg[111:104];
711
 
712
         // get sequence number and timestamp
713
         if (`TESTBENCH.seqno_enable)
714
          seq_no = `TESTBENCH.packet_seq_no;
715
         else
716
          seq_no = 0;
717
         if (`TESTBENCH.timestamp_enable)
718
          begin
719
             // get timestamp from packet
720
             timestamp = 0;
721
             if (`timestamp_offset < 0)
722
              position = transmit_pkt_size_reg -4 + `timestamp_offset;
723
             else
724
              position = `timestamp_offset;
725
             for (i=0; i<4; i=i+1)
726
              for (j = 0; j < 8; j= j+1)
727
               timestamp[(3-i)*8 + j] = transmit_pkt_reg[(position+i)*8 + j];
728
          end // if (`TESTBENCH.timestamp_enable)
729
 
730
         if (collision_counter == 0)
731
          begin
732
             $write("%0d ns: Starting packet transmission to MAC",
733
                 ttime);
734
             $fwrite(event_file, "%0d ns: Starting packet transmission to MAC",
735
                     ttime);
736
 
737
          end // if (collision_counter == 0)
738
         else
739
          begin
740
             $write("%0d ns: Retransmitting packet",
741
                    ttime);
742
             $fwrite(event_file, "%0d ns: Retransmitting packet",
743
                     ttime);
744
          end // else: !if(collision_counter == 0)
745
 
746
         $write(", size = %0d", transmit_pkt_size_reg);
747
         $fwrite(event_file, ", size = %0d", transmit_pkt_size_reg);
748
 
749
         if (`TESTBENCH.seqno_enable && (!`TESTBENCH.user_frame))
750
          begin
751
             $write(", seq no = %0d", seq_no);
752
             $fwrite(event_file, ", seq no = %0d", seq_no);
753
          end // if (`TESTBENCH.seqno_enable)
754
 
755
         if (`TESTBENCH.timestamp_enable && (!`TESTBENCH.user_frame))
756
          begin
757
             $write(", timestamp = %0d", timestamp);
758
             $fwrite(event_file, ", timestamp = %0d", timestamp);
759
          end // if (`TESTBENCH.timestamp_enable)
760
         $write("\n");
761
         $fwrite(event_file, "\n");
762
 
763
         mac_addr = transmit_pkt_reg[95:48];
764
         $write("SA = %h:%h:%h:%h:%h:%h, ",
765
                mac_addr[ 7: 0], mac_addr[15: 8], mac_addr[23:16],
766
                mac_addr[31:24], mac_addr[39:32], mac_addr[47:40]);
767
 
768
         $fwrite(event_file, "SA = %h:%h:%h:%h:%h:%h, ",
769
                 mac_addr[ 7: 0], mac_addr[15: 8], mac_addr[23:16],
770
                 mac_addr[31:24], mac_addr[39:32], mac_addr[47:40]);
771
 
772
         mac_addr = transmit_pkt_reg[47:0];
773
         $write("DA = %h:%h:%h:%h:%h:%h",
774
                mac_addr[ 7: 0], mac_addr[15: 8], mac_addr[23:16],
775
                mac_addr[31:24], mac_addr[39:32], mac_addr[47:40]);
776
 
777
         $fwrite(event_file, "DA = %h:%h:%h:%h:%h:%h",
778
                 mac_addr[ 7: 0], mac_addr[15: 8], mac_addr[23:16],
779
                 mac_addr[31:24], mac_addr[39:32], mac_addr[47:40]);
780
 
781
         if (type_length_field[15:0] == `DEFAULT_VLAN_TPID)
782
          begin
783
             $write(", VLAN TCI = %h%h", transmit_pkt_reg[119:112],
784
                    transmit_pkt_reg[127:120]);
785
             $fwrite(event_file, ", VLAN TCI = %h%h", transmit_pkt_reg[119:112],
786
                     transmit_pkt_reg[127:120]);
787
             // get length field
788
             type_length_field[15:8] = transmit_pkt_reg[135:128];
789
             type_length_field[7:0]  = transmit_pkt_reg[143:136];
790
          end
791
         $write(", type/length = %h", type_length_field[15:0]);
792
         $fwrite(event_file, ", type/length = %h", type_length_field[15:0]);
793
         $write("\n");
794
         $fwrite(event_file, "\n");
795
 
796
         if (`LOG_TRANSMITTED_FRAMES)
797
          print_packet(event_file, transmit_pkt_reg, transmit_pkt_size_reg);
798
      end
799
   endtask // log_transmitted_packet
800
 
801
//**************************** RECEIVE ROUTINES *****************************//
802
 
803
   integer rcv_cycle_count, rcv_byte_count;
804
   reg     SFD_received; // flag to indicate SFD received
805
 
806
   reg [7:0] rcv_buffer;
807
   reg [`MAX_PKT_SIZE*8-1:0]     receive_pkt_data;
808
 
809
 
810
   initial
811
    begin
812
       rcv_buffer = 0;
813
       SFD_received = 0;
814
       `ext_SFD_received = SFD_received;
815
       rcv_cycle_count = 0;
816
       rcv_byte_count = 0;
817
    end
818
 
819
   always @(posedge transmit_clk)
820
    if (port_rx_enable && TX_EN && (!SFD_received))
821
     begin: mii_rcv_block
822
 
823
        integer ttime;
824
 
825
        ttime = $time;
826
        if (receive_state != `RCV_BUSY) // first bit of preamble, calculate IFG
827
         begin
828
            if (`SPEED_100Mb)
829
             last_IFG = (ttime - first_IFG_cycle)/10; // 10 ns per bit
830
            else
831
             last_IFG = (ttime - first_IFG_cycle)/100; // 100 ns per bit
832
            $write("%0d ns: Preamble detected, last IFG = %0d bits\n",
833
                   ttime, last_IFG);
834
            $fwrite(event_file, "%0d ns: Preamble detected, last IFG = %0d bits\n",
835
                    ttime, last_IFG);
836
         end // if (receive_state == `IDLE)
837
 
838
        receive_state = `RCV_BUSY;
839
        `ext_receive_state = receive_state;
840
        rcv_buffer = {TXD[3:0], rcv_buffer[7:4]};
841
        if ((rcv_buffer == `SFD) && (!collision_detect))
842
         begin
843
            #1 SFD_received = 1;
844
            `ext_SFD_received = SFD_received;
845
            ttime = $time;
846
            $write("%0d ns: SFD received, last IFG = %0d bits\n",
847
                   ttime, last_IFG);
848
            $fwrite(event_file, "%0d ns: SFD received, last IFG = %0d bits\n",
849
                   ttime, last_IFG);
850
 
851
            // check and print IFG violations,
852
            // but do not check IFG for first packet
853
            if ((last_IFG < `MIN_IFG) && (receive_packet_count != 0))
854
             begin
855
                $write("IFG violation, received IFG = %0d bits, minimum IFG = %0d bits\n",
856
                       last_IFG, `MIN_IFG);
857
                $fwrite(event_file, "IFG violation, received IFG = %0d bits, minimum IFG = %0d bits\n",
858
                        last_IFG, `MIN_IFG);
859
                if (`TERMINATE_ON_IFG_VIOLATION)
860
                 $finish;
861
             end // if (last_IFG < `MIN_IFG)
862
            rcv_cycle_count = 0;
863
            rcv_byte_count = 0;
864
            alignment_error = 0;
865
         end // if ((rcv_buffer == `SFD) && (!collision_detect))
866
     end // block: mii_rcv_block
867
 
868
   always @(posedge transmit_clk)
869
    if (SFD_received)
870
     begin: SFD_rcv
871
            integer j;
872
        local_receive_data_valid = 0;
873
        rcv_buffer = {TXD[3:0], rcv_buffer[7:4]};
874
 
875
        rcv_cycle_count = rcv_cycle_count +1;
876
        if (TX_EN && (rcv_cycle_count % (8/`MII_WIDTH) == 0))
877
         begin
878
            // check if we exceeded the buffer size
879
            if (rcv_byte_count < `MAX_PKT_SIZE)
880
             begin
881
                for (j=0; j< 8; j = j+1)
882
                 receive_pkt_data[(rcv_cycle_count*`MII_WIDTH/8)*8 -1 -j]
883
                       = rcv_buffer[7-j];
884
             end // if (rcv_byte_count < `MAX_PKT_SIZE)
885
            rcv_byte_count = rcv_byte_count+1;
886
         end // if (TX_EN && (rcv_cycle_count % (8/`MII_WIDTH) == 0))
887
     end // if (SFD_received)
888
 
889
   always @(negedge TX_EN)
890
    if (port_rx_enable && SFD_received && (!collision_detect)
891
        && (!`force_collision))
892
     begin: receive_log_block
893
 
894
        receive_state = `RCV_IDLE;
895
        `ext_receive_state = receive_state;
896
        // check for oversize frame
897
        if (rcv_byte_count > `MAX_PKT_SIZE)
898
         begin
899
            $write("%t ns: Maximum packet size exceeded while receiving from MAC, size = %0d bytes\n",
900
                   $time, rcv_byte_count);
901
            $fwrite(event_file, "%t ns: Maximum packet size exceeded while receiving from MAC, size = %0d bytes\n",
902
                    $time, rcv_byte_count);
903
            rcv_byte_count = `MAX_PKT_SIZE; // truncate packet to max size
904
            if (`TERMINATE_ON_OVERSIZE_FRAME)
905
             begin
906
                if (`LOG_RECEIVED_FRAMES || `LOG_FRAMES_WITH_ERRORS)
907
                 print_packet(event_file, receive_pkt_data, rcv_byte_count);
908
                $finish;
909
             end // if (`TERMINATE_ON_OVERSIZE_FRAME)
910
         end // if (rcv_byte_count > `MAX_PKT_SIZE)
911
 
912
        // Copy packet from buffer
913
        `TESTBENCH.receive_pkt = receive_pkt_data;
914
        `TESTBENCH.receive_pkt_size = rcv_byte_count;
915
        local_receive_data_valid = 1;
916
        `TESTBENCH.receive_data_available = 1;
917
 
918
        if (rcv_cycle_count % (8/`MII_WIDTH) != 0) begin
919
         // frame alignment error
920
            alignment_error = 1;
921
            receive_alignment_err_count = receive_alignment_err_count+1;
922
        end else
923
         alignment_error = 0;
924
        // log message
925
 
926
        if (pause_frame(receive_pkt_data[511:0], rcv_byte_count)) // pause received
927
         begin
928
            pause_parameter = get_pause_time(receive_pkt_data[511:0]);
929
            log_pause_frame;
930
            if (!`ignore_rcv_pause) // respond to pause only if flag set
931
             begin
932
                pause_parameter = pause_parameter + `pause_increment;
933
                      // add or subtract user-defined increment
934
                if (pause_parameter < 0)
935
                 pause_parameter = 0;
936
                paused = (pause_parameter != 0);
937
                if (paused)
938
                 begin
939
                    transmit_state = `XMIT_PAUSED;
940
                    `ext_transmit_state = transmit_state;
941
                 end // if (paused)
942
             end // if (!ignore_rcv_pause)
943
         end // if pause_frame(receive_pkt_data,
944
        else
945
         log_received_packet;
946
 
947
        rcv_buffer = 0;
948
        SFD_received = 0;
949
        `ext_SFD_received = SFD_received;
950
        rcv_cycle_count = 0;
951
        rcv_byte_count = 0;
952
     end // block: receive_log_block
953
 
954
   // Keep track of the cycle in which IFG begins
955
   always @(negedge TX_EN)
956
    if (port_rx_enable)
957
     begin: monitor_IFG
958
        @(posedge transmit_clk);
959
        first_IFG_cycle = $time;
960
     end // block: monitor_IFG
961
 
962
   task log_received_packet;
963
 
964
      integer  ttime, payload_start, i, j;
965
      reg [31:0] seq_no, timestamp;
966
      reg [47:0] mac_addr;
967
      reg [15:0] type_length_field;
968
      integer position, header_length;
969
      reg [31:0] computed_crc, received_crc;
970
      reg errored_packet;
971
 
972
      begin
973
         ttime = $time;
974
         errored_packet = 0;
975
         receive_packet_count = receive_packet_count + 1;
976
         receive_packet_byte_count = receive_packet_byte_count + rcv_byte_count;
977
 
978
         header_length = 6*2 + 4 + 2; // size of L2 header with no tagging
979
 
980
         // get type/length field
981
         type_length_field[15:8] = receive_pkt_data[103:96];
982
         type_length_field[7:0]  = receive_pkt_data[111:104];
983
 
984
         // get sequence number and timestamp
985
         seq_no = 0;
986
         timestamp = 0;
987
         if (`TESTBENCH.seqno_enable)
988
          begin
989
             if (`seq_number_offset < 0)
990
              // sequence number at the end of frame before CRC
991
              position = rcv_byte_count -4 + `seq_number_offset;
992
             else
993
              position = `seq_number_offset;
994
             if ((position >= 0) && (position +4 <= `MAX_PKT_SIZE))
995
              for (i=0; i<4; i=i+1)
996
               for (j = 0; j < 8; j= j+1)
997
                seq_no[(3-i)*8 + j] =  receive_pkt_data[(position+i)*8 + j];
998
          end // if (`TESTBENCH.seqno_enable)
999
         if (`TESTBENCH.timestamp_enable)
1000
          begin
1001
 
1002
             // get timestamp from packet
1003
             timestamp = 0;
1004
             if (`timestamp_offset < 0)
1005
              // timestamp at the end of frame before CRC
1006
              position =rcv_byte_count -4 + `timestamp_offset;
1007
             else
1008
              position = `timestamp_offset;
1009
             if ((position >= 0) && (position +4 <= `MAX_PKT_SIZE))
1010
              for (i=0; i<4; i=i+1)
1011
               for (j = 0; j < 8; j= j+1)
1012
                timestamp[(3-i)*8 + j] =  receive_pkt_data[(position+i)*8 + j];
1013
          end // if (`TESTBENCH.timestamp_enable)
1014
 
1015
         if (rcv_byte_count < `MIN_FRAME_SIZE) // under-size frame
1016
          begin
1017
             $write("%0d ns: Received undersize packet, ",
1018
                    ttime);
1019
             $fwrite(event_file, "%0d ns: Received undersize packet, ",
1020
                     ttime);
1021
             errored_packet = 1;
1022
             receive_undersized_err_count = receive_undersized_err_count+1;
1023
          end // if (pkt_size < `MIN_FRAME_SIZE)
1024
         else
1025
          begin
1026
             $write("%0d ns: Received packet, ",
1027
                    ttime);
1028
             $fwrite(event_file, "%0d ns: Received packet, ",
1029
                     ttime);
1030
          end // else: !if(pkt_size < `MIN_FRAME_SIZE)
1031
 
1032
         if (rcv_byte_count >= 8)
1033
          begin
1034
             computed_crc = CRC32(receive_pkt_data, rcv_byte_count);
1035
             for (i= 0; i < 4; i=i+1)
1036
              for (j=0; j<8; j = j+1)
1037
               received_crc[8*i +j] = receive_pkt_data[(rcv_byte_count-4+i)*8 +j];
1038
          end // if (rcv_byte_count >= 8)
1039
 
1040
         $write("size = %0d", rcv_byte_count);
1041
         $fwrite(event_file, "size = %0d", rcv_byte_count);
1042
         if (!errored_packet) // do not print parameters for undersize frames
1043
          begin
1044
             if (`TESTBENCH.seqno_enable)
1045
              begin
1046
                 $write(", seq no = %0d", seq_no);
1047
                 $fwrite(event_file, ", seq no = %0d", seq_no);
1048
              end // if (`TESTBENCH.seqno_enable)
1049
             if (`TESTBENCH.timestamp_enable)
1050
              begin
1051
                 $write(", timestamp = %0d", timestamp);
1052
                 $fwrite(event_file, ", timestamp = %0d", timestamp);
1053
              end // if (`TESTBENCH.timestamp_enable)
1054
             $write("\n");
1055
             $fwrite(event_file, "\n");
1056
 
1057
             mac_addr = receive_pkt_data[95:48];
1058
             $write("SA = %h:%h:%h:%h:%h:%h, ",
1059
                    mac_addr[ 7: 0], mac_addr[15: 8], mac_addr[23:16],
1060
                    mac_addr[31:24], mac_addr[39:32], mac_addr[47:40]);
1061
             $fwrite(event_file, "SA = %h:%h:%h:%h:%h:%h, ",
1062
                     mac_addr[ 7: 0], mac_addr[15: 8], mac_addr[23:16],
1063
                     mac_addr[31:24], mac_addr[39:32], mac_addr[47:40]);
1064
 
1065
             mac_addr = receive_pkt_data[47:0];
1066
             $write("DA = %h:%h:%h:%h:%h:%h",
1067
                    mac_addr[ 7: 0], mac_addr[15: 8], mac_addr[23:16],
1068
                    mac_addr[31:24], mac_addr[39:32], mac_addr[47:40]);
1069
             $fwrite(event_file, "DA = %h:%h:%h:%h:%h:%h",
1070
                     mac_addr[ 7: 0], mac_addr[15: 8], mac_addr[23:16],
1071
                     mac_addr[31:24], mac_addr[39:32], mac_addr[47:40]);
1072
 
1073
             if (type_length_field[15:0] == `DEFAULT_VLAN_TPID) // tagged frame
1074
              begin
1075
                 $write(", VLAN TCI = %h%h", receive_pkt_data[119:112],
1076
                        receive_pkt_data[127:120]);
1077
                 $fwrite(event_file, ", VLAN TCI = %h%h", receive_pkt_data[119:112],
1078
                         receive_pkt_data[127:120]);
1079
                 // get length field
1080
                 type_length_field[15:8] = receive_pkt_data[135:128];
1081
                 type_length_field[7:0]  = receive_pkt_data[143:136];
1082
                 header_length = header_length +4;
1083
              end
1084
             $write(", type/length = %h", type_length_field[15:0]);
1085
             $fwrite(event_file, ", type/length = %h", type_length_field[15:0]);
1086
             $write("\n");
1087
             $fwrite(event_file, "\n");
1088
          end // if (!errored_packet)
1089
         else
1090
          begin // under-size frame
1091
             $write("\n");
1092
             $fwrite(event_file, "\n");
1093
             if (`TERMINATE_ON_UNDERSIZE_FRAME)
1094
              begin
1095
                 if (`LOG_RECEIVED_FRAMES || `LOG_FRAMES_WITH_ERRORS)
1096
                  print_packet(event_file, receive_pkt_data, rcv_byte_count);
1097
                 $finish;
1098
              end // if (`TERMINATE_ON_UNDERSIZE_FRAME)
1099
          end // else: !if(!errored_packet)
1100
 
1101
         // check for errors
1102
         if (alignment_error)
1103
          begin
1104
             $write("Frame alignment error\n");
1105
             $fwrite(event_file, "Frame alignment error\n");
1106
             errored_packet = 1;
1107
             if (`TERMINATE_ON_ALIGNMENT_ERROR)
1108
              begin
1109
                 if (`LOG_RECEIVED_FRAMES || `LOG_FRAMES_WITH_ERRORS)
1110
                  print_packet(event_file, receive_pkt_data, rcv_byte_count);
1111
                 $finish;
1112
              end // if (`TERMINATE_ON_ALIGNMENT_ERROR)
1113
          end // if (alignment_error)
1114
 
1115
         if (computed_crc != received_crc)
1116
          begin
1117
             $write("CRC error, computed CRC = %x, received CRC = %x\n",
1118
                    computed_crc[31:0], received_crc[31:0]);
1119
             $fwrite(event_file, "CRC error, computed CRC = %x, received CRC = %x\n",
1120
                     computed_crc[31:0], received_crc[31:0]);
1121
             errored_packet = 1;
1122
             receive_crc_err_count = receive_crc_err_count + 1;
1123
             if (`TERMINATE_ON_CRC_ERROR)
1124
              begin
1125
                 if (`LOG_RECEIVED_FRAMES || `LOG_FRAMES_WITH_ERRORS)
1126
                  print_packet(event_file, receive_pkt_data, rcv_byte_count);
1127
                 $finish;
1128
              end // if (`TERMINATE_ON_CRC_ERROR)
1129
          end // if (computed_crc != received_crc)
1130
 
1131
         if (type_length_field[15:11] == 5'b00000) // 802.3 frame
1132
             // check for length error
1133
          begin
1134
             if ((rcv_byte_count-header_length) != {16'd0, type_length_field})
1135
              begin
1136
                 $write("Length error, type/length field = %0d, expected value = %0d\n",
1137
                        type_length_field, rcv_byte_count-header_length);
1138
                 $fwrite(event_file,
1139
                         "Length error, type/length field = %0d, expected value = %0d\n",
1140
                         type_length_field, rcv_byte_count-header_length);
1141
                 errored_packet = 1;
1142
                 receive_length_err_count = receive_length_err_count+1;
1143
              end // if ((rcv_byte_count-header_length) != {16'd0, type_length_field})
1144
          end // if (type_length_field[15:11] == 5'b00000)
1145
         if (`LOG_RECEIVED_FRAMES)
1146
          print_packet(event_file, receive_pkt_data, rcv_byte_count);
1147
         else
1148
          if (`LOG_FRAMES_WITH_ERRORS && errored_packet)
1149
           print_packet(event_file, receive_pkt_data, rcv_byte_count);
1150
      end
1151
   endtask // log_received_packet
1152
 
1153
   task log_pause_frame;
1154
      integer  ttime, i, j;
1155
      reg [15:0] pause_time;
1156
      reg [47:0] mac_addr;
1157
      reg [31:0] computed_crc, received_crc;
1158
      reg errored_packet;
1159
 
1160
      begin
1161
         ttime = $time;
1162
         errored_packet = 0;
1163
 
1164
         receive_pause_frm_count = receive_pause_frm_count+1;
1165
         // compute CRC
1166
         computed_crc = CRC32(receive_pkt_data, rcv_byte_count);
1167
         for (i= 0; i < 4; i=i+1)
1168
          for (j=0; j<8; j = j+1)
1169
           received_crc[8*i +j] = receive_pkt_data[(rcv_byte_count-4+i)*8 +j];
1170
         $write("%0d ns: Received PAUSE frame, ",
1171
                ttime);
1172
         $fwrite(event_file, "%0d ns: Received PAUSE frame, ",
1173
                 ttime);
1174
         $write("size = %0d, ", rcv_byte_count);
1175
         $fwrite(event_file, "size = %0d, ", rcv_byte_count);
1176
 
1177
         mac_addr = receive_pkt_data[95:48];
1178
         $write("SA = %h:%h:%h:%h:%h:%h, ",
1179
                mac_addr[ 7: 0], mac_addr[15: 8], mac_addr[23:16],
1180
                mac_addr[31:24], mac_addr[39:32], mac_addr[47:40]);
1181
         $fwrite(event_file, "SA = %h:%h:%h:%h:%h:%h, ",
1182
                 mac_addr[ 7: 0], mac_addr[15: 8], mac_addr[23:16],
1183
                 mac_addr[31:24], mac_addr[39:32], mac_addr[47:40]);
1184
         pause_time[15:8] = receive_pkt_data[135:128];
1185
         pause_time[ 7:0] = receive_pkt_data[143:136];
1186
         $write("pause time = %x\n", pause_time[15:0]);
1187
         $fwrite(event_file, "pause time = %x\n", pause_time[15:0]);
1188
         // check for errors
1189
         if (alignment_error)
1190
          begin
1191
             $write("Frame alignment error\n");
1192
             $fwrite(event_file, "Frame alignment error\n");
1193
             errored_packet = 1;
1194
          end // if (alignment_error)
1195
 
1196
         if (computed_crc != received_crc)
1197
          begin
1198
             $write("CRC error, computed CRC = %x, received CRC = %x\n",
1199
                    computed_crc[31:0], received_crc[31:0]);
1200
             $fwrite(event_file, "CRC error, computed CRC = %x, received CRC = %x\n",
1201
                     computed_crc[31:0], received_crc[31:0]);
1202
             errored_packet = 1;
1203
          end // if (computed_crc != received_crc)
1204
         if (`LOG_RECEIVED_FRAMES)
1205
          print_packet(event_file, receive_pkt_data, rcv_byte_count);
1206
         else
1207
          if (`LOG_FRAMES_WITH_ERRORS && errored_packet)
1208
           print_packet(event_file, receive_pkt_data, rcv_byte_count);
1209
      end
1210
   endtask // log_pause_frame
1211
 
1212
   /****************************************************************************/
1213
   /*              Collision handling for half-duplex interface                */
1214
   /****************************************************************************/
1215
 
1216
   always @ (TX_EN or carrier_sense)
1217
    if (port_tx_enable && `TESTBENCH.transmit_enable && (!`force_collision))
1218
     begin : collision_detection
1219
           integer ttime;
1220
       #0;
1221
       if (carrier_sense == 1 && TX_EN == 1 && (!`FULL_DUPLEX_PORT))
1222
        begin
1223
           #(`collision_detection_delay * 10);
1224
           collision_detect = 1;
1225
           ttime = $time;
1226
           transmit_state = `COLLISION;
1227
           receive_state = `COLLISION;
1228
           `ext_transmit_state = transmit_state;
1229
           `ext_receive_state = receive_state;
1230
 
1231
           // check for out-of-window collision
1232
           if (bytes_sent > 64)
1233
            begin
1234
               $write("%0d ns: Out-of-window collision, collision counter = %0d\n",
1235
                      ttime, collision_counter+1);
1236
               $fwrite(event_file,
1237
                       "%0d ns: Out-of-window collision, collision counter = %0d\n",
1238
                       ttime, collision_counter+1);
1239
            end // if (bytes_sent > 64)
1240
           else
1241
            begin
1242
               $write("%0d ns: Collision detected, collision counter = %0d\n",
1243
                      ttime, collision_counter+1);
1244
               $fwrite(event_file,
1245
                       "%0d ns: Collision detected, collision counter = %0d\n",
1246
                       ttime, collision_counter+1);
1247
            end // else: !if(bytes_sent > 64)
1248
        end // if (carrier_sense==1 && TX_EN==1 && (!`FULL_DUPLEX_PORT))
1249
    end // always @ (TX_EN or CRS_DV)
1250
 
1251
   always @ (posedge collision_detect)
1252
    begin : collision_handling
1253
       integer backoff_slots, backoff_interval;
1254
       integer ttime, i, x;
1255
 
1256
       SFD_received = 0;
1257
       `ext_SFD_received = SFD_received;
1258
       backoff_complete = 0;
1259
       if (`DEBUG_MII)
1260
        $write("%t ns: waiting for transmit state = XMIT_DATA\n", $time);
1261
 
1262
       disable transmit_block;
1263
       disable retransmit_block;
1264
       disable transmit_packet;
1265
       disable transmit_frame_extend_bits;
1266
       disable transmit;
1267
 
1268
       if (`DEBUG_MII)
1269
        $write("%t ns: Sending jamming signal\n",$time);
1270
       transmit_jam_signal;
1271
       if (port_tx_enable)
1272
        transmit_state = `XMIT_IDLE;
1273
       else
1274
        transmit_state = `INACTIVE;
1275
       `ext_transmit_state = transmit_state;
1276
       carrier_sense = 0;
1277
       RX_DV = 0;
1278
       wait(TX_EN == 0);
1279
       #1
1280
        collision_detect = 0;
1281
 
1282
       // Do backoff 
1283
       collision_counter = collision_counter +1;
1284
       if ((collision_counter >= `MAX_COLLISIONS) ||
1285
           (collision_counter >= `TESTBENCH.collision_limit))
1286
        begin
1287
           collision_limit_reached = 1;
1288
           ttime = $time;
1289
           $write("%t ns: Aborting transmission to MAC due to excessive collisions, collision counter = %0d\n",
1290
                  $time, collision_counter);
1291
           $fwrite(event_file,
1292
                   "%t ns: Aborting transmission to MAC due to excessive collisions, collision counter = %0d\n",
1293
                   $time, collision_counter);
1294
           backoff_interval = 0;
1295
           collision_counter = 0;
1296
        end // if ((collision_counter >= `MAX_COLLISIONS) ||...
1297
       else
1298
        begin
1299
           // compute backoff interval
1300
           if (collision_counter == 0)
1301
            backoff_interval = 0;
1302
           else
1303
            begin
1304
               backoff_slots = `TESTBENCH.backoff_slots[collision_counter];
1305
               backoff_interval = backoff_slots;  // deterministic backoff
1306
               if (`TESTBENCH.backoff_type[collision_counter]) // random backoff
1307
                begin
1308
                   x = $random();
1309
                   backoff_interval = x[15:0] % backoff_slots;
1310
                end // if (`TESTBENCH.backoff_type[index])
1311
            end // else: !if(collision_counter == 0)
1312
        end // else: !if((collision_counter >= `MAX_COLLISIONS) ||...
1313
 
1314
       // wait for backoff interval
1315
       if (backoff_interval > 0)
1316
        begin
1317
           if (`DEBUG_MII)
1318
            $write("%t ns: Going into backoff, backoff interval = %0d slot(s)\n",
1319
                   $time, backoff_interval);
1320
           if (`SPEED_100Mb) // 100 Mb port
1321
            #(backoff_interval * 100 * 512); // 512 bits * 10 ns
1322
           else
1323
            #(backoff_interval * 1000 * 512); // 512 bits * 100 ns
1324
           if (`DEBUG_MII)
1325
            $write("%t ns: Backoff complete\n",$time);
1326
        end // if (backoff_interval > 0)
1327
 
1328
       backoff_complete = 1;
1329
       transmit_state = `XMIT_IDLE;
1330
       `ext_transmit_state = transmit_state;
1331
 
1332
    end // always @ (posedge collision_detect)
1333
 
1334
   // generate sense signal for half-duplex
1335
   always @(TX_EN)
1336
    if (port_tx_enable)
1337
     begin
1338
        #0;
1339
        if (TX_EN == 1) // starting to receive frame
1340
         extended_TX_EN = 1;
1341
        else            // end of reception
1342
         begin
1343
            if (`SPEED_100Mb) // 100 Mb port
1344
             #(`TESTBENCH.port_min_ifg * 100); // IFG * 10 ns/bit
1345
            else
1346
             #(`TESTBENCH.port_min_ifg * 1000); // IFG * 100 ns/bit
1347
            if (TX_EN == 0)
1348
             extended_TX_EN = 0;
1349
         end // else: !if(TX_EN == 1)
1350
     end // always @ (TX_EN)
1351
 
1352
   // Force collisions with an incoming frame
1353
   always @ (posedge transmit_clk)
1354
    if (port_tx_enable && port_rx_enable && (!`FULL_DUPLEX_PORT) &&
1355
        `force_collision && TX_EN && (!carrier_sense))
1356
     begin : force_collision_block
1357
           integer ttime;
1358
        if (`DEBUG_MII)
1359
         $display("%t ns: Waiting to force collision, delay = %0d MII cycles",
1360
                  $time, `force_collision_delay);
1361
        // count down to the bit position of collision
1362
        `force_collision_delay = `force_collision_delay - `MII_WIDTH;
1363
        if ((`force_collision_delay == 0) ||
1364
            (`force_collision_delay[31] == 1))
1365
         // Force collision now
1366
         begin
1367
            #(`collision_detection_delay * 10);
1368
            carrier_sense = 1;  // activate carrier sense
1369
            RX_DV = 1;
1370
            forced_collision_detect = 1;
1371
            ttime = $time;
1372
            transmit_state = `COLLISION;
1373
            receive_state = `COLLISION;
1374
            `ext_transmit_state = transmit_state;
1375
            `ext_receive_state = receive_state;
1376
            forced_col_counter = forced_col_counter +1;
1377
            $write("%0d ns: Forcing collision, collision counter = %0d\n",
1378
                   ttime, forced_col_counter);
1379
            $fwrite(event_file, "%0d ns: Forcing collision, collision counter = %0d\n",
1380
                    ttime, forced_col_counter);
1381
            if (`DEBUG_MII)
1382
             $write("%t ns: Sending jamming signal\n",$time);
1383
            transmit_jam_signal;
1384
            if (port_tx_enable)
1385
             transmit_state = `XMIT_IDLE;
1386
            else
1387
             transmit_state = `INACTIVE;
1388
            `ext_transmit_state = transmit_state;
1389
            carrier_sense = 0;
1390
            RX_DV = 0;
1391
            wait(TX_EN == 0);
1392
            SFD_received = 0;
1393
            `ext_SFD_received = SFD_received;
1394
 
1395
            #1
1396
             forced_collision_detect = 0;
1397
             // Check if it is time to disable forced collisions
1398
             `forced_collision_count = `forced_collision_count -1;
1399
            if (`forced_collision_count == 0)
1400
             begin
1401
                `force_collision = 0;
1402
                forced_col_counter = 0;
1403
             end // if (`forced_collision_countn == 0)
1404
            else // reload position of forced collision
1405
             `force_collision_delay = `collision_offset;
1406
         end // if (force_collision_delay == 0)
1407
     end // block: force_collision
1408
 
1409
   // reset pointer to position of collision at the end of each frame
1410
   always @(negedge TX_EN)
1411
    if (port_tx_enable && port_rx_enable && (!`FULL_DUPLEX_PORT) &&
1412
        `force_collision)
1413
     begin
1414
        if (`DEBUG_MII)
1415
         $display("%t ns: End of forced collision, TX_EN sensed low", $time);
1416
        `force_collision_delay = `collision_offset;
1417
     end // if (port_tx_enable && port_rx_enable && (!`FULL_DUPLEX_PORT) &&...
1418
 
1419
   task transmit_jam_signal; // transmit 32 bits of 0101... jamming pattern 
1420
      integer i;
1421
      begin
1422
         for (i=0; i < `jam_length/`MII_WIDTH; i = i+1)
1423
          begin
1424
             tx_reg = 8'h55;
1425
             transmit(tx_reg, 1);
1426
          end
1427
      end
1428
   endtask // transmit_jam_signal
1429
 
1430
   /****************************************************************************/
1431
   /*                              Utility Routines                            */
1432
   /****************************************************************************/
1433
 
1434
   task print_packet;
1435
      input [31:0]                      event_file;
1436
      input [`MAX_PKT_SIZE*8-1:0]        pkt_data;
1437
      input [15:0]                       pkt_size;
1438
      integer i, j;
1439
      reg [7:0] x;
1440
      begin
1441
         $write("Contents:\n");
1442
         $fwrite(event_file, "Contents:\n");
1443
         for (i=0; i< pkt_size; i=i+1)
1444
          begin
1445
             for (j=0; j<8; j= j+1)
1446
              x[j] = pkt_data[i*8 +j];
1447
             $write("%x", x[7:0]);
1448
             $fwrite(event_file, "%x", x[7:0]);
1449
             if ((i == pkt_size-1) || (i[3:0] == 4'b1111))
1450
              begin
1451
                 $write("\n");
1452
                 $fwrite(event_file, "\n");
1453
              end // if ((i == pkt_size-1) || (i[3:0] == 4'b1111))
1454
             else
1455
              begin
1456
                 $write(" ");
1457
                 $fwrite(event_file, " ");
1458
              end // else: !if((i == pkt_size-1) || (i[3:0] == 4'b1111))
1459
          end // for (i=0; i< pkt_size; i=i+1)
1460
         $write("****\n");
1461
         $fwrite(event_file, "****\n");
1462
      end
1463
   endtask // print_packet
1464
 
1465
   function [31:0] CRC32; // compute CRC-32
1466
      input [`MAX_PKT_SIZE*8-1:0] packet;
1467
      input [15:0]                 packet_size;
1468
 
1469
   parameter gen_degree = 32;           // Degree of generator polynomial
1470
   integer   i, j, k;
1471
 
1472
   reg [gen_degree-1:0]         gen_polynomial;   // Generator polynomial
1473
   reg [`MAX_PKT_SIZE*8-1:0]    operand;
1474
 
1475
   begin
1476
      gen_polynomial = 32'b11101101101110001000001100100000;
1477
      /* Generator polynomial = x**32 + x**26 + x**23 + x**22 +
1478
       x**16 + x**12 + x**11 + x**10 + x**8 + x**7 + x**5 +
1479
       x**4 + x**2 + x**1 + 1.
1480
       Coefficient of x**32 omitted */
1481
 
1482
      for (i=0; i < packet_size*8; i= i+1)
1483
       operand[i] = packet[i];
1484
 
1485
      // clear CRC area in packet
1486
      for (i=(packet_size-4)*8; i < packet_size*8; i= i+1)
1487
       operand[i] = 0;
1488
 
1489
      // Invert first 32 bits of operand before CRC computation
1490
      operand[31:0] = ~operand[31:0];
1491
 
1492
      // Compute CRC
1493
      for (i=0; i < (packet_size-4)*8; i = i+1)
1494
       if (operand[i])
1495
        for (j=0; j < 32; j= j+1)
1496
         operand[i+j+1] = operand[i+j+1] ^ gen_polynomial[j];
1497
 
1498
      // Copy CRC 
1499
      for (i=0; i <= 24; i= i+8)
1500
       for (j=0; j < 8; j = j+1)
1501
        CRC32[i+j] = ~operand[(packet_size-4)*8+i+j];
1502
   end
1503
   endfunction // CRC32
1504
 
1505
   function pause_frame; // returns 1 if the input frame is a Pause frame
1506
      input [511:0] pkt_data;
1507
      input pkt_size;
1508
      integer pkt_size;
1509
      reg [47:0]                  destination_mac_addr;
1510
      reg [15:0]                  frame_type;
1511
      reg [15:0]                  opcode;
1512
 
1513
      begin
1514
 
1515
         if (pkt_size < 64)
1516
          pause_frame = 0;
1517
         else
1518
          begin
1519
             // get destination address, type, and opcode
1520
             destination_mac_addr[47:40] = pkt_data[7:0];
1521
             destination_mac_addr[39:32] = pkt_data[15:8];
1522
             destination_mac_addr[31:24] = pkt_data[23:16];
1523
             destination_mac_addr[23:16] = pkt_data[31:24];
1524
             destination_mac_addr[15:8]  = pkt_data[39:32];
1525
             destination_mac_addr[7:0]   = pkt_data[47:40];
1526
 
1527
             frame_type[15:8] = pkt_data[103:96];
1528
             frame_type[7:0]  = pkt_data[111:104];
1529
 
1530
             opcode[15:8] = pkt_data[119:112];
1531
             opcode[7:0]  = pkt_data[127:120];
1532
 
1533
             if ((destination_mac_addr == `PAUSE_DEST_MAC) &&
1534
                 (frame_type == `PAUSE_TYPE) &&
1535
                 (opcode == `PAUSE_OPCODE))
1536
              pause_frame = 1;
1537
             else
1538
              pause_frame = 0;
1539
          end // else: !if(packet_size < 64)
1540
      end
1541
   endfunction // pause_frame
1542
 
1543
   function [31:0] get_pause_time; // returns pause parameter from pause frame
1544
      input [511:0] pkt_data;
1545
      begin
1546
         get_pause_time[15:8] = pkt_data[135:128];
1547
         get_pause_time[ 7:0] = pkt_data[143:136];
1548
         get_pause_time[31:16] = 16'd0;
1549
 
1550
      end
1551
   endfunction // get_pause_time
1552
 
1553
task status;
1554
begin
1555
   $display("#############################");
1556
   $display("   TB MII Statistic            ");
1557
   $display(" TB TO DUT :                 ");
1558
   $display("     Frm cnt       : %d  ", transmitted_packet_count);
1559
   $display("     Byte cnt      : %d  ", transmitted_packet_byte_count);
1560
   $display(" DUT TO TB :                  ");
1561
   $display("     Frm cnt       : %d  ", receive_packet_count);
1562
   $display("     Byte cnt      : %d  ", receive_packet_byte_count);
1563
   $display("     Pause Frm  cnt: %d  ", receive_pause_frm_count);
1564
   $display("     Alig Err   cnt: %d  ", receive_alignment_err_count);
1565
   $display("     usized Err cnt: %d  ", receive_undersized_err_count);
1566
   $display("     crc Err    cnt: %d  ", receive_crc_err_count);
1567
   $display("     Length Err cnt: %d  ", receive_length_err_count);
1568
 
1569
   $display("#############################");
1570
 
1571
end
1572
endtask
1573
 
1574
endmodule // tb_mii
1575
 
1576
 
1577
 
1578
 
1579
 
1580
 

powered by: WebSVN 2.1.0

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