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

Subversion Repositories turbo8051

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

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

powered by: WebSVN 2.1.0

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