diff options
Diffstat (limited to 'fpga/usrp3/lib/xge_interface')
-rw-r--r-- | fpga/usrp3/lib/xge_interface/Makefile.srcs | 10 | ||||
-rw-r--r-- | fpga/usrp3/lib/xge_interface/axi64_to_xge64.v | 86 | ||||
-rw-r--r-- | fpga/usrp3/lib/xge_interface/axi_count_packets_in_fifo.v | 155 | ||||
-rw-r--r-- | fpga/usrp3/lib/xge_interface/xge64_to_axi64.v | 309 | ||||
-rw-r--r-- | fpga/usrp3/lib/xge_interface/xge_handshake.v | 60 | ||||
-rw-r--r-- | fpga/usrp3/lib/xge_interface/xge_mac_wrapper.v | 325 |
6 files changed, 945 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/xge_interface/Makefile.srcs b/fpga/usrp3/lib/xge_interface/Makefile.srcs new file mode 100644 index 000000000..63cef065d --- /dev/null +++ b/fpga/usrp3/lib/xge_interface/Makefile.srcs @@ -0,0 +1,10 @@ +################################################## +# Logic to interface to Opencores 10G MAC +################################################## +XGE_INTERFACE_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/xge_interface/, \ +axi64_to_xge64.v \ +axi_count_packets_in_fifo.v \ +xge64_to_axi64.v \ +xge_handshake.v \ +xge_mac_wrapper.v \ +)) diff --git a/fpga/usrp3/lib/xge_interface/axi64_to_xge64.v b/fpga/usrp3/lib/xge_interface/axi64_to_xge64.v new file mode 100644 index 000000000..4bb9d200b --- /dev/null +++ b/fpga/usrp3/lib/xge_interface/axi64_to_xge64.v @@ -0,0 +1,86 @@ +// +// Copyright 2013 Ettus Research LLC +// + + +// +// Removes 6 alignment bytes at the beginning of every packet. +// This gives us proper alignment to the IP/UDP header. +// +// Place an SOF indication in bit[3] of the output tuser. +// + +module axi64_to_xge64 + ( + input clk, + input reset, + input clear, + input [63:0] s_axis_tdata, + input [3:0] s_axis_tuser, + input s_axis_tlast, + input s_axis_tvalid, + output s_axis_tready, + output [63:0] m_axis_tdata, + output [3:0] m_axis_tuser, + output m_axis_tlast, + output m_axis_tvalid, + input m_axis_tready + ); + + localparam STORE_FIRST = 0; + localparam FORWARD_FULL = 1; + localparam RELEASE_LAST = 2; + + reg [1:0] state; + reg [15:0] saved; + reg [2:0] last_occ; + reg last_sof; + + //on last line when eof and not finishing with 7 or 8 bytes as last word. + wire last_line = (s_axis_tlast && !(s_axis_tuser[2:0] == 3'b111 || s_axis_tuser[2:0] == 3'b000)); + + always @(posedge clk) begin + if(reset | clear) begin + last_sof <= 0; + last_occ <= 0; + state <= STORE_FIRST; + end + else begin + if (s_axis_tvalid && s_axis_tready) begin + saved <= s_axis_tdata[15:0]; + last_occ <= s_axis_tuser[2:0]; + last_sof <= (state == STORE_FIRST) ; + end + + case(state) + + STORE_FIRST: begin + if (s_axis_tvalid && s_axis_tready) begin + state <= FORWARD_FULL; + end + end + + FORWARD_FULL: begin + if (s_axis_tvalid && s_axis_tready && s_axis_tlast) begin + state <= last_line? STORE_FIRST : RELEASE_LAST; + end + end + + RELEASE_LAST: begin + if (m_axis_tvalid && m_axis_tready) begin + state <= STORE_FIRST; + end + end + + endcase //state + end + end + + assign m_axis_tdata[63:0] = {saved, s_axis_tdata[63:16]}; + assign m_axis_tuser[3] = last_sof; + assign m_axis_tlast = (state == RELEASE_LAST)? 1'b1 : last_line; + assign m_axis_tuser[2:0] = ((state == RELEASE_LAST)? last_occ : (last_line? s_axis_tuser[2:0] : 3'b110)) + 3'b010; + assign m_axis_tvalid = (state == STORE_FIRST)? 0 : ((state == RELEASE_LAST)? 1 : s_axis_tvalid); + assign s_axis_tready = (state == STORE_FIRST)? 1 : ((state == RELEASE_LAST)? 0 : m_axis_tready); + +endmodule //fifo69_txrealign diff --git a/fpga/usrp3/lib/xge_interface/axi_count_packets_in_fifo.v b/fpga/usrp3/lib/xge_interface/axi_count_packets_in_fifo.v new file mode 100644 index 000000000..45eae42c0 --- /dev/null +++ b/fpga/usrp3/lib/xge_interface/axi_count_packets_in_fifo.v @@ -0,0 +1,155 @@ +// +// Copyright 2013 Ettus Research LLC +// + + +// +// Tracks the number of complete packets in an AXI FIFO so that +// the XGE MAC can commit to transmitting a packet. +// + +module axi_count_packets_in_fifo + ( + input clk, + input reset, + input in_axis_tvalid, + input in_axis_tready, + input in_axis_tlast, + input out_axis_tvalid, + input out_axis_tready, + input out_axis_tlast, + input pkt_tx_full, + output enable_tx + ); + + localparam WAIT_SOF = 0; + localparam WAIT_EOF = 1; + + localparam WAIT_FULL = 0; + localparam DELAY_TO_EOF = 0; + localparam WAIT_SPACE = 2; + + + reg in_state, out_state; + reg [1:0] full_state; + reg pause_tx; + + reg [7:0] pkt_count; + + + // + // Count packets arriving into large FIFO + // + always @(posedge clk) + if (reset) begin + in_state <= WAIT_SOF; + end else + case(in_state) + WAIT_SOF: + if (in_axis_tvalid && in_axis_tready) begin + in_state <= WAIT_EOF; + end else begin + in_state <= WAIT_SOF; + end + WAIT_EOF: + if (in_axis_tlast && in_axis_tvalid && in_axis_tready) begin + in_state <= WAIT_SOF; + end else begin + in_state <= WAIT_EOF; + end + endcase // case(in_state) + + + // + // Count packets leaving large FIFO + // + always @(posedge clk) + if (reset) begin + out_state <= WAIT_SOF; + end else + case(out_state) + WAIT_SOF: + if (out_axis_tvalid && out_axis_tready) begin + out_state <= WAIT_EOF; + end else begin + out_state <= WAIT_SOF; + end + WAIT_EOF: + if (out_axis_tlast && out_axis_tvalid && out_axis_tready) begin + out_state <= WAIT_SOF; + end else begin + out_state <= WAIT_EOF; + end + endcase // case(in_state) + + + // + // Count packets in FIFO. + // No protection on counter wrap, + // unclear how such an error could occur or how to gracefully deal with it. + // + always @(posedge clk) + if (reset) + pkt_count <= 0; + else if (((out_state==WAIT_EOF) && out_axis_tlast && out_axis_tvalid && out_axis_tready) + && ((in_state==WAIT_EOF) && in_axis_tlast && in_axis_tvalid && in_axis_tready)) + pkt_count <= pkt_count; + else if ((out_state==WAIT_EOF) && out_axis_tlast && out_axis_tvalid && out_axis_tready) + pkt_count <= pkt_count - 1; + else if ((in_state==WAIT_EOF) && in_axis_tlast && in_axis_tvalid && in_axis_tready) + pkt_count <= pkt_count + 1; + + + // + // Guard against Tx MAC overflow (as indicated by pkt_tx_full) + // + always @(posedge clk) + if (reset) begin + pause_tx <= 0; + full_state <= WAIT_FULL; + end + else begin + pause_tx <= 0; + case(full_state) + WAIT_FULL: + // Search for pkt_tx_full going asserted + if (pkt_tx_full && (out_state == WAIT_SOF)) begin + full_state <= WAIT_SPACE; + pause_tx <= 1; + end else if (pkt_tx_full && (out_state == WAIT_EOF)) begin + full_state <= DELAY_TO_EOF; + end + + DELAY_TO_EOF: + // pkt_tx_full has gone asserted during Tx of a packet from FIFO. + // Wait until either FIFO has space again and transition direct to WAIT_FULL + // or at EOF if pkt_tx_full is still asserted the transition to WAIT_SPACE until + // MAC flags there is space again. + if (pkt_tx_full && out_axis_tlast && out_axis_tvalid && out_axis_tready) begin + full_state <= WAIT_SPACE; + pause_tx <= 1; + end else if (pkt_tx_full) begin + full_state <= DELAY_TO_EOF; + end else + full_state <= WAIT_FULL; + + WAIT_SPACE: + // Wait for MAC to flag space in internal Tx FIFO again then transition to WAIT_FULL. + if (pkt_tx_full) begin + full_state <= WAIT_SPACE; + pause_tx <= 1; + end else + full_state <= WAIT_FULL; + + endcase // case(full_state) + end + + + // Enable Tx to MAC + assign enable_tx = (pkt_count != 0) && ~pause_tx; + + + + +endmodule // count_tx_packets + diff --git a/fpga/usrp3/lib/xge_interface/xge64_to_axi64.v b/fpga/usrp3/lib/xge_interface/xge64_to_axi64.v new file mode 100644 index 000000000..1ff4af748 --- /dev/null +++ b/fpga/usrp3/lib/xge_interface/xge64_to_axi64.v @@ -0,0 +1,309 @@ +// +// Copyright 2013 Ettus Research LLC +// + + +// Adds 6 bytes at the beginning of every packet +// This gives us good32/64bit alignment of IP/UDP headers. +// +// The 6 bytes added include an octet passed as a parameter allowing a label to +// be added as metatdata in the header padding. This is typically the ingress +// port to be tagged in the packet as metadata. +// +// bit[65] EOF +// bit[64] SOF +// bit[68:66] occ +// +// This design will break if downstream can not be guarenteed to be ready to accept data. +// XGE MAC expects to be able to stream whole packet with no handshaking. +// We force downstream packet gate to discard packet by signalling error with tlast and +// resynchronizing with upstream. +// + +module xge64_to_axi64 + #(parameter LABEL=0) + ( + input clk, + input reset, + input clear, + input [63:0] datain, + input [2:0] occ, + input sof, + input eof, + input err, + input valid, + output reg [63:0] axis_tdata, + output reg [3:0] axis_tuser, + output reg axis_tlast, + output reg axis_tvalid, // Signal data avilable to downstream + input axis_tready + ); + + localparam EMPTY = 0; + localparam IN_USE = 1; + localparam FLUSHING3 = 2; + localparam FLUSHING4 = 3; + localparam FLUSHING5 = 4; + localparam FLUSHING6 = 5; + localparam FLUSHING7 = 6; + localparam FLUSHING8 = 7; + localparam ERROR1 = 8; + + + localparam EOF1 = 3'b001; + localparam EOF2 = 3'b010; + localparam EOF3 = 3'b011; + localparam EOF4 = 3'b100; + localparam EOF5 = 3'b101; + localparam EOF6 = 3'b110; + localparam EOF7 = 3'b111; + localparam EOF8 = 3'b000; + + reg [3:0] state; + reg err_reg; + reg [47:0] holding_reg; + + always @(posedge clk) + if(reset | clear) begin + state <= EMPTY; + axis_tdata <= 0; + holding_reg <= 0; + axis_tvalid <= 0; + end else begin + // Defaults + axis_tvalid <= 0; + axis_tuser <= 0; + axis_tlast <= 0; + err_reg <= 0; + + case(state) + EMPTY: begin + if (valid & axis_tready & sof) begin + // Start of packet should always be received in this state. + // It should NEVER be possible to get a packet from the MAC with EOF also set in + // the first 64 bits so not designed for. + // Add pad. Store last 6 octets into holding, change state to show data in holding. + state <= IN_USE; + axis_tvalid <= 1; + end + else if (valid & ~axis_tready) + // Assert on this condition, add H/W to deal with overflow later. + $display("ERROR: xge64_to_axi64, valid & ~axis_tready"); + + holding_reg <= datain[47:0]; + axis_tdata[63:56] <= LABEL; // Tag packet with label + axis_tdata[55:16] <= 40'h0; + axis_tdata[15:0] <= datain[63:48]; + end + + IN_USE: begin + if (valid & axis_tready & (eof | err)) begin + // End of packet should always be received in this state. + // If Error is asserted from MAC, immediate EOF is forced, + // and the error flag set in tuser. State machine will return to WAIT + // state and search for new SOF thereby discarding anything left of error packet. + // + // In the case of 3 through 8 valid octets in the final 64bits input, + // we must run another cycle afterwards since we have 6 more bytes still in holding. + err_reg <= err; + holding_reg[47:0] <= datain[47:0]; + axis_tdata[63:16] <= holding_reg[47:0]; + axis_tdata[15:0] <= datain[63:48]; + axis_tvalid <= 1; + + case(occ[2:0]) + // 8 valid Octets in last word of packet, finish next cycle + 0: begin + state <= FLUSHING8; + end + // 7 valid Octets in last word of packet, finish next cycle + 7: begin + state <= FLUSHING7; + end + // 6 valid octets in last word of packet, finish next cycle + 6: begin + state <= FLUSHING6; + end + // 5 valid octets in last word of packet, finish next cycle + 5: begin + state <= FLUSHING5; + end + // 4 valid octets in last word of packet, finish next cycle + 4: begin + state <= FLUSHING4; + end + // 3 valid octets in last word of packet, finish next cycle + 3: begin + state <= FLUSHING3; + end + // 2 valid octets in last word of packet, finish this cycle + 2: begin + axis_tuser <= {err,EOF8}; + state <= EMPTY; + axis_tlast <= 1; + end + // 1 valid octets in last word of packet, finish this cycle + 1: begin + axis_tuser <= {err,EOF7}; + state <= EMPTY; + axis_tlast <= 1; + end + endcase // case (occ[2:0]) + end // if (valid & axis_tready & eof) + else if (valid & axis_tready) begin + // No EOF indication so in packet payload somewhere still. + state <= IN_USE; + holding_reg[47:0] <= datain[47:0]; + axis_tdata[63:16] <= holding_reg[47:0]; + axis_tdata[15:0] <= datain[63:48]; + axis_tvalid <= 1; + end + else if (valid & ~axis_tready) begin + // Assert on this condition + $display("ERROR: xge64_to_axi64, valid & ~axis_tready"); + // Keep error state asserted ready for downstream to accept + state <= ERROR1; + axis_tlast <= 1; + axis_tvalid <= 1; + axis_tuser <= {1'b1, EOF8}; // Force error in this packet. + end else if (~valid) begin + // Assert on this condition, don't expect the MAC to ever throtle dataflow intra-packet. + $display("ERROR: xge64_to_axi64, ~valid "); + state <= ERROR1; + axis_tlast <= 1; + axis_tvalid <= 1; + axis_tuser <= {1'b1, EOF8}; // Force error in this packet. + end + end // case: IN_USE + + FLUSHING3: begin + if (axis_tready) begin + // EOF has been received last cycle. + // Ethernet interframe gap means we don't have to search for back-to-back EOF-SOF here. + // 1 valid Octets to finish + state <= EMPTY; + axis_tlast <= 1; + axis_tuser <= {err_reg, EOF1}; + axis_tdata[63:16] <= holding_reg[47:0]; + axis_tvalid <= 1; + end else begin + state <= ERROR1; + axis_tlast <= 1; + axis_tvalid <= 1; + axis_tuser <= {1'b1, EOF8}; // Force error in this packet. + end // else: !if(axis_tready) + end + + FLUSHING4: begin + if (axis_tready) begin + // EOF has been received last cycle. + // Ethernet interframe gap means we don't have to search for back-to-back EOF-SOF here. + // 2 valid Octets to finish + state <= EMPTY; + axis_tlast <= 1; + axis_tuser <= {err_reg, EOF2}; + axis_tdata[63:16] <= holding_reg[47:0]; + axis_tvalid <= 1; + end else begin + state <= ERROR1; + axis_tlast <= 1; + axis_tvalid <= 1; + axis_tuser <= {1'b1, EOF8}; // Force error in this packet. + end // else: !if(axis_tready) + end + + FLUSHING5: begin + if (axis_tready) begin + // EOF has been received last cycle. + // Ethernet interframe gap means we don't have to search for back-to-back EOF-SOF here. + // 3 valid Octets to finish + state <= EMPTY; + axis_tlast <= 1; + axis_tuser <= {err_reg, EOF3}; + axis_tdata[63:16] <= holding_reg[47:0]; + axis_tvalid <= 1; + end else begin + state <= ERROR1; + axis_tlast <= 1; + axis_tvalid <= 1; + axis_tuser <= {1'b1, EOF8}; // Force error in this packet. + end // else: !if(axis_tready) + end + + FLUSHING6: begin + if (axis_tready) begin + // EOF has been received last cycle. + // Ethernet interframe gap means we don't have to search for back-to-back EOF-SOF here. + // 4 valid Octets to finish + state <= EMPTY; + axis_tlast <= 1; + axis_tuser <= {err_reg, EOF4}; + axis_tdata[63:16] <= holding_reg[47:0]; + axis_tvalid <= 1; + end else begin + state <= ERROR1; + axis_tlast <= 1; + axis_tvalid <= 1; + axis_tuser <= {1'b1, EOF8}; // Force error in this packet. + end // else: !if(axis_tready) + end + + FLUSHING7: begin + if (axis_tready) begin + // EOF has been received last cycle. + // Ethernet interframe gap means we don't have to search for back-to-back EOF-SOF here. + // 5 valid Octets to finish + state <= EMPTY; + axis_tlast <= 1; + axis_tuser <= {err_reg, EOF5}; + axis_tdata[63:16] <= holding_reg[47:0]; + axis_tvalid <= 1; + end else begin + state <= ERROR1; + axis_tlast <= 1; + axis_tvalid <= 1; + axis_tuser <= {1'b1, EOF8}; // Force error in this packet. + end // else: !if(axis_tready) + end + + FLUSHING8: begin + if (axis_tready) begin + // EOF has been received last cycle. + // Ethernet interframe gap means we don't have to search for back-to-back EOF-SOF here. + // 6 valid Octets to finish + state <= EMPTY; + axis_tlast <= 1; + axis_tuser <= {err_reg, EOF6}; + axis_tdata[63:16] <= holding_reg[47:0]; + axis_tvalid <= 1; + end else begin + state <= ERROR1; + axis_tlast <= 1; + axis_tvalid <= 1; + axis_tuser <= {1'b1, EOF8}; // Force error in this packet. + end // else: !if(axis_tready) + end + + ERROR1: begin + // We were already actively receiving a packet from the upstream MAC and the downstream + // signaled not ready by de-asserting tready. Since we can't back pressure the MAC we have to + // abandon the current packet, discarding any data already sent down stream by sending an asserted error + // with a tlast when ever tready becomes asserted again. Meanwhile we start dropping arriving MAC + // data on the floor since there is nothing useful we can do with it currently. + if (axis_tready) + begin + // OK tready is asserted again so tlast is geting accepted this cycle along with an asserted error. + state <= EMPTY; + end else begin + // Keep error state asserted ready for downstream to accept + axis_tlast <= 1; + axis_tvalid <= 1; + axis_tuser <= {1'b1, EOF8}; // Force error in this packet. + end + end // case: ERROR1 + + + endcase // case(state) + end // else: !if(reset | clear) + +endmodule diff --git a/fpga/usrp3/lib/xge_interface/xge_handshake.v b/fpga/usrp3/lib/xge_interface/xge_handshake.v new file mode 100644 index 000000000..251099f57 --- /dev/null +++ b/fpga/usrp3/lib/xge_interface/xge_handshake.v @@ -0,0 +1,60 @@ +// +// Copyright 2013 Ettus Research LLC +// + +// +// +// Provide required handshake to Opencores XGE MAC to initiate Rx of one available packet +// +// + + +module xge_handshake + ( + input clk, + input reset, + output reg pkt_rx_ren, + input pkt_rx_avail, + input pkt_rx_eop + ); + + localparam IDLE=0; + localparam RX=1; + + reg state; + + + always @(posedge clk) + if (reset) begin + pkt_rx_ren <= 0; + state <= IDLE; + end else begin + case (state) + // + // Wait for pkt_rx_avail to be asserted, then assert pkt_rx_ren next cycle + // + IDLE: begin + if (pkt_rx_avail) begin + pkt_rx_ren <= 1; + state <= RX; + end else begin + pkt_rx_ren <= 0; + state <= IDLE; + end + end + // + // Keep pkt_rx_ren asserted until EOF received. + // + RX: begin + if (pkt_rx_eop) begin + pkt_rx_ren <= 0; + state <= IDLE; + end else begin + pkt_rx_ren <= 1; + state <= RX; + end + end + + endcase // case(state) + end // else: !if(reset) +endmodule // xge_handshake diff --git a/fpga/usrp3/lib/xge_interface/xge_mac_wrapper.v b/fpga/usrp3/lib/xge_interface/xge_mac_wrapper.v new file mode 100644 index 000000000..21c71ba37 --- /dev/null +++ b/fpga/usrp3/lib/xge_interface/xge_mac_wrapper.v @@ -0,0 +1,325 @@ +// +// Copyright 2013 Ettus Research LLC +// + + +// +// Wrap XGE MAC so that: +// +// *) Signals are crossed between the MAC's own 156.25MHz clock domain and the +// main FPGA clock domain. +// *) 6 byte Padding is added at RX, including metadata so that IP headers become aligned. +// *) 6 Byte padding is stripped at TX, so that Eth header data starts immediately. +// *) TX & RX can buffer at least an MTU sized packet +// *) On TX, to not start an Ethernet Tx until a complete packet is present in the +// last Tx FIFO so that the MAC doesn't underrun. +// + +module xge_mac_wrapper + #(parameter PORTNUM=8'd0) + + ( + // XGMII + input xgmii_clk, + output [63:0] xgmii_txd, + output [7:0] xgmii_txc, + input [63:0] xgmii_rxd, + input [7:0] xgmii_rxc, + // MDIO + output mdc, + output mdio_in, + input mdio_out, + // Wishbone I/F + input [7:0] wb_adr_i, // To wishbone_if0 of wishbone_if.v + input wb_clk_i, // To sync_clk_wb0 of sync_clk_wb.v, ... + input wb_cyc_i, // To wishbone_if0 of wishbone_if.v + input [31:0] wb_dat_i, // To wishbone_if0 of wishbone_if.v + input wb_rst_i, // To sync_clk_wb0 of sync_clk_wb.v, ... + input wb_stb_i, // To wishbone_if0 of wishbone_if.v + input wb_we_i, // To wishbone_if0 of wishbone_if.v + output wb_ack_o, // From wishbone_if0 of wishbone_if.v + output [31:0] wb_dat_o, // From wishbone_if0 of wishbone_if.v + output wb_int_o, // From wishbone_if0 of wishbone_if.v + // Client FIFO Interfaces + input sys_clk, + input reset, // From sys_clk domain. + output [63:0] rx_tdata, + output [3:0] rx_tuser, + output rx_tlast, + output rx_tvalid, + input rx_tready, + input [63:0] tx_tdata, + input [3:0] tx_tuser, // Bit[3] (error) is ignored for now. + input tx_tlast, + input tx_tvalid, + output tx_tready, + // Other + input phy_ready, + // Debug + output [31:0] debug_rx, + output [31:0] debug_tx); + + + + (* ASYNC_REG = "TRUE" *) + reg xgmii_reset_r1; + reg xgmii_reset; + + // + // Generate 156MHz synchronized reset localy + // + always @(posedge xgmii_clk or posedge reset) + begin + if (reset) begin + xgmii_reset_r1 <= 1'b1; + xgmii_reset <= 1'b1; + end + else begin + xgmii_reset_r1 <= 1'b0; // IJB. Was PLL lock here. + xgmii_reset <= xgmii_reset_r1; + end + end // always @ (posedge xgmii_clk or posedge reset) + + // + // 10G MAC + // + wire [63:0] eth_rx_data; + wire eth_rx_avail; + wire eth_rx_eof; + wire eth_rx_err; + wire [2:0] eth_rx_occ; + wire eth_rx_sof; + wire eth_rx_valid; + wire eth_rx_ren; + + wire eth_tx_full; + wire [63:0] eth_tx_data; + wire eth_tx_eof; + wire [2:0] eth_tx_occ; + wire eth_tx_sof; + wire eth_tx_valid; + + xge_mac xge_mac + ( + // Outputs + .pkt_rx_avail (eth_rx_avail), + .pkt_rx_data (eth_rx_data), + .pkt_rx_eop (eth_rx_eof), + .pkt_rx_err (eth_rx_err), + .pkt_rx_mod (eth_rx_occ), + .pkt_rx_sop (eth_rx_sof), + .pkt_rx_val (eth_rx_valid), + .pkt_tx_full (eth_tx_full), + .wb_ack_o (wb_ack_o), + .wb_dat_o (wb_dat_o), + .wb_int_o (xge_int), + .xgmii_txc (xgmii_txc[7:0]), + .xgmii_txd (xgmii_txd[63:0]), + .mdc (mdc), + .mdio_out (mdio_in),// Switch sense of in and out here for master and slave. + .mdio_tri (mdio_tri), + .xge_gpo ( ), + // Inputs + .clk_156m25 (xgmii_clk), + .clk_xgmii_rx (xgmii_clk), + .clk_xgmii_tx (xgmii_clk), + .pkt_rx_ren (eth_rx_ren), + .pkt_tx_data (eth_tx_data), + .pkt_tx_eop (eth_tx_eof), + .pkt_tx_mod (eth_tx_occ), + .pkt_tx_sop (eth_tx_sof), + .pkt_tx_val (eth_tx_valid), + .reset_156m25_n (~xgmii_reset), + .reset_xgmii_rx_n (~xgmii_reset), + .reset_xgmii_tx_n (~xgmii_reset), + .wb_adr_i (wb_adr_i[7:0]), + .wb_clk_i (wb_clk_i), + .wb_cyc_i (wb_cyc_i), + .wb_dat_i (wb_dat_i), + .wb_rst_i (wb_rst_i), + .wb_stb_i (wb_stb_i), + .wb_we_i (wb_we_i), + .xgmii_rxc (xgmii_rxc[7:0]), + .xgmii_rxd (xgmii_rxd[63:0]), + .mdio_in (mdio_out), // Switch sense of in and out here for master and slave. + .xge_gpi (/*{2'b00,align_status,mgt_tx_ready,sync_status[3:0]}*/0) + ); + + + /////////////////////////////////////////////////////////////////////////////////////// + // RX FIFO Chain + /////////////////////////////////////////////////////////////////////////////////////// + wire [63:0] rx_tdata_int; + wire [3:0] rx_tuser_int; + wire rx_talst_int; + wire rx_tvalid_int; + wire rx_tready_int; + + // + // Logic to drive pkt_rx_ren on XGE MAC + // + xge_handshake xge_handshake + ( + .clk(xgmii_clk), + .reset(xgmii_reset), + .pkt_rx_ren(eth_rx_ren), + .pkt_rx_avail(eth_rx_avail), + .pkt_rx_eop(eth_rx_eof) + ); + + // + // Add pad of 6 empty bytes before MAC addresses of new Rxed packet so that IP + // headers are alligned. Also put metadata in first octet of pad that shows + // ingress port. + // + xge64_to_axi64 #(.LABEL(PORTNUM)) xge64_to_axi64 + ( + .clk(xgmii_clk), + .reset(xgmii_reset), + .clear(clear), + .datain(eth_rx_data), + .occ(eth_rx_occ), + .sof(eth_rx_sof), + .eof(eth_rx_eof), + .err(eth_rx_err), + .valid(eth_rx_valid), + .axis_tdata(rx_tdata_int), + .axis_tuser(rx_tuser_int), + .axis_tlast(rx_tlast_int), + .axis_tvalid(rx_tvalid_int), + .axis_tready(rx_tready_int) + ); + + // + // Large FIFO must be able to run input side at 64b@156MHz to sustain 10Gb Rx. + // + + axi64_8k_2clk_fifo rxfifo_2clk + ( + .s_aresetn(~xgmii_reset), + .s_aclk(xgmii_clk), + .s_axis_tvalid(rx_tvalid_int), + .s_axis_tready(rx_tready_int), + .s_axis_tdata(rx_tdata_int), + .s_axis_tlast(rx_tlast_int), + .s_axis_tuser(rx_tuser_int), + .axis_wr_data_count(), + + .m_aclk(sys_clk), + .m_axis_tvalid(rx_tvalid), + .m_axis_tready(rx_tready), + .m_axis_tdata(rx_tdata), + .m_axis_tlast(rx_tlast), + .m_axis_tuser(rx_tuser), + .axis_rd_data_count() ); + + + /////////////////////////////////////////////////////////////////////////////////////// + // TX FIFO Chain + /////////////////////////////////////////////////////////////////////////////////////// + + wire [63:0] tx_tdata_int; + wire [3:0] tx_tuser_int; + wire tx_tlast_int; + wire tx_tvalid_int; + wire tx_tready_int; + + wire [63:0] tx_tdata_int2; + wire [3:0] tx_tuser_int2; + wire tx_tlast_int2; + wire tx_tvalid_int2; + wire tx_tready_int2; + + wire tx_tvalid_int3; + wire tx_tready_int3; + wire tx_sof_int3; + + + axi64_8k_2clk_fifo txfifo_2clk_1x + ( + .s_aresetn(~xgmii_reset), + .s_aclk(sys_clk), + .s_axis_tvalid(tx_tvalid), + .s_axis_tready(tx_tready), + .s_axis_tdata(tx_tdata), + .s_axis_tlast(tx_tlast), + .s_axis_tuser(tx_tuser), + .axis_wr_data_count(), + + .m_aclk(xgmii_clk), + .m_axis_tvalid(tx_tvalid_int), + .m_axis_tready(tx_tready_int), + .m_axis_tdata(tx_tdata_int), + .m_axis_tlast(tx_tlast_int), + .m_axis_tuser(tx_tuser_int), + .axis_rd_data_count() ); + + // + // Strip the 6 octet ethernet padding we used internally. + // Put SOF into bit[3] of tuser. + // + axi64_to_xge64 axi64_to_xge64 + ( + .clk(xgmii_clk), + .reset(xgmii_reset), + .clear(clear), + .s_axis_tdata(tx_tdata_int), + .s_axis_tuser(tx_tuser_int), + .s_axis_tlast(tx_tlast_int), + .s_axis_tvalid(tx_tvalid_int), + .s_axis_tready(tx_tready_int), + .m_axis_tdata(tx_tdata_int2), + .m_axis_tuser(tx_tuser_int2), + .m_axis_tlast(tx_tlast_int2), + .m_axis_tvalid(tx_tvalid_int2), + .m_axis_tready(tx_tready_int2) + ); + + // + // Large FIFO can hold a max sized ethernet packet. + // + axi64_8k_2clk_fifo txfifo_2clk_2 + ( + .s_aresetn(~xgmii_reset), + .s_aclk(xgmii_clk), + .s_axis_tvalid(tx_tvalid_int2), + .s_axis_tready(tx_tready_int2), + .s_axis_tdata(tx_tdata_int2), + .s_axis_tlast(tx_tlast_int2), + .s_axis_tuser(tx_tuser_int2), + .axis_wr_data_count(), + + .m_aclk(xgmii_clk), + .m_axis_tvalid(tx_tvalid_int3), + .m_axis_tready(tx_tready_int3), + .m_axis_tdata(eth_tx_data), + .m_axis_tlast(eth_tx_eof), + .m_axis_tuser({tx_sof_int3,eth_tx_occ}), + .axis_rd_data_count() ); + + // + // Monitor number of Ethernet packets in tx_fifo2 + // + axi_count_packets_in_fifo axi_count_packets_in_fifo + ( + .clk(xgmii_clk), + .reset(xgmii_reset), + .in_axis_tvalid(tx_tvalid_int2), + .in_axis_tready(tx_tready_int2), + .in_axis_tlast(tx_tlast_int2), + .out_axis_tvalid(tx_tvalid_int3), + .out_axis_tready(tx_tready_int3), + .out_axis_tlast(eth_tx_eof), + .pkt_tx_full(eth_tx_full), + .enable_tx(enable_tx) ); + + // + // + // Supress FIFO flags to stop overflow of MAC in Tx direction + // + assign eth_tx_valid = tx_tvalid_int3 & enable_tx; + assign tx_tready_int3 = enable_tx; + assign eth_tx_sof = tx_sof_int3 & enable_tx; + + +endmodule |