OpenCores
URL https://opencores.org/ocsvn/1000base-x/1000base-x/trunk

Subversion Repositories 1000base-x

[/] [1000base-x/] [trunk/] [testbench/] [rtl/] [verilog/] [gmii_rx_model.v] - Blame information for rev 4

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 dwp
//////////////////////////////////////////////////////////////////////
2
////                                                              ////
3
////  File name "gmii_rx_model.v"                                 ////
4
////                                                              ////
5
////  This file is part of the :                                  ////
6
////                                                              ////
7
//// "1000BASE-X IEEE 802.3-2008 Clause 36 - PCS project"         ////
8
////                                                              ////
9
////  http://opencores.org/project,1000base-x                     ////
10
////                                                              ////
11
////  Author(s):                                                  ////
12
////      - D.W.Pegler Cambridge Broadband Networks Ltd           ////
13
////                                                              ////
14
////      { peglerd@gmail.com, dwp@cambridgebroadand.com }        ////
15
////                                                              ////
16
//////////////////////////////////////////////////////////////////////
17
////                                                              ////
18
//// Copyright (C) 2009 AUTHORS. All rights reserved.             ////
19
////                                                              ////
20
//// This source file may be used and distributed without         ////
21
//// restriction provided that this copyright statement is not    ////
22
//// removed from the file and that any derivative work contains  ////
23
//// the original copyright notice and the associated disclaimer. ////
24
////                                                              ////
25
//// This source file is free software; you can redistribute it   ////
26
//// and/or modify it under the terms of the GNU Lesser General   ////
27
//// Public License as published by the Free Software Foundation; ////
28
//// either version 2.1 of the License, or (at your option) any   ////
29
//// later version.                                               ////
30
////                                                              ////
31
//// This source is distributed in the hope that it will be       ////
32
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
33
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
34
//// PURPOSE.  See the GNU Lesser General Public License for more ////
35
//// details.                                                     ////
36
////                                                              ////
37
//// You should have received a copy of the GNU Lesser General    ////
38
//// Public License along with this source; if not, download it   ////
39
//// from http://www.opencores.org/lgpl.shtml                     ////
40
////                                                              ////
41
//////////////////////////////////////////////////////////////////////
42
////                                                              ////
43
////                                                              ////
44
//////////////////////////////////////////////////////////////////////
45
 
