mirror of
https://github.com/fpganinja/taxi.git
synced 2025-12-07 16:28:40 -08:00
example: Add example design for HTG-9200
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
@@ -130,6 +130,7 @@ Example designs are provided for several different FPGA boards, showcasing many
|
||||
* Cisco Nexus K3P-Q/ExaNIC X100 (Xilinx Kintex UltraScale+ XCKU3P)
|
||||
* Digilent Arty A7 (Xilinx Artix 7 XC7A35T)
|
||||
* HiTech Global HTG-940 (Xilinx Virtex UltraScale+ XCVU9P/XCVU13P)
|
||||
* HiTech Global HTG-9200 (Xilinx Virtex UltraScale+ XCVU9P/XCVU13P)
|
||||
* Silicom fb2CG@KU15P (Xilinx Kintex UltraScale+ XCKU15P)
|
||||
* Xilinx Alveo U45N/SN1000 (Xilinx Virtex UltraScale+ XCU26)
|
||||
* Xilinx Alveo U50 (Xilinx Virtex UltraScale+ XCU50)
|
||||
|
||||
67
src/eth/example/HTG9200/fpga/README.md
Normal file
67
src/eth/example/HTG9200/fpga/README.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Taxi Example Design for HTG-9200
|
||||
|
||||
## Introduction
|
||||
|
||||
This example design targets the HiTech Global HTG-9200 FPGA board.
|
||||
|
||||
The design places looped-back MACs on the Ethernet ports, as well as XFCP on the USB UART for monitoring and control.
|
||||
|
||||
* USB UART
|
||||
* XFCP (921600 baud)
|
||||
* QSFP28
|
||||
* Looped-back 10GBASE-R or 25GBASE-R MACs via GTY transceivers
|
||||
|
||||
## Board details
|
||||
|
||||
* FPGA: xcvu9p-flgb2104-2-e
|
||||
* USB UART: Silicon Labs CP2103
|
||||
* 1000BASE-T PHY: TI DP83867IRPAP via RGMII
|
||||
|
||||
## Licensing
|
||||
|
||||
* Toolchain
|
||||
* Vivado Enterprise (requires license)
|
||||
* IP
|
||||
* No licensed vendor IP or 3rd party IP
|
||||
|
||||
## How to build
|
||||
|
||||
Run `make` in the appropriate `fpga*` subdirectory to build the bitstream. Ensure that the Xilinx Vivado toolchain components are in PATH.
|
||||
|
||||
## Board configuration
|
||||
|
||||
For correct operation, several DIP switches need to be set correctly. Additionally, some other component-level modifications may be required.
|
||||
|
||||
DIP switch settings:
|
||||
|
||||
* S2.1: off (enable EMCCLK, if needed to boot from flash)
|
||||
* S3.2: off (enable U24 ref_clk)
|
||||
* S4.5: off (enable U47 osc_gty2)
|
||||
* S4.8: on (enable U48 outputs)
|
||||
|
||||
Note that S4.8 has no effect if R441 is not installed (which appears to be the default configuration) as U48 has an internal pull-down on OEb. The PLL configuration in this design also ignores the IN_SEL pins, so S4.6 and S4.7 have no effect. The other DIP switches do not affect the operation of this design.
|
||||
|
||||
When using optical modules or active optical cables, it is necessary to pull the lpmode pins low to enable the lasers. On the HTG-9200, the lpmode pins are not connected to the FPGA, so it is necessary to pull the pins low on the board. The board has footprints for pull-down resistors on the lpmode pins, which are not populated by default. These are R414, R392, R336, R316, R276, R475, R471, R473, and R477 (respectively for QSFP1-9). Shorting across these footprints or installing pull-down resistors of around 150 ohms will bring installed modules out of low power mode.
|
||||
|
||||
The HTG-9200 was originally designed for Virtex UltraScale, so by default some of the power supply voltages are too high for an UltraScale+ device. In particular, the Avcc supplies for the GTY transceivers are set to 1.0 V, which is not only outside of the recommended range of 0.873-0.927 V but it also matches the absolute max of 1.0 V. Additionally, Vccint and Vccbram are set to 0.95V, which is outside of the recommended range of 0.825-0.876 V for standard speed grades but below the absolute max of 1.0 V. Checking the supply voltages and swapping out the feedback resistors on the Vccint, Vccbram and MGT Avcc power supplies is therefore highly recommended. Note that the supplies labeled GTH feed the MGT banks on the right side of the device, which are GTH transceivers on UltraScale and GTY transceivers on UltraScale+.
|
||||
|
||||
The table below contains the power rail test points and feedback resistor values for the power supply rails in question for several different speed grades of Virtex UltraScale and UltraScale+ devices.
|
||||
|
||||
| Rail | VCCINT | VCCBRAM | GTY_AVCC | GTH_AVCC |
|
||||
| ----------- | ------------ | ------------ | ------------ | ------------ |
|
||||
| Test point | P6 | P8 | P9 | P1 |
|
||||
| Regulator | U4, U56 | U11 | U13 | U20 |
|
||||
| Part | 4/2 LTM4650 | LTM4625 | 4/4 LTM4644 | 4/4 LTM4644 |
|
||||
| Current | 100A | 5A | 16A | 16A |
|
||||
| FB resistor | R354 | R494 | R38 | R61 |
|
||||
| US -3, -1H | 90.9K (1.0V) | 90.9K (1.0V) | 22.6K (1.0V) | 22.6K (1.0V) |
|
||||
| US -2, -1 | 105K (0.95V) | 105K (0.95V) | 22.6K (1.0V) | 22.6K (1.0V) |
|
||||
| US+ -3 | 121K (0.90V) | 121K (0.90V) | 30.1K (0.9V) | 30.1K (0.9V) |
|
||||
| US+ -2, -1 | 147K (0.85V) | 147K (0.85V) | 30.1K (0.9V) | 30.1K (0.9V) |
|
||||
| US+ -2L | 301K (0.72V) | 147K (0.85V) | 30.1K (0.9V) | 30.1K (0.9V) |
|
||||
|
||||
## How to test
|
||||
|
||||
Run `make program` to program the board with Vivado.
|
||||
|
||||
To test the looped-back MAC, it is recommended to use a network tester like the Viavi T-BERD 5800 that supports basic layer 2 tests with a loopback. Do not connect the looped-back MAC to a network as the reflected packets may cause problems.
|
||||
153
src/eth/example/HTG9200/fpga/common/vivado.mk
Normal file
153
src/eth/example/HTG9200/fpga/common/vivado.mk
Normal file
@@ -0,0 +1,153 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
###################################################################
|
||||
#
|
||||
# Xilinx Vivado FPGA Makefile
|
||||
#
|
||||
# Copyright (c) 2016-2025 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 - list of source files
|
||||
# INC_FILES - list of include files
|
||||
# XDC_FILES - list of timing constraint files
|
||||
# XCI_FILES - list of IP XCI files
|
||||
# IP_TCL_FILES - list of IP TCL files (sourced during project creation)
|
||||
# CONFIG_TCL_FILES - list of config TCL files (sourced before each build)
|
||||
#
|
||||
# Note: both SYN_FILES and INC_FILES support file list files. File list
|
||||
# files are files with a .f extension that contain a list of additional
|
||||
# files to include, one path relative to the .f file location per line.
|
||||
# The .f files are processed recursively, and then the complete file list
|
||||
# is de-duplicated, with later files in the list taking precedence.
|
||||
#
|
||||
# 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: fpga vivado tmpclean clean distclean
|
||||
|
||||
# prevent make from deleting intermediate files and reports
|
||||
.PRECIOUS: %.xpr %.bit %.bin %.ltx %.xsa %.mcs %.prm
|
||||
.SECONDARY:
|
||||
|
||||
CONFIG ?= config.mk
|
||||
-include $(CONFIG)
|
||||
|
||||
FPGA_TOP ?= fpga
|
||||
PROJECT ?= $(FPGA_TOP)
|
||||
XDC_FILES ?= $(PROJECT).xdc
|
||||
|
||||
# handle file list files
|
||||
process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1)))
|
||||
process_f_files = $(foreach f,$1,$(if $(filter %.f,$f),$(call process_f_file,$f),$f))
|
||||
uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $(lastword $1)),$(notdir $f)),$f,))) $(lastword $1))
|
||||
SYN_FILES := $(call uniq_base,$(call process_f_files,$(SYN_FILES)))
|
||||
INC_FILES := $(call uniq_base,$(call process_f_files,$(INC_FILES)))
|
||||
|
||||
###################################################################
|
||||
# Main Targets
|
||||
#
|
||||
# all: build everything (fpga)
|
||||
# fpga: build FPGA config
|
||||
# vivado: open project in Vivado
|
||||
# tmpclean: remove intermediate files
|
||||
# clean: remove output files and project files
|
||||
# distclean: remove archived output files
|
||||
###################################################################
|
||||
|
||||
all: fpga
|
||||
|
||||
fpga: $(PROJECT).bit
|
||||
|
||||
vivado: $(PROJECT).xpr
|
||||
vivado $(PROJECT).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 update_config.tcl run_synth.tcl run_impl.tcl generate_bit.tcl
|
||||
|
||||
clean:: tmpclean
|
||||
-rm -rf *.bit *.bin *.ltx *.xsa 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 fresh project if Makefile or IP files have changed
|
||||
create_project.tcl: Makefile $(XCI_FILES) $(IP_TCL_FILES)
|
||||
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)" >> $@
|
||||
echo "set_property top $(FPGA_TOP) [current_fileset]" >> $@
|
||||
echo "add_files -fileset constrs_1 $(XDC_FILES)" >> $@
|
||||
for x in $(XCI_FILES); do echo "import_ip $$x" >> $@; done
|
||||
for x in $(IP_TCL_FILES); do echo "source $$x" >> $@; done
|
||||
for x in $(CONFIG_TCL_FILES); do echo "source $$x" >> $@; done
|
||||
|
||||
# source config TCL scripts if any source file has changed
|
||||
update_config.tcl: $(CONFIG_TCL_FILES) $(SYN_FILES) $(INC_FILES) $(XDC_FILES)
|
||||
echo "open_project -quiet $(PROJECT).xpr" > $@
|
||||
for x in $(CONFIG_TCL_FILES); do echo "source $$x" >> $@; done
|
||||
|
||||
$(PROJECT).xpr: create_project.tcl update_config.tcl
|
||||
vivado -nojournal -nolog -mode batch $(foreach x,$?,-source $x)
|
||||
|
||||
# synthesis run
|
||||
$(PROJECT).runs/synth_1/$(PROJECT).dcp: create_project.tcl update_config.tcl $(SYN_FILES) $(INC_FILES) $(XDC_FILES) | $(PROJECT).xpr
|
||||
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
|
||||
|
||||
# output files (including potentially bit, bin, ltx, and xsa)
|
||||
$(PROJECT).bit $(PROJECT).bin $(PROJECT).ltx $(PROJECT).xsa: $(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 -bin_file $(PROJECT).runs/impl_1/$(PROJECT).bit" >> generate_bit.tcl
|
||||
echo "write_debug_probes -force $(PROJECT).runs/impl_1/$(PROJECT).ltx" >> generate_bit.tcl
|
||||
echo "write_hw_platform -fixed -force -include_bit $(PROJECT).xsa" >> generate_bit.tcl
|
||||
vivado -nojournal -nolog -mode batch -source generate_bit.tcl
|
||||
ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).bit .
|
||||
ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).bin .
|
||||
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; \
|
||||
cp -pv $(PROJECT).runs/impl_1/$(PROJECT).bin rev/$(PROJECT)_rev$$COUNT.bin; \
|
||||
if [ -e $(PROJECT).runs/impl_1/$(PROJECT).ltx ]; then cp -pv $(PROJECT).runs/impl_1/$(PROJECT).ltx rev/$(PROJECT)_rev$$COUNT.ltx; fi; \
|
||||
if [ -e $(PROJECT).xsa ]; then cp -pv $(PROJECT).xsa rev/$(PROJECT)_rev$$COUNT.xsa; fi
|
||||
1089
src/eth/example/HTG9200/fpga/fpga.xdc
Normal file
1089
src/eth/example/HTG9200/fpga/fpga.xdc
Normal file
File diff suppressed because it is too large
Load Diff
93
src/eth/example/HTG9200/fpga/fpga_10g_vu13p/Makefile
Normal file
93
src/eth/example/HTG9200/fpga/fpga_10g_vu13p/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
# FPGA settings
|
||||
FPGA_PART = xcvu13p-fhgb2104-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.sv
|
||||
SYN_FILES += $(RTL_DIR)/fpga_core.sv
|
||||
SYN_FILES += $(RTL_DIR)/../pll/si5341_i2c_init.sv
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_if_uart.f
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_switch.sv
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_stats.f
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_i2c_master.f
|
||||
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
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/io/rtl/taxi_debounce_switch.sv
|
||||
|
||||
# XDC files
|
||||
XDC_FILES = ../fpga.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_10g_161.tcl
|
||||
|
||||
# Configuration
|
||||
# CONFIG_TCL_FILES = ./config.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
|
||||
|
||||
%_primary.mcs %_secondary.mcs %_primary.prm %_secondary.prm: %.bit
|
||||
echo "write_cfgmem -force -format mcs -size 128 -interface SPIx8 -loadbit {up 0x0000000 $*.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 _primary.mcs _secondary.mcs _primary.prm _secondary.prm; \
|
||||
do cp $*$$x rev/$*_rev$$COUNT$$x; \
|
||||
echo "Output: rev/$*_rev$$COUNT$$x"; done;
|
||||
|
||||
flash: $(FPGA_TOP)_primary.mcs $(FPGA_TOP)_secondary.mcs $(FPGA_TOP)_primary.prm $(FPGA_TOP)_secondary.prm
|
||||
echo "open_hw" > 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 {s25fl512s-spi-x1_x2_x4_x8}] 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)_primary.mcs\" \"$(FPGA_TOP)_secondary.mcs\"] [current_hw_cfgmem]" >> flash.tcl
|
||||
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP)_primary.prm\" \"$(FPGA_TOP)_secondary.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
|
||||
93
src/eth/example/HTG9200/fpga/fpga_10g_vu9p/Makefile
Normal file
93
src/eth/example/HTG9200/fpga/fpga_10g_vu9p/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
# FPGA settings
|
||||
FPGA_PART = xcvu9p-flgb2104-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.sv
|
||||
SYN_FILES += $(RTL_DIR)/fpga_core.sv
|
||||
SYN_FILES += $(RTL_DIR)/../pll/si5341_i2c_init.sv
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_if_uart.f
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_switch.sv
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_stats.f
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_i2c_master.f
|
||||
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
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/io/rtl/taxi_debounce_switch.sv
|
||||
|
||||
# XDC files
|
||||
XDC_FILES = ../fpga.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_10g_161.tcl
|
||||
|
||||
# Configuration
|
||||
# CONFIG_TCL_FILES = ./config.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
|
||||
|
||||
%_primary.mcs %_secondary.mcs %_primary.prm %_secondary.prm: %.bit
|
||||
echo "write_cfgmem -force -format mcs -size 128 -interface SPIx8 -loadbit {up 0x0000000 $*.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 _primary.mcs _secondary.mcs _primary.prm _secondary.prm; \
|
||||
do cp $*$$x rev/$*_rev$$COUNT$$x; \
|
||||
echo "Output: rev/$*_rev$$COUNT$$x"; done;
|
||||
|
||||
flash: $(FPGA_TOP)_primary.mcs $(FPGA_TOP)_secondary.mcs $(FPGA_TOP)_primary.prm $(FPGA_TOP)_secondary.prm
|
||||
echo "open_hw" > 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 {s25fl512s-spi-x1_x2_x4_x8}] 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)_primary.mcs\" \"$(FPGA_TOP)_secondary.mcs\"] [current_hw_cfgmem]" >> flash.tcl
|
||||
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP)_primary.prm\" \"$(FPGA_TOP)_secondary.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
|
||||
93
src/eth/example/HTG9200/fpga/fpga_vu13p/Makefile
Normal file
93
src/eth/example/HTG9200/fpga/fpga_vu13p/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
# FPGA settings
|
||||
FPGA_PART = xcvu13p-fhgb2104-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.sv
|
||||
SYN_FILES += $(RTL_DIR)/fpga_core.sv
|
||||
SYN_FILES += $(RTL_DIR)/../pll/si5341_i2c_init.sv
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_if_uart.f
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_switch.sv
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_stats.f
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_i2c_master.f
|
||||
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
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/io/rtl/taxi_debounce_switch.sv
|
||||
|
||||
# XDC files
|
||||
XDC_FILES = ../fpga.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_161.tcl
|
||||
|
||||
# Configuration
|
||||
# CONFIG_TCL_FILES = ./config.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
|
||||
|
||||
%_primary.mcs %_secondary.mcs %_primary.prm %_secondary.prm: %.bit
|
||||
echo "write_cfgmem -force -format mcs -size 128 -interface SPIx8 -loadbit {up 0x0000000 $*.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 _primary.mcs _secondary.mcs _primary.prm _secondary.prm; \
|
||||
do cp $*$$x rev/$*_rev$$COUNT$$x; \
|
||||
echo "Output: rev/$*_rev$$COUNT$$x"; done;
|
||||
|
||||
flash: $(FPGA_TOP)_primary.mcs $(FPGA_TOP)_secondary.mcs $(FPGA_TOP)_primary.prm $(FPGA_TOP)_secondary.prm
|
||||
echo "open_hw" > 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 {s25fl512s-spi-x1_x2_x4_x8}] 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)_primary.mcs\" \"$(FPGA_TOP)_secondary.mcs\"] [current_hw_cfgmem]" >> flash.tcl
|
||||
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP)_primary.prm\" \"$(FPGA_TOP)_secondary.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
|
||||
93
src/eth/example/HTG9200/fpga/fpga_vu9p/Makefile
Normal file
93
src/eth/example/HTG9200/fpga/fpga_vu9p/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
# FPGA settings
|
||||
FPGA_PART = xcvu9p-flgb2104-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.sv
|
||||
SYN_FILES += $(RTL_DIR)/fpga_core.sv
|
||||
SYN_FILES += $(RTL_DIR)/../pll/si5341_i2c_init.sv
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_if_uart.f
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_switch.sv
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_stats.f
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_i2c_master.f
|
||||
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
|
||||
SYN_FILES += $(TAXI_SRC_DIR)/io/rtl/taxi_debounce_switch.sv
|
||||
|
||||
# XDC files
|
||||
XDC_FILES = ../fpga.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_161.tcl
|
||||
|
||||
# Configuration
|
||||
# CONFIG_TCL_FILES = ./config.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
|
||||
|
||||
%_primary.mcs %_secondary.mcs %_primary.prm %_secondary.prm: %.bit
|
||||
echo "write_cfgmem -force -format mcs -size 128 -interface SPIx8 -loadbit {up 0x0000000 $*.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 _primary.mcs _secondary.mcs _primary.prm _secondary.prm; \
|
||||
do cp $*$$x rev/$*_rev$$COUNT$$x; \
|
||||
echo "Output: rev/$*_rev$$COUNT$$x"; done;
|
||||
|
||||
flash: $(FPGA_TOP)_primary.mcs $(FPGA_TOP)_secondary.mcs $(FPGA_TOP)_primary.prm $(FPGA_TOP)_secondary.prm
|
||||
echo "open_hw" > 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 {s25fl512s-spi-x1_x2_x4_x8}] 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)_primary.mcs\" \"$(FPGA_TOP)_secondary.mcs\"] [current_hw_cfgmem]" >> flash.tcl
|
||||
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP)_primary.prm\" \"$(FPGA_TOP)_secondary.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
|
||||
1
src/eth/example/HTG9200/fpga/lib/taxi
Symbolic link
1
src/eth/example/HTG9200/fpga/lib/taxi
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../../../../
|
||||
@@ -0,0 +1,412 @@
|
||||
# Si534x/7x/8x/9x Registers Script
|
||||
#
|
||||
# Part: Si5341
|
||||
# Project File: X:\Projects\verilog-ethernet\example\HTG9200\fpga_25g\pll\HTG9200_161-9k2_161.slabtimeproj
|
||||
# Design ID: 9k2_161
|
||||
# Includes Pre/Post Download Control Register Writes: Yes
|
||||
# Die Revision: B1
|
||||
# Creator: ClockBuilder Pro v4.1 [2021-09-22]
|
||||
# Created On: 2023-07-19 01:51:06 GMT-07:00
|
||||
Address,Data
|
||||
#
|
||||
# Start configuration preamble
|
||||
0x0B24,0xC0
|
||||
0x0B25,0x00
|
||||
# Rev D stuck divider fix
|
||||
0x0502,0x01
|
||||
0x0505,0x03
|
||||
0x0957,0x17
|
||||
0x0B4E,0x1A
|
||||
# End configuration preamble
|
||||
#
|
||||
# Delay 300 msec
|
||||
# Delay is worst case time for device to complete any calibration
|
||||
# that is running due to device state change previous to this script
|
||||
# being processed.
|
||||
#
|
||||
# Start configuration registers
|
||||
0x0006,0x00
|
||||
0x0007,0x00
|
||||
0x0008,0x00
|
||||
0x000B,0x74
|
||||
0x0017,0xD0
|
||||
0x0018,0xFF
|
||||
0x0021,0x0B
|
||||
0x0022,0x00
|
||||
0x002B,0x02
|
||||
0x002C,0x33
|
||||
0x002D,0x05
|
||||
0x002E,0xAE
|
||||
0x002F,0x00
|
||||
0x0030,0xAE
|
||||
0x0031,0x00
|
||||
0x0032,0x00
|
||||
0x0033,0x00
|
||||
0x0034,0x00
|
||||
0x0035,0x00
|
||||
0x0036,0xAE
|
||||
0x0037,0x00
|
||||
0x0038,0xAE
|
||||
0x0039,0x00
|
||||
0x003A,0x00
|
||||
0x003B,0x00
|
||||
0x003C,0x00
|
||||
0x003D,0x00
|
||||
0x0041,0x07
|
||||
0x0042,0x07
|
||||
0x0043,0x00
|
||||
0x0044,0x00
|
||||
0x009E,0x00
|
||||
0x0102,0x01
|
||||
0x0108,0x06
|
||||
0x0109,0x09
|
||||
0x010A,0x3B
|
||||
0x010B,0x28
|
||||
0x010D,0x06
|
||||
0x010E,0x09
|
||||
0x010F,0x3B
|
||||
0x0110,0x28
|
||||
0x0112,0x02
|
||||
0x0113,0x09
|
||||
0x0114,0x3B
|
||||
0x0115,0x29
|
||||
0x0117,0x06
|
||||
0x0118,0x09
|
||||
0x0119,0x3B
|
||||
0x011A,0x28
|
||||
0x011C,0x06
|
||||
0x011D,0x09
|
||||
0x011E,0x3B
|
||||
0x011F,0x28
|
||||
0x0121,0x06
|
||||
0x0122,0x09
|
||||
0x0123,0x3B
|
||||
0x0124,0x28
|
||||
0x0126,0x06
|
||||
0x0127,0x09
|
||||
0x0128,0x3B
|
||||
0x0129,0x28
|
||||
0x012B,0x06
|
||||
0x012C,0x09
|
||||
0x012D,0x3B
|
||||
0x012E,0x28
|
||||
0x0130,0x06
|
||||
0x0131,0x09
|
||||
0x0132,0x3B
|
||||
0x0133,0x28
|
||||
0x013A,0x06
|
||||
0x013B,0x09
|
||||
0x013C,0x3B
|
||||
0x013D,0x28
|
||||
0x013F,0x00
|
||||
0x0140,0x00
|
||||
0x0141,0x40
|
||||
0x0206,0x00
|
||||
0x0208,0x02
|
||||
0x0209,0x00
|
||||
0x020A,0x00
|
||||
0x020B,0x00
|
||||
0x020C,0x00
|
||||
0x020D,0x00
|
||||
0x020E,0x01
|
||||
0x020F,0x00
|
||||
0x0210,0x00
|
||||
0x0211,0x00
|
||||
0x0212,0x02
|
||||
0x0213,0x00
|
||||
0x0214,0x00
|
||||
0x0215,0x00
|
||||
0x0216,0x00
|
||||
0x0217,0x00
|
||||
0x0218,0x01
|
||||
0x0219,0x00
|
||||
0x021A,0x00
|
||||
0x021B,0x00
|
||||
0x021C,0x00
|
||||
0x021D,0x00
|
||||
0x021E,0x00
|
||||
0x021F,0x00
|
||||
0x0220,0x00
|
||||
0x0221,0x00
|
||||
0x0222,0x00
|
||||
0x0223,0x00
|
||||
0x0224,0x00
|
||||
0x0225,0x00
|
||||
0x0226,0x00
|
||||
0x0227,0x00
|
||||
0x0228,0x00
|
||||
0x0229,0x00
|
||||
0x022A,0x00
|
||||
0x022B,0x00
|
||||
0x022C,0x00
|
||||
0x022D,0x00
|
||||
0x022E,0x00
|
||||
0x022F,0x00
|
||||
0x0235,0x00
|
||||
0x0236,0x00
|
||||
0x0237,0x00
|
||||
0x0238,0x90
|
||||
0x0239,0x54
|
||||
0x023A,0x00
|
||||
0x023B,0x00
|
||||
0x023C,0x00
|
||||
0x023D,0x00
|
||||
0x023E,0x80
|
||||
0x024A,0x00
|
||||
0x024B,0x00
|
||||
0x024C,0x00
|
||||
0x024D,0x00
|
||||
0x024E,0x00
|
||||
0x024F,0x00
|
||||
0x0250,0x03
|
||||
0x0251,0x00
|
||||
0x0252,0x00
|
||||
0x0253,0x00
|
||||
0x0254,0x00
|
||||
0x0255,0x00
|
||||
0x0256,0x00
|
||||
0x0257,0x00
|
||||
0x0258,0x00
|
||||
0x0259,0x00
|
||||
0x025A,0x00
|
||||
0x025B,0x00
|
||||
0x025C,0x00
|
||||
0x025D,0x00
|
||||
0x025E,0x00
|
||||
0x025F,0x00
|
||||
0x0260,0x00
|
||||
0x0261,0x00
|
||||
0x0262,0x00
|
||||
0x0263,0x00
|
||||
0x0264,0x00
|
||||
0x0268,0x00
|
||||
0x0269,0x00
|
||||
0x026A,0x00
|
||||
0x026B,0x39
|
||||
0x026C,0x6B
|
||||
0x026D,0x32
|
||||
0x026E,0x5F
|
||||
0x026F,0x31
|
||||
0x0270,0x36
|
||||
0x0271,0x31
|
||||
0x0272,0x00
|
||||
0x0302,0x00
|
||||
0x0303,0x00
|
||||
0x0304,0x00
|
||||
0x0305,0x80
|
||||
0x0306,0x14
|
||||
0x0307,0x00
|
||||
0x0308,0x00
|
||||
0x0309,0x00
|
||||
0x030A,0x00
|
||||
0x030B,0x80
|
||||
0x030C,0x00
|
||||
0x030D,0x00
|
||||
0x030E,0x00
|
||||
0x030F,0x10
|
||||
0x0310,0x42
|
||||
0x0311,0x08
|
||||
0x0312,0x00
|
||||
0x0313,0x00
|
||||
0x0314,0x00
|
||||
0x0315,0x00
|
||||
0x0316,0x80
|
||||
0x0317,0x00
|
||||
0x0318,0x00
|
||||
0x0319,0x00
|
||||
0x031A,0x00
|
||||
0x031B,0x00
|
||||
0x031C,0x00
|
||||
0x031D,0x00
|
||||
0x031E,0x00
|
||||
0x031F,0x00
|
||||
0x0320,0x00
|
||||
0x0321,0x00
|
||||
0x0322,0x00
|
||||
0x0323,0x00
|
||||
0x0324,0x00
|
||||
0x0325,0x00
|
||||
0x0326,0x00
|
||||
0x0327,0x00
|
||||
0x0328,0x00
|
||||
0x0329,0x00
|
||||
0x032A,0x00
|
||||
0x032B,0x00
|
||||
0x032C,0x00
|
||||
0x032D,0x00
|
||||
0x032E,0x00
|
||||
0x032F,0x00
|
||||
0x0330,0x00
|
||||
0x0331,0x00
|
||||
0x0332,0x00
|
||||
0x0333,0x00
|
||||
0x0334,0x00
|
||||
0x0335,0x00
|
||||
0x0336,0x00
|
||||
0x0337,0x00
|
||||
0x0338,0x00
|
||||
0x0339,0x1F
|
||||
0x033B,0x00
|
||||
0x033C,0x00
|
||||
0x033D,0x00
|
||||
0x033E,0x00
|
||||
0x033F,0x00
|
||||
0x0340,0x00
|
||||
0x0341,0x00
|
||||
0x0342,0x00
|
||||
0x0343,0x00
|
||||
0x0344,0x00
|
||||
0x0345,0x00
|
||||
0x0346,0x00
|
||||
0x0347,0x00
|
||||
0x0348,0x00
|
||||
0x0349,0x00
|
||||
0x034A,0x00
|
||||
0x034B,0x00
|
||||
0x034C,0x00
|
||||
0x034D,0x00
|
||||
0x034E,0x00
|
||||
0x034F,0x00
|
||||
0x0350,0x00
|
||||
0x0351,0x00
|
||||
0x0352,0x00
|
||||
0x0353,0x00
|
||||
0x0354,0x00
|
||||
0x0355,0x00
|
||||
0x0356,0x00
|
||||
0x0357,0x00
|
||||
0x0358,0x00
|
||||
0x0359,0x00
|
||||
0x035A,0x00
|
||||
0x035B,0x00
|
||||
0x035C,0x00
|
||||
0x035D,0x00
|
||||
0x035E,0x00
|
||||
0x035F,0x00
|
||||
0x0360,0x00
|
||||
0x0361,0x00
|
||||
0x0362,0x00
|
||||
0x0802,0x00
|
||||
0x0803,0x00
|
||||
0x0804,0x00
|
||||
0x0805,0x00
|
||||
0x0806,0x00
|
||||
0x0807,0x00
|
||||
0x0808,0x00
|
||||
0x0809,0x00
|
||||
0x080A,0x00
|
||||
0x080B,0x00
|
||||
0x080C,0x00
|
||||
0x080D,0x00
|
||||
0x080E,0x00
|
||||
0x080F,0x00
|
||||
0x0810,0x00
|
||||
0x0811,0x00
|
||||
0x0812,0x00
|
||||
0x0813,0x00
|
||||
0x0814,0x00
|
||||
0x0815,0x00
|
||||
0x0816,0x00
|
||||
0x0817,0x00
|
||||
0x0818,0x00
|
||||
0x0819,0x00
|
||||
0x081A,0x00
|
||||
0x081B,0x00
|
||||
0x081C,0x00
|
||||
0x081D,0x00
|
||||
0x081E,0x00
|
||||
0x081F,0x00
|
||||
0x0820,0x00
|
||||
0x0821,0x00
|
||||
0x0822,0x00
|
||||
0x0823,0x00
|
||||
0x0824,0x00
|
||||
0x0825,0x00
|
||||
0x0826,0x00
|
||||
0x0827,0x00
|
||||
0x0828,0x00
|
||||
0x0829,0x00
|
||||
0x082A,0x00
|
||||
0x082B,0x00
|
||||
0x082C,0x00
|
||||
0x082D,0x00
|
||||
0x082E,0x00
|
||||
0x082F,0x00
|
||||
0x0830,0x00
|
||||
0x0831,0x00
|
||||
0x0832,0x00
|
||||
0x0833,0x00
|
||||
0x0834,0x00
|
||||
0x0835,0x00
|
||||
0x0836,0x00
|
||||
0x0837,0x00
|
||||
0x0838,0x00
|
||||
0x0839,0x00
|
||||
0x083A,0x00
|
||||
0x083B,0x00
|
||||
0x083C,0x00
|
||||
0x083D,0x00
|
||||
0x083E,0x00
|
||||
0x083F,0x00
|
||||
0x0840,0x00
|
||||
0x0841,0x00
|
||||
0x0842,0x00
|
||||
0x0843,0x00
|
||||
0x0844,0x00
|
||||
0x0845,0x00
|
||||
0x0846,0x00
|
||||
0x0847,0x00
|
||||
0x0848,0x00
|
||||
0x0849,0x00
|
||||
0x084A,0x00
|
||||
0x084B,0x00
|
||||
0x084C,0x00
|
||||
0x084D,0x00
|
||||
0x084E,0x00
|
||||
0x084F,0x00
|
||||
0x0850,0x00
|
||||
0x0851,0x00
|
||||
0x0852,0x00
|
||||
0x0853,0x00
|
||||
0x0854,0x00
|
||||
0x0855,0x00
|
||||
0x0856,0x00
|
||||
0x0857,0x00
|
||||
0x0858,0x00
|
||||
0x0859,0x00
|
||||
0x085A,0x00
|
||||
0x085B,0x00
|
||||
0x085C,0x00
|
||||
0x085D,0x00
|
||||
0x085E,0x00
|
||||
0x085F,0x00
|
||||
0x0860,0x00
|
||||
0x0861,0x00
|
||||
0x090E,0x00
|
||||
0x091C,0x04
|
||||
0x0943,0x00
|
||||
0x0949,0x03
|
||||
0x094A,0x30
|
||||
0x094E,0x49
|
||||
0x094F,0x02
|
||||
0x095E,0x00
|
||||
0x0A02,0x00
|
||||
0x0A03,0x03
|
||||
0x0A04,0x01
|
||||
0x0A05,0x03
|
||||
0x0A14,0x00
|
||||
0x0A1A,0x00
|
||||
0x0A20,0x00
|
||||
0x0A26,0x00
|
||||
0x0A2C,0x00
|
||||
0x0B44,0x0F
|
||||
0x0B4A,0x1C
|
||||
0x0B57,0xA5
|
||||
0x0B58,0x00
|
||||
# End configuration registers
|
||||
#
|
||||
# Start configuration postamble
|
||||
0x001C,0x01
|
||||
0x0B24,0xC3
|
||||
0x0B25,0x02
|
||||
# End configuration postamble
|
||||
Binary file not shown.
644
src/eth/example/HTG9200/fpga/pll/si5341_i2c_init.py
Executable file
644
src/eth/example/HTG9200/fpga/pll/si5341_i2c_init.py
Executable file
@@ -0,0 +1,644 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Generates an I2C init module for multiple chips
|
||||
"""
|
||||
|
||||
from jinja2 import Template
|
||||
|
||||
|
||||
def si5341_cmds(regs, dev_addr=0x77):
|
||||
cur_page = None
|
||||
cur_addr = None
|
||||
|
||||
cmds = []
|
||||
|
||||
print(f"Reading register list file '{regs}'...")
|
||||
|
||||
with open(regs, "r") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line == "Address,Data":
|
||||
continue
|
||||
if line[0] == '#':
|
||||
cmds.append(f"// {line[1:].strip()}")
|
||||
|
||||
if line.startswith("# Delay"):
|
||||
cmds.append("cmd_delay(10); // delay 300 ms")
|
||||
cur_addr = None
|
||||
|
||||
continue
|
||||
|
||||
d = line.split(",")
|
||||
addr = int(d[0], 0)
|
||||
page = (addr >> 8) & 0xff
|
||||
data = int(d[1], 0)
|
||||
|
||||
if page != cur_page:
|
||||
cmds.append(f"cmd_start(7'h{dev_addr:02x});")
|
||||
cmds.append("cmd_wr(8'h01);")
|
||||
cmds.append(f"cmd_wr(8'h{page:02x}); // set page {page:#04x}")
|
||||
cur_page = page
|
||||
cur_addr = None
|
||||
|
||||
if addr != cur_addr:
|
||||
cmds.append(f"cmd_start(7'h{dev_addr:02x});")
|
||||
cmds.append(f"cmd_wr(8'h{addr & 0xff:02x});")
|
||||
cur_addr = addr
|
||||
|
||||
cmds.append(f"cmd_wr(8'h{data:02x}); // write {data:#04x} to {addr:#06x}")
|
||||
cur_addr += 1
|
||||
|
||||
return cmds
|
||||
|
||||
|
||||
def mux_cmds(val, dev_addr):
|
||||
cmds = []
|
||||
cmds.append(f"cmd_start(7'h{dev_addr:02x});")
|
||||
cmds.append(f"cmd_wr(8'h{val:02x});")
|
||||
cmds.append("cmd_stop(); // I2C stop")
|
||||
return cmds
|
||||
|
||||
|
||||
def main():
|
||||
cmds = []
|
||||
|
||||
cmds.append("// Initial delay")
|
||||
cmds.append("cmd_delay(6); // delay 30 ms")
|
||||
|
||||
# Si5341 on HTG 9200
|
||||
cmds.append("// Set muxes to select U48 Si5341 on HTG-9200")
|
||||
cmds.extend(mux_cmds(0x00, 0x70))
|
||||
cmds.extend(mux_cmds(0x04, 0x71))
|
||||
|
||||
cmds.extend(si5341_cmds("HTG9200_161-9k2_161-Registers.txt", 0x77))
|
||||
generate(cmds)
|
||||
|
||||
|
||||
def generate(cmds=None, name=None, output=None):
|
||||
if cmds is None:
|
||||
raise Exception("Command list is required")
|
||||
|
||||
if name is None:
|
||||
name = "si5341_i2c_init"
|
||||
|
||||
if output is None:
|
||||
output = name + ".sv"
|
||||
|
||||
print(f"Generating Si5341 I2C init module {name}...")
|
||||
|
||||
cmds.append("cmd_halt(); // end")
|
||||
|
||||
cmd_str = ""
|
||||
cmd_count = 0
|
||||
|
||||
for cmd in cmds:
|
||||
if cmd.startswith('//'):
|
||||
cmd_str += f" {cmd}\n"
|
||||
else:
|
||||
cmd_str += f" init_data[{cmd_count}] = {cmd}\n"
|
||||
cmd_count += 1
|
||||
|
||||
t = Template(u"""// SPDX-License-Identifier: CERN-OHL-S-2.0
|
||||
/*
|
||||
|
||||
Copyright (c) 2015-2025 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
`resetall
|
||||
`timescale 1ns / 1ps
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* {{name}}
|
||||
*/
|
||||
module {{name}} #
|
||||
(
|
||||
parameter logic SIM_SPEEDUP = 1'b0
|
||||
)
|
||||
(
|
||||
input wire logic clk,
|
||||
input wire logic rst,
|
||||
|
||||
/*
|
||||
* I2C master interface
|
||||
*/
|
||||
taxi_axis_if.src m_axis_cmd,
|
||||
taxi_axis_if.src m_axis_tx,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire logic busy,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire logic start
|
||||
);
|
||||
|
||||
/*
|
||||
|
||||
Generic module for I2C bus initialization. Good for use when multiple devices
|
||||
on an I2C bus must be initialized on system start without intervention of a
|
||||
general-purpose processor.
|
||||
|
||||
Copy this file and change init_data and INIT_DATA_LEN as needed.
|
||||
|
||||
This module can be used in two modes: simple device initialization, or multiple
|
||||
device initialization. In multiple device mode, the same initialization sequence
|
||||
can be performed on multiple different device addresses.
|
||||
|
||||
To use single device mode, only use the start write to address and write data commands.
|
||||
The module will generate the I2C commands in sequential order. Terminate the list
|
||||
with a 0 entry.
|
||||
|
||||
To use the multiple device mode, use the start data and start address block commands
|
||||
to set up lists of initialization data and device addresses. The module enters
|
||||
multiple device mode upon seeing a start data block command. The module stores the
|
||||
offset of the start of the data block and then skips ahead until it reaches a start
|
||||
address block command. The module will store the offset to the address block and
|
||||
read the first address in the block. Then it will jump back to the data block
|
||||
and execute it, substituting the stored address for each current address write
|
||||
command. Upon reaching the start address block command, the module will read out the
|
||||
next address and start again at the top of the data block. If the module encounters
|
||||
a start data block command while looking for an address, then it will store a new data
|
||||
offset and then look for a start address block command. Terminate the list with a 0
|
||||
entry. Normal address commands will operate normally inside a data block.
|
||||
|
||||
Commands:
|
||||
|
||||
00 0000000 : stop
|
||||
00 0000001 : exit multiple device mode
|
||||
00 0000011 : start write to current address
|
||||
00 0001000 : start address block
|
||||
00 0001001 : start data block
|
||||
00 001dddd : delay 2**(16+d) cycles
|
||||
00 1000001 : send I2C stop
|
||||
01 aaaaaaa : start write to address
|
||||
1 dddddddd : write 8-bit data
|
||||
|
||||
Examples
|
||||
|
||||
write 0x11223344 to register 0x0004 on device at 0x50
|
||||
|
||||
01 1010000 start write to 0x50
|
||||
1 00000000 write address 0x0004
|
||||
1 00000100
|
||||
1 00010001 write data 0x11223344
|
||||
1 00100010
|
||||
1 00110011
|
||||
1 01000100
|
||||
0 00000000 stop
|
||||
|
||||
write 0x11223344 to register 0x0004 on devices at 0x50, 0x51, 0x52, and 0x53
|
||||
|
||||
00 0001001 start data block
|
||||
00 0000011 start write to current address
|
||||
1 00000000 write address 0x0004
|
||||
1 00000100
|
||||
1 00010001 write data 0x11223344
|
||||
1 00100010
|
||||
1 00110011
|
||||
1 01000100
|
||||
00 0001000 start address block
|
||||
01 1010000 address 0x50
|
||||
01 1010001 address 0x51
|
||||
01 1010010 address 0x52
|
||||
01 1010011 address 0x53
|
||||
00 0000001 exit multi-dev mode
|
||||
00 0000000 stop
|
||||
|
||||
*/
|
||||
|
||||
// check configuration
|
||||
if (m_axis_cmd.DATA_W < 12)
|
||||
$fatal(0, "Command interface width must be at least 12 bits (instance %m)");
|
||||
|
||||
if (m_axis_tx.DATA_W != 8)
|
||||
$fatal(0, "Data interface width must be 8 bits (instance %m)");
|
||||
|
||||
function [8:0] cmd_start(input [6:0] addr);
|
||||
cmd_start = {2'b01, addr};
|
||||
endfunction
|
||||
|
||||
function [8:0] cmd_wr(input [7:0] data);
|
||||
cmd_wr = {1'b1, data};
|
||||
endfunction
|
||||
|
||||
function [8:0] cmd_stop();
|
||||
cmd_stop = {2'b00, 7'b1000001};
|
||||
endfunction
|
||||
|
||||
function [8:0] cmd_delay(input [3:0] d);
|
||||
cmd_delay = {2'b00, 3'b001, d};
|
||||
endfunction
|
||||
|
||||
function [8:0] cmd_halt();
|
||||
cmd_halt = 9'd0;
|
||||
endfunction
|
||||
|
||||
function [8:0] blk_start_data();
|
||||
blk_start_data = {2'b00, 7'b0001001};
|
||||
endfunction
|
||||
|
||||
function [8:0] blk_start_addr();
|
||||
blk_start_addr = {2'b00, 7'b0001000};
|
||||
endfunction
|
||||
|
||||
function [8:0] cmd_start_cur();
|
||||
cmd_start_cur = {2'b00, 7'b0000011};
|
||||
endfunction
|
||||
|
||||
function [8:0] cmd_exit();
|
||||
cmd_exit = {2'b00, 7'b0000001};
|
||||
endfunction
|
||||
|
||||
// init_data ROM
|
||||
localparam INIT_DATA_LEN = {{cmd_count}};
|
||||
|
||||
reg [8:0] init_data [INIT_DATA_LEN-1:0];
|
||||
|
||||
initial begin
|
||||
{{cmd_str-}}
|
||||
end
|
||||
|
||||
localparam [2:0]
|
||||
STATE_IDLE = 3'd0,
|
||||
STATE_RUN = 3'd1,
|
||||
STATE_TABLE_1 = 3'd2,
|
||||
STATE_TABLE_2 = 3'd3,
|
||||
STATE_TABLE_3 = 3'd4;
|
||||
|
||||
logic [2:0] state_reg = STATE_IDLE, state_next;
|
||||
|
||||
localparam AW = $clog2(INIT_DATA_LEN);
|
||||
|
||||
logic [8:0] init_data_reg = '0;
|
||||
|
||||
logic [AW-1:0] address_reg = '0, address_next;
|
||||
logic [AW-1:0] address_ptr_reg = '0, address_ptr_next;
|
||||
logic [AW-1:0] data_ptr_reg = '0, data_ptr_next;
|
||||
|
||||
logic [6:0] cur_address_reg = '0, cur_address_next;
|
||||
|
||||
logic [31:0] delay_counter_reg = '0, delay_counter_next;
|
||||
|
||||
logic [6:0] m_axis_cmd_address_reg = '0, m_axis_cmd_address_next;
|
||||
logic m_axis_cmd_start_reg = 1'b0, m_axis_cmd_start_next;
|
||||
logic m_axis_cmd_write_reg = 1'b0, m_axis_cmd_write_next;
|
||||
logic m_axis_cmd_stop_reg = 1'b0, m_axis_cmd_stop_next;
|
||||
logic m_axis_cmd_valid_reg = 1'b0, m_axis_cmd_valid_next;
|
||||
|
||||
logic [7:0] m_axis_tx_tdata_reg = '0, m_axis_tx_tdata_next;
|
||||
logic m_axis_tx_tvalid_reg = 1'b0, m_axis_tx_tvalid_next;
|
||||
|
||||
logic start_flag_reg = 1'b0, start_flag_next;
|
||||
|
||||
logic busy_reg = 1'b0;
|
||||
|
||||
assign m_axis_cmd.tdata[6:0] = m_axis_cmd_address_reg;
|
||||
assign m_axis_cmd.tdata[7] = m_axis_cmd_start_reg;
|
||||
assign m_axis_cmd.tdata[8] = 1'b0; // read
|
||||
assign m_axis_cmd.tdata[9] = m_axis_cmd_write_reg;
|
||||
assign m_axis_cmd.tdata[10] = 1'b0; // write multi
|
||||
assign m_axis_cmd.tdata[11] = m_axis_cmd_stop_reg;
|
||||
assign m_axis_cmd.tvalid = m_axis_cmd_valid_reg;
|
||||
assign m_axis_cmd.tlast = 1'b1;
|
||||
assign m_axis_cmd.tid = '0;
|
||||
assign m_axis_cmd.tdest = '0;
|
||||
assign m_axis_cmd.tuser = '0;
|
||||
|
||||
assign m_axis_tx.tdata = m_axis_tx_tdata_reg;
|
||||
assign m_axis_tx.tvalid = m_axis_tx_tvalid_reg;
|
||||
assign m_axis_tx.tlast = 1'b1;
|
||||
assign m_axis_tx.tid = '0;
|
||||
assign m_axis_tx.tdest = '0;
|
||||
assign m_axis_tx.tuser = '0;
|
||||
|
||||
assign busy = busy_reg;
|
||||
|
||||
always_comb begin
|
||||
state_next = STATE_IDLE;
|
||||
|
||||
address_next = address_reg;
|
||||
address_ptr_next = address_ptr_reg;
|
||||
data_ptr_next = data_ptr_reg;
|
||||
|
||||
cur_address_next = cur_address_reg;
|
||||
|
||||
delay_counter_next = delay_counter_reg;
|
||||
|
||||
m_axis_cmd_address_next = m_axis_cmd_address_reg;
|
||||
m_axis_cmd_start_next = m_axis_cmd_start_reg && !(m_axis_cmd.tvalid && m_axis_cmd.tready);
|
||||
m_axis_cmd_write_next = m_axis_cmd_write_reg && !(m_axis_cmd.tvalid && m_axis_cmd.tready);
|
||||
m_axis_cmd_stop_next = m_axis_cmd_stop_reg && !(m_axis_cmd.tvalid && m_axis_cmd.tready);
|
||||
m_axis_cmd_valid_next = m_axis_cmd_valid_reg && !m_axis_cmd.tready;
|
||||
|
||||
m_axis_tx_tdata_next = m_axis_tx_tdata_reg;
|
||||
m_axis_tx_tvalid_next = m_axis_tx_tvalid_reg && !m_axis_tx.tready;
|
||||
|
||||
start_flag_next = start_flag_reg;
|
||||
|
||||
if (m_axis_cmd.tvalid || m_axis_tx.tvalid) begin
|
||||
// wait for output registers to clear
|
||||
state_next = state_reg;
|
||||
end else if (delay_counter_reg != 0) begin
|
||||
// delay
|
||||
delay_counter_next = delay_counter_reg - 1;
|
||||
state_next = state_reg;
|
||||
end else begin
|
||||
case (state_reg)
|
||||
STATE_IDLE: begin
|
||||
// wait for start signal
|
||||
if (!start_flag_reg && start) begin
|
||||
address_next = '0;
|
||||
start_flag_next = 1'b1;
|
||||
state_next = STATE_RUN;
|
||||
end else begin
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
STATE_RUN: begin
|
||||
// process commands
|
||||
if (init_data_reg[8] == 1'b1) begin
|
||||
// write data
|
||||
m_axis_cmd_write_next = 1'b1;
|
||||
m_axis_cmd_stop_next = 1'b0;
|
||||
m_axis_cmd_valid_next = 1'b1;
|
||||
|
||||
m_axis_tx_tdata_next = init_data_reg[7:0];
|
||||
m_axis_tx_tvalid_next = 1'b1;
|
||||
|
||||
address_next = address_reg + 1;
|
||||
|
||||
state_next = STATE_RUN;
|
||||
end else if (init_data_reg[8:7] == 2'b01) begin
|
||||
// write address
|
||||
m_axis_cmd_address_next = init_data_reg[6:0];
|
||||
m_axis_cmd_start_next = 1'b1;
|
||||
|
||||
address_next = address_reg + 1;
|
||||
|
||||
state_next = STATE_RUN;
|
||||
end else if (init_data_reg[8:4] == 5'b00001) begin
|
||||
// delay
|
||||
if (SIM_SPEEDUP) begin
|
||||
delay_counter_next = 32'd1 << (init_data_reg[3:0]);
|
||||
end else begin
|
||||
delay_counter_next = 32'd1 << (init_data_reg[3:0]+16);
|
||||
end
|
||||
|
||||
address_next = address_reg + 1;
|
||||
|
||||
state_next = STATE_RUN;
|
||||
end else if (init_data_reg == 9'b001000001) begin
|
||||
// send stop
|
||||
m_axis_cmd_write_next = 1'b0;
|
||||
m_axis_cmd_start_next = 1'b0;
|
||||
m_axis_cmd_stop_next = 1'b1;
|
||||
m_axis_cmd_valid_next = 1'b1;
|
||||
|
||||
address_next = address_reg + 1;
|
||||
|
||||
state_next = STATE_RUN;
|
||||
end else if (init_data_reg == 9'b000001001) begin
|
||||
// data table start
|
||||
data_ptr_next = address_reg + 1;
|
||||
address_next = address_reg + 1;
|
||||
state_next = STATE_TABLE_1;
|
||||
end else if (init_data_reg == 9'd0) begin
|
||||
// stop
|
||||
m_axis_cmd_start_next = 1'b0;
|
||||
m_axis_cmd_write_next = 1'b0;
|
||||
m_axis_cmd_stop_next = 1'b1;
|
||||
m_axis_cmd_valid_next = 1'b1;
|
||||
|
||||
state_next = STATE_IDLE;
|
||||
end else begin
|
||||
// invalid command, skip
|
||||
address_next = address_reg + 1;
|
||||
state_next = STATE_RUN;
|
||||
end
|
||||
end
|
||||
STATE_TABLE_1: begin
|
||||
// find address table start
|
||||
if (init_data_reg == 9'b000001000) begin
|
||||
// address table start
|
||||
address_ptr_next = address_reg + 1;
|
||||
address_next = address_reg + 1;
|
||||
state_next = STATE_TABLE_2;
|
||||
end else if (init_data_reg == 9'b000001001) begin
|
||||
// data table start
|
||||
data_ptr_next = address_reg + 1;
|
||||
address_next = address_reg + 1;
|
||||
state_next = STATE_TABLE_1;
|
||||
end else if (init_data_reg == 1) begin
|
||||
// exit mode
|
||||
address_next = address_reg + 1;
|
||||
state_next = STATE_RUN;
|
||||
end else if (init_data_reg == 9'd0) begin
|
||||
// stop
|
||||
m_axis_cmd_start_next = 1'b0;
|
||||
m_axis_cmd_write_next = 1'b0;
|
||||
m_axis_cmd_stop_next = 1'b1;
|
||||
m_axis_cmd_valid_next = 1'b1;
|
||||
|
||||
state_next = STATE_IDLE;
|
||||
end else begin
|
||||
// invalid command, skip
|
||||
address_next = address_reg + 1;
|
||||
state_next = STATE_TABLE_1;
|
||||
end
|
||||
end
|
||||
STATE_TABLE_2: begin
|
||||
// find next address
|
||||
if (init_data_reg[8:7] == 2'b01) begin
|
||||
// write address command
|
||||
// store address and move to data table
|
||||
cur_address_next = init_data_reg[6:0];
|
||||
address_ptr_next = address_reg + 1;
|
||||
address_next = data_ptr_reg;
|
||||
state_next = STATE_TABLE_3;
|
||||
end else if (init_data_reg == 9'b000001001) begin
|
||||
// data table start
|
||||
data_ptr_next = address_reg + 1;
|
||||
address_next = address_reg + 1;
|
||||
state_next = STATE_TABLE_1;
|
||||
end else if (init_data_reg == 9'd1) begin
|
||||
// exit mode
|
||||
address_next = address_reg + 1;
|
||||
state_next = STATE_RUN;
|
||||
end else if (init_data_reg == 9'd0) begin
|
||||
// stop
|
||||
m_axis_cmd_start_next = 1'b0;
|
||||
m_axis_cmd_write_next = 1'b0;
|
||||
m_axis_cmd_stop_next = 1'b1;
|
||||
m_axis_cmd_valid_next = 1'b1;
|
||||
|
||||
state_next = STATE_IDLE;
|
||||
end else begin
|
||||
// invalid command, skip
|
||||
address_next = address_reg + 1;
|
||||
state_next = STATE_TABLE_2;
|
||||
end
|
||||
end
|
||||
STATE_TABLE_3: begin
|
||||
// process data table with selected address
|
||||
if (init_data_reg[8] == 1'b1) begin
|
||||
// write data
|
||||
m_axis_cmd_write_next = 1'b1;
|
||||
m_axis_cmd_stop_next = 1'b0;
|
||||
m_axis_cmd_valid_next = 1'b1;
|
||||
|
||||
m_axis_tx_tdata_next = init_data_reg[7:0];
|
||||
m_axis_tx_tvalid_next = 1'b1;
|
||||
|
||||
address_next = address_reg + 1;
|
||||
|
||||
state_next = STATE_TABLE_3;
|
||||
end else if (init_data_reg[8:7] == 2'b01) begin
|
||||
// write address
|
||||
m_axis_cmd_address_next = init_data_reg[6:0];
|
||||
m_axis_cmd_start_next = 1'b1;
|
||||
|
||||
address_next = address_reg + 1;
|
||||
|
||||
state_next = STATE_TABLE_3;
|
||||
end else if (init_data_reg == 9'b000000011) begin
|
||||
// write current address
|
||||
m_axis_cmd_address_next = cur_address_reg;
|
||||
m_axis_cmd_start_next = 1'b1;
|
||||
|
||||
address_next = address_reg + 1;
|
||||
|
||||
state_next = STATE_TABLE_3;
|
||||
end else if (init_data_reg[8:4] == 5'b00001) begin
|
||||
// delay
|
||||
if (SIM_SPEEDUP) begin
|
||||
delay_counter_next = 32'd1 << (init_data_reg[3:0]);
|
||||
end else begin
|
||||
delay_counter_next = 32'd1 << (init_data_reg[3:0]+16);
|
||||
end
|
||||
|
||||
address_next = address_reg + 1;
|
||||
|
||||
state_next = STATE_TABLE_3;
|
||||
end else if (init_data_reg == 9'b001000001) begin
|
||||
// send stop
|
||||
m_axis_cmd_write_next = 1'b0;
|
||||
m_axis_cmd_start_next = 1'b0;
|
||||
m_axis_cmd_stop_next = 1'b1;
|
||||
m_axis_cmd_valid_next = 1'b1;
|
||||
|
||||
address_next = address_reg + 1;
|
||||
|
||||
state_next = STATE_TABLE_3;
|
||||
end else if (init_data_reg == 9'b000001001) begin
|
||||
// data table start
|
||||
data_ptr_next = address_reg + 1;
|
||||
address_next = address_reg + 1;
|
||||
state_next = STATE_TABLE_1;
|
||||
end else if (init_data_reg == 9'b000001000) begin
|
||||
// address table start
|
||||
address_next = address_ptr_reg;
|
||||
state_next = STATE_TABLE_2;
|
||||
end else if (init_data_reg == 9'd1) begin
|
||||
// exit mode
|
||||
address_next = address_reg + 1;
|
||||
state_next = STATE_RUN;
|
||||
end else if (init_data_reg == 9'd0) begin
|
||||
// stop
|
||||
m_axis_cmd_start_next = 1'b0;
|
||||
m_axis_cmd_write_next = 1'b0;
|
||||
m_axis_cmd_stop_next = 1'b1;
|
||||
m_axis_cmd_valid_next = 1'b1;
|
||||
|
||||
state_next = STATE_IDLE;
|
||||
end else begin
|
||||
// invalid command, skip
|
||||
address_next = address_reg + 1;
|
||||
state_next = STATE_TABLE_3;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
// invalid state
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
state_reg <= state_next;
|
||||
|
||||
// read init_data ROM
|
||||
init_data_reg <= init_data[address_next];
|
||||
|
||||
address_reg <= address_next;
|
||||
address_ptr_reg <= address_ptr_next;
|
||||
data_ptr_reg <= data_ptr_next;
|
||||
|
||||
cur_address_reg <= cur_address_next;
|
||||
|
||||
delay_counter_reg <= delay_counter_next;
|
||||
|
||||
m_axis_cmd_address_reg <= m_axis_cmd_address_next;
|
||||
m_axis_cmd_start_reg <= m_axis_cmd_start_next;
|
||||
m_axis_cmd_write_reg <= m_axis_cmd_write_next;
|
||||
m_axis_cmd_stop_reg <= m_axis_cmd_stop_next;
|
||||
m_axis_cmd_valid_reg <= m_axis_cmd_valid_next;
|
||||
|
||||
m_axis_tx_tdata_reg <= m_axis_tx_tdata_next;
|
||||
m_axis_tx_tvalid_reg <= m_axis_tx_tvalid_next;
|
||||
|
||||
start_flag_reg <= start && start_flag_next;
|
||||
|
||||
busy_reg <= (state_reg != STATE_IDLE);
|
||||
|
||||
if (rst) begin
|
||||
state_reg <= STATE_IDLE;
|
||||
|
||||
init_data_reg <= '0;
|
||||
|
||||
address_reg <= '0;
|
||||
address_ptr_reg <= '0;
|
||||
data_ptr_reg <= '0;
|
||||
|
||||
cur_address_reg <= '0;
|
||||
|
||||
delay_counter_reg <= '0;
|
||||
|
||||
m_axis_cmd_valid_reg <= 1'b0;
|
||||
|
||||
m_axis_tx_tvalid_reg <= 1'b0;
|
||||
|
||||
start_flag_reg <= 1'b0;
|
||||
|
||||
busy_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
||||
""")
|
||||
|
||||
print(f"Writing file '{output}'...")
|
||||
|
||||
with open(output, 'w') as f:
|
||||
f.write(t.render(
|
||||
cmd_str=cmd_str,
|
||||
cmd_count=cmd_count,
|
||||
name=name
|
||||
))
|
||||
f.flush()
|
||||
|
||||
print("Done")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1088
src/eth/example/HTG9200/fpga/pll/si5341_i2c_init.sv
Normal file
1088
src/eth/example/HTG9200/fpga/pll/si5341_i2c_init.sv
Normal file
File diff suppressed because it is too large
Load Diff
381
src/eth/example/HTG9200/fpga/rtl/fpga.sv
Normal file
381
src/eth/example/HTG9200/fpga/rtl/fpga.sv
Normal file
@@ -0,0 +1,381 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
|
||||
Copyright (c) 2021-2025 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
`resetall
|
||||
`timescale 1ns / 1ps
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* FPGA top-level module
|
||||
*/
|
||||
module fpga #
|
||||
(
|
||||
parameter logic SIM = 1'b0,
|
||||
parameter string VENDOR = "XILINX",
|
||||
parameter string FAMILY = "virtexuplus"
|
||||
)
|
||||
(
|
||||
/*
|
||||
* Clock: 200 MHz LVDS
|
||||
*/
|
||||
input wire logic ref_clk_p,
|
||||
input wire logic ref_clk_n,
|
||||
|
||||
/*
|
||||
* GPIO
|
||||
*/
|
||||
input wire logic [1:0] btn,
|
||||
input wire logic [7:0] sw,
|
||||
output wire logic [7:0] led,
|
||||
|
||||
/*
|
||||
* I2C for board management
|
||||
*/
|
||||
inout wire logic i2c_main_scl,
|
||||
inout wire logic i2c_main_sda,
|
||||
output wire logic i2c_main_rst_n,
|
||||
|
||||
/*
|
||||
* PLL
|
||||
*/
|
||||
output wire logic clk_gty2_fdec,
|
||||
output wire logic clk_gty2_finc,
|
||||
input wire logic clk_gty2_intr_n,
|
||||
input wire logic clk_gty2_lol_n,
|
||||
output wire logic clk_gty2_oe_n,
|
||||
output wire logic clk_gty2_sync_n,
|
||||
output wire logic clk_gty2_rst_n,
|
||||
|
||||
/*
|
||||
* UART: 921600 bps, 8N1
|
||||
*/
|
||||
output wire logic uart_rxd,
|
||||
input wire logic uart_txd,
|
||||
input wire logic uart_rts,
|
||||
output wire logic uart_cts,
|
||||
output wire logic uart_rst_n,
|
||||
output wire logic uart_suspend_n,
|
||||
|
||||
/*
|
||||
* Ethernet: QSFP28
|
||||
*/
|
||||
output wire logic [3:0] qsfp_1_tx_p,
|
||||
output wire logic [3:0] qsfp_1_tx_n,
|
||||
input wire logic [3:0] qsfp_1_rx_p,
|
||||
input wire logic [3:0] qsfp_1_rx_n,
|
||||
input wire logic qsfp_1_mgt_refclk_p,
|
||||
input wire logic qsfp_1_mgt_refclk_n,
|
||||
output wire logic qsfp_1_resetl,
|
||||
input wire logic qsfp_1_modprsl,
|
||||
input wire logic qsfp_1_intl,
|
||||
|
||||
output wire logic [3:0] qsfp_2_tx_p,
|
||||
output wire logic [3:0] qsfp_2_tx_n,
|
||||
input wire logic [3:0] qsfp_2_rx_p,
|
||||
input wire logic [3:0] qsfp_2_rx_n,
|
||||
input wire logic qsfp_2_mgt_refclk_p,
|
||||
input wire logic qsfp_2_mgt_refclk_n,
|
||||
output wire logic qsfp_2_resetl,
|
||||
input wire logic qsfp_2_modprsl,
|
||||
input wire logic qsfp_2_intl,
|
||||
|
||||
output wire logic [3:0] qsfp_3_tx_p,
|
||||
output wire logic [3:0] qsfp_3_tx_n,
|
||||
input wire logic [3:0] qsfp_3_rx_p,
|
||||
input wire logic [3:0] qsfp_3_rx_n,
|
||||
input wire logic qsfp_3_mgt_refclk_p,
|
||||
input wire logic qsfp_3_mgt_refclk_n,
|
||||
output wire logic qsfp_3_resetl,
|
||||
input wire logic qsfp_3_modprsl,
|
||||
input wire logic qsfp_3_intl,
|
||||
|
||||
output wire logic [3:0] qsfp_4_tx_p,
|
||||
output wire logic [3:0] qsfp_4_tx_n,
|
||||
input wire logic [3:0] qsfp_4_rx_p,
|
||||
input wire logic [3:0] qsfp_4_rx_n,
|
||||
input wire logic qsfp_4_mgt_refclk_p,
|
||||
input wire logic qsfp_4_mgt_refclk_n,
|
||||
output wire logic qsfp_4_resetl,
|
||||
input wire logic qsfp_4_modprsl,
|
||||
input wire logic qsfp_4_intl,
|
||||
|
||||
output wire logic [3:0] qsfp_5_tx_p,
|
||||
output wire logic [3:0] qsfp_5_tx_n,
|
||||
input wire logic [3:0] qsfp_5_rx_p,
|
||||
input wire logic [3:0] qsfp_5_rx_n,
|
||||
input wire logic qsfp_5_mgt_refclk_p,
|
||||
input wire logic qsfp_5_mgt_refclk_n,
|
||||
output wire logic qsfp_5_resetl,
|
||||
input wire logic qsfp_5_modprsl,
|
||||
input wire logic qsfp_5_intl,
|
||||
|
||||
output wire logic [3:0] qsfp_6_tx_p,
|
||||
output wire logic [3:0] qsfp_6_tx_n,
|
||||
input wire logic [3:0] qsfp_6_rx_p,
|
||||
input wire logic [3:0] qsfp_6_rx_n,
|
||||
input wire logic qsfp_6_mgt_refclk_p,
|
||||
input wire logic qsfp_6_mgt_refclk_n,
|
||||
output wire logic qsfp_6_resetl,
|
||||
input wire logic qsfp_6_modprsl,
|
||||
input wire logic qsfp_6_intl,
|
||||
|
||||
output wire logic [3:0] qsfp_7_tx_p,
|
||||
output wire logic [3:0] qsfp_7_tx_n,
|
||||
input wire logic [3:0] qsfp_7_rx_p,
|
||||
input wire logic [3:0] qsfp_7_rx_n,
|
||||
input wire logic qsfp_7_mgt_refclk_p,
|
||||
input wire logic qsfp_7_mgt_refclk_n,
|
||||
output wire logic qsfp_7_resetl,
|
||||
input wire logic qsfp_7_modprsl,
|
||||
input wire logic qsfp_7_intl,
|
||||
|
||||
output wire logic [3:0] qsfp_8_tx_p,
|
||||
output wire logic [3:0] qsfp_8_tx_n,
|
||||
input wire logic [3:0] qsfp_8_rx_p,
|
||||
input wire logic [3:0] qsfp_8_rx_n,
|
||||
input wire logic qsfp_8_mgt_refclk_p,
|
||||
input wire logic qsfp_8_mgt_refclk_n,
|
||||
output wire logic qsfp_8_resetl,
|
||||
input wire logic qsfp_8_modprsl,
|
||||
input wire logic qsfp_8_intl,
|
||||
|
||||
output wire logic [3:0] qsfp_9_tx_p,
|
||||
output wire logic [3:0] qsfp_9_tx_n,
|
||||
input wire logic [3:0] qsfp_9_rx_p,
|
||||
input wire logic [3:0] qsfp_9_rx_n,
|
||||
input wire logic qsfp_9_mgt_refclk_p,
|
||||
input wire logic qsfp_9_mgt_refclk_n,
|
||||
output wire logic qsfp_9_resetl,
|
||||
input wire logic qsfp_9_modprsl,
|
||||
input wire logic qsfp_9_intl
|
||||
);
|
||||
|
||||
// Clock and reset
|
||||
|
||||
wire ref_clk_ibufg;
|
||||
|
||||
// Internal 125 MHz clock
|
||||
wire clk_125mhz_mmcm_out;
|
||||
wire clk_125mhz_int;
|
||||
wire rst_125mhz_int;
|
||||
|
||||
wire mmcm_rst = ~btn[0];
|
||||
wire mmcm_locked;
|
||||
wire mmcm_clkfb;
|
||||
|
||||
IBUFGDS #(
|
||||
.DIFF_TERM("FALSE"),
|
||||
.IBUF_LOW_PWR("FALSE")
|
||||
)
|
||||
ref_clk_ibufg_inst (
|
||||
.O (ref_clk_ibufg),
|
||||
.I (ref_clk_p),
|
||||
.IB (ref_clk_n)
|
||||
);
|
||||
|
||||
// MMCM instance
|
||||
MMCME4_BASE #(
|
||||
// 200 MHz input
|
||||
.CLKIN1_PERIOD(5.0),
|
||||
.REF_JITTER1(0.010),
|
||||
// 200 MHz input / 1 = 200 MHz PFD (range 10 MHz to 500 MHz)
|
||||
.DIVCLK_DIVIDE(1),
|
||||
// 200 MHz PFD * 5 = 1000 MHz VCO (range 800 MHz to 1600 MHz)
|
||||
.CLKFBOUT_MULT_F(5),
|
||||
.CLKFBOUT_PHASE(0),
|
||||
// 1000 MHz / 8 = 125 MHz, 0 degrees
|
||||
.CLKOUT0_DIVIDE_F(8),
|
||||
.CLKOUT0_DUTY_CYCLE(0.5),
|
||||
.CLKOUT0_PHASE(0),
|
||||
// Not used
|
||||
.CLKOUT1_DIVIDE(1),
|
||||
.CLKOUT1_DUTY_CYCLE(0.5),
|
||||
.CLKOUT1_PHASE(0),
|
||||
// Not used
|
||||
.CLKOUT2_DIVIDE(1),
|
||||
.CLKOUT2_DUTY_CYCLE(0.5),
|
||||
.CLKOUT2_PHASE(0),
|
||||
// Not used
|
||||
.CLKOUT3_DIVIDE(1),
|
||||
.CLKOUT3_DUTY_CYCLE(0.5),
|
||||
.CLKOUT3_PHASE(0),
|
||||
// Not used
|
||||
.CLKOUT4_DIVIDE(1),
|
||||
.CLKOUT4_DUTY_CYCLE(0.5),
|
||||
.CLKOUT4_PHASE(0),
|
||||
.CLKOUT4_CASCADE("FALSE"),
|
||||
// Not used
|
||||
.CLKOUT5_DIVIDE(1),
|
||||
.CLKOUT5_DUTY_CYCLE(0.5),
|
||||
.CLKOUT5_PHASE(0),
|
||||
// Not used
|
||||
.CLKOUT6_DIVIDE(1),
|
||||
.CLKOUT6_DUTY_CYCLE(0.5),
|
||||
.CLKOUT6_PHASE(0),
|
||||
|
||||
// optimized bandwidth
|
||||
.BANDWIDTH("OPTIMIZED"),
|
||||
// don't wait for lock during startup
|
||||
.STARTUP_WAIT("FALSE")
|
||||
)
|
||||
clk_mmcm_inst (
|
||||
// 200 MHz input
|
||||
.CLKIN1(ref_clk_ibufg),
|
||||
// direct clkfb feeback
|
||||
.CLKFBIN(mmcm_clkfb),
|
||||
.CLKFBOUT(mmcm_clkfb),
|
||||
.CLKFBOUTB(),
|
||||
// 125 MHz, 0 degrees
|
||||
.CLKOUT0(clk_125mhz_mmcm_out),
|
||||
.CLKOUT0B(),
|
||||
// Not used
|
||||
.CLKOUT1(),
|
||||
.CLKOUT1B(),
|
||||
// Not used
|
||||
.CLKOUT2(),
|
||||
.CLKOUT2B(),
|
||||
// Not used
|
||||
.CLKOUT3(),
|
||||
.CLKOUT3B(),
|
||||
// Not used
|
||||
.CLKOUT4(),
|
||||
// Not used
|
||||
.CLKOUT5(),
|
||||
// Not used
|
||||
.CLKOUT6(),
|
||||
// reset input
|
||||
.RST(mmcm_rst),
|
||||
// don't power down
|
||||
.PWRDWN(1'b0),
|
||||
// locked output
|
||||
.LOCKED(mmcm_locked)
|
||||
);
|
||||
|
||||
BUFG
|
||||
clk_125mhz_bufg_inst (
|
||||
.I(clk_125mhz_mmcm_out),
|
||||
.O(clk_125mhz_int)
|
||||
);
|
||||
|
||||
taxi_sync_reset #(
|
||||
.N(4)
|
||||
)
|
||||
sync_reset_125mhz_inst (
|
||||
.clk(clk_125mhz_int),
|
||||
.rst(~mmcm_locked),
|
||||
.out(rst_125mhz_int)
|
||||
);
|
||||
|
||||
// GPIO
|
||||
wire btn_int;
|
||||
wire [7:0] sw_int;
|
||||
|
||||
taxi_debounce_switch #(
|
||||
.WIDTH(9),
|
||||
.N(4),
|
||||
.RATE(125000)
|
||||
)
|
||||
debounce_switch_inst (
|
||||
.clk(clk_125mhz_int),
|
||||
.rst(rst_125mhz_int),
|
||||
.in({btn[1],
|
||||
sw}),
|
||||
.out({btn_int,
|
||||
sw_int})
|
||||
);
|
||||
|
||||
wire uart_txd_int;
|
||||
wire uart_rts_int;
|
||||
|
||||
taxi_sync_signal #(
|
||||
.WIDTH(2),
|
||||
.N(2)
|
||||
)
|
||||
sync_signal_inst (
|
||||
.clk(clk_125mhz_int),
|
||||
.in({uart_txd, uart_rts}),
|
||||
.out({uart_txd_int, uart_rts_int})
|
||||
);
|
||||
|
||||
wire i2c_scl_i;
|
||||
wire i2c_scl_o;
|
||||
wire i2c_sda_i;
|
||||
wire i2c_sda_o;
|
||||
|
||||
assign i2c_scl_i = i2c_main_scl;
|
||||
assign i2c_main_scl = i2c_scl_o ? 1'bz : 1'b0;
|
||||
assign i2c_sda_i = i2c_main_sda;
|
||||
assign i2c_main_sda = i2c_sda_o ? 1'bz : 1'b0;
|
||||
assign i2c_main_rst_n = 1'b1;
|
||||
|
||||
fpga_core
|
||||
core_inst (
|
||||
/*
|
||||
* Clock: 125MHz
|
||||
* Synchronous reset
|
||||
*/
|
||||
.clk_125mhz(clk_125mhz_int),
|
||||
.rst_125mhz(rst_125mhz_int),
|
||||
|
||||
/*
|
||||
* GPIO
|
||||
*/
|
||||
.btn(btn_int),
|
||||
.sw(sw_int),
|
||||
.led(led),
|
||||
|
||||
/*
|
||||
* I2C for board management
|
||||
*/
|
||||
.i2c_scl_i(i2c_scl_i),
|
||||
.i2c_scl_o(i2c_scl_o),
|
||||
.i2c_sda_i(i2c_sda_i),
|
||||
.i2c_sda_o(i2c_sda_o),
|
||||
|
||||
/*
|
||||
* PLL
|
||||
*/
|
||||
.clk_gty2_fdec(clk_gty2_fdec),
|
||||
.clk_gty2_finc(clk_gty2_finc),
|
||||
.clk_gty2_intr_n(clk_gty2_intr_n),
|
||||
.clk_gty2_lol_n(clk_gty2_lol_n),
|
||||
.clk_gty2_oe_n(clk_gty2_oe_n),
|
||||
.clk_gty2_sync_n(clk_gty2_sync_n),
|
||||
.clk_gty2_rst_n(clk_gty2_rst_n),
|
||||
|
||||
/*
|
||||
* UART: 921600 bps, 8N1
|
||||
*/
|
||||
.uart_rxd(uart_rxd),
|
||||
.uart_txd(uart_txd_int),
|
||||
.uart_rts(uart_rts_int),
|
||||
.uart_cts(uart_cts),
|
||||
.uart_rst_n(uart_rst_n),
|
||||
.uart_suspend_n(uart_suspend_n),
|
||||
|
||||
/*
|
||||
* Ethernet: QSFP28
|
||||
*/
|
||||
.eth_gty_tx_p({qsfp_9_tx_p, qsfp_8_tx_p, qsfp_7_tx_p, qsfp_6_tx_p, qsfp_5_tx_p, qsfp_4_tx_p, qsfp_3_tx_p, qsfp_2_tx_p, qsfp_1_tx_p}),
|
||||
.eth_gty_tx_n({qsfp_9_tx_n, qsfp_8_tx_n, qsfp_7_tx_n, qsfp_6_tx_n, qsfp_5_tx_n, qsfp_4_tx_n, qsfp_3_tx_n, qsfp_2_tx_n, qsfp_1_tx_n}),
|
||||
.eth_gty_rx_p({qsfp_9_rx_p, qsfp_8_rx_p, qsfp_7_rx_p, qsfp_6_rx_p, qsfp_5_rx_p, qsfp_4_rx_p, qsfp_3_rx_p, qsfp_2_rx_p, qsfp_1_rx_p}),
|
||||
.eth_gty_rx_n({qsfp_9_rx_n, qsfp_8_rx_n, qsfp_7_rx_n, qsfp_6_rx_n, qsfp_5_rx_n, qsfp_4_rx_n, qsfp_3_rx_n, qsfp_2_rx_n, qsfp_1_rx_n}),
|
||||
.eth_gty_mgt_refclk_p({qsfp_9_mgt_refclk_p, qsfp_8_mgt_refclk_p, qsfp_7_mgt_refclk_p, qsfp_6_mgt_refclk_p, qsfp_5_mgt_refclk_p, qsfp_4_mgt_refclk_p, qsfp_3_mgt_refclk_p, qsfp_2_mgt_refclk_p, qsfp_1_mgt_refclk_p}),
|
||||
.eth_gty_mgt_refclk_n({qsfp_9_mgt_refclk_n, qsfp_8_mgt_refclk_n, qsfp_7_mgt_refclk_n, qsfp_6_mgt_refclk_n, qsfp_5_mgt_refclk_n, qsfp_4_mgt_refclk_n, qsfp_3_mgt_refclk_n, qsfp_2_mgt_refclk_n, qsfp_1_mgt_refclk_n}),
|
||||
.eth_gty_mgt_refclk_out(),
|
||||
|
||||
.eth_port_resetl({qsfp_9_resetl, qsfp_8_resetl, qsfp_7_resetl, qsfp_6_resetl, qsfp_5_resetl, qsfp_4_resetl, qsfp_3_resetl, qsfp_2_resetl, qsfp_1_resetl}),
|
||||
.eth_port_modprsl({qsfp_9_modprsl, qsfp_8_modprsl, qsfp_7_modprsl, qsfp_6_modprsl, qsfp_5_modprsl, qsfp_4_modprsl, qsfp_3_modprsl, qsfp_2_modprsl, qsfp_1_modprsl}),
|
||||
.eth_port_intl({qsfp_9_intl, qsfp_8_intl, qsfp_7_intl, qsfp_6_intl, qsfp_5_intl, qsfp_4_intl, qsfp_3_intl, qsfp_2_intl, qsfp_1_intl})
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
||||
674
src/eth/example/HTG9200/fpga/rtl/fpga_core.sv
Normal file
674
src/eth/example/HTG9200/fpga/rtl/fpga_core.sv
Normal file
@@ -0,0 +1,674 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
|
||||
Copyright (c) 2021-2025 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
`resetall
|
||||
`timescale 1ns / 1ps
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* FPGA core logic
|
||||
*/
|
||||
module fpga_core #
|
||||
(
|
||||
parameter logic SIM = 1'b0,
|
||||
parameter string VENDOR = "XILINX",
|
||||
parameter string FAMILY = "virtexuplus",
|
||||
parameter PORT_CNT = 9,
|
||||
parameter GTY_QUAD_CNT = PORT_CNT,
|
||||
parameter GTY_CNT = GTY_QUAD_CNT*4,
|
||||
parameter GTY_CLK_CNT = GTY_QUAD_CNT
|
||||
)
|
||||
(
|
||||
/*
|
||||
* Clock: 125MHz
|
||||
* Synchronous reset
|
||||
*/
|
||||
input wire logic clk_125mhz,
|
||||
input wire logic rst_125mhz,
|
||||
|
||||
/*
|
||||
* GPIO
|
||||
*/
|
||||
input wire logic btn,
|
||||
input wire logic [7:0] sw,
|
||||
output wire logic [7:0] led,
|
||||
|
||||
/*
|
||||
* I2C for board management
|
||||
*/
|
||||
input wire logic i2c_scl_i,
|
||||
output wire logic i2c_scl_o,
|
||||
input wire logic i2c_sda_i,
|
||||
output wire logic i2c_sda_o,
|
||||
|
||||
/*
|
||||
* PLL
|
||||
*/
|
||||
output wire logic clk_gty2_fdec,
|
||||
output wire logic clk_gty2_finc,
|
||||
input wire logic clk_gty2_intr_n,
|
||||
input wire logic clk_gty2_lol_n,
|
||||
output wire logic clk_gty2_oe_n,
|
||||
output wire logic clk_gty2_sync_n,
|
||||
output wire logic clk_gty2_rst_n,
|
||||
|
||||
/*
|
||||
* UART: 921600 bps, 8N1
|
||||
*/
|
||||
output wire logic uart_rxd,
|
||||
input wire logic uart_txd,
|
||||
input wire logic uart_rts,
|
||||
output wire logic uart_cts,
|
||||
output wire logic uart_rst_n,
|
||||
output wire logic uart_suspend_n,
|
||||
|
||||
/*
|
||||
* Ethernet: QSFP28
|
||||
*/
|
||||
output wire logic [GTY_CNT-1:0] eth_gty_tx_p,
|
||||
output wire logic [GTY_CNT-1:0] eth_gty_tx_n,
|
||||
input wire logic [GTY_CNT-1:0] eth_gty_rx_p,
|
||||
input wire logic [GTY_CNT-1:0] eth_gty_rx_n,
|
||||
input wire logic [GTY_CLK_CNT-1:0] eth_gty_mgt_refclk_p,
|
||||
input wire logic [GTY_CLK_CNT-1:0] eth_gty_mgt_refclk_n,
|
||||
output wire logic [GTY_CLK_CNT-1:0] eth_gty_mgt_refclk_out,
|
||||
|
||||
output wire logic [PORT_CNT-1:0] eth_port_resetl,
|
||||
input wire logic [PORT_CNT-1:0] eth_port_modprsl,
|
||||
input wire logic [PORT_CNT-1:0] eth_port_intl
|
||||
);
|
||||
|
||||
wire i2c_init_scl_i = i2c_scl_i;
|
||||
wire i2c_init_scl_o;
|
||||
wire i2c_init_sda_i = i2c_sda_i;
|
||||
wire i2c_init_sda_o;
|
||||
|
||||
wire i2c_xfcp_scl_i = i2c_scl_i;
|
||||
wire i2c_xfcp_scl_o;
|
||||
wire i2c_xfcp_sda_i = i2c_sda_i;
|
||||
wire i2c_xfcp_sda_o;
|
||||
|
||||
assign i2c_scl_o = i2c_init_scl_o & i2c_xfcp_scl_o;
|
||||
assign i2c_sda_o = i2c_init_sda_o & i2c_xfcp_sda_o;
|
||||
|
||||
// Si5341 init
|
||||
taxi_axis_if #(.DATA_W(12)) si5341_i2c_cmd();
|
||||
taxi_axis_if #(.DATA_W(8)) si5341_i2c_tx();
|
||||
taxi_axis_if #(.DATA_W(8)) si5341_i2c_rx();
|
||||
|
||||
assign si5341_i2c_rx.tready = 1'b1;
|
||||
|
||||
wire si5341_i2c_busy;
|
||||
|
||||
taxi_i2c_master
|
||||
si5341_i2c_master_inst (
|
||||
.clk(clk_125mhz),
|
||||
.rst(rst_125mhz),
|
||||
|
||||
/*
|
||||
* Host interface
|
||||
*/
|
||||
.s_axis_cmd(si5341_i2c_cmd),
|
||||
.s_axis_tx(si5341_i2c_tx),
|
||||
.m_axis_rx(si5341_i2c_rx),
|
||||
|
||||
/*
|
||||
* I2C interface
|
||||
*/
|
||||
.scl_i(i2c_init_scl_i),
|
||||
.scl_o(i2c_init_scl_o),
|
||||
.sda_i(i2c_init_sda_i),
|
||||
.sda_o(i2c_init_sda_o),
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
.busy(),
|
||||
.bus_control(),
|
||||
.bus_active(),
|
||||
.missed_ack(),
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
.prescale(SIM ? 32 : 312),
|
||||
.stop_on_idle(1)
|
||||
);
|
||||
|
||||
si5341_i2c_init #(
|
||||
.SIM_SPEEDUP(SIM)
|
||||
)
|
||||
si5341_i2c_init_inst (
|
||||
.clk(clk_125mhz),
|
||||
.rst(rst_125mhz),
|
||||
|
||||
/*
|
||||
* I2C master interface
|
||||
*/
|
||||
.m_axis_cmd(si5341_i2c_cmd),
|
||||
.m_axis_tx(si5341_i2c_tx),
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
.busy(si5341_i2c_busy),
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
.start(1'b1)
|
||||
);
|
||||
|
||||
assign clk_gty2_fdec = 1'b0;
|
||||
assign clk_gty2_finc = 1'b0;
|
||||
assign clk_gty2_oe_n = 1'b0;
|
||||
assign clk_gty2_sync_n = 1'b1;
|
||||
assign clk_gty2_rst_n = !rst_125mhz;
|
||||
|
||||
// XFCP
|
||||
taxi_axis_if #(.DATA_W(8), .USER_EN(1), .USER_W(1)) xfcp_ds(), xfcp_us();
|
||||
|
||||
assign uart_cts = 1'b1;
|
||||
assign uart_rst_n = 1'b1;
|
||||
assign uart_suspend_n = 1'b1;
|
||||
|
||||
taxi_xfcp_if_uart #(
|
||||
.TX_FIFO_DEPTH(512),
|
||||
.RX_FIFO_DEPTH(512)
|
||||
)
|
||||
xfcp_if_uart_inst (
|
||||
.clk(clk_125mhz),
|
||||
.rst(rst_125mhz),
|
||||
|
||||
/*
|
||||
* UART interface
|
||||
*/
|
||||
.uart_rxd(uart_txd),
|
||||
.uart_txd(uart_rxd),
|
||||
|
||||
/*
|
||||
* XFCP downstream interface
|
||||
*/
|
||||
.xfcp_dsp_ds(xfcp_ds),
|
||||
.xfcp_dsp_us(xfcp_us),
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
.prescale(16'(125000000/921600))
|
||||
);
|
||||
|
||||
taxi_axis_if #(.DATA_W(8), .USER_EN(1), .USER_W(1)) xfcp_sw_ds[2](), xfcp_sw_us[2]();
|
||||
|
||||
taxi_xfcp_switch #(
|
||||
.XFCP_ID_STR("HTG-9200"),
|
||||
.XFCP_EXT_ID(0),
|
||||
.XFCP_EXT_ID_STR("Taxi example"),
|
||||
.PORTS($size(xfcp_sw_us))
|
||||
)
|
||||
xfcp_sw_inst (
|
||||
.clk(clk_125mhz),
|
||||
.rst(rst_125mhz),
|
||||
|
||||
/*
|
||||
* XFCP upstream port
|
||||
*/
|
||||
.xfcp_usp_ds(xfcp_ds),
|
||||
.xfcp_usp_us(xfcp_us),
|
||||
|
||||
/*
|
||||
* XFCP downstream ports
|
||||
*/
|
||||
.xfcp_dsp_ds(xfcp_sw_ds),
|
||||
.xfcp_dsp_us(xfcp_sw_us)
|
||||
);
|
||||
|
||||
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(11)) axis_stat();
|
||||
|
||||
taxi_xfcp_mod_stats #(
|
||||
.XFCP_ID_STR("Statistics"),
|
||||
.XFCP_EXT_ID(0),
|
||||
.XFCP_EXT_ID_STR(""),
|
||||
.STAT_COUNT_W(64),
|
||||
.STAT_PIPELINE(2)
|
||||
)
|
||||
xfcp_stats_inst (
|
||||
.clk(clk_125mhz),
|
||||
.rst(rst_125mhz),
|
||||
|
||||
/*
|
||||
* XFCP upstream port
|
||||
*/
|
||||
.xfcp_usp_ds(xfcp_sw_ds[0]),
|
||||
.xfcp_usp_us(xfcp_sw_us[0]),
|
||||
|
||||
/*
|
||||
* Statistics increment input
|
||||
*/
|
||||
.s_axis_stat(axis_stat)
|
||||
);
|
||||
|
||||
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(axis_stat.ID_W)) axis_eth_stat[GTY_QUAD_CNT]();
|
||||
|
||||
taxi_axis_arb_mux #(
|
||||
.S_COUNT($size(axis_eth_stat)),
|
||||
.UPDATE_TID(1'b0),
|
||||
.ARB_ROUND_ROBIN(1'b1),
|
||||
.ARB_LSB_HIGH_PRIO(1'b0)
|
||||
)
|
||||
stat_mux_inst (
|
||||
.clk(clk_125mhz),
|
||||
.rst(rst_125mhz),
|
||||
|
||||
/*
|
||||
* AXI4-Stream inputs (sink)
|
||||
*/
|
||||
.s_axis(axis_eth_stat),
|
||||
|
||||
/*
|
||||
* AXI4-Stream output (source)
|
||||
*/
|
||||
.m_axis(axis_stat)
|
||||
);
|
||||
|
||||
taxi_xfcp_mod_i2c_master #(
|
||||
.DEFAULT_PRESCALE(16'(125000000/400000/4))
|
||||
)
|
||||
xfcp_mod_i2c_inst (
|
||||
.clk(clk_125mhz),
|
||||
.rst(rst_125mhz),
|
||||
|
||||
/*
|
||||
* XFCP upstream port
|
||||
*/
|
||||
.xfcp_usp_ds(xfcp_sw_ds[1]),
|
||||
.xfcp_usp_us(xfcp_sw_us[1]),
|
||||
|
||||
/*
|
||||
* I2C interface
|
||||
*/
|
||||
.i2c_scl_i(i2c_xfcp_scl_i),
|
||||
.i2c_scl_o(i2c_xfcp_scl_o),
|
||||
.i2c_sda_i(i2c_xfcp_sda_i),
|
||||
.i2c_sda_o(i2c_xfcp_sda_o)
|
||||
);
|
||||
|
||||
// Ethernet
|
||||
wire eth_reset = SIM ? 1'b0 : (si5341_i2c_busy || !clk_gty2_lol_n);
|
||||
assign eth_port_resetl = {PORT_CNT{~eth_reset}};
|
||||
|
||||
wire [GTY_CNT-1:0] eth_gty_tx_clk;
|
||||
wire [GTY_CNT-1:0] eth_gty_tx_rst;
|
||||
taxi_axis_if #(.DATA_W(64), .ID_W(8)) 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 [GTY_CNT-1:0] eth_gty_rx_clk;
|
||||
wire [GTY_CNT-1:0] eth_gty_rx_rst;
|
||||
taxi_axis_if #(.DATA_W(64), .ID_W(8)) eth_gty_axis_rx[GTY_CNT]();
|
||||
|
||||
wire [GTY_CNT-1:0] eth_gty_rx_status;
|
||||
|
||||
wire [GTY_QUAD_CNT-1:0] eth_gty_gtpowergood;
|
||||
|
||||
wire [GTY_CLK_CNT-1:0] eth_gty_mgt_refclk;
|
||||
wire [GTY_CLK_CNT-1:0] eth_gty_mgt_refclk_bufg;
|
||||
|
||||
wire [GTY_CLK_CNT-1:0] eth_gty_rst;
|
||||
|
||||
for (genvar n = 0; n < GTY_CLK_CNT; n = n + 1) begin : gty_clk
|
||||
|
||||
wire eth_gty_mgt_refclk_int;
|
||||
|
||||
if (SIM) begin
|
||||
|
||||
assign eth_gty_mgt_refclk[n] = eth_gty_mgt_refclk_p[n];
|
||||
assign eth_gty_mgt_refclk_int = eth_gty_mgt_refclk_p[n];
|
||||
assign eth_gty_mgt_refclk_bufg[n] = eth_gty_mgt_refclk_int;
|
||||
|
||||
end else begin
|
||||
|
||||
IBUFDS_GTE4 ibufds_gte4_eth_gty_mgt_refclk_inst (
|
||||
.I (eth_gty_mgt_refclk_p[n]),
|
||||
.IB (eth_gty_mgt_refclk_n[n]),
|
||||
.CEB (1'b0),
|
||||
.O (eth_gty_mgt_refclk[n]),
|
||||
.ODIV2 (eth_gty_mgt_refclk_int)
|
||||
);
|
||||
|
||||
BUFG_GT bufg_gt_eth_gty_mgt_refclk_inst (
|
||||
.CE (ð_gty_gtpowergood),
|
||||
.CEMASK (1'b1),
|
||||
.CLR (1'b0),
|
||||
.CLRMASK (1'b1),
|
||||
.DIV (3'd0),
|
||||
.I (eth_gty_mgt_refclk_int),
|
||||
.O (eth_gty_mgt_refclk_bufg[n])
|
||||
);
|
||||
|
||||
end
|
||||
|
||||
assign eth_gty_mgt_refclk_out[n] = eth_gty_mgt_refclk_bufg[n];
|
||||
|
||||
taxi_sync_reset #(
|
||||
.N(4)
|
||||
)
|
||||
qsfp_sync_reset_inst (
|
||||
.clk(eth_gty_mgt_refclk_bufg[n]),
|
||||
.rst(rst_125mhz || eth_reset),
|
||||
.out(eth_gty_rst[n])
|
||||
);
|
||||
|
||||
end
|
||||
|
||||
localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP1[4] = '{"QSFP1.1", "QSFP1.2", "QSFP1.3", "QSFP1.4"};
|
||||
localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP2[4] = '{"QSFP2.1", "QSFP2.2", "QSFP2.3", "QSFP2.4"};
|
||||
localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP3[4] = '{"QSFP3.1", "QSFP3.2", "QSFP3.3", "QSFP3.4"};
|
||||
localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP4[4] = '{"QSFP4.1", "QSFP4.2", "QSFP4.3", "QSFP4.4"};
|
||||
localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP5[4] = '{"QSFP5.1", "QSFP5.2", "QSFP5.3", "QSFP5.4"};
|
||||
localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP6[4] = '{"QSFP6.1", "QSFP6.2", "QSFP6.3", "QSFP6.4"};
|
||||
localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP7[4] = '{"QSFP7.1", "QSFP7.2", "QSFP7.3", "QSFP7.4"};
|
||||
localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP8[4] = '{"QSFP8.1", "QSFP8.2", "QSFP8.3", "QSFP8.4"};
|
||||
localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP9[4] = '{"QSFP9.1", "QSFP9.2", "QSFP9.3", "QSFP9.4"};
|
||||
|
||||
for (genvar n = 0; n < GTY_QUAD_CNT; n = n + 1) begin : gty_quad
|
||||
|
||||
localparam CLK = n;
|
||||
localparam CNT = 4;
|
||||
|
||||
taxi_eth_mac_25g_us #(
|
||||
.SIM(SIM),
|
||||
.VENDOR(VENDOR),
|
||||
.FAMILY(FAMILY),
|
||||
|
||||
.CNT(CNT),
|
||||
|
||||
// GT config
|
||||
.CFG_LOW_LATENCY(1),
|
||||
|
||||
// GT type
|
||||
.GT_TYPE("GTY"),
|
||||
|
||||
// PHY parameters
|
||||
.PADDING_EN(1'b1),
|
||||
.DIC_EN(1'b1),
|
||||
.MIN_FRAME_LEN(64),
|
||||
.PTP_TS_EN(1'b0),
|
||||
.PTP_TS_FMT_TOD(1'b1),
|
||||
.PTP_TS_W(96),
|
||||
.PRBS31_EN(1'b0),
|
||||
.TX_SERDES_PIPELINE(1),
|
||||
.RX_SERDES_PIPELINE(1),
|
||||
.COUNT_125US(125000/6.4),
|
||||
.STAT_EN(1),
|
||||
.STAT_TX_LEVEL(1),
|
||||
.STAT_RX_LEVEL(1),
|
||||
.STAT_ID_BASE(n*CNT*(16+16)),
|
||||
.STAT_UPDATE_PERIOD(1024),
|
||||
.STAT_STR_EN(1),
|
||||
.STAT_PREFIX_STR(
|
||||
n == 0 ? STAT_PREFIX_STR_QSFP1 :
|
||||
n == 1 ? STAT_PREFIX_STR_QSFP2 :
|
||||
n == 2 ? STAT_PREFIX_STR_QSFP3 :
|
||||
n == 3 ? STAT_PREFIX_STR_QSFP4 :
|
||||
n == 4 ? STAT_PREFIX_STR_QSFP5 :
|
||||
n == 5 ? STAT_PREFIX_STR_QSFP6 :
|
||||
n == 6 ? STAT_PREFIX_STR_QSFP7 :
|
||||
n == 7 ? STAT_PREFIX_STR_QSFP8 :
|
||||
STAT_PREFIX_STR_QSFP9
|
||||
)
|
||||
)
|
||||
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[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('0),
|
||||
.rx_rst_out(eth_gty_rx_rst[n*CNT +: CNT]),
|
||||
.tx_clk(eth_gty_tx_clk[n*CNT +: CNT]),
|
||||
.tx_rst_in('0),
|
||||
.tx_rst_out(eth_gty_tx_rst[n*CNT +: CNT]),
|
||||
.ptp_sample_clk('0),
|
||||
|
||||
/*
|
||||
* 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]),
|
||||
|
||||
/*
|
||||
* PTP clock
|
||||
*/
|
||||
.tx_ptp_ts('{CNT{'0}}),
|
||||
.tx_ptp_ts_step('0),
|
||||
.rx_ptp_ts('{CNT{'0}}),
|
||||
.rx_ptp_ts_step('0),
|
||||
|
||||
/*
|
||||
* Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE)
|
||||
*/
|
||||
.tx_lfc_req('0),
|
||||
.tx_lfc_resend('0),
|
||||
.rx_lfc_en('0),
|
||||
.rx_lfc_req(),
|
||||
.rx_lfc_ack('0),
|
||||
|
||||
/*
|
||||
* Priority Flow Control (PFC) (IEEE 802.3 annex 31D PFC)
|
||||
*/
|
||||
.tx_pfc_req('{CNT{'0}}),
|
||||
.tx_pfc_resend('0),
|
||||
.rx_pfc_en('{CNT{'0}}),
|
||||
.rx_pfc_req(),
|
||||
.rx_pfc_ack('{CNT{'0}}),
|
||||
|
||||
/*
|
||||
* Pause interface
|
||||
*/
|
||||
.tx_lfc_pause_en('0),
|
||||
.tx_pause_req('0),
|
||||
.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_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('0),
|
||||
.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_max_pkt_len('{CNT{16'd9218}}),
|
||||
.cfg_tx_ifg('{CNT{8'd12}}),
|
||||
.cfg_tx_enable('1),
|
||||
.cfg_rx_max_pkt_len('{CNT{16'd9218}}),
|
||||
.cfg_rx_enable('1),
|
||||
.cfg_tx_prbs31_enable('0),
|
||||
.cfg_rx_prbs31_enable('0),
|
||||
.cfg_mcf_rx_eth_dst_mcast('{CNT{48'h01_80_C2_00_00_01}}),
|
||||
.cfg_mcf_rx_check_eth_dst_mcast('1),
|
||||
.cfg_mcf_rx_eth_dst_ucast('{CNT{48'd0}}),
|
||||
.cfg_mcf_rx_check_eth_dst_ucast('0),
|
||||
.cfg_mcf_rx_eth_src('{CNT{48'd0}}),
|
||||
.cfg_mcf_rx_check_eth_src('0),
|
||||
.cfg_mcf_rx_eth_type('{CNT{16'h8808}}),
|
||||
.cfg_mcf_rx_opcode_lfc('{CNT{16'h0001}}),
|
||||
.cfg_mcf_rx_check_opcode_lfc('1),
|
||||
.cfg_mcf_rx_opcode_pfc('{CNT{16'h0101}}),
|
||||
.cfg_mcf_rx_check_opcode_pfc('1),
|
||||
.cfg_mcf_rx_forward('0),
|
||||
.cfg_mcf_rx_enable('0),
|
||||
.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('0),
|
||||
.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('0),
|
||||
.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('0),
|
||||
.cfg_rx_pfc_opcode('{CNT{16'h0101}}),
|
||||
.cfg_rx_pfc_en('0)
|
||||
);
|
||||
|
||||
end
|
||||
|
||||
for (genvar n = 0; n < GTY_CNT; n = n + 1) begin : gty_ch
|
||||
|
||||
taxi_axis_async_fifo #(
|
||||
.DEPTH(16384),
|
||||
.RAM_PIPELINE(2),
|
||||
.FRAME_FIFO(1),
|
||||
.USER_BAD_FRAME_VALUE(1'b1),
|
||||
.USER_BAD_FRAME_MASK(1'b1),
|
||||
.DROP_OVERSIZE_FRAME(1),
|
||||
.DROP_BAD_FRAME(1),
|
||||
.DROP_WHEN_FULL(1)
|
||||
)
|
||||
ch_fifo (
|
||||
/*
|
||||
* AXI4-Stream input (sink)
|
||||
*/
|
||||
.s_clk(eth_gty_rx_clk[n]),
|
||||
.s_rst(eth_gty_rx_rst[n]),
|
||||
.s_axis(eth_gty_axis_rx[n]),
|
||||
|
||||
/*
|
||||
* AXI4-Stream output (source)
|
||||
*/
|
||||
.m_clk(eth_gty_tx_clk[n]),
|
||||
.m_rst(eth_gty_tx_rst[n]),
|
||||
.m_axis(eth_gty_axis_tx[n]),
|
||||
|
||||
/*
|
||||
* Pause
|
||||
*/
|
||||
.s_pause_req(1'b0),
|
||||
.s_pause_ack(),
|
||||
.m_pause_req(1'b0),
|
||||
.m_pause_ack(),
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
.s_status_depth(),
|
||||
.s_status_depth_commit(),
|
||||
.s_status_overflow(),
|
||||
.s_status_bad_frame(),
|
||||
.s_status_good_frame(),
|
||||
.m_status_depth(),
|
||||
.m_status_depth_commit(),
|
||||
.m_status_overflow(),
|
||||
.m_status_bad_frame(),
|
||||
.m_status_good_frame()
|
||||
);
|
||||
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
||||
65
src/eth/example/HTG9200/fpga/tb/fpga_core/Makefile
Normal file
65
src/eth/example/HTG9200/fpga/tb/fpga_core/Makefile
Normal file
@@ -0,0 +1,65 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2020-2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
|
||||
TOPLEVEL_LANG = verilog
|
||||
|
||||
SIM ?= verilator
|
||||
WAVES ?= 0
|
||||
|
||||
COCOTB_HDL_TIMEUNIT = 1ns
|
||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
||||
|
||||
RTL_DIR = ../../rtl
|
||||
LIB_DIR = ../../lib
|
||||
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
|
||||
|
||||
DUT = fpga_core
|
||||
COCOTB_TEST_MODULES = test_$(DUT)
|
||||
COCOTB_TOPLEVEL = $(DUT)
|
||||
MODULE = $(COCOTB_TEST_MODULES)
|
||||
TOPLEVEL = $(COCOTB_TOPLEVEL)
|
||||
VERILOG_SOURCES += $(RTL_DIR)/$(DUT).sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/../pll/si5341_i2c_init.sv
|
||||
VERILOG_SOURCES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
|
||||
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_if_uart.f
|
||||
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_switch.sv
|
||||
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_stats.f
|
||||
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_i2c_master.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
|
||||
VERILOG_SOURCES += $(TAXI_SRC_DIR)/io/rtl/taxi_debounce_switch.sv
|
||||
|
||||
# handle file list files
|
||||
process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1)))
|
||||
process_f_files = $(foreach f,$1,$(if $(filter %.f,$f),$(call process_f_file,$f),$f))
|
||||
uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $(lastword $1)),$(notdir $f)),$f,))) $(lastword $1))
|
||||
VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES)))
|
||||
|
||||
# module parameters
|
||||
export PARAM_SIM := "1'b1"
|
||||
export PARAM_VENDOR := "\"XILINX\""
|
||||
export PARAM_FAMILY := "\"virtexuplus\""
|
||||
export PARAM_PORT_CNT := 9
|
||||
export PARAM_GTY_QUAD_CNT := $(PARAM_PORT_CNT)
|
||||
export PARAM_GTY_CNT := $(shell echo $$(( 4 * $(PARAM_GTY_QUAD_CNT) )))
|
||||
export PARAM_GTY_CLK_CNT := $(PARAM_GTY_QUAD_CNT)
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(COCOTB_TOPLEVEL).$(subst PARAM_,,$(v))=$($(v)))
|
||||
else ifeq ($(SIM), verilator)
|
||||
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v)))
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
COMPILE_ARGS += --trace-fst
|
||||
VERILATOR_TRACE = 1
|
||||
endif
|
||||
endif
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
1
src/eth/example/HTG9200/fpga/tb/fpga_core/baser.py
Symbolic link
1
src/eth/example/HTG9200/fpga/tb/fpga_core/baser.py
Symbolic link
@@ -0,0 +1 @@
|
||||
../../lib/taxi/src/eth/tb/baser.py
|
||||
254
src/eth/example/HTG9200/fpga/tb/fpga_core/test_fpga_core.py
Normal file
254
src/eth/example/HTG9200/fpga/tb/fpga_core/test_fpga_core.py
Normal file
@@ -0,0 +1,254 @@
|
||||
#!/usr/bin/env python
|
||||
# SPDX-License-Identifier: MIT
|
||||
"""
|
||||
|
||||
Copyright (c) 2020-2025 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
import cocotb_test.simulator
|
||||
|
||||
import cocotb
|
||||
from cocotb.log import SimLog
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge, Timer, Combine
|
||||
|
||||
from cocotbext.eth import XgmiiFrame
|
||||
from cocotbext.uart import UartSource, UartSink
|
||||
|
||||
try:
|
||||
from baser import BaseRSerdesSource, BaseRSerdesSink
|
||||
except ImportError:
|
||||
# attempt import from current directory
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
|
||||
try:
|
||||
from baser import BaseRSerdesSource, BaseRSerdesSink
|
||||
finally:
|
||||
del sys.path[0]
|
||||
|
||||
|
||||
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_125mhz, 8, units="ns").start())
|
||||
|
||||
self.uart_source = UartSource(dut.uart_rxd, baud=921600, bits=8, stop_bits=1)
|
||||
self.uart_sink = UartSink(dut.uart_txd, baud=921600, bits=8, stop_bits=1)
|
||||
|
||||
self.qsfp_sources = []
|
||||
self.qsfp_sinks = []
|
||||
|
||||
for inst in dut.gty_quad:
|
||||
for ch in inst.mac_inst.ch:
|
||||
gt_inst = ch.ch_inst.gt.gt_inst
|
||||
|
||||
if ch.ch_inst.CFG_LOW_LATENCY.value:
|
||||
clk = 2.482
|
||||
gbx_cfg = (66, [64, 65])
|
||||
else:
|
||||
clk = 2.56
|
||||
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())
|
||||
|
||||
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
|
||||
))
|
||||
|
||||
dut.i2c_scl_i.setimmediatevalue(1)
|
||||
dut.i2c_sda_i.setimmediatevalue(1)
|
||||
dut.clk_gty2_intr_n.setimmediatevalue(1)
|
||||
dut.clk_gty2_lol_n.setimmediatevalue(1)
|
||||
dut.sw.setimmediatevalue(0)
|
||||
dut.eth_port_modprsl.setimmediatevalue(0)
|
||||
dut.eth_port_intl.setimmediatevalue(0)
|
||||
|
||||
cocotb.start_soon(self._run_refclk())
|
||||
|
||||
async def init(self):
|
||||
|
||||
self.dut.rst_125mhz.setimmediatevalue(0)
|
||||
|
||||
for k in range(10):
|
||||
await RisingEdge(self.dut.clk_125mhz)
|
||||
|
||||
self.dut.rst_125mhz.value = 1
|
||||
|
||||
for k in range(10):
|
||||
await RisingEdge(self.dut.clk_125mhz)
|
||||
|
||||
self.dut.rst_125mhz.value = 0
|
||||
|
||||
for k in range(10):
|
||||
await RisingEdge(self.dut.clk_125mhz)
|
||||
|
||||
async def _run_refclk(self):
|
||||
t = Timer(3.2, 'ns')
|
||||
val = 2**len(self.dut.eth_gty_mgt_refclk_p)-1
|
||||
while True:
|
||||
self.dut.eth_gty_mgt_refclk_p.value = val
|
||||
await t
|
||||
self.dut.eth_gty_mgt_refclk_p.value = 0
|
||||
await t
|
||||
|
||||
|
||||
async def mac_test(tb, source, sink):
|
||||
tb.log.info("Test MAC")
|
||||
|
||||
tb.log.info("Wait for block lock")
|
||||
for k in range(1200):
|
||||
await RisingEdge(tb.dut.clk_125mhz)
|
||||
|
||||
tb.log.info("Multiple small packets")
|
||||
|
||||
count = 64
|
||||
|
||||
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))
|
||||
|
||||
for k in range(count):
|
||||
rx_frame = await sink.recv()
|
||||
|
||||
tb.log.info("RX frame: %s", rx_frame)
|
||||
|
||||
assert rx_frame.get_payload() == pkts[k]
|
||||
assert rx_frame.check_fcs()
|
||||
|
||||
tb.log.info("Multiple large packets")
|
||||
|
||||
count = 32
|
||||
|
||||
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))
|
||||
|
||||
for k in range(count):
|
||||
rx_frame = await sink.recv()
|
||||
|
||||
tb.log.info("RX frame: %s", rx_frame)
|
||||
|
||||
assert rx_frame.get_payload() == pkts[k]
|
||||
assert rx_frame.check_fcs()
|
||||
|
||||
tb.log.info("MAC test done")
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def run_test(dut):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.init()
|
||||
|
||||
tests = []
|
||||
|
||||
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])))
|
||||
|
||||
await Combine(*tests)
|
||||
|
||||
await RisingEdge(dut.clk_125mhz)
|
||||
await RisingEdge(dut.clk_125mhz)
|
||||
|
||||
|
||||
# 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(tests_dir, '..', '..', 'lib'))
|
||||
taxi_src_dir = os.path.abspath(os.path.join(lib_dir, 'taxi', 'src'))
|
||||
|
||||
|
||||
def process_f_files(files):
|
||||
lst = {}
|
||||
for f in files:
|
||||
if f[-2:].lower() == '.f':
|
||||
with open(f, 'r') as fp:
|
||||
l = fp.read().split()
|
||||
for f in process_f_files([os.path.join(os.path.dirname(f), x) for x in l]):
|
||||
lst[os.path.basename(f)] = f
|
||||
else:
|
||||
lst[os.path.basename(f)] = f
|
||||
return list(lst.values())
|
||||
|
||||
|
||||
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}.sv"),
|
||||
os.path.join(rtl_dir, "..", "pll", "si5341_i2c_init.sv"),
|
||||
os.path.join(taxi_src_dir, "eth", "rtl", "us", "taxi_eth_mac_25g_us.f"),
|
||||
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_if_uart.f"),
|
||||
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_switch.sv"),
|
||||
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_mod_stats.f"),
|
||||
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_mod_i2c_master.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"),
|
||||
os.path.join(taxi_src_dir, "io", "rtl", "taxi_debounce_switch.sv"),
|
||||
]
|
||||
|
||||
verilog_sources = process_f_files(verilog_sources)
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['SIM'] = "1'b1"
|
||||
parameters['VENDOR'] = "\"XILINX\""
|
||||
parameters['FAMILY'] = "\"virtexuplus\""
|
||||
parameters['PORT_CNT'] = 9
|
||||
parameters['GTY_QUAD_CNT'] = parameters['PORT_CNT']
|
||||
parameters['GTY_CNT'] = parameters['GTY_QUAD_CNT']*4
|
||||
parameters['GTY_CLK_CNT'] = parameters['GTY_QUAD_CNT']
|
||||
|
||||
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(
|
||||
simulator="verilator",
|
||||
python_search=[tests_dir],
|
||||
verilog_sources=verilog_sources,
|
||||
toplevel=toplevel,
|
||||
module=module,
|
||||
parameters=parameters,
|
||||
sim_build=sim_build,
|
||||
extra_env=extra_env,
|
||||
)
|
||||
Reference in New Issue
Block a user