File: eth_ipv4_chdr64_adapter.v

package info (click to toggle)
uhd 4.9.0.0%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 184,180 kB
  • sloc: cpp: 262,887; python: 112,011; ansic: 102,670; vhdl: 57,031; tcl: 19,924; xml: 8,581; makefile: 3,028; sh: 2,812; pascal: 230; javascript: 120; csh: 94; asm: 20; perl: 11
file content (401 lines) | stat: -rw-r--r-- 15,306 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
//
// Copyright 2019 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: eth_ipv4_chdr64_adapter
// Description: A generic transport adapter module that can be used in
//   a veriety of transports. It does the following:
//   - Exposes a configuration port for mgmt packets to configure the node
//   - Implements a return-address map for packets with metadata other than
//     the CHDR. Additional metadata can be passed as a tuser to this module
//     which will store it in a map indexed by the SrcEPID in a management
//     packet. For all returning packets, the metadata will be looked up in
//     the map and attached as the outgoing tuser.
//   - Implements a loopback path for node-info discovery
//
// Parameters:
//   - PROTOVER: RFNoC protocol version {8'd<major>, 8'd<minor>}
//   - MTU: Log2 of the MTU of the packet in 64-bit words
//   - CPU_FIFO_SIZE: Log2 of the FIFO depth (in 64-bit words) for the CPU egress path
//   - RT_TBL_SIZE: Log2 of the depth of the return-address routing table
//   - NODE_INST: The node type to return for a node-info discovery
//   - DROP_UNKNOWN_MAC: Drop packets not addressed to us?
//
// Signals:
//   - device_id : The ID of the device that has instantiated this module
//   - s_mac_*: The input Ethernet stream from the MAC (plus tuser for trailing bytes + err)
//   - m_mac_*: The output Ethernet stream to the MAC (plus tuser for trailing bytes + err)
//   - s_chdr_*: The input CHDR stream from the rfnoc infrastructure
//   - m_chdr_*: The output CHDR stream to the rfnoc infrastructure
//   - s_cpu_*: The input Ethernet stream from the CPU (plus tuser for trailing bytes + err)
//   - m_cpu_*: The output Ethernet stream to the CPU (plus tuser for trailing bytes + err)
//   - my_eth_addr: The Ethernet (MAC) address of this endpoint
//   - my_ipv4_addr: The IPv4 address of this endpoint
//   - my_udp_chdr_port: The UDP port allocated for CHDR traffic on this endpoint
//

