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

Subversion Repositories turbo8051

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

powered by: WebSVN 2.1.0

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