1//
2// Copyright 2020 Ettus Research, a National Instruments Brand
3//
4// SPDX-License-Identifier: LGPL-3.0-or-later
5// Module: eth_ipv4_interface
6//
7// Description:
8//   Adapts from internal CHDR to UDP/IPV4 Ethernet packets.
9//   Packets not specifically addressed to CHDR are routed
10//   to the CPU
11//
12// Parameters:
13//   - PROTOVER: RFNoC protocol version {8'd<major>, 8'd<minor>}
14//   - CPU_FIFO_SIZE: Log2 of the FIFO depth (in bytes) for the CPU egress path
15//   - CHDR_FIFO_SIZE: Log2 of the FIFO depth (in bytes) for the CHDR egress path
16//   - RT_TBL_SIZE: Log2 of the depth of the return-address routing table
17//   - NODE_INST: The node type to return for a node-info discovery
18//   - DROP_UNKNOWN_MAC: Drop packets not addressed to us?
19//   - DROP_MIN_PACKET: Drop packets smaller than 64 bytes?
20//   - PREAMBLE_BYTES: Number of bytes of Preamble expected
21//   - ADD_SOF: Add a SOF indication into the tuser field of e2c
22//   - SYNC: Set if MAC is not the same as bus_clk
23//   - ENET_W: Width of the link to the Ethernet MAC
24//   - CPU_W: Width of the CPU interface
25//   - CHDR_W: Width of the CHDR interface
26//
27
28module eth_ipv4_interface #(
29  logic [15:0] PROTOVER         = {8'd1, 8'd0},
30  int          CPU_FIFO_SIZE    = $clog2(8*1024),
31  int          CHDR_FIFO_SIZE   = $clog2(8*1024),
32  int          NODE_INST        = 0,
33  int          RT_TBL_SIZE      = 6,
34  int          REG_AWIDTH       = 14,
35  int          BASE             = 0,
36  bit          DROP_UNKNOWN_MAC = 0,
37  bit          DROP_MIN_PACKET  = 0,
38  int          PREAMBLE_BYTES   = 6,
39  bit          ADD_SOF          = 1,
40  bit          SYNC             = 0,
41  int          ENET_W           = 64,
42  int          CPU_W            = 64,
43  int          CHDR_W           = 64
44) (
45  input logic        bus_clk,
46  input logic        bus_rst,
47  input logic [15:0] device_id,
48
49  // Register port: Write port (domain: bus_clk)
50  input logic                  reg_wr_req,
51  input logic [REG_AWIDTH-1:0] reg_wr_addr,
52  input logic [31:0]           reg_wr_data,
53
54  // Register port: Read port (domain: bus_clk)
55  input  logic                  reg_rd_req,
56  input  logic [REG_AWIDTH-1:0] reg_rd_addr,
57  output logic                  reg_rd_resp,
58  output logic     [31:0]       reg_rd_data,
59
60  // Status ports (domain: bus_clk)
61  output logic [47:0] my_mac,
62  output logic [31:0] my_ip,
63  output logic [15:0] my_udp_chdr_port,
64
65  // Ethernet MAC
66  AxiStreamIf.master eth_tx, // tUser = {1'b0,trailing bytes};
67  AxiStreamIf.slave  eth_rx, // tUser = {error,trailing bytes};
68  // CHDR router interface
69  AxiStreamIf.master e2v, // tUser = {*not used*};
70  AxiStreamIf.slave  v2e, // tUser = {*not used*};
71  // CPU DMA
72  AxiStreamIf.master e2c, // tUser = {sof,trailing bytes};
73  AxiStreamIf.slave  c2e  // tUser = {1'b0,trailing bytes};
74
75 );
76
77  localparam [47:0] DEFAULT_MAC_ADDR  = {8'h00, 8'h80, 8'h2f, 8'h16, 8'hc5, 8'h2f};
78  localparam [31:0] DEFAULT_IP_ADDR   = {8'd192, 8'd168, 8'd10, 8'd2};
79  localparam [31:0] DEFAULT_UDP_PORT  = 16'd49153;
80
81  //---------------------------------------------------------
82  // Registers
83  //---------------------------------------------------------
84  // Include for register offsets
85  `include "eth_regs.vh"
86  // Allocate one full page for M
87  // mac_reg: MAC address for the dispatcher module. This value is used to
88  // determine if the packet is meant for this device and should be consumed.
89  //
90  // ip_reg: IP address for the dispatcher module. This value is used to
91  // determine if the packet is addressed to this device
92  //
93  // This module supports two destination ports.
94  logic [47:0] mac_reg         = DEFAULT_MAC_ADDR;
95  logic [31:0] ip_reg          = DEFAULT_IP_ADDR;
96  logic [15:0] udp_port        = DEFAULT_UDP_PORT;
97  logic [47:0] bridge_mac_reg  = DEFAULT_MAC_ADDR;
98  logic [31:0] bridge_ip_reg   = DEFAULT_IP_ADDR;
99  logic [15:0] bridge_udp_port = DEFAULT_UDP_PORT;
100  logic        bridge_en;
101  logic        cpu_dropped;
102  logic        chdr_dropped;
103  logic [31:0] chdr_drop_count = 0;
104  logic [31:0] cpu_drop_count  = 0;
105
106  always_comb begin : bridge_mux
107    my_mac            = bridge_en ? bridge_mac_reg : mac_reg;
108    my_ip             = bridge_en ? bridge_ip_reg : ip_reg;
109    my_udp_chdr_port  = bridge_en ? bridge_udp_port : udp_port;
110  end
111
112  always_ff @(posedge bus_clk) begin : reg_wr_ff
113    if (bus_rst) begin
114      mac_reg         <= DEFAULT_MAC_ADDR;
115      ip_reg          <= DEFAULT_IP_ADDR;
116      udp_port        <= DEFAULT_UDP_PORT;
117      bridge_en       <= 1'b0;
118      bridge_mac_reg  <= DEFAULT_MAC_ADDR;
119      bridge_ip_reg   <= DEFAULT_IP_ADDR;
120      bridge_udp_port <= DEFAULT_UDP_PORT;
121    end
122    else begin
123      if (reg_wr_req)
124        case (reg_wr_addr)
125
126        REG_MAC_LSB:
127          mac_reg[31:0]         <= reg_wr_data;
128
129        REG_MAC_MSB:
130          mac_reg[47:32]        <= reg_wr_data[15:0];
131
132        REG_IP:
133          ip_reg                <= reg_wr_data;
134
135        REG_UDP:
136          udp_port              <= reg_wr_data[15:0];
137
138        REG_BRIDGE_MAC_LSB:
139          bridge_mac_reg[31:0]  <= reg_wr_data;
140
141        REG_BRIDGE_MAC_MSB:
142          bridge_mac_reg[47:32] <= reg_wr_data[15:0];
143
144        REG_BRIDGE_IP:
145          bridge_ip_reg         <= reg_wr_data;
146
147        REG_BRIDGE_UDP:
148          bridge_udp_port       <= reg_wr_data[15:0];
149
150        REG_BRIDGE_ENABLE:
151          bridge_en             <= reg_wr_data[0];
152        endcase
153    end
154  end
155
156  always_ff @ (posedge bus_clk) begin : reg_rd_ff
157    if (bus_rst) begin
158      reg_rd_resp <= 1'b0;
159      reg_rd_data <= 32'd0;
160      chdr_drop_count <= 32'd0;
161      cpu_drop_count  <= 32'd0;
162    end
163    else begin
164      if (chdr_dropped) begin
165        chdr_drop_count <= chdr_drop_count+1;
166      end
167      if (cpu_dropped) begin
168        cpu_drop_count <= cpu_drop_count+1;
169      end
170      if (reg_rd_req) begin
171        // Assert read response one cycle after read request
172        reg_rd_resp <= 1'b1;
173        case (reg_rd_addr)
174          REG_MAC_LSB:
175            reg_rd_data <= mac_reg[31:0];
176
177          REG_MAC_MSB:
178            reg_rd_data <= {16'b0,mac_reg[47:32]};
179
180          REG_IP:
181            reg_rd_data <= ip_reg;
182
183          REG_UDP:
184            reg_rd_data <= {16'b0, udp_port};
185
186          REG_BRIDGE_MAC_LSB:
187            reg_rd_data <= bridge_mac_reg[31:0];
188
189          REG_BRIDGE_MAC_MSB:
190            reg_rd_data <= {16'b0,bridge_mac_reg[47:32]};
191
192          REG_BRIDGE_IP:
193            reg_rd_data <= bridge_ip_reg;
194
195          REG_BRIDGE_UDP:
196            reg_rd_data <= {16'b0, bridge_udp_port};
197
198          REG_BRIDGE_ENABLE:
199            reg_rd_data <= {31'b0,bridge_en};
200          // Drop counts are used to debug situations
201          // Where the incoming data goes faster than
202          // chdr can consume it
203          REG_CHDR_DROPPED:
204            begin
205              reg_rd_data <= chdr_drop_count;
206              chdr_drop_count <= 0; // clear when read
207            end
208          REG_CPU_DROPPED:
209            begin
210              reg_rd_data <= cpu_drop_count;
211              cpu_drop_count <= 0; // clear when read
212            end
213         default:
214            reg_rd_resp <= 1'b0;
215         endcase
216      end
217      // Deassert read response after one clock cycle
218      if (reg_rd_resp) begin
219         reg_rd_resp <= 1'b0;
220      end
221    end
222  end
223
224  logic b_dropped_valid;
225  logic e_cpu_dropped,  b_cpu_dropped;
226  logic e_chdr_dropped, b_chdr_dropped;
227  // push over the clock domain
228  // Sized to fit into 2 SRL's
229  axi_fifo_2clk #(.WIDTH(2), .SIZE(4)) fifo_i (
230    .reset(eth_rx.rst),
231    .i_aclk(eth_rx.clk),
232    .i_tdata({e_cpu_dropped, e_chdr_dropped}),
233    .i_tvalid(e_cpu_dropped || e_chdr_dropped), .i_tready(/*not used*/),
234    .o_aclk(bus_clk),
235    .o_tdata({b_cpu_dropped, b_chdr_dropped}),
236    .o_tvalid(b_dropped_valid), .o_tready(1'b1)
237  );
238
239  always_comb begin
240    cpu_dropped  = b_cpu_dropped  && b_dropped_valid;
241    chdr_dropped = b_chdr_dropped && b_dropped_valid;
242  end
243
244  eth_ipv4_chdr_adapter #(
245    .PROTOVER        (PROTOVER),
246    .CPU_FIFO_SIZE   (CPU_FIFO_SIZE),
247    .CHDR_FIFO_SIZE  (CHDR_FIFO_SIZE),
248    .RT_TBL_SIZE     (RT_TBL_SIZE),
249    .NODE_INST       (NODE_INST),
250    .DROP_UNKNOWN_MAC(DROP_UNKNOWN_MAC),
251    .DROP_MIN_PACKET (DROP_MIN_PACKET),
252    .PREAMBLE_BYTES  (PREAMBLE_BYTES),
253    .ADD_SOF         (ADD_SOF),
254    .SYNC            (SYNC),
255    .ENET_W          (ENET_W),
256    .CPU_W           (CPU_W),
257    .CHDR_W          (CHDR_W)
258  ) eth_adapter_i (
259    .eth_rx          (eth_rx   ),
260    .eth_tx          (eth_tx   ),
261    .v2e             (v2e      ),
262    .e2v             (e2v      ),
263    .c2e             (c2e      ),
264    .e2c             (e2c      ),
265    .device_id       (device_id),
266    .my_mac          (my_mac   ),
267    .my_ip           (my_ip    ),
268    .my_udp_chdr_port(my_udp_chdr_port),
269    .chdr_dropped    (e_chdr_dropped),
270    .cpu_dropped     (e_cpu_dropped)
271  );
272
273
274endmodule : eth_ipv4_interface
275