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

Subversion Repositories turbo8051

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

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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