46
`include "timescale_tb.v"
47
 
48
module gmii_rx_model #(
49
  parameter DEBUG     = 0,
50
  parameter REDUCED   = 0,
51
  parameter in_delay  = 2
52
)(
53
  interface check_intf,
54
 
55
  input         mii_rxck_in,
56
  input         gmii_rxck_in,
57
  output        mii_rxck_out,
58
 
59
  input [7:0]   rxd,
60
  input         rx_dv,
61
  input         rx_er
62
);
63
 
64
   import tb_utils::hexformat;
65
 
66
   import ethernet_frame::EthernetFrame;
67
   import ethernet_frame::EthernetSpeed;
68
   import ethernet_frame::ETH10;
69
   import ethernet_frame::ETH1000;
70
   import ethernet_frame::ethernet_inter_frame_gap;
71
   import ethernet_frame::ethernet_address_t;
72
   import ethernet_frame::ethernet_preamble_len;
73
   import ethernet_frame::FrameMailBox;
74
   import ethernet_frame::fmt_addr;
75
   import ethernet_frame::ethernet_preamble;
76
   import ethernet_frame::ethernet_sfd;
77
 
78
  wire [7:0] tmp_rxd;
79
  wire       tmp_rx_dv, tmp_rx_er;
80
 
81
   assign #in_delay tmp_rx_dv = rx_dv;
82
   assign #in_delay tmp_rx_er = rx_er;
83
   assign #in_delay tmp_rxd   = rxd;
84
 
85
   EthernetSpeed  speed = ETH1000;
86
 
87
   reg       mii_rxck10baseT;
88
 
89
   wire      rx_clk  = (speed == ETH1000) ? gmii_rxck_in     :
90
                       (speed == ETH10)   ? mii_rxck10baseT : mii_rxck_in ;
91
 
92
   assign mii_rxck_out = (speed == ETH10) ? mii_rxck10baseT : mii_rxck_in;
93
 
94
   FrameMailBox registered_mailboxes[ethernet_address_t];
95
 
96
   int       eth_parity = 0; int  eth_errors = 0;
97
 
98
   virtual   ether_send_intf loopback_intf;
99
 
100
  //----------------------------------------------------------------------------
101
  // Generate 10 baseT rx clock
102
  //----------------------------------------------------------------------------
103
  initial
104
    begin
105
      mii_rxck10baseT <= 0;
106
      while(1)
107
        begin
108
          repeat(5)
109
            @(posedge mii_rxck_in) mii_rxck10baseT <= 1;
110
          repeat(5)
111
            @(posedge mii_rxck_in) mii_rxck10baseT <= 0;
112
        end
113
    end
114
 
115
 
116
  //----------------------------------------------------------------------------
117
  // Check interface functions
118
  //----------------------------------------------------------------------------
119
 
120
  function automatic string check_intf.whoami();
121
    string buffer;
122
    $sformat(buffer, "%m");
123
    return buffer.substr(0, buffer.len()-17);
124
  endfunction
125
 
126
  // Register a mailbox to receive frames from a particular source address.
127
  function automatic void check_intf.register_mailbox(ethernet_address_t sa, FrameMailBox mbx);
128
    $display("%m: Registering a mailbox to address %s", fmt_addr(sa));
129
    registered_mailboxes[sa] = mbx;
130
  endfunction
131
 
132
  // Remove a mailbox.
133
  function automatic void check_intf.unregister_mailbox(ethernet_address_t sa);
134
    registered_mailboxes.delete(sa);
135
  endfunction
136
 
137
  // Set/clear loopback
138
  function automatic void check_intf.enable_loopback(virtual ether_send_intf intf);
139
    loopback_intf = intf;
140
  endfunction
141
 
142
  function automatic void check_intf.set_parity_errors(int parity, int errors);
143
    eth_parity = parity;
144
    eth_errors = errors;
145
  endfunction
146
 
147
  function automatic void check_intf.set_speed(EthernetSpeed m);
148
    speed = m;
149
  endfunction
150
 
151
 
152
   task automatic check_frame(EthernetFrame frame);
153
      ethernet_address_t da;
154
 
155
      if (!frame.check_crc())
156
        begin
157
           $display(" -> Error, CRC incorrect.");
158
           $display(" ->   Received %s", hexformat(frame.get_crc()));
159
           $display(" ->   Expected %s", hexformat(frame.calc_crc()));
160
           return;
161
        end
162
 
163
      da = frame.get_da();
164
 
165
      // Look for a mailbox registered to this address.
166
      if(registered_mailboxes.exists(da))
167
        void'(registered_mailboxes[da].try_put(frame));
168
      else
169
        begin
170
           ethernet_address_t addr;
171
           $display("Warning, no handler registered for Ethernet address %s.", fmt_addr(da));
172
           $display("%0d addresses registered:", registered_mailboxes.num());
173
           for(int ok=registered_mailboxes.first(addr); ok; ok=registered_mailboxes.next(addr))
174
             $display("  %s", fmt_addr(addr));
175
        end
176
   endtask
177
 
178
  //----------------------------------------------------------------------------
179
  // Receive Process.
180
  //----------------------------------------------------------------------------
181
 
182
  task automatic gmii_receive();
183
     EthernetFrame rx_frame;
184
     int odd, prev_dibit;
185
     int nybbles[$];
186
     int raw_frame[$];
187
     int errored;
188
     int preamble_count;
189
     int found_sfd;
190
     int min_gap_symbols;
191
 
192
     int gap = 0;
193
 
194
     if(DEBUG) $display("%m");
195
 
196
     while(tmp_rx_dv !== 1)
197
       begin
198
          gap++;
199
          @(posedge rx_clk);
200
       end
201
 
202
     if(DEBUG) $display("%m: Start of receive frame.");
203
 
204
     min_gap_symbols = (speed==ETH1000) ? ethernet_inter_frame_gap/8 : ethernet_inter_frame_gap/(REDUCED ? 2 : 4);
205
 
206
     if(gap < min_gap_symbols)
207
       $display("%m: Warning, insufficient interframe gap (got %0d symbols, require %0d).", gap, min_gap_symbols);
208
 
209
     // Now grab the frame. We don't attempt to decode it during reception.
210
     nybbles = {};  errored = 0; odd = 0; prev_dibit = 0;
211
 
212
     while(tmp_rx_dv)
213
       begin
214
          if(REDUCED & odd)
215
            begin
216
               nybbles.push_back(((tmp_rxd & 3)<<2) | prev_dibit);
217
 
218
               if(tmp_rx_er) errored = 1;
219
            end
220
          else if(!REDUCED)
221
            begin
222
               nybbles.push_back(tmp_rxd & 'hf);
223
 
224
               if (speed == ETH1000) nybbles.push_back((tmp_rxd>>4) & 'hf);
225
 
226
               if(tmp_rx_er) errored = 1;
227
            end
228
 
229
          prev_dibit = tmp_rxd & 3;
230
          odd = !odd;
231
 
232
          @(posedge rx_clk);
233
       end
234
 
235
    // This will mostly catch collisions, so make it just a warning.
236
    if (errored) begin
237
       $display("%m: Warning, frame contained errors (rx_er detected).");
238
       return;
239
    end
240
 
241
    // Search for the SFD.
242
    preamble_count = 0; found_sfd = 0;
243
 
244
     for (int i=0; i<nybbles.size(); i++)
245
       begin
246
          int nyb = nybbles[i];
247
 
248
          if      (nyb == ethernet_preamble) preamble_count++;
249
          else if (nyb == ethernet_sfd) begin
250
             found_sfd = 1; break;
251
          end
252
          else preamble_count = 0;
253
       end
254
 
255
    if (!found_sfd) begin
256
       $display("%m: Error, SFD not found.");
257
       $display("%s", hexformat(nybbles[0:20], "0x%02x", ","));
258
       return;
259
    end
260
 
261
     if (preamble_count != ethernet_preamble_len) begin
262
        $display("%m: Warning, preamble was %0d nybbles long.", preamble_count);
263
       $stop;
264
    end
265
 
266
    if ((preamble_count<4) || (preamble_count>2*ethernet_preamble_len)) return;
267
 
268
    // Chop off preamble and SFD.
269
    nybbles = nybbles[preamble_count+1:$];
270
 
271
    // Deal with an odd number of nybbles.
272
    if(nybbles.size() & 1)
273
      begin
274
        nybbles.push_back(0);
275
        $display("%m: Warning, frame contained an odd number of nybbles.");
276
      end
277
 
278
    // Convert frame to bytes:
279
    raw_frame = {};
280
 
281
     for (int i=0; i<nybbles.size(); i+=2)
282
       raw_frame.push_back(nybbles[i] | (nybbles[i+1]<<4));
283
 
284
    if (raw_frame.size() < ethernet_frame::ethernet_min_frame_size)
285
      begin
286
         // This will mostly catch collisions, so make it just a warning.
287
         $display("%m: Warning, frame too small. (%0d bytes).", raw_frame.size());
288
         $display("%m: Raw received frame:");
289
         $display("%s", hexformat(raw_frame, "0x%01x", ","));
290
         return;
291
      end
292
 
293
    if(DEBUG>1)
294
      begin
295
        $display("%m: Raw received frame:");
296
        $display("%s", hexformat(raw_frame, "0x%01x", ","));
297
      end
298
 
299
    rx_frame = new(.initraw(raw_frame));
300
 
301
    if (loopback_intf)
302
      begin
303
         // Swap around dst and src MAC addresses
304
         ethernet_address_t sa = rx_frame.get_sa();
305
 
306
         rx_frame.set_sa(rx_frame.get_da()); rx_frame.set_da(sa);
307
 
308
        // Retransmit frame.
309
        loopback_intf.queue_frame(rx_frame);
310
      end
311
    else
312
      check_frame(rx_frame);
313
 
314
  endtask
315
 
316
  always
317
    gmii_receive();
318
 
319
endmodule
320
 
321
 

powered by: WebSVN 2.1.0

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