From 7e570709f2844396ac6e3cc48538c1141175e4a9 Mon Sep 17 00:00:00 2001 From: Leon Schuermann Date: Fri, 8 Oct 2021 12:30:08 +0200 Subject: [PATCH] Add Xilinx Kintex UltraScale+ KCU116 board This commit adds the Xilinx Kintex UltraScale+ KCU116 board featuring the XCKU5P-2FFVB676E FPGA and 4 zSFP cages. XGMII PHYs are instantiated for all four cages in `fpga.v` and passed down to `fpga_core.v`. Only the first (SFP 0) cage is connected to the instantiated UDP/IP core. The I2C bus to the SFPs uses an I2C mux chip and is currently unsupported. 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. --- example/KCU116/fpga_10g/Makefile | 25 + example/KCU116/fpga_10g/README.md | 37 + example/KCU116/fpga_10g/common/vivado.mk | 123 ++++ example/KCU116/fpga_10g/fpga.xdc | 67 ++ example/KCU116/fpga_10g/fpga/Makefile | 58 ++ .../fpga_10g/ip/gtwizard_ultrascale_0.tcl | 23 + example/KCU116/fpga_10g/lib/eth | 1 + example/KCU116/fpga_10g/rtl/fpga.v | 678 ++++++++++++++++++ example/KCU116/fpga_10g/rtl/fpga_core.v | 618 ++++++++++++++++ 9 files changed, 1630 insertions(+) create mode 100644 example/KCU116/fpga_10g/Makefile create mode 100644 example/KCU116/fpga_10g/README.md create mode 100644 example/KCU116/fpga_10g/common/vivado.mk create mode 100644 example/KCU116/fpga_10g/fpga.xdc create mode 100644 example/KCU116/fpga_10g/fpga/Makefile create mode 100644 example/KCU116/fpga_10g/ip/gtwizard_ultrascale_0.tcl create mode 120000 example/KCU116/fpga_10g/lib/eth create mode 100644 example/KCU116/fpga_10g/rtl/fpga.v create mode 100644 example/KCU116/fpga_10g/rtl/fpga_core.v 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