`default_nettype none
module eth_ipv4_chdr64_adapter #(
  parameter [15:0] PROTOVER         = {8'd1, 8'd0},
  parameter        MTU              = 10,
  parameter        CPU_FIFO_SIZE    = MTU,
  parameter        RT_TBL_SIZE      = 6,
  parameter        NODE_INST        = 0,
  parameter [0:0]  DROP_UNKNOWN_MAC = 1,
  parameter [0:0]  IS_CPU_ARM       = 0
)(
  // Clocking and reset interface
  input  wire        clk,
  input  wire        rst,
  // Device info
  input  wire [15:0] device_id,
  // AXI-Stream interface to/from MAC
  input  wire [63:0] s_mac_tdata,
  input  wire [3:0]  s_mac_tuser,
  input  wire        s_mac_tlast,
  input  wire        s_mac_tvalid,
  output wire        s_mac_tready,
  output wire [63:0] m_mac_tdata,
  output wire [3:0]  m_mac_tuser,
  output wire        m_mac_tlast,
  output wire        m_mac_tvalid,
  input  wire        m_mac_tready,
  // AXI-Stream interface to/from CHDR infrastructure
  input  wire [63:0] s_chdr_tdata,
  input  wire        s_chdr_tlast,
  input  wire        s_chdr_tvalid,
  output wire        s_chdr_tready,
  output wire [63:0] m_chdr_tdata,
  output wire        m_chdr_tlast,
  output wire        m_chdr_tvalid,
  input  wire        m_chdr_tready,
  // AXI-Stream interface to/from CPU
  input  wire [63:0] s_cpu_tdata,
  input  wire [3:0]  s_cpu_tuser,
  input  wire        s_cpu_tlast,
  input  wire        s_cpu_tvalid,
  output wire        s_cpu_tready,
  output wire [63:0] m_cpu_tdata,
  output wire [3:0]  m_cpu_tuser,
  output wire        m_cpu_tlast,
  output wire        m_cpu_tvalid,
  input  wire        m_cpu_tready,
  // Device addresses
  input  wire [47:0] my_eth_addr,
  input  wire [31:0] my_ipv4_addr,
  input  wire [15:0] my_udp_chdr_port
);

  `include "../core/rfnoc_chdr_utils.vh"
  `include "../core/rfnoc_chdr_internal_utils.vh"
  `include "rfnoc_xport_types.vh"

  //-----------------------------------------------------------------------
  // Byte-swapping function
  // Ethernet fields we wrote out left-to-right, but AXI-Stream time-orders
  // its data right-to-left.
  //-----------------------------------------------------------------------
  function [63:0] bswap64(
    input  [63:0] din
  );
    begin
      bswap64 = {din[0 +: 8], din[8 +: 8], din[16 +: 8], din[24 +: 8],
                 din[32+: 8], din[40+: 8], din[48 +: 8], din[56 +: 8]};
    end
  endfunction

  //---------------------------------------
  // E2X and E2C DEMUX
  //---------------------------------------
  wire [63:0] e2x_chdr_tdata;
  wire [95:0] e2x_chdr_tuser;
  wire        e2x_chdr_tlast, e2x_chdr_tvalid, e2x_chdr_tready;
  wire [63:0] e2c_chdr_tdata;
  wire [3:0]  e2c_chdr_tuser;
  wire        e2c_chdr_tlast, e2c_chdr_tvalid, e2c_chdr_tready;

  // Ethernet sink. Inspects packet and dispatches
  // to the correct port.
  eth_ipv4_chdr64_dispatch #(
    .DROP_UNKNOWN_MAC(DROP_UNKNOWN_MAC)
  ) eth_dispatch_i (
    .clk              (clk),
    .rst              (rst),
    .s_mac_tdata      (s_mac_tdata),
    .s_mac_tuser      (s_mac_tuser),
    .s_mac_tlast      (s_mac_tlast),
    .s_mac_tvalid     (s_mac_tvalid),
    .s_mac_tready     (s_mac_tready),
    .m_chdr_tdata     (e2x_chdr_tdata),
    .m_chdr_tuser     (e2x_chdr_tuser),
    .m_chdr_tlast     (e2x_chdr_tlast),
    .m_chdr_tvalid    (e2x_chdr_tvalid),
    .m_chdr_tready    (e2x_chdr_tready),
    .m_cpu_tdata      (e2c_chdr_tdata),
    .m_cpu_tuser      (e2c_chdr_tuser),
    .m_cpu_tlast      (e2c_chdr_tlast),
    .m_cpu_tvalid     (e2c_chdr_tvalid),
    .m_cpu_tready     (e2c_chdr_tready),
    .my_eth_addr      (my_eth_addr),
    .my_ipv4_addr     (my_ipv4_addr),
    .my_udp_chdr_port (my_udp_chdr_port)
  );

  //---------------------------------------
  // CHDR Transport Adapter
  //---------------------------------------

  wire [63:0] x2e_chdr_tdata;
  wire [95:0] x2e_chdr_tuser;
  wire        x2e_chdr_tlast, x2e_chdr_tvalid, x2e_chdr_tready;
  wire [63:0] e2x_fifo_tdata;
  wire        e2x_fifo_tlast, e2x_fifo_tvalid, e2x_fifo_tready;
  wire [63:0] e2c_fifo_tdata;
  wire [3:0]  e2c_fifo_tuser;
  wire        e2c_fifo_tlast, e2c_fifo_tvalid, e2c_fifo_tready;

  chdr_xport_adapter_generic #(
    .PROTOVER     (PROTOVER),
    .CHDR_W       (64),
    .USER_W       (96),
    .TBL_SIZE     (RT_TBL_SIZE),
    .NODE_SUBTYPE (NODE_SUBTYPE_XPORT_IPV4_CHDR64),
    .NODE_INST    (NODE_INST),
    .ALLOW_DISC   (1)
  ) xport_adapter_gen_i (
    .clk                 (clk),
    .rst                 (rst),
    .device_id           (device_id),
    .s_axis_xport_tdata  (e2x_chdr_tdata),
    .s_axis_xport_tuser  (e2x_chdr_tuser),
    .s_axis_xport_tlast  (e2x_chdr_tlast),
    .s_axis_xport_tvalid (e2x_chdr_tvalid),
    .s_axis_xport_tready (e2x_chdr_tready),
    .m_axis_xport_tdata  (x2e_chdr_tdata),
    .m_axis_xport_tuser  (x2e_chdr_tuser),
    .m_axis_xport_tlast  (x2e_chdr_tlast),
    .m_axis_xport_tvalid (x2e_chdr_tvalid),
    .m_axis_xport_tready (x2e_chdr_tready),
    .s_axis_rfnoc_tdata  (s_chdr_tdata),
    .s_axis_rfnoc_tlast  (s_chdr_tlast),
    .s_axis_rfnoc_tvalid (s_chdr_tvalid),
    .s_axis_rfnoc_tready (s_chdr_tready),
    .m_axis_rfnoc_tdata  (e2x_fifo_tdata),
    .m_axis_rfnoc_tlast  (e2x_fifo_tlast),
    .m_axis_rfnoc_tvalid (e2x_fifo_tvalid),
    .m_axis_rfnoc_tready (e2x_fifo_tready),
    .ctrlport_req_wr     (/* unused */),
    .ctrlport_req_rd     (/* unused */),
    .ctrlport_req_addr   (/* unused */),
    .ctrlport_req_data   (/* unused */),
    .ctrlport_resp_ack   (/* unused */),
    .ctrlport_resp_data  (/* unused */)
  );

  generate
    if (IS_CPU_ARM == 1'b1) begin
      //---------------------------------------
      // Ethernet framer for ARM
      //---------------------------------------

      // Strip the 6 octet ethernet padding we used internally
      // before sending to ARM.
      // Put SOF into bit[3] of tuser.
      axi64_to_xge64 arm_framer (
        .clk(clk),
        .reset(rst),
        .clear(1'b0),
        .s_axis_tdata(e2c_chdr_tdata),
        .s_axis_tuser(e2c_chdr_tuser),
        .s_axis_tlast(e2c_chdr_tlast),
        .s_axis_tvalid(e2c_chdr_tvalid),
        .s_axis_tready(e2c_chdr_tready),
        .m_axis_tdata(e2c_fifo_tdata),
        .m_axis_tuser(e2c_fifo_tuser),
        .m_axis_tlast(e2c_fifo_tlast),
        .m_axis_tvalid(e2c_fifo_tvalid),
        .m_axis_tready(e2c_fifo_tready)
      );
    end else begin
      assign e2c_fifo_tdata  = e2c_chdr_tdata;
      assign e2c_fifo_tuser  = e2c_chdr_tuser;
      assign e2c_fifo_tlast  = e2c_chdr_tlast;
      assign e2c_fifo_tvalid = e2c_chdr_tvalid;
      assign e2c_chdr_tready = e2c_fifo_tready;
    end
  endgenerate

  //---------------------------------------
  // E2X and E2C Output Buffering
  //---------------------------------------

  // The CPU can be slow to respond (relative to packet wirespeed) so
  // extra buffer for packets destined there so it doesn't back up.
  axi_fifo #(
    .WIDTH(64+4+1),.SIZE(CPU_FIFO_SIZE)
  ) cpu_fifo_i (
    .clk(clk), .reset(rst), .clear(1'b0),
    .i_tdata({e2c_fifo_tlast, e2c_fifo_tuser, e2c_fifo_tdata}),
    .i_tvalid(e2c_fifo_tvalid), .i_tready(e2c_fifo_tready),
    .o_tdata({m_cpu_tlast, m_cpu_tuser, m_cpu_tdata}),
    .o_tvalid(m_cpu_tvalid), .o_tready(m_cpu_tready),
    .occupied(), .space()
  );

  // The transport should hook up to a crossbar downstream, which
  // may backpressure this module because it is in the middle of
  // transferring a packet. To ensure that upstream logic is not
  // blocked, we instantiate one packet worth of buffering here.
  axi_fifo #(
    .WIDTH(64+1),.SIZE(MTU)
  ) chdr_fifo_i (
    .clk(clk), .reset(rst), .clear(1'b0),
    .i_tdata({e2x_fifo_tlast, e2x_fifo_tdata}),
    .i_tvalid(e2x_fifo_tvalid), .i_tready(e2x_fifo_tready),
    .o_tdata({m_chdr_tlast, m_chdr_tdata}),
    .o_tvalid(m_chdr_tvalid), .o_tready(m_chdr_tready),
    .occupied(), .space()
  );

  //---------------------------------------
  // Ethernet Framer for X2E
  //---------------------------------------
  wire [63:0] x2e_framed_tdata;
  wire [3:0]  x2e_framed_tuser;
  wire        x2e_framed_tlast, x2e_framed_tvalid, x2e_framed_tready;

  localparam [2:0] ST_IDLE           = 3'd0;
  localparam [2:0] ST_ETH_L0         = 3'd1;
  localparam [2:0] ST_ETH_L1         = 3'd2;
  localparam [2:0] ST_ETH_L2_IPV4_L0 = 3'd3;
  localparam [2:0] ST_IPV4_L1        = 3'd4;
  localparam [2:0] ST_IPV4_L2        = 3'd5;
  localparam [2:0] ST_IPV4_UDP_HDR   = 3'd6;
  localparam [2:0] ST_CHDR_PAYLOAD   = 3'd7;

  reg [2:0]  frame_state = ST_IDLE;
  reg [15:0] chdr_len = 16'd0;
  reg [63:0] frame_tdata;

  always @(posedge clk) begin
    if(rst) begin
      frame_state <= ST_IDLE;
      chdr_len <= 16'd0;
    end else begin
      case(frame_state)
        ST_IDLE: begin
          if (x2e_chdr_tvalid) begin
            frame_state <= ST_ETH_L0;
            chdr_len <= chdr_get_length(x2e_chdr_tdata);
          end
        end
        ST_CHDR_PAYLOAD: begin
          if (x2e_chdr_tvalid & x2e_framed_tready)
            if (x2e_chdr_tlast)
              frame_state <= ST_IDLE;
        end
        default: begin
          if(x2e_framed_tready)
            frame_state <= frame_state + 3'd1;
        end
      endcase
    end
  end

  assign x2e_chdr_tready = (frame_state == ST_CHDR_PAYLOAD) ? x2e_framed_tready : 1'b0;
  assign x2e_framed_tvalid = (frame_state == ST_CHDR_PAYLOAD) ? x2e_chdr_tvalid : (frame_state == ST_IDLE) ? 1'b0 : 1'b1;
  assign x2e_framed_tlast = (frame_state == ST_CHDR_PAYLOAD) ? x2e_chdr_tlast : 1'b0;
  assign x2e_framed_tuser = ((frame_state == ST_CHDR_PAYLOAD) & x2e_chdr_tlast) ? {1'b0, chdr_len[2:0]} : 4'b0000;
  assign x2e_framed_tdata = frame_tdata;

  wire [47:0] pad = 48'h0;
  wire [47:0] mac_dst = x2e_chdr_tuser[47:0];   // Extract from router lookup results
  wire [15:0] eth_type = 16'h0800;  // IPv4
  wire [15:0] misc_ip = { 4'd4 /* IPv4 */, 4'd5 /* IP HDR Len */, 8'h00 /* DSCP and ECN */};
  wire [15:0] ip_len = (16'd28 + chdr_len);  // 20 for IP, 8 for UDP
  wire [15:0] ident = 16'h0;
  wire [15:0] flag_frag = { 3'b010 /* don't fragment */, 13'h0 };
  wire [15:0] ttl_prot = { 8'h10 /* TTL */, 8'h11 /* UDP */ };
  wire [15:0] iphdr_checksum;
  wire [31:0] ip_dst = x2e_chdr_tuser[79:48];   // Extract from router lookup results
  wire [15:0] udp_dst = x2e_chdr_tuser[95:80];  // Extract from router lookup results
  wire [15:0] udp_len = (16'd8 + chdr_len);
  wire [15:0] udp_checksum = 16'h0;

  ip_hdr_checksum ip_hdr_checksum (
    .clk(clk), .in({misc_ip, ip_len, ident, flag_frag, ttl_prot, 16'd0,
    my_ipv4_addr, ip_dst}), .clken(1'b1), .out(iphdr_checksum)
  );

  always @(*) begin
    case(frame_state)
      ST_ETH_L0         : frame_tdata <= bswap64({pad[47:0], mac_dst[47:32]});
      ST_ETH_L1         : frame_tdata <= bswap64({mac_dst[31:0], my_eth_addr[47:16]});
      ST_ETH_L2_IPV4_L0 : frame_tdata <= bswap64({my_eth_addr[15:0], eth_type[15:0], misc_ip[15:0], ip_len[15:0]});
      ST_IPV4_L1        : frame_tdata <= bswap64({ident[15:0], flag_frag[15:0], ttl_prot[15:0], iphdr_checksum[15:0]});
      ST_IPV4_L2        : frame_tdata <= bswap64({my_ipv4_addr[31:0], ip_dst[31:0]});
      ST_IPV4_UDP_HDR   : frame_tdata <= bswap64({my_udp_chdr_port[15:0], udp_dst[15:0], udp_len[15:0], udp_checksum[15:0]});
      default           : frame_tdata <= x2e_chdr_tdata;
    endcase
  end

  wire [63:0] c2e_tdata;
  wire [3:0]  c2e_tuser;
  wire        c2e_tlast;
  wire        c2e_tvalid;
  wire        c2e_tready;

  generate
    if (IS_CPU_ARM == 1'b1) begin
      //---------------------------------------
      // Ethernet deframer for ARM
      //---------------------------------------

      // Add pad of 6 empty bytes to the ethernet packet going from the CPU to the
      // SFP. This padding added before MAC addresses aligns the source and
      // destination IP addresses, UDP headers etc.
      // Note that the xge_mac_wrapper strips this padding to recreate the ethernet
      // packet
      arm_deframer inst_arm_deframer
      (
        .clk(clk),
        .reset(rst),
        .clear(1'b0),

        .s_axis_tdata(s_cpu_tdata),
        .s_axis_tuser(s_cpu_tuser),
        .s_axis_tlast(s_cpu_tlast),
        .s_axis_tvalid(s_cpu_tvalid),
        .s_axis_tready(s_cpu_tready),

        .m_axis_tdata(c2e_tdata),
        .m_axis_tuser(c2e_tuser),
        .m_axis_tlast(c2e_tlast),
        .m_axis_tvalid(c2e_tvalid),
        .m_axis_tready(c2e_tready)
      );
    end else begin
      assign c2e_tdata    = s_cpu_tdata;
      assign c2e_tuser    = s_cpu_tuser;
      assign c2e_tlast    = s_cpu_tlast;
      assign c2e_tvalid   = s_cpu_tvalid;
      assign s_cpu_tready = c2e_tready;
    end
  endgenerate

  //---------------------------------------
  // X2E and C2E MUX
  //---------------------------------------
  axi_mux #(
    .SIZE(2), .PRIO(0), .WIDTH(64+4), .PRE_FIFO_SIZE(0), .POST_FIFO_SIZE(1)
  ) eth_mux_i (
    .clk(clk), .reset(rst), .clear(1'b0),
    .i_tdata({c2e_tuser, c2e_tdata, x2e_framed_tuser, x2e_framed_tdata}), .i_tlast({c2e_tlast, x2e_framed_tlast}),
    .i_tvalid({c2e_tvalid, x2e_framed_tvalid}), .i_tready({c2e_tready, x2e_framed_tready}),
    .o_tdata({m_mac_tuser, m_mac_tdata}), .o_tlast(m_mac_tlast),
    .o_tvalid(m_mac_tvalid), .o_tready(m_mac_tready)
  );

endmodule // eth_ipv4_chdr64_adapter
`default_nettype wire