1///////////////////////////////////////////////////////////////////
2//
3// Copyright 2019 Ettus Research, a National Instruments brand
4//
5// SPDX-License-Identifier: LGPL-3.0-or-later
6//
7// Module: eth_internal
8// Description:
9//   Reduces clutter at top level.
10//   - FPGA-internal Ethernet port
11//   - ARP responder instead of other CPU connection
12//
13//////////////////////////////////////////////////////////////////////
14
15`default_nettype none
16module eth_internal #(
17  parameter        DWIDTH       = 32,
18  parameter        AWIDTH       = 14,
19  parameter [7:0]  PORTNUM      = 0,
20  parameter [15:0] RFNOC_PROTOVER  = {8'd1, 8'd0}
21)(
22  // Resets
23  input wire        bus_rst,
24
25  // Clocks
26  input wire        bus_clk,
27
28  //Axi-lite
29  input  wire                s_axi_aclk,
30  input  wire                s_axi_aresetn,
31  input  wire [AWIDTH-1:0]   s_axi_awaddr,
32  input  wire                s_axi_awvalid,
33  output wire                s_axi_awready,
34
35  input  wire [DWIDTH-1:0]   s_axi_wdata,
36  input  wire [DWIDTH/8-1:0] s_axi_wstrb,
37  input  wire                s_axi_wvalid,
38  output wire                s_axi_wready,
39
40  output wire [1:0]          s_axi_bresp,
41  output wire                s_axi_bvalid,
42  input  wire                s_axi_bready,
43
44  input  wire [AWIDTH-1:0]   s_axi_araddr,
45  input  wire                s_axi_arvalid,
46  output wire                s_axi_arready,
47
48  output wire [DWIDTH-1:0]   s_axi_rdata,
49  output wire [1:0]          s_axi_rresp,
50  output wire                s_axi_rvalid,
51  input  wire                s_axi_rready,
52
53  // Host-Ethernet DMA interface
54  output wire [63:0]  e2h_tdata,
55  output wire [7:0]   e2h_tkeep,
56  output wire         e2h_tlast,
57  output wire         e2h_tvalid,
58  input  wire         e2h_tready,
59
60  input  wire [63:0]  h2e_tdata,
61  input  wire [7:0]   h2e_tkeep,
62  input  wire         h2e_tlast,
63  input  wire         h2e_tvalid,
64  output wire         h2e_tready,
65
66  // RFNoC interface
67  output wire [63:0]  e2v_tdata,
68  output wire         e2v_tlast,
69  output wire         e2v_tvalid,
70  input  wire         e2v_tready,
71
72  input  wire [63:0]  v2e_tdata,
73  input  wire         v2e_tlast,
74  input  wire         v2e_tvalid,
75  output wire         v2e_tready,
76
77  // MISC
78  output wire  [31:0] port_info,
79  input  wire  [15:0] device_id,
80
81  output wire         link_up,
82  output reg          activity
83
84);
85
86  localparam REG_BASE_ETH_IO      = 14'h0;
87  localparam REG_BASE_ETH_SWITCH  = 14'h1000;
88
89  // AXI4-Lite to RegPort (PS to PL Register Access)
90  wire                reg_wr_req;
91  wire  [AWIDTH-1:0]  reg_wr_addr;
92  wire  [DWIDTH-1:0]  reg_wr_data;
93  wire                reg_rd_req;
94  wire  [AWIDTH-1:0]  reg_rd_addr;
95  wire                reg_rd_resp, reg_rd_resp_eth_if;
96  reg                 reg_rd_resp_io = 1'b0;
97  wire  [DWIDTH-1:0]  reg_rd_data, reg_rd_data_eth_if;
98  reg   [DWIDTH-1:0]  reg_rd_data_io = 'd0;
99
100  axil_regport_master #(
101    .DWIDTH         (DWIDTH),   // Width of the AXI4-Lite data bus (must be 32 or 64)
102    .AWIDTH         (AWIDTH),   // Width of the address bus
103    .WRBASE         (0),        // Write address base
104    .RDBASE         (0),        // Read address base
105    .TIMEOUT        (10)        // log2(timeout). Read will timeout after (2^TIMEOUT - 1) cycles
106  ) eth_dma_reg_mst_i (
107    // Clock and reset
108    .s_axi_aclk     (s_axi_aclk),
109    .s_axi_aresetn  (s_axi_aresetn),
110    // AXI4-Lite: Write address port (domain: s_axi_aclk)
111    .s_axi_awaddr   (s_axi_awaddr),
112    .s_axi_awvalid  (s_axi_awvalid),
113    .s_axi_awready  (s_axi_awready),
114    // AXI4-Lite: Write data port (domain: s_axi_aclk)
115    .s_axi_wdata    (s_axi_wdata),
116    .s_axi_wstrb    (s_axi_wstrb),
117    .s_axi_wvalid   (s_axi_wvalid),
118    .s_axi_wready   (s_axi_wready),
119    // AXI4-Lite: Write response port (domain: s_axi_aclk)
120    .s_axi_bresp    (s_axi_bresp),
121    .s_axi_bvalid   (s_axi_bvalid),
122    .s_axi_bready   (s_axi_bready),
123    // AXI4-Lite: Read address port (domain: s_axi_aclk)
124    .s_axi_araddr   (s_axi_araddr),
125    .s_axi_arvalid  (s_axi_arvalid),
126    .s_axi_arready  (s_axi_arready),
127    // AXI4-Lite: Read data port (domain: s_axi_aclk)
128    .s_axi_rdata    (s_axi_rdata),
129    .s_axi_rresp    (s_axi_rresp),
130    .s_axi_rvalid   (s_axi_rvalid),
131    .s_axi_rready   (s_axi_rready),
132    // Register port: Write port (domain: reg_clk)
133    .reg_clk        (bus_clk),
134    .reg_wr_req     (reg_wr_req),
135    .reg_wr_addr    (reg_wr_addr),
136    .reg_wr_data    (reg_wr_data),
137    // Register port: Read port (domain: reg_clk)
138    .reg_rd_req     (reg_rd_req),
139    .reg_rd_addr    (reg_rd_addr),
140    .reg_rd_resp    (reg_rd_resp),
141    .reg_rd_data    (reg_rd_data)
142  );
143
144  // Regport Mux for response
145  regport_resp_mux #(
146    .WIDTH      (DWIDTH),
147    .NUM_SLAVES (2)
148  ) reg_resp_mux_i (
149    .clk(bus_clk), .reset(bus_rst),
150    .sla_rd_resp({reg_rd_resp_eth_if, reg_rd_resp_io}),
151    .sla_rd_data({reg_rd_data_eth_if, reg_rd_data_io}),
152    .mst_rd_resp(reg_rd_resp), .mst_rd_data(reg_rd_data)
153  );
154
155  // ARP responder
156  wire [63:0] e2c_tdata;
157  wire [7:0]  e2c_tkeep;
158  wire        e2c_tlast;
159  wire        e2c_tvalid;
160  wire        e2c_tready;
161
162  wire [63:0] c2e_tdata;
163  wire [7:0]  c2e_tkeep;
164  wire        c2e_tlast;
165  wire        c2e_tvalid;
166  wire        c2e_tready;
167
168  wire [3:0] e2c_tuser;
169  wire [3:0] c2e_tuser;
170
171  // ARM Host-to-Ethernet
172  wire [3:0] e2h_tuser;
173  wire [3:0] h2e_tuser;
174
175  // Host Ethernet-to-CHDR
176  wire [63:0] h2e_chdr_tdata;
177  wire [3:0]  h2e_chdr_tuser;
178  wire        h2e_chdr_tlast;
179  wire        h2e_chdr_tvalid;
180  wire        h2e_chdr_tready;
181  wire [63:0] e2h_chdr_tdata;
182  wire [3:0]  e2h_chdr_tuser;
183  wire        e2h_chdr_tlast;
184  wire        e2h_chdr_tvalid;
185  wire        e2h_chdr_tready;
186
187
188  // In AXI Stream, tkeep is the byte qualifier that indicates
189  // whether the content of the associated byte
190  // of TDATA is processed as part of the data stream.
191  // tuser as used in eth_interface is the number of valid bytes
192
193  // Converting tuser to tkeep for ingress packets
194  assign e2c_tkeep = ~e2c_tlast ? 8'b1111_1111
195                   : (e2c_tuser == 4'd0) ? 8'b1111_1111
196                   : (e2c_tuser == 4'd1) ? 8'b0000_0001
197                   : (e2c_tuser == 4'd2) ? 8'b0000_0011
198                   : (e2c_tuser == 4'd3) ? 8'b0000_0111
199                   : (e2c_tuser == 4'd4) ? 8'b0000_1111
200                   : (e2c_tuser == 4'd5) ? 8'b0001_1111
201                   : (e2c_tuser == 4'd6) ? 8'b0011_1111
202                   : 8'b0111_1111;
203
204  // Converting tkeep to tuser for egress packets
205  assign c2e_tuser = ~c2e_tlast ? 4'd0
206                   : (c2e_tkeep == 8'b1111_1111) ? 4'd0
207                   : (c2e_tkeep == 8'b0111_1111) ? 4'd7
208                   : (c2e_tkeep == 8'b0011_1111) ? 4'd6
209                   : (c2e_tkeep == 8'b0001_1111) ? 4'd5
210                   : (c2e_tkeep == 8'b0000_1111) ? 4'd4
211                   : (c2e_tkeep == 8'b0000_0111) ? 4'd3
212                   : (c2e_tkeep == 8'b0000_0011) ? 4'd2
213                   : (c2e_tkeep == 8'b0000_0001) ? 4'd1
214                   : 4'd0;
215
216  // Converting tuser to tkeep for ingress packets
217  assign e2h_tkeep = ~e2h_tlast ? 8'b1111_1111
218                   : (e2h_tuser == 4'd0) ? 8'b1111_1111
219                   : (e2h_tuser == 4'd1) ? 8'b0000_0001
220                   : (e2h_tuser == 4'd2) ? 8'b0000_0011
221                   : (e2h_tuser == 4'd3) ? 8'b0000_0111
222                   : (e2h_tuser == 4'd4) ? 8'b0000_1111
223                   : (e2h_tuser == 4'd5) ? 8'b0001_1111
224                   : (e2h_tuser == 4'd6) ? 8'b0011_1111
225                   : 8'b0111_1111;
226
227  // Converting tkeep to tuser for egress packets
228  assign h2e_tuser = ~h2e_tlast ? 4'd0
229                   : (h2e_tkeep == 8'b1111_1111) ? 4'd0
230                   : (h2e_tkeep == 8'b0111_1111) ? 4'd7
231                   : (h2e_tkeep == 8'b0011_1111) ? 4'd6
232                   : (h2e_tkeep == 8'b0001_1111) ? 4'd5
233                   : (h2e_tkeep == 8'b0000_1111) ? 4'd4
234                   : (h2e_tkeep == 8'b0000_0111) ? 4'd3
235                   : (h2e_tkeep == 8'b0000_0011) ? 4'd2
236                   : (h2e_tkeep == 8'b0000_0001) ? 4'd1
237                   : 4'd0;
238
239  // FPGA-side addresses for the ARP responder
240  wire [47:0] my_mac;
241  wire [31:0] my_ip;
242  wire [15:0] my_udp_port;
243
244  arm_deframer arm_deframer_i (
245    .clk(bus_clk),
246    .reset(bus_rst),
247    .clear(1'b0),
248    .s_axis_tdata(h2e_tdata),
249    .s_axis_tuser(h2e_tuser),
250    .s_axis_tlast(h2e_tlast),
251    .s_axis_tvalid(h2e_tvalid),
252    .s_axis_tready(h2e_tready),
253    .m_axis_tdata(h2e_chdr_tdata),
254    .m_axis_tuser(h2e_chdr_tuser),
255    .m_axis_tlast(h2e_chdr_tlast),
256    .m_axis_tvalid(h2e_chdr_tvalid),
257    .m_axis_tready(h2e_chdr_tready)
258  );
259
260  axi64_to_xge64 arm_framer (
261    .clk(bus_clk),
262    .reset(bus_rst),
263    .clear(1'b0),
264    .s_axis_tdata(e2h_chdr_tdata),
265    .s_axis_tuser(e2h_chdr_tuser),
266    .s_axis_tlast(e2h_chdr_tlast),
267    .s_axis_tvalid(e2h_chdr_tvalid),
268    .s_axis_tready(e2h_chdr_tready),
269    .m_axis_tdata(e2h_tdata),
270    .m_axis_tuser(e2h_tuser),
271    .m_axis_tlast(e2h_tlast),
272    .m_axis_tvalid(e2h_tvalid),
273    .m_axis_tready(e2h_tready)
274  );
275
276  eth_interface #(
277     .PROTOVER(RFNOC_PROTOVER),
278     .MTU(10),
279     .NODE_INST(0),
280     .REG_AWIDTH (AWIDTH),
281     .BASE(REG_BASE_ETH_SWITCH)
282  ) eth_interface (
283    .clk           (bus_clk),
284    .reset         (bus_rst),
285    .device_id     (device_id),
286    .reg_wr_req    (reg_wr_req),
287    .reg_wr_addr   (reg_wr_addr),
288    .reg_wr_data   (reg_wr_data),
289    .reg_rd_req    (reg_rd_req),
290    .reg_rd_addr   (reg_rd_addr),
291    .reg_rd_resp   (reg_rd_resp_eth_if),
292    .reg_rd_data   (reg_rd_data_eth_if),
293    .my_mac        (my_mac),
294    .my_ip         (my_ip),
295    .my_udp_port   (my_udp_port),
296    .eth_tx_tdata  (e2h_chdr_tdata),
297    .eth_tx_tuser  (e2h_chdr_tuser),
298    .eth_tx_tlast  (e2h_chdr_tlast),
299    .eth_tx_tvalid (e2h_chdr_tvalid),
300    .eth_tx_tready (e2h_chdr_tready),
301    .eth_rx_tdata  (h2e_chdr_tdata),
302    .eth_rx_tuser  (h2e_chdr_tuser),
303    .eth_rx_tlast  (h2e_chdr_tlast),
304    .eth_rx_tvalid (h2e_chdr_tvalid),
305    .eth_rx_tready (h2e_chdr_tready),
306    .e2v_tdata     (e2v_tdata),
307    .e2v_tlast     (e2v_tlast),
308    .e2v_tvalid    (e2v_tvalid),
309    .e2v_tready    (e2v_tready),
310    .v2e_tdata     (v2e_tdata),
311    .v2e_tlast     (v2e_tlast),
312    .v2e_tvalid    (v2e_tvalid),
313    .v2e_tready    (v2e_tready),
314    .e2c_tdata     (e2c_tdata),
315    .e2c_tuser     (e2c_tuser),
316    .e2c_tlast     (e2c_tlast),
317    .e2c_tvalid    (e2c_tvalid),
318    .e2c_tready    (e2c_tready),
319    .c2e_tdata     (c2e_tdata),
320    .c2e_tuser     (c2e_tuser),
321    .c2e_tlast     (c2e_tlast),
322    .c2e_tvalid    (c2e_tvalid),
323    .c2e_tready    (c2e_tready)
324  );
325
326  arp_responder arp_responder_i (
327    .aclk          (bus_clk),
328    .aresetn       (~bus_rst),
329    .mac_addr      (my_mac),
330    .ip_addr       (my_ip),
331    .s_axis_tdata  (e2c_tdata),
332    .s_axis_tvalid (e2c_tvalid),
333    .s_axis_tready (e2c_tready),
334    .s_axis_tkeep  (e2c_tkeep),
335    .s_axis_tlast  (e2c_tlast),
336    .s_axis_tuser  (1'b0),
337    .m_axis_tdata  (c2e_tdata),
338    .m_axis_tvalid (c2e_tvalid),
339    .m_axis_tready (c2e_tready),
340    .m_axis_tkeep  (c2e_tkeep),
341    .m_axis_tlast  (c2e_tlast),
342    .m_axis_tuser  ()
343  );
344
345  //-----------------------------------------------------------------
346  // "I/O" Registers
347  //-----------------------------------------------------------------
348  localparam [7:0] COMPAT_NUM         = 8'd2;
349  localparam [7:0] MGT_PROTOCOL       = 8'd4; // 10 GbE Internal (8'd2 is 10 GbE External)
350
351  // Common registers
352  localparam REG_PORT_INFO            = REG_BASE_ETH_IO + 'h0;
353  localparam REG_MAC_CTRL_STATUS      = REG_BASE_ETH_IO + 'h4;
354  localparam REG_PHY_CTRL_STATUS      = REG_BASE_ETH_IO + 'h8;
355  localparam REG_MAC_LED_CTL          = REG_BASE_ETH_IO + 'hC;
356
357  // Protocol specific constants
358  localparam [1:0]  MAC_LED_CTL_RST_VAL = 2'h0;
359
360  localparam [31:0] MAC_CTRL_RST_VAL = {31'h0, 1'b1}; // tx_enable on reset
361  localparam [31:0] PHY_CTRL_RST_VAL = 32'h0;
362
363  // Writable registers
364  reg [31:0] mac_ctrl_reg = MAC_CTRL_RST_VAL;
365  reg [31:0] phy_ctrl_reg = PHY_CTRL_RST_VAL;
366  reg [1:0]  mac_led_ctl  = MAC_LED_CTL_RST_VAL;
367
368  always @(posedge bus_clk) begin
369    if (bus_rst) begin
370      mac_ctrl_reg <= MAC_CTRL_RST_VAL;
371      phy_ctrl_reg <= PHY_CTRL_RST_VAL;
372      mac_led_ctl  <= MAC_LED_CTL_RST_VAL;
373    end else if (reg_wr_req) begin
374      case(reg_wr_addr)
375        REG_MAC_CTRL_STATUS:
376          mac_ctrl_reg <= reg_wr_data;
377        REG_PHY_CTRL_STATUS:
378          phy_ctrl_reg <= reg_wr_data;
379        REG_MAC_LED_CTL:
380          mac_led_ctl <= reg_wr_data[1:0];
381      endcase
382    end
383  end
384
385  // Readable registers
386  wire [31:0] mac_status, phy_status;
387
388  assign port_info = {COMPAT_NUM, 6'h0, activity, link_up, MGT_PROTOCOL, PORTNUM};
389
390  always @(posedge bus_clk) begin
391    // No reset handling needed for readback
392    if (reg_rd_req) begin
393      reg_rd_resp_io <= 1'b1;
394      case(reg_rd_addr)
395        REG_PORT_INFO:
396          reg_rd_data_io <= port_info;
397        REG_MAC_CTRL_STATUS:
398          reg_rd_data_io <= mac_status;
399        REG_PHY_CTRL_STATUS:
400          reg_rd_data_io <= phy_status;
401        REG_MAC_LED_CTL:
402          reg_rd_data_io <= {30'd0, mac_led_ctl};
403        default:
404          reg_rd_resp_io <= 1'b0;
405      endcase
406    end if (reg_rd_resp_io) begin
407      reg_rd_resp_io <= 1'b0;
408    end
409  end
410
411  assign mac_status = 'd0;
412  assign phy_status[31:8] = 24'h0;
413  assign link_up = 1'b1;
414
415  wire identify_enable = mac_led_ctl[0];
416  wire identify_value  = mac_led_ctl[1];
417
418  //-----------------------------------------------------------------
419  // Activity detector
420  //-----------------------------------------------------------------
421  wire activity_int;
422
423  pulse_stretch act_pulse_str_i (
424    .clk(bus_clk),
425    .rst(bus_rst | ~link_up),
426    .pulse((h2e_tvalid & h2e_tready) | (e2h_tvalid & e2h_tready)),
427    .pulse_stretched(activity_int)
428  );
429
430  always @ (posedge bus_clk) activity <= identify_enable ? identify_value : activity_int;
431
432endmodule
433`default_nettype wire
434