diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000..0339a54bf --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,18 @@ +FROM ubuntu:22.04 + +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install --no-install-recommends \ + net-tools less python3 python3-pip \ + software-properties-common vim build-essential \ + git curl wget unzip python3-dev \ + gtkwave iverilog myhdl-cosimulation python3-myhdl + +RUN pip3 install cocotb \ + cocotb-bus cocotb-test cocotbext-axi \ + cocotbext-eth cocotbext-pcie \ + pytest scapy \ + tox pytest-xdist pytest-sugar + +RUN git clone https://github.com/myhdl/myhdl && \ + cd myhdl/cosimulation/icarus && \ + make && cp myhdl.vpi /usr/lib/aarch64-linux-gnu/ivl/ diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..7d09c69ed --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,65 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.241.1/containers/python-3 +{ + "name": "verilog-ethernet-devenv", + + "build": { + "dockerfile": "Dockerfile", + "context": "..", + "args": { + // Update 'VARIANT' to pick a Python version: 3, 3.10, 3.9, 3.8, 3.7, 3.6 + // Append -bullseye or -buster to pin to an OS version. + // Use -bullseye variants on local on arm64/Apple Silicon. + "VARIANT": "3.10-bullseye", + // Options + "NODE_VERSION": "lts/*" + } + }, + + // Configure tool-specific properties. + "customizations": { + // Configure properties specific to VS Code. + "vscode": { + // Set *default* container specific settings.json values on container create. + "settings": { + "python.defaultInterpreterPath": "/usr/local/bin/python", + "python.linting.enabled": true, + "python.linting.pylintEnabled": true, + "python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8", + "python.formatting.blackPath": "/usr/local/py-utils/bin/black", + "python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf", + "python.linting.banditPath": "/usr/local/py-utils/bin/bandit", + "python.linting.flake8Path": "/usr/local/py-utils/bin/flake8", + "python.linting.mypyPath": "/usr/local/py-utils/bin/mypy", + "python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle", + "python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle", + "python.linting.pylintPath": "/usr/local/py-utils/bin/pylint" + }, + + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-python.python", + "ms-toolsai.jupyter-renderers", + "ms-toolsai.jupyter", + "ms-python.vscode-pylance", + "ms-vscode.cmake-tools", + "leafvmaple.verilog", + "mshr-h.VerilogHDL", + "GitHub.copilot" + // "BenjaminBenais.copilot-theme" + ] + } + }, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + // "remoteUser": "vscode" + + "runArgs": [ + "--privileged", + "-e", "DISPLAY=host.docker.internal:0", + "-v", "/tmp/.X11-unix:/tmp/.X11-unix" + ] +} diff --git a/example/KR260/fpga_10g/Makefile b/example/KR260/fpga_10g/Makefile new file mode 100644 index 000000000..f504bd06f --- /dev/null +++ b/example/KR260/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/KR260/fpga_10g/README.md b/example/KR260/fpga_10g/README.md new file mode 100644 index 000000000..83a45c284 --- /dev/null +++ b/example/KR260/fpga_10g/README.md @@ -0,0 +1,29 @@ +# Verilog Ethernet KR260 Example Design + +## Introduction + +This example design targets the AMD KR260 FPGA SoC 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. + +* FPGA: `XCK26-SFVC784-2LV-C` (or `-I`, if industrial-grade) +* 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 + +Program the KR260 board with Vivado's Hardware Device Manager (via JTAG). Connect the KR260 SFP+ port to a 10G Ethernet NIC in your host. Then run in your host machine: + + 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/KR260/fpga_10g/common/vivado.mk b/example/KR260/fpga_10g/common/vivado.mk new file mode 100644 index 000000000..21e6a5fed --- /dev/null +++ b/example/KR260/fpga_10g/common/vivado.mk @@ -0,0 +1,131 @@ +################################################################### +# +# 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) + +FPGA_TOP ?= fpga +PROJECT ?= $(FPGA_TOP) + +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 *.ltx program.tcl generate_mcs.tcl *.mcs *.prm flash.tcl + -rm -rf *_utilization.rpt *_utilization_hierarchical.rpt + +distclean: clean + -rm -rf rev + +################################################################### +# Target implementations +################################################################### + +# Vivado project file +create_project.tcl: 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) $(PROJECT)" > $@ + echo "add_files -fileset sources_1 defines.v $(SYN_FILES_REL)" >> $@ + echo "set_property top $(FPGA_TOP) [current_fileset]" >> $@ + echo "add_files -fileset constrs_1 $(XDC_FILES_REL)" >> $@ + for x in $(XCI_FILES_REL); do echo "import_ip $$x" >> $@; done + for x in $(IP_TCL_FILES_REL); do echo "source $$x" >> $@; done + +$(PROJECT).xpr: create_project.tcl + vivado -nojournal -nolog -mode batch $(foreach x,$?,-source $x) + +# synthesis run +$(PROJECT).runs/synth_1/$(PROJECT).dcp: $(PROJECT).xpr $(SYN_FILES_REL) $(INC_FILES_REL) $(XDC_FILES_REL) + echo "open_project $(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 + vivado -nojournal -nolog -mode batch -source run_synth.tcl + +# implementation run +$(PROJECT).runs/impl_1/$(PROJECT)_routed.dcp: $(PROJECT).runs/synth_1/$(PROJECT).dcp + echo "open_project $(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 "open_run impl_1" >> run_impl.tcl + echo "report_utilization -file $(PROJECT)_utilization.rpt" >> run_impl.tcl + echo "report_utilization -hierarchical -file $(PROJECT)_utilization_hierarchical.rpt" >> run_impl.tcl + vivado -nojournal -nolog -mode batch -source run_impl.tcl + +# bit file +$(PROJECT).bit $(PROJECT).ltx: $(PROJECT).runs/impl_1/$(PROJECT)_routed.dcp + echo "open_project $(PROJECT).xpr" > generate_bit.tcl + echo "open_run impl_1" >> generate_bit.tcl + echo "write_bitstream -force $(PROJECT).runs/impl_1/$(PROJECT).bit" >> generate_bit.tcl + echo "write_debug_probes -force $(PROJECT).runs/impl_1/$(PROJECT).ltx" >> generate_bit.tcl + vivado -nojournal -nolog -mode batch -source generate_bit.tcl + ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).bit . + if [ -e $(PROJECT).runs/impl_1/$(PROJECT).ltx ]; then ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).ltx .; fi + mkdir -p rev + COUNT=100; \ + while [ -e rev/$(PROJECT)_rev$$COUNT.bit ]; \ + do COUNT=$$((COUNT+1)); done; \ + cp -pv $(PROJECT).runs/impl_1/$(PROJECT).bit rev/$(PROJECT)_rev$$COUNT.bit; \ + if [ -e $(PROJECT).runs/impl_1/$(PROJECT).ltx ]; then cp -pv $(PROJECT).runs/impl_1/$(PROJECT).ltx rev/$(PROJECT)_rev$$COUNT.ltx; fi diff --git a/example/KR260/fpga_10g/fpga.xdc b/example/KR260/fpga_10g/fpga.xdc new file mode 100644 index 000000000..f7ecaa24c --- /dev/null +++ b/example/KR260/fpga_10g/fpga.xdc @@ -0,0 +1,35 @@ +# XDC constraints for the AMD KR260 board +# part: XCK26-SFVC784-2LV-C/I + +# General configuration +set_property BITSTREAM.GENERAL.COMPRESS true [current_design] + +# System clocks +# +# use the 25 MHz clock outputs to the PL from U91 +# and feed that into a PLL to convert it to 125 MHz +set_property -dict {LOC C3 IOSTANDARD LVCMOS18} [get_ports clk_25mhz_ref] ;# HPA_CLK0P_CLK, HPA_CLK0_P, via U91, SOM240_1 A6 +create_clock -period 40.000 -name clk_25mhz [get_ports clk_25mhz_ref] + +# LEDs +set_property -dict {LOC F8 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {led[0]}] ;# HPA14P, HPA14_P, som240_1_d13, VCCO - som240_1_d1 +set_property -dict {LOC E8 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {led[1]}] ;# HPA14N, HPA14_N, som240_1_d14, VCCO - som240_1_d1 + +set_false_path -to [get_ports {led[*]}] +set_output_delay 0 [get_ports {led[*]}] + +# SFP+ Interface +set_property -dict {LOC T2 } [get_ports sfp0_rx_p] ;# GTH_DP2_C2M_P, som240_2_b1 +set_property -dict {LOC T1 } [get_ports sfp0_rx_n] ;# GTH_DP2_C2M_N, som240_2_b2 +set_property -dict {LOC R4 } [get_ports sfp0_tx_p] ;# GTH_DP2_M2C_P, som240_2_b5 +set_property -dict {LOC R3 } [get_ports sfp0_tx_n] ;# GTH_DP2_M2C_N, som240_2_b6 + +set_property -dict {LOC Y6 } [get_ports sfp_mgt_refclk_0_p] ;# GTH_REFCLK0_C2M_P via U90, SOM240_2 C3 +set_property -dict {LOC Y5 } [get_ports sfp_mgt_refclk_0_n] ;# GTH_REFCLK0_C2M_N via U90, SOM240_2 C4 +set_property -dict {LOC Y10 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8 } [get_ports sfp0_tx_disable_b] ;# HDB19, SOM240_2_A47 + +# 156.25 MHz MGT reference clock +create_clock -period 6.400 -name sfp_mgt_refclk_0 [get_ports sfp_mgt_refclk_0_p] + +set_false_path -to [get_ports {sfp0_tx_disable_b}] +set_output_delay 0 [get_ports {sfp0_tx_disable_b}] diff --git a/example/KR260/fpga_10g/fpga/Makefile b/example/KR260/fpga_10g/fpga/Makefile new file mode 100644 index 000000000..c8b187c63 --- /dev/null +++ b/example/KR260/fpga_10g/fpga/Makefile @@ -0,0 +1,74 @@ + +# FPGA settings +FPGA_PART = XCK26-SFVC784-2LV-C +FPGA_TOP = fpga +FPGA_ARCH = zynquplus + +# Files for synthesis +SYN_FILES = rtl/fpga.v +SYN_FILES += rtl/fpga_core.v +SYN_FILES += rtl/eth_xcvr_phy_wrapper.v +SYN_FILES += rtl/debounce_switch.v +SYN_FILES += rtl/sync_signal.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_rx_watchdog.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_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/eth_xcvr_gt.tcl +IP_TCL_FILES += ip/zynq_ps.tcl + +include ../common/vivado.mk + +program: $(FPGA_TOP).bit + echo "open_hw" > program.tcl + echo "connect_hw_server" >> program.tcl + echo "open_hw_target" >> program.tcl + echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl + echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl + echo "set_property PROGRAM.FILE {$(FPGA_TOP).bit} [current_hw_device]" >> program.tcl + echo "program_hw_devices [current_hw_device]" >> program.tcl + echo "exit" >> program.tcl + vivado -nojournal -nolog -mode batch -source program.tcl + diff --git a/example/KR260/fpga_10g/ip/eth_xcvr_gt.tcl b/example/KR260/fpga_10g/ip/eth_xcvr_gt.tcl new file mode 100644 index 000000000..990b94c4a --- /dev/null +++ b/example/KR260/fpga_10g/ip/eth_xcvr_gt.tcl @@ -0,0 +1,76 @@ +# Copyright (c) 2021 Alex Forencich +# +# 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. + +set base_name {eth_xcvr_gt} + +set preset {GTH-10GBASE-R} + +set freerun_freq {125} +set line_rate {10.3125} +set refclk_freq {156.25} +set qpll_fracn [expr {int(fmod($line_rate*1000/2 / $refclk_freq, 1)*pow(2, 24))}] +set user_data_width {64} +set int_data_width {32} +set extra_ports [list] +set extra_pll_ports [list {qpll0lock_out}] + +set config [dict create] + +dict set config TX_LINE_RATE $line_rate +dict set config TX_REFCLK_FREQUENCY $refclk_freq +dict set config TX_QPLL_FRACN_NUMERATOR $qpll_fracn +dict set config TX_USER_DATA_WIDTH $user_data_width +dict set config TX_INT_DATA_WIDTH $int_data_width +dict set config RX_LINE_RATE $line_rate +dict set config RX_REFCLK_FREQUENCY $refclk_freq +dict set config RX_QPLL_FRACN_NUMERATOR $qpll_fracn +dict set config RX_USER_DATA_WIDTH $user_data_width +dict set config RX_INT_DATA_WIDTH $int_data_width +dict set config ENABLE_OPTIONAL_PORTS $extra_ports +dict set config LOCATE_COMMON {CORE} +dict set config LOCATE_RESET_CONTROLLER {CORE} +dict set config LOCATE_TX_USER_CLOCKING {CORE} +dict set config LOCATE_RX_USER_CLOCKING {CORE} +dict set config LOCATE_USER_DATA_WIDTH_SIZING {CORE} +dict set config FREERUN_FREQUENCY $freerun_freq +dict set config DISABLE_LOC_XDC {1} + +proc create_gtwizard_ip {name preset config} { + create_ip -name gtwizard_ultrascale -vendor xilinx.com -library ip -module_name $name + set ip [get_ips $name] + set_property CONFIG.preset $preset $ip + set config_list {} + dict for {name value} $config { + lappend config_list "CONFIG.${name}" $value + } + set_property -dict $config_list $ip +} + +# variant with channel and common +dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] +dict set config LOCATE_COMMON {CORE} + +create_gtwizard_ip "${base_name}_full" $preset $config + +# variant with channel only +dict set config ENABLE_OPTIONAL_PORTS $extra_ports +dict set config LOCATE_COMMON {EXAMPLE_DESIGN} + +create_gtwizard_ip "${base_name}_channel" $preset $config diff --git a/example/KR260/fpga_10g/ip/zynq_ps.tcl b/example/KR260/fpga_10g/ip/zynq_ps.tcl new file mode 100644 index 000000000..f25b3aa9a --- /dev/null +++ b/example/KR260/fpga_10g/ip/zynq_ps.tcl @@ -0,0 +1,230 @@ +# Copyright 2022, The Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS +# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and documentation are those +# of the authors and should not be interpreted as representing official policies, +# either expressed or implied, of The Regents of the University of California. + +# create block design +create_bd_design "zynq_ps" + +# Create blocks + +# Zynq PS +set zynq_ultra_ps [ create_bd_cell -type ip -vlnv xilinx.com:ip:zynq_ultra_ps_e zynq_ultra_ps ] +set_property -dict [list \ + CONFIG.PSU_BANK_0_IO_STANDARD {LVCMOS18} \ + CONFIG.PSU_BANK_1_IO_STANDARD {LVCMOS18} \ + CONFIG.PSU_BANK_2_IO_STANDARD {LVCMOS18} \ + CONFIG.PSU_BANK_3_IO_STANDARD {LVCMOS33} \ + CONFIG.PSU_DYNAMIC_DDR_CONFIG_EN 1 \ + CONFIG.PSU__DDRC__COMPONENTS {UDIMM} \ + CONFIG.PSU__DDRC__DEVICE_CAPACITY {4096 MBits} \ + CONFIG.PSU__DDRC__SPEED_BIN {DDR4_2133P} \ + CONFIG.PSU__DDRC__ROW_ADDR_COUNT {15} \ + CONFIG.PSU__DDRC__T_RC {46.5} \ + CONFIG.PSU__DDRC__T_FAW {21.0} \ + CONFIG.PSU__DDRC__DDR4_ADDR_MAPPING {0} \ + CONFIG.PSU__DDRC__FREQ_MHZ {1067} \ + CONFIG.PSU__PMU__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__PMU__GPI0__ENABLE {1} \ + CONFIG.PSU__PMU__GPI1__ENABLE {0} \ + CONFIG.PSU__PMU__GPI2__ENABLE {0} \ + CONFIG.PSU__PMU__GPI3__ENABLE {0} \ + CONFIG.PSU__PMU__GPI4__ENABLE {0} \ + CONFIG.PSU__PMU__GPI5__ENABLE {0} \ + CONFIG.PSU__QSPI__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__QSPI__PERIPHERAL__MODE {Dual Parallel} \ + CONFIG.PSU__QSPI__GRP_FBCLK__ENABLE {1} \ + CONFIG.PSU__CAN1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__CAN1__PERIPHERAL__IO {MIO 24 .. 25} \ + CONFIG.PSU__GPIO0_MIO__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__GPIO1_MIO__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__I2C0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__I2C0__PERIPHERAL__IO {MIO 14 .. 15} \ + CONFIG.PSU__I2C1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__I2C1__PERIPHERAL__IO {MIO 16 .. 17} \ + CONFIG.PSU__UART0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__UART0__PERIPHERAL__IO {MIO 18 .. 19} \ + CONFIG.PSU__UART1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__UART1__PERIPHERAL__IO {MIO 20 .. 21} \ + CONFIG.PSU__SD1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__SD1__GRP_CD__ENABLE {1} \ + CONFIG.PSU__SD1__GRP_WP__ENABLE {1} \ + CONFIG.PSU__ENET3__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__ENET3__GRP_MDIO__ENABLE {1} \ + CONFIG.PSU__USB0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__USB0__REF_CLK_SEL {Ref Clk2} \ + CONFIG.PSU__USB3_0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__USB3_0__PERIPHERAL__IO {GT Lane2} \ + CONFIG.PSU__DISPLAYPORT__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__DPAUX__PERIPHERAL__IO {MIO 27 .. 30} \ + CONFIG.PSU__DP__REF_CLK_SEL {Ref Clk3} \ + CONFIG.PSU__DP__LANE_SEL {Single Lower} \ + CONFIG.PSU__SATA__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__SATA__LANE1__IO {GT Lane3} \ + CONFIG.PSU__PCIE__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__PCIE__PERIPHERAL__ROOTPORT_IO {MIO 31} \ + CONFIG.PSU__PCIE__DEVICE_PORT_TYPE {Root Port} \ + CONFIG.PSU__PCIE__BAR0_ENABLE {0} \ + CONFIG.PSU__PCIE__CLASS_CODE_BASE {0x06} \ + CONFIG.PSU__PCIE__CLASS_CODE_SUB {0x04} \ + CONFIG.PSU__SWDT0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__SWDT1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__TTC0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__TTC1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__TTC2__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__TTC3__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__USE__M_AXI_GP0 {1} \ + CONFIG.PSU__MAXIGP0__DATA_WIDTH {32} \ + CONFIG.PSU__USE__M_AXI_GP1 {0} \ + CONFIG.PSU__USE__M_AXI_GP2 {0} \ + CONFIG.PSU__USE__S_AXI_GP0 {1} \ + CONFIG.PSU__USE__IRQ0 {1} \ + CONFIG.PSU__CRF_APB__ACPU_CTRL__SRCSEL {APLL} \ + CONFIG.PSU__CRF_APB__DDR_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRF_APB__DP_VIDEO_REF_CTRL__SRCSEL {VPLL} \ + CONFIG.PSU__CRF_APB__DP_AUDIO_REF_CTRL__SRCSEL {RPLL} \ + CONFIG.PSU__CRF_APB__DP_STC_REF_CTRL__SRCSEL {RPLL} \ + CONFIG.PSU__CRF_APB__DPDMA_REF_CTRL__FREQMHZ {667} \ + CONFIG.PSU__CRF_APB__DPDMA_REF_CTRL__SRCSEL {APLL} \ + CONFIG.PSU__CRF_APB__GDMA_REF_CTRL__FREQMHZ {667} \ + CONFIG.PSU__CRF_APB__GDMA_REF_CTRL__SRCSEL {APLL} \ + CONFIG.PSU__CRF_APB__GPU_REF_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRF_APB__TOPSW_MAIN_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRF_APB__TOPSW_LSBUS_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__ADMA_REF_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRL_APB__CPU_R5_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRL_APB__IOU_SWITCH_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRL_APB__LPD_LSBUS_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__LPD_SWITCH_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRL_APB__PCAP_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__PL0_REF_CTRL__FREQMHZ {300} \ + CONFIG.PSU__CRL_APB__PL0_REF_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__SDIO1_REF_CTRL__SRCSEL {IOPLL} \ +] $zynq_ultra_ps + +# control AXI interconnect +set axi_interconnect_ctrl [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect axi_interconnect_ctrl ] + +# reset +set proc_sys_reset [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset proc_sys_reset ] + +# Create connections + +# Clock +set pl_clk0 [get_bd_pins $zynq_ultra_ps/pl_clk0] +make_bd_pins_external $pl_clk0 +set_property name pl_clk0 [get_bd_ports -of_objects [get_bd_nets -of_objects $pl_clk0]] +set pl_clk0_port [get_bd_ports -of_objects [get_bd_nets -of_objects $pl_clk0]] + +connect_bd_net $pl_clk0 [get_bd_pins $zynq_ultra_ps/maxihpm0_fpd_aclk] +connect_bd_net $pl_clk0 [get_bd_pins $zynq_ultra_ps/saxihpc0_fpd_aclk] +connect_bd_net $pl_clk0 [get_bd_pins $proc_sys_reset/slowest_sync_clk] +connect_bd_net $pl_clk0 [get_bd_pins $axi_interconnect_ctrl/ACLK] +connect_bd_net $pl_clk0 [get_bd_pins $axi_interconnect_ctrl/S00_ACLK] +connect_bd_net $pl_clk0 [get_bd_pins $axi_interconnect_ctrl/M00_ACLK] +connect_bd_net $pl_clk0 [get_bd_pins $axi_interconnect_ctrl/M01_ACLK] + +set pl_clk0_busif [list] + +# Reset +set pl_resetn0 [get_bd_pins $zynq_ultra_ps/pl_resetn0] +connect_bd_net $pl_resetn0 [get_bd_pins $proc_sys_reset/ext_reset_in] + +set pl_reset [get_bd_pins $proc_sys_reset/peripheral_reset] +make_bd_pins_external $pl_reset +set_property name pl_reset [get_bd_ports -of_objects [get_bd_nets -of_objects $pl_reset]] + +set interconnect_aresetn [get_bd_pins $proc_sys_reset/interconnect_aresetn] +connect_bd_net $interconnect_aresetn [get_bd_pins $axi_interconnect_ctrl/ARESETN] +connect_bd_net $interconnect_aresetn [get_bd_pins $axi_interconnect_ctrl/S00_ARESETN] +connect_bd_net $interconnect_aresetn [get_bd_pins $axi_interconnect_ctrl/M00_ARESETN] +connect_bd_net $interconnect_aresetn [get_bd_pins $axi_interconnect_ctrl/M01_ARESETN] + +# MMIO +connect_bd_intf_net [get_bd_intf_pins $zynq_ultra_ps/M_AXI_HPM0_FPD] [get_bd_intf_pins $axi_interconnect_ctrl/S00_AXI] + +# Control interface +set m_axil_ctrl_pin [get_bd_intf_pins $axi_interconnect_ctrl/M00_AXI] +make_bd_intf_pins_external $m_axil_ctrl_pin +set_property name m_axil_ctrl [get_bd_intf_ports -of_objects [get_bd_intf_nets -of_objects $m_axil_ctrl_pin]] +set m_axil_ctrl_port [get_bd_intf_ports -of_objects [get_bd_intf_nets -of_objects $m_axil_ctrl_pin]] +set_property -dict [list \ + CONFIG.PROTOCOL AXI4LITE \ + CONFIG.DATA_WIDTH 32 \ + CONFIG.ADDR_WIDTH 24 \ +] $m_axil_ctrl_port +lappend pl_clk0_busif $m_axil_ctrl_port + +# Application control interface +set m_axil_app_ctrl_pin [get_bd_intf_pins $axi_interconnect_ctrl/M01_AXI] +make_bd_intf_pins_external $m_axil_app_ctrl_pin +set_property name m_axil_app_ctrl [get_bd_intf_ports -of_objects [get_bd_intf_nets -of_objects $m_axil_app_ctrl_pin]] +set m_axil_app_ctrl_port [get_bd_intf_ports -of_objects [get_bd_intf_nets -of_objects $m_axil_app_ctrl_pin]] +set_property -dict [list \ + CONFIG.PROTOCOL AXI4LITE \ + CONFIG.DATA_WIDTH 32 \ + CONFIG.ADDR_WIDTH 24 \ +] $m_axil_app_ctrl_port +lappend pl_clk0_busif $m_axil_app_ctrl_port + +# DMA interface +set s_axi_dma_pin [get_bd_intf_pins $zynq_ultra_ps/S_AXI_HPC0_FPD] +make_bd_intf_pins_external $s_axi_dma_pin +set_property name s_axi_dma [get_bd_intf_ports -of_objects [get_bd_intf_nets -of_objects $s_axi_dma_pin]] +set s_axi_dma_port [get_bd_intf_ports -of_objects [get_bd_intf_nets -of_objects $s_axi_dma_pin]] +lappend pl_clk0_busif $s_axi_dma_port + +# IRQ +set pl_ps_irq0 [get_bd_pins $zynq_ultra_ps/pl_ps_irq0] +make_bd_pins_external $pl_ps_irq0 +set_property name pl_ps_irq0 [get_bd_ports -of_objects [get_bd_nets -of_objects $pl_ps_irq0]] +set pl_ps_irq0_port [get_bd_ports -of_objects [get_bd_nets -of_objects $pl_ps_irq0]] +set_property -dict [list \ + CONFIG.PortWidth 8 \ +] $pl_ps_irq0_port + +# Port clock associations +set lst [list] +foreach port $pl_clk0_busif { + lappend lst [get_property name $port] +} +set_property CONFIG.ASSOCIATED_BUSIF [join $lst ":"] $pl_clk0_port + +# Assign addresses +assign_bd_address -target_address_space /s_axi_dma [get_bd_addr_segs $zynq_ultra_ps/SAXIGP0/HPC0_DDR_HIGH] -force +assign_bd_address -target_address_space /s_axi_dma [get_bd_addr_segs $zynq_ultra_ps/SAXIGP0/HPC0_QSPI] -force +assign_bd_address -target_address_space /s_axi_dma [get_bd_addr_segs $zynq_ultra_ps/SAXIGP0/HPC0_DDR_LOW] -force +assign_bd_address -target_address_space /s_axi_dma [get_bd_addr_segs $zynq_ultra_ps/SAXIGP0/HPC0_LPS_OCM] -force + +assign_bd_address -offset 0xA000_0000 -range 16M -target_address_space $zynq_ultra_ps/Data [get_bd_addr_segs $m_axil_ctrl_port/Reg] -force +assign_bd_address -offset 0xA800_0000 -range 16M -target_address_space $zynq_ultra_ps/Data [get_bd_addr_segs $m_axil_app_ctrl_port/Reg] -force + +validate_bd_design + +# Save block design +save_bd_design [current_bd_design] +close_bd_design [current_bd_design] diff --git a/example/KR260/fpga_10g/lib/eth b/example/KR260/fpga_10g/lib/eth new file mode 120000 index 000000000..11a54ed36 --- /dev/null +++ b/example/KR260/fpga_10g/lib/eth @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/example/KR260/fpga_10g/rtl/debounce_switch.v b/example/KR260/fpga_10g/rtl/debounce_switch.v new file mode 100644 index 000000000..8e93a50c4 --- /dev/null +++ b/example/KR260/fpga_10g/rtl/debounce_switch.v @@ -0,0 +1,93 @@ +/* + +Copyright (c) 2014-2018 Alex Forencich + +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 + +`resetall +`timescale 1 ns / 1 ps +`default_nettype none + +/* + * Synchronizes switch and button inputs with a slow sampled shift register + */ +module debounce_switch #( + parameter WIDTH=1, // width of the input and output signals + parameter N=3, // length of shift register + parameter RATE=125000 // clock division factor +)( + input wire clk, + input wire rst, + input wire [WIDTH-1:0] in, + output wire [WIDTH-1:0] out +); + +reg [23:0] cnt_reg = 24'd0; + +reg [N-1:0] debounce_reg[WIDTH-1:0]; + +reg [WIDTH-1:0] state; + +/* + * The synchronized output is the state register + */ +assign out = state; + +integer k; + +always @(posedge clk or posedge rst) begin + if (rst) begin + cnt_reg <= 0; + state <= 0; + + for (k = 0; k < WIDTH; k = k + 1) begin + debounce_reg[k] <= 0; + end + end else begin + if (cnt_reg < RATE) begin + cnt_reg <= cnt_reg + 24'd1; + end else begin + cnt_reg <= 24'd0; + end + + if (cnt_reg == 24'd0) begin + for (k = 0; k < WIDTH; k = k + 1) begin + debounce_reg[k] <= {debounce_reg[k][N-2:0], in[k]}; + end + end + + for (k = 0; k < WIDTH; k = k + 1) begin + if (|debounce_reg[k] == 0) begin + state[k] <= 0; + end else if (&debounce_reg[k] == 1) begin + state[k] <= 1; + end else begin + state[k] <= state[k]; + end + end + end +end + +endmodule + +`resetall diff --git a/example/KR260/fpga_10g/rtl/eth_xcvr_phy_wrapper.v b/example/KR260/fpga_10g/rtl/eth_xcvr_phy_wrapper.v new file mode 100644 index 000000000..bbbfd08d6 --- /dev/null +++ b/example/KR260/fpga_10g/rtl/eth_xcvr_phy_wrapper.v @@ -0,0 +1,299 @@ +/* + +Copyright (c) 2021 Alex Forencich + +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 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Transceiver and PHY wrapper + */ +module eth_xcvr_phy_wrapper # +( + parameter HAS_COMMON = 1, + parameter DATA_WIDTH = 64, + parameter CTRL_WIDTH = (DATA_WIDTH/8), + parameter HDR_WIDTH = 2, + parameter PRBS31_ENABLE = 0, + parameter TX_SERDES_PIPELINE = 0, + parameter RX_SERDES_PIPELINE = 0, + parameter BITSLIP_HIGH_CYCLES = 1, + parameter BITSLIP_LOW_CYCLES = 8, + parameter COUNT_125US = 125000/6.4 +) +( + input wire xcvr_ctrl_clk, + input wire xcvr_ctrl_rst, + + /* + * Common + */ + output wire xcvr_gtpowergood_out, + + /* + * PLL out + */ + input wire xcvr_gtrefclk00_in, + output wire xcvr_qpll0lock_out, + output wire xcvr_qpll0outclk_out, + output wire xcvr_qpll0outrefclk_out, + + /* + * PLL in + */ + input wire xcvr_qpll0lock_in, + output wire xcvr_qpll0reset_out, + input wire xcvr_qpll0clk_in, + input wire xcvr_qpll0refclk_in, + + /* + * Serial data + */ + output wire xcvr_txp, + output wire xcvr_txn, + input wire xcvr_rxp, + input wire xcvr_rxn, + + /* + * PHY connections + */ + output wire phy_tx_clk, + output wire phy_tx_rst, + input wire [DATA_WIDTH-1:0] phy_xgmii_txd, + input wire [CTRL_WIDTH-1:0] phy_xgmii_txc, + output wire phy_rx_clk, + output wire phy_rx_rst, + output wire [DATA_WIDTH-1:0] phy_xgmii_rxd, + output wire [CTRL_WIDTH-1:0] phy_xgmii_rxc, + output wire phy_tx_bad_block, + output wire [6:0] phy_rx_error_count, + output wire phy_rx_bad_block, + output wire phy_rx_sequence_error, + output wire phy_rx_block_lock, + output wire phy_rx_high_ber, + input wire phy_tx_prbs31_enable, + input wire phy_rx_prbs31_enable +); + +wire phy_rx_reset_req; + +wire gt_reset_tx_datapath = 1'b0; +wire gt_reset_rx_datapath = phy_rx_reset_req; + +wire gt_reset_tx_done; +wire gt_reset_rx_done; + +wire [5:0] gt_txheader; +wire [63:0] gt_txdata; +wire gt_rxgearboxslip; +wire [5:0] gt_rxheader; +wire [1:0] gt_rxheadervalid; +wire [63:0] gt_rxdata; +wire [1:0] gt_rxdatavalid; + +generate + +if (HAS_COMMON) begin : xcvr + + eth_xcvr_gt_full + eth_xcvr_gt_full_inst ( + // Common + .gtwiz_reset_clk_freerun_in(xcvr_ctrl_clk), + .gtwiz_reset_all_in(xcvr_ctrl_rst), + .gtpowergood_out(xcvr_gtpowergood_out), + + // PLL + .gtrefclk00_in(xcvr_gtrefclk00_in), + .qpll0lock_out(xcvr_qpll0lock_out), + .qpll0outclk_out(xcvr_qpll0outclk_out), + .qpll0outrefclk_out(xcvr_qpll0outrefclk_out), + + // Serial data + .gthtxp_out(xcvr_txp), + .gthtxn_out(xcvr_txn), + .gthrxp_in(xcvr_rxp), + .gthrxn_in(xcvr_rxn), + + // Transmit + .gtwiz_userclk_tx_reset_in(1'b0), + .gtwiz_userclk_tx_srcclk_out(), + .gtwiz_userclk_tx_usrclk_out(), + .gtwiz_userclk_tx_usrclk2_out(phy_tx_clk), + .gtwiz_userclk_tx_active_out(), + .gtwiz_reset_tx_pll_and_datapath_in(1'b0), + .gtwiz_reset_tx_datapath_in(gt_reset_tx_datapath), + .gtwiz_reset_tx_done_out(gt_reset_tx_done), + .txpmaresetdone_out(), + .txprgdivresetdone_out(), + + .gtwiz_userdata_tx_in(gt_txdata), + .txheader_in(gt_txheader), + .txsequence_in(7'b0), + + // Receive + .gtwiz_userclk_rx_reset_in(1'b0), + .gtwiz_userclk_rx_srcclk_out(), + .gtwiz_userclk_rx_usrclk_out(), + .gtwiz_userclk_rx_usrclk2_out(phy_rx_clk), + .gtwiz_userclk_rx_active_out(), + .gtwiz_reset_rx_pll_and_datapath_in(1'b0), + .gtwiz_reset_rx_datapath_in(gt_reset_rx_datapath), + .gtwiz_reset_rx_cdr_stable_out(), + .gtwiz_reset_rx_done_out(gt_reset_rx_done), + .rxpmaresetdone_out(), + .rxprgdivresetdone_out(), + + .rxgearboxslip_in(gt_rxgearboxslip), + .gtwiz_userdata_rx_out(gt_rxdata), + .rxdatavalid_out(gt_rxdatavalid), + .rxheader_out(gt_rxheader), + .rxheadervalid_out(gt_rxheadervalid), + .rxstartofseq_out() + ); + +end else begin : xcvr + + eth_xcvr_gt_channel + eth_xcvr_gt_channel_inst ( + // Common + .gtwiz_reset_clk_freerun_in(xcvr_ctrl_clk), + .gtwiz_reset_all_in(xcvr_ctrl_rst), + .gtpowergood_out(xcvr_gtpowergood_out), + + // PLL + .gtwiz_reset_qpll0lock_in(xcvr_qpll0lock_in), + .gtwiz_reset_qpll0reset_out(xcvr_qpll0reset_out), + .qpll0clk_in(xcvr_qpll0clk_in), + .qpll0refclk_in(xcvr_qpll0refclk_in), + .qpll1clk_in(1'b0), + .qpll1refclk_in(1'b0), + + // Serial data + .gthtxp_out(xcvr_txp), + .gthtxn_out(xcvr_txn), + .gthrxp_in(xcvr_rxp), + .gthrxn_in(xcvr_rxn), + + // Transmit + .gtwiz_userclk_tx_reset_in(1'b0), + .gtwiz_userclk_tx_srcclk_out(), + .gtwiz_userclk_tx_usrclk_out(), + .gtwiz_userclk_tx_usrclk2_out(phy_tx_clk), + .gtwiz_userclk_tx_active_out(), + .gtwiz_reset_tx_pll_and_datapath_in(1'b0), + .gtwiz_reset_tx_datapath_in(gt_reset_tx_datapath), + .gtwiz_reset_tx_done_out(gt_reset_tx_done), + .txpmaresetdone_out(), + .txprgdivresetdone_out(), + + .gtwiz_userdata_tx_in(gt_txdata), + .txheader_in(gt_txheader), + .txsequence_in(7'b0), + + // Receive + .gtwiz_userclk_rx_reset_in(1'b0), + .gtwiz_userclk_rx_srcclk_out(), + .gtwiz_userclk_rx_usrclk_out(), + .gtwiz_userclk_rx_usrclk2_out(phy_rx_clk), + .gtwiz_userclk_rx_active_out(), + .gtwiz_reset_rx_pll_and_datapath_in(1'b0), + .gtwiz_reset_rx_datapath_in(gt_reset_rx_datapath), + .gtwiz_reset_rx_cdr_stable_out(), + .gtwiz_reset_rx_done_out(gt_reset_rx_done), + .rxpmaresetdone_out(), + .rxprgdivresetdone_out(), + + .rxgearboxslip_in(gt_rxgearboxslip), + .gtwiz_userdata_rx_out(gt_rxdata), + .rxdatavalid_out(gt_rxdatavalid), + .rxheader_out(gt_rxheader), + .rxheadervalid_out(gt_rxheadervalid), + .rxstartofseq_out() + ); + +end + +endgenerate + +sync_reset #( + .N(4) +) +tx_reset_sync_inst ( + .clk(phy_tx_clk), + .rst(!gt_reset_tx_done), + .out(phy_tx_rst) +); + +sync_reset #( + .N(4) +) +rx_reset_sync_inst ( + .clk(phy_rx_clk), + .rst(!gt_reset_rx_done), + .out(phy_rx_rst) +); + +eth_phy_10g #( + .DATA_WIDTH(DATA_WIDTH), + .CTRL_WIDTH(CTRL_WIDTH), + .HDR_WIDTH(HDR_WIDTH), + .BIT_REVERSE(1), + .SCRAMBLER_DISABLE(0), + .PRBS31_ENABLE(PRBS31_ENABLE), + .TX_SERDES_PIPELINE(TX_SERDES_PIPELINE), + .RX_SERDES_PIPELINE(RX_SERDES_PIPELINE), + .BITSLIP_HIGH_CYCLES(BITSLIP_HIGH_CYCLES), + .BITSLIP_LOW_CYCLES(BITSLIP_LOW_CYCLES), + .COUNT_125US(COUNT_125US) +) +phy_inst ( + .tx_clk(phy_tx_clk), + .tx_rst(phy_tx_rst), + .rx_clk(phy_rx_clk), + .rx_rst(phy_rx_rst), + .xgmii_txd(phy_xgmii_txd), + .xgmii_txc(phy_xgmii_txc), + .xgmii_rxd(phy_xgmii_rxd), + .xgmii_rxc(phy_xgmii_rxc), + .serdes_tx_data(gt_txdata), + .serdes_tx_hdr(gt_txheader), + .serdes_rx_data(gt_rxdata), + .serdes_rx_hdr(gt_rxheader), + .serdes_rx_bitslip(gt_rxgearboxslip), + .serdes_rx_reset_req(phy_rx_reset_req), + .tx_bad_block(phy_tx_bad_block), + .rx_error_count(phy_rx_error_count), + .rx_bad_block(phy_rx_bad_block), + .rx_sequence_error(phy_rx_sequence_error), + .rx_block_lock(phy_rx_block_lock), + .rx_high_ber(phy_rx_high_ber), + .tx_prbs31_enable(phy_tx_prbs31_enable), + .rx_prbs31_enable(phy_rx_prbs31_enable) +); + +endmodule + +`resetall diff --git a/example/KR260/fpga_10g/rtl/fpga.v b/example/KR260/fpga_10g/rtl/fpga.v new file mode 100644 index 000000000..eca2bec72 --- /dev/null +++ b/example/KR260/fpga_10g/rtl/fpga.v @@ -0,0 +1,500 @@ +/* + +Copyright (c) 2020-2021 Alex Forencich +Copyright (c) 2023 Víctor Mayoral Vilches + +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 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * FPGA top-level module + */ +module fpga # +( + // AXI interface configuration (DMA) + parameter AXI_DATA_WIDTH = 128, + parameter AXI_ADDR_WIDTH = 32, + parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8), + parameter AXI_ID_WIDTH = 8, + + // Interrupts + parameter IRQ_COUNT = 32, + parameter IRQ_STRETCH = 10, + + // AXI lite interface configuration (control) + parameter AXIL_CTRL_DATA_WIDTH = 32, + parameter AXIL_CTRL_ADDR_WIDTH = 24, + parameter AXIL_CTRL_STRB_WIDTH = (AXIL_CTRL_DATA_WIDTH/8), + + // AXI lite interface configuration (application control) + parameter AXIL_APP_CTRL_DATA_WIDTH = AXIL_CTRL_DATA_WIDTH, + parameter AXIL_APP_CTRL_ADDR_WIDTH = 24, + parameter AXIL_APP_CTRL_STRB_WIDTH = (AXIL_APP_CTRL_DATA_WIDTH/8) +) +( + /* + * Clock: 25 MHz LVCMOS18 + */ + input wire clk_25mhz_ref, + + /* + * GPIO + */ + output wire [1:0] led, + + /* + * Ethernet: SFP+ + */ + input wire sfp0_rx_p, + input wire sfp0_rx_n, + output wire sfp0_tx_p, + output wire sfp0_tx_n, + input wire sfp_mgt_refclk_0_p, + input wire sfp_mgt_refclk_0_n, + output wire sfp0_tx_disable_b +); + +// Clock and reset +wire clk_25mhz_bufg; + +// 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 = reset; +wire mmcm_locked; +wire mmcm_clkfb; + + +// BUFG stands for "buffer gate." The BUFG primitive is used to create a +// buffer gate, which is a digital circuit component that is used to +// amplify and/or isolate a signal. +// +// Using a BUFG gate helps to ensure that the clock signal is distributed +// properly throughout the system and reaches all the necessary components +// with minimal delay. +// +// https://docs.xilinx.com/r/2022.1-English/ug974-vivado-ultrascale-libraries/BUFG +BUFG +clk_25mhz_bufg_in_inst ( + .I(clk_25mhz_ref), + .O(clk_25mhz_bufg) +); + + +// Base Mixed Mode Clock Manager (MMCM) +// +// used to implement a Phase-Locked Loop (PLL) with Multiplier/Multiplier +// and Phase Shift (MMCM) functionality +// see https://docs.xilinx.com/r/2022.1-English/ug974-vivado-ultrascale-libraries/MMCME4_BASE + +// MMCM instance +// 25 MHz in, 125 MHz out +// PFD range: 10 MHz to 500 MHz +// VCO range: 800 MHz to 1600 MHz +// M = 8, D = 1 sets Fvco = 1000 MHz (in range) +// Divide by 8 to get output frequency of 125 MHz +MMCME4_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(40), + .CLKFBOUT_PHASE(0), + .DIVCLK_DIVIDE(1), + .REF_JITTER1(0.010), + .CLKIN1_PERIOD(40.0), + .STARTUP_WAIT("FALSE"), + .CLKOUT4_CASCADE("FALSE") +) +clk_mmcm_inst ( + .CLKIN1(clk_25mhz_bufg), + .CLKFBIN(mmcm_clkfb), + // .RST(mmcm_rst), + .RST(1'b0), + .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) +); + +// Clock and reset +wire zynq_pl_clk; +wire zynq_pl_reset; + +// Zynq AXI MM +wire [IRQ_COUNT-1:0] irq; + +wire [AXI_ID_WIDTH-1:0] axi_awid; +wire [AXI_ADDR_WIDTH-1:0] axi_awaddr; +wire [7:0] axi_awlen; +wire [2:0] axi_awsize; +wire [1:0] axi_awburst; +wire axi_awlock; +wire [3:0] axi_awcache; +wire [2:0] axi_awprot; +wire axi_awvalid; +wire axi_awready; +wire [AXI_DATA_WIDTH-1:0] axi_wdata; +wire [AXI_STRB_WIDTH-1:0] axi_wstrb; +wire axi_wlast; +wire axi_wvalid; +wire axi_wready; +wire [AXI_ID_WIDTH-1:0] axi_bid; +wire [1:0] axi_bresp; +wire axi_bvalid; +wire axi_bready; +wire [AXI_ID_WIDTH-1:0] axi_arid; +wire [AXI_ADDR_WIDTH-1:0] axi_araddr; +wire [7:0] axi_arlen; +wire [2:0] axi_arsize; +wire [1:0] axi_arburst; +wire axi_arlock; +wire [3:0] axi_arcache; +wire [2:0] axi_arprot; +wire axi_arvalid; +wire axi_arready; +wire [AXI_ID_WIDTH-1:0] axi_rid; +wire [AXI_DATA_WIDTH-1:0] axi_rdata; +wire [1:0] axi_rresp; +wire axi_rlast; +wire axi_rvalid; +wire axi_rready; + +// AXI lite connections +wire [AXIL_CTRL_ADDR_WIDTH-1:0] axil_ctrl_awaddr; +wire [2:0] axil_ctrl_awprot; +wire axil_ctrl_awvalid; +wire axil_ctrl_awready; +wire [AXIL_CTRL_DATA_WIDTH-1:0] axil_ctrl_wdata; +wire [AXIL_CTRL_STRB_WIDTH-1:0] axil_ctrl_wstrb; +wire axil_ctrl_wvalid; +wire axil_ctrl_wready; +wire [1:0] axil_ctrl_bresp; +wire axil_ctrl_bvalid; +wire axil_ctrl_bready; +wire [AXIL_CTRL_ADDR_WIDTH-1:0] axil_ctrl_araddr; +wire [2:0] axil_ctrl_arprot; +wire axil_ctrl_arvalid; +wire axil_ctrl_arready; +wire [AXIL_CTRL_DATA_WIDTH-1:0] axil_ctrl_rdata; +wire [1:0] axil_ctrl_rresp; +wire axil_ctrl_rvalid; +wire axil_ctrl_rready; + +wire [AXIL_APP_CTRL_ADDR_WIDTH-1:0] axil_app_ctrl_awaddr; +wire [2:0] axil_app_ctrl_awprot; +wire axil_app_ctrl_awvalid; +wire axil_app_ctrl_awready; +wire [AXIL_APP_CTRL_DATA_WIDTH-1:0] axil_app_ctrl_wdata; +wire [AXIL_APP_CTRL_STRB_WIDTH-1:0] axil_app_ctrl_wstrb; +wire axil_app_ctrl_wvalid; +wire axil_app_ctrl_wready; +wire [1:0] axil_app_ctrl_bresp; +wire axil_app_ctrl_bvalid; +wire axil_app_ctrl_bready; +wire [AXIL_APP_CTRL_ADDR_WIDTH-1:0] axil_app_ctrl_araddr; +wire [2:0] axil_app_ctrl_arprot; +wire axil_app_ctrl_arvalid; +wire axil_app_ctrl_arready; +wire [AXIL_APP_CTRL_DATA_WIDTH-1:0] axil_app_ctrl_rdata; +wire [1:0] axil_app_ctrl_rresp; +wire axil_app_ctrl_rvalid; +wire axil_app_ctrl_rready; + +// implements an interrupt stretching mechanism to extend the duration +// of an interrupt signal to ensure that it is long enough to be detected +// by the receiving system. +reg [(IRQ_COUNT*IRQ_STRETCH)-1:0] irq_stretch = {(IRQ_COUNT*IRQ_STRETCH){1'b0}}; +always @(posedge zynq_pl_clk) begin + if (zynq_pl_reset) begin + irq_stretch <= {(IRQ_COUNT*IRQ_STRETCH){1'b0}}; + end else begin + /* IRQ shift vector */ + irq_stretch <= {irq_stretch[0 +: (IRQ_COUNT*IRQ_STRETCH)-IRQ_COUNT], irq}; + end +end + +reg [IRQ_COUNT-1:0] zynq_irq; +integer i, k; +always @* begin + for (k = 0; k < IRQ_COUNT; k = k + 1) begin + zynq_irq[k] = 1'b0; + for (i = 0; i < (IRQ_COUNT*IRQ_STRETCH); i = i + IRQ_COUNT) begin + zynq_irq[k] = zynq_irq[k] | irq_stretch[k + i]; + end + end +end + +// Zynq UltraScale+ PS +zynq_ps zynq_ps_inst ( + .pl_clk0(zynq_pl_clk), + .pl_reset(zynq_pl_reset), + .pl_ps_irq0(zynq_irq), + + .m_axil_ctrl_araddr(axil_ctrl_araddr), + .m_axil_ctrl_arprot(axil_ctrl_arprot), + .m_axil_ctrl_arready(axil_ctrl_arready), + .m_axil_ctrl_arvalid(axil_ctrl_arvalid), + .m_axil_ctrl_awaddr(axil_ctrl_awaddr), + .m_axil_ctrl_awprot(axil_ctrl_awprot), + .m_axil_ctrl_awready(axil_ctrl_awready), + .m_axil_ctrl_awvalid(axil_ctrl_awvalid), + .m_axil_ctrl_bready(axil_ctrl_bready), + .m_axil_ctrl_bresp(axil_ctrl_bresp), + .m_axil_ctrl_bvalid(axil_ctrl_bvalid), + .m_axil_ctrl_rdata(axil_ctrl_rdata), + .m_axil_ctrl_rready(axil_ctrl_rready), + .m_axil_ctrl_rresp(axil_ctrl_rresp), + .m_axil_ctrl_rvalid(axil_ctrl_rvalid), + .m_axil_ctrl_wdata(axil_ctrl_wdata), + .m_axil_ctrl_wready(axil_ctrl_wready), + .m_axil_ctrl_wstrb(axil_ctrl_wstrb), + .m_axil_ctrl_wvalid(axil_ctrl_wvalid), + + .m_axil_app_ctrl_araddr(axil_app_ctrl_araddr), + .m_axil_app_ctrl_arprot(axil_app_ctrl_arprot), + .m_axil_app_ctrl_arready(axil_app_ctrl_arready), + .m_axil_app_ctrl_arvalid(axil_app_ctrl_arvalid), + .m_axil_app_ctrl_awaddr(axil_app_ctrl_awaddr), + .m_axil_app_ctrl_awprot(axil_app_ctrl_awprot), + .m_axil_app_ctrl_awready(axil_app_ctrl_awready), + .m_axil_app_ctrl_awvalid(axil_app_ctrl_awvalid), + .m_axil_app_ctrl_bready(axil_app_ctrl_bready), + .m_axil_app_ctrl_bresp(axil_app_ctrl_bresp), + .m_axil_app_ctrl_bvalid(axil_app_ctrl_bvalid), + .m_axil_app_ctrl_rdata(axil_app_ctrl_rdata), + .m_axil_app_ctrl_rready(axil_app_ctrl_rready), + .m_axil_app_ctrl_rresp(axil_app_ctrl_rresp), + .m_axil_app_ctrl_rvalid(axil_app_ctrl_rvalid), + .m_axil_app_ctrl_wdata(axil_app_ctrl_wdata), + .m_axil_app_ctrl_wready(axil_app_ctrl_wready), + .m_axil_app_ctrl_wstrb(axil_app_ctrl_wstrb), + .m_axil_app_ctrl_wvalid(axil_app_ctrl_wvalid), + + .s_axi_dma_araddr(axi_araddr), + .s_axi_dma_arburst(axi_arburst), + .s_axi_dma_arcache(axi_arcache), + .s_axi_dma_arid(axi_arid), + .s_axi_dma_arlen(axi_arlen), + .s_axi_dma_arlock(axi_arlock), + .s_axi_dma_arprot(axi_arprot), + .s_axi_dma_arqos({4{1'b0}}), + .s_axi_dma_arready(axi_arready), + .s_axi_dma_arsize(axi_arsize), + .s_axi_dma_aruser(1'b0), + .s_axi_dma_arvalid(axi_arvalid), + .s_axi_dma_awaddr(axi_awaddr), + .s_axi_dma_awburst(axi_awburst), + .s_axi_dma_awcache(axi_awcache), + .s_axi_dma_awid(axi_awid), + .s_axi_dma_awlen(axi_awlen), + .s_axi_dma_awlock(axi_awlock), + .s_axi_dma_awprot(axi_awprot), + .s_axi_dma_awqos({4{1'b0}}), + .s_axi_dma_awready(axi_awready), + .s_axi_dma_awsize(axi_awsize), + .s_axi_dma_awuser(1'b0), + .s_axi_dma_awvalid(axi_awvalid), + .s_axi_dma_bid(axi_bid), + .s_axi_dma_bready(axi_bready), + .s_axi_dma_bresp(axi_bresp), + .s_axi_dma_bvalid(axi_bvalid), + .s_axi_dma_rdata(axi_rdata), + .s_axi_dma_rid(axi_rid), + .s_axi_dma_rlast(axi_rlast), + .s_axi_dma_rready(axi_rready), + .s_axi_dma_rresp(axi_rresp), + .s_axi_dma_rvalid(axi_rvalid), + .s_axi_dma_wdata(axi_wdata), + .s_axi_dma_wlast(axi_wlast), + .s_axi_dma_wready(axi_wready), + .s_axi_dma_wstrb(axi_wstrb), + .s_axi_dma_wvalid(axi_wvalid) +); + +// XGMII 10G PHY +assign sfp0_tx_disable_b = 1'b1; + +wire sfp0_tx_clk_int; +wire sfp0_tx_rst_int; +wire [63:0] sfp0_txd_int; +wire [7:0] sfp0_txc_int; +wire sfp0_rx_clk_int; +wire sfp0_rx_rst_int; +wire [63:0] sfp0_rxd_int; +wire [7:0] sfp0_rxc_int; + +assign clk_156mhz_int = sfp0_tx_clk_int; +assign rst_156mhz_int = sfp0_tx_rst_int; + +wire sfp0_rx_block_lock; + +wire sfp_mgt_refclk_0; + +// Gigabit Transceiver Buffer +// +// Differential input buffer designed to work with the GTE +// (Gigabit Transceiver) transceiver tiles +// +// see https://docs.xilinx.com/r/2022.1-English/ug974-vivado-ultrascale-libraries/IBUFDS_GTE4 +IBUFDS_GTE4 ibufds_gte4_sfp_mgt_refclk_0_inst ( + .I (sfp_mgt_refclk_0_p), + .IB (sfp_mgt_refclk_0_n), + .CEB (1'b0), + .O (sfp_mgt_refclk_0), + .ODIV2 () +); + +wire sfp_qpll0lock; +wire sfp_qpll0outclk; +wire sfp_qpll0outrefclk; + +eth_xcvr_phy_wrapper #( + .HAS_COMMON(1) +) +sfp0_phy_inst ( + .xcvr_ctrl_clk(clk_125mhz_int), + .xcvr_ctrl_rst(rst_125mhz_int), + + // Common + .xcvr_gtpowergood_out(), + + // PLL out + .xcvr_gtrefclk00_in(sfp_mgt_refclk_0), + .xcvr_qpll0lock_out(sfp_qpll0lock), + .xcvr_qpll0outclk_out(sfp_qpll0outclk), + .xcvr_qpll0outrefclk_out(sfp_qpll0outrefclk), + + // PLL in + .xcvr_qpll0lock_in(1'b0), + .xcvr_qpll0reset_out(), + .xcvr_qpll0clk_in(1'b0), + .xcvr_qpll0refclk_in(1'b0), + + // Serial data + .xcvr_txp(sfp0_tx_p), + .xcvr_txn(sfp0_tx_n), + .xcvr_rxp(sfp0_rx_p), + .xcvr_rxn(sfp0_rx_n), + + // PHY connections + .phy_tx_clk(sfp0_tx_clk_int), + .phy_tx_rst(sfp0_tx_rst_int), + .phy_xgmii_txd(sfp0_txd_int), + .phy_xgmii_txc(sfp0_txc_int), + .phy_rx_clk(sfp0_rx_clk_int), + .phy_rx_rst(sfp0_rx_rst_int), + .phy_xgmii_rxd(sfp0_rxd_int), + .phy_xgmii_rxc(sfp0_rxc_int), + .phy_tx_bad_block(), + .phy_rx_error_count(), + .phy_rx_bad_block(), + .phy_rx_sequence_error(), + .phy_rx_block_lock(sfp0_rx_block_lock), + .phy_rx_high_ber(), + .phy_tx_prbs31_enable(), + .phy_rx_prbs31_enable() +); + + +fpga_core +core_inst ( + /* + * Clock: 156.25 MHz + * Synchronous reset + */ + .clk(clk_156mhz_int), + .rst(rst_156mhz_int), + /* + * GPIO + */ + .led(led), + /* + * Ethernet: SFP+ + */ + .sfp0_tx_clk(sfp0_tx_clk_int), + .sfp0_tx_rst(sfp0_tx_rst_int), + .sfp0_txd(sfp0_txd_int), + .sfp0_txc(sfp0_txc_int), + .sfp0_rx_clk(sfp0_rx_clk_int), + .sfp0_rx_rst(sfp0_rx_rst_int), + .sfp0_rxd(sfp0_rxd_int), + .sfp0_rxc(sfp0_rxc_int) +); + +endmodule + +`resetall diff --git a/example/KR260/fpga_10g/rtl/fpga_core.v b/example/KR260/fpga_10g/rtl/fpga_core.v new file mode 100644 index 000000000..243f631f1 --- /dev/null +++ b/example/KR260/fpga_10g/rtl/fpga_core.v @@ -0,0 +1,586 @@ +/* + +Copyright (c) 2020-2021 Alex Forencich +Copyright (c) 2023 Víctor Mayoral Vilches + +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 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * FPGA core logic + */ +module fpga_core +( + /* + * Clock: 156.25MHz + * Synchronous reset + */ + input wire clk, + input wire rst, + + /* + * GPIO + */ + output wire [1:0] led, + + /* + * Ethernet: SFP+ + */ + input wire sfp0_tx_clk, + input wire sfp0_tx_rst, + output wire [63:0] sfp0_txd, + output wire [7:0] sfp0_txc, + input wire sfp0_rx_clk, + input wire sfp0_rx_rst, + input wire [63:0] sfp0_rxd, + input wire [7:0] sfp0_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 [1: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; + +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(sfp0_rx_clk), + .rx_rst(sfp0_rx_rst), + .tx_clk(sfp0_tx_clk), + .tx_rst(sfp0_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(sfp0_rxd), + .xgmii_rxc(sfp0_rxc), + .xgmii_txd(sfp0_txd), + .xgmii_txc(sfp0_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 + +`resetall diff --git a/example/KR260/fpga_10g/rtl/sync_signal.v b/example/KR260/fpga_10g/rtl/sync_signal.v new file mode 100644 index 000000000..74b855fa1 --- /dev/null +++ b/example/KR260/fpga_10g/rtl/sync_signal.v @@ -0,0 +1,62 @@ +/* + +Copyright (c) 2014-2018 Alex Forencich + +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 + +`resetall +`timescale 1 ns / 1 ps +`default_nettype none + +/* + * Synchronizes an asyncronous signal to a given clock by using a pipeline of + * two registers. + */ +module sync_signal #( + parameter WIDTH=1, // width of the input and output signals + parameter N=2 // depth of synchronizer +)( + input wire clk, + input wire [WIDTH-1:0] in, + output wire [WIDTH-1:0] out +); + +reg [WIDTH-1:0] sync_reg[N-1:0]; + +/* + * The synchronized output is the last register in the pipeline. + */ +assign out = sync_reg[N-1]; + +integer k; + +always @(posedge clk) begin + sync_reg[0] <= in; + for (k = 1; k < N; k = k + 1) begin + sync_reg[k] <= sync_reg[k-1]; + end +end + +endmodule + +`resetall diff --git a/example/KR260/fpga_10g/tb/fpga_core/Makefile b/example/KR260/fpga_10g/tb/fpga_core/Makefile new file mode 100644 index 000000000..ae7aa58db --- /dev/null +++ b/example/KR260/fpga_10g/tb/fpga_core/Makefile @@ -0,0 +1,97 @@ +# Copyright (c) 2020 Alex Forencich +# +# 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. + +TOPLEVEL_LANG = verilog + +SIM ?= icarus +WAVES ?= 0 + +COCOTB_HDL_TIMEUNIT = 1ns +COCOTB_HDL_TIMEPRECISION = 1ps + +DUT = fpga_core +TOPLEVEL = $(DUT) +MODULE = test_$(DUT) +VERILOG_SOURCES += ../../rtl/$(DUT).v +VERILOG_SOURCES += ../../lib/eth/rtl/eth_mac_10g_fifo.v +VERILOG_SOURCES += ../../lib/eth/rtl/eth_mac_10g.v +VERILOG_SOURCES += ../../lib/eth/rtl/axis_xgmii_rx_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/axis_xgmii_tx_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/lfsr.v +VERILOG_SOURCES += ../../lib/eth/rtl/eth_axis_rx.v +VERILOG_SOURCES += ../../lib/eth/rtl/eth_axis_tx.v +VERILOG_SOURCES += ../../lib/eth/rtl/udp_complete_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/udp_checksum_gen_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/udp_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/udp_ip_rx_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/udp_ip_tx_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/ip_complete_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/ip_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/ip_eth_rx_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/ip_eth_tx_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/ip_arb_mux.v +VERILOG_SOURCES += ../../lib/eth/rtl/arp.v +VERILOG_SOURCES += ../../lib/eth/rtl/arp_cache.v +VERILOG_SOURCES += ../../lib/eth/rtl/arp_eth_rx.v +VERILOG_SOURCES += ../../lib/eth/rtl/arp_eth_tx.v +VERILOG_SOURCES += ../../lib/eth/rtl/eth_arb_mux.v +VERILOG_SOURCES += ../../lib/eth/lib/axis/rtl/arbiter.v +VERILOG_SOURCES += ../../lib/eth/lib/axis/rtl/priority_encoder.v +VERILOG_SOURCES += ../../lib/eth/lib/axis/rtl/axis_fifo.v +VERILOG_SOURCES += ../../lib/eth/lib/axis/rtl/axis_async_fifo.v +VERILOG_SOURCES += ../../lib/eth/lib/axis/rtl/axis_async_fifo_adapter.v + +# module parameters +#export PARAM_A ?= value + +ifeq ($(SIM), icarus) + PLUSARGS += -fst + +# COMPILE_ARGS += -P $(TOPLEVEL).A=$(PARAM_A) + + ifeq ($(WAVES), 1) + VERILOG_SOURCES += iverilog_dump.v + COMPILE_ARGS += -s iverilog_dump + endif +else ifeq ($(SIM), verilator) + COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH + +# COMPILE_ARGS += -GA=$(PARAM_A) + + ifeq ($(WAVES), 1) + COMPILE_ARGS += --trace-fst + endif +endif + +include $(shell cocotb-config --makefiles)/Makefile.sim + +iverilog_dump.v: + echo 'module iverilog_dump();' > $@ + echo 'initial begin' >> $@ + echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@ + echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@ + echo 'end' >> $@ + echo 'endmodule' >> $@ + +clean:: + @rm -rf iverilog_dump.v + @rm -rf dump.fst $(TOPLEVEL).fst + @rm -rf __pycache__ + @rm results.xml diff --git a/example/KR260/fpga_10g/tb/fpga_core/test_fpga_core.py b/example/KR260/fpga_10g/tb/fpga_core/test_fpga_core.py new file mode 100644 index 000000000..bebffe0ed --- /dev/null +++ b/example/KR260/fpga_10g/tb/fpga_core/test_fpga_core.py @@ -0,0 +1,224 @@ +""" + +Copyright (c) 2020 Alex Forencich + +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. + +""" + +import logging +import os + +from scapy.layers.l2 import Ether, ARP +from scapy.layers.inet import IP, UDP + +import cocotb_test.simulator + +import cocotb +from cocotb.log import SimLog +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge + +from cocotbext.eth import XgmiiFrame, XgmiiSource, XgmiiSink + + +class TB: + def __init__(self, dut): + self.dut = dut + + self.log = SimLog("cocotb.tb") + self.log.setLevel(logging.DEBUG) + + cocotb.start_soon(Clock(dut.clk, 6.4, units="ns").start()) + + # Ethernet + cocotb.start_soon(Clock(dut.sfp0_rx_clk, 6.4, units="ns").start()) + self.sfp0_source = XgmiiSource(dut.sfp0_rxd, dut.sfp0_rxc, dut.sfp0_rx_clk, dut.sfp0_rx_rst) + cocotb.start_soon(Clock(dut.sfp0_tx_clk, 6.4, units="ns").start()) + self.sfp0_sink = XgmiiSink(dut.sfp0_txd, dut.sfp0_txc, dut.sfp0_tx_clk, dut.sfp0_tx_rst) + + # No push buttons, nor DIP switches + # + # dut.btnu.setimmediatevalue(0) + # dut.btnl.setimmediatevalue(0) + # dut.btnd.setimmediatevalue(0) + # dut.btnr.setimmediatevalue(0) + # dut.btnc.setimmediatevalue(0) + # dut.sw.setimmediatevalue(0) + + # No PL-side UART + # + # dut.uart_rxd.setimmediatevalue(0) + # dut.uart_rts.setimmediatevalue(0) + + async def init(self): + + self.dut.rst.setimmediatevalue(0) + self.dut.sfp0_rx_rst.setimmediatevalue(0) + self.dut.sfp0_tx_rst.setimmediatevalue(0) + + for k in range(10): + await RisingEdge(self.dut.clk) + + self.dut.rst.value = 1 + self.dut.sfp0_rx_rst.value = 1 + self.dut.sfp0_tx_rst.value = 1 + + for k in range(10): + await RisingEdge(self.dut.clk) + + self.dut.rst.value = 0 + self.dut.sfp0_rx_rst.value = 0 + self.dut.sfp0_tx_rst.value = 0 + + +@cocotb.test() +async def run_test(dut): + + tb = TB(dut) + + await tb.init() + + tb.log.info("test UDP RX packet") + + payload = bytes([x % 256 for x in range(256)]) + eth = Ether(src='5a:51:52:53:54:55', dst='02:00:00:00:00:00') + ip = IP(src='192.168.1.100', dst='192.168.1.128') + udp = UDP(sport=5678, dport=1234) + test_pkt = eth / ip / udp / payload + + test_frame = XgmiiFrame.from_payload(test_pkt.build()) + + await tb.sfp0_source.send(test_frame) + + tb.log.info("receive ARP request") + + rx_frame = await tb.sfp0_sink.recv() + + rx_pkt = Ether(bytes(rx_frame.get_payload())) + + tb.log.info("RX packet: %s", repr(rx_pkt)) + + assert rx_pkt.dst == 'ff:ff:ff:ff:ff:ff' + assert rx_pkt.src == test_pkt.dst + assert rx_pkt[ARP].hwtype == 1 + assert rx_pkt[ARP].ptype == 0x0800 + assert rx_pkt[ARP].hwlen == 6 + assert rx_pkt[ARP].plen == 4 + assert rx_pkt[ARP].op == 1 + assert rx_pkt[ARP].hwsrc == test_pkt.dst + assert rx_pkt[ARP].psrc == test_pkt[IP].dst + assert rx_pkt[ARP].hwdst == '00:00:00:00:00:00' + assert rx_pkt[ARP].pdst == test_pkt[IP].src + + tb.log.info("send ARP response") + + eth = Ether(src=test_pkt.src, dst=test_pkt.dst) + arp = ARP(hwtype=1, ptype=0x0800, hwlen=6, plen=4, op=2, + hwsrc=test_pkt.src, psrc=test_pkt[IP].src, + hwdst=test_pkt.dst, pdst=test_pkt[IP].dst) + resp_pkt = eth / arp + + resp_frame = XgmiiFrame.from_payload(resp_pkt.build()) + + await tb.sfp0_source.send(resp_frame) + + tb.log.info("receive UDP packet") + + rx_frame = await tb.sfp0_sink.recv() + + rx_pkt = Ether(bytes(rx_frame.get_payload())) + + tb.log.info("RX packet: %s", repr(rx_pkt)) + + assert rx_pkt.dst == test_pkt.src + assert rx_pkt.src == test_pkt.dst + assert rx_pkt[IP].dst == test_pkt[IP].src + assert rx_pkt[IP].src == test_pkt[IP].dst + assert rx_pkt[UDP].dport == test_pkt[UDP].sport + assert rx_pkt[UDP].sport == test_pkt[UDP].dport + assert rx_pkt[UDP].payload == test_pkt[UDP].payload + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + +# cocotb-test + +tests_dir = os.path.abspath(os.path.dirname(__file__)) +rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl')) +lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib')) +axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'lib', 'axis', 'rtl')) +eth_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'rtl')) + + +def test_fpga_core(request): + dut = "fpga_core" + module = os.path.splitext(os.path.basename(__file__))[0] + toplevel = dut + + verilog_sources = [ + os.path.join(rtl_dir, f"{dut}.v"), + os.path.join(eth_rtl_dir, "eth_mac_10g_fifo.v"), + os.path.join(eth_rtl_dir, "eth_mac_10g.v"), + os.path.join(eth_rtl_dir, "axis_xgmii_rx_64.v"), + os.path.join(eth_rtl_dir, "axis_xgmii_tx_64.v"), + os.path.join(eth_rtl_dir, "lfsr.v"), + os.path.join(eth_rtl_dir, "eth_axis_rx.v"), + os.path.join(eth_rtl_dir, "eth_axis_tx.v"), + os.path.join(eth_rtl_dir, "udp_complete_64.v"), + os.path.join(eth_rtl_dir, "udp_checksum_gen_64.v"), + os.path.join(eth_rtl_dir, "udp_64.v"), + os.path.join(eth_rtl_dir, "udp_ip_rx_64.v"), + os.path.join(eth_rtl_dir, "udp_ip_tx_64.v"), + os.path.join(eth_rtl_dir, "ip_complete_64.v"), + os.path.join(eth_rtl_dir, "ip_64.v"), + os.path.join(eth_rtl_dir, "ip_eth_rx_64.v"), + os.path.join(eth_rtl_dir, "ip_eth_tx_64.v"), + os.path.join(eth_rtl_dir, "ip_arb_mux.v"), + os.path.join(eth_rtl_dir, "arp.v"), + os.path.join(eth_rtl_dir, "arp_cache.v"), + os.path.join(eth_rtl_dir, "arp_eth_rx.v"), + os.path.join(eth_rtl_dir, "arp_eth_tx.v"), + os.path.join(eth_rtl_dir, "eth_arb_mux.v"), + os.path.join(axis_rtl_dir, "arbiter.v"), + os.path.join(axis_rtl_dir, "priority_encoder.v"), + os.path.join(axis_rtl_dir, "axis_fifo.v"), + os.path.join(axis_rtl_dir, "axis_async_fifo.v"), + os.path.join(axis_rtl_dir, "axis_async_fifo_adapter.v"), + ] + + parameters = {} + + # parameters['A'] = val + + extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()} + + sim_build = os.path.join(tests_dir, "sim_build", + request.node.name.replace('[', '-').replace(']', '')) + + cocotb_test.simulator.run( + python_search=[tests_dir], + verilog_sources=verilog_sources, + toplevel=toplevel, + module=module, + parameters=parameters, + sim_build=sim_build, + extra_env=extra_env, + ) diff --git a/example/KR260/fpga_10g_ddr/Makefile b/example/KR260/fpga_10g_ddr/Makefile new file mode 100644 index 000000000..f504bd06f --- /dev/null +++ b/example/KR260/fpga_10g_ddr/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/KR260/fpga_10g_ddr/README.md b/example/KR260/fpga_10g_ddr/README.md new file mode 100644 index 000000000..83a45c284 --- /dev/null +++ b/example/KR260/fpga_10g_ddr/README.md @@ -0,0 +1,29 @@ +# Verilog Ethernet KR260 Example Design + +## Introduction + +This example design targets the AMD KR260 FPGA SoC 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. + +* FPGA: `XCK26-SFVC784-2LV-C` (or `-I`, if industrial-grade) +* 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 + +Program the KR260 board with Vivado's Hardware Device Manager (via JTAG). Connect the KR260 SFP+ port to a 10G Ethernet NIC in your host. Then run in your host machine: + + 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/KR260/fpga_10g_ddr/common/vivado.mk b/example/KR260/fpga_10g_ddr/common/vivado.mk new file mode 100644 index 000000000..21e6a5fed --- /dev/null +++ b/example/KR260/fpga_10g_ddr/common/vivado.mk @@ -0,0 +1,131 @@ +################################################################### +# +# 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) + +FPGA_TOP ?= fpga +PROJECT ?= $(FPGA_TOP) + +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 *.ltx program.tcl generate_mcs.tcl *.mcs *.prm flash.tcl + -rm -rf *_utilization.rpt *_utilization_hierarchical.rpt + +distclean: clean + -rm -rf rev + +################################################################### +# Target implementations +################################################################### + +# Vivado project file +create_project.tcl: 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) $(PROJECT)" > $@ + echo "add_files -fileset sources_1 defines.v $(SYN_FILES_REL)" >> $@ + echo "set_property top $(FPGA_TOP) [current_fileset]" >> $@ + echo "add_files -fileset constrs_1 $(XDC_FILES_REL)" >> $@ + for x in $(XCI_FILES_REL); do echo "import_ip $$x" >> $@; done + for x in $(IP_TCL_FILES_REL); do echo "source $$x" >> $@; done + +$(PROJECT).xpr: create_project.tcl + vivado -nojournal -nolog -mode batch $(foreach x,$?,-source $x) + +# synthesis run +$(PROJECT).runs/synth_1/$(PROJECT).dcp: $(PROJECT).xpr $(SYN_FILES_REL) $(INC_FILES_REL) $(XDC_FILES_REL) + echo "open_project $(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 + vivado -nojournal -nolog -mode batch -source run_synth.tcl + +# implementation run +$(PROJECT).runs/impl_1/$(PROJECT)_routed.dcp: $(PROJECT).runs/synth_1/$(PROJECT).dcp + echo "open_project $(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 "open_run impl_1" >> run_impl.tcl + echo "report_utilization -file $(PROJECT)_utilization.rpt" >> run_impl.tcl + echo "report_utilization -hierarchical -file $(PROJECT)_utilization_hierarchical.rpt" >> run_impl.tcl + vivado -nojournal -nolog -mode batch -source run_impl.tcl + +# bit file +$(PROJECT).bit $(PROJECT).ltx: $(PROJECT).runs/impl_1/$(PROJECT)_routed.dcp + echo "open_project $(PROJECT).xpr" > generate_bit.tcl + echo "open_run impl_1" >> generate_bit.tcl + echo "write_bitstream -force $(PROJECT).runs/impl_1/$(PROJECT).bit" >> generate_bit.tcl + echo "write_debug_probes -force $(PROJECT).runs/impl_1/$(PROJECT).ltx" >> generate_bit.tcl + vivado -nojournal -nolog -mode batch -source generate_bit.tcl + ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).bit . + if [ -e $(PROJECT).runs/impl_1/$(PROJECT).ltx ]; then ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).ltx .; fi + mkdir -p rev + COUNT=100; \ + while [ -e rev/$(PROJECT)_rev$$COUNT.bit ]; \ + do COUNT=$$((COUNT+1)); done; \ + cp -pv $(PROJECT).runs/impl_1/$(PROJECT).bit rev/$(PROJECT)_rev$$COUNT.bit; \ + if [ -e $(PROJECT).runs/impl_1/$(PROJECT).ltx ]; then cp -pv $(PROJECT).runs/impl_1/$(PROJECT).ltx rev/$(PROJECT)_rev$$COUNT.ltx; fi diff --git a/example/KR260/fpga_10g_ddr/fpga.xdc b/example/KR260/fpga_10g_ddr/fpga.xdc new file mode 100644 index 000000000..f7ecaa24c --- /dev/null +++ b/example/KR260/fpga_10g_ddr/fpga.xdc @@ -0,0 +1,35 @@ +# XDC constraints for the AMD KR260 board +# part: XCK26-SFVC784-2LV-C/I + +# General configuration +set_property BITSTREAM.GENERAL.COMPRESS true [current_design] + +# System clocks +# +# use the 25 MHz clock outputs to the PL from U91 +# and feed that into a PLL to convert it to 125 MHz +set_property -dict {LOC C3 IOSTANDARD LVCMOS18} [get_ports clk_25mhz_ref] ;# HPA_CLK0P_CLK, HPA_CLK0_P, via U91, SOM240_1 A6 +create_clock -period 40.000 -name clk_25mhz [get_ports clk_25mhz_ref] + +# LEDs +set_property -dict {LOC F8 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {led[0]}] ;# HPA14P, HPA14_P, som240_1_d13, VCCO - som240_1_d1 +set_property -dict {LOC E8 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {led[1]}] ;# HPA14N, HPA14_N, som240_1_d14, VCCO - som240_1_d1 + +set_false_path -to [get_ports {led[*]}] +set_output_delay 0 [get_ports {led[*]}] + +# SFP+ Interface +set_property -dict {LOC T2 } [get_ports sfp0_rx_p] ;# GTH_DP2_C2M_P, som240_2_b1 +set_property -dict {LOC T1 } [get_ports sfp0_rx_n] ;# GTH_DP2_C2M_N, som240_2_b2 +set_property -dict {LOC R4 } [get_ports sfp0_tx_p] ;# GTH_DP2_M2C_P, som240_2_b5 +set_property -dict {LOC R3 } [get_ports sfp0_tx_n] ;# GTH_DP2_M2C_N, som240_2_b6 + +set_property -dict {LOC Y6 } [get_ports sfp_mgt_refclk_0_p] ;# GTH_REFCLK0_C2M_P via U90, SOM240_2 C3 +set_property -dict {LOC Y5 } [get_ports sfp_mgt_refclk_0_n] ;# GTH_REFCLK0_C2M_N via U90, SOM240_2 C4 +set_property -dict {LOC Y10 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8 } [get_ports sfp0_tx_disable_b] ;# HDB19, SOM240_2_A47 + +# 156.25 MHz MGT reference clock +create_clock -period 6.400 -name sfp_mgt_refclk_0 [get_ports sfp_mgt_refclk_0_p] + +set_false_path -to [get_ports {sfp0_tx_disable_b}] +set_output_delay 0 [get_ports {sfp0_tx_disable_b}] diff --git a/example/KR260/fpga_10g_ddr/fpga/.gitignore b/example/KR260/fpga_10g_ddr/fpga/.gitignore new file mode 100644 index 000000000..68d603392 --- /dev/null +++ b/example/KR260/fpga_10g_ddr/fpga/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!.Makefile \ No newline at end of file diff --git a/example/KR260/fpga_10g_ddr/ip/eth_xcvr_gt.tcl b/example/KR260/fpga_10g_ddr/ip/eth_xcvr_gt.tcl new file mode 100644 index 000000000..990b94c4a --- /dev/null +++ b/example/KR260/fpga_10g_ddr/ip/eth_xcvr_gt.tcl @@ -0,0 +1,76 @@ +# Copyright (c) 2021 Alex Forencich +# +# 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. + +set base_name {eth_xcvr_gt} + +set preset {GTH-10GBASE-R} + +set freerun_freq {125} +set line_rate {10.3125} +set refclk_freq {156.25} +set qpll_fracn [expr {int(fmod($line_rate*1000/2 / $refclk_freq, 1)*pow(2, 24))}] +set user_data_width {64} +set int_data_width {32} +set extra_ports [list] +set extra_pll_ports [list {qpll0lock_out}] + +set config [dict create] + +dict set config TX_LINE_RATE $line_rate +dict set config TX_REFCLK_FREQUENCY $refclk_freq +dict set config TX_QPLL_FRACN_NUMERATOR $qpll_fracn +dict set config TX_USER_DATA_WIDTH $user_data_width +dict set config TX_INT_DATA_WIDTH $int_data_width +dict set config RX_LINE_RATE $line_rate +dict set config RX_REFCLK_FREQUENCY $refclk_freq +dict set config RX_QPLL_FRACN_NUMERATOR $qpll_fracn +dict set config RX_USER_DATA_WIDTH $user_data_width +dict set config RX_INT_DATA_WIDTH $int_data_width +dict set config ENABLE_OPTIONAL_PORTS $extra_ports +dict set config LOCATE_COMMON {CORE} +dict set config LOCATE_RESET_CONTROLLER {CORE} +dict set config LOCATE_TX_USER_CLOCKING {CORE} +dict set config LOCATE_RX_USER_CLOCKING {CORE} +dict set config LOCATE_USER_DATA_WIDTH_SIZING {CORE} +dict set config FREERUN_FREQUENCY $freerun_freq +dict set config DISABLE_LOC_XDC {1} + +proc create_gtwizard_ip {name preset config} { + create_ip -name gtwizard_ultrascale -vendor xilinx.com -library ip -module_name $name + set ip [get_ips $name] + set_property CONFIG.preset $preset $ip + set config_list {} + dict for {name value} $config { + lappend config_list "CONFIG.${name}" $value + } + set_property -dict $config_list $ip +} + +# variant with channel and common +dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] +dict set config LOCATE_COMMON {CORE} + +create_gtwizard_ip "${base_name}_full" $preset $config + +# variant with channel only +dict set config ENABLE_OPTIONAL_PORTS $extra_ports +dict set config LOCATE_COMMON {EXAMPLE_DESIGN} + +create_gtwizard_ip "${base_name}_channel" $preset $config diff --git a/example/KR260/fpga_10g_ddr/ip/zynq_ps.tcl b/example/KR260/fpga_10g_ddr/ip/zynq_ps.tcl new file mode 100644 index 000000000..38baf1dae --- /dev/null +++ b/example/KR260/fpga_10g_ddr/ip/zynq_ps.tcl @@ -0,0 +1,209 @@ +# Copyright 2022, The Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS +# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and documentation are those +# of the authors and should not be interpreted as representing official policies, +# either expressed or implied, of The Regents of the University of California. + +# create block design +create_bd_design "zynq_ps" + +# Create blocks + +# Zynq PS +set zynq_ultra_ps [ create_bd_cell -type ip -vlnv xilinx.com:ip:zynq_ultra_ps_e zynq_ultra_ps ] +set_property -dict [list \ + CONFIG.PSU_BANK_0_IO_STANDARD {LVCMOS18} \ + CONFIG.PSU_BANK_1_IO_STANDARD {LVCMOS18} \ + CONFIG.PSU_BANK_2_IO_STANDARD {LVCMOS18} \ + CONFIG.PSU_BANK_3_IO_STANDARD {LVCMOS33} \ + CONFIG.PSU_DYNAMIC_DDR_CONFIG_EN 1 \ + CONFIG.PSU__DDRC__COMPONENTS {UDIMM} \ + CONFIG.PSU__DDRC__DEVICE_CAPACITY {4096 MBits} \ + CONFIG.PSU__DDRC__SPEED_BIN {DDR4_2133P} \ + CONFIG.PSU__DDRC__ROW_ADDR_COUNT {15} \ + CONFIG.PSU__DDRC__T_RC {46.5} \ + CONFIG.PSU__DDRC__T_FAW {21.0} \ + CONFIG.PSU__DDRC__DDR4_ADDR_MAPPING {0} \ + CONFIG.PSU__DDRC__FREQ_MHZ {1067} \ + CONFIG.PSU__PMU__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__PMU__GPI0__ENABLE {1} \ + CONFIG.PSU__PMU__GPI1__ENABLE {0} \ + CONFIG.PSU__PMU__GPI2__ENABLE {0} \ + CONFIG.PSU__PMU__GPI3__ENABLE {0} \ + CONFIG.PSU__PMU__GPI4__ENABLE {0} \ + CONFIG.PSU__PMU__GPI5__ENABLE {0} \ + CONFIG.PSU__QSPI__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__QSPI__PERIPHERAL__MODE {Dual Parallel} \ + CONFIG.PSU__QSPI__GRP_FBCLK__ENABLE {1} \ + CONFIG.PSU__CAN1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__CAN1__PERIPHERAL__IO {MIO 24 .. 25} \ + CONFIG.PSU__GPIO0_MIO__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__GPIO1_MIO__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__I2C0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__I2C0__PERIPHERAL__IO {MIO 14 .. 15} \ + CONFIG.PSU__I2C1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__I2C1__PERIPHERAL__IO {MIO 16 .. 17} \ + CONFIG.PSU__UART0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__UART0__PERIPHERAL__IO {MIO 18 .. 19} \ + CONFIG.PSU__UART1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__UART1__PERIPHERAL__IO {MIO 20 .. 21} \ + CONFIG.PSU__SD1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__SD1__GRP_CD__ENABLE {1} \ + CONFIG.PSU__SD1__GRP_WP__ENABLE {1} \ + CONFIG.PSU__ENET3__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__ENET3__GRP_MDIO__ENABLE {1} \ + CONFIG.PSU__USB0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__USB0__REF_CLK_SEL {Ref Clk2} \ + CONFIG.PSU__USB3_0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__USB3_0__PERIPHERAL__IO {GT Lane2} \ + CONFIG.PSU__DISPLAYPORT__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__DPAUX__PERIPHERAL__IO {MIO 27 .. 30} \ + CONFIG.PSU__DP__REF_CLK_SEL {Ref Clk3} \ + CONFIG.PSU__DP__LANE_SEL {Single Lower} \ + CONFIG.PSU__SATA__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__SATA__LANE1__IO {GT Lane3} \ + CONFIG.PSU__PCIE__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__PCIE__PERIPHERAL__ROOTPORT_IO {MIO 31} \ + CONFIG.PSU__PCIE__DEVICE_PORT_TYPE {Root Port} \ + CONFIG.PSU__PCIE__BAR0_ENABLE {0} \ + CONFIG.PSU__PCIE__CLASS_CODE_BASE {0x06} \ + CONFIG.PSU__PCIE__CLASS_CODE_SUB {0x04} \ + CONFIG.PSU__SWDT0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__SWDT1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__TTC0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__TTC1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__TTC2__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__TTC3__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__USE__M_AXI_GP0 {1} \ + CONFIG.PSU__MAXIGP0__DATA_WIDTH {32} \ + CONFIG.PSU__USE__M_AXI_GP1 {0} \ + CONFIG.PSU__USE__M_AXI_GP2 {0} \ + CONFIG.PSU__USE__S_AXI_GP0 {0} \ + CONFIG.PSU__USE__S_AXI_GP2 {1} \ + CONFIG.PSU__USE__IRQ0 {0} \ + CONFIG.PSU__CRF_APB__ACPU_CTRL__SRCSEL {APLL} \ + CONFIG.PSU__CRF_APB__DDR_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRF_APB__DP_VIDEO_REF_CTRL__SRCSEL {VPLL} \ + CONFIG.PSU__CRF_APB__DP_AUDIO_REF_CTRL__SRCSEL {RPLL} \ + CONFIG.PSU__CRF_APB__DP_STC_REF_CTRL__SRCSEL {RPLL} \ + CONFIG.PSU__CRF_APB__DPDMA_REF_CTRL__FREQMHZ {667} \ + CONFIG.PSU__CRF_APB__DPDMA_REF_CTRL__SRCSEL {APLL} \ + CONFIG.PSU__CRF_APB__GDMA_REF_CTRL__FREQMHZ {667} \ + CONFIG.PSU__CRF_APB__GDMA_REF_CTRL__SRCSEL {APLL} \ + CONFIG.PSU__CRF_APB__GPU_REF_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRF_APB__TOPSW_MAIN_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRF_APB__TOPSW_LSBUS_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__ADMA_REF_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRL_APB__CPU_R5_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRL_APB__IOU_SWITCH_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRL_APB__LPD_LSBUS_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__LPD_SWITCH_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRL_APB__PCAP_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__PL0_REF_CTRL__FREQMHZ {300} \ + CONFIG.PSU__CRL_APB__PL0_REF_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__SDIO1_REF_CTRL__SRCSEL {IOPLL} \ +] $zynq_ultra_ps + +# reset +set proc_sys_reset [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset proc_sys_reset ] + +# Create connections + +# Clock +set pl_clk0 [get_bd_pins $zynq_ultra_ps/pl_clk0] +make_bd_pins_external $pl_clk0 +set_property name pl_clk0 [get_bd_ports -of_objects [get_bd_nets -of_objects $pl_clk0]] +set pl_clk0_port [get_bd_ports -of_objects [get_bd_nets -of_objects $pl_clk0]] + +connect_bd_net $pl_clk0 [get_bd_pins $proc_sys_reset/slowest_sync_clk] + +set pl_clk0_busif [list] + +# Reset +set pl_resetn0 [get_bd_pins $zynq_ultra_ps/pl_resetn0] +connect_bd_net $pl_resetn0 [get_bd_pins $proc_sys_reset/ext_reset_in] + +set pl_reset [get_bd_pins $proc_sys_reset/peripheral_reset] +make_bd_pins_external $pl_reset +set_property name pl_reset [get_bd_ports -of_objects [get_bd_nets -of_objects $pl_reset]] + +# robotcore-udpip interface: clk and rst for S_AXI and M_AXI +create_bd_port -dir I -type clk -freq_hz 156250000 clk_156mhz_i +create_bd_port -dir I -type rst rstn_156mhz_i + +# robotcore-udpip interface S_AXI -> HP0 + +connect_bd_net [get_bd_ports clk_156mhz_i] [get_bd_pins zynq_ultra_ps/saxihp0_fpd_aclk] +# Smart connect +create_bd_cell -type ip -vlnv xilinx.com:ip:smartconnect:1.0 smartconnect_0 +set_property -dict [list CONFIG.NUM_SI {1}] [get_bd_cells smartconnect_0] +connect_bd_intf_net [get_bd_intf_pins $zynq_ultra_ps/S_AXI_HP0_FPD] [get_bd_intf_pins smartconnect_0/M00_AXI] +connect_bd_net [get_bd_ports clk_156mhz_i] [get_bd_pins smartconnect_0/aclk] +connect_bd_net [get_bd_ports rstn_156mhz_i] [get_bd_pins smartconnect_0/aresetn] +make_bd_intf_pins_external [get_bd_intf_pins smartconnect_0/S00_AXI] +set_property name s_axi_hp0 [get_bd_intf_ports S00_AXI_0] +set_property CONFIG.DATA_WIDTH 64 [get_bd_intf_ports /s_axi_hp0] +set_property -dict [list CONFIG.FREQ_HZ {156250000}] [get_bd_intf_ports s_axi_hp0] +# Assign addresses +assign_bd_address -target_address_space /zynq_ultra_ps/Data [get_bd_addr_segs axi_gpio_0/S_AXI/Reg] -force +assign_bd_address -target_address_space /s_axi_hp0 [get_bd_addr_segs $zynq_ultra_ps/SAXIGP0/HP0_DDR_HIGH] -force +assign_bd_address -target_address_space /s_axi_hp0 [get_bd_addr_segs $zynq_ultra_ps/SAXIGP0/HP0_QSPI] -force +assign_bd_address -target_address_space /s_axi_hp0 [get_bd_addr_segs $zynq_ultra_ps/SAXIGP0/HP0_DDR_LOW] -force +assign_bd_address -target_address_space /s_axi_hp0 [get_bd_addr_segs $zynq_ultra_ps/SAXIGP0/HP0_LPS_OCM] -force + +# robotcore-udpip interface M_AXI -> HPM0 + +connect_bd_net [get_bd_ports clk_156mhz_i] [get_bd_pins zynq_ultra_ps/maxihpm0_fpd_aclk] +# Smart connect +create_bd_cell -type ip -vlnv xilinx.com:ip:smartconnect:1.0 smartconnect_1 +set_property -dict [list CONFIG.NUM_SI {1}] [get_bd_cells smartconnect_1] +connect_bd_intf_net [get_bd_intf_pins $zynq_ultra_ps/M_AXI_HPM0_FPD] [get_bd_intf_pins smartconnect_1/S00_AXI] +connect_bd_net [get_bd_ports clk_156mhz_i] [get_bd_pins smartconnect_1/aclk] +connect_bd_net [get_bd_ports rstn_156mhz_i] [get_bd_pins smartconnect_1/aresetn] +# TEMP (GPIO) +create_bd_cell -type ip -vlnv xilinx.com:ip:axi_gpio:2.0 axi_gpio_0 +set_property -dict [list CONFIG.C_ALL_OUTPUTS {1}] [get_bd_cells axi_gpio_0] +connect_bd_net [get_bd_ports clk_156mhz_i] [get_bd_pins axi_gpio_0/s_axi_aclk] +connect_bd_net [get_bd_ports rstn_156mhz_i] [get_bd_pins axi_gpio_0/s_axi_aresetn] +connect_bd_intf_net [get_bd_intf_pins smartconnect_1/M00_AXI] [get_bd_intf_pins axi_gpio_0/S_AXI] +make_bd_intf_pins_external [get_bd_intf_pins axi_gpio_0/GPIO] +set_property name GPIO_SHMEM [get_bd_intf_ports GPIO_0] +# Assign addresses +assign_bd_address -target_address_space /zynq_ultra_ps/Data [get_bd_addr_segs axi_gpio_0/S_AXI/Reg] -force +set_property offset 0x00A0000000 [get_bd_addr_segs {zynq_ultra_ps/Data/SEG_axi_gpio_0_Reg}] + +# Port clock associations +set lst [list] +foreach port $pl_clk0_busif { + lappend lst [get_property name $port] +} +set_property CONFIG.ASSOCIATED_BUSIF [join $lst ":"] $pl_clk0_port + +validate_bd_design + +# Save block design +save_bd_design [current_bd_design] +close_bd_design [current_bd_design] diff --git a/example/KR260/fpga_10g_ddr/lib/eth b/example/KR260/fpga_10g_ddr/lib/eth new file mode 120000 index 000000000..11a54ed36 --- /dev/null +++ b/example/KR260/fpga_10g_ddr/lib/eth @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/example/KR260/fpga_10g_ddr/rtl/debounce_switch.v b/example/KR260/fpga_10g_ddr/rtl/debounce_switch.v new file mode 100644 index 000000000..8e93a50c4 --- /dev/null +++ b/example/KR260/fpga_10g_ddr/rtl/debounce_switch.v @@ -0,0 +1,93 @@ +/* + +Copyright (c) 2014-2018 Alex Forencich + +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 + +`resetall +`timescale 1 ns / 1 ps +`default_nettype none + +/* + * Synchronizes switch and button inputs with a slow sampled shift register + */ +module debounce_switch #( + parameter WIDTH=1, // width of the input and output signals + parameter N=3, // length of shift register + parameter RATE=125000 // clock division factor +)( + input wire clk, + input wire rst, + input wire [WIDTH-1:0] in, + output wire [WIDTH-1:0] out +); + +reg [23:0] cnt_reg = 24'd0; + +reg [N-1:0] debounce_reg[WIDTH-1:0]; + +reg [WIDTH-1:0] state; + +/* + * The synchronized output is the state register + */ +assign out = state; + +integer k; + +always @(posedge clk or posedge rst) begin + if (rst) begin + cnt_reg <= 0; + state <= 0; + + for (k = 0; k < WIDTH; k = k + 1) begin + debounce_reg[k] <= 0; + end + end else begin + if (cnt_reg < RATE) begin + cnt_reg <= cnt_reg + 24'd1; + end else begin + cnt_reg <= 24'd0; + end + + if (cnt_reg == 24'd0) begin + for (k = 0; k < WIDTH; k = k + 1) begin + debounce_reg[k] <= {debounce_reg[k][N-2:0], in[k]}; + end + end + + for (k = 0; k < WIDTH; k = k + 1) begin + if (|debounce_reg[k] == 0) begin + state[k] <= 0; + end else if (&debounce_reg[k] == 1) begin + state[k] <= 1; + end else begin + state[k] <= state[k]; + end + end + end +end + +endmodule + +`resetall diff --git a/example/KR260/fpga_10g_ddr/rtl/eth_xcvr_phy_wrapper.v b/example/KR260/fpga_10g_ddr/rtl/eth_xcvr_phy_wrapper.v new file mode 100644 index 000000000..bbbfd08d6 --- /dev/null +++ b/example/KR260/fpga_10g_ddr/rtl/eth_xcvr_phy_wrapper.v @@ -0,0 +1,299 @@ +/* + +Copyright (c) 2021 Alex Forencich + +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 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Transceiver and PHY wrapper + */ +module eth_xcvr_phy_wrapper # +( + parameter HAS_COMMON = 1, + parameter DATA_WIDTH = 64, + parameter CTRL_WIDTH = (DATA_WIDTH/8), + parameter HDR_WIDTH = 2, + parameter PRBS31_ENABLE = 0, + parameter TX_SERDES_PIPELINE = 0, + parameter RX_SERDES_PIPELINE = 0, + parameter BITSLIP_HIGH_CYCLES = 1, + parameter BITSLIP_LOW_CYCLES = 8, + parameter COUNT_125US = 125000/6.4 +) +( + input wire xcvr_ctrl_clk, + input wire xcvr_ctrl_rst, + + /* + * Common + */ + output wire xcvr_gtpowergood_out, + + /* + * PLL out + */ + input wire xcvr_gtrefclk00_in, + output wire xcvr_qpll0lock_out, + output wire xcvr_qpll0outclk_out, + output wire xcvr_qpll0outrefclk_out, + + /* + * PLL in + */ + input wire xcvr_qpll0lock_in, + output wire xcvr_qpll0reset_out, + input wire xcvr_qpll0clk_in, + input wire xcvr_qpll0refclk_in, + + /* + * Serial data + */ + output wire xcvr_txp, + output wire xcvr_txn, + input wire xcvr_rxp, + input wire xcvr_rxn, + + /* + * PHY connections + */ + output wire phy_tx_clk, + output wire phy_tx_rst, + input wire [DATA_WIDTH-1:0] phy_xgmii_txd, + input wire [CTRL_WIDTH-1:0] phy_xgmii_txc, + output wire phy_rx_clk, + output wire phy_rx_rst, + output wire [DATA_WIDTH-1:0] phy_xgmii_rxd, + output wire [CTRL_WIDTH-1:0] phy_xgmii_rxc, + output wire phy_tx_bad_block, + output wire [6:0] phy_rx_error_count, + output wire phy_rx_bad_block, + output wire phy_rx_sequence_error, + output wire phy_rx_block_lock, + output wire phy_rx_high_ber, + input wire phy_tx_prbs31_enable, + input wire phy_rx_prbs31_enable +); + +wire phy_rx_reset_req; + +wire gt_reset_tx_datapath = 1'b0; +wire gt_reset_rx_datapath = phy_rx_reset_req; + +wire gt_reset_tx_done; +wire gt_reset_rx_done; + +wire [5:0] gt_txheader; +wire [63:0] gt_txdata; +wire gt_rxgearboxslip; +wire [5:0] gt_rxheader; +wire [1:0] gt_rxheadervalid; +wire [63:0] gt_rxdata; +wire [1:0] gt_rxdatavalid; + +generate + +if (HAS_COMMON) begin : xcvr + + eth_xcvr_gt_full + eth_xcvr_gt_full_inst ( + // Common + .gtwiz_reset_clk_freerun_in(xcvr_ctrl_clk), + .gtwiz_reset_all_in(xcvr_ctrl_rst), + .gtpowergood_out(xcvr_gtpowergood_out), + + // PLL + .gtrefclk00_in(xcvr_gtrefclk00_in), + .qpll0lock_out(xcvr_qpll0lock_out), + .qpll0outclk_out(xcvr_qpll0outclk_out), + .qpll0outrefclk_out(xcvr_qpll0outrefclk_out), + + // Serial data + .gthtxp_out(xcvr_txp), + .gthtxn_out(xcvr_txn), + .gthrxp_in(xcvr_rxp), + .gthrxn_in(xcvr_rxn), + + // Transmit + .gtwiz_userclk_tx_reset_in(1'b0), + .gtwiz_userclk_tx_srcclk_out(), + .gtwiz_userclk_tx_usrclk_out(), + .gtwiz_userclk_tx_usrclk2_out(phy_tx_clk), + .gtwiz_userclk_tx_active_out(), + .gtwiz_reset_tx_pll_and_datapath_in(1'b0), + .gtwiz_reset_tx_datapath_in(gt_reset_tx_datapath), + .gtwiz_reset_tx_done_out(gt_reset_tx_done), + .txpmaresetdone_out(), + .txprgdivresetdone_out(), + + .gtwiz_userdata_tx_in(gt_txdata), + .txheader_in(gt_txheader), + .txsequence_in(7'b0), + + // Receive + .gtwiz_userclk_rx_reset_in(1'b0), + .gtwiz_userclk_rx_srcclk_out(), + .gtwiz_userclk_rx_usrclk_out(), + .gtwiz_userclk_rx_usrclk2_out(phy_rx_clk), + .gtwiz_userclk_rx_active_out(), + .gtwiz_reset_rx_pll_and_datapath_in(1'b0), + .gtwiz_reset_rx_datapath_in(gt_reset_rx_datapath), + .gtwiz_reset_rx_cdr_stable_out(), + .gtwiz_reset_rx_done_out(gt_reset_rx_done), + .rxpmaresetdone_out(), + .rxprgdivresetdone_out(), + + .rxgearboxslip_in(gt_rxgearboxslip), + .gtwiz_userdata_rx_out(gt_rxdata), + .rxdatavalid_out(gt_rxdatavalid), + .rxheader_out(gt_rxheader), + .rxheadervalid_out(gt_rxheadervalid), + .rxstartofseq_out() + ); + +end else begin : xcvr + + eth_xcvr_gt_channel + eth_xcvr_gt_channel_inst ( + // Common + .gtwiz_reset_clk_freerun_in(xcvr_ctrl_clk), + .gtwiz_reset_all_in(xcvr_ctrl_rst), + .gtpowergood_out(xcvr_gtpowergood_out), + + // PLL + .gtwiz_reset_qpll0lock_in(xcvr_qpll0lock_in), + .gtwiz_reset_qpll0reset_out(xcvr_qpll0reset_out), + .qpll0clk_in(xcvr_qpll0clk_in), + .qpll0refclk_in(xcvr_qpll0refclk_in), + .qpll1clk_in(1'b0), + .qpll1refclk_in(1'b0), + + // Serial data + .gthtxp_out(xcvr_txp), + .gthtxn_out(xcvr_txn), + .gthrxp_in(xcvr_rxp), + .gthrxn_in(xcvr_rxn), + + // Transmit + .gtwiz_userclk_tx_reset_in(1'b0), + .gtwiz_userclk_tx_srcclk_out(), + .gtwiz_userclk_tx_usrclk_out(), + .gtwiz_userclk_tx_usrclk2_out(phy_tx_clk), + .gtwiz_userclk_tx_active_out(), + .gtwiz_reset_tx_pll_and_datapath_in(1'b0), + .gtwiz_reset_tx_datapath_in(gt_reset_tx_datapath), + .gtwiz_reset_tx_done_out(gt_reset_tx_done), + .txpmaresetdone_out(), + .txprgdivresetdone_out(), + + .gtwiz_userdata_tx_in(gt_txdata), + .txheader_in(gt_txheader), + .txsequence_in(7'b0), + + // Receive + .gtwiz_userclk_rx_reset_in(1'b0), + .gtwiz_userclk_rx_srcclk_out(), + .gtwiz_userclk_rx_usrclk_out(), + .gtwiz_userclk_rx_usrclk2_out(phy_rx_clk), + .gtwiz_userclk_rx_active_out(), + .gtwiz_reset_rx_pll_and_datapath_in(1'b0), + .gtwiz_reset_rx_datapath_in(gt_reset_rx_datapath), + .gtwiz_reset_rx_cdr_stable_out(), + .gtwiz_reset_rx_done_out(gt_reset_rx_done), + .rxpmaresetdone_out(), + .rxprgdivresetdone_out(), + + .rxgearboxslip_in(gt_rxgearboxslip), + .gtwiz_userdata_rx_out(gt_rxdata), + .rxdatavalid_out(gt_rxdatavalid), + .rxheader_out(gt_rxheader), + .rxheadervalid_out(gt_rxheadervalid), + .rxstartofseq_out() + ); + +end + +endgenerate + +sync_reset #( + .N(4) +) +tx_reset_sync_inst ( + .clk(phy_tx_clk), + .rst(!gt_reset_tx_done), + .out(phy_tx_rst) +); + +sync_reset #( + .N(4) +) +rx_reset_sync_inst ( + .clk(phy_rx_clk), + .rst(!gt_reset_rx_done), + .out(phy_rx_rst) +); + +eth_phy_10g #( + .DATA_WIDTH(DATA_WIDTH), + .CTRL_WIDTH(CTRL_WIDTH), + .HDR_WIDTH(HDR_WIDTH), + .BIT_REVERSE(1), + .SCRAMBLER_DISABLE(0), + .PRBS31_ENABLE(PRBS31_ENABLE), + .TX_SERDES_PIPELINE(TX_SERDES_PIPELINE), + .RX_SERDES_PIPELINE(RX_SERDES_PIPELINE), + .BITSLIP_HIGH_CYCLES(BITSLIP_HIGH_CYCLES), + .BITSLIP_LOW_CYCLES(BITSLIP_LOW_CYCLES), + .COUNT_125US(COUNT_125US) +) +phy_inst ( + .tx_clk(phy_tx_clk), + .tx_rst(phy_tx_rst), + .rx_clk(phy_rx_clk), + .rx_rst(phy_rx_rst), + .xgmii_txd(phy_xgmii_txd), + .xgmii_txc(phy_xgmii_txc), + .xgmii_rxd(phy_xgmii_rxd), + .xgmii_rxc(phy_xgmii_rxc), + .serdes_tx_data(gt_txdata), + .serdes_tx_hdr(gt_txheader), + .serdes_rx_data(gt_rxdata), + .serdes_rx_hdr(gt_rxheader), + .serdes_rx_bitslip(gt_rxgearboxslip), + .serdes_rx_reset_req(phy_rx_reset_req), + .tx_bad_block(phy_tx_bad_block), + .rx_error_count(phy_rx_error_count), + .rx_bad_block(phy_rx_bad_block), + .rx_sequence_error(phy_rx_sequence_error), + .rx_block_lock(phy_rx_block_lock), + .rx_high_ber(phy_rx_high_ber), + .tx_prbs31_enable(phy_tx_prbs31_enable), + .rx_prbs31_enable(phy_rx_prbs31_enable) +); + +endmodule + +`resetall diff --git a/example/KR260/fpga_10g_ddr/rtl/fpga.v b/example/KR260/fpga_10g_ddr/rtl/fpga.v new file mode 100644 index 000000000..d7c89b5c9 --- /dev/null +++ b/example/KR260/fpga_10g_ddr/rtl/fpga.v @@ -0,0 +1,430 @@ +/* + +Copyright (c) 2020-2021 Alex Forencich +Copyright (c) 2023 Víctor Mayoral Vilches + +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 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * FPGA top-level module + */ +module fpga # +( + // AXI interface configuration (DMA) + parameter AXI_DATA_WIDTH = 128, + parameter AXI_ADDR_WIDTH = 32, + parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8), + parameter AXI_ID_WIDTH = 8, + + // AXI lite interface configuration (control) + parameter AXIL_CTRL_DATA_WIDTH = 32, + parameter AXIL_CTRL_ADDR_WIDTH = 24, + parameter AXIL_CTRL_STRB_WIDTH = (AXIL_CTRL_DATA_WIDTH/8), + + // AXI lite interface configuration (application control) + parameter AXIL_APP_CTRL_DATA_WIDTH = AXIL_CTRL_DATA_WIDTH, + parameter AXIL_APP_CTRL_ADDR_WIDTH = 24, + parameter AXIL_APP_CTRL_STRB_WIDTH = (AXIL_APP_CTRL_DATA_WIDTH/8) +) +( + /* + * Clock: 25 MHz LVCMOS18 + */ + input wire clk_25mhz_ref, + + /* + * GPIO + */ + output wire [1:0] led, + + /* + * Ethernet: SFP+ + */ + input wire sfp0_rx_p, + input wire sfp0_rx_n, + output wire sfp0_tx_p, + output wire sfp0_tx_n, + input wire sfp_mgt_refclk_0_p, + input wire sfp_mgt_refclk_0_n, + output wire sfp0_tx_disable_b +); + +// Clock and reset +wire clk_25mhz_bufg; + +// 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 = reset; +wire mmcm_locked; +wire mmcm_clkfb; + + +// BUFG stands for "buffer gate." The BUFG primitive is used to create a +// buffer gate, which is a digital circuit component that is used to +// amplify and/or isolate a signal. +// +// Using a BUFG gate helps to ensure that the clock signal is distributed +// properly throughout the system and reaches all the necessary components +// with minimal delay. +// +// https://docs.xilinx.com/r/2022.1-English/ug974-vivado-ultrascale-libraries/BUFG +BUFG +clk_25mhz_bufg_in_inst ( + .I(clk_25mhz_ref), + .O(clk_25mhz_bufg) +); + + +// Base Mixed Mode Clock Manager (MMCM) +// +// used to implement a Phase-Locked Loop (PLL) with Multiplier/Multiplier +// and Phase Shift (MMCM) functionality +// see https://docs.xilinx.com/r/2022.1-English/ug974-vivado-ultrascale-libraries/MMCME4_BASE + +// MMCM instance +// 25 MHz in, 125 MHz out +// PFD range: 10 MHz to 500 MHz +// VCO range: 800 MHz to 1600 MHz +// M = 8, D = 1 sets Fvco = 1000 MHz (in range) +// Divide by 8 to get output frequency of 125 MHz +MMCME4_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(40), + .CLKFBOUT_PHASE(0), + .DIVCLK_DIVIDE(1), + .REF_JITTER1(0.010), + .CLKIN1_PERIOD(40.0), + .STARTUP_WAIT("FALSE"), + .CLKOUT4_CASCADE("FALSE") +) +clk_mmcm_inst ( + .CLKIN1(clk_25mhz_bufg), + .CLKFBIN(mmcm_clkfb), + // .RST(mmcm_rst), + .RST(1'b0), + .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) +); + +// M_AXI for UDP packets (PL<->PS) +wire [00:00] fpga_core_axi_arid ; +wire [31:00] fpga_core_axi_araddr ; +wire [07:00] fpga_core_axi_arlen ; +wire [02:00] fpga_core_axi_arsize ; +wire [01:00] fpga_core_axi_arburst; +wire fpga_core_axi_arlock ; +wire [03:00] fpga_core_axi_arcache; +wire [02:00] fpga_core_axi_arprot ; +wire fpga_core_axi_arvalid; +wire fpga_core_axi_arready; +wire [01:00] fpga_core_axi_rid ; +wire [63:00] fpga_core_axi_rdata ; +wire [01:00] fpga_core_axi_rresp ; +wire fpga_core_axi_rlast ; +wire fpga_core_axi_rvalid ; +wire fpga_core_axi_rready ; +wire [00:00] fpga_core_axi_awid ; +wire [31:00] fpga_core_axi_awaddr ; +wire [07:00] fpga_core_axi_awlen ; +wire [02:00] fpga_core_axi_awsize ; +wire [01:00] fpga_core_axi_awburst; +wire fpga_core_axi_awlock ; +wire [03:00] fpga_core_axi_awcache; +wire [02:00] fpga_core_axi_awprot ; +wire fpga_core_axi_awvalid; +wire fpga_core_axi_awready; +wire [63:00] fpga_core_axi_wdata ; +wire [07:00] fpga_core_axi_wstrb ; +wire fpga_core_axi_wlast ; +wire fpga_core_axi_wvalid ; +wire fpga_core_axi_wready ; +wire [07:00] fpga_core_axi_bid ; +wire [01:00] fpga_core_axi_bresp ; +wire fpga_core_axi_bvalid ; +wire fpga_core_axi_bready ; + +// Control +wire [31:00] shared_mem_ptr_s; + +// Zynq UltraScale+ PS +zynq_ps zynq_ps_inst ( + .clk_156mhz_i (clk_156mhz_int ), + .rstn_156mhz_i (~rst_156mhz_int ), + .GPIO_SHMEM_tri_o (shared_mem_ptr_s ), + + .s_axi_hp0_araddr (fpga_core_axi_araddr ), + .s_axi_hp0_arburst (fpga_core_axi_arburst ), + .s_axi_hp0_arcache (fpga_core_axi_arcache ), + // .s_axi_hp0_arid (fpga_core_axi_arid ), + .s_axi_hp0_arlen (fpga_core_axi_arlen ), + .s_axi_hp0_arlock (fpga_core_axi_arlock ), + .s_axi_hp0_arprot (fpga_core_axi_arprot ), + .s_axi_hp0_arqos ( ), + .s_axi_hp0_arready (fpga_core_axi_arready ), + .s_axi_hp0_arsize (fpga_core_axi_arsize ), + // .s_axi_hp0_aruser ( ), + .s_axi_hp0_arvalid (fpga_core_axi_arvalid ), + .s_axi_hp0_awaddr (fpga_core_axi_awaddr ), + .s_axi_hp0_awburst (fpga_core_axi_awburst ), + .s_axi_hp0_awcache (fpga_core_axi_awcache ), + // .s_axi_hp0_awid (fpga_core_axi_awid ), + .s_axi_hp0_awlen (fpga_core_axi_awlen ), + .s_axi_hp0_awlock (fpga_core_axi_awlock ), + .s_axi_hp0_awprot (fpga_core_axi_awprot ), + .s_axi_hp0_awqos ( ), + .s_axi_hp0_awready (fpga_core_axi_awready ), + .s_axi_hp0_awsize (fpga_core_axi_awsize ), + // .s_axi_hp0_awuser ( ), + .s_axi_hp0_awvalid (fpga_core_axi_awvalid ), + // .s_axi_hp0_bid (fpga_core_axi_bid ), + .s_axi_hp0_bready (fpga_core_axi_bready ), + .s_axi_hp0_bresp (fpga_core_axi_bresp ), + .s_axi_hp0_bvalid (fpga_core_axi_bvalid ), + .s_axi_hp0_rdata (fpga_core_axi_rdata ), + // .s_axi_hp0_rid (fpga_core_axi_rid ), + .s_axi_hp0_rlast (fpga_core_axi_rlast ), + .s_axi_hp0_rready (fpga_core_axi_rready ), + .s_axi_hp0_rresp (fpga_core_axi_rresp ), + .s_axi_hp0_rvalid (fpga_core_axi_rvalid ), + .s_axi_hp0_wdata (fpga_core_axi_wdata ), + .s_axi_hp0_wlast (fpga_core_axi_wlast ), + .s_axi_hp0_wready (fpga_core_axi_wready ), + .s_axi_hp0_wstrb (fpga_core_axi_wstrb ), + .s_axi_hp0_wvalid (fpga_core_axi_wvalid ) +); + +// XGMII 10G PHY +assign sfp0_tx_disable_b = 1'b1; + +wire sfp0_tx_clk_int; +wire sfp0_tx_rst_int; +wire [63:0] sfp0_txd_int; +wire [7:0] sfp0_txc_int; +wire sfp0_rx_clk_int; +wire sfp0_rx_rst_int; +wire [63:0] sfp0_rxd_int; +wire [7:0] sfp0_rxc_int; + +assign clk_156mhz_int = sfp0_tx_clk_int; +assign rst_156mhz_int = sfp0_tx_rst_int; + +wire sfp0_rx_block_lock; + +wire sfp_mgt_refclk_0; + +// Gigabit Transceiver Buffer +// +// Differential input buffer designed to work with the GTE +// (Gigabit Transceiver) transceiver tiles +// +// see https://docs.xilinx.com/r/2022.1-English/ug974-vivado-ultrascale-libraries/IBUFDS_GTE4 +IBUFDS_GTE4 ibufds_gte4_sfp_mgt_refclk_0_inst ( + .I (sfp_mgt_refclk_0_p), + .IB (sfp_mgt_refclk_0_n), + .CEB (1'b0), + .O (sfp_mgt_refclk_0), + .ODIV2 () +); + +wire sfp_qpll0lock; +wire sfp_qpll0outclk; +wire sfp_qpll0outrefclk; + +eth_xcvr_phy_wrapper #( + .HAS_COMMON(1) +) +sfp0_phy_inst ( + .xcvr_ctrl_clk(clk_125mhz_int), + .xcvr_ctrl_rst(rst_125mhz_int), + + // Common + .xcvr_gtpowergood_out(), + + // PLL out + .xcvr_gtrefclk00_in(sfp_mgt_refclk_0), + .xcvr_qpll0lock_out(sfp_qpll0lock), + .xcvr_qpll0outclk_out(sfp_qpll0outclk), + .xcvr_qpll0outrefclk_out(sfp_qpll0outrefclk), + + // PLL in + .xcvr_qpll0lock_in(1'b0), + .xcvr_qpll0reset_out(), + .xcvr_qpll0clk_in(1'b0), + .xcvr_qpll0refclk_in(1'b0), + + // Serial data + .xcvr_txp(sfp0_tx_p), + .xcvr_txn(sfp0_tx_n), + .xcvr_rxp(sfp0_rx_p), + .xcvr_rxn(sfp0_rx_n), + + // PHY connections + .phy_tx_clk(sfp0_tx_clk_int), + .phy_tx_rst(sfp0_tx_rst_int), + .phy_xgmii_txd(sfp0_txd_int), + .phy_xgmii_txc(sfp0_txc_int), + .phy_rx_clk(sfp0_rx_clk_int), + .phy_rx_rst(sfp0_rx_rst_int), + .phy_xgmii_rxd(sfp0_rxd_int), + .phy_xgmii_rxc(sfp0_rxc_int), + .phy_tx_bad_block(), + .phy_rx_error_count(), + .phy_rx_bad_block(), + .phy_rx_sequence_error(), + .phy_rx_block_lock(sfp0_rx_block_lock), + .phy_rx_high_ber(), + .phy_tx_prbs31_enable(), + .phy_rx_prbs31_enable() +); + + +fpga_core +core_inst ( + /* + * Clock: 156.25 MHz + * Synchronous reset + */ + .clk(clk_156mhz_int), + .rst(rst_156mhz_int), + /* + * GPIO + */ + .led(led), + /* + * Ethernet: SFP+ + */ + .sfp0_tx_clk(sfp0_tx_clk_int), + .sfp0_tx_rst(sfp0_tx_rst_int), + .sfp0_txd(sfp0_txd_int), + .sfp0_txc(sfp0_txc_int), + .sfp0_rx_clk(sfp0_rx_clk_int), + .sfp0_rx_rst(sfp0_rx_rst_int), + .sfp0_rxd(sfp0_rxd_int), + .sfp0_rxc(sfp0_rxc_int), + /* + * Master AXI (for udp rx/tx) + */ + .m_axi_arid (fpga_core_axi_arid ), + .m_axi_araddr (fpga_core_axi_araddr ), + .m_axi_arlen (fpga_core_axi_arlen ), + .m_axi_arsize (fpga_core_axi_arsize ), + .m_axi_arburst (fpga_core_axi_arburst), + .m_axi_arlock (fpga_core_axi_arlock ), + .m_axi_arcache (fpga_core_axi_arcache), + .m_axi_arprot (fpga_core_axi_arprot ), + .m_axi_arvalid (fpga_core_axi_arvalid), + .m_axi_arready (fpga_core_axi_arready), + .m_axi_rid (fpga_core_axi_rid ), + .m_axi_rdata (fpga_core_axi_rdata ), + .m_axi_rresp (fpga_core_axi_rresp ), + .m_axi_rlast (fpga_core_axi_rlast ), + .m_axi_rvalid (fpga_core_axi_rvalid ), + .m_axi_rready (fpga_core_axi_rready ), + .m_axi_awid (fpga_core_axi_awid ), + .m_axi_awaddr (fpga_core_axi_awaddr ), + .m_axi_awlen (fpga_core_axi_awlen ), + .m_axi_awsize (fpga_core_axi_awsize ), + .m_axi_awburst (fpga_core_axi_awburst), + .m_axi_awlock (fpga_core_axi_awlock ), + .m_axi_awcache (fpga_core_axi_awcache), + .m_axi_awprot (fpga_core_axi_awprot ), + .m_axi_awvalid (fpga_core_axi_awvalid), + .m_axi_awready (fpga_core_axi_awready), + .m_axi_wdata (fpga_core_axi_wdata ), + .m_axi_wstrb (fpga_core_axi_wstrb ), + .m_axi_wlast (fpga_core_axi_wlast ), + .m_axi_wvalid (fpga_core_axi_wvalid ), + .m_axi_wready (fpga_core_axi_wready ), + .m_axi_bid (fpga_core_axi_bid ), + .m_axi_bresp (fpga_core_axi_bresp ), + .m_axi_bvalid (fpga_core_axi_bvalid ), + .m_axi_bready (fpga_core_axi_bready ), + /* + * Master AXI (for udp rx/tx) + */ + .shared_mem_ptr_i (shared_mem_ptr_s) +); + +endmodule + +`resetall diff --git a/example/KR260/fpga_10g_ddr/rtl/fpga_core.v b/example/KR260/fpga_10g_ddr/rtl/fpga_core.v new file mode 100644 index 000000000..d006d17aa --- /dev/null +++ b/example/KR260/fpga_10g_ddr/rtl/fpga_core.v @@ -0,0 +1,705 @@ +/* + +Copyright (c) 2020-2021 Alex Forencich +Copyright (c) 2023 Víctor Mayoral Vilches + +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 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * FPGA core logic + */ +module fpga_core +( + /* + * Clock: 156.25MHz + * Synchronous reset + */ + input wire clk, + input wire rst, + + /* + * GPIO + */ + output wire [1:0] led, + + /* + * Ethernet: SFP+ + */ + input wire sfp0_tx_clk, + input wire sfp0_tx_rst, + output wire [63:0] sfp0_txd, + output wire [7:0] sfp0_txc, + input wire sfp0_rx_clk, + input wire sfp0_rx_rst, + input wire [63:0] sfp0_rxd, + input wire [7:0] sfp0_rxc, + + /* + * Master AXI (for udp rx/tx) + */ + output wire [07:00] m_axi_arid , + output wire [31:00] m_axi_araddr , + output wire [07:00] m_axi_arlen , + output wire [02:00] m_axi_arsize , + output wire [01:00] m_axi_arburst, + output wire m_axi_arlock , + output wire [03:00] m_axi_arcache, + output wire [02:00] m_axi_arprot , + output wire m_axi_arvalid, + input wire m_axi_arready, + input wire [07:00] m_axi_rid , + input wire [63:00] m_axi_rdata , + input wire [01:00] m_axi_rresp , + input wire m_axi_rlast , + input wire m_axi_rvalid , + output wire m_axi_rready , + output wire [07:00] m_axi_awid , + output wire [31:00] m_axi_awaddr , + output wire [07:00] m_axi_awlen , + output wire [02:00] m_axi_awsize , + output wire [01:00] m_axi_awburst, + output wire m_axi_awlock , + output wire [03:00] m_axi_awcache, + output wire [02:00] m_axi_awprot , + output wire m_axi_awvalid, + input wire m_axi_awready, + output wire [63:00] m_axi_wdata , + output wire [07:00] m_axi_wstrb , + output wire m_axi_wlast , + output wire m_axi_wvalid , + input wire m_axi_wready , + input wire [07:00] m_axi_bid , + input wire [01:00] m_axi_bresp , + input wire m_axi_bvalid , + output wire m_axi_bready , + + /* + * Control + */ + input wire [31:00] shared_mem_ptr_i +); + +// 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] axis_udp_rx_payload_tdata; +wire [7:0] axis_udp_rx_payload_tkeep; +wire axis_udp_rx_payload_tvalid; +wire axis_udp_rx_payload_tready; +wire axis_udp_rx_payload_tlast; +wire axis_udp_rx_payload_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] axis_udp_tx_payload_tdata; +wire [7:0] axis_udp_tx_payload_tkeep; +wire axis_udp_tx_payload_tvalid; +wire axis_udp_tx_payload_tready; +wire axis_udp_tx_payload_tlast; +wire axis_udp_tx_payload_tuser; + +// Configuration +wire [47:0] local_mac = 48'h02_00_00_00_00_00; +wire [31:0] local_ip = {8'd192, 8'd168, 8'd2, 8'd128}; +wire [31:0] gateway_ip = {8'd192, 8'd168, 8'd2, 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 (axis_udp_rx_payload_tvalid) begin + if ((~match_cond_reg & ~no_match_reg) | + (axis_udp_rx_payload_tvalid & axis_udp_rx_payload_tready & axis_udp_rx_payload_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_hdr_valid = 1'b1; // TEMPORARY; anything to be checked to consider header as valid? +assign tx_udp_ip_dest_ip = {8'd192, 8'd168, 8'd2, 8'd2}; +assign tx_udp_source_port = 1234; +assign tx_udp_dest_port = 5678; +assign tx_udp_length = 1024; + +// Place first payload byte onto LEDs +reg valid_last = 0; +reg [1:0] led_reg = 0; + +always @(posedge clk) begin + if (rst) begin + led_reg <= 0; + end else begin + valid_last <= axis_udp_tx_payload_tvalid; + if (axis_udp_tx_payload_tvalid & ~valid_last) begin + led_reg <= axis_udp_tx_payload_tdata; + end + end +end + +assign led = led_reg; + +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(sfp0_rx_clk), + .rx_rst(sfp0_rx_rst), + .tx_clk(sfp0_tx_clk), + .tx_rst(sfp0_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(sfp0_rxd), + .xgmii_rxc(sfp0_rxc), + .xgmii_txd(sfp0_txd), + .xgmii_txc(sfp0_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 (axis_udp_tx_payload_tdata), + .s_udp_payload_axis_tkeep (axis_udp_tx_payload_tkeep), + .s_udp_payload_axis_tvalid(axis_udp_tx_payload_tvalid), + .s_udp_payload_axis_tready(axis_udp_tx_payload_tready), + .s_udp_payload_axis_tlast (axis_udp_tx_payload_tlast), + .s_udp_payload_axis_tuser (axis_udp_tx_payload_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 (axis_udp_rx_payload_tdata), + .m_udp_payload_axis_tkeep (axis_udp_rx_payload_tkeep), + .m_udp_payload_axis_tvalid(axis_udp_rx_payload_tvalid), + .m_udp_payload_axis_tready(axis_udp_rx_payload_tready), + .m_udp_payload_axis_tlast (axis_udp_rx_payload_tlast), + .m_udp_payload_axis_tuser (axis_udp_rx_payload_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 (internal) <-> AXI (external) + +reg valid_address; +always @(posedge clk) begin + if (rst || shared_mem_ptr_i == 32'b0) begin + valid_address = 0; + end else begin + valid_address = 1; + end +end +reg valid_addr_last, valid_addr_sec2last; +wire valid_addr_one_pulse; +assign valid_addr_one_pulse = valid_addr_last & !valid_addr_sec2last; +always @(posedge clk) begin + if (rst) begin + valid_addr_last <= 0; + valid_addr_sec2last <= 0; + end else begin + valid_addr_last <= valid_address; + valid_addr_sec2last <= valid_addr_last; + end +end + +axi_dma_wr #( + .AXI_DATA_WIDTH (64), + .AXI_ADDR_WIDTH (32), + .AXI_ID_WIDTH (1), + .AXI_MAX_BURST_LEN(256), + .AXIS_DATA_WIDTH (64), + .AXIS_KEEP_ENABLE (1), + .AXIS_KEEP_WIDTH (8), + .AXIS_LAST_ENABLE (1), + .AXIS_ID_ENABLE (0), + .AXIS_DEST_ENABLE (0), + .AXIS_USER_ENABLE (1), + .AXIS_USER_WIDTH (1) +) axi_dma_wr_inst ( + .clk (clk), + .rst (rst), + .s_axis_write_desc_addr (shared_mem_ptr_i ), + .s_axis_write_desc_len (1024 ), + .s_axis_write_desc_tag (8'd0 ), + .s_axis_write_desc_valid (valid_address ), + .s_axis_write_desc_ready (), + .s_axis_write_data_tdata (axis_udp_rx_payload_tdata ), + .s_axis_write_data_tkeep (axis_udp_rx_payload_tkeep ), + .s_axis_write_data_tvalid (axis_udp_rx_payload_tvalid), + .s_axis_write_data_tready (axis_udp_rx_payload_tready), + .s_axis_write_data_tlast (axis_udp_rx_payload_tlast ), + .s_axis_write_data_tid (1'b0), + .s_axis_write_data_tdest (), + .s_axis_write_data_tuser (axis_udp_rx_payload_tuser ), + .m_axi_awid (m_axi_awid ), + .m_axi_awaddr (m_axi_awaddr ), + .m_axi_awlen (m_axi_awlen ), + .m_axi_awsize (m_axi_awsize ), + .m_axi_awburst (m_axi_awburst), + .m_axi_awlock (m_axi_awlock ), + .m_axi_awcache (m_axi_awcache), + .m_axi_awprot (m_axi_awprot ), + .m_axi_awvalid (m_axi_awvalid), + .m_axi_awready (m_axi_awready), + .m_axi_wdata (m_axi_wdata ), + .m_axi_wstrb (m_axi_wstrb ), + .m_axi_wlast (m_axi_wlast ), + .m_axi_wvalid (m_axi_wvalid ), + .m_axi_wready (m_axi_wready ), + .m_axi_bid (m_axi_bid ), + .m_axi_bresp (m_axi_bresp ), + .m_axi_bvalid (m_axi_bvalid ), + .m_axi_bready (m_axi_bready ), + .enable (1'b1 ), + .abort (1'b0 ) +); + +axi_dma_rd #( + .AXI_DATA_WIDTH (64), + .AXI_ADDR_WIDTH (32), + .AXI_ID_WIDTH (1 ), + .AXI_MAX_BURST_LEN (256), + .AXIS_DATA_WIDTH (64), + .AXIS_KEEP_ENABLE (1 ), + .AXIS_KEEP_WIDTH (8 ), + .AXIS_LAST_ENABLE (1 ), + .AXIS_ID_ENABLE (0 ), + .AXIS_DEST_ENABLE (0 ), + .AXIS_USER_ENABLE (1 ), + .AXIS_USER_WIDTH (1 ) +) axi_dma_rd_inst ( + .clk (clk), + .rst (rst), + .s_axis_read_desc_addr (shared_mem_ptr_i), + .s_axis_read_desc_len (1024), + .s_axis_read_desc_tag (8'd0), + .s_axis_read_desc_id (1'b0), + .s_axis_read_desc_dest (), + .s_axis_read_desc_user (1'b0), + .s_axis_read_desc_valid (valid_addr_one_pulse), + .s_axis_read_desc_ready ( ), + .m_axis_read_desc_status_tag ( ), + .m_axis_read_desc_status_error ( ), + .m_axis_read_desc_status_valid ( ), + .m_axis_read_data_tdata (axis_udp_tx_payload_tdata ), + .m_axis_read_data_tkeep (axis_udp_tx_payload_tkeep ), + .m_axis_read_data_tvalid (axis_udp_tx_payload_tvalid ), // Important: one-cycle pulse per each transaction to be performed; otherwise, axi_dma_rd will queue a second transaction after the intended one + .m_axis_read_data_tready (axis_udp_tx_payload_tready ), + .m_axis_read_data_tlast (axis_udp_tx_payload_tlast ), + .m_axis_read_data_tid ( ), + .m_axis_read_data_tdest ( ), + .m_axis_read_data_tuser (axis_udp_tx_payload_tuser ), + .m_axi_arid (m_axi_arid ), + .m_axi_araddr (m_axi_araddr ), + .m_axi_arlen (m_axi_arlen ), + .m_axi_arsize (m_axi_arsize ), + .m_axi_arburst (m_axi_arburst ), + .m_axi_arlock (m_axi_arlock ), + .m_axi_arcache (m_axi_arcache ), + .m_axi_arprot (m_axi_arprot ), + .m_axi_arvalid (m_axi_arvalid ), + .m_axi_arready (m_axi_arready ), + .m_axi_rid (m_axi_rid ), + .m_axi_rdata (m_axi_rdata ), + .m_axi_rresp (m_axi_rresp ), + .m_axi_rlast (m_axi_rlast ), + .m_axi_rvalid (m_axi_rvalid ), + .m_axi_rready (m_axi_rready ), + .enable (1'b1 ) +); + +// Dump waves for simulation +`ifdef COCOTB_SIM +initial begin + $dumpfile ("fpga_core.vcd"); + $dumpvars (0, fpga_core); + #1; +end +`endif + +endmodule + +`resetall diff --git a/example/KR260/fpga_10g_ddr/rtl/sync_signal.v b/example/KR260/fpga_10g_ddr/rtl/sync_signal.v new file mode 100644 index 000000000..74b855fa1 --- /dev/null +++ b/example/KR260/fpga_10g_ddr/rtl/sync_signal.v @@ -0,0 +1,62 @@ +/* + +Copyright (c) 2014-2018 Alex Forencich + +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 + +`resetall +`timescale 1 ns / 1 ps +`default_nettype none + +/* + * Synchronizes an asyncronous signal to a given clock by using a pipeline of + * two registers. + */ +module sync_signal #( + parameter WIDTH=1, // width of the input and output signals + parameter N=2 // depth of synchronizer +)( + input wire clk, + input wire [WIDTH-1:0] in, + output wire [WIDTH-1:0] out +); + +reg [WIDTH-1:0] sync_reg[N-1:0]; + +/* + * The synchronized output is the last register in the pipeline. + */ +assign out = sync_reg[N-1]; + +integer k; + +always @(posedge clk) begin + sync_reg[0] <= in; + for (k = 1; k < N; k = k + 1) begin + sync_reg[k] <= sync_reg[k-1]; + end +end + +endmodule + +`resetall diff --git a/example/KR260/fpga_10g_ddr/sw/hw_test_from_ps.py b/example/KR260/fpga_10g_ddr/sw/hw_test_from_ps.py new file mode 100644 index 000000000..dfe5638c6 --- /dev/null +++ b/example/KR260/fpga_10g_ddr/sw/hw_test_from_ps.py @@ -0,0 +1,37 @@ +# Dependencies +from pynq import Overlay +from pynq import allocate +from pynq.lib import AxiGPIO +from pynq import MMIO +import time +import numpy as np + +# Overlay +overlay = Overlay("fpga.bit") + +# Allocate memory shared with PL +shared_mem = allocate(shape=(256,), dtype='u8') # 256 x 64b = 2KB +print( "Base address of shared region: " + str(hex(shared_mem.device_address)) ) + +# Dump a message to shared memory +tx_message_str = "Hi from KR260 PS Ubuntu targeting workstation" +tx_message_unicode_arr = np.array([ord(c) for c in tx_message_str], dtype=np.uint64) +for array_index in range(len(tx_message_unicode_arr)): + shared_mem[array_index] = tx_message_unicode_arr[array_index] + +# Send base address to gpio in the PL (this will trigger a read transaction to the shared memory from the PL side) +mmio_gpio = MMIO(0xA0000000, 0x10000) +gpio_offset = 0 # Offset for 32b data for gpio channel 1 +gpio_data = shared_mem.device_address +mmio_gpio.write(gpio_offset, gpio_data) + +# Continuously print region where the incoming packet should be placed +while True: + shared_mem.invalidate() + print("\n") + for i in range(256): + hex_word = shared_mem[i] + input_bytes = hex_word.tobytes() + unicode_string = "".join([chr(b) for b in input_bytes]) + print(str(unicode_string), end="") + time.sleep(1) diff --git a/example/KR260/fpga_10g_ddr/sw/hw_test_from_ws.py b/example/KR260/fpga_10g_ddr/sw/hw_test_from_ws.py new file mode 100644 index 000000000..7a0bd5e63 --- /dev/null +++ b/example/KR260/fpga_10g_ddr/sw/hw_test_from_ws.py @@ -0,0 +1,56 @@ +######################################## +# Imports +######################################## + +import socket +from scapy.layers.l2 import Ether, ARP +from scapy.sendrecv import sendp, sniff + +######################################## +# Opens UDP socket +######################################## + +UDP_IP = "192.168.2.2" +UDP_PORT = 5678 +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +sock.bind((UDP_IP, UDP_PORT)) +print(f"Opened UDP Socket at port {UDP_PORT}...") + +######################################## +# Waits for arp request and send arp response back +######################################## + +interface = 'enp1s0' +eth = Ether(src='00:e0:c0:4f:59:11', dst='02:00:00:00:00:00') +arp = ARP(hwtype=1, ptype=0x0800, hwlen=6, plen=4, op=2, + hwsrc='00:e0:c0:4f:59:11', psrc='192.168.2.2', + hwdst='02:00:00:00:00:00', pdst='192.168.2.128') +resp_pkt = eth / arp +filter_expr = 'arp and src host 192.168.2.128' + +print("Waiting for ARP request...") +while True: + arp_request = sniff(count=1, iface=interface, filter=filter_expr) + if arp_request[0].op == 1: + print("Sending ARP response...") + sendp(resp_pkt, iface=interface) + break + +######################################## +# Listens UDP +######################################## + +print("Waiting for receiving UDP packet...") +data, addr = sock.recvfrom(1024) # receive up to 1024 bytes of data +decoded_data = data.decode('utf-8') # decode the data to UTF-8 string +print(decoded_data) + +######################################## +# Replies UDP +######################################## + +print("Sending ack back...") +ack_message = "ack: " + decoded_data +ack_message_encoded = ack_message.encode('utf-8') +sock.sendto(ack_message_encoded, addr) +print(ack_message) diff --git a/example/KR260/fpga_10g_ddr/tb/fpga_core/.gitignore b/example/KR260/fpga_10g_ddr/tb/fpga_core/.gitignore new file mode 100644 index 000000000..7ac4a3848 --- /dev/null +++ b/example/KR260/fpga_10g_ddr/tb/fpga_core/.gitignore @@ -0,0 +1,3 @@ +/sim_build +results.xml +fpga_core.vcd \ No newline at end of file diff --git a/example/KR260/fpga_10g_ddr/tb/fpga_core/Makefile b/example/KR260/fpga_10g_ddr/tb/fpga_core/Makefile new file mode 100644 index 000000000..19526d2fa --- /dev/null +++ b/example/KR260/fpga_10g_ddr/tb/fpga_core/Makefile @@ -0,0 +1,99 @@ +# Copyright (c) 2020 Alex Forencich +# +# 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. + +TOPLEVEL_LANG = verilog + +SIM ?= icarus +WAVES ?= 0 + +COCOTB_HDL_TIMEUNIT = 1ns +COCOTB_HDL_TIMEPRECISION = 1ps + +DUT = fpga_core +TOPLEVEL = $(DUT) +MODULE = test_$(DUT) +VERILOG_SOURCES += ../../rtl/$(DUT).v +VERILOG_SOURCES += ../../lib/eth/rtl/eth_mac_10g_fifo.v +VERILOG_SOURCES += ../../lib/eth/rtl/eth_mac_10g.v +VERILOG_SOURCES += ../../lib/eth/rtl/axis_xgmii_rx_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/axis_xgmii_tx_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/lfsr.v +VERILOG_SOURCES += ../../lib/eth/rtl/eth_axis_rx.v +VERILOG_SOURCES += ../../lib/eth/rtl/eth_axis_tx.v +VERILOG_SOURCES += ../../lib/eth/rtl/udp_complete_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/udp_checksum_gen_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/udp_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/udp_ip_rx_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/udp_ip_tx_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/ip_complete_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/ip_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/ip_eth_rx_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/ip_eth_tx_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/ip_arb_mux.v +VERILOG_SOURCES += ../../lib/eth/rtl/arp.v +VERILOG_SOURCES += ../../lib/eth/rtl/arp_cache.v +VERILOG_SOURCES += ../../lib/eth/rtl/arp_eth_rx.v +VERILOG_SOURCES += ../../lib/eth/rtl/arp_eth_tx.v +VERILOG_SOURCES += ../../lib/eth/rtl/eth_arb_mux.v +VERILOG_SOURCES += ../../lib/eth/lib/axis/rtl/arbiter.v +VERILOG_SOURCES += ../../lib/eth/lib/axis/rtl/priority_encoder.v +VERILOG_SOURCES += ../../lib/eth/lib/axis/rtl/axis_fifo.v +VERILOG_SOURCES += ../../lib/eth/lib/axis/rtl/axis_async_fifo.v +VERILOG_SOURCES += ../../lib/eth/lib/axis/rtl/axis_async_fifo_adapter.v +VERILOG_SOURCES += ../../lib/eth/lib/axi/rtl/axi_dma_wr.v +VERILOG_SOURCES += ../../lib/eth/lib/axi/rtl/axi_dma_rd.v + +# module parameters +#export PARAM_A ?= value + +ifeq ($(SIM), icarus) + PLUSARGS += -fst + +# COMPILE_ARGS += -P $(TOPLEVEL).A=$(PARAM_A) + + ifeq ($(WAVES), 1) + VERILOG_SOURCES += iverilog_dump.v + COMPILE_ARGS += -s iverilog_dump + endif +else ifeq ($(SIM), verilator) + COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH + +# COMPILE_ARGS += -GA=$(PARAM_A) + + ifeq ($(WAVES), 1) + COMPILE_ARGS += --trace-fst + endif +endif + +include $(shell cocotb-config --makefiles)/Makefile.sim + +iverilog_dump.v: + echo 'module iverilog_dump();' > $@ + echo 'initial begin' >> $@ + echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@ + echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@ + echo 'end' >> $@ + echo 'endmodule' >> $@ + +clean:: + @rm -rf iverilog_dump.v + @rm -rf dump.fst $(TOPLEVEL).fst + @rm -rf __pycache__ + @rm results.xml diff --git a/example/KR260/fpga_10g_ddr/tb/fpga_core/run_test_2048byte_udp_rx_gtkwave.tcl b/example/KR260/fpga_10g_ddr/tb/fpga_core/run_test_2048byte_udp_rx_gtkwave.tcl new file mode 100644 index 000000000..3b76b79c1 --- /dev/null +++ b/example/KR260/fpga_10g_ddr/tb/fpga_core/run_test_2048byte_udp_rx_gtkwave.tcl @@ -0,0 +1,62 @@ +# add_waves.tcl +set sig_list { \ + clk \ + rst \ + sfp0_rx_clk \ + sfp0_rx_rst \ + sfp0_rxd \ + sfp0_rxc \ + axis_udp_rx_payload_tdata \ + axis_udp_rx_payload_tkeep \ + axis_udp_rx_payload_tvalid \ + axis_udp_rx_payload_tready \ + axis_udp_rx_payload_tlast \ + axis_udp_rx_payload_tuser \ + axi_dma_wr_inst.clk \ + axi_dma_wr_inst.rst \ + axi_dma_wr_inst.enable \ + axi_dma_wr_inst.abort \ + axi_dma_wr_inst.s_axis_write_desc_addr \ + axi_dma_wr_inst.s_axis_write_desc_len \ + axi_dma_wr_inst.s_axis_write_desc_tag \ + axi_dma_wr_inst.s_axis_write_desc_valid \ + axi_dma_wr_inst.s_axis_write_desc_ready \ + axi_dma_wr_inst.s_axis_write_data_tdata \ + axi_dma_wr_inst.s_axis_write_data_tkeep \ + axi_dma_wr_inst.s_axis_write_data_tvalid \ + axi_dma_wr_inst.s_axis_write_data_tready \ + axi_dma_wr_inst.s_axis_write_data_tlast \ + axi_dma_wr_inst.s_axis_write_data_tid \ + axi_dma_wr_inst.s_axis_write_data_tdest \ + axi_dma_wr_inst.s_axis_write_data_tuser \ + m_axi_awid \ + m_axi_awaddr \ + m_axi_awlen \ + m_axi_awsize \ + m_axi_awburst \ + m_axi_awlock \ + m_axi_awcache \ + m_axi_awprot \ + m_axi_awvalid \ + m_axi_awready \ + m_axi_wdata \ + m_axi_wstrb \ + m_axi_wlast \ + m_axi_wvalid \ + m_axi_wready \ + m_axi_bid \ + m_axi_bresp \ + m_axi_bvalid \ + m_axi_bready \ +} + +gtkwave::addSignalsFromList $sig_list + +# Zoom full (Shift + Alt + F) +gtkwave::/Time/Zoom/Zoom_Full + +# Change signal formats +gtkwave::/Edit/Highlight_Regexp "axi_dma_wr_inst.clk" +gtkwave::/Edit/Data_Format/Hexadecimal +gtkwave::/Edit/UnHighlight_All + diff --git a/example/KR260/fpga_10g_ddr/tb/fpga_core/run_test_2048byte_udp_tx_gtkwave.tcl b/example/KR260/fpga_10g_ddr/tb/fpga_core/run_test_2048byte_udp_tx_gtkwave.tcl new file mode 100644 index 000000000..8bd5d5e57 --- /dev/null +++ b/example/KR260/fpga_10g_ddr/tb/fpga_core/run_test_2048byte_udp_tx_gtkwave.tcl @@ -0,0 +1,57 @@ +# add_waves.tcl +set sig_list { \ + clk \ + rst \ + axi_dma_wr_inst.enable \ + axi_dma_wr_inst.abort \ + axi_dma_wr_inst.s_axis_write_desc_addr \ + axi_dma_wr_inst.s_axis_write_desc_len \ + axi_dma_wr_inst.s_axis_write_desc_tag \ + axi_dma_wr_inst.s_axis_write_desc_valid \ + axi_dma_wr_inst.s_axis_write_desc_ready \ + axi_dma_wr_inst.s_axis_write_data_tdata \ + axi_dma_wr_inst.s_axis_write_data_tkeep \ + axi_dma_wr_inst.s_axis_write_data_tvalid \ + axi_dma_wr_inst.s_axis_write_data_tready \ + axi_dma_wr_inst.s_axis_write_data_tlast \ + axi_dma_wr_inst.s_axis_write_data_tid \ + axi_dma_wr_inst.s_axis_write_data_tdest \ + axi_dma_wr_inst.s_axis_write_data_tuser \ + m_axi_arid \ + m_axi_araddr \ + m_axi_arlen \ + m_axi_arsize \ + m_axi_arburst \ + m_axi_arlock \ + m_axi_arcache \ + m_axi_arprot \ + m_axi_arvalid \ + m_axi_arready \ + m_axi_rid \ + m_axi_rdata \ + m_axi_rresp \ + m_axi_rlast \ + m_axi_rvalid \ + m_axi_rready \ + axis_udp_tx_payload_tdata \ + axis_udp_tx_payload_tkeep \ + axis_udp_tx_payload_tvalid \ + axis_udp_tx_payload_tready \ + axis_udp_tx_payload_tlast \ + axis_udp_tx_payload_tuser \ + sfp0_tx_clk \ + sfp0_tx_rst \ + sfp0_txd \ + sfp0_txc \ +} + +gtkwave::addSignalsFromList $sig_list + +# Zoom full (Shift + Alt + F) +gtkwave::/Time/Zoom/Zoom_Full + +# Change signal formats +gtkwave::/Edit/Highlight_Regexp "axi_dma_wr_inst.clk" +gtkwave::/Edit/Data_Format/Hexadecimal +gtkwave::/Edit/UnHighlight_All + diff --git a/example/KR260/fpga_10g_ddr/tb/fpga_core/test_fpga_core.py b/example/KR260/fpga_10g_ddr/tb/fpga_core/test_fpga_core.py new file mode 100644 index 000000000..01ccdcd71 --- /dev/null +++ b/example/KR260/fpga_10g_ddr/tb/fpga_core/test_fpga_core.py @@ -0,0 +1,268 @@ +""" + +Copyright (c) 2020 Alex Forencich + +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. + +""" + +################################################################################### +# Imports +################################################################################### + +import logging +import os + +from scapy.layers.l2 import Ether, ARP +from scapy.layers.inet import IP, UDP + +import cocotb_test.simulator + +import cocotb +from cocotb.log import SimLog +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge + +from cocotbext.eth import XgmiiFrame, XgmiiSource, XgmiiSink +from cocotbext.axi import AxiBus, AxiRam + +################################################################################### +# TB class (common for all tests) +################################################################################### + +class TB: + def __init__(self, dut): + self.dut = dut + + self.log = SimLog("cocotb.tb") + self.log.setLevel(logging.DEBUG) + + cocotb.start_soon(Clock(dut.clk, 6.4, units="ns").start()) + + # Ethernet + cocotb.start_soon(Clock(dut.sfp0_rx_clk, 6.4, units="ns").start()) + self.sfp0_source = XgmiiSource(dut.sfp0_rxd, dut.sfp0_rxc, dut.sfp0_rx_clk, dut.sfp0_rx_rst) + cocotb.start_soon(Clock(dut.sfp0_tx_clk, 6.4, units="ns").start()) + self.sfp0_sink = XgmiiSink(dut.sfp0_txd, dut.sfp0_txc, dut.sfp0_tx_clk, dut.sfp0_tx_rst) + + # AXI master interface + self.axi_ram = AxiRam(AxiBus.from_prefix(dut, "m_axi"), dut.clk, dut.rst, size=2**16) + self.dut.shared_mem_ptr_i = 64 + + async def init(self): + + self.dut.rst.setimmediatevalue(0) + self.dut.sfp0_rx_rst.setimmediatevalue(0) + self.dut.sfp0_tx_rst.setimmediatevalue(0) + + for k in range(10): + await RisingEdge(self.dut.clk) + + self.dut.rst.value = 1 + self.dut.sfp0_rx_rst.value = 1 + self.dut.sfp0_tx_rst.value = 1 + + for k in range(10): + await RisingEdge(self.dut.clk) + + self.dut.rst.value = 0 + self.dut.sfp0_rx_rst.value = 0 + self.dut.sfp0_tx_rst.value = 0 + +################################################################################### +# Test: sfprx_to_shmem +# Stimulus: SFP packet generated and sent to DUT SFP RX port +# Expected: packet payload available at DUT m_axi +################################################################################### + +@cocotb.test() +async def run_test_1024byte_udp_rx(dut): + + # Initialize TB + + tb = TB(dut) + await tb.init() + + # Generate UDP packet and send it to DUT through SFP rx + + tb.log.info("Generating UDP packet...") + # Payload + payload = bytes([x % 256 for x in range(256)]) + payload_1024b = payload + for _ in range(int(1024/256)-1): payload_1024b += payload + # Wrap packet + eth = Ether(src='5a:51:52:53:54:55', dst='02:00:00:00:00:00') + ip = IP(src='192.168.2.100', dst='192.168.2.128') + udp = UDP(sport=5678, dport=1234) + test_pkt = eth / ip / udp / payload_1024b + test_frame = XgmiiFrame.from_payload(test_pkt.build()) + # Send packet to DUT + await tb.sfp0_source.send(test_frame) + for _ in range(1000): await RisingEdge(dut.clk) + + # Check memory content amd dump it + + read_str = tb.axi_ram.read(int(tb.dut.shared_mem_ptr_i), 1024) + tb.log.info("Dumping axi ram content..." + tb.axi_ram.hexdump_str(0x0000, 2048, prefix="RAM")) + assert(read_str == payload_1024b) + await RisingEdge(dut.clk) + +################################################################################### +# Test: shmem_to_sfprx +# Stimulus: UDP packet payload placed at shared memory +# Expected: packet payload available at DUT sfp tx +################################################################################### + +@cocotb.test() +async def run_test_1024byte_udp_tx(dut): + + # Initialize TB + + tb = TB(dut) + await tb.init() + tb.log.info("test UDP TX packet") + + # Generate pkt_info (only to store src/dst info) + + eth = Ether(src='5a:51:52:53:54:55', dst='02:00:00:00:00:00') + ip = IP(src='192.168.2.2', dst='192.168.2.128') + udp = UDP(sport=5678, dport=1234) + info_pkt = eth / ip / udp + + # Generate payload and dump it into axi ram + + payload = bytes([x % 256 for x in range(256)]) + payload_1024b = payload + for _ in range(int(1024/256)-1): payload_1024b += payload + tb.axi_ram.write(int(tb.dut.shared_mem_ptr_i), payload_1024b) + tb.log.info(tb.axi_ram.hexdump_str(0x0000, 2048, prefix="RAM")) + + # Monitor sfp tx until detecting traffic (ARP request from the DUT) + + tb.log.info("receive ARP request from DUT") + rx_frame = await tb.sfp0_sink.recv() + rx_pkt = Ether(bytes(rx_frame.get_payload())) + tb.log.info("RX packet: %s", repr(rx_pkt)) + tb.log.info(rx_pkt.payload) + + assert rx_pkt.dst == 'ff:ff:ff:ff:ff:ff' + assert rx_pkt.src == info_pkt.dst + assert rx_pkt[ARP].hwtype == 1 + assert rx_pkt[ARP].ptype == 0x0800 + assert rx_pkt[ARP].hwlen == 6 + assert rx_pkt[ARP].plen == 4 + assert rx_pkt[ARP].op == 1 + assert rx_pkt[ARP].hwsrc == info_pkt.dst + assert rx_pkt[ARP].psrc == info_pkt[IP].dst + assert rx_pkt[ARP].hwdst == '00:00:00:00:00:00' + assert rx_pkt[ARP].pdst == info_pkt[IP].src + + # Monitor sfp tx until detecting traffic (ARP response to the DUT) + + tb.log.info("send ARP response to DUT") + arp = ARP(hwtype=1, ptype=0x0800, hwlen=6, plen=4, op=2, + hwsrc=info_pkt.src, psrc=info_pkt[IP].src, + hwdst=info_pkt.dst, pdst=info_pkt[IP].dst) + resp_pkt = eth / arp + resp_frame = XgmiiFrame.from_payload(resp_pkt.build()) + await tb.sfp0_source.send(resp_frame) + + # Monitor sfp tx until detecting traffic (UDP from the DUT) + + tb.log.info("receive UDP packet from DUT") + rx_frame = await tb.sfp0_sink.recv() + rx_pkt = Ether(bytes(rx_frame.get_payload())) + tb.log.info("RX packet: %s", repr(rx_pkt)) + + assert rx_pkt.dst == info_pkt.src + assert rx_pkt.src == info_pkt.dst + assert rx_pkt[IP].dst == info_pkt[IP].src + assert rx_pkt[IP].src == info_pkt[IP].dst + assert rx_pkt[UDP].dport == info_pkt[UDP].sport + assert rx_pkt[UDP].sport == info_pkt[UDP].dport + + for _ in range(10): await RisingEdge(dut.clk) + +################################################################################### +# paths, cocotb and simulator definitions +################################################################################### + +tests_dir = os.path.abspath(os.path.dirname(__file__)) +rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl')) +lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib')) +axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'lib', 'axis', 'rtl')) +eth_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'rtl')) + + +def test_fpga_core(request): + dut = "fpga_core" + module = os.path.splitext(os.path.basename(__file__))[0] + toplevel = dut + + verilog_sources = [ + os.path.join(rtl_dir, f"{dut}.v"), + os.path.join(eth_rtl_dir, "eth_mac_10g_fifo.v"), + os.path.join(eth_rtl_dir, "eth_mac_10g.v"), + os.path.join(eth_rtl_dir, "axis_xgmii_rx_64.v"), + os.path.join(eth_rtl_dir, "axis_xgmii_tx_64.v"), + os.path.join(eth_rtl_dir, "lfsr.v"), + os.path.join(eth_rtl_dir, "eth_axis_rx.v"), + os.path.join(eth_rtl_dir, "eth_axis_tx.v"), + os.path.join(eth_rtl_dir, "udp_complete_64.v"), + os.path.join(eth_rtl_dir, "udp_checksum_gen_64.v"), + os.path.join(eth_rtl_dir, "udp_64.v"), + os.path.join(eth_rtl_dir, "udp_ip_rx_64.v"), + os.path.join(eth_rtl_dir, "udp_ip_tx_64.v"), + os.path.join(eth_rtl_dir, "ip_complete_64.v"), + os.path.join(eth_rtl_dir, "ip_64.v"), + os.path.join(eth_rtl_dir, "ip_eth_rx_64.v"), + os.path.join(eth_rtl_dir, "ip_eth_tx_64.v"), + os.path.join(eth_rtl_dir, "ip_arb_mux.v"), + os.path.join(eth_rtl_dir, "arp.v"), + os.path.join(eth_rtl_dir, "arp_cache.v"), + os.path.join(eth_rtl_dir, "arp_eth_rx.v"), + os.path.join(eth_rtl_dir, "arp_eth_tx.v"), + os.path.join(eth_rtl_dir, "eth_arb_mux.v"), + os.path.join(axis_rtl_dir, "arbiter.v"), + os.path.join(axis_rtl_dir, "priority_encoder.v"), + os.path.join(axis_rtl_dir, "axis_fifo.v"), + os.path.join(axis_rtl_dir, "axis_async_fifo.v"), + os.path.join(axis_rtl_dir, "axis_async_fifo_adapter.v"), + os.path.join(axis_rtl_dir, "axi_dma_wr.v"), + os.path.join(axis_rtl_dir, "axi_dma_rd.v"), + ] + + parameters = {} + + # parameters['A'] = val + + extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()} + + sim_build = os.path.join(tests_dir, "sim_build", + request.node.name.replace('[', '-').replace(']', '')) + + cocotb_test.simulator.run( + python_search=[tests_dir], + verilog_sources=verilog_sources, + toplevel=toplevel, + module=module, + parameters=parameters, + sim_build=sim_build, + extra_env=extra_env, + )