eth: Add 100G configuration to NT200A01/XT200A02 example design

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2026-08-11 14:35:11 -07:00
parent 8a9c3ae5c9
commit 1d741faa1c
17 changed files with 993 additions and 328 deletions

View File

@@ -19,7 +19,7 @@ TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
SYN_FILES = $(RTL_DIR)/fpga_nt200a01.sv
SYN_FILES += $(RTL_DIR)/fpga_core.sv
SYN_FILES += $(RTL_DIR)/../pll/si5340_i2c_init.sv
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_100g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/lss/rtl/taxi_i2c_master.sv
SYN_FILES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
@@ -29,13 +29,15 @@ SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
XDC_FILES += ../syn/NT200A01/fpga.xdc
XDC_FILES += ../syn/NT200A01/gpio.xdc
XDC_FILES += ../syn/NT200A01/qsfp.xdc
XDC_FILES += ../syn/NT200A01/eth_cmac.xdc
XDC_FILES += $(TAXI_SRC_DIR)/eth/syn/vivado/taxi_eth_mac_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/axis/syn/vivado/taxi_axis_async_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_reset.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl
# IP
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_322.tcl
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_100g_us_cmace3.tcl
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_100g_us_gty_322.tcl
# Configuration
CONFIG_TCL_FILES = config.tcl

View File

@@ -8,10 +8,10 @@
set params [dict create]
# 10G MAC configuration
# MAC configuration
dict set params CFG_LOW_LATENCY "1"
dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "64"
dict set params MAC_DATA_W "512"
# apply parameters to top-level
set param_list {}

View File

@@ -8,7 +8,7 @@
set params [dict create]
# 10G MAC configuration
# MAC configuration
dict set params CFG_LOW_LATENCY "1"
dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "32"

View File

