diff --git a/src/zircon/rtl/zircon_ip_rx_egress.sv b/src/zircon/rtl/zircon_ip_rx_egress.sv new file mode 100644 index 0000000..eebe6b2 --- /dev/null +++ b/src/zircon/rtl/zircon_ip_rx_egress.sv @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Zircon IP stack - RX egress module + */ +module zircon_ip_rx_egress # +( + parameter N_UI = 4 +) +( + input wire logic clk, + input wire logic rst, + + /* + * Internal interfaces + */ + taxi_axis_if.snk s_axis_pkt, + + /* + * Client user interface + */ + input wire logic ui_clk, + input wire logic ui_rst, + taxi_axis_if.src m_axis_ui_rx +); + +localparam UI_DATA_W = m_axis_ui_rx.DATA_W; +localparam DATA_W = s_axis_pkt.DATA_W; + +// RX FIFO +taxi_axis_async_fifo #( + .DEPTH((UI_DATA_W > DATA_W ? UI_DATA_W : DATA_W)/8*32), + .RAM_PIPELINE(1), + .OUTPUT_FIFO_EN(1'b0), + .FRAME_FIFO(1'b0), + .USER_BAD_FRAME_VALUE(1'b1), + .USER_BAD_FRAME_MASK(1'b1), + .DROP_OVERSIZE_FRAME(1'b0), + .DROP_BAD_FRAME(1'b0), + .DROP_WHEN_FULL(1'b0), + .MARK_WHEN_FULL(1'b0), + .PAUSE_EN(1'b0) +) +rx_fifo_inst ( + /* + * AXI4-Stream input (sink) + */ + .s_clk(clk), + .s_rst(rst), + .s_axis(s_axis_pkt), + + /* + * AXI4-Stream output (source) + */ + .m_clk(ui_clk), + .m_rst(ui_rst), + .m_axis(m_axis_ui_rx), + + /* + * Pause + */ + .s_pause_req(1'b0), + .s_pause_ack(), + .m_pause_req(1'b0), + .m_pause_ack(), + + /* + * Status + */ + .s_status_depth(), + .s_status_depth_commit(), + .s_status_overflow(), + .s_status_bad_frame(), + .s_status_good_frame(), + .m_status_depth(), + .m_status_depth_commit(), + .m_status_overflow(), + .m_status_bad_frame(), + .m_status_good_frame() +); + +endmodule + +`resetall diff --git a/src/zircon/rtl/zircon_ip_rx_ingress.sv b/src/zircon/rtl/zircon_ip_rx_ingress.sv new file mode 100644 index 0000000..dd1fb92 --- /dev/null +++ b/src/zircon/rtl/zircon_ip_rx_ingress.sv @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Zircon IP stack - RX ingress module + */ +module zircon_ip_rx_ingress # +( + parameter logic IPV6_EN = 1'b1, + parameter logic HASH_EN = 1'b1 +) +( + input wire logic clk, + input wire logic rst, + + /* + * MAC interfaces + */ + input wire logic mac_rx_clk, + input wire logic mac_rx_rst, + taxi_axis_if.snk s_axis_mac_rx, + + /* + * Internal interfaces + */ + taxi_axis_if.src m_axis_pkt, + taxi_axis_if.src m_axis_meta_hdr, + taxi_axis_if.src m_axis_meta_len +); + +localparam MAC_DATA_W = s_axis_mac_rx.DATA_W; +localparam RX_USER_W = s_axis_mac_rx.USER_W; +localparam DATA_W = m_axis_pkt.DATA_W; +localparam META_DATA_W = m_axis_meta_hdr.DATA_W; + +taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(RX_USER_W)) mac_rx_int(); +taxi_axis_if #(.DATA_W(32), .USER_EN(1), .USER_W(RX_USER_W)) rx_pkt_hdr(); +taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(RX_USER_W)) rx_bcast_int[2](); + +taxi_axis_async_fifo_adapter #( + .DEPTH((MAC_DATA_W > DATA_W ? MAC_DATA_W : DATA_W)/8*32), + .RAM_PIPELINE(1), + .OUTPUT_FIFO_EN(1'b0), + .FRAME_FIFO(1'b0), + .USER_BAD_FRAME_VALUE(1'b1), + .USER_BAD_FRAME_MASK(1'b1), + .DROP_OVERSIZE_FRAME(1'b0), + .DROP_BAD_FRAME(1'b0), + .DROP_WHEN_FULL(1'b0), + .MARK_WHEN_FULL(1'b1), + .PAUSE_EN(1'b0) +) +rx_fifo_inst ( + /* + * AXI4-Stream input (sink) + */ + .s_clk(mac_rx_clk), + .s_rst(mac_rx_rst), + .s_axis(s_axis_mac_rx), + + /* + * AXI4-Stream output (source) + */ + .m_clk(clk), + .m_rst(rst), + .m_axis(mac_rx_int), + + /* + * Pause + */ + .s_pause_req(1'b0), + .s_pause_ack(), + .m_pause_req(1'b0), + .m_pause_ack(), + + /* + * Status + */ + .s_status_depth(), + .s_status_depth_commit(), + .s_status_overflow(), + .s_status_bad_frame(), + .s_status_good_frame(), + .m_status_depth(), + .m_status_depth_commit(), + .m_status_overflow(), + .m_status_bad_frame(), + .m_status_good_frame() +); + +taxi_axis_broadcast #( + .M_COUNT($size(rx_bcast_int)) +) +rx_broadcast_inst ( + .clk(clk), + .rst(rst), + + /* + * AXI4-Stream input (sink) + */ + .s_axis(mac_rx_int), + + /* + * AXI4-Stream outputs (sources) + */ + .m_axis(rx_bcast_int) +); + +zircon_ip_len_cksum #( + .START_OFFSET(14) +) +rx_len_cksum_inst ( + .clk(clk), + .rst(rst), + + /* + * Packet passthrough + */ + .s_axis_pkt(rx_bcast_int[0]), + .m_axis_pkt(m_axis_pkt), + + /* + * Packet metadata output + */ + .m_axis_meta(m_axis_meta_len) +); + +taxi_axis_adapter +hdr_adapter_inst ( + .clk(clk), + .rst(rst), + + /* + * AXI4-Stream input (sink) + */ + .s_axis(rx_bcast_int[1]), + + /* + * AXI4-Stream output (source) + */ + .m_axis(rx_pkt_hdr) +); + +zircon_ip_rx_parse #( + .IPV6_EN(IPV6_EN), + .HASH_EN(HASH_EN) +) +rx_parse_inst ( + .clk(clk), + .rst(rst), + + /* + * Packet header input + */ + .s_axis_pkt(rx_pkt_hdr), + + /* + * Packet metadata output + */ + .m_axis_meta(m_axis_meta_hdr) +); + +endmodule + +`resetall diff --git a/src/zircon/rtl/zircon_ip_tx_egress.sv b/src/zircon/rtl/zircon_ip_tx_egress.sv new file mode 100644 index 0000000..f3ccc21 --- /dev/null +++ b/src/zircon/rtl/zircon_ip_tx_egress.sv @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Zircon IP stack - TX egress module + */ +module zircon_ip_tx_egress # +( + parameter logic IPV6_EN = 1'b1 +) +( + input wire logic clk, + input wire logic rst, + + /* + * Internal interfaces + */ + taxi_axis_if.snk s_axis_pkt, + taxi_axis_if.snk s_axis_meta, + + /* + * MAC interfaces + */ + input wire logic mac_tx_clk, + input wire logic mac_tx_rst, + taxi_axis_if.src m_axis_mac_tx, + taxi_axis_if.snk s_axis_mac_tx_cpl +); + +localparam MAC_DATA_W = m_axis_mac_tx.DATA_W; +localparam TX_USER_W = m_axis_mac_tx.USER_W; +localparam TX_TAG_W = m_axis_mac_tx.ID_W; +localparam DATA_W = s_axis_pkt.DATA_W; +localparam META_DATA_W = s_axis_meta.DATA_W; + +taxi_axis_if #(.DATA_W(32), .USER_EN(1), .USER_W(TX_USER_W), .ID_EN(1), .ID_W(TX_TAG_W)) tx_pkt_hdr(); +taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(TX_USER_W), .ID_EN(1), .ID_W(TX_TAG_W)) pkt_parts[2](); +taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(TX_USER_W), .ID_EN(1), .ID_W(TX_TAG_W)) mac_tx_int(); + +// build header +zircon_ip_tx_deparse #( + .IPV6_EN(IPV6_EN) +) +tx_deparse_inst ( + .clk(clk), + .rst(rst), + + /* + * Packet metadata input + */ + .s_axis_meta(s_axis_meta), + + /* + * Packet header output + */ + .m_axis_pkt(tx_pkt_hdr) +); + +taxi_axis_adapter +hdr_adapter_inst ( + .clk(clk), + .rst(rst), + + /* + * AXI4-Stream input (sink) + */ + .s_axis(tx_pkt_hdr), + + /* + * AXI4-Stream output (source) + */ + .m_axis(pkt_parts[0]) +); + +assign pkt_parts[1].tdata = s_axis_pkt.tdata; +assign pkt_parts[1].tkeep = s_axis_pkt.tkeep; +assign pkt_parts[1].tstrb = s_axis_pkt.tstrb; +assign pkt_parts[1].tvalid = s_axis_pkt.tvalid; +assign pkt_parts[1].tlast = s_axis_pkt.tlast; +assign pkt_parts[1].tid = s_axis_pkt.tid; +assign pkt_parts[1].tdest = s_axis_pkt.tdest; +assign pkt_parts[1].tuser = s_axis_pkt.tuser; + +assign s_axis_pkt.tready = pkt_parts[1].tready; + +// combine header and payload +taxi_axis_concat #( + .S_COUNT(2) +) +tx_hdr_concat_inst ( + .clk(clk), + .rst(rst), + + + /* + * AXI4-Stream inputs (sinks) + */ + .s_axis(pkt_parts), + + /* + * AXI4-Stream output (source) + */ + .m_axis(mac_tx_int) +); + +// TX FIFO +taxi_axis_async_fifo #( + .DEPTH((MAC_DATA_W > DATA_W ? MAC_DATA_W : DATA_W)/8*32), + .RAM_PIPELINE(1), + .OUTPUT_FIFO_EN(1'b0), + .FRAME_FIFO(1'b1), + .USER_BAD_FRAME_VALUE(1'b1), + .USER_BAD_FRAME_MASK(1'b1), + .DROP_OVERSIZE_FRAME(1'b0), + .DROP_BAD_FRAME(1'b0), + .DROP_WHEN_FULL(1'b0), + .MARK_WHEN_FULL(1'b0), + .PAUSE_EN(1'b0) +) +tx_fifo_inst ( + /* + * AXI4-Stream input (sink) + */ + .s_clk(clk), + .s_rst(rst), + .s_axis(mac_tx_int), + + /* + * AXI4-Stream output (source) + */ + .m_clk(mac_tx_clk), + .m_rst(mac_tx_rst), + .m_axis(m_axis_mac_tx), + + /* + * Pause + */ + .s_pause_req(1'b0), + .s_pause_ack(), + .m_pause_req(1'b0), + .m_pause_ack(), + + /* + * Status + */ + .s_status_depth(), + .s_status_depth_commit(), + .s_status_overflow(), + .s_status_bad_frame(), + .s_status_good_frame(), + .m_status_depth(), + .m_status_depth_commit(), + .m_status_overflow(), + .m_status_bad_frame(), + .m_status_good_frame() +); + +endmodule + +`resetall diff --git a/src/zircon/rtl/zircon_ip_tx_ingress.sv b/src/zircon/rtl/zircon_ip_tx_ingress.sv new file mode 100644 index 0000000..5755a9d --- /dev/null +++ b/src/zircon/rtl/zircon_ip_tx_ingress.sv @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Zircon IP stack - TX ingress module + */ +module zircon_ip_tx_ingress # +( + parameter N_UI = 4 +) +( + input wire logic clk, + input wire logic rst, + + /* + * Client user interface + */ + input wire logic ui_clk, + input wire logic ui_rst, + taxi_axis_if.snk s_axis_ui_tx, + taxi_axis_if.src m_axis_ui_tx_cpl, + + /* + * Internal interfaces + */ + taxi_axis_if.src m_axis_pkt +); + +localparam UI_DATA_W = s_axis_ui_tx.DATA_W; +localparam DATA_W = m_axis_pkt.DATA_W; + +// TX FIFO +taxi_axis_async_fifo #( + .DEPTH((UI_DATA_W > DATA_W ? UI_DATA_W : DATA_W)/8*32), + .RAM_PIPELINE(1), + .OUTPUT_FIFO_EN(1'b0), + .FRAME_FIFO(1'b0), + .USER_BAD_FRAME_VALUE(1'b1), + .USER_BAD_FRAME_MASK(1'b1), + .DROP_OVERSIZE_FRAME(1'b0), + .DROP_BAD_FRAME(1'b0), + .DROP_WHEN_FULL(1'b0), + .MARK_WHEN_FULL(1'b0), + .PAUSE_EN(1'b0) +) +tx_fifo_inst ( + /* + * AXI4-Stream input (sink) + */ + .s_clk(ui_clk), + .s_rst(ui_rst), + .s_axis(s_axis_ui_tx), + + /* + * AXI4-Stream output (source) + */ + .m_clk(clk), + .m_rst(rst), + .m_axis(m_axis_pkt), + + /* + * Pause + */ + .s_pause_req(1'b0), + .s_pause_ack(), + .m_pause_req(1'b0), + .m_pause_ack(), + + /* + * Status + */ + .s_status_depth(), + .s_status_depth_commit(), + .s_status_overflow(), + .s_status_bad_frame(), + .s_status_good_frame(), + .m_status_depth(), + .m_status_depth_commit(), + .m_status_overflow(), + .m_status_bad_frame(), + .m_status_good_frame() +); + +endmodule + +`resetall