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