@@ -0,0 +1,159 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# FPGA settings
FPGA_PART = xcvu095-ffva2104-2-e
FPGA_TOP = fpga
FPGA_ARCH = virtexu
RTL_DIR = ../rtl
LIB_DIR = ../lib
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
# Files for synthesis
SYN_FILES = $(RTL_DIR)/fpga_nt200a01.sv
SYN_FILES += $(RTL_DIR)/fpga_core.sv
SYN_FILES += $(RTL_DIR)/../pll/si5340_i2c_init.sv
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/lss/rtl/taxi_i2c_master.sv
SYN_FILES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
# XDC files
XDC_FILES += ../syn/NT200A01/fpga.xdc
XDC_FILES += ../syn/NT200A01/gpio.xdc
XDC_FILES += ../syn/NT200A01/qsfp.xdc
XDC_FILES += $(TAXI_SRC_DIR)/eth/syn/vivado/taxi_eth_mac_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/axis/syn/vivado/taxi_axis_async_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_reset.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl
# IP
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_322.tcl
# Configuration
CONFIG_TCL_FILES = config.tcl
include ../common/vivado.mk
%_fallback.bit: %.bit
echo "open_project $*.xpr" > generate_fallback_bit.tcl
echo "open_run impl_1" >> generate_fallback_bit.tcl
echo "startgroup" >> generate_fallback_bit.tcl
echo "set_property BITSTREAM.CONFIG.SPI_32BIT_ADDR NO [current_design]" >> generate_fallback_bit.tcl
echo "endgroup" >> generate_fallback_bit.tcl
echo "write_bitstream -verbose -force $*_fallback.bit" >> generate_fallback_bit.tcl
echo "undo" >> generate_fallback_bit.tcl
echo "exit" >> generate_fallback_bit.tcl
vivado -nojournal -nolog -mode batch -source generate_fallback_bit.tcl
mkdir -p rev
EXT=bit; COUNT=100; \
while [ -e rev/$*_rev$$COUNT.$$EXT ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
cp $@ rev/$*_fallback_rev$$COUNT.$$EXT; \
echo "Output: rev/$*_fallback_rev$$COUNT.$$EXT";
program: $(FPGA_TOP).bit
echo "open_hw_manager" > 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
%.mcs %.prm: %.bit
echo "write_cfgmem -force -format mcs -size 64 -interface SPIx4 -loadbit {up 0x00000000 $*.bit} -checksum -file $*.mcs" > generate_mcs.tcl
echo "exit" >> generate_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*$$x rev/$*_rev$$COUNT$$x; \
echo "Output: rev/$*_rev$$COUNT$$x"; done;
%_fallback.mcs %_fallback.prm: %_fallback.bit
echo "write_cfgmem -force -format mcs -size 64 -interface SPIx4 -loadbit {up 0x03000000 $*_fallback.bit} -checksum -file $*_fallback.mcs" > generate_fallback_mcs.tcl
echo "exit" >> generate_fallback_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_fallback_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*_fallback$$x rev/$*_fallback_rev$$COUNT$$x; \
echo "Output: rev/$*_fallback_rev$$COUNT$$x"; done;
%_full.mcs %_full.prm: %_fallback.bit %.bit
echo "write_cfgmem -force -format mcs -size 64 -interface SPIx4 -loadbit {up 0x00000000 $*.bit up 0x03000000 $*_fallback.bit} -checksum -file $*_full.mcs" > generate_full_mcs.tcl
echo "exit" >> generate_full_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_full_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*_full$$x rev/$*_full_rev$$COUNT$$x; \
echo "Output: rev/$*_full_rev$$COUNT$$x"; done;
flash: $(FPGA_TOP).mcs $(FPGA_TOP).prm
echo "open_hw_manager" > flash.tcl
echo "connect_hw_server" >> flash.tcl
echo "open_hw_target" >> flash.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> flash.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> flash.tcl
echo "create_hw_cfgmem -hw_device [current_hw_device] [lindex [get_cfgmem_parts {mt25ql512-spi-x1_x2_x4}] 0]" >> flash.tcl
echo "current_hw_cfgmem -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM [current_hw_device]]" >> flash.tcl
echo "set_property PROGRAM.FILES [list \"$(FPGA_TOP).mcs\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP).prm\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ERASE 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.VERIFY 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CHECKSUM 0 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ADDRESS_RANGE {use_file} [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [current_hw_cfgmem]" >> flash.tcl
echo "create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]]" >> flash.tcl
echo "program_hw_devices [current_hw_device]" >> flash.tcl
echo "refresh_hw_device [current_hw_device]" >> flash.tcl
echo "program_hw_cfgmem -hw_cfgmem [current_hw_cfgmem]" >> flash.tcl
echo "boot_hw_device [current_hw_device]" >> flash.tcl
echo "exit" >> flash.tcl
vivado -nojournal -nolog -mode batch -source flash.tcl
flash%: $(FPGA_TOP)%.mcs $(FPGA_TOP)%.prm
echo "open_hw_manager" > flash$*.tcl
echo "connect_hw_server" >> flash$*.tcl
echo "open_hw_target" >> flash$*.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> flash$*.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> flash$*.tcl
echo "create_hw_cfgmem -hw_device [current_hw_device] [lindex [get_cfgmem_parts {mt25ql512-spi-x1_x2_x4}] 0]" >> flash$*.tcl
echo "current_hw_cfgmem -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM [current_hw_device]]" >> flash$*.tcl
echo "set_property PROGRAM.FILES [list \"$(FPGA_TOP)$*.mcs\"] [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP)$*.prm\"] [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.ERASE 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.VERIFY 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.CHECKSUM 0 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.ADDRESS_RANGE {use_file} [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [current_hw_cfgmem]" >> flash$*.tcl
echo "create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]]" >> flash$*.tcl
echo "program_hw_devices [current_hw_device]" >> flash$*.tcl
echo "refresh_hw_device [current_hw_device]" >> flash$*.tcl
echo "program_hw_cfgmem -hw_cfgmem [current_hw_cfgmem]" >> flash$*.tcl
echo "boot_hw_device [current_hw_device]" >> flash$*.tcl
echo "exit" >> flash$*.tcl
vivado -nojournal -nolog -mode batch -source flash$*.tcl

View File

@@ -0,0 +1,22 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
set params [dict create]
# MAC configuration
dict set params CFG_LOW_LATENCY "1"
dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "64"
# apply parameters to top-level
set param_list {}
dict for {name value} $params {
lappend param_list $name=$value
}
set_property generic $param_list [get_filesets sources_1]

View File

@@ -19,7 +19,7 @@ TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
SYN_FILES = $(RTL_DIR)/fpga_nt200a02.sv
SYN_FILES += $(RTL_DIR)/fpga_core.sv
SYN_FILES += $(RTL_DIR)/../pll/si5340_i2c_init.sv
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_100g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/lss/rtl/taxi_i2c_master.sv
SYN_FILES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
@@ -29,13 +29,15 @@ SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
XDC_FILES += ../syn/NT200A02/fpga.xdc
XDC_FILES += ../syn/NT200A02/gpio.xdc
XDC_FILES += ../syn/NT200A02/qsfp.xdc
XDC_FILES += ../syn/NT200A02/eth_cmac.xdc
XDC_FILES += $(TAXI_SRC_DIR)/eth/syn/vivado/taxi_eth_mac_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/axis/syn/vivado/taxi_axis_async_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_reset.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl
# IP
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_322.tcl
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_100g_us_cmace4.tcl
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_100g_us_gty_322.tcl
# Configuration
CONFIG_TCL_FILES = config.tcl

View File

@@ -8,10 +8,10 @@
set params [dict create]
# 10G MAC configuration
# MAC configuration
dict set params CFG_LOW_LATENCY "1"
dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "64"
dict set params MAC_DATA_W "512"
# apply parameters to top-level
set param_list {}

View File

@@ -8,7 +8,7 @@
set params [dict create]
# 10G MAC configuration
# MAC configuration
dict set params CFG_LOW_LATENCY "1"
dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "32"

View File

@@ -0,0 +1,159 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# FPGA settings
FPGA_PART = xcvu5p-flva2104-2-e
FPGA_TOP = fpga
FPGA_ARCH = virtexuplus
RTL_DIR = ../rtl
LIB_DIR = ../lib
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
# Files for synthesis
SYN_FILES = $(RTL_DIR)/fpga_nt200a02.sv
SYN_FILES += $(RTL_DIR)/fpga_core.sv
SYN_FILES += $(RTL_DIR)/../pll/si5340_i2c_init.sv
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/lss/rtl/taxi_i2c_master.sv
SYN_FILES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
# XDC files
XDC_FILES += ../syn/NT200A02/fpga.xdc
XDC_FILES += ../syn/NT200A02/gpio.xdc
XDC_FILES += ../syn/NT200A02/qsfp.xdc
XDC_FILES += $(TAXI_SRC_DIR)/eth/syn/vivado/taxi_eth_mac_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/axis/syn/vivado/taxi_axis_async_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_reset.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl
# IP
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_322.tcl
# Configuration
CONFIG_TCL_FILES = config.tcl
include ../common/vivado.mk
%_fallback.bit: %.bit
echo "open_project $*.xpr" > generate_fallback_bit.tcl
echo "open_run impl_1" >> generate_fallback_bit.tcl
echo "startgroup" >> generate_fallback_bit.tcl
echo "set_property BITSTREAM.CONFIG.SPI_32BIT_ADDR NO [current_design]" >> generate_fallback_bit.tcl
echo "endgroup" >> generate_fallback_bit.tcl
echo "write_bitstream -verbose -force $*_fallback.bit" >> generate_fallback_bit.tcl
echo "undo" >> generate_fallback_bit.tcl
echo "exit" >> generate_fallback_bit.tcl
vivado -nojournal -nolog -mode batch -source generate_fallback_bit.tcl
mkdir -p rev
EXT=bit; COUNT=100; \
while [ -e rev/$*_rev$$COUNT.$$EXT ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
cp $@ rev/$*_fallback_rev$$COUNT.$$EXT; \
echo "Output: rev/$*_fallback_rev$$COUNT.$$EXT";
program: $(FPGA_TOP).bit
echo "open_hw_manager" > 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
%.mcs %.prm: %.bit
echo "write_cfgmem -force -format mcs -size 256 -interface SPIx4 -loadbit {up 0x00000000 $*.bit} -checksum -file $*.mcs" > generate_mcs.tcl
echo "exit" >> generate_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*$$x rev/$*_rev$$COUNT$$x; \
echo "Output: rev/$*_rev$$COUNT$$x"; done;
%_fallback.mcs %_fallback.prm: %_fallback.bit
echo "write_cfgmem -force -format mcs -size 256 -interface SPIx4 -loadbit {up 0x0C000000 $*_fallback.bit} -checksum -file $*_fallback.mcs" > generate_fallback_mcs.tcl
echo "exit" >> generate_fallback_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_fallback_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*_fallback$$x rev/$*_fallback_rev$$COUNT$$x; \
echo "Output: rev/$*_fallback_rev$$COUNT$$x"; done;
%_full.mcs %_full.prm: %_fallback.bit %.bit
echo "write_cfgmem -force -format mcs -size 256 -interface SPIx4 -loadbit {up 0x00000000 $*.bit up 0x0C000000 $*_fallback.bit} -checksum -file $*_full.mcs" > generate_full_mcs.tcl
echo "exit" >> generate_full_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_full_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*_full$$x rev/$*_full_rev$$COUNT$$x; \
echo "Output: rev/$*_full_rev$$COUNT$$x"; done;
flash: $(FPGA_TOP).mcs $(FPGA_TOP).prm
echo "open_hw_manager" > flash.tcl
echo "connect_hw_server" >> flash.tcl
echo "open_hw_target" >> flash.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> flash.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> flash.tcl
echo "create_hw_cfgmem -hw_device [current_hw_device] [lindex [get_cfgmem_parts {mt25qu02g-spi-x1_x2_x4}] 0]" >> flash.tcl
echo "current_hw_cfgmem -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM [current_hw_device]]" >> flash.tcl
echo "set_property PROGRAM.FILES [list \"$(FPGA_TOP).mcs\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP).prm\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ERASE 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.VERIFY 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CHECKSUM 0 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ADDRESS_RANGE {use_file} [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [current_hw_cfgmem]" >> flash.tcl
echo "create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]]" >> flash.tcl
echo "program_hw_devices [current_hw_device]" >> flash.tcl
echo "refresh_hw_device [current_hw_device]" >> flash.tcl
echo "program_hw_cfgmem -hw_cfgmem [current_hw_cfgmem]" >> flash.tcl
echo "boot_hw_device [current_hw_device]" >> flash.tcl
echo "exit" >> flash.tcl
vivado -nojournal -nolog -mode batch -source flash.tcl
flash%: $(FPGA_TOP)%.mcs $(FPGA_TOP)%.prm
echo "open_hw_manager" > flash$*.tcl
echo "connect_hw_server" >> flash$*.tcl
echo "open_hw_target" >> flash$*.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> flash$*.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> flash$*.tcl
echo "create_hw_cfgmem -hw_device [current_hw_device] [lindex [get_cfgmem_parts {mt25qu02g-spi-x1_x2_x4}] 0]" >> flash$*.tcl
echo "current_hw_cfgmem -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM [current_hw_device]]" >> flash$*.tcl
echo "set_property PROGRAM.FILES [list \"$(FPGA_TOP)$*.mcs\"] [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP)$*.prm\"] [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.ERASE 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.VERIFY 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.CHECKSUM 0 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.ADDRESS_RANGE {use_file} [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [current_hw_cfgmem]" >> flash$*.tcl
echo "create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]]" >> flash$*.tcl
echo "program_hw_devices [current_hw_device]" >> flash$*.tcl
echo "refresh_hw_device [current_hw_device]" >> flash$*.tcl
echo "program_hw_cfgmem -hw_cfgmem [current_hw_cfgmem]" >> flash$*.tcl
echo "boot_hw_device [current_hw_device]" >> flash$*.tcl
echo "exit" >> flash$*.tcl
vivado -nojournal -nolog -mode batch -source flash$*.tcl

View File

@@ -0,0 +1,22 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
set params [dict create]
# MAC configuration
dict set params CFG_LOW_LATENCY "1"
dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "64"
# apply parameters to top-level
set param_list {}
dict for {name value} $params {
lappend param_list $name=$value
}
set_property generic $param_list [get_filesets sources_1]

View File

@@ -28,11 +28,10 @@ module fpga_core #
parameter GTY_QUAD_CNT = PORT_CNT,
parameter GTY_CNT = GTY_QUAD_CNT*4,
parameter GTY_CLK_CNT = GTY_QUAD_CNT,
// 10G/25G MAC configuration
// MAC configuration
parameter logic CFG_LOW_LATENCY = 1'b1,
parameter logic COMBINED_MAC_PCS = 1'b1,
parameter MAC_DATA_W = 64
parameter MAC_DATA_W = 512
)
(
/*
@@ -79,30 +78,43 @@ assign eth_port_i2c_scl_o = '1;
assign eth_port_i2c_sda_o = '1;
// QSFP28
localparam MAC_CNT = MAC_DATA_W > 64 ? GTY_QUAD_CNT : GTY_CNT;
assign eth_port_resetl = '1;
assign eth_port_lpmode = '0;
wire eth_gty_tx_clk[GTY_CNT];
wire eth_gty_tx_rst[GTY_CNT];
taxi_axis_if #(.DATA_W(MAC_DATA_W), .ID_W(8), .USER_EN(1), .USER_W(1)) eth_gty_axis_tx[GTY_CNT]();
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) eth_gty_axis_tx_cpl[GTY_CNT]();
wire eth_gty_tx_clk[MAC_CNT];
wire eth_gty_tx_rst[MAC_CNT];
taxi_axis_if #(.DATA_W(MAC_DATA_W), .ID_W(8), .USER_EN(1), .USER_W(1)) eth_gty_axis_tx[MAC_CNT]();
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) eth_gty_axis_tx_cpl[MAC_CNT]();
wire eth_gty_rx_clk[GTY_CNT];
wire eth_gty_rx_rst[GTY_CNT];
taxi_axis_if #(.DATA_W(MAC_DATA_W), .ID_W(8), .USER_EN(1), .USER_W(1)) eth_gty_axis_rx[GTY_CNT]();
wire eth_gty_rx_clk[MAC_CNT];
wire eth_gty_rx_rst[MAC_CNT];
taxi_axis_if #(.DATA_W(MAC_DATA_W), .ID_W(8), .USER_EN(1), .USER_W(1)) eth_gty_axis_rx[MAC_CNT]();
taxi_axis_if #(.DATA_W(16), .KEEP_W(1), .KEEP_EN(0), .LAST_EN(0), .USER_EN(1), .USER_W(1), .ID_EN(1), .ID_W(10)) axis_eth_stat[GTY_QUAD_CNT]();
wire eth_gty_rx_status[GTY_CNT];
wire eth_gty_rx_status[MAC_CNT];
assign qsfp_led[0][0] = eth_gty_rx_status[0];
assign qsfp_led[0][1] = eth_gty_rx_status[1];
assign qsfp_led[0][2] = eth_gty_rx_status[2];
assign qsfp_led[0][3] = eth_gty_rx_status[3];
assign qsfp_led[1][0] = eth_gty_rx_status[4];
assign qsfp_led[1][1] = eth_gty_rx_status[5];
assign qsfp_led[1][2] = eth_gty_rx_status[6];
assign qsfp_led[1][3] = eth_gty_rx_status[7];
if (MAC_CNT == 2) begin
assign qsfp_led[0][0] = eth_gty_rx_status[0];
assign qsfp_led[0][1] = 1'b0;
assign qsfp_led[0][2] = 1'b0;
assign qsfp_led[0][3] = 1'b0;
assign qsfp_led[1][0] = eth_gty_rx_status[1];
assign qsfp_led[1][1] = 1'b0;
assign qsfp_led[1][2] = 1'b0;
assign qsfp_led[1][3] = 1'b0;
end else begin
assign qsfp_led[0][0] = eth_gty_rx_status[0];
assign qsfp_led[0][1] = eth_gty_rx_status[1];
assign qsfp_led[0][2] = eth_gty_rx_status[2];
assign qsfp_led[0][3] = eth_gty_rx_status[3];
assign qsfp_led[1][0] = eth_gty_rx_status[4];
assign qsfp_led[1][1] = eth_gty_rx_status[5];
assign qsfp_led[1][2] = eth_gty_rx_status[6];
assign qsfp_led[1][3] = eth_gty_rx_status[7];
end
wire [GTY_QUAD_CNT-1:0] eth_gty_gtpowergood;
@@ -173,6 +185,7 @@ localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP1[4] = '{"QSFP1.1", "QSFP1.2", "Q
for (genvar n = 0; n < GTY_QUAD_CNT; n = n + 1) begin : gt_quad
localparam CLK = n;
localparam CNT = 4;
taxi_apb_if #(
@@ -181,274 +194,515 @@ for (genvar n = 0; n < GTY_QUAD_CNT; n = n + 1) begin : gt_quad
)
gt_apb_ctrl();
taxi_eth_mac_25g_us #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
if (MAC_DATA_W == 512) begin: mac
.CNT(4),
taxi_eth_mac_100g_us #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
// GT config
.CFG_LOW_LATENCY(CFG_LOW_LATENCY),
.GT_CNT(CNT),
// GT type
.GT_TYPE("GTY"),
// GT config
.CFG_LOW_LATENCY(CFG_LOW_LATENCY),
// GT parameters
.GT_TX_POLARITY(n == 0 ? 4'b0101 : 4'b0001),
.GT_RX_POLARITY(n == 0 ? 4'b1011 : 4'b0011),
// GT type
.GT_TYPE("GTY"),
// MAC/PHY config
.COMBINED_MAC_PCS(COMBINED_MAC_PCS),
.DATA_W(eth_gty_axis_tx[0].DATA_W),
.USXGMII_EN(COMBINED_MAC_PCS),
.DIC_EN(1'b1),
.PTP_TS_EN(1'b0),
.PTP_TD_EN(1'b0),
.PTP_TS_FMT_TOD(1'b1),
.PTP_TS_W(96),
.PTP_TD_SDI_PIPELINE(2),
.PRBS31_EN(1'b0),
.TX_SERDES_PIPELINE(1),
.RX_SERDES_PIPELINE(1),
.COUNT_125US(125000/6.4),
.STAT_EN(0),
.STAT_TX_LEVEL(1),
.STAT_RX_LEVEL(1),
.STAT_ID_BASE(n*CNT*(16+16)),
.STAT_UPDATE_PERIOD(1024),
.STAT_STR_EN(0),
.STAT_PREFIX_STR(n == 0 ? STAT_PREFIX_STR_QSFP0 : STAT_PREFIX_STR_QSFP1)
)
mac_inst (
.xcvr_ctrl_clk(clk_125mhz),
.xcvr_ctrl_rst(eth_gty_rst[n]),
// GT parameters
.GT_TX_POLARITY(n == 0 ? 4'b0101 : 4'b0001),
.GT_RX_POLARITY(n == 0 ? 4'b1011 : 4'b0011),
/*
* Transceiver control
*/
.s_apb_ctrl(gt_apb_ctrl),
// MAC/PHY config
.PTP_TS_EN(1'b0),
.PTP_TD_EN(1'b0),
.PTP_TS_FMT_TOD(1'b1),
.PTP_TS_W(96),
.PTP_TD_SDI_PIPELINE(2),
.TX_SERDES_PIPELINE(1),
.RX_SERDES_PIPELINE(1),
.STAT_EN(0),
.STAT_TX_LEVEL(1),
.STAT_RX_LEVEL(1),
.STAT_ID_BASE(n*CNT*(16+16)),
.STAT_UPDATE_PERIOD(1024),
.STAT_STR_EN(0),
.STAT_PREFIX_STR(n == 0 ? "QSFP0" : "QSFP1")
)
mac_inst (
.xcvr_ctrl_clk(clk_125mhz),
.xcvr_ctrl_rst(eth_gty_rst[CLK]),
/*
* Common
*/
.xcvr_gtpowergood_out(eth_gty_gtpowergood[n]),
.xcvr_gtrefclk00_in(eth_gty_mgt_refclk[n]),
.xcvr_qpll0pd_in(1'b0),
.xcvr_qpll0reset_in(1'b0),
.xcvr_qpll0pcierate_in(3'd0),
.xcvr_qpll0lock_out(),
.xcvr_qpll0clk_out(),
.xcvr_qpll0refclk_out(),
.xcvr_gtrefclk01_in(eth_gty_mgt_refclk[n]),
.xcvr_qpll1pd_in(1'b0),
.xcvr_qpll1reset_in(1'b0),
.xcvr_qpll1pcierate_in(3'd0),
.xcvr_qpll1lock_out(),
.xcvr_qpll1clk_out(),
.xcvr_qpll1refclk_out(),
/*
* Transceiver control
*/
.s_apb_ctrl(gt_apb_ctrl),
/*
* Serial data
*/
.xcvr_txp(eth_gty_tx_p[n*CNT +: CNT]),
.xcvr_txn(eth_gty_tx_n[n*CNT +: CNT]),
.xcvr_rxp(eth_gty_rx_p[n*CNT +: CNT]),
.xcvr_rxn(eth_gty_rx_n[n*CNT +: CNT]),
/*
* Common
*/
.xcvr_gtpowergood_out(eth_gty_gtpowergood[n]),
.xcvr_gtrefclk00_in(eth_gty_mgt_refclk[CLK]),
.xcvr_qpll0pd_in(1'b0),
.xcvr_qpll0lock_out(),
.xcvr_qpll0clk_out(),
.xcvr_qpll0refclk_out(),
.xcvr_gtrefclk01_in(eth_gty_mgt_refclk[CLK]),
.xcvr_qpll1pd_in(1'b0),
.xcvr_qpll1lock_out(),
.xcvr_qpll1clk_out(),
.xcvr_qpll1refclk_out(),
/*
* MAC clocks
*/
.rx_clk(eth_gty_rx_clk[n*CNT +: CNT]),
.rx_rst_in('{CNT{1'b0}}),
.rx_rst_out(eth_gty_rx_rst[n*CNT +: CNT]),
.tx_clk(eth_gty_tx_clk[n*CNT +: CNT]),
.tx_rst_in('{CNT{1'b0}}),
.tx_rst_out(eth_gty_tx_rst[n*CNT +: CNT]),
/*
* Serial data
*/
.xcvr_txp(eth_gty_tx_p[n*CNT +: CNT]),
.xcvr_txn(eth_gty_tx_n[n*CNT +: CNT]),
.xcvr_rxp(eth_gty_rx_p[n*CNT +: CNT]),
.xcvr_rxn(eth_gty_rx_n[n*CNT +: CNT]),
/*
* Transmit interface (AXI stream)
*/
.s_axis_tx(eth_gty_axis_tx[n*CNT +: CNT]),
.m_axis_tx_cpl(eth_gty_axis_tx_cpl[n*CNT +: CNT]),
/*
* MAC clocks
*/
.rx_clk(eth_gty_rx_clk[n]),
.rx_rst_in(1'b0),
.rx_rst_out(eth_gty_rx_rst[n]),
.tx_clk(eth_gty_tx_clk[n]),
.tx_rst_in(1'b0),
.tx_rst_out(eth_gty_tx_rst[n]),
/*
* Receive interface (AXI stream)
*/
.m_axis_rx(eth_gty_axis_rx[n*CNT +: CNT]),
/*
* Transmit interface (AXI stream)
*/
.s_axis_tx(eth_gty_axis_tx[n]),
.m_axis_tx_cpl(eth_gty_axis_tx_cpl[n]),
/*
* USXGMII autonegotiation
*/
.an_en('{CNT{1'b1}}),
.an_restart('{CNT{1'b0}}),
.an_speedup('{CNT{1'b0}}),
.an_timeout_en('{CNT{1'b1}}),
.an_usxgmii_en('{CNT{1'b0}}),
.an_usxgmii_auto('{CNT{1'b1}}),
.an_intr(),
.an_running(),
.an_complete(),
.an_timeout(),
.an_usxgmii_mode(),
.an_adv_ability_usxgmii('{CNT{16'h1601}}),
.an_lp_adv_ability(),
.an_lp_usxgmii_link(),
.an_lp_usxgmii_speed(),
.an_res_full_duplex(),
/*
* Receive interface (AXI stream)
*/
.m_axis_rx(eth_gty_axis_rx[n]),
/*
* PTP clock
*/
.ptp_clk(1'b0),
.ptp_rst(1'b0),
.ptp_sample_clk(1'b0),
.ptp_td_sdi(1'b0),
.tx_ptp_ts_in('{CNT{'0}}),
.tx_ptp_ts_out(),
.tx_ptp_ts_step_out(),
.tx_ptp_locked(),
.rx_ptp_ts_in('{CNT{'0}}),
.rx_ptp_ts_out(),
.rx_ptp_ts_step_out(),
.rx_ptp_locked(),
/*
* PTP clock
*/
.ptp_clk(1'b0),
.ptp_rst(1'b0),
.ptp_sample_clk(1'b0),
.ptp_td_sdi(1'b0),
.tx_ptp_ts_in('0),
.tx_ptp_ts_out(),
.tx_ptp_ts_step_out(),
.tx_ptp_locked(),
.rx_ptp_ts_in('0),
.rx_ptp_ts_out(),
.rx_ptp_ts_step_out(),
.rx_ptp_locked(),
/*
* Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE)
*/
.tx_lfc_req('{CNT{1'b0}}),
.tx_lfc_resend('{CNT{1'b0}}),
.rx_lfc_en('{CNT{1'b0}}),
.rx_lfc_req(),
.rx_lfc_ack('{CNT{1'b0}}),
/*
* Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE)
*/
.tx_lfc_req(1'b0),
.tx_lfc_resend(1'b0),
.rx_lfc_en(1'b0),
.rx_lfc_req(),
.rx_lfc_ack(1'b0),
/*
* Priority Flow Control (PFC) (IEEE 802.3 annex 31D PFC)
*/
.tx_pfc_req('{CNT{'0}}),
.tx_pfc_resend('{CNT{1'b0}}),
.rx_pfc_en('{CNT{'0}}),
.rx_pfc_req(),
.rx_pfc_ack('{CNT{'0}}),
/*
* Priority Flow Control (PFC) (IEEE 802.3 annex 31D PFC)
*/
.tx_pfc_req('0),
.tx_pfc_resend(1'b0),
.rx_pfc_en('0),
.rx_pfc_req(),
.rx_pfc_ack('0),
/*
* Pause interface
*/
.tx_lfc_pause_en('{CNT{1'b0}}),
.tx_pause_req('{CNT{1'b0}}),
.tx_pause_ack(),
/*
* Pause interface
*/
.tx_lfc_pause_en(1'b0),
.tx_pause_req(1'b0),
.tx_pause_ack(),
/*
* Statistics
*/
.stat_clk(clk_125mhz),
.stat_rst(rst_125mhz),
.m_axis_stat(axis_eth_stat[n]),
/*
* Statistics
*/
.stat_clk(clk_125mhz),
.stat_rst(rst_125mhz),
.m_axis_stat(axis_eth_stat[n]),
/*
* Status
*/
.tx_start_packet(),
.stat_tx_byte(),
.stat_tx_pkt_len(),
.stat_tx_pkt_ucast(),
.stat_tx_pkt_mcast(),
.stat_tx_pkt_bcast(),
.stat_tx_pkt_vlan(),
.stat_tx_pkt_good(),
.stat_tx_pkt_bad(),
.stat_tx_pad_frame(),
.stat_tx_err_oversize(),
.stat_tx_err_user(),
.stat_tx_err_underflow(),
.rx_start_packet(),
.rx_error_count(),
.rx_block_lock(),
.rx_high_ber(),
.rx_status(eth_gty_rx_status[n*CNT +: CNT]),
.stat_rx_byte(),
.stat_rx_pkt_len(),
.stat_rx_pkt_fragment(),
.stat_rx_pkt_jabber(),
.stat_rx_pkt_ucast(),
.stat_rx_pkt_mcast(),
.stat_rx_pkt_bcast(),
.stat_rx_pkt_vlan(),
.stat_rx_pkt_good(),
.stat_rx_pkt_bad(),
.stat_rx_err_oversize(),
.stat_rx_err_bad_fcs(),
.stat_rx_err_bad_block(),
.stat_rx_err_framing(),
.stat_rx_err_preamble(),
.stat_rx_fifo_drop('{CNT{1'b0}}),
.stat_tx_mcf(),
.stat_rx_mcf(),
.stat_tx_lfc_pkt(),
.stat_tx_lfc_xon(),
.stat_tx_lfc_xoff(),
.stat_tx_lfc_paused(),
.stat_tx_pfc_pkt(),
.stat_tx_pfc_xon(),
.stat_tx_pfc_xoff(),
.stat_tx_pfc_paused(),
.stat_rx_lfc_pkt(),
.stat_rx_lfc_xon(),
.stat_rx_lfc_xoff(),
.stat_rx_lfc_paused(),
.stat_rx_pfc_pkt(),
.stat_rx_pfc_xon(),
.stat_rx_pfc_xoff(),
.stat_rx_pfc_paused(),
/*
* Status
*/
.tx_start_packet(),
.stat_tx_byte(),
.stat_tx_pkt_len(),
.stat_tx_pkt_ucast(),
.stat_tx_pkt_mcast(),
.stat_tx_pkt_bcast(),
.stat_tx_pkt_vlan(),
.stat_tx_pkt_good(),
.stat_tx_pkt_bad(),
.stat_tx_pad_frame(),
.stat_tx_err_oversize(),
.stat_tx_err_user(),
.stat_tx_err_underflow(),
.rx_start_packet(),
.rx_error_count(),
.rx_block_lock(),
.rx_high_ber(),
.rx_status(eth_gty_rx_status[n]),
.stat_rx_byte(),
.stat_rx_pkt_len(),
.stat_rx_pkt_fragment(),
.stat_rx_pkt_jabber(),
.stat_rx_pkt_ucast(),
.stat_rx_pkt_mcast(),
.stat_rx_pkt_bcast(),
.stat_rx_pkt_vlan(),
.stat_rx_pkt_good(),
.stat_rx_pkt_bad(),
.stat_rx_err_oversize(),
.stat_rx_err_bad_fcs(),
.stat_rx_err_bad_block(),
.stat_rx_err_framing(),
.stat_rx_err_preamble(),
.stat_rx_fifo_drop(1'b0),
.stat_tx_mcf(),
.stat_rx_mcf(),
.stat_tx_lfc_pkt(),
.stat_tx_lfc_xon(),
.stat_tx_lfc_xoff(),
.stat_tx_lfc_paused(),
.stat_tx_pfc_pkt(),
.stat_tx_pfc_xon(),
.stat_tx_pfc_xoff(),
.stat_tx_pfc_paused(),
.stat_rx_lfc_pkt(),
.stat_rx_lfc_xon(),
.stat_rx_lfc_xoff(),
.stat_rx_lfc_paused(),
.stat_rx_pfc_pkt(),
.stat_rx_pfc_xon(),
.stat_rx_pfc_xoff(),
.stat_rx_pfc_paused(),
/*
* Configuration
*/
.cfg_tx_pad_en('{CNT{1'b1}}),
.cfg_tx_min_pkt_len('{CNT{8'd60-1}}),
.cfg_tx_max_pkt_len('{CNT{16'd9218-1}}),
.cfg_tx_ifg('{CNT{8'd12}}),
.cfg_tx_enable('{CNT{1'b1}}),
.cfg_rx_max_pkt_len('{CNT{16'd9218-1}}),
.cfg_rx_enable('{CNT{1'b1}}),
.cfg_tx_prbs31_enable('{CNT{1'b0}}),
.cfg_rx_prbs31_enable('{CNT{1'b0}}),
.cfg_mcf_rx_eth_dst_mcast('{CNT{48'h01_80_C2_00_00_01}}),
.cfg_mcf_rx_check_eth_dst_mcast('{CNT{1'b1}}),
.cfg_mcf_rx_eth_dst_ucast('{CNT{48'd0}}),
.cfg_mcf_rx_check_eth_dst_ucast('{CNT{1'b0}}),
.cfg_mcf_rx_eth_src('{CNT{48'd0}}),
.cfg_mcf_rx_check_eth_src('{CNT{1'b0}}),
.cfg_mcf_rx_eth_type('{CNT{16'h8808}}),
.cfg_mcf_rx_opcode_lfc('{CNT{16'h0001}}),
.cfg_mcf_rx_check_opcode_lfc('{CNT{1'b1}}),
.cfg_mcf_rx_opcode_pfc('{CNT{16'h0101}}),
.cfg_mcf_rx_check_opcode_pfc('{CNT{1'b1}}),
.cfg_mcf_rx_forward('{CNT{1'b0}}),
.cfg_mcf_rx_enable('{CNT{1'b0}}),
.cfg_tx_lfc_eth_dst('{CNT{48'h01_80_C2_00_00_01}}),
.cfg_tx_lfc_eth_src('{CNT{48'h80_23_31_43_54_4C}}),
.cfg_tx_lfc_eth_type('{CNT{16'h8808}}),
.cfg_tx_lfc_opcode('{CNT{16'h0001}}),
.cfg_tx_lfc_en('{CNT{1'b0}}),
.cfg_tx_lfc_quanta('{CNT{16'hffff}}),
.cfg_tx_lfc_refresh('{CNT{16'h7fff}}),
.cfg_tx_pfc_eth_dst('{CNT{48'h01_80_C2_00_00_01}}),
.cfg_tx_pfc_eth_src('{CNT{48'h80_23_31_43_54_4C}}),
.cfg_tx_pfc_eth_type('{CNT{16'h8808}}),
.cfg_tx_pfc_opcode('{CNT{16'h0101}}),
.cfg_tx_pfc_en('{CNT{1'b0}}),
.cfg_tx_pfc_quanta('{CNT{'{8{16'hffff}}}}),
.cfg_tx_pfc_refresh('{CNT{'{8{16'h7fff}}}}),
.cfg_rx_lfc_opcode('{CNT{16'h0001}}),
.cfg_rx_lfc_en('{CNT{1'b0}}),
.cfg_rx_pfc_opcode('{CNT{16'h0101}}),
.cfg_rx_pfc_en('{CNT{1'b0}})
);
/*
* Configuration
*/
.cfg_tx_pad_en(1'b1),
.cfg_tx_min_pkt_len(8'd60-1),
.cfg_tx_max_pkt_len(16'd9218-1),
.cfg_tx_ifg(8'd12),
.cfg_tx_enable(1'b1),
.cfg_rx_max_pkt_len(16'd9218-1),
.cfg_rx_enable(1'b1),
.cfg_tx_prbs31_enable(1'b0),
.cfg_rx_prbs31_enable(1'b0),
.cfg_mcf_rx_eth_dst_mcast(48'h01_80_C2_00_00_01),
.cfg_mcf_rx_check_eth_dst_mcast(1'b1),
.cfg_mcf_rx_eth_dst_ucast(48'd0),
.cfg_mcf_rx_check_eth_dst_ucast(1'b0),
.cfg_mcf_rx_eth_src(48'd0),
.cfg_mcf_rx_check_eth_src(1'b0),
.cfg_mcf_rx_eth_type(16'h8808),
.cfg_mcf_rx_opcode_lfc(16'h0001),
.cfg_mcf_rx_check_opcode_lfc(1'b1),
.cfg_mcf_rx_opcode_pfc(16'h0101),
.cfg_mcf_rx_check_opcode_pfc(1'b1),
.cfg_mcf_rx_forward(1'b0),
.cfg_mcf_rx_enable(1'b0),
.cfg_tx_lfc_eth_dst(48'h01_80_C2_00_00_01),
.cfg_tx_lfc_eth_src(48'h80_23_31_43_54_4C),
.cfg_tx_lfc_eth_type(16'h8808),
.cfg_tx_lfc_opcode(16'h0001),
.cfg_tx_lfc_en(1'b0),
.cfg_tx_lfc_quanta(16'hffff),
.cfg_tx_lfc_refresh(16'h7fff),
.cfg_tx_pfc_eth_dst(48'h01_80_C2_00_00_01),
.cfg_tx_pfc_eth_src(48'h80_23_31_43_54_4C),
.cfg_tx_pfc_eth_type(16'h8808),
.cfg_tx_pfc_opcode(16'h0101),
.cfg_tx_pfc_en(1'b0),
.cfg_tx_pfc_quanta('{8{16'hffff}}),
.cfg_tx_pfc_refresh('{8{16'h7fff}}),
.cfg_rx_lfc_opcode(16'h0001),
.cfg_rx_lfc_en(1'b0),
.cfg_rx_pfc_opcode(16'h0101),
.cfg_rx_pfc_en(1'b0)
);
end else begin: mac
taxi_eth_mac_25g_us #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
.CNT(CNT),
// GT config
.CFG_LOW_LATENCY(CFG_LOW_LATENCY),
// GT type
.GT_TYPE("GTY"),
// GT parameters
.GT_TX_POLARITY(n == 0 ? 4'b0101 : 4'b0001),
.GT_RX_POLARITY(n == 0 ? 4'b1011 : 4'b0011),
// MAC/PHY config
.COMBINED_MAC_PCS(COMBINED_MAC_PCS),
.DATA_W(eth_gty_axis_tx[0].DATA_W),
.USXGMII_EN(COMBINED_MAC_PCS),
.DIC_EN(1'b1),
.PTP_TS_EN(1'b0),
.PTP_TD_EN(1'b0),
.PTP_TS_FMT_TOD(1'b1),
.PTP_TS_W(96),
.PTP_TD_SDI_PIPELINE(2),
.PRBS31_EN(1'b0),
.TX_SERDES_PIPELINE(1),
.RX_SERDES_PIPELINE(1),
.COUNT_125US(125000/6.4),
.STAT_EN(0),
.STAT_TX_LEVEL(1),
.STAT_RX_LEVEL(1),
.STAT_ID_BASE(n*CNT*(16+16)),
.STAT_UPDATE_PERIOD(1024),
.STAT_STR_EN(0),
.STAT_PREFIX_STR(n == 0 ? STAT_PREFIX_STR_QSFP0 : STAT_PREFIX_STR_QSFP1)
)
mac_inst (
.xcvr_ctrl_clk(clk_125mhz),
.xcvr_ctrl_rst(eth_gty_rst[CLK]),
/*
* Transceiver control
*/
.s_apb_ctrl(gt_apb_ctrl),
/*
* Common
*/
.xcvr_gtpowergood_out(eth_gty_gtpowergood[n]),
.xcvr_gtrefclk00_in(eth_gty_mgt_refclk[CLK]),
.xcvr_qpll0pd_in(1'b0),
.xcvr_qpll0reset_in(1'b0),
.xcvr_qpll0pcierate_in(3'd0),
.xcvr_qpll0lock_out(),
.xcvr_qpll0clk_out(),
.xcvr_qpll0refclk_out(),
.xcvr_gtrefclk01_in(eth_gty_mgt_refclk[CLK]),
.xcvr_qpll1pd_in(1'b0),
.xcvr_qpll1reset_in(1'b0),
.xcvr_qpll1pcierate_in(3'd0),
.xcvr_qpll1lock_out(),
.xcvr_qpll1clk_out(),
.xcvr_qpll1refclk_out(),
/*
* Serial data
*/
.xcvr_txp(eth_gty_tx_p[n*CNT +: CNT]),
.xcvr_txn(eth_gty_tx_n[n*CNT +: CNT]),
.xcvr_rxp(eth_gty_rx_p[n*CNT +: CNT]),
.xcvr_rxn(eth_gty_rx_n[n*CNT +: CNT]),
/*
* MAC clocks
*/
.rx_clk(eth_gty_rx_clk[n*CNT +: CNT]),
.rx_rst_in('{CNT{1'b0}}),
.rx_rst_out(eth_gty_rx_rst[n*CNT +: CNT]),
.tx_clk(eth_gty_tx_clk[n*CNT +: CNT]),
.tx_rst_in('{CNT{1'b0}}),
.tx_rst_out(eth_gty_tx_rst[n*CNT +: CNT]),
/*
* Transmit interface (AXI stream)
*/
.s_axis_tx(eth_gty_axis_tx[n*CNT +: CNT]),
.m_axis_tx_cpl(eth_gty_axis_tx_cpl[n*CNT +: CNT]),
/*
* Receive interface (AXI stream)
*/
.m_axis_rx(eth_gty_axis_rx[n*CNT +: CNT]),
/*
* USXGMII autonegotiation
*/
.an_en('{CNT{1'b1}}),
.an_restart('{CNT{1'b0}}),
.an_speedup('{CNT{1'b0}}),
.an_timeout_en('{CNT{1'b1}}),
.an_usxgmii_en('{CNT{1'b0}}),
.an_usxgmii_auto('{CNT{1'b1}}),
.an_intr(),
.an_running(),
.an_complete(),
.an_timeout(),
.an_usxgmii_mode(),
.an_adv_ability_usxgmii('{CNT{16'h1601}}),
.an_lp_adv_ability(),
.an_lp_usxgmii_link(),
.an_lp_usxgmii_speed(),
.an_res_full_duplex(),
/*
* PTP clock
*/
.ptp_clk(1'b0),
.ptp_rst(1'b0),
.ptp_sample_clk(1'b0),
.ptp_td_sdi(1'b0),
.tx_ptp_ts_in('{CNT{'0}}),
.tx_ptp_ts_out(),
.tx_ptp_ts_step_out(),
.tx_ptp_locked(),
.rx_ptp_ts_in('{CNT{'0}}),
.rx_ptp_ts_out(),
.rx_ptp_ts_step_out(),
.rx_ptp_locked(),
/*
* Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE)
*/
.tx_lfc_req('{CNT{1'b0}}),
.tx_lfc_resend('{CNT{1'b0}}),
.rx_lfc_en('{CNT{1'b0}}),
.rx_lfc_req(),
.rx_lfc_ack('{CNT{1'b0}}),
/*
* Priority Flow Control (PFC) (IEEE 802.3 annex 31D PFC)
*/
.tx_pfc_req('{CNT{'0}}),
.tx_pfc_resend('{CNT{1'b0}}),
.rx_pfc_en('{CNT{'0}}),
.rx_pfc_req(),
.rx_pfc_ack('{CNT{'0}}),
/*
* Pause interface
*/
.tx_lfc_pause_en('{CNT{1'b0}}),
.tx_pause_req('{CNT{1'b0}}),
.tx_pause_ack(),
/*
* Statistics
*/
.stat_clk(clk_125mhz),
.stat_rst(rst_125mhz),
.m_axis_stat(axis_eth_stat[n]),
/*
* Status
*/
.tx_start_packet(),
.stat_tx_byte(),
.stat_tx_pkt_len(),
.stat_tx_pkt_ucast(),
.stat_tx_pkt_mcast(),
.stat_tx_pkt_bcast(),
.stat_tx_pkt_vlan(),
.stat_tx_pkt_good(),
.stat_tx_pkt_bad(),
.stat_tx_pad_frame(),
.stat_tx_err_oversize(),
.stat_tx_err_user(),
.stat_tx_err_underflow(),
.rx_start_packet(),
.rx_error_count(),
.rx_block_lock(),
.rx_high_ber(),
.rx_status(eth_gty_rx_status[n*CNT +: CNT]),
.stat_rx_byte(),
.stat_rx_pkt_len(),
.stat_rx_pkt_fragment(),
.stat_rx_pkt_jabber(),
.stat_rx_pkt_ucast(),
.stat_rx_pkt_mcast(),
.stat_rx_pkt_bcast(),
.stat_rx_pkt_vlan(),
.stat_rx_pkt_good(),
.stat_rx_pkt_bad(),
.stat_rx_err_oversize(),
.stat_rx_err_bad_fcs(),
.stat_rx_err_bad_block(),
.stat_rx_err_framing(),
.stat_rx_err_preamble(),
.stat_rx_fifo_drop('{CNT{1'b0}}),
.stat_tx_mcf(),
.stat_rx_mcf(),
.stat_tx_lfc_pkt(),
.stat_tx_lfc_xon(),
.stat_tx_lfc_xoff(),
.stat_tx_lfc_paused(),
.stat_tx_pfc_pkt(),
.stat_tx_pfc_xon(),
.stat_tx_pfc_xoff(),
.stat_tx_pfc_paused(),
.stat_rx_lfc_pkt(),
.stat_rx_lfc_xon(),
.stat_rx_lfc_xoff(),
.stat_rx_lfc_paused(),
.stat_rx_pfc_pkt(),
.stat_rx_pfc_xon(),
.stat_rx_pfc_xoff(),
.stat_rx_pfc_paused(),
/*
* Configuration
*/
.cfg_tx_pad_en('{CNT{1'b1}}),
.cfg_tx_min_pkt_len('{CNT{8'd60-1}}),
.cfg_tx_max_pkt_len('{CNT{16'd9218-1}}),
.cfg_tx_ifg('{CNT{8'd12}}),
.cfg_tx_enable('{CNT{1'b1}}),
.cfg_rx_max_pkt_len('{CNT{16'd9218-1}}),
.cfg_rx_enable('{CNT{1'b1}}),
.cfg_tx_prbs31_enable('{CNT{1'b0}}),
.cfg_rx_prbs31_enable('{CNT{1'b0}}),
.cfg_mcf_rx_eth_dst_mcast('{CNT{48'h01_80_C2_00_00_01}}),
.cfg_mcf_rx_check_eth_dst_mcast('{CNT{1'b1}}),
.cfg_mcf_rx_eth_dst_ucast('{CNT{48'd0}}),
.cfg_mcf_rx_check_eth_dst_ucast('{CNT{1'b0}}),
.cfg_mcf_rx_eth_src('{CNT{48'd0}}),
.cfg_mcf_rx_check_eth_src('{CNT{1'b0}}),
.cfg_mcf_rx_eth_type('{CNT{16'h8808}}),
.cfg_mcf_rx_opcode_lfc('{CNT{16'h0001}}),
.cfg_mcf_rx_check_opcode_lfc('{CNT{1'b1}}),
.cfg_mcf_rx_opcode_pfc('{CNT{16'h0101}}),
.cfg_mcf_rx_check_opcode_pfc('{CNT{1'b1}}),
.cfg_mcf_rx_forward('{CNT{1'b0}}),
.cfg_mcf_rx_enable('{CNT{1'b0}}),
.cfg_tx_lfc_eth_dst('{CNT{48'h01_80_C2_00_00_01}}),
.cfg_tx_lfc_eth_src('{CNT{48'h80_23_31_43_54_4C}}),
.cfg_tx_lfc_eth_type('{CNT{16'h8808}}),
.cfg_tx_lfc_opcode('{CNT{16'h0001}}),
.cfg_tx_lfc_en('{CNT{1'b0}}),
.cfg_tx_lfc_quanta('{CNT{16'hffff}}),
.cfg_tx_lfc_refresh('{CNT{16'h7fff}}),
.cfg_tx_pfc_eth_dst('{CNT{48'h01_80_C2_00_00_01}}),
.cfg_tx_pfc_eth_src('{CNT{48'h80_23_31_43_54_4C}}),
.cfg_tx_pfc_eth_type('{CNT{16'h8808}}),
.cfg_tx_pfc_opcode('{CNT{16'h0101}}),
.cfg_tx_pfc_en('{CNT{1'b0}}),
.cfg_tx_pfc_quanta('{CNT{'{8{16'hffff}}}}),
.cfg_tx_pfc_refresh('{CNT{'{8{16'h7fff}}}}),
.cfg_rx_lfc_opcode('{CNT{16'h0001}}),
.cfg_rx_lfc_en('{CNT{1'b0}}),
.cfg_rx_pfc_opcode('{CNT{16'h0101}}),
.cfg_rx_pfc_en('{CNT{1'b0}})
);
end
end
for (genvar n = 0; n < GTY_CNT; n = n + 1) begin : qsfp_ch
for (genvar n = 0; n < $size(eth_gty_axis_tx); n = n + 1) begin : gty_ch
taxi_axis_async_fifo #(
.DEPTH(16384),

