diff --git a/example/KCU116/fpga_10g/Makefile b/example/KCU116/fpga_10g/Makefile new file mode 100644 index 000000000..f504bd06f --- /dev/null +++ b/example/KCU116/fpga_10g/Makefile @@ -0,0 +1,25 @@ +# Targets +TARGETS:= + +# Subdirectories +SUBDIRS = fpga +SUBDIRS_CLEAN = $(patsubst %,%.clean,$(SUBDIRS)) + +# Rules +.PHONY: all +all: $(SUBDIRS) $(TARGETS) + +.PHONY: $(SUBDIRS) +$(SUBDIRS): + cd $@ && $(MAKE) + +.PHONY: $(SUBDIRS_CLEAN) +$(SUBDIRS_CLEAN): + cd $(@:.clean=) && $(MAKE) clean + +.PHONY: clean +clean: $(SUBDIRS_CLEAN) + -rm -rf $(TARGETS) + +program: + #djtgcfg prog -d Atlys --index 0 --file fpga/fpga.bit diff --git a/example/KCU116/fpga_10g/README.md b/example/KCU116/fpga_10g/README.md new file mode 100644 index 000000000..84c85c385 --- /dev/null +++ b/example/KCU116/fpga_10g/README.md @@ -0,0 +1,37 @@ +# Verilog Ethernet Xilinx KCU116 Example Design + +## Introduction + +This example design targets the Xilinx Kintex UltraScale+ KCU116 FPGA board. + +The design by default listens to UDP port 1234 at IP address 192.168.1.128 and +will echo back any packets received. The design will also respond correctly to +ARP requests. Only SFP0 works by default. + +The reference clock for the GTY transceiver connected to the SFPs is generated +by an external, on-board Si5328 clock chip which must be configured to output a +clock signal of 156.25MHz before the transceiver can be used. This configuration +is performed through the onboard Zynq-based baseboard management +controller. Software for configuring the Zynq BMC and setting the proper clock +frequencies can be found on Xilinx' website. + +* FPGA: XCKU5P-2FFVB676E +* PHY: 10G BASE-R PHY IP core and internal GTY transceiver + +## How to build + +Run make to build. Ensure that the Xilinx Vivado toolchain components are in +PATH. + +## How to test + +Run make program to program the NetFPGA SUME board with Vivado. Then run + + netcat -u 192.168.1.128 1234 + +to open a UDP connection to port 1234. Any text entered into netcat will be +echoed back after pressing enter. + +It is also possible to use hping to test the design by running + + hping 192.168.1.128 -2 -p 1234 -d 1024 diff --git a/example/KCU116/fpga_10g/common/vivado.mk b/example/KCU116/fpga_10g/common/vivado.mk new file mode 100644 index 000000000..83bcb8d90 --- /dev/null +++ b/example/KCU116/fpga_10g/common/vivado.mk @@ -0,0 +1,123 @@ +################################################################### +# +# Xilinx Vivado FPGA Makefile +# +# Copyright (c) 2016 Alex Forencich +# +################################################################### +# +# Parameters: +# FPGA_TOP - Top module name +# FPGA_FAMILY - FPGA family (e.g. VirtexUltrascale) +# FPGA_DEVICE - FPGA device (e.g. xcvu095-ffva2104-2-e) +# SYN_FILES - space-separated list of source files +# INC_FILES - space-separated list of include files +# XDC_FILES - space-separated list of timing constraint files +# XCI_FILES - space-separated list of IP XCI files +# +# Example: +# +# FPGA_TOP = fpga +# FPGA_FAMILY = VirtexUltrascale +# FPGA_DEVICE = xcvu095-ffva2104-2-e +# SYN_FILES = rtl/fpga.v +# XDC_FILES = fpga.xdc +# XCI_FILES = ip/pcspma.xci +# include ../common/vivado.mk +# +################################################################### + +# phony targets +.PHONY: clean fpga + +# prevent make from deleting intermediate files and reports +.PRECIOUS: %.xpr %.bit %.mcs %.prm +.SECONDARY: + +CONFIG ?= config.mk +-include ../$(CONFIG) + +SYN_FILES_REL = $(patsubst %, ../%, $(SYN_FILES)) +INC_FILES_REL = $(patsubst %, ../%, $(INC_FILES)) +XCI_FILES_REL = $(patsubst %, ../%, $(XCI_FILES)) +IP_TCL_FILES_REL = $(patsubst %, ../%, $(IP_TCL_FILES)) + +ifdef XDC_FILES + XDC_FILES_REL = $(patsubst %, ../%, $(XDC_FILES)) +else + XDC_FILES_REL = $(FPGA_TOP).xdc +endif + +################################################################### +# Main Targets +# +# all: build everything +# clean: remove output files and project files +################################################################### + +all: fpga + +fpga: $(FPGA_TOP).bit + +vivado: $(FPGA_TOP).xpr + vivado $(FPGA_TOP).xpr + +tmpclean: + -rm -rf *.log *.jou *.cache *.gen *.hbs *.hw *.ip_user_files *.runs *.xpr *.html *.xml *.sim *.srcs *.str .Xil defines.v + -rm -rf create_project.tcl run_synth.tcl run_impl.tcl generate_bit.tcl + +clean: tmpclean + -rm -rf *.bit program.tcl generate_mcs.tcl *.mcs *.prm flash.tcl + +distclean: clean + -rm -rf rev + +################################################################### +# Target implementations +################################################################### + +# Vivado project file +%.xpr: Makefile $(XCI_FILES_REL) $(IP_TCL_FILES_REL) + rm -rf defines.v + touch defines.v + for x in $(DEFS); do echo '`define' $$x >> defines.v; done + echo "create_project -force -part $(FPGA_PART) $*" > create_project.tcl + echo "add_files -fileset sources_1 defines.v" >> create_project.tcl + for x in $(SYN_FILES_REL); do echo "add_files -fileset sources_1 $$x" >> create_project.tcl; done + for x in $(XDC_FILES_REL); do echo "add_files -fileset constrs_1 $$x" >> create_project.tcl; done + for x in $(XCI_FILES_REL); do echo "import_ip $$x" >> create_project.tcl; done + for x in $(IP_TCL_FILES_REL); do echo "source $$x" >> create_project.tcl; done + echo "exit" >> create_project.tcl + vivado -nojournal -nolog -mode batch -source create_project.tcl + +# synthesis run +%.runs/synth_1/%.dcp: %.xpr $(SYN_FILES_REL) $(INC_FILES_REL) $(XDC_FILES_REL) + echo "open_project $*.xpr" > run_synth.tcl + echo "reset_run synth_1" >> run_synth.tcl + echo "launch_runs -jobs 4 synth_1" >> run_synth.tcl + echo "wait_on_run synth_1" >> run_synth.tcl + echo "exit" >> run_synth.tcl + vivado -nojournal -nolog -mode batch -source run_synth.tcl + +# implementation run +%.runs/impl_1/%_routed.dcp: %.runs/synth_1/%.dcp + echo "open_project $*.xpr" > run_impl.tcl + echo "reset_run impl_1" >> run_impl.tcl + echo "launch_runs -jobs 4 impl_1" >> run_impl.tcl + echo "wait_on_run impl_1" >> run_impl.tcl + echo "exit" >> run_impl.tcl + vivado -nojournal -nolog -mode batch -source run_impl.tcl + +# bit file +%.bit: %.runs/impl_1/%_routed.dcp + echo "open_project $*.xpr" > generate_bit.tcl + echo "open_run impl_1" >> generate_bit.tcl + echo "write_bitstream -force $*.bit" >> generate_bit.tcl + echo "exit" >> generate_bit.tcl + vivado -nojournal -nolog -mode batch -source generate_bit.tcl + mkdir -p rev + EXT=bit; COUNT=100; \ + while [ -e rev/$*_rev$$COUNT.$$EXT ]; \ + do COUNT=$$((COUNT+1)); done; \ + cp $@ rev/$*_rev$$COUNT.$$EXT; \ + echo "Output: rev/$*_rev$$COUNT.$$EXT"; diff --git a/example/KCU116/fpga_10g/fpga.xdc b/example/KCU116/fpga_10g/fpga.xdc new file mode 100644 index 000000000..d340c521f --- /dev/null +++ b/example/KCU116/fpga_10g/fpga.xdc @@ -0,0 +1,67 @@ +# XDC constraints for the Xilinx Kintex UltraScale+ KCU116 +# part: xcku5p-ffvb676-2-e + +# General configuration +set_property CFGBVS GND [current_design] +set_property BITSTREAM.GENERAL.COMPRESS true [current_design] + +# 300MHz sysclk +set_property -dict {LOC K22 IOSTANDARD DIFF_SSTL12 } [get_ports clk_300mhz_p]; +set_property -dict {LOC K23 IOSTANDARD DIFF_SSTL12 } [get_ports clk_300mhz_n]; + +# LEDs +set_property -dict {LOC C9 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12} [get_ports {user_led[0]}] +set_property -dict {LOC D9 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12} [get_ports {user_led[1]}] +set_property -dict {LOC E10 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12} [get_ports {user_led[2]}] +set_property -dict {LOC E11 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12} [get_ports {user_led[3]}] +set_property -dict {LOC F9 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12} [get_ports {user_led[4]}] +set_property -dict {LOC F10 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12} [get_ports {user_led[5]}] +set_property -dict {LOC G9 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12} [get_ports {user_led[6]}] +set_property -dict {LOC G10 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12} [get_ports {user_led[7]}] + +set_false_path -to [get_ports {user_led[*]}] +set_output_delay 0 [get_ports {user_led[*]}] + +# SFP Interfaces +set_property -dict {LOC M2 } [get_ports sfp_0_rx_p]; +set_property -dict {LOC M1 } [get_ports sfp_0_rx_n]; +set_property -dict {LOC N5 } [get_ports sfp_0_tx_p]; +set_property -dict {LOC N4 } [get_ports sfp_0_tx_n]; +set_property -dict {LOC AB14 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12} [get_ports sfp_0_tx_disable_n] + +set_property -dict {LOC K2 } [get_ports sfp_1_rx_p]; +set_property -dict {LOC K1 } [get_ports sfp_1_rx_n]; +set_property -dict {LOC L5 } [get_ports sfp_1_tx_p]; +set_property -dict {LOC L4 } [get_ports sfp_1_tx_n]; +set_property -dict {LOC AA14 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12} [get_ports sfp_1_tx_disable_n] + +set_property -dict {LOC H2 } [get_ports sfp_2_rx_p]; +set_property -dict {LOC H1 } [get_ports sfp_2_rx_n]; +set_property -dict {LOC J5 } [get_ports sfp_2_tx_p]; +set_property -dict {LOC J4 } [get_ports sfp_2_tx_n]; +set_property -dict {LOC AA15 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12} [get_ports sfp_2_tx_disable_n] + +set_property -dict {LOC F2 } [get_ports sfp_3_rx_p]; +set_property -dict {LOC F1 } [get_ports sfp_3_rx_n]; +set_property -dict {LOC G5 } [get_ports sfp_3_tx_p]; +set_property -dict {LOC G4 } [get_ports sfp_3_tx_n]; +set_property -dict {LOC Y15 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12} [get_ports sfp_3_tx_disable_n] + +set_property -dict {LOC P7 } [get_ports sfp_mgt_refclk_p]; # Bank 226 - MGTREFCLK0P_226 +set_property -dict {LOC P6 } [get_ports sfp_mgt_refclk_n]; # Bank 226 - MGTREFCLK0N_226 + +# 156.25 MHz MGT reference clock +create_clock -period 6.4 -name sfp_mgt_refclk [get_ports sfp_mgt_refclk_p] + +set_false_path -to [get_ports { \ + sfp_3_tx_disable_n \ + sfp_2_tx_disable_n \ + sfp_1_tx_disable_n \ + sfp_0_tx_disable_n \ +}] +set_output_delay 0 [get_ports { \ + sfp_3_tx_disable_n \ + sfp_2_tx_disable_n \ + sfp_1_tx_disable_n \ + sfp_0_tx_disable_n \ +}] diff --git a/example/KCU116/fpga_10g/fpga/Makefile b/example/KCU116/fpga_10g/fpga/Makefile new file mode 100644 index 000000000..3b6327cf3 --- /dev/null +++ b/example/KCU116/fpga_10g/fpga/Makefile @@ -0,0 +1,58 @@ + +# FPGA settings +FPGA_PART = xcku5p-ffvb676-2-e +FPGA_TOP = fpga +FPGA_ARCH = kintexuplus + +# Files for synthesis +SYN_FILES = rtl/fpga.v +SYN_FILES += rtl/fpga_core.v +SYN_FILES += lib/eth/rtl/eth_mac_10g_fifo.v +SYN_FILES += lib/eth/rtl/eth_mac_10g.v +SYN_FILES += lib/eth/rtl/axis_xgmii_rx_64.v +SYN_FILES += lib/eth/rtl/axis_xgmii_tx_64.v +SYN_FILES += lib/eth/rtl/eth_phy_10g.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_rx.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_rx_if.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_rx_frame_sync.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_rx_ber_mon.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_tx.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_tx_if.v +SYN_FILES += lib/eth/rtl/xgmii_baser_dec_64.v +SYN_FILES += lib/eth/rtl/xgmii_baser_enc_64.v +SYN_FILES += lib/eth/rtl/lfsr.v +SYN_FILES += lib/eth/rtl/eth_axis_rx.v +SYN_FILES += lib/eth/rtl/eth_axis_tx.v +SYN_FILES += lib/eth/rtl/udp_complete_64.v +SYN_FILES += lib/eth/rtl/udp_checksum_gen_64.v +SYN_FILES += lib/eth/rtl/udp_64.v +SYN_FILES += lib/eth/rtl/udp_ip_rx_64.v +SYN_FILES += lib/eth/rtl/udp_ip_tx_64.v +SYN_FILES += lib/eth/rtl/ip_complete_64.v +SYN_FILES += lib/eth/rtl/ip_64.v +SYN_FILES += lib/eth/rtl/ip_eth_rx_64.v +SYN_FILES += lib/eth/rtl/ip_eth_tx_64.v +SYN_FILES += lib/eth/rtl/ip_arb_mux.v +SYN_FILES += lib/eth/rtl/arp.v +SYN_FILES += lib/eth/rtl/arp_cache.v +SYN_FILES += lib/eth/rtl/arp_eth_rx.v +SYN_FILES += lib/eth/rtl/arp_eth_tx.v +SYN_FILES += lib/eth/rtl/eth_arb_mux.v +SYN_FILES += lib/eth/lib/axis/rtl/arbiter.v +SYN_FILES += lib/eth/lib/axis/rtl/priority_encoder.v +SYN_FILES += lib/eth/lib/axis/rtl/axis_fifo.v +SYN_FILES += lib/eth/lib/axis/rtl/axis_register.v +SYN_FILES += lib/eth/lib/axis/rtl/axis_async_fifo.v +SYN_FILES += lib/eth/lib/axis/rtl/axis_async_fifo_adapter.v +SYN_FILES += lib/eth/lib/axis/rtl/sync_reset.v + +# XDC files +XDC_FILES = fpga.xdc +XDC_FILES += lib/eth/syn/vivado/eth_mac_fifo.tcl +XDC_FILES += lib/eth/lib/axis/syn/vivado/axis_async_fifo.tcl +XDC_FILES += lib/eth/lib/axis/syn/vivado/sync_reset.tcl + +# IP +IP_TCL_FILES = ip/gtwizard_ultrascale_0.tcl + +include ../common/vivado.mk diff --git a/example/KCU116/fpga_10g/ip/gtwizard_ultrascale_0.tcl b/example/KCU116/fpga_10g/ip/gtwizard_ultrascale_0.tcl new file mode 100644 index 000000000..a879269cc --- /dev/null +++ b/example/KCU116/fpga_10g/ip/gtwizard_ultrascale_0.tcl @@ -0,0 +1,23 @@ + +create_ip -name gtwizard_ultrascale -vendor xilinx.com -library ip -module_name gtwizard_ultrascale_0 + +set_property -dict [list CONFIG.preset {GTY-10GBASE-R}] [get_ips gtwizard_ultrascale_0] + +set_property -dict [list \ + CONFIG.CHANNEL_ENABLE {X0Y11 X0Y10 X0Y9 X0Y8} \ + CONFIG.TX_MASTER_CHANNEL {X0Y8} \ + CONFIG.RX_MASTER_CHANNEL {X0Y8} \ + CONFIG.TX_LINE_RATE {10.3125} \ + CONFIG.TX_REFCLK_FREQUENCY {156.25} \ + CONFIG.TX_USER_DATA_WIDTH {64} \ + CONFIG.TX_INT_DATA_WIDTH {64} \ + CONFIG.RX_LINE_RATE {10.3125} \ + CONFIG.RX_REFCLK_FREQUENCY {156.25} \ + CONFIG.RX_USER_DATA_WIDTH {64} \ + CONFIG.RX_INT_DATA_WIDTH {64} \ + CONFIG.RX_REFCLK_SOURCE {X0Y11 clk0 X0Y10 clk0 X0Y9 clk0 X0Y8 clk0} \ + CONFIG.TX_REFCLK_SOURCE {X0Y11 clk0 X0Y10 clk0 X0Y9 clk0 X0Y8 clk0} \ + CONFIG.FREERUN_FREQUENCY {125} \ + CONFIG.ENABLE_OPTIONAL_PORTS {rxpolarity_in txpolarity_in} \ +] [get_ips gtwizard_ultrascale_0] + diff --git a/example/KCU116/fpga_10g/lib/eth b/example/KCU116/fpga_10g/lib/eth new file mode 120000 index 000000000..11a54ed36 --- /dev/null +++ b/example/KCU116/fpga_10g/lib/eth @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/example/KCU116/fpga_10g/rtl/fpga.v b/example/KCU116/fpga_10g/rtl/fpga.v new file mode 100644 index 000000000..d9b492c7f --- /dev/null +++ b/example/KCU116/fpga_10g/rtl/fpga.v @@ -0,0 +1,678 @@ +/* + +Copyright (c) 2021 Leon Schuermann + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * FPGA top-level module + */ +module fpga ( + /* + * Clock: 300MHz LVDS + */ + input wire clk_300mhz_p, + input wire clk_300mhz_n, + + /* + * GPIO + */ + output wire [7:0] user_led, + + /* + * Ethernet: SFP+ + */ + input wire sfp_0_rx_p, + input wire sfp_0_rx_n, + output wire sfp_0_tx_p, + output wire sfp_0_tx_n, + output wire sfp_0_tx_disable_n, + + input wire sfp_1_rx_p, + input wire sfp_1_rx_n, + output wire sfp_1_tx_p, + output wire sfp_1_tx_n, + output wire sfp_1_tx_disable_n, + + input wire sfp_2_rx_p, + input wire sfp_2_rx_n, + output wire sfp_2_tx_p, + output wire sfp_2_tx_n, + output wire sfp_2_tx_disable_n, + + input wire sfp_3_rx_p, + input wire sfp_3_rx_n, + output wire sfp_3_tx_p, + output wire sfp_3_tx_n, + output wire sfp_3_tx_disable_n, + + input wire sfp_mgt_refclk_p, + input wire sfp_mgt_refclk_n +); + +// Clock and reset + +// Internal 125 MHz clock +wire clk_125mhz_mmcm_out; +wire clk_125mhz_int; +wire rst_125mhz_int; + +// Internal 156.25 MHz clock +wire clk_156mhz_int; +wire rst_156mhz_int; + +wire mmcm_rst = 1'b0; +wire mmcm_locked; +wire mmcm_clkfb; + +IBUFGDS #( + .DIFF_TERM("FALSE"), + .IBUF_LOW_PWR("FALSE") +) +clk_300mhz_ibufg_inst ( + .O (clk_300mhz_ibufg), + .I (clk_300mhz_p), + .IB (clk_300mhz_n) +); + + +// MMCM instance +// 300 MHz in, 125 MHz out +// PFD range: 10 MHz to 500 MHz +// VCO range: 800 MHz to 1600 MHz +// M = 64, D = 11 sets Fvco = 937.5 MHz (in range) +// Divide by 7.5 to get output frequency of 125 MHz +MMCME2_BASE #( + .BANDWIDTH("OPTIMIZED"), + .CLKOUT0_DIVIDE_F(8), + .CLKOUT0_DUTY_CYCLE(0.5), + .CLKOUT0_PHASE(0), + .CLKOUT1_DIVIDE(1), + .CLKOUT1_DUTY_CYCLE(0.5), + .CLKOUT1_PHASE(0), + .CLKOUT2_DIVIDE(1), + .CLKOUT2_DUTY_CYCLE(0.5), + .CLKOUT2_PHASE(0), + .CLKOUT3_DIVIDE(1), + .CLKOUT3_DUTY_CYCLE(0.5), + .CLKOUT3_PHASE(0), + .CLKOUT4_DIVIDE(1), + .CLKOUT4_DUTY_CYCLE(0.5), + .CLKOUT4_PHASE(0), + .CLKOUT5_DIVIDE(1), + .CLKOUT5_DUTY_CYCLE(0.5), + .CLKOUT5_PHASE(0), + .CLKOUT6_DIVIDE(1), + .CLKOUT6_DUTY_CYCLE(0.5), + .CLKOUT6_PHASE(0), + .CLKFBOUT_MULT_F(10), + .CLKFBOUT_PHASE(0), + .DIVCLK_DIVIDE(3), + .REF_JITTER1(0.010), + .CLKIN1_PERIOD(3.333), + .STARTUP_WAIT("FALSE"), + .CLKOUT4_CASCADE("FALSE") +) +clk_mmcm_inst ( + .CLKIN1(clk_300mhz_ibufg), + .CLKFBIN(mmcm_clkfb), + .RST(mmcm_rst), + .PWRDWN(1'b0), + .CLKOUT0(clk_125mhz_mmcm_out), + .CLKOUT0B(), + .CLKOUT1(), + .CLKOUT1B(), + .CLKOUT2(), + .CLKOUT2B(), + .CLKOUT3(), + .CLKOUT3B(), + .CLKOUT4(), + .CLKOUT5(), + .CLKOUT6(), + .CLKFBOUT(mmcm_clkfb), + .CLKFBOUTB(), + .LOCKED(mmcm_locked) +); + +BUFG +clk_125mhz_bufg_inst ( + .I(clk_125mhz_mmcm_out), + .O(clk_125mhz_int) +); + +sync_reset #( + .N(4) +) +sync_reset_125mhz_inst ( + .clk(clk_125mhz_int), + .rst(~mmcm_locked), + .out(rst_125mhz_int) +); + +// GPIO +wire [1:0] sfp_0_led_int; +wire [1:0] sfp_1_led_int; +wire [1:0] sfp_2_led_int; +wire [1:0] sfp_3_led_int; + +// What to do with this LED? We don't have any more physical LEDs +// available on the board. +wire [1:0] sma_led_int; + +// XGMII 10G PHY + +assign sfp_0_tx_disable_n = 1'b1; +assign sfp_1_tx_disable_n = 1'b1; +assign sfp_2_tx_disable_n = 1'b1; +assign sfp_3_tx_disable_n = 1'b1; + +wire sfp_0_tx_clk_int; +wire sfp_0_tx_rst_int; +wire [63:0] sfp_0_txd_int; +wire [7:0] sfp_0_txc_int; +wire sfp_0_rx_clk_int; +wire sfp_0_rx_rst_int; +wire [63:0] sfp_0_rxd_int; +wire [7:0] sfp_0_rxc_int; +wire sfp_1_tx_clk_int; +wire sfp_1_tx_rst_int; +wire [63:0] sfp_1_txd_int; +wire [7:0] sfp_1_txc_int; +wire sfp_1_rx_clk_int; +wire sfp_1_rx_rst_int; +wire [63:0] sfp_1_rxd_int; +wire [7:0] sfp_1_rxc_int; +wire sfp_2_tx_clk_int; +wire sfp_2_tx_rst_int; +wire [63:0] sfp_2_txd_int; +wire [7:0] sfp_2_txc_int; +wire sfp_2_rx_clk_int; +wire sfp_2_rx_rst_int; +wire [63:0] sfp_2_rxd_int; +wire [7:0] sfp_2_rxc_int; +wire sfp_3_tx_clk_int; +wire sfp_3_tx_rst_int; +wire [63:0] sfp_3_txd_int; +wire [7:0] sfp_3_txc_int; +wire sfp_3_rx_clk_int; +wire sfp_3_rx_rst_int; +wire [63:0] sfp_3_rxd_int; +wire [7:0] sfp_3_rxc_int; + +wire sfp_0_rx_block_lock; +wire sfp_1_rx_block_lock; +wire sfp_2_rx_block_lock; +wire sfp_3_rx_block_lock; + +wire sfp_gtpowergood; + +wire sfp_mgt_refclk; +wire sfp_mgt_refclk_int; +wire sfp_mgt_refclk_bufg; + +wire [3:0] gt_txclkout; +wire gt_txusrclk; + +wire [3:0] gt_rxclkout; +wire [3:0] gt_rxusrclk; + +wire gt_reset_tx_done; +wire gt_reset_rx_done; + +wire [3:0] gt_txprgdivresetdone; +wire [3:0] gt_txpmaresetdone; +wire [3:0] gt_rxprgdivresetdone; +wire [3:0] gt_rxpmaresetdone; + +wire gt_tx_reset = ~((>_txprgdivresetdone) & (>_txpmaresetdone)); +wire gt_rx_reset = ~>_rxpmaresetdone; + +reg gt_userclk_tx_active = 1'b0; +reg [3:0] gt_userclk_rx_active = 1'b0; + +IBUFDS_GTE4 ibufds_gte4_sfp_mgt_refclk_inst ( + .I (sfp_mgt_refclk_p), + .IB (sfp_mgt_refclk_n), + .CEB (1'b0), + .O (sfp_mgt_refclk), + .ODIV2 (sfp_mgt_refclk_int) +); + +BUFG_GT bufg_gt_refclk_inst ( + .CE (sfp_gtpowergood), + .CEMASK (1'b1), + .CLR (1'b0), + .CLRMASK (1'b1), + .DIV (3'b000), + .I (sfp_mgt_refclk_int), + .O (sfp_mgt_refclk_bufg) +); + +BUFG_GT bufg_gt_tx_usrclk_inst ( + .CE (1'b1), + .CEMASK (1'b0), + .CLR (gt_tx_reset), + .CLRMASK (1'b0), + .DIV (3'd0), + .I (gt_txclkout[0]), + .O (gt_txusrclk) +); + +assign clk_156mhz_int = gt_txusrclk; + +always @(posedge gt_txusrclk, posedge gt_tx_reset) begin + if (gt_tx_reset) begin + gt_userclk_tx_active <= 1'b0; + end else begin + gt_userclk_tx_active <= 1'b1; + end +end + +genvar n; + +generate + +for (n = 0 ; n < 4; n = n + 1) begin + + BUFG_GT bufg_gt_rx_usrclk_0_inst ( + .CE (1'b1), + .CEMASK (1'b0), + .CLR (gt_rx_reset), + .CLRMASK (1'b0), + .DIV (3'd0), + .I (gt_rxclkout[n]), + .O (gt_rxusrclk[n]) + ); + + always @(posedge gt_rxusrclk[n], posedge gt_rx_reset) begin + if (gt_rx_reset) begin + gt_userclk_rx_active[n] <= 1'b0; + end else begin + gt_userclk_rx_active[n] <= 1'b1; + end + end + +end + +endgenerate + +sync_reset #( + .N(4) +) +sync_reset_156mhz_inst ( + .clk(clk_156mhz_int), + .rst(~gt_reset_tx_done), + .out(rst_156mhz_int) +); + +wire [5:0] sfp_0_gt_txheader; +wire [63:0] sfp_0_gt_txdata; +wire sfp_0_gt_rxgearboxslip; +wire [5:0] sfp_0_gt_rxheader; +wire [1:0] sfp_0_gt_rxheadervalid; +wire [63:0] sfp_0_gt_rxdata; +wire [1:0] sfp_0_gt_rxdatavalid; + +wire [5:0] sfp_1_gt_txheader; +wire [63:0] sfp_1_gt_txdata; +wire sfp_1_gt_rxgearboxslip; +wire [5:0] sfp_1_gt_rxheader; +wire [1:0] sfp_1_gt_rxheadervalid; +wire [63:0] sfp_1_gt_rxdata; +wire [1:0] sfp_1_gt_rxdatavalid; + +wire [5:0] sfp_2_gt_txheader; +wire [63:0] sfp_2_gt_txdata; +wire sfp_2_gt_rxgearboxslip; +wire [5:0] sfp_2_gt_rxheader; +wire [1:0] sfp_2_gt_rxheadervalid; +wire [63:0] sfp_2_gt_rxdata; +wire [1:0] sfp_2_gt_rxdatavalid; + +wire [5:0] sfp_3_gt_txheader; +wire [63:0] sfp_3_gt_txdata; +wire sfp_3_gt_rxgearboxslip; +wire [5:0] sfp_3_gt_rxheader; +wire [1:0] sfp_3_gt_rxheadervalid; +wire [63:0] sfp_3_gt_rxdata; +wire [1:0] sfp_3_gt_rxdatavalid; + +gtwizard_ultrascale_0 +sfp_gty_inst ( + .gtwiz_userclk_tx_active_in(>_userclk_tx_active), + .gtwiz_userclk_rx_active_in(>_userclk_rx_active), + + .gtwiz_reset_clk_freerun_in(clk_125mhz_int), + .gtwiz_reset_all_in(rst_125mhz_int), + + .gtwiz_reset_tx_pll_and_datapath_in(1'b0), + .gtwiz_reset_tx_datapath_in(1'b0), + + .gtwiz_reset_rx_pll_and_datapath_in(1'b0), + .gtwiz_reset_rx_datapath_in(1'b0), + + .gtwiz_reset_rx_cdr_stable_out(), + + .gtwiz_reset_tx_done_out(gt_reset_tx_done), + .gtwiz_reset_rx_done_out(gt_reset_rx_done), + + .gtrefclk00_in(sfp_mgt_refclk), + + .qpll0outclk_out(), + .qpll0outrefclk_out(), + + // .rxpmareset_in(2'd0), + + .gtyrxn_in({ + sfp_3_rx_n, + sfp_2_rx_n, + sfp_1_rx_n, + sfp_0_rx_n + }), + .gtyrxp_in({ + sfp_3_rx_p, + sfp_2_rx_p, + sfp_1_rx_p, + sfp_0_rx_p + }), + + .rxusrclk_in(gt_rxusrclk), + .rxusrclk2_in(gt_rxusrclk), + + .gtwiz_userdata_tx_in({ + sfp_3_gt_txdata, + sfp_2_gt_txdata, + sfp_1_gt_txdata, + sfp_0_gt_txdata + }), + .txheader_in({ + sfp_3_gt_txheader, + sfp_2_gt_txheader, + sfp_1_gt_txheader, + sfp_0_gt_txheader + }), + .txsequence_in({4{7'b0}}), + + .txusrclk_in({4{gt_txusrclk}}), + .txusrclk2_in({4{gt_txusrclk}}), + + .gtpowergood_out(sfp_gtpowergood), + + .gtytxn_out({ + sfp_3_tx_n, + sfp_2_tx_n, + sfp_1_tx_n, + sfp_0_tx_n + }), + .gtytxp_out({ + sfp_3_tx_p, + sfp_2_tx_p, + sfp_1_tx_p, + sfp_0_tx_p + }), + + .txpolarity_in(4'b00), + .rxpolarity_in(4'b00), + + .rxgearboxslip_in({ + sfp_3_gt_rxgearboxslip, + sfp_2_gt_rxgearboxslip, + sfp_1_gt_rxgearboxslip, + sfp_0_gt_rxgearboxslip + }), + .gtwiz_userdata_rx_out({ + sfp_3_gt_rxdata, + sfp_2_gt_rxdata, + sfp_1_gt_rxdata, + sfp_0_gt_rxdata + }), + .rxdatavalid_out({ + sfp_3_gt_rxdatavalid, + sfp_2_gt_rxdatavalid, + sfp_1_gt_rxdatavalid, + sfp_0_gt_rxdatavalid + }), + .rxheader_out({ + sfp_3_gt_rxheader, + sfp_2_gt_rxheader, + sfp_1_gt_rxheader, + sfp_0_gt_rxheader + }), + .rxheadervalid_out({ + sfp_3_gt_rxheadervalid, + sfp_2_gt_rxheadervalid, + sfp_1_gt_rxheadervalid, + sfp_0_gt_rxheadervalid + }), + .rxoutclk_out(gt_rxclkout), + .rxpmaresetdone_out(gt_rxpmaresetdone), + .rxprgdivresetdone_out(gt_rxprgdivresetdone), + .rxstartofseq_out(), + + .txoutclk_out(gt_txclkout), + .txpmaresetdone_out(gt_txpmaresetdone), + .txprgdivresetdone_out(gt_txprgdivresetdone) +); + +assign sfp_0_tx_clk_int = clk_156mhz_int; +assign sfp_0_tx_rst_int = rst_156mhz_int; + +assign sfp_0_rx_clk_int = gt_rxusrclk[0]; + +sync_reset #( + .N(4) +) +sfp_0_rx_rst_reset_sync_inst ( + .clk(sfp_0_rx_clk_int), + .rst(~gt_reset_rx_done), + .out(sfp_0_rx_rst_int) +); + +eth_phy_10g #( + .BIT_REVERSE(1) +) +sfp_0_phy_inst ( + .tx_clk(sfp_0_tx_clk_int), + .tx_rst(sfp_0_tx_rst_int), + .rx_clk(sfp_0_rx_clk_int), + .rx_rst(sfp_0_rx_rst_int), + .xgmii_txd(sfp_0_txd_int), + .xgmii_txc(sfp_0_txc_int), + .xgmii_rxd(sfp_0_rxd_int), + .xgmii_rxc(sfp_0_rxc_int), + .serdes_tx_data(sfp_0_gt_txdata), + .serdes_tx_hdr(sfp_0_gt_txheader), + .serdes_rx_data(sfp_0_gt_rxdata), + .serdes_rx_hdr(sfp_0_gt_rxheader), + .serdes_rx_bitslip(sfp_0_gt_rxgearboxslip), + .rx_block_lock(sfp_0_rx_block_lock), + .rx_high_ber() +); + +assign sfp_1_tx_clk_int = clk_156mhz_int; +assign sfp_1_tx_rst_int = rst_156mhz_int; + +assign sfp_1_rx_clk_int = gt_rxusrclk[1]; + +sync_reset #( + .N(4) +) +sfp_1_rx_rst_reset_sync_inst ( + .clk(sfp_1_rx_clk_int), + .rst(~gt_reset_rx_done), + .out(sfp_1_rx_rst_int) +); + +eth_phy_10g #( + .BIT_REVERSE(1) +) +sfp_1_phy_inst ( + .tx_clk(sfp_1_tx_clk_int), + .tx_rst(sfp_1_tx_rst_int), + .rx_clk(sfp_1_rx_clk_int), + .rx_rst(sfp_1_rx_rst_int), + .xgmii_txd(sfp_1_txd_int), + .xgmii_txc(sfp_1_txc_int), + .xgmii_rxd(sfp_1_rxd_int), + .xgmii_rxc(sfp_1_rxc_int), + .serdes_tx_data(sfp_1_gt_txdata), + .serdes_tx_hdr(sfp_1_gt_txheader), + .serdes_rx_data(sfp_1_gt_rxdata), + .serdes_rx_hdr(sfp_1_gt_rxheader), + .serdes_rx_bitslip(sfp_1_gt_rxgearboxslip), + .rx_block_lock(sfp_1_rx_block_lock), + .rx_high_ber() +); + +assign sfp_2_tx_clk_int = clk_156mhz_int; +assign sfp_2_tx_rst_int = rst_156mhz_int; + +assign sfp_2_rx_clk_int = gt_rxusrclk[2]; + +sync_reset #( + .N(4) +) +sfp_2_rx_rst_reset_sync_inst ( + .clk(sfp_2_rx_clk_int), + .rst(~gt_reset_rx_done), + .out(sfp_2_rx_rst_int) +); + +eth_phy_10g #( + .BIT_REVERSE(1) +) +sfp_2_phy_inst ( + .tx_clk(sfp_2_tx_clk_int), + .tx_rst(sfp_2_tx_rst_int), + .rx_clk(sfp_2_rx_clk_int), + .rx_rst(sfp_2_rx_rst_int), + .xgmii_txd(sfp_2_txd_int), + .xgmii_txc(sfp_2_txc_int), + .xgmii_rxd(sfp_2_rxd_int), + .xgmii_rxc(sfp_2_rxc_int), + .serdes_tx_data(sfp_2_gt_txdata), + .serdes_tx_hdr(sfp_2_gt_txheader), + .serdes_rx_data(sfp_2_gt_rxdata), + .serdes_rx_hdr(sfp_2_gt_rxheader), + .serdes_rx_bitslip(sfp_2_gt_rxgearboxslip), + .rx_block_lock(sfp_2_rx_block_lock), + .rx_high_ber() +); + +assign sfp_3_tx_clk_int = clk_156mhz_int; +assign sfp_3_tx_rst_int = rst_156mhz_int; + +assign sfp_3_rx_clk_int = gt_rxusrclk[3]; + +sync_reset #( + .N(4) +) +sfp_3_rx_rst_reset_sync_inst ( + .clk(sfp_3_rx_clk_int), + .rst(~gt_reset_rx_done), + .out(sfp_3_rx_rst_int) +); + +eth_phy_10g #( + .BIT_REVERSE(1) +) +sfp_3_phy_inst ( + .tx_clk(sfp_3_tx_clk_int), + .tx_rst(sfp_3_tx_rst_int), + .rx_clk(sfp_3_rx_clk_int), + .rx_rst(sfp_3_rx_rst_int), + .xgmii_txd(sfp_3_txd_int), + .xgmii_txc(sfp_3_txc_int), + .xgmii_rxd(sfp_3_rxd_int), + .xgmii_rxc(sfp_3_rxc_int), + .serdes_tx_data(sfp_3_gt_txdata), + .serdes_tx_hdr(sfp_3_gt_txheader), + .serdes_rx_data(sfp_3_gt_rxdata), + .serdes_rx_hdr(sfp_3_gt_rxheader), + .serdes_rx_bitslip(sfp_3_gt_rxgearboxslip), + .rx_block_lock(sfp_3_rx_block_lock), + .rx_high_ber() +); + + +assign user_led[1:0] = sfp_0_led_int; +assign user_led[3:2] = sfp_1_led_int; +assign user_led[5:4] = sfp_2_led_int; +assign user_led[7:6] = sfp_3_led_int; + +fpga_core +core_inst ( + /* + * Clock: 156.25 MHz + * Synchronous reset + */ + .clk(clk_156mhz_int), + .rst(rst_156mhz_int), + /* + * GPIO + */ + .sfp_0_led(sfp_0_led_int), + .sfp_1_led(sfp_1_led_int), + .sfp_2_led(sfp_2_led_int), + .sfp_3_led(sfp_3_led_int), + .sma_led(sma_led_int), + /* + * Ethernet: SFP+ + */ + .sfp_0_tx_clk(sfp_0_tx_clk_int), + .sfp_0_tx_rst(sfp_0_tx_rst_int), + .sfp_0_txd(sfp_0_txd_int), + .sfp_0_txc(sfp_0_txc_int), + .sfp_0_rx_clk(sfp_0_rx_clk_int), + .sfp_0_rx_rst(sfp_0_rx_rst_int), + .sfp_0_rxd(sfp_0_rxd_int), + .sfp_0_rxc(sfp_0_rxc_int), + .sfp_1_tx_clk(sfp_1_tx_clk_int), + .sfp_1_tx_rst(sfp_1_tx_rst_int), + .sfp_1_txd(sfp_1_txd_int), + .sfp_1_txc(sfp_1_txc_int), + .sfp_1_rx_clk(sfp_1_rx_clk_int), + .sfp_1_rx_rst(sfp_1_rx_rst_int), + .sfp_1_rxd(sfp_1_rxd_int), + .sfp_1_rxc(sfp_1_rxc_int), + .sfp_2_tx_clk(sfp_2_tx_clk_int), + .sfp_2_tx_rst(sfp_2_tx_rst_int), + .sfp_2_txd(sfp_2_txd_int), + .sfp_2_txc(sfp_2_txc_int), + .sfp_2_rx_clk(sfp_2_rx_clk_int), + .sfp_2_rx_rst(sfp_2_rx_rst_int), + .sfp_2_rxd(sfp_2_rxd_int), + .sfp_2_rxc(sfp_2_rxc_int), + .sfp_3_tx_clk(sfp_3_tx_clk_int), + .sfp_3_tx_rst(sfp_3_tx_rst_int), + .sfp_3_txd(sfp_3_txd_int), + .sfp_3_txc(sfp_3_txc_int), + .sfp_3_rx_clk(sfp_3_rx_clk_int), + .sfp_3_rx_rst(sfp_3_rx_rst_int), + .sfp_3_rxd(sfp_3_rxd_int), + .sfp_3_rxc(sfp_3_rxc_int) +); + +endmodule diff --git a/example/KCU116/fpga_10g/rtl/fpga_core.v b/example/KCU116/fpga_10g/rtl/fpga_core.v new file mode 100644 index 000000000..0c8338ed6 --- /dev/null +++ b/example/KCU116/fpga_10g/rtl/fpga_core.v @@ -0,0 +1,618 @@ +/* + +Copyright (c) 2021 Leon Schuermann + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * FPGA core logic + */ +module fpga_core +( + /* + * Clock: 156.25MHz + * Synchronous reset + */ + input wire clk, + input wire rst, + + /* + * GPIO + */ + output wire [1:0] sfp_0_led, + output wire [1:0] sfp_1_led, + output wire [1:0] sfp_2_led, + output wire [1:0] sfp_3_led, + output wire [1:0] sma_led, + + /* + * Ethernet: SFP+ + */ + input wire sfp_0_tx_clk, + input wire sfp_0_tx_rst, + output wire [63:0] sfp_0_txd, + output wire [7:0] sfp_0_txc, + input wire sfp_0_rx_clk, + input wire sfp_0_rx_rst, + input wire [63:0] sfp_0_rxd, + input wire [7:0] sfp_0_rxc, + input wire sfp_1_tx_clk, + input wire sfp_1_tx_rst, + output wire [63:0] sfp_1_txd, + output wire [7:0] sfp_1_txc, + input wire sfp_1_rx_clk, + input wire sfp_1_rx_rst, + input wire [63:0] sfp_1_rxd, + input wire [7:0] sfp_1_rxc, + input wire sfp_2_tx_clk, + input wire sfp_2_tx_rst, + output wire [63:0] sfp_2_txd, + output wire [7:0] sfp_2_txc, + input wire sfp_2_rx_clk, + input wire sfp_2_rx_rst, + input wire [63:0] sfp_2_rxd, + input wire [7:0] sfp_2_rxc, + input wire sfp_3_tx_clk, + input wire sfp_3_tx_rst, + output wire [63:0] sfp_3_txd, + output wire [7:0] sfp_3_txc, + input wire sfp_3_rx_clk, + input wire sfp_3_rx_rst, + input wire [63:0] sfp_3_rxd, + input wire [7:0] sfp_3_rxc +); + +// AXI between MAC and Ethernet modules +wire [63:0] rx_axis_tdata; +wire [7:0] rx_axis_tkeep; +wire rx_axis_tvalid; +wire rx_axis_tready; +wire rx_axis_tlast; +wire rx_axis_tuser; + +wire [63:0] tx_axis_tdata; +wire [7:0] tx_axis_tkeep; +wire tx_axis_tvalid; +wire tx_axis_tready; +wire tx_axis_tlast; +wire tx_axis_tuser; + +// Ethernet frame between Ethernet modules and UDP stack +wire rx_eth_hdr_ready; +wire rx_eth_hdr_valid; +wire [47:0] rx_eth_dest_mac; +wire [47:0] rx_eth_src_mac; +wire [15:0] rx_eth_type; +wire [63:0] rx_eth_payload_axis_tdata; +wire [7:0] rx_eth_payload_axis_tkeep; +wire rx_eth_payload_axis_tvalid; +wire rx_eth_payload_axis_tready; +wire rx_eth_payload_axis_tlast; +wire rx_eth_payload_axis_tuser; + +wire tx_eth_hdr_ready; +wire tx_eth_hdr_valid; +wire [47:0] tx_eth_dest_mac; +wire [47:0] tx_eth_src_mac; +wire [15:0] tx_eth_type; +wire [63:0] tx_eth_payload_axis_tdata; +wire [7:0] tx_eth_payload_axis_tkeep; +wire tx_eth_payload_axis_tvalid; +wire tx_eth_payload_axis_tready; +wire tx_eth_payload_axis_tlast; +wire tx_eth_payload_axis_tuser; + +// IP frame connections +wire rx_ip_hdr_valid; +wire rx_ip_hdr_ready; +wire [47:0] rx_ip_eth_dest_mac; +wire [47:0] rx_ip_eth_src_mac; +wire [15:0] rx_ip_eth_type; +wire [3:0] rx_ip_version; +wire [3:0] rx_ip_ihl; +wire [5:0] rx_ip_dscp; +wire [1:0] rx_ip_ecn; +wire [15:0] rx_ip_length; +wire [15:0] rx_ip_identification; +wire [2:0] rx_ip_flags; +wire [12:0] rx_ip_fragment_offset; +wire [7:0] rx_ip_ttl; +wire [7:0] rx_ip_protocol; +wire [15:0] rx_ip_header_checksum; +wire [31:0] rx_ip_source_ip; +wire [31:0] rx_ip_dest_ip; +wire [63:0] rx_ip_payload_axis_tdata; +wire [7:0] rx_ip_payload_axis_tkeep; +wire rx_ip_payload_axis_tvalid; +wire rx_ip_payload_axis_tready; +wire rx_ip_payload_axis_tlast; +wire rx_ip_payload_axis_tuser; + +wire tx_ip_hdr_valid; +wire tx_ip_hdr_ready; +wire [5:0] tx_ip_dscp; +wire [1:0] tx_ip_ecn; +wire [15:0] tx_ip_length; +wire [7:0] tx_ip_ttl; +wire [7:0] tx_ip_protocol; +wire [31:0] tx_ip_source_ip; +wire [31:0] tx_ip_dest_ip; +wire [63:0] tx_ip_payload_axis_tdata; +wire [7:0] tx_ip_payload_axis_tkeep; +wire tx_ip_payload_axis_tvalid; +wire tx_ip_payload_axis_tready; +wire tx_ip_payload_axis_tlast; +wire tx_ip_payload_axis_tuser; + +// UDP frame connections +wire rx_udp_hdr_valid; +wire rx_udp_hdr_ready; +wire [47:0] rx_udp_eth_dest_mac; +wire [47:0] rx_udp_eth_src_mac; +wire [15:0] rx_udp_eth_type; +wire [3:0] rx_udp_ip_version; +wire [3:0] rx_udp_ip_ihl; +wire [5:0] rx_udp_ip_dscp; +wire [1:0] rx_udp_ip_ecn; +wire [15:0] rx_udp_ip_length; +wire [15:0] rx_udp_ip_identification; +wire [2:0] rx_udp_ip_flags; +wire [12:0] rx_udp_ip_fragment_offset; +wire [7:0] rx_udp_ip_ttl; +wire [7:0] rx_udp_ip_protocol; +wire [15:0] rx_udp_ip_header_checksum; +wire [31:0] rx_udp_ip_source_ip; +wire [31:0] rx_udp_ip_dest_ip; +wire [15:0] rx_udp_source_port; +wire [15:0] rx_udp_dest_port; +wire [15:0] rx_udp_length; +wire [15:0] rx_udp_checksum; +wire [63:0] rx_udp_payload_axis_tdata; +wire [7:0] rx_udp_payload_axis_tkeep; +wire rx_udp_payload_axis_tvalid; +wire rx_udp_payload_axis_tready; +wire rx_udp_payload_axis_tlast; +wire rx_udp_payload_axis_tuser; + +wire tx_udp_hdr_valid; +wire tx_udp_hdr_ready; +wire [5:0] tx_udp_ip_dscp; +wire [1:0] tx_udp_ip_ecn; +wire [7:0] tx_udp_ip_ttl; +wire [31:0] tx_udp_ip_source_ip; +wire [31:0] tx_udp_ip_dest_ip; +wire [15:0] tx_udp_source_port; +wire [15:0] tx_udp_dest_port; +wire [15:0] tx_udp_length; +wire [15:0] tx_udp_checksum; +wire [63:0] tx_udp_payload_axis_tdata; +wire [7:0] tx_udp_payload_axis_tkeep; +wire tx_udp_payload_axis_tvalid; +wire tx_udp_payload_axis_tready; +wire tx_udp_payload_axis_tlast; +wire tx_udp_payload_axis_tuser; + +wire [63:0] rx_fifo_udp_payload_axis_tdata; +wire [7:0] rx_fifo_udp_payload_axis_tkeep; +wire rx_fifo_udp_payload_axis_tvalid; +wire rx_fifo_udp_payload_axis_tready; +wire rx_fifo_udp_payload_axis_tlast; +wire rx_fifo_udp_payload_axis_tuser; + +wire [63:0] tx_fifo_udp_payload_axis_tdata; +wire [7:0] tx_fifo_udp_payload_axis_tkeep; +wire tx_fifo_udp_payload_axis_tvalid; +wire tx_fifo_udp_payload_axis_tready; +wire tx_fifo_udp_payload_axis_tlast; +wire tx_fifo_udp_payload_axis_tuser; + +// Configuration +wire [47:0] local_mac = 48'h02_00_00_00_00_00; +wire [31:0] local_ip = {8'd192, 8'd168, 8'd1, 8'd128}; +wire [31:0] gateway_ip = {8'd192, 8'd168, 8'd1, 8'd1}; +wire [31:0] subnet_mask = {8'd255, 8'd255, 8'd255, 8'd0}; + +// IP ports not used +assign rx_ip_hdr_ready = 1; +assign rx_ip_payload_axis_tready = 1; + +assign tx_ip_hdr_valid = 0; +assign tx_ip_dscp = 0; +assign tx_ip_ecn = 0; +assign tx_ip_length = 0; +assign tx_ip_ttl = 0; +assign tx_ip_protocol = 0; +assign tx_ip_source_ip = 0; +assign tx_ip_dest_ip = 0; +assign tx_ip_payload_axis_tdata = 0; +assign tx_ip_payload_axis_tkeep = 0; +assign tx_ip_payload_axis_tvalid = 0; +assign tx_ip_payload_axis_tlast = 0; +assign tx_ip_payload_axis_tuser = 0; + +// Loop back UDP +wire match_cond = rx_udp_dest_port == 1234; +wire no_match = ~match_cond; + +reg match_cond_reg = 0; +reg no_match_reg = 0; + +always @(posedge clk) begin + if (rst) begin + match_cond_reg <= 0; + no_match_reg <= 0; + end else begin + if (rx_udp_payload_axis_tvalid) begin + if ((~match_cond_reg & ~no_match_reg) | + (rx_udp_payload_axis_tvalid & rx_udp_payload_axis_tready & rx_udp_payload_axis_tlast)) begin + match_cond_reg <= match_cond; + no_match_reg <= no_match; + end + end else begin + match_cond_reg <= 0; + no_match_reg <= 0; + end + end +end + +assign tx_udp_hdr_valid = rx_udp_hdr_valid & match_cond; +assign rx_udp_hdr_ready = (tx_eth_hdr_ready & match_cond) | no_match; +assign tx_udp_ip_dscp = 0; +assign tx_udp_ip_ecn = 0; +assign tx_udp_ip_ttl = 64; +assign tx_udp_ip_source_ip = local_ip; +assign tx_udp_ip_dest_ip = rx_udp_ip_source_ip; +assign tx_udp_source_port = rx_udp_dest_port; +assign tx_udp_dest_port = rx_udp_source_port; +assign tx_udp_length = rx_udp_length; +assign tx_udp_checksum = 0; + +assign tx_udp_payload_axis_tdata = tx_fifo_udp_payload_axis_tdata; +assign tx_udp_payload_axis_tkeep = tx_fifo_udp_payload_axis_tkeep; +assign tx_udp_payload_axis_tvalid = tx_fifo_udp_payload_axis_tvalid; +assign tx_fifo_udp_payload_axis_tready = tx_udp_payload_axis_tready; +assign tx_udp_payload_axis_tlast = tx_fifo_udp_payload_axis_tlast; +assign tx_udp_payload_axis_tuser = tx_fifo_udp_payload_axis_tuser; + +assign rx_fifo_udp_payload_axis_tdata = rx_udp_payload_axis_tdata; +assign rx_fifo_udp_payload_axis_tkeep = rx_udp_payload_axis_tkeep; +assign rx_fifo_udp_payload_axis_tvalid = rx_udp_payload_axis_tvalid & match_cond_reg; +assign rx_udp_payload_axis_tready = (rx_fifo_udp_payload_axis_tready & match_cond_reg) | no_match_reg; +assign rx_fifo_udp_payload_axis_tlast = rx_udp_payload_axis_tlast; +assign rx_fifo_udp_payload_axis_tuser = rx_udp_payload_axis_tuser; + +// Place first payload byte onto LEDs +reg valid_last = 0; +reg [7:0] led_reg = 0; + +always @(posedge clk) begin + if (rst) begin + led_reg <= 0; + end else begin + valid_last <= tx_udp_payload_axis_tvalid; + if (tx_udp_payload_axis_tvalid & ~valid_last) begin + led_reg <= tx_udp_payload_axis_tdata; + end + end +end + +assign led = led_reg; + +assign sfp_1_txd = 64'h0707070707070707; +assign sfp_1_txc = 8'hff; + +assign sfp_2_txd = 64'h0707070707070707; +assign sfp_2_txc = 8'hff; + +assign sfp_3_txd = 64'h0707070707070707; +assign sfp_3_txc = 8'hff; + +eth_mac_10g_fifo #( + .ENABLE_PADDING(1), + .ENABLE_DIC(1), + .MIN_FRAME_LENGTH(64), + .TX_FIFO_DEPTH(4096), + .TX_FRAME_FIFO(1), + .RX_FIFO_DEPTH(4096), + .RX_FRAME_FIFO(1) +) +eth_mac_10g_fifo_inst ( + .rx_clk(sfp_0_rx_clk), + .rx_rst(sfp_0_rx_rst), + .tx_clk(sfp_0_tx_clk), + .tx_rst(sfp_0_tx_rst), + .logic_clk(clk), + .logic_rst(rst), + + .tx_axis_tdata(tx_axis_tdata), + .tx_axis_tkeep(tx_axis_tkeep), + .tx_axis_tvalid(tx_axis_tvalid), + .tx_axis_tready(tx_axis_tready), + .tx_axis_tlast(tx_axis_tlast), + .tx_axis_tuser(tx_axis_tuser), + + .rx_axis_tdata(rx_axis_tdata), + .rx_axis_tkeep(rx_axis_tkeep), + .rx_axis_tvalid(rx_axis_tvalid), + .rx_axis_tready(rx_axis_tready), + .rx_axis_tlast(rx_axis_tlast), + .rx_axis_tuser(rx_axis_tuser), + + .xgmii_rxd(sfp_0_rxd), + .xgmii_rxc(sfp_0_rxc), + .xgmii_txd(sfp_0_txd), + .xgmii_txc(sfp_0_txc), + + .tx_fifo_overflow(), + .tx_fifo_bad_frame(), + .tx_fifo_good_frame(), + .rx_error_bad_frame(), + .rx_error_bad_fcs(), + .rx_fifo_overflow(), + .rx_fifo_bad_frame(), + .rx_fifo_good_frame(), + + .ifg_delay(8'd12) +); + +eth_axis_rx #( + .DATA_WIDTH(64) +) +eth_axis_rx_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(rx_axis_tdata), + .s_axis_tkeep(rx_axis_tkeep), + .s_axis_tvalid(rx_axis_tvalid), + .s_axis_tready(rx_axis_tready), + .s_axis_tlast(rx_axis_tlast), + .s_axis_tuser(rx_axis_tuser), + // Ethernet frame output + .m_eth_hdr_valid(rx_eth_hdr_valid), + .m_eth_hdr_ready(rx_eth_hdr_ready), + .m_eth_dest_mac(rx_eth_dest_mac), + .m_eth_src_mac(rx_eth_src_mac), + .m_eth_type(rx_eth_type), + .m_eth_payload_axis_tdata(rx_eth_payload_axis_tdata), + .m_eth_payload_axis_tkeep(rx_eth_payload_axis_tkeep), + .m_eth_payload_axis_tvalid(rx_eth_payload_axis_tvalid), + .m_eth_payload_axis_tready(rx_eth_payload_axis_tready), + .m_eth_payload_axis_tlast(rx_eth_payload_axis_tlast), + .m_eth_payload_axis_tuser(rx_eth_payload_axis_tuser), + // Status signals + .busy(), + .error_header_early_termination() +); + +eth_axis_tx #( + .DATA_WIDTH(64) +) +eth_axis_tx_inst ( + .clk(clk), + .rst(rst), + // Ethernet frame input + .s_eth_hdr_valid(tx_eth_hdr_valid), + .s_eth_hdr_ready(tx_eth_hdr_ready), + .s_eth_dest_mac(tx_eth_dest_mac), + .s_eth_src_mac(tx_eth_src_mac), + .s_eth_type(tx_eth_type), + .s_eth_payload_axis_tdata(tx_eth_payload_axis_tdata), + .s_eth_payload_axis_tkeep(tx_eth_payload_axis_tkeep), + .s_eth_payload_axis_tvalid(tx_eth_payload_axis_tvalid), + .s_eth_payload_axis_tready(tx_eth_payload_axis_tready), + .s_eth_payload_axis_tlast(tx_eth_payload_axis_tlast), + .s_eth_payload_axis_tuser(tx_eth_payload_axis_tuser), + // AXI output + .m_axis_tdata(tx_axis_tdata), + .m_axis_tkeep(tx_axis_tkeep), + .m_axis_tvalid(tx_axis_tvalid), + .m_axis_tready(tx_axis_tready), + .m_axis_tlast(tx_axis_tlast), + .m_axis_tuser(tx_axis_tuser), + // Status signals + .busy() +); + +udp_complete_64 +udp_complete_inst ( + .clk(clk), + .rst(rst), + // Ethernet frame input + .s_eth_hdr_valid(rx_eth_hdr_valid), + .s_eth_hdr_ready(rx_eth_hdr_ready), + .s_eth_dest_mac(rx_eth_dest_mac), + .s_eth_src_mac(rx_eth_src_mac), + .s_eth_type(rx_eth_type), + .s_eth_payload_axis_tdata(rx_eth_payload_axis_tdata), + .s_eth_payload_axis_tkeep(rx_eth_payload_axis_tkeep), + .s_eth_payload_axis_tvalid(rx_eth_payload_axis_tvalid), + .s_eth_payload_axis_tready(rx_eth_payload_axis_tready), + .s_eth_payload_axis_tlast(rx_eth_payload_axis_tlast), + .s_eth_payload_axis_tuser(rx_eth_payload_axis_tuser), + // Ethernet frame output + .m_eth_hdr_valid(tx_eth_hdr_valid), + .m_eth_hdr_ready(tx_eth_hdr_ready), + .m_eth_dest_mac(tx_eth_dest_mac), + .m_eth_src_mac(tx_eth_src_mac), + .m_eth_type(tx_eth_type), + .m_eth_payload_axis_tdata(tx_eth_payload_axis_tdata), + .m_eth_payload_axis_tkeep(tx_eth_payload_axis_tkeep), + .m_eth_payload_axis_tvalid(tx_eth_payload_axis_tvalid), + .m_eth_payload_axis_tready(tx_eth_payload_axis_tready), + .m_eth_payload_axis_tlast(tx_eth_payload_axis_tlast), + .m_eth_payload_axis_tuser(tx_eth_payload_axis_tuser), + // IP frame input + .s_ip_hdr_valid(tx_ip_hdr_valid), + .s_ip_hdr_ready(tx_ip_hdr_ready), + .s_ip_dscp(tx_ip_dscp), + .s_ip_ecn(tx_ip_ecn), + .s_ip_length(tx_ip_length), + .s_ip_ttl(tx_ip_ttl), + .s_ip_protocol(tx_ip_protocol), + .s_ip_source_ip(tx_ip_source_ip), + .s_ip_dest_ip(tx_ip_dest_ip), + .s_ip_payload_axis_tdata(tx_ip_payload_axis_tdata), + .s_ip_payload_axis_tkeep(tx_ip_payload_axis_tkeep), + .s_ip_payload_axis_tvalid(tx_ip_payload_axis_tvalid), + .s_ip_payload_axis_tready(tx_ip_payload_axis_tready), + .s_ip_payload_axis_tlast(tx_ip_payload_axis_tlast), + .s_ip_payload_axis_tuser(tx_ip_payload_axis_tuser), + // IP frame output + .m_ip_hdr_valid(rx_ip_hdr_valid), + .m_ip_hdr_ready(rx_ip_hdr_ready), + .m_ip_eth_dest_mac(rx_ip_eth_dest_mac), + .m_ip_eth_src_mac(rx_ip_eth_src_mac), + .m_ip_eth_type(rx_ip_eth_type), + .m_ip_version(rx_ip_version), + .m_ip_ihl(rx_ip_ihl), + .m_ip_dscp(rx_ip_dscp), + .m_ip_ecn(rx_ip_ecn), + .m_ip_length(rx_ip_length), + .m_ip_identification(rx_ip_identification), + .m_ip_flags(rx_ip_flags), + .m_ip_fragment_offset(rx_ip_fragment_offset), + .m_ip_ttl(rx_ip_ttl), + .m_ip_protocol(rx_ip_protocol), + .m_ip_header_checksum(rx_ip_header_checksum), + .m_ip_source_ip(rx_ip_source_ip), + .m_ip_dest_ip(rx_ip_dest_ip), + .m_ip_payload_axis_tdata(rx_ip_payload_axis_tdata), + .m_ip_payload_axis_tkeep(rx_ip_payload_axis_tkeep), + .m_ip_payload_axis_tvalid(rx_ip_payload_axis_tvalid), + .m_ip_payload_axis_tready(rx_ip_payload_axis_tready), + .m_ip_payload_axis_tlast(rx_ip_payload_axis_tlast), + .m_ip_payload_axis_tuser(rx_ip_payload_axis_tuser), + // UDP frame input + .s_udp_hdr_valid(tx_udp_hdr_valid), + .s_udp_hdr_ready(tx_udp_hdr_ready), + .s_udp_ip_dscp(tx_udp_ip_dscp), + .s_udp_ip_ecn(tx_udp_ip_ecn), + .s_udp_ip_ttl(tx_udp_ip_ttl), + .s_udp_ip_source_ip(tx_udp_ip_source_ip), + .s_udp_ip_dest_ip(tx_udp_ip_dest_ip), + .s_udp_source_port(tx_udp_source_port), + .s_udp_dest_port(tx_udp_dest_port), + .s_udp_length(tx_udp_length), + .s_udp_checksum(tx_udp_checksum), + .s_udp_payload_axis_tdata(tx_udp_payload_axis_tdata), + .s_udp_payload_axis_tkeep(tx_udp_payload_axis_tkeep), + .s_udp_payload_axis_tvalid(tx_udp_payload_axis_tvalid), + .s_udp_payload_axis_tready(tx_udp_payload_axis_tready), + .s_udp_payload_axis_tlast(tx_udp_payload_axis_tlast), + .s_udp_payload_axis_tuser(tx_udp_payload_axis_tuser), + // UDP frame output + .m_udp_hdr_valid(rx_udp_hdr_valid), + .m_udp_hdr_ready(rx_udp_hdr_ready), + .m_udp_eth_dest_mac(rx_udp_eth_dest_mac), + .m_udp_eth_src_mac(rx_udp_eth_src_mac), + .m_udp_eth_type(rx_udp_eth_type), + .m_udp_ip_version(rx_udp_ip_version), + .m_udp_ip_ihl(rx_udp_ip_ihl), + .m_udp_ip_dscp(rx_udp_ip_dscp), + .m_udp_ip_ecn(rx_udp_ip_ecn), + .m_udp_ip_length(rx_udp_ip_length), + .m_udp_ip_identification(rx_udp_ip_identification), + .m_udp_ip_flags(rx_udp_ip_flags), + .m_udp_ip_fragment_offset(rx_udp_ip_fragment_offset), + .m_udp_ip_ttl(rx_udp_ip_ttl), + .m_udp_ip_protocol(rx_udp_ip_protocol), + .m_udp_ip_header_checksum(rx_udp_ip_header_checksum), + .m_udp_ip_source_ip(rx_udp_ip_source_ip), + .m_udp_ip_dest_ip(rx_udp_ip_dest_ip), + .m_udp_source_port(rx_udp_source_port), + .m_udp_dest_port(rx_udp_dest_port), + .m_udp_length(rx_udp_length), + .m_udp_checksum(rx_udp_checksum), + .m_udp_payload_axis_tdata(rx_udp_payload_axis_tdata), + .m_udp_payload_axis_tkeep(rx_udp_payload_axis_tkeep), + .m_udp_payload_axis_tvalid(rx_udp_payload_axis_tvalid), + .m_udp_payload_axis_tready(rx_udp_payload_axis_tready), + .m_udp_payload_axis_tlast(rx_udp_payload_axis_tlast), + .m_udp_payload_axis_tuser(rx_udp_payload_axis_tuser), + // Status signals + .ip_rx_busy(), + .ip_tx_busy(), + .udp_rx_busy(), + .udp_tx_busy(), + .ip_rx_error_header_early_termination(), + .ip_rx_error_payload_early_termination(), + .ip_rx_error_invalid_header(), + .ip_rx_error_invalid_checksum(), + .ip_tx_error_payload_early_termination(), + .ip_tx_error_arp_failed(), + .udp_rx_error_header_early_termination(), + .udp_rx_error_payload_early_termination(), + .udp_tx_error_payload_early_termination(), + // Configuration + .local_mac(local_mac), + .local_ip(local_ip), + .gateway_ip(gateway_ip), + .subnet_mask(subnet_mask), + .clear_arp_cache(1'b0) +); + +axis_fifo #( + .DEPTH(8192), + .DATA_WIDTH(64), + .KEEP_ENABLE(1), + .KEEP_WIDTH(8), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(1), + .USER_WIDTH(1), + .FRAME_FIFO(0) +) +udp_payload_fifo ( + .clk(clk), + .rst(rst), + + // AXI input + .s_axis_tdata(rx_fifo_udp_payload_axis_tdata), + .s_axis_tkeep(rx_fifo_udp_payload_axis_tkeep), + .s_axis_tvalid(rx_fifo_udp_payload_axis_tvalid), + .s_axis_tready(rx_fifo_udp_payload_axis_tready), + .s_axis_tlast(rx_fifo_udp_payload_axis_tlast), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(rx_fifo_udp_payload_axis_tuser), + + // AXI output + .m_axis_tdata(tx_fifo_udp_payload_axis_tdata), + .m_axis_tkeep(tx_fifo_udp_payload_axis_tkeep), + .m_axis_tvalid(tx_fifo_udp_payload_axis_tvalid), + .m_axis_tready(tx_fifo_udp_payload_axis_tready), + .m_axis_tlast(tx_fifo_udp_payload_axis_tlast), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser(tx_fifo_udp_payload_axis_tuser), + + // Status + .status_overflow(), + .status_bad_frame(), + .status_good_frame() +); + +endmodule