diff options
Diffstat (limited to 'fpga/usrp3/lib/rfnoc/xport/eth_internal.v')
-rw-r--r-- | fpga/usrp3/lib/rfnoc/xport/eth_internal.v | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/rfnoc/xport/eth_internal.v b/fpga/usrp3/lib/rfnoc/xport/eth_internal.v new file mode 100644 index 000000000..49cf838a5 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/xport/eth_internal.v @@ -0,0 +1,433 @@ +/////////////////////////////////////////////////////////////////// +// +// Copyright 2019 Ettus Research, a National Instruments brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: eth_internal +// Description: +// Reduces clutter at top level. +// - FPGA-internal Ethernet port +// - ARP responder instead of other CPU connection +// +////////////////////////////////////////////////////////////////////// + +`default_nettype none +module eth_internal #( + parameter DWIDTH = 32, + parameter AWIDTH = 14, + parameter [7:0] PORTNUM = 0, + parameter [15:0] RFNOC_PROTOVER = {8'd1, 8'd0} +)( + // Resets + input wire bus_rst, + + // Clocks + input wire bus_clk, + + //Axi-lite + input wire s_axi_aclk, + input wire s_axi_aresetn, + input wire [AWIDTH-1:0] s_axi_awaddr, + input wire s_axi_awvalid, + output wire s_axi_awready, + + input wire [DWIDTH-1:0] s_axi_wdata, + input wire [DWIDTH/8-1:0] s_axi_wstrb, + input wire s_axi_wvalid, + output wire s_axi_wready, + + output wire [1:0] s_axi_bresp, + output wire s_axi_bvalid, + input wire s_axi_bready, + + input wire [AWIDTH-1:0] s_axi_araddr, + input wire s_axi_arvalid, + output wire s_axi_arready, + + output wire [DWIDTH-1:0] s_axi_rdata, + output wire [1:0] s_axi_rresp, + output wire s_axi_rvalid, + input wire s_axi_rready, + + // Host-Ethernet DMA interface + output wire [63:0] e2h_tdata, + output wire [7:0] e2h_tkeep, + output wire e2h_tlast, + output wire e2h_tvalid, + input wire e2h_tready, + + input wire [63:0] h2e_tdata, + input wire [7:0] h2e_tkeep, + input wire h2e_tlast, + input wire h2e_tvalid, + output wire h2e_tready, + + // RFNoC interface + output wire [63:0] e2v_tdata, + output wire e2v_tlast, + output wire e2v_tvalid, + input wire e2v_tready, + + input wire [63:0] v2e_tdata, + input wire v2e_tlast, + input wire v2e_tvalid, + output wire v2e_tready, + + // MISC + output wire [31:0] port_info, + input wire [15:0] device_id, + + output wire link_up, + output reg activity + +); + + localparam REG_BASE_ETH_IO = 14'h0; + localparam REG_BASE_ETH_SWITCH = 14'h1000; + + // AXI4-Lite to RegPort (PS to PL Register Access) + wire reg_wr_req; + wire [AWIDTH-1:0] reg_wr_addr; + wire [DWIDTH-1:0] reg_wr_data; + wire reg_rd_req; + wire [AWIDTH-1:0] reg_rd_addr; + wire reg_rd_resp, reg_rd_resp_eth_if; + reg reg_rd_resp_io = 1'b0; + wire [DWIDTH-1:0] reg_rd_data, reg_rd_data_eth_if; + reg [DWIDTH-1:0] reg_rd_data_io = 'd0; + + axil_regport_master #( + .DWIDTH (DWIDTH), // Width of the AXI4-Lite data bus (must be 32 or 64) + .AWIDTH (AWIDTH), // Width of the address bus + .WRBASE (0), // Write address base + .RDBASE (0), // Read address base + .TIMEOUT (10) // log2(timeout). Read will timeout after (2^TIMEOUT - 1) cycles + ) eth_dma_reg_mst_i ( + // Clock and reset + .s_axi_aclk (s_axi_aclk), + .s_axi_aresetn (s_axi_aresetn), + // AXI4-Lite: Write address port (domain: s_axi_aclk) + .s_axi_awaddr (s_axi_awaddr), + .s_axi_awvalid (s_axi_awvalid), + .s_axi_awready (s_axi_awready), + // AXI4-Lite: Write data port (domain: s_axi_aclk) + .s_axi_wdata (s_axi_wdata), + .s_axi_wstrb (s_axi_wstrb), + .s_axi_wvalid (s_axi_wvalid), + .s_axi_wready (s_axi_wready), + // AXI4-Lite: Write response port (domain: s_axi_aclk) + .s_axi_bresp (s_axi_bresp), + .s_axi_bvalid (s_axi_bvalid), + .s_axi_bready (s_axi_bready), + // AXI4-Lite: Read address port (domain: s_axi_aclk) + .s_axi_araddr (s_axi_araddr), + .s_axi_arvalid (s_axi_arvalid), + .s_axi_arready (s_axi_arready), + // AXI4-Lite: Read data port (domain: s_axi_aclk) + .s_axi_rdata (s_axi_rdata), + .s_axi_rresp (s_axi_rresp), + .s_axi_rvalid (s_axi_rvalid), + .s_axi_rready (s_axi_rready), + // Register port: Write port (domain: reg_clk) + .reg_clk (bus_clk), + .reg_wr_req (reg_wr_req), + .reg_wr_addr (reg_wr_addr), + .reg_wr_data (reg_wr_data), + // Register port: Read port (domain: reg_clk) + .reg_rd_req (reg_rd_req), + .reg_rd_addr (reg_rd_addr), + .reg_rd_resp (reg_rd_resp), + .reg_rd_data (reg_rd_data) + ); + + // Regport Mux for response + regport_resp_mux #( + .WIDTH (DWIDTH), + .NUM_SLAVES (2) + ) reg_resp_mux_i ( + .clk(bus_clk), .reset(bus_rst), + .sla_rd_resp({reg_rd_resp_eth_if, reg_rd_resp_io}), + .sla_rd_data({reg_rd_data_eth_if, reg_rd_data_io}), + .mst_rd_resp(reg_rd_resp), .mst_rd_data(reg_rd_data) + ); + + // ARP responder + wire [63:0] e2c_tdata; + wire [7:0] e2c_tkeep; + wire e2c_tlast; + wire e2c_tvalid; + wire e2c_tready; + + wire [63:0] c2e_tdata; + wire [7:0] c2e_tkeep; + wire c2e_tlast; + wire c2e_tvalid; + wire c2e_tready; + + wire [3:0] e2c_tuser; + wire [3:0] c2e_tuser; + + // ARM Host-to-Ethernet + wire [3:0] e2h_tuser; + wire [3:0] h2e_tuser; + + // Host Ethernet-to-CHDR + wire [63:0] h2e_chdr_tdata; + wire [3:0] h2e_chdr_tuser; + wire h2e_chdr_tlast; + wire h2e_chdr_tvalid; + wire h2e_chdr_tready; + wire [63:0] e2h_chdr_tdata; + wire [3:0] e2h_chdr_tuser; + wire e2h_chdr_tlast; + wire e2h_chdr_tvalid; + wire e2h_chdr_tready; + + + // In AXI Stream, tkeep is the byte qualifier that indicates + // whether the content of the associated byte + // of TDATA is processed as part of the data stream. + // tuser as used in eth_interface is the number of valid bytes + + // Converting tuser to tkeep for ingress packets + assign e2c_tkeep = ~e2c_tlast ? 8'b1111_1111 + : (e2c_tuser == 4'd0) ? 8'b1111_1111 + : (e2c_tuser == 4'd1) ? 8'b0000_0001 + : (e2c_tuser == 4'd2) ? 8'b0000_0011 + : (e2c_tuser == 4'd3) ? 8'b0000_0111 + : (e2c_tuser == 4'd4) ? 8'b0000_1111 + : (e2c_tuser == 4'd5) ? 8'b0001_1111 + : (e2c_tuser == 4'd6) ? 8'b0011_1111 + : 8'b0111_1111; + + // Converting tkeep to tuser for egress packets + assign c2e_tuser = ~c2e_tlast ? 4'd0 + : (c2e_tkeep == 8'b1111_1111) ? 4'd0 + : (c2e_tkeep == 8'b0111_1111) ? 4'd7 + : (c2e_tkeep == 8'b0011_1111) ? 4'd6 + : (c2e_tkeep == 8'b0001_1111) ? 4'd5 + : (c2e_tkeep == 8'b0000_1111) ? 4'd4 + : (c2e_tkeep == 8'b0000_0111) ? 4'd3 + : (c2e_tkeep == 8'b0000_0011) ? 4'd2 + : (c2e_tkeep == 8'b0000_0001) ? 4'd1 + : 4'd0; + + // Converting tuser to tkeep for ingress packets + assign e2h_tkeep = ~e2h_tlast ? 8'b1111_1111 + : (e2h_tuser == 4'd0) ? 8'b1111_1111 + : (e2h_tuser == 4'd1) ? 8'b0000_0001 + : (e2h_tuser == 4'd2) ? 8'b0000_0011 + : (e2h_tuser == 4'd3) ? 8'b0000_0111 + : (e2h_tuser == 4'd4) ? 8'b0000_1111 + : (e2h_tuser == 4'd5) ? 8'b0001_1111 + : (e2h_tuser == 4'd6) ? 8'b0011_1111 + : 8'b0111_1111; + + // Converting tkeep to tuser for egress packets + assign h2e_tuser = ~h2e_tlast ? 4'd0 + : (h2e_tkeep == 8'b1111_1111) ? 4'd0 + : (h2e_tkeep == 8'b0111_1111) ? 4'd7 + : (h2e_tkeep == 8'b0011_1111) ? 4'd6 + : (h2e_tkeep == 8'b0001_1111) ? 4'd5 + : (h2e_tkeep == 8'b0000_1111) ? 4'd4 + : (h2e_tkeep == 8'b0000_0111) ? 4'd3 + : (h2e_tkeep == 8'b0000_0011) ? 4'd2 + : (h2e_tkeep == 8'b0000_0001) ? 4'd1 + : 4'd0; + + // FPGA-side addresses for the ARP responder + wire [47:0] my_mac; + wire [31:0] my_ip; + wire [15:0] my_udp_port; + + arm_deframer arm_deframer_i ( + .clk(bus_clk), + .reset(bus_rst), + .clear(1'b0), + .s_axis_tdata(h2e_tdata), + .s_axis_tuser(h2e_tuser), + .s_axis_tlast(h2e_tlast), + .s_axis_tvalid(h2e_tvalid), + .s_axis_tready(h2e_tready), + .m_axis_tdata(h2e_chdr_tdata), + .m_axis_tuser(h2e_chdr_tuser), + .m_axis_tlast(h2e_chdr_tlast), + .m_axis_tvalid(h2e_chdr_tvalid), + .m_axis_tready(h2e_chdr_tready) + ); + + axi64_to_xge64 arm_framer ( + .clk(bus_clk), + .reset(bus_rst), + .clear(1'b0), + .s_axis_tdata(e2h_chdr_tdata), + .s_axis_tuser(e2h_chdr_tuser), + .s_axis_tlast(e2h_chdr_tlast), + .s_axis_tvalid(e2h_chdr_tvalid), + .s_axis_tready(e2h_chdr_tready), + .m_axis_tdata(e2h_tdata), + .m_axis_tuser(e2h_tuser), + .m_axis_tlast(e2h_tlast), + .m_axis_tvalid(e2h_tvalid), + .m_axis_tready(e2h_tready) + ); + + eth_interface #( + .PROTOVER(RFNOC_PROTOVER), + .MTU(10), + .NODE_INST(0), + .REG_AWIDTH (AWIDTH), + .BASE(REG_BASE_ETH_SWITCH) + ) eth_interface ( + .clk (bus_clk), + .reset (bus_rst), + .device_id (device_id), + .reg_wr_req (reg_wr_req), + .reg_wr_addr (reg_wr_addr), + .reg_wr_data (reg_wr_data), + .reg_rd_req (reg_rd_req), + .reg_rd_addr (reg_rd_addr), + .reg_rd_resp (reg_rd_resp_eth_if), + .reg_rd_data (reg_rd_data_eth_if), + .my_mac (my_mac), + .my_ip (my_ip), + .my_udp_port (my_udp_port), + .eth_tx_tdata (e2h_chdr_tdata), + .eth_tx_tuser (e2h_chdr_tuser), + .eth_tx_tlast (e2h_chdr_tlast), + .eth_tx_tvalid (e2h_chdr_tvalid), + .eth_tx_tready (e2h_chdr_tready), + .eth_rx_tdata (h2e_chdr_tdata), + .eth_rx_tuser (h2e_chdr_tuser), + .eth_rx_tlast (h2e_chdr_tlast), + .eth_rx_tvalid (h2e_chdr_tvalid), + .eth_rx_tready (h2e_chdr_tready), + .e2v_tdata (e2v_tdata), + .e2v_tlast (e2v_tlast), + .e2v_tvalid (e2v_tvalid), + .e2v_tready (e2v_tready), + .v2e_tdata (v2e_tdata), + .v2e_tlast (v2e_tlast), + .v2e_tvalid (v2e_tvalid), + .v2e_tready (v2e_tready), + .e2c_tdata (e2c_tdata), + .e2c_tuser (e2c_tuser), + .e2c_tlast (e2c_tlast), + .e2c_tvalid (e2c_tvalid), + .e2c_tready (e2c_tready), + .c2e_tdata (c2e_tdata), + .c2e_tuser (c2e_tuser), + .c2e_tlast (c2e_tlast), + .c2e_tvalid (c2e_tvalid), + .c2e_tready (c2e_tready) + ); + + arp_responder arp_responder_i ( + .aclk (bus_clk), + .aresetn (~bus_rst), + .mac_addr (my_mac), + .ip_addr (my_ip), + .s_axis_tdata (e2c_tdata), + .s_axis_tvalid (e2c_tvalid), + .s_axis_tready (e2c_tready), + .s_axis_tkeep (e2c_tkeep), + .s_axis_tlast (e2c_tlast), + .s_axis_tuser (1'b0), + .m_axis_tdata (c2e_tdata), + .m_axis_tvalid (c2e_tvalid), + .m_axis_tready (c2e_tready), + .m_axis_tkeep (c2e_tkeep), + .m_axis_tlast (c2e_tlast), + .m_axis_tuser () + ); + + //----------------------------------------------------------------- + // "I/O" Registers + //----------------------------------------------------------------- + localparam [7:0] COMPAT_NUM = 8'd2; + localparam [7:0] MGT_PROTOCOL = 8'd4; // 10 GbE Internal (8'd2 is 10 GbE External) + + // Common registers + localparam REG_PORT_INFO = REG_BASE_ETH_IO + 'h0; + localparam REG_MAC_CTRL_STATUS = REG_BASE_ETH_IO + 'h4; + localparam REG_PHY_CTRL_STATUS = REG_BASE_ETH_IO + 'h8; + localparam REG_MAC_LED_CTL = REG_BASE_ETH_IO + 'hC; + + // Protocol specific constants + localparam [1:0] MAC_LED_CTL_RST_VAL = 2'h0; + + localparam [31:0] MAC_CTRL_RST_VAL = {31'h0, 1'b1}; // tx_enable on reset + localparam [31:0] PHY_CTRL_RST_VAL = 32'h0; + + // Writable registers + reg [31:0] mac_ctrl_reg = MAC_CTRL_RST_VAL; + reg [31:0] phy_ctrl_reg = PHY_CTRL_RST_VAL; + reg [1:0] mac_led_ctl = MAC_LED_CTL_RST_VAL; + + always @(posedge bus_clk) begin + if (bus_rst) begin + mac_ctrl_reg <= MAC_CTRL_RST_VAL; + phy_ctrl_reg <= PHY_CTRL_RST_VAL; + mac_led_ctl <= MAC_LED_CTL_RST_VAL; + end else if (reg_wr_req) begin + case(reg_wr_addr) + REG_MAC_CTRL_STATUS: + mac_ctrl_reg <= reg_wr_data; + REG_PHY_CTRL_STATUS: + phy_ctrl_reg <= reg_wr_data; + REG_MAC_LED_CTL: + mac_led_ctl <= reg_wr_data[1:0]; + endcase + end + end + + // Readable registers + wire [31:0] mac_status, phy_status; + + assign port_info = {COMPAT_NUM, 6'h0, activity, link_up, MGT_PROTOCOL, PORTNUM}; + + always @(posedge bus_clk) begin + // No reset handling needed for readback + if (reg_rd_req) begin + reg_rd_resp_io <= 1'b1; + case(reg_rd_addr) + REG_PORT_INFO: + reg_rd_data_io <= port_info; + REG_MAC_CTRL_STATUS: + reg_rd_data_io <= mac_status; + REG_PHY_CTRL_STATUS: + reg_rd_data_io <= phy_status; + REG_MAC_LED_CTL: + reg_rd_data_io <= {30'd0, mac_led_ctl}; + default: + reg_rd_resp_io <= 1'b0; + endcase + end if (reg_rd_resp_io) begin + reg_rd_resp_io <= 1'b0; + end + end + + assign mac_status = 'd0; + assign phy_status[31:8] = 24'h0; + assign link_up = 1'b1; + + wire identify_enable = mac_led_ctl[0]; + wire identify_value = mac_led_ctl[1]; + + //----------------------------------------------------------------- + // Activity detector + //----------------------------------------------------------------- + wire activity_int; + + pulse_stretch act_pulse_str_i ( + .clk(bus_clk), + .rst(bus_rst | ~link_up), + .pulse((h2e_tvalid & h2e_tready) | (e2h_tvalid & e2h_tready)), + .pulse_stretched(activity_int) + ); + + always @ (posedge bus_clk) activity <= identify_enable ? identify_value : activity_int; + +endmodule +`default_nettype wire |