View File

@@ -23,10 +23,10 @@ module fpga #
parameter string VENDOR = "XILINX",
// device family
parameter string FAMILY = "virtexu",
// 10G/25G MAC configuration
// MAC configuration
parameter logic CFG_LOW_LATENCY = 1'b1,
parameter logic COMBINED_MAC_PCS = 1'b1,
parameter MAC_DATA_W = 64
parameter MAC_DATA_W = 512
)
(
/*

View File

@@ -23,10 +23,10 @@ module fpga #
parameter string VENDOR = "XILINX",
// device family
parameter string FAMILY = "virtexuplus",
// 10G/25G MAC configuration
// MAC configuration
parameter logic CFG_LOW_LATENCY = 1'b1,
parameter logic COMBINED_MAC_PCS = 1'b1,
parameter MAC_DATA_W = 64
parameter MAC_DATA_W = 512
)
(
/*

View File

@@ -0,0 +1,4 @@
# CMACs
set_property LOC CMAC_SITE_X0Y2 [get_cells -hierarchical -filter {NAME =~ core_inst/gt_quad[0].mac.* && REF_NAME==CMAC}]
set_property LOC CMAC_SITE_X0Y3 [get_cells -hierarchical -filter {NAME =~ core_inst/gt_quad[1].mac.* && REF_NAME==CMAC}]

View File

@@ -0,0 +1,4 @@
# CMACs
set_property LOC CMACE4_X0Y4 [get_cells -hierarchical -filter {NAME =~ core_inst/gt_quad[0].mac.* && REF_NAME==CMACE4}]
set_property LOC CMACE4_X0Y5 [get_cells -hierarchical -filter {NAME =~ core_inst/gt_quad[1].mac.* && REF_NAME==CMACE4}]

View File

@@ -1,6 +1,6 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2020-2026 FPGA Ninja, LLC
# Copyright (c) 2020-2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
@@ -24,6 +24,7 @@ MODULE = $(COCOTB_TEST_MODULES)
TOPLEVEL = $(COCOTB_TOPLEVEL)
VERILOG_SOURCES += $(RTL_DIR)/$(DUT).sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_100g_us.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
@@ -44,7 +45,7 @@ export PARAM_GTY_CNT := $(shell echo $$(( 4 * $(PARAM_GTY_QUAD_CNT) )))
export PARAM_GTY_CLK_CNT := $(PARAM_GTY_QUAD_CNT)
export PARAM_CFG_LOW_LATENCY := "1'b1"
export PARAM_COMBINED_MAC_PCS := "1'b1"
export PARAM_MAC_DATA_W := "64"
export PARAM_MAC_DATA_W := "512"
ifeq ($(SIM), icarus)
PLUSARGS += -fst

View File

@@ -9,7 +9,6 @@ Authors:
"""
import itertools
import logging
import os
import sys
@@ -21,7 +20,10 @@ import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, Combine
from cocotbext.eth import EthMacFrame, EthMac
from cocotbext.eth import GmiiFrame
from cocotbext.eth import XgmiiFrame
from cocotbext.axi import AxiStreamBus
try:
from baser import BaseRSerdesSource, BaseRSerdesSink
@@ -49,47 +51,78 @@ class TB:
for clk in dut.eth_gty_mgt_refclk_p:
cocotb.start_soon(Clock(clk, 3.102, units="ns").start())
for ch in itertools.chain.from_iterable([inst.mac_inst.ch for inst in dut.gt_quad]):
gt_inst = ch.ch_inst.gt.gt_inst
has_cmac = False
if ch.ch_inst.DATA_W.value == 64:
if ch.ch_inst.CFG_LOW_LATENCY.value:
clk = 2.482
gbx_cfg = (66, [64, 65])
else:
clk = 2.56
gbx_cfg = None
else:
if ch.ch_inst.CFG_LOW_LATENCY.value:
for quad in dut.gt_quad:
if dut.MAC_DATA_W.value == 512:
inst = quad.mac.mac_inst
has_cmac = True
mac = EthMac(
tx_clk=inst.ch[0].ch_inst.gt.gt_inst.gt_txoutclk,
tx_rst=inst.tx_rst_out,
tx_bus=AxiStreamBus.from_entity(inst.cmac.cmac_axis_tx),
# tx_ptp_time=inst.tx_ptp_ts_out,
# tx_ptp_ts=inst.tx_ptp_ts,
# tx_ptp_ts_tag=inst.tx_ptp_ts_tag,
# tx_ptp_ts_valid=inst.tx_ptp_ts_valid,
rx_clk=inst.ch[0].ch_inst.gt.gt_inst.gt_rxoutclk,
rx_rst=inst.rx_rst_out,
rx_bus=AxiStreamBus.from_entity(inst.cmac.cmac_axis_rx),
# rx_ptp_time=inst.rx_ptp_ts_out,
ifg=12, speed=100e9
)
self.qsfp_sources.append(mac.rx)
self.qsfp_sinks.append(mac.tx)
for ch in quad.mac.mac_inst.ch:
gt_inst = ch.ch_inst.gt.gt_inst
if has_cmac:
clk = 3.102
gbx_cfg = (66, [64, 65])
cocotb.start_soon(Clock(gt_inst.gt_txoutclk, clk, units="ns").start())
cocotb.start_soon(Clock(gt_inst.gt_rxoutclk, clk, units="ns").start())
continue
elif ch.ch_inst.DATA_W.value == 64:
if ch.ch_inst.CFG_LOW_LATENCY.value:
clk = 2.482
gbx_cfg = (66, [64, 65])
else:
clk = 2.56
gbx_cfg = None
else:
clk = 3.2
gbx_cfg = None
if ch.ch_inst.CFG_LOW_LATENCY.value:
clk = 3.102
gbx_cfg = (66, [64, 65])
else:
clk = 3.2
gbx_cfg = None
cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start())
cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start())
cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start())
cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start())
self.qsfp_sources.append(BaseRSerdesSource(
data=gt_inst.serdes_rx_data,
data_valid=gt_inst.serdes_rx_data_valid,
hdr=gt_inst.serdes_rx_hdr,
hdr_valid=gt_inst.serdes_rx_hdr_valid,
clock=gt_inst.rx_clk,
slip=gt_inst.serdes_rx_bitslip,
reverse=True,
gbx_cfg=gbx_cfg
))
self.qsfp_sinks.append(BaseRSerdesSink(
data=gt_inst.serdes_tx_data,
data_valid=gt_inst.serdes_tx_data_valid,
hdr=gt_inst.serdes_tx_hdr,
hdr_valid=gt_inst.serdes_tx_hdr_valid,
gbx_sync=gt_inst.serdes_tx_gbx_sync,
clock=gt_inst.tx_clk,
reverse=True,
gbx_cfg=gbx_cfg
))
self.qsfp_sources.append(BaseRSerdesSource(
data=gt_inst.serdes_rx_data,
data_valid=gt_inst.serdes_rx_data_valid,
hdr=gt_inst.serdes_rx_hdr,
hdr_valid=gt_inst.serdes_rx_hdr_valid,
clock=gt_inst.rx_clk,
slip=gt_inst.serdes_rx_bitslip,
reverse=True,
gbx_cfg=gbx_cfg
))
self.qsfp_sinks.append(BaseRSerdesSink(
data=gt_inst.serdes_tx_data,
data_valid=gt_inst.serdes_tx_data_valid,
hdr=gt_inst.serdes_tx_hdr,
hdr_valid=gt_inst.serdes_tx_hdr_valid,
gbx_sync=gt_inst.serdes_tx_gbx_sync,
clock=gt_inst.tx_clk,
reverse=True,
gbx_cfg=gbx_cfg
))
async def init(self):
@@ -109,13 +142,9 @@ class TB:
await RisingEdge(self.dut.clk_125mhz)
async def mac_test(tb, source, sink):
async def mac_test(tb, source, sink, frame_type=GmiiFrame):
tb.log.info("Test MAC")
tb.log.info("Wait for block lock")
for k in range(1200):
await RisingEdge(tb.dut.clk_125mhz)
sink.clear()
tb.log.info("Multiple small packets")
@@ -125,7 +154,7 @@ async def mac_test(tb, source, sink):
pkts = [bytearray([(x+k) % 256 for x in range(60)]) for k in range(count)]
for p in pkts:
await source.send(XgmiiFrame.from_payload(p))
await source.send(frame_type.from_payload(p))
for k in range(count):
rx_frame = await sink.recv()
@@ -142,7 +171,7 @@ async def mac_test(tb, source, sink):
pkts = [bytearray([(x+k) % 256 for x in range(1514)]) for k in range(count)]
for p in pkts:
await source.send(XgmiiFrame.from_payload(p))
await source.send(frame_type.from_payload(p))
for k in range(count):
rx_frame = await sink.recv()
@@ -164,12 +193,18 @@ async def run_test(dut):
tests = []
tb.log.info("Start BASE-T MAC loopback test")
tb.log.info("Wait for block lock")
for k in range(1200):
await RisingEdge(dut.clk_125mhz)
ft = XgmiiFrame
if dut.MAC_DATA_W.value == 512:
ft = EthMacFrame
for k in range(len(tb.qsfp_sources)):
tb.log.info("Start QSFP %d MAC loopback test", k)
tests.append(cocotb.start_soon(mac_test(tb, tb.qsfp_sources[k], tb.qsfp_sinks[k])))
tests.append(cocotb.start_soon(mac_test(tb, tb.qsfp_sources[k], tb.qsfp_sinks[k], ft)))
await Combine(*tests)
@@ -198,7 +233,7 @@ def process_f_files(files):
return list(lst.values())
@pytest.mark.parametrize("mac_data_w", [32, 64])
@pytest.mark.parametrize("mac_data_w", [32, 64, 512])
def test_fpga_core(request, mac_data_w):
dut = "fpga_core"
module = os.path.splitext(os.path.basename(__file__))[0]
@@ -207,6 +242,7 @@ def test_fpga_core(request, mac_data_w):
verilog_sources = [
os.path.join(rtl_dir, f"{dut}.sv"),
os.path.join(taxi_src_dir, "eth", "rtl", "us", "taxi_eth_mac_25g_us.f"),
os.path.join(taxi_src_dir, "eth", "rtl", "us", "taxi_eth_mac_100g_us.f"),
os.path.join(taxi_src_dir, "axis", "rtl", "taxi_axis_async_fifo.f"),
os.path.join(taxi_src_dir, "sync", "rtl", "taxi_sync_reset.sv"),
os.path.join(taxi_src_dir, "sync", "rtl", "taxi_sync_signal.sv"),