mirror of
https://github.com/fpganinja/taxi.git
synced 2025-12-07 16:28:40 -08:00
example/KC705: Add example design for Xilinx KC705
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
@@ -92,6 +92,7 @@ To facilitate the dual-license model, contributions to the project can only be a
|
||||
Example designs are provided for several different FPGA boards, showcasing many of the capabilities of this library. Building the example designs will require the appropriate vendor toolchain and may also require tool and IP licenses.
|
||||
|
||||
* Digilent Arty A7 (Xilinx Artix 7 XC7A35T)
|
||||
* Xilinx KC705 (Xilinx Kintex 7 XC7K325T)
|
||||
|
||||
## Testing
|
||||
|
||||
|
||||
46
example/KC705/fpga/README.md
Normal file
46
example/KC705/fpga/README.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Taxi Example Design for KC705
|
||||
|
||||
## Introduction
|
||||
|
||||
This example design targets the Xilinx KC705 FPGA board.
|
||||
|
||||
The design places looped-back MACs on both the BASE-T port as well as the SFP+ cage, as well as a looped-back UART on on the USB UART connection.
|
||||
|
||||
* USB UART
|
||||
* Looped-back UART
|
||||
* RJ-45 Ethernet port with Marvell 88E1111 PHY
|
||||
* Looped-back MAC via GMII
|
||||
* Looped-back MAC via RGMII
|
||||
* Looped-back MAC via SGMII via Xilinx PCS/PMA core and GTX transceiver
|
||||
* SFP+ cage
|
||||
* Looped-back 1000BASE-X via Xilinx PCS/PMA core and GTX transceiver
|
||||
|
||||
## Board details
|
||||
|
||||
* FPGA: XC7K325T-2FFG900C
|
||||
* 1000BASE-T PHY: Marvell 88E1111 via GMII, RGMII, or SGMII
|
||||
* 1000BASE-X PHY: Xilinx PCS/PMA core via GTX transceiver
|
||||
|
||||
## 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
|
||||
|
||||
Several jumpers must be configured to configure the PHY chip for the appropriate mode.
|
||||
|
||||
| Mode | J29 | J30 | J64 |
|
||||
| -------- | ---- | ---- | ---- |
|
||||
| GMII/MII | 1-2 | 1-2 | open |
|
||||
| RGMII | 1-2 | open | 1-2 |
|
||||
| SGMII | 2-3 | 2-3 | open |
|
||||
|
||||
Also, note that version 1.0 of the KC705 has the SFP+ TX and RX connections polarity-inverted. Version 1.1 has this fixed. This setting is controlled via a top-level parameter setting that is configurable via config.tcl, so ensure to use a design matching the board revision.
|
||||
|
||||
## How to test
|
||||
|
||||
Run `make program` to program the board with Vivado.
|
||||
|
||||
To test the looped-back UART, use any serial terminal software like minicom, screen, etc. The looped-back UART will echo typed text back without modification.
|
||||
|
||||
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
example/KC705/fpga/common/vivado.mk
Normal file
153
example/KC705/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
|
||||
12
example/KC705/fpga/eth_gmii.xdc
Normal file
12
example/KC705/fpga/eth_gmii.xdc
Normal file
@@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
# Ethernet constraints
|
||||
|
||||
# BUFGMUX outputs (GMII)
|
||||
set_clock_groups -physically_exclusive -group clk_mmcm_out -group phy_tx_clk
|
||||
15
example/KC705/fpga/eth_rgmii.xdc
Normal file
15
example/KC705/fpga/eth_rgmii.xdc
Normal file
@@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
# Ethernet constraints
|
||||
|
||||
# IDELAY from PHY chip (RGMII)
|
||||
set_property IDELAY_VALUE 0 [get_cells {phy_if.phy_rx_ctl_idelay phy_if.phy_rxd_idelay_bit[*].idelay_inst}]
|
||||
|
||||
# MMCM phase (RGMII)
|
||||
set_property CLKOUT1_PHASE 90 [get_cells clk_mmcm_inst]
|
||||
141
example/KC705/fpga/fpga.xdc
Normal file
141
example/KC705/fpga/fpga.xdc
Normal file
@@ -0,0 +1,141 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2014-2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
# XDC constraints for the Xilinx KC705 board
|
||||
# part: xc7k325tffg900-2
|
||||
|
||||
# General configuration
|
||||
set_property CFGBVS VCCO [current_design]
|
||||
set_property CONFIG_VOLTAGE 2.5 [current_design]
|
||||
set_property BITSTREAM.GENERAL.COMPRESS true [current_design]
|
||||
|
||||
# System clocks
|
||||
# 200 MHz system clock
|
||||
set_property -dict {LOC AD12 IOSTANDARD LVDS} [get_ports clk_200mhz_p] ;# from SiT9102 U6.4
|
||||
set_property -dict {LOC AD11 IOSTANDARD LVDS} [get_ports clk_200mhz_n] ;# from SiT9102 U6.5
|
||||
create_clock -period 5.000 -name clk_200mhz [get_ports clk_200mhz_p]
|
||||
|
||||
# Si570 user clock (156.25 MHz default)
|
||||
#set_property -dict {LOC K28 IOSTANDARD LVDS_25} [get_ports clk_user_p] ;# from Si570 U45.4
|
||||
#set_property -dict {LOC K29 IOSTANDARD LVDS_25} [get_ports clk_user_n] ;# from Si570 U45.5
|
||||
#create_clock -period 6.400 -name clk_user [get_ports clk_user_p]
|
||||
|
||||
# User SMA clock
|
||||
#set_property -dict {LOC L25 IOSTANDARD LVDS_25} [get_ports clk_user_sma_p] ;# from J11
|
||||
#set_property -dict {LOC K25 IOSTANDARD LVDS_25} [get_ports clk_user_sma_n] ;# from J12
|
||||
#create_clock -period 10.000 -name clk_user_sma [get_ports clk_user_sma_p]
|
||||
|
||||
# LEDs
|
||||
set_property -dict {LOC AB8 IOSTANDARD LVCMOS15 SLEW SLOW DRIVE 12} [get_ports {led[0]}] ;# to DS4
|
||||
set_property -dict {LOC AA8 IOSTANDARD LVCMOS15 SLEW SLOW DRIVE 12} [get_ports {led[1]}] ;# to DS1
|
||||
set_property -dict {LOC AC9 IOSTANDARD LVCMOS15 SLEW SLOW DRIVE 12} [get_ports {led[2]}] ;# to DS10
|
||||
set_property -dict {LOC AB9 IOSTANDARD LVCMOS15 SLEW SLOW DRIVE 12} [get_ports {led[3]}] ;# to DS2
|
||||
set_property -dict {LOC AE26 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports {led[4]}] ;# to DS3
|
||||
set_property -dict {LOC G19 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports {led[5]}] ;# to DS25
|
||||
set_property -dict {LOC E18 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports {led[6]}] ;# to DS26
|
||||
set_property -dict {LOC F16 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports {led[7]}] ;# to DS27
|
||||
|
||||
set_false_path -to [get_ports {led[*]}]
|
||||
set_output_delay 0 [get_ports {led[*]}]
|
||||
|
||||
# Reset button
|
||||
set_property -dict {LOC AB7 IOSTANDARD LVCMOS15} [get_ports reset] ;# from SW7
|
||||
|
||||
set_false_path -from [get_ports {reset}]
|
||||
set_input_delay 0 [get_ports {reset}]
|
||||
|
||||
# Push buttons
|
||||
set_property -dict {LOC AA12 IOSTANDARD LVCMOS15} [get_ports btnu] ;# from SW2
|
||||
set_property -dict {LOC AC6 IOSTANDARD LVCMOS15} [get_ports btnl] ;# from SW6
|
||||
set_property -dict {LOC AB12 IOSTANDARD LVCMOS15} [get_ports btnd] ;# from SW4
|
||||
set_property -dict {LOC AG5 IOSTANDARD LVCMOS15} [get_ports btnr] ;# from SW3
|
||||
set_property -dict {LOC G12 IOSTANDARD LVCMOS25} [get_ports btnc] ;# from SW5
|
||||
|
||||
set_false_path -from [get_ports {btnu btnl btnd btnr btnc}]
|
||||
set_input_delay 0 [get_ports {btnu btnl btnd btnr btnc}]
|
||||
|
||||
# Toggle switches
|
||||
set_property -dict {LOC Y29 IOSTANDARD LVCMOS25} [get_ports {sw[0]}] ;# from SW4.1
|
||||
set_property -dict {LOC W29 IOSTANDARD LVCMOS25} [get_ports {sw[1]}] ;# from SW4.2
|
||||
set_property -dict {LOC AA28 IOSTANDARD LVCMOS25} [get_ports {sw[2]}] ;# from SW4.3
|
||||
set_property -dict {LOC Y28 IOSTANDARD LVCMOS25} [get_ports {sw[3]}] ;# from SW4.4
|
||||
|
||||
set_false_path -from [get_ports {sw[*]}]
|
||||
set_input_delay 0 [get_ports {sw[*]}]
|
||||
|
||||
# UART
|
||||
set_property -dict {LOC K24 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports uart_txd]
|
||||
set_property -dict {LOC M19 IOSTANDARD LVCMOS25} [get_ports uart_rxd]
|
||||
set_property -dict {LOC L27 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports uart_rts]
|
||||
set_property -dict {LOC K23 IOSTANDARD LVCMOS25} [get_ports uart_cts]
|
||||
|
||||
set_false_path -to [get_ports {uart_txd uart_rts}]
|
||||
set_output_delay 0 [get_ports {uart_txd uart_rts}]
|
||||
set_false_path -from [get_ports {uart_rxd uart_cts}]
|
||||
set_input_delay 0 [get_ports {uart_rxd uart_cts}]
|
||||
|
||||
# GTX for Ethernet
|
||||
set_property -dict {LOC G4 } [get_ports sfp_rx_p] ;# MGTXRXP2_117 GTXE2_CHANNEL_X0Y10 / GTXE2_COMMON_X0Y2 from P5.13
|
||||
set_property -dict {LOC G3 } [get_ports sfp_rx_n] ;# MGTXRXN2_117 GTXE2_CHANNEL_X0Y10 / GTXE2_COMMON_X0Y2 from P5.12
|
||||
set_property -dict {LOC H2 } [get_ports sfp_tx_p] ;# MGTXTXP2_117 GTXE2_CHANNEL_X0Y10 / GTXE2_COMMON_X0Y2 from P5.18
|
||||
set_property -dict {LOC H1 } [get_ports sfp_tx_n] ;# MGTXTXN2_117 GTXE2_CHANNEL_X0Y10 / GTXE2_COMMON_X0Y2 from P5.19
|
||||
set_property -dict {LOC H6 } [get_ports phy_sgmii_rx_p] ;# MGTXRXP1_117 GTXE2_CHANNEL_X0Y9 / GTXE2_COMMON_X0Y2 from U37.A7 SOUT_P
|
||||
set_property -dict {LOC H5 } [get_ports phy_sgmii_rx_n] ;# MGTXRXN1_117 GTXE2_CHANNEL_X0Y9 / GTXE2_COMMON_X0Y2 from U37.A8 SOUT_N
|
||||
set_property -dict {LOC J4 } [get_ports phy_sgmii_tx_p] ;# MGTXTXP1_117 GTXE2_CHANNEL_X0Y9 / GTXE2_COMMON_X0Y2 from U37.A3 SIN_P
|
||||
set_property -dict {LOC J3 } [get_ports phy_sgmii_tx_n] ;# MGTXTXN1_117 GTXE2_CHANNEL_X0Y9 / GTXE2_COMMON_X0Y2 from U37.A4 SIN_N
|
||||
set_property -dict {LOC G8 } [get_ports sgmii_clk_p] ;# MGTREFCLK0P_117 from U2.7
|
||||
set_property -dict {LOC G7 } [get_ports sgmii_clk_n] ;# MGTREFCLK0N_117 from U2.6
|
||||
#set_property -dict {LOC L8 } [get_ports sfp_clk_p] ;# MGTREFCLK0P_116 from Si5324 U70.28 CKOUT1_P
|
||||
#set_property -dict {LOC L7 } [get_ports sfp_clk_n] ;# MGTREFCLK0N_116 from Si5324 U70.29 CKOUT1_N
|
||||
|
||||
set_property -dict {LOC Y20 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports {sfp_tx_disable_b}]
|
||||
|
||||
create_clock -period 8.000 -name sgmii_clk [get_ports sgmii_clk_p]
|
||||
#create_clock -period 6.400 -name sgmii_clk [get_ports sfp_clk_p]
|
||||
|
||||
# Gigabit Ethernet GMII PHY
|
||||
set_property -dict {LOC U27 IOSTANDARD LVCMOS25} [get_ports phy_rx_clk] ;# from U37.C1 RXCLK
|
||||
set_property -dict {LOC U30 IOSTANDARD LVCMOS25} [get_ports {phy_rxd[0]}] ;# from U37.B2 RXD0
|
||||
set_property -dict {LOC U25 IOSTANDARD LVCMOS25} [get_ports {phy_rxd[1]}] ;# from U37.D3 RXD1
|
||||
set_property -dict {LOC T25 IOSTANDARD LVCMOS25} [get_ports {phy_rxd[2]}] ;# from U37.C3 RXD2
|
||||
set_property -dict {LOC U28 IOSTANDARD LVCMOS25} [get_ports {phy_rxd[3]}] ;# from U37.B3 RXD3
|
||||
set_property -dict {LOC R19 IOSTANDARD LVCMOS25} [get_ports {phy_rxd[4]}] ;# from U37.C4 RXD4
|
||||
set_property -dict {LOC T27 IOSTANDARD LVCMOS25} [get_ports {phy_rxd[5]}] ;# from U37.A1 RXD5
|
||||
set_property -dict {LOC T26 IOSTANDARD LVCMOS25} [get_ports {phy_rxd[6]}] ;# from U37.A2 RXD6
|
||||
set_property -dict {LOC T28 IOSTANDARD LVCMOS25} [get_ports {phy_rxd[7]}] ;# from U37.C5 RXD7
|
||||
set_property -dict {LOC R28 IOSTANDARD LVCMOS25} [get_ports phy_rx_dv] ;# from U37.B1 RXCTL_RXDV
|
||||
set_property -dict {LOC V26 IOSTANDARD LVCMOS25} [get_ports phy_rx_er] ;# from U37.D4 RXER
|
||||
set_property -dict {LOC K30 IOSTANDARD LVCMOS25 SLEW FAST DRIVE 16} [get_ports phy_gtx_clk] ;# from U37.E2 TXC_GTXCLK
|
||||
set_property -dict {LOC M28 IOSTANDARD LVCMOS25} [get_ports phy_tx_clk] ;# from U37.D1 TXCLK
|
||||
set_property -dict {LOC N27 IOSTANDARD LVCMOS25 SLEW FAST DRIVE 16} [get_ports {phy_txd[0]}] ;# from U37.F1 TXD0
|
||||
set_property -dict {LOC N25 IOSTANDARD LVCMOS25 SLEW FAST DRIVE 16} [get_ports {phy_txd[1]}] ;# from U37.G2 TXD1
|
||||
set_property -dict {LOC M29 IOSTANDARD LVCMOS25 SLEW FAST DRIVE 16} [get_ports {phy_txd[2]}] ;# from U37.G3 TXD2
|
||||
set_property -dict {LOC L28 IOSTANDARD LVCMOS25 SLEW FAST DRIVE 16} [get_ports {phy_txd[3]}] ;# from U37.H1 TXD3
|
||||
set_property -dict {LOC J26 IOSTANDARD LVCMOS25 SLEW FAST DRIVE 16} [get_ports {phy_txd[4]}] ;# from U37.H2 TXD4
|
||||
set_property -dict {LOC K26 IOSTANDARD LVCMOS25 SLEW FAST DRIVE 16} [get_ports {phy_txd[5]}] ;# from U37.H3 TXD5
|
||||
set_property -dict {LOC L30 IOSTANDARD LVCMOS25 SLEW FAST DRIVE 16} [get_ports {phy_txd[6]}] ;# from U37.J1 TXD6
|
||||
set_property -dict {LOC J28 IOSTANDARD LVCMOS25 SLEW FAST DRIVE 16} [get_ports {phy_txd[7]}] ;# from U37.J2 TXD7
|
||||
set_property -dict {LOC M27 IOSTANDARD LVCMOS25 SLEW FAST DRIVE 16} [get_ports phy_tx_en] ;# from U37.E1 TXCTL_TXEN
|
||||
set_property -dict {LOC N29 IOSTANDARD LVCMOS25 SLEW FAST DRIVE 16} [get_ports phy_tx_er] ;# from U37.F2 TXER
|
||||
set_property -dict {LOC L20 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports phy_reset_n] ;# from U37.K3 RESET_B
|
||||
set_property -dict {LOC N30 IOSTANDARD LVCMOS25} [get_ports phy_int_n] ;# from U37.L1 INT_B
|
||||
#set_property -dict {LOC J21 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports phy_mdio] ;# from U37.M1 MDIO
|
||||
#set_property -dict {LOC R23 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports phy_mdc] ;# from U37.L3 MDC
|
||||
|
||||
create_clock -period 40.000 -name phy_tx_clk [get_ports phy_tx_clk]
|
||||
create_clock -period 8.000 -name phy_rx_clk [get_ports phy_rx_clk]
|
||||
|
||||
set_false_path -to [get_ports {phy_reset_n}]
|
||||
set_output_delay 0 [get_ports {phy_reset_n}]
|
||||
set_false_path -from [get_ports {phy_int_n}]
|
||||
set_input_delay 0 [get_ports {phy_int_n}]
|
||||
|
||||
#set_false_path -to [get_ports {phy_mdio phy_mdc}]
|
||||
#set_output_delay 0 [get_ports {phy_mdio phy_mdc}]
|
||||
#set_false_path -from [get_ports {phy_mdio}]
|
||||
#set_input_delay 0 [get_ports {phy_mdio}]
|
||||
50
example/KC705/fpga/fpga_gmii_1g/Makefile
Normal file
50
example/KC705/fpga/fpga_gmii_1g/Makefile
Normal file
@@ -0,0 +1,50 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
# FPGA settings
|
||||
FPGA_PART = xc7k325tffg900-2
|
||||
FPGA_TOP = fpga
|
||||
FPGA_ARCH = kintex7
|
||||
|
||||
# Files for synthesis
|
||||
SYN_FILES = ../rtl/fpga.sv
|
||||
SYN_FILES += ../rtl/fpga_core.sv
|
||||
SYN_FILES += ../lib/taxi/rtl/eth/taxi_eth_mac_1g_fifo.f
|
||||
SYN_FILES += ../lib/taxi/rtl/eth/taxi_eth_mac_1g_gmii_fifo.f
|
||||
SYN_FILES += ../lib/taxi/rtl/lss/taxi_uart.f
|
||||
SYN_FILES += ../lib/taxi/rtl/sync/taxi_sync_reset.sv
|
||||
SYN_FILES += ../lib/taxi/rtl/sync/taxi_sync_signal.sv
|
||||
SYN_FILES += ../lib/taxi/rtl/io/taxi_debounce_switch.sv
|
||||
|
||||
# XDC files
|
||||
XDC_FILES = ../fpga.xdc
|
||||
XDC_FILES += ../eth_gmii.xdc
|
||||
XDC_FILES += ../lib/taxi/syn/vivado/taxi_eth_mac_1g_gmii.tcl
|
||||
XDC_FILES += ../lib/taxi/syn/vivado/taxi_eth_mac_fifo.tcl
|
||||
XDC_FILES += ../lib/taxi/syn/vivado/taxi_axis_async_fifo.tcl
|
||||
XDC_FILES += ../lib/taxi/syn/vivado/taxi_sync_reset.tcl
|
||||
|
||||
# IP
|
||||
IP_TCL_FILES = ../ip/sgmii_pcs_pma_0.tcl
|
||||
IP_TCL_FILES += ../ip/basex_pcs_pma_0.tcl
|
||||
|
||||
# Configuration
|
||||
CONFIG_TCL_FILES = config.tcl
|
||||
|
||||
include ../common/vivado.mk
|
||||
|
||||
program: $(PROJECT).bit
|
||||
echo "open_hw_manager" > program.tcl
|
||||
echo "connect_hw_server" >> program.tcl
|
||||
echo "open_hw_target" >> program.tcl
|
||||
echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl
|
||||
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl
|
||||
echo "set_property PROGRAM.FILE {$(PROJECT).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
|
||||
26
example/KC705/fpga/fpga_gmii_1g/config.tcl
Normal file
26
example/KC705/fpga/fpga_gmii_1g/config.tcl
Normal file
@@ -0,0 +1,26 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
set params [dict create]
|
||||
|
||||
# Type of PHY on RJ-45 10/100/1000BASE-T port (GMII, RGMII, or SGMII)
|
||||
dict set params BASET_PHY_TYPE "GMII"
|
||||
|
||||
# Invert polarity for SFP+ cage
|
||||
# KC705 rev 1.0: diff pairs to SFP+ are polarity-swapped
|
||||
dict set params SFP_INVERT "1"
|
||||
# KC705 rev 1.1: diff pairs to SFP+ are correct
|
||||
#dict set params SFP_INVERT "0"
|
||||
|
||||
# apply parameters to top-level
|
||||
set param_list {}
|
||||
dict for {name value} $params {
|
||||
lappend param_list $name=$value
|
||||
}
|
||||
|
||||
set_property generic $param_list [get_filesets sources_1]
|
||||
51
example/KC705/fpga/fpga_rgmii_1g/Makefile
Normal file
51
example/KC705/fpga/fpga_rgmii_1g/Makefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
# FPGA settings
|
||||
FPGA_PART = xc7k325tffg900-2
|
||||
FPGA_TOP = fpga
|
||||
FPGA_ARCH = kintex7
|
||||
|
||||
# Files for synthesis
|
||||
SYN_FILES = ../rtl/fpga.sv
|
||||
SYN_FILES += ../rtl/fpga_core.sv
|
||||
SYN_FILES += ../lib/taxi/rtl/eth/taxi_eth_mac_1g_fifo.f
|
||||
SYN_FILES += ../lib/taxi/rtl/eth/taxi_eth_mac_1g_rgmii_fifo.f
|
||||
SYN_FILES += ../lib/taxi/rtl/lss/taxi_uart.f
|
||||
SYN_FILES += ../lib/taxi/rtl/sync/taxi_sync_reset.sv
|
||||
SYN_FILES += ../lib/taxi/rtl/sync/taxi_sync_signal.sv
|
||||
SYN_FILES += ../lib/taxi/rtl/io/taxi_debounce_switch.sv
|
||||
|
||||
# XDC files
|
||||
XDC_FILES = ../fpga.xdc
|
||||
XDC_FILES += ../eth_rgmii.xdc
|
||||
XDC_FILES += ../lib/taxi/syn/vivado/taxi_rgmii_phy_if.tcl
|
||||
XDC_FILES += ../lib/taxi/syn/vivado/taxi_eth_mac_1g_rgmii.tcl
|
||||
XDC_FILES += ../lib/taxi/syn/vivado/taxi_eth_mac_fifo.tcl
|
||||
XDC_FILES += ../lib/taxi/syn/vivado/taxi_axis_async_fifo.tcl
|
||||
XDC_FILES += ../lib/taxi/syn/vivado/taxi_sync_reset.tcl
|
||||
|
||||
# IP
|
||||
IP_TCL_FILES = ../ip/sgmii_pcs_pma_0.tcl
|
||||
IP_TCL_FILES += ../ip/basex_pcs_pma_0.tcl
|
||||
|
||||
# Configuration
|
||||
CONFIG_TCL_FILES = ./config.tcl
|
||||
|
||||
include ../common/vivado.mk
|
||||
|
||||
program: $(PROJECT).bit
|
||||
echo "open_hw_manager" > program.tcl
|
||||
echo "connect_hw_server" >> program.tcl
|
||||
echo "open_hw_target" >> program.tcl
|
||||
echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl
|
||||
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl
|
||||
echo "set_property PROGRAM.FILE {$(PROJECT).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
|
||||
26
example/KC705/fpga/fpga_rgmii_1g/config.tcl
Normal file
26
example/KC705/fpga/fpga_rgmii_1g/config.tcl
Normal file
@@ -0,0 +1,26 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
set params [dict create]
|
||||
|
||||
# Type of PHY on RJ-45 10/100/1000BASE-T port (GMII, RGMII, or SGMII)
|
||||
dict set params BASET_PHY_TYPE "RGMII"
|
||||
|
||||
# Invert polarity for SFP+ cage
|
||||
# KC705 rev 1.0: diff pairs to SFP+ are polarity-swapped
|
||||
dict set params SFP_INVERT "1"
|
||||
# KC705 rev 1.1: diff pairs to SFP+ are correct
|
||||
#dict set params SFP_INVERT "0"
|
||||
|
||||
# apply parameters to top-level
|
||||
set param_list {}
|
||||
dict for {name value} $params {
|
||||
lappend param_list $name=$value
|
||||
}
|
||||
|
||||
set_property generic $param_list [get_filesets sources_1]
|
||||
21
example/KC705/fpga/fpga_rgmii_1g/generate_bit_iodelay.tcl
Normal file
21
example/KC705/fpga/fpga_rgmii_1g/generate_bit_iodelay.tcl
Normal file
@@ -0,0 +1,21 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
# Generate bit file with different IODELAY settings without rebuilding the full project
|
||||
|
||||
open_project fpga.xpr
|
||||
open_run impl_1
|
||||
|
||||
# IDELAY from PHY chip (RGMII)
|
||||
set_property IDELAY_VALUE 0 [get_cells {phy_if.phy_rx_ctl_idelay phy_if.phy_rxd_idelay_bit[*].idelay_inst}]
|
||||
|
||||
# MMCM phase (RGMII)
|
||||
set_property CLKOUT1_PHASE 90 [get_cells clk_mmcm_inst]
|
||||
|
||||
write_bitstream -force fpga.bit
|
||||
exit
|
||||
47
example/KC705/fpga/fpga_sgmii_1g/Makefile
Normal file
47
example/KC705/fpga/fpga_sgmii_1g/Makefile
Normal file
@@ -0,0 +1,47 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
# FPGA settings
|
||||
FPGA_PART = xc7k325tffg900-2
|
||||
FPGA_TOP = fpga
|
||||
FPGA_ARCH = kintex7
|
||||
|
||||
# Files for synthesis
|
||||
SYN_FILES = ../rtl/fpga.sv
|
||||
SYN_FILES += ../rtl/fpga_core.sv
|
||||
SYN_FILES += ../lib/taxi/rtl/eth/taxi_eth_mac_1g_fifo.f
|
||||
SYN_FILES += ../lib/taxi/rtl/lss/taxi_uart.f
|
||||
SYN_FILES += ../lib/taxi/rtl/sync/taxi_sync_reset.sv
|
||||
SYN_FILES += ../lib/taxi/rtl/sync/taxi_sync_signal.sv
|
||||
SYN_FILES += ../lib/taxi/rtl/io/taxi_debounce_switch.sv
|
||||
|
||||
# XDC files
|
||||
XDC_FILES = ../fpga.xdc
|
||||
XDC_FILES += ../lib/taxi/syn/vivado/taxi_eth_mac_fifo.tcl
|
||||
XDC_FILES += ../lib/taxi/syn/vivado/taxi_axis_async_fifo.tcl
|
||||
XDC_FILES += ../lib/taxi/syn/vivado/taxi_sync_reset.tcl
|
||||
|
||||
# IP
|
||||
IP_TCL_FILES = ../ip/sgmii_pcs_pma_0.tcl
|
||||
IP_TCL_FILES += ../ip/basex_pcs_pma_0.tcl
|
||||
|
||||
# Configuration
|
||||
CONFIG_TCL_FILES = ./config.tcl
|
||||
|
||||
include ../common/vivado.mk
|
||||
|
||||
program: $(PROJECT).bit
|
||||
echo "open_hw_manager" > program.tcl
|
||||
echo "connect_hw_server" >> program.tcl
|
||||
echo "open_hw_target" >> program.tcl
|
||||
echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl
|
||||
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl
|
||||
echo "set_property PROGRAM.FILE {$(PROJECT).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
|
||||
26
example/KC705/fpga/fpga_sgmii_1g/config.tcl
Normal file
26
example/KC705/fpga/fpga_sgmii_1g/config.tcl
Normal file
@@ -0,0 +1,26 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
set params [dict create]
|
||||
|
||||
# Type of PHY on RJ-45 10/100/1000BASE-T port (GMII, RGMII, or SGMII)
|
||||
dict set params BASET_PHY_TYPE "SGMII"
|
||||
|
||||
# Invert polarity for SFP+ cage
|
||||
# KC705 rev 1.0: diff pairs to SFP+ are polarity-swapped
|
||||
dict set params SFP_INVERT "1"
|
||||
# KC705 rev 1.1: diff pairs to SFP+ are correct
|
||||
#dict set params SFP_INVERT "0"
|
||||
|
||||
# apply parameters to top-level
|
||||
set param_list {}
|
||||
dict for {name value} $params {
|
||||
lappend param_list $name=$value
|
||||
}
|
||||
|
||||
set_property generic $param_list [get_filesets sources_1]
|
||||
18
example/KC705/fpga/ip/basex_pcs_pma_0.tcl
Normal file
18
example/KC705/fpga/ip/basex_pcs_pma_0.tcl
Normal file
@@ -0,0 +1,18 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
create_ip -name gig_ethernet_pcs_pma -vendor xilinx.com -library ip -module_name basex_pcs_pma_0
|
||||
|
||||
set_property -dict [list \
|
||||
CONFIG.Standard {1000BASEX} \
|
||||
CONFIG.Physical_Interface {Transceiver} \
|
||||
CONFIG.Management_Interface {false} \
|
||||
CONFIG.Auto_Negotiation {false} \
|
||||
CONFIG.TransceiverControl {true} \
|
||||
CONFIG.SupportLevel {Include_Shared_Logic_in_Example_Design} \
|
||||
] [get_ips basex_pcs_pma_0]
|
||||
16
example/KC705/fpga/ip/sgmii_pcs_pma_0.tcl
Normal file
16
example/KC705/fpga/ip/sgmii_pcs_pma_0.tcl
Normal file
@@ -0,0 +1,16 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (c) 2025 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
#
|
||||
|
||||
create_ip -name gig_ethernet_pcs_pma -vendor xilinx.com -library ip -module_name sgmii_pcs_pma_0
|
||||
|
||||
set_property -dict [list \
|
||||
CONFIG.Standard {SGMII} \
|
||||
CONFIG.Physical_Interface {Transceiver} \
|
||||
CONFIG.Management_Interface {false} \
|
||||
CONFIG.SupportLevel {Include_Shared_Logic_in_Core} \
|
||||
] [get_ips sgmii_pcs_pma_0]
|
||||
1
example/KC705/fpga/lib/taxi
Symbolic link
1
example/KC705/fpga/lib/taxi
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../../
|
||||
708
example/KC705/fpga/rtl/fpga.sv
Normal file
708
example/KC705/fpga/rtl/fpga.sv
Normal file
@@ -0,0 +1,708 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
|
||||
Copyright (c) 2014-2025 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
`resetall
|
||||
`timescale 1ns / 1ps
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* FPGA top-level module
|
||||
*/
|
||||
module fpga #
|
||||
(
|
||||
// simulation (set to avoid vendor primitives)
|
||||
parameter logic SIM = 1'b0,
|
||||
// vendor ("GENERIC", "XILINX", "ALTERA")
|
||||
parameter VENDOR = "XILINX",
|
||||
// device family
|
||||
parameter FAMILY = "kintex7",
|
||||
// Use 90 degree clock for RGMII transmit
|
||||
parameter logic USE_CLK90 = 1'b1,
|
||||
// BASE-T PHY type (GMII, RGMII, SGMII)
|
||||
parameter BASET_PHY_TYPE = "GMII",
|
||||
// Invert SFP data pins
|
||||
parameter logic SFP_INVERT = 1'b1
|
||||
)
|
||||
(
|
||||
/*
|
||||
* Clock: 200MHz
|
||||
* Reset: Push button, active high
|
||||
*/
|
||||
input wire logic clk_200mhz_p,
|
||||
input wire logic clk_200mhz_n,
|
||||
input wire logic reset,
|
||||
|
||||
/*
|
||||
* GPIO
|
||||
*/
|
||||
input wire logic btnu,
|
||||
input wire logic btnl,
|
||||
input wire logic btnd,
|
||||
input wire logic btnr,
|
||||
input wire logic btnc,
|
||||
input wire logic [3:0] sw,
|
||||
output wire logic [7:0] led,
|
||||
|
||||
/*
|
||||
* UART: 115200 bps, 8N1
|
||||
*/
|
||||
input wire logic uart_rxd,
|
||||
output wire logic uart_txd,
|
||||
output wire logic uart_rts,
|
||||
input wire logic uart_cts,
|
||||
|
||||
/*
|
||||
* Ethernet: SFP+
|
||||
*/
|
||||
input wire logic sfp_rx_p,
|
||||
input wire logic sfp_rx_n,
|
||||
output wire logic sfp_tx_p,
|
||||
output wire logic sfp_tx_n,
|
||||
input wire logic phy_sgmii_rx_p,
|
||||
input wire logic phy_sgmii_rx_n,
|
||||
output wire logic phy_sgmii_tx_p,
|
||||
output wire logic phy_sgmii_tx_n,
|
||||
input wire logic sgmii_clk_p,
|
||||
input wire logic sgmii_clk_n,
|
||||
|
||||
output wire logic sfp_tx_disable_b,
|
||||
|
||||
/*
|
||||
* Ethernet: 1000BASE-T GMII, RGMII, or SGMII
|
||||
*/
|
||||
input wire logic phy_rx_clk,
|
||||
input wire logic [7:0] phy_rxd,
|
||||
input wire logic phy_rx_dv,
|
||||
input wire logic phy_rx_er,
|
||||
output wire logic phy_gtx_clk,
|
||||
input wire logic phy_tx_clk,
|
||||
output wire logic [7:0] phy_txd,
|
||||
output wire logic phy_tx_en,
|
||||
output wire logic phy_tx_er,
|
||||
output wire logic phy_reset_n,
|
||||
input wire logic phy_int_n
|
||||
);
|
||||
|
||||
// Clock and reset
|
||||
|
||||
wire clk_200mhz_ibufg;
|
||||
|
||||
// Internal 125 MHz clock
|
||||
wire clk_mmcm_out;
|
||||
wire clk_int;
|
||||
wire clk90_mmcm_out;
|
||||
wire clk90_int;
|
||||
wire rst_int;
|
||||
|
||||
wire clk_200mhz_mmcm_out;
|
||||
wire clk_200mhz_int;
|
||||
|
||||
wire mmcm_rst = reset;
|
||||
wire mmcm_locked;
|
||||
wire mmcm_clkfb;
|
||||
|
||||
IBUFGDS
|
||||
clk_200mhz_ibufgds_inst(
|
||||
.I(clk_200mhz_p),
|
||||
.IB(clk_200mhz_n),
|
||||
.O(clk_200mhz_ibufg)
|
||||
);
|
||||
|
||||
// MMCM instance
|
||||
MMCME2_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 600 MHz to 1440 MHz)
|
||||
.CLKFBOUT_MULT_F(5),
|
||||
.CLKFBOUT_PHASE(0),
|
||||
// 1250 MHz VCO / 8 = 125 MHz, 0 degrees
|
||||
.CLKOUT0_DIVIDE_F(8),
|
||||
.CLKOUT0_DUTY_CYCLE(0.5),
|
||||
.CLKOUT0_PHASE(0),
|
||||
// 1250 MHz VCO / 8 = 125 MHz, 90 degrees
|
||||
.CLKOUT1_DIVIDE(8),
|
||||
.CLKOUT1_DUTY_CYCLE(0.5),
|
||||
.CLKOUT1_PHASE(90),
|
||||
// 1250 MHz VCO / 5 = 200 MHz, 0 degrees
|
||||
.CLKOUT2_DIVIDE(5),
|
||||
.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(clk_200mhz_ibufg),
|
||||
// direct clkfb feeback
|
||||
.CLKFBIN(mmcm_clkfb),
|
||||
.CLKFBOUT(mmcm_clkfb),
|
||||
.CLKFBOUTB(),
|
||||
// 125 MHz, 0 degrees
|
||||
.CLKOUT0(clk_mmcm_out),
|
||||
.CLKOUT0B(),
|
||||
// 125 MHz, 90 degrees
|
||||
.CLKOUT1(clk90_mmcm_out),
|
||||
.CLKOUT1B(),
|
||||
// 200 MHz, 0 degrees
|
||||
.CLKOUT2(clk_200mhz_mmcm_out),
|
||||
.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_bufg_inst (
|
||||
.I(clk_mmcm_out),
|
||||
.O(clk_int)
|
||||
);
|
||||
|
||||
BUFG
|
||||
clk90_bufg_inst (
|
||||
.I(clk90_mmcm_out),
|
||||
.O(clk90_int)
|
||||
);
|
||||
|
||||
BUFG
|
||||
clk_200mhz_bufg_inst (
|
||||
.I(clk_200mhz_mmcm_out),
|
||||
.O(clk_200mhz_int)
|
||||
);
|
||||
|
||||
taxi_sync_reset #(
|
||||
.N(4)
|
||||
)
|
||||
sync_reset_inst (
|
||||
.clk(clk_int),
|
||||
.rst(~mmcm_locked),
|
||||
.out(rst_int)
|
||||
);
|
||||
|
||||
// GPIO
|
||||
wire btnu_int;
|
||||
wire btnl_int;
|
||||
wire btnd_int;
|
||||
wire btnr_int;
|
||||
wire btnc_int;
|
||||
wire [3:0] sw_int;
|
||||
|
||||
taxi_debounce_switch #(
|
||||
.WIDTH(9),
|
||||
.N(4),
|
||||
.RATE(125000)
|
||||
)
|
||||
debounce_switch_inst (
|
||||
.clk(clk_int),
|
||||
.rst(rst_int),
|
||||
.in({btnu,
|
||||
btnl,
|
||||
btnd,
|
||||
btnr,
|
||||
btnc,
|
||||
sw}),
|
||||
.out({btnu_int,
|
||||
btnl_int,
|
||||
btnd_int,
|
||||
btnr_int,
|
||||
btnc_int,
|
||||
sw_int})
|
||||
);
|
||||
|
||||
wire uart_rxd_int;
|
||||
wire uart_cts_int;
|
||||
|
||||
taxi_sync_signal #(
|
||||
.WIDTH(2),
|
||||
.N(2)
|
||||
)
|
||||
sync_signal_inst (
|
||||
.clk(clk_int),
|
||||
.in({uart_rxd, uart_cts}),
|
||||
.out({uart_rxd_int, uart_cts_int})
|
||||
);
|
||||
|
||||
wire [7:0] led_int;
|
||||
|
||||
// SGMII interface to PHY
|
||||
wire phy_sgmii_clk_int;
|
||||
wire phy_sgmii_rst_int;
|
||||
wire phy_sgmii_clk_en_int;
|
||||
wire [7:0] phy_sgmii_txd_int;
|
||||
wire phy_sgmii_tx_en_int;
|
||||
wire phy_sgmii_tx_er_int;
|
||||
wire [7:0] phy_sgmii_rxd_int;
|
||||
wire phy_sgmii_rx_dv_int;
|
||||
wire phy_sgmii_rx_er_int;
|
||||
|
||||
wire sgmii_gtrefclk;
|
||||
wire sgmii_gtrefclk_bufg;
|
||||
wire sgmii_txuserclk;
|
||||
wire sgmii_txuserclk2;
|
||||
wire sgmii_rxuserclk;
|
||||
wire sgmii_rxuserclk2;
|
||||
wire sgmii_pma_reset;
|
||||
wire sgmii_mmcm_locked;
|
||||
|
||||
wire phy_sgmii_resetdone;
|
||||
|
||||
assign phy_sgmii_clk_int = sgmii_txuserclk2;
|
||||
|
||||
taxi_sync_reset #(
|
||||
.N(4)
|
||||
)
|
||||
sync_reset_sgmii_inst (
|
||||
.clk(phy_sgmii_clk_int),
|
||||
.rst(rst_int || !phy_sgmii_resetdone),
|
||||
.out(phy_sgmii_rst_int)
|
||||
);
|
||||
|
||||
wire [15:0] sgmii_status_vect;
|
||||
|
||||
wire sgmii_status_link_status = sgmii_status_vect[0];
|
||||
wire sgmii_status_link_synchronization = sgmii_status_vect[1];
|
||||
wire sgmii_status_rudi_c = sgmii_status_vect[2];
|
||||
wire sgmii_status_rudi_i = sgmii_status_vect[3];
|
||||
wire sgmii_status_rudi_invalid = sgmii_status_vect[4];
|
||||
wire sgmii_status_rxdisperr = sgmii_status_vect[5];
|
||||
wire sgmii_status_rxnotintable = sgmii_status_vect[6];
|
||||
wire sgmii_status_phy_link_status = sgmii_status_vect[7];
|
||||
wire [1:0] sgmii_status_remote_fault_encdg = sgmii_status_vect[9:8];
|
||||
wire [1:0] sgmii_status_speed = sgmii_status_vect[11:10];
|
||||
wire sgmii_status_duplex = sgmii_status_vect[12];
|
||||
wire sgmii_status_remote_fault = sgmii_status_vect[13];
|
||||
wire [1:0] sgmii_status_pause = sgmii_status_vect[15:14];
|
||||
|
||||
wire [4:0] sgmii_config_vect;
|
||||
|
||||
assign sgmii_config_vect[4] = 1'b1; // autonegotiation enable
|
||||
assign sgmii_config_vect[3] = 1'b0; // isolate
|
||||
assign sgmii_config_vect[2] = 1'b0; // power down
|
||||
assign sgmii_config_vect[1] = 1'b0; // loopback enable
|
||||
assign sgmii_config_vect[0] = 1'b0; // unidirectional enable
|
||||
|
||||
wire [15:0] sgmii_an_config_vect;
|
||||
|
||||
assign sgmii_an_config_vect[15] = 1'b1; // SGMII link status
|
||||
assign sgmii_an_config_vect[14] = 1'b1; // SGMII Acknowledge
|
||||
assign sgmii_an_config_vect[13:12] = 2'b01; // full duplex
|
||||
assign sgmii_an_config_vect[11:10] = 2'b10; // SGMII speed
|
||||
assign sgmii_an_config_vect[9] = 1'b0; // reserved
|
||||
assign sgmii_an_config_vect[8:7] = 2'b00; // pause frames - SGMII reserved
|
||||
assign sgmii_an_config_vect[6] = 1'b0; // reserved
|
||||
assign sgmii_an_config_vect[5] = 1'b0; // full duplex - SGMII reserved
|
||||
assign sgmii_an_config_vect[4:1] = 4'b0000; // reserved
|
||||
assign sgmii_an_config_vect[0] = 1'b1; // SGMII
|
||||
|
||||
sgmii_pcs_pma_0
|
||||
sgmii_pcspma (
|
||||
// Transceiver Interface
|
||||
.gtrefclk_p (sgmii_clk_p),
|
||||
.gtrefclk_n (sgmii_clk_n),
|
||||
.gtrefclk_out (sgmii_gtrefclk),
|
||||
.gtrefclk_bufg_out (sgmii_gtrefclk_bufg),
|
||||
.txp (phy_sgmii_tx_p),
|
||||
.txn (phy_sgmii_tx_n),
|
||||
.rxp (phy_sgmii_rx_p),
|
||||
.rxn (phy_sgmii_rx_n),
|
||||
.resetdone (phy_sgmii_resetdone),
|
||||
.userclk_out (sgmii_txuserclk),
|
||||
.userclk2_out (sgmii_txuserclk2),
|
||||
.rxuserclk_out (sgmii_rxuserclk),
|
||||
.rxuserclk2_out (sgmii_rxuserclk2),
|
||||
.independent_clock_bufg(clk_int),
|
||||
.pma_reset_out (sgmii_pma_reset),
|
||||
.mmcm_locked_out (sgmii_mmcm_locked),
|
||||
.gt0_qplloutclk_out (),
|
||||
.gt0_qplloutrefclk_out (),
|
||||
// GMII Interface
|
||||
.sgmii_clk_r (),
|
||||
.sgmii_clk_f (),
|
||||
.sgmii_clk_en (phy_sgmii_clk_en_int),
|
||||
.gmii_txd (phy_sgmii_txd_int),
|
||||
.gmii_tx_en (phy_sgmii_tx_en_int),
|
||||
.gmii_tx_er (phy_sgmii_tx_er_int),
|
||||
.gmii_rxd (phy_sgmii_rxd_int),
|
||||
.gmii_rx_dv (phy_sgmii_rx_dv_int),
|
||||
.gmii_rx_er (phy_sgmii_rx_er_int),
|
||||
.gmii_isolate (),
|
||||
// Management: Alternative to MDIO Interface
|
||||
.configuration_vector (sgmii_config_vect),
|
||||
.an_interrupt (),
|
||||
.an_adv_config_vector (sgmii_an_config_vect),
|
||||
.an_restart_config (1'b0),
|
||||
// Speed Control
|
||||
.speed_is_10_100 (sgmii_status_speed != 2'b10),
|
||||
.speed_is_100 (sgmii_status_speed == 2'b01),
|
||||
// General IO's
|
||||
.status_vector (sgmii_status_vect),
|
||||
.reset (rst_int),
|
||||
.signal_detect (1'b1)
|
||||
);
|
||||
|
||||
// 1000BASE-X SFP
|
||||
wire sfp_gmii_clk_int;
|
||||
wire sfp_gmii_rst_int;
|
||||
wire sfp_gmii_clk_en_int;
|
||||
wire [7:0] sfp_gmii_txd_int;
|
||||
wire sfp_gmii_tx_en_int;
|
||||
wire sfp_gmii_tx_er_int;
|
||||
wire [7:0] sfp_gmii_rxd_int;
|
||||
wire sfp_gmii_rx_dv_int;
|
||||
wire sfp_gmii_rx_er_int;
|
||||
|
||||
wire sfp_gmii_txuserclk2 = sgmii_txuserclk2;
|
||||
wire sfp_gmii_resetdone;
|
||||
|
||||
assign sfp_gmii_clk_int = sfp_gmii_txuserclk2;
|
||||
|
||||
taxi_sync_reset #(
|
||||
.N(4)
|
||||
)
|
||||
sync_reset_sfp_inst (
|
||||
.clk(sfp_gmii_clk_int),
|
||||
.rst(rst_int || !sfp_gmii_resetdone),
|
||||
.out(sfp_gmii_rst_int)
|
||||
);
|
||||
|
||||
wire [15:0] sfp_status_vect;
|
||||
|
||||
wire sfp_status_link_status = sfp_status_vect[0];
|
||||
wire sfp_status_link_synchronization = sfp_status_vect[1];
|
||||
wire sfp_status_rudi_c = sfp_status_vect[2];
|
||||
wire sfp_status_rudi_i = sfp_status_vect[3];
|
||||
wire sfp_status_rudi_invalid = sfp_status_vect[4];
|
||||
wire sfp_status_rxdisperr = sfp_status_vect[5];
|
||||
wire sfp_status_rxnotintable = sfp_status_vect[6];
|
||||
wire sfp_status_phy_link_status = sfp_status_vect[7];
|
||||
wire [1:0] sfp_status_remote_fault_encdg = sfp_status_vect[9:8];
|
||||
wire [1:0] sfp_status_speed = sfp_status_vect[11:10];
|
||||
wire sfp_status_duplex = sfp_status_vect[12];
|
||||
wire sfp_status_remote_fault = sfp_status_vect[13];
|
||||
wire [1:0] sfp_status_pause = sfp_status_vect[15:14];
|
||||
|
||||
wire [4:0] sfp_config_vect;
|
||||
|
||||
assign sfp_config_vect[4] = 1'b0; // autonegotiation enable
|
||||
assign sfp_config_vect[3] = 1'b0; // isolate
|
||||
assign sfp_config_vect[2] = 1'b0; // power down
|
||||
assign sfp_config_vect[1] = 1'b0; // loopback enable
|
||||
assign sfp_config_vect[0] = 1'b0; // unidirectional enable
|
||||
|
||||
basex_pcs_pma_0 your_instance_name (
|
||||
// Transceiver Interface
|
||||
.gtrefclk(sgmii_gtrefclk),
|
||||
.gtrefclk_bufg(sgmii_gtrefclk_bufg),
|
||||
.txp(sfp_tx_p),
|
||||
.txn(sfp_tx_n),
|
||||
.rxp(sfp_rx_p),
|
||||
.rxn(sfp_rx_n),
|
||||
.independent_clock_bufg(clk_int),
|
||||
.txoutclk(),
|
||||
.rxoutclk(),
|
||||
.resetdone(sfp_gmii_resetdone),
|
||||
.cplllock(),
|
||||
.mmcm_reset(),
|
||||
.userclk(sgmii_txuserclk),
|
||||
.userclk2(sgmii_txuserclk2),
|
||||
.pma_reset(sgmii_pma_reset),
|
||||
.mmcm_locked(sgmii_mmcm_locked),
|
||||
.rxuserclk(sgmii_rxuserclk),
|
||||
.rxuserclk2(sgmii_rxuserclk2),
|
||||
// GMII Interface
|
||||
.gmii_txd(sfp_gmii_txd_int),
|
||||
.gmii_tx_en(sfp_gmii_tx_en_int),
|
||||
.gmii_tx_er(sfp_gmii_tx_er_int),
|
||||
.gmii_rxd(sfp_gmii_rxd_int),
|
||||
.gmii_rx_dv(sfp_gmii_rx_dv_int),
|
||||
.gmii_rx_er(sfp_gmii_rx_er_int),
|
||||
.gmii_isolate(),
|
||||
// Management: Alternative to MDIO Interface
|
||||
.configuration_vector(sfp_config_vect),
|
||||
// General IO's
|
||||
.status_vector(sfp_status_vect),
|
||||
.reset(rst_int),
|
||||
.signal_detect(1'b1),
|
||||
|
||||
.gt0_qplloutclk_in(1'b0),
|
||||
.gt0_qplloutrefclk_in(1'b0),
|
||||
.gt0_rxchariscomma_out(),
|
||||
.gt0_rxcharisk_out(),
|
||||
.gt0_rxbyteisaligned_out(),
|
||||
.gt0_rxbyterealign_out(),
|
||||
.gt0_rxcommadet_out(),
|
||||
.gt0_txpolarity_in(SFP_INVERT),
|
||||
.gt0_txdiffctrl_in(4'b1000),
|
||||
.gt0_txpostcursor_in(5'b00000),
|
||||
.gt0_txprecursor_in(5'b00000),
|
||||
.gt0_rxpolarity_in(SFP_INVERT),
|
||||
.gt0_txinhibit_in(1'b0),
|
||||
.gt0_txprbssel_in(3'b000),
|
||||
.gt0_txprbsforceerr_in(1'b0),
|
||||
.gt0_rxprbscntreset_in(1'b0),
|
||||
.gt0_rxprbserr_out(),
|
||||
.gt0_rxprbssel_in(3'b000),
|
||||
.gt0_loopback_in(3'b000),
|
||||
.gt0_txresetdone_out(),
|
||||
.gt0_rxresetdone_out(),
|
||||
.gt0_rxdisperr_out(),
|
||||
.gt0_txbufstatus_out(),
|
||||
.gt0_rxnotintable_out(),
|
||||
.gt0_eyescanreset_in(1'b0),
|
||||
.gt0_eyescandataerror_out(),
|
||||
.gt0_eyescantrigger_in(1'b0),
|
||||
.gt0_rxcdrhold_in(1'b0),
|
||||
.gt0_rxpmareset_in(1'b0),
|
||||
.gt0_txpmareset_in(1'b0),
|
||||
.gt0_rxpcsreset_in(1'b0),
|
||||
.gt0_txpcsreset_in(1'b0),
|
||||
.gt0_rxbufreset_in(1'b0),
|
||||
.gt0_rxbufstatus_out(),
|
||||
.gt0_rxdfelpmreset_in(1'b0),
|
||||
.gt0_rxdfeagcovrden_in(1'b0),
|
||||
.gt0_rxlpmen_in(1'b1),
|
||||
.gt0_rxmonitorout_out(),
|
||||
.gt0_rxmonitorsel_in(2'b00),
|
||||
.gt0_drpaddr_in(9'd0),
|
||||
.gt0_drpclk_in(1'b0),
|
||||
.gt0_drpdi_in(9'd0),
|
||||
.gt0_drpdo_out(),
|
||||
.gt0_drpen_in(1'b0),
|
||||
.gt0_drprdy_out(),
|
||||
.gt0_drpwe_in(1'b0),
|
||||
.gt0_dmonitorout_out()
|
||||
);
|
||||
|
||||
assign sfp_gmii_clk_en_int = 1'b1;
|
||||
|
||||
// SGMII interface debug:
|
||||
// SW1:1 (sw[0]) off for payload byte, on for status vector
|
||||
// SW1:2 (sw[1]) off for LSB of status vector, on for MSB
|
||||
assign led = sw[3] ? (sw[2] ? sfp_status_vect[15:8] : sfp_status_vect[7:0]) : led_int;
|
||||
|
||||
wire phy_rgmii_rx_clk_int;
|
||||
wire [3:0] phy_rgmii_rxd_int;
|
||||
wire phy_rgmii_rx_ctl_int;
|
||||
wire phy_rgmii_tx_clk_int;
|
||||
wire [3:0] phy_rgmii_txd_int;
|
||||
wire phy_rgmii_tx_ctl_int;
|
||||
|
||||
wire phy_gmii_rx_clk_int;
|
||||
wire [7:0] phy_gmii_rxd_int;
|
||||
wire phy_gmii_rx_dv_int;
|
||||
wire phy_gmii_rx_er_int;
|
||||
wire phy_gmii_gtx_clk_int;
|
||||
wire phy_gmii_tx_clk_int;
|
||||
wire [7:0] phy_gmii_txd_int;
|
||||
wire phy_gmii_tx_en_int;
|
||||
wire phy_gmii_tx_er_int;
|
||||
|
||||
if (BASET_PHY_TYPE == "RGMII") begin : phy_if
|
||||
|
||||
assign phy_rgmii_rx_clk_int = phy_rx_clk;
|
||||
|
||||
// IODELAY elements for RGMII interface to PHY
|
||||
IDELAYCTRL
|
||||
idelayctrl_inst (
|
||||
.REFCLK(clk_200mhz_int),
|
||||
.RST(rst_int),
|
||||
.RDY()
|
||||
);
|
||||
|
||||
for (genvar n = 0; n < 4; n = n + 1) begin : phy_rxd_idelay_bit
|
||||
|
||||
IDELAYE2 #(
|
||||
.IDELAY_TYPE("FIXED")
|
||||
)
|
||||
idelay_inst (
|
||||
.IDATAIN(phy_rxd[n]),
|
||||
.DATAOUT(phy_rgmii_rxd_int[n]),
|
||||
.DATAIN(1'b0),
|
||||
.C(1'b0),
|
||||
.CE(1'b0),
|
||||
.INC(1'b0),
|
||||
.CINVCTRL(1'b0),
|
||||
.CNTVALUEIN(5'd0),
|
||||
.CNTVALUEOUT(),
|
||||
.LD(1'b0),
|
||||
.LDPIPEEN(1'b0),
|
||||
.REGRST(1'b0)
|
||||
);
|
||||
|
||||
end
|
||||
|
||||
IDELAYE2 #(
|
||||
.IDELAY_TYPE("FIXED")
|
||||
)
|
||||
phy_rx_ctl_idelay (
|
||||
.IDATAIN(phy_rx_dv),
|
||||
.DATAOUT(phy_rgmii_rx_ctl_int),
|
||||
.DATAIN(1'b0),
|
||||
.C(1'b0),
|
||||
.CE(1'b0),
|
||||
.INC(1'b0),
|
||||
.CINVCTRL(1'b0),
|
||||
.CNTVALUEIN(5'd0),
|
||||
.CNTVALUEOUT(),
|
||||
.LD(1'b0),
|
||||
.LDPIPEEN(1'b0),
|
||||
.REGRST(1'b0)
|
||||
);
|
||||
|
||||
assign phy_gtx_clk = phy_rgmii_tx_clk_int;
|
||||
assign phy_txd[3:0] = phy_rgmii_txd_int;
|
||||
assign phy_tx_en = phy_rgmii_tx_ctl_int;
|
||||
|
||||
assign phy_txd[7:4] = '0;
|
||||
assign phy_tx_er = 1'b0;
|
||||
|
||||
assign phy_gmii_rx_clk_int = 1'b0;
|
||||
assign phy_gmii_rxd_int = '0;
|
||||
assign phy_gmii_rx_dv_int = 1'b0;
|
||||
assign phy_gmii_rx_er_int = 1'b0;
|
||||
assign phy_gmii_tx_clk_int = 1'b0;
|
||||
|
||||
end else begin : phy_if
|
||||
|
||||
assign phy_rgmii_rx_clk_int = 1'b0;
|
||||
assign phy_rgmii_rxd_int = '0;
|
||||
assign phy_rgmii_rx_ctl_int = 1'b0;
|
||||
|
||||
assign phy_gmii_rx_clk_int = phy_rx_clk;
|
||||
assign phy_gmii_rxd_int = phy_rxd;
|
||||
assign phy_gmii_rx_dv_int = phy_rx_dv;
|
||||
assign phy_gmii_rx_er_int = phy_rx_er;
|
||||
|
||||
assign phy_gtx_clk = phy_gmii_gtx_clk_int;
|
||||
assign phy_gmii_tx_clk_int = phy_tx_clk;
|
||||
assign phy_txd = phy_gmii_txd_int;
|
||||
assign phy_tx_en = phy_gmii_tx_en_int;
|
||||
assign phy_tx_er = phy_gmii_tx_er_int;
|
||||
|
||||
end
|
||||
|
||||
fpga_core #(
|
||||
.SIM(SIM),
|
||||
.VENDOR(VENDOR),
|
||||
.FAMILY(FAMILY),
|
||||
.USE_CLK90(USE_CLK90),
|
||||
.BASET_PHY_TYPE(BASET_PHY_TYPE),
|
||||
.SFP_INVERT(SFP_INVERT)
|
||||
)
|
||||
core_inst (
|
||||
/*
|
||||
* Clock: 125MHz
|
||||
* Synchronous reset
|
||||
*/
|
||||
.clk(clk_int),
|
||||
.clk90(clk90_int),
|
||||
.rst(rst_int),
|
||||
|
||||
/*
|
||||
* GPIO
|
||||
*/
|
||||
.btnu(btnu_int),
|
||||
.btnl(btnl_int),
|
||||
.btnd(btnd_int),
|
||||
.btnr(btnr_int),
|
||||
.btnc(btnc_int),
|
||||
.sw(sw_int),
|
||||
.led(led_int),
|
||||
|
||||
/*
|
||||
* UART: 115200 bps, 8N1
|
||||
*/
|
||||
.uart_rxd(uart_rxd_int),
|
||||
.uart_txd(uart_txd),
|
||||
.uart_rts(uart_rts),
|
||||
.uart_cts(uart_cts_int),
|
||||
|
||||
/*
|
||||
* Ethernet: 1000BASE-X SFP
|
||||
*/
|
||||
.sfp_gmii_clk(sfp_gmii_clk_int),
|
||||
.sfp_gmii_rst(sfp_gmii_rst_int),
|
||||
.sfp_gmii_clk_en(sfp_gmii_clk_en_int),
|
||||
.sfp_gmii_rxd(sfp_gmii_rxd_int),
|
||||
.sfp_gmii_rx_dv(sfp_gmii_rx_dv_int),
|
||||
.sfp_gmii_rx_er(sfp_gmii_rx_er_int),
|
||||
.sfp_gmii_txd(sfp_gmii_txd_int),
|
||||
.sfp_gmii_tx_en(sfp_gmii_tx_en_int),
|
||||
.sfp_gmii_tx_er(sfp_gmii_tx_er_int),
|
||||
.sfp_tx_disable_b(sfp_tx_disable_b),
|
||||
|
||||
/*
|
||||
* Ethernet: 1000BASE-T GMII/RGMII/SGMII
|
||||
*/
|
||||
.phy_sgmii_clk(phy_sgmii_clk_int),
|
||||
.phy_sgmii_rst(phy_sgmii_rst_int),
|
||||
.phy_sgmii_clk_en(phy_sgmii_clk_en_int),
|
||||
.phy_sgmii_rxd(phy_sgmii_rxd_int),
|
||||
.phy_sgmii_rx_dv(phy_sgmii_rx_dv_int),
|
||||
.phy_sgmii_rx_er(phy_sgmii_rx_er_int),
|
||||
.phy_sgmii_txd(phy_sgmii_txd_int),
|
||||
.phy_sgmii_tx_en(phy_sgmii_tx_en_int),
|
||||
.phy_sgmii_tx_er(phy_sgmii_tx_er_int),
|
||||
.phy_rgmii_rx_clk(phy_rgmii_rx_clk_int),
|
||||
.phy_rgmii_rxd(phy_rgmii_rxd_int),
|
||||
.phy_rgmii_rx_ctl(phy_rgmii_rx_ctl_int),
|
||||
.phy_rgmii_tx_clk(phy_rgmii_tx_clk_int),
|
||||
.phy_rgmii_txd(phy_rgmii_txd_int),
|
||||
.phy_rgmii_tx_ctl(phy_rgmii_tx_ctl_int),
|
||||
.phy_gmii_rx_clk(phy_gmii_rx_clk_int),
|
||||
.phy_gmii_rxd(phy_gmii_rxd_int),
|
||||
.phy_gmii_rx_dv(phy_gmii_rx_dv_int),
|
||||
.phy_gmii_rx_er(phy_gmii_rx_er_int),
|
||||
.phy_gmii_gtx_clk(phy_gmii_gtx_clk_int),
|
||||
.phy_gmii_tx_clk(phy_gmii_tx_clk_int),
|
||||
.phy_gmii_txd(phy_gmii_txd_int),
|
||||
.phy_gmii_tx_en(phy_gmii_tx_en_int),
|
||||
.phy_gmii_tx_er(phy_gmii_tx_er_int),
|
||||
.phy_reset_n(phy_reset_n),
|
||||
.phy_int_n(phy_int_n)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
||||
453
example/KC705/fpga/rtl/fpga_core.sv
Normal file
453
example/KC705/fpga/rtl/fpga_core.sv
Normal file
@@ -0,0 +1,453 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
|
||||
Copyright (c) 2014-2025 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
`resetall
|
||||
`timescale 1ns / 1ps
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* FPGA core logic
|
||||
*/
|
||||
module fpga_core #
|
||||
(
|
||||
// simulation (set to avoid vendor primitives)
|
||||
parameter logic SIM = 1'b0,
|
||||
// vendor ("GENERIC", "XILINX", "ALTERA")
|
||||
parameter VENDOR = "XILINX",
|
||||
// device family
|
||||
parameter FAMILY = "kintex7",
|
||||
// Use 90 degree clock for RGMII transmit
|
||||
parameter logic USE_CLK90 = 1'b1,
|
||||
// BASE-T PHY type (GMII, RGMII, SGMII)
|
||||
parameter BASET_PHY_TYPE = "GMII",
|
||||
// Invert SFP data pins
|
||||
parameter logic SFP_INVERT = 1'b1
|
||||
)
|
||||
(
|
||||
/*
|
||||
* Clock: 125MHz
|
||||
* Synchronous reset
|
||||
*/
|
||||
input wire logic clk,
|
||||
input wire logic clk90,
|
||||
input wire logic rst,
|
||||
|
||||
/*
|
||||
* GPIO
|
||||
*/
|
||||
input wire logic btnu,
|
||||
input wire logic btnl,
|
||||
input wire logic btnd,
|
||||
input wire logic btnr,
|
||||
input wire logic btnc,
|
||||
input wire logic [7:0] sw,
|
||||
output wire logic [7:0] led,
|
||||
|
||||
/*
|
||||
* UART: 115200 bps, 8N1
|
||||
*/
|
||||
input wire logic uart_rxd,
|
||||
output wire logic uart_txd,
|
||||
output wire logic uart_rts,
|
||||
input wire logic uart_cts,
|
||||
|
||||
/*
|
||||
* Ethernet: 1000BASE-X SFP
|
||||
*/
|
||||
input wire logic sfp_gmii_clk,
|
||||
input wire logic sfp_gmii_rst,
|
||||
input wire logic sfp_gmii_clk_en,
|
||||
input wire logic [7:0] sfp_gmii_rxd,
|
||||
input wire logic sfp_gmii_rx_dv,
|
||||
input wire logic sfp_gmii_rx_er,
|
||||
output wire logic [7:0] sfp_gmii_txd,
|
||||
output wire logic sfp_gmii_tx_en,
|
||||
output wire logic sfp_gmii_tx_er,
|
||||
output wire logic sfp_tx_disable_b,
|
||||
|
||||
/*
|
||||
* Ethernet: 1000BASE-T
|
||||
*/
|
||||
input wire logic phy_sgmii_clk,
|
||||
input wire logic phy_sgmii_rst,
|
||||
input wire logic phy_sgmii_clk_en,
|
||||
input wire logic [7:0] phy_sgmii_rxd,
|
||||
input wire logic phy_sgmii_rx_dv,
|
||||
input wire logic phy_sgmii_rx_er,
|
||||
output wire logic [7:0] phy_sgmii_txd,
|
||||
output wire logic phy_sgmii_tx_en,
|
||||
output wire logic phy_sgmii_tx_er,
|
||||
input wire logic phy_rgmii_rx_clk,
|
||||
input wire logic [3:0] phy_rgmii_rxd,
|
||||
input wire logic phy_rgmii_rx_ctl,
|
||||
output wire logic phy_rgmii_tx_clk,
|
||||
output wire logic [3:0] phy_rgmii_txd,
|
||||
output wire logic phy_rgmii_tx_ctl,
|
||||
input wire logic phy_gmii_rx_clk,
|
||||
input wire logic [7:0] phy_gmii_rxd,
|
||||
input wire logic phy_gmii_rx_dv,
|
||||
input wire logic phy_gmii_rx_er,
|
||||
output wire logic phy_gmii_gtx_clk,
|
||||
input wire logic phy_gmii_tx_clk,
|
||||
output wire logic [7:0] phy_gmii_txd,
|
||||
output wire logic phy_gmii_tx_en,
|
||||
output wire logic phy_gmii_tx_er,
|
||||
output wire logic phy_reset_n,
|
||||
input wire logic phy_int_n
|
||||
);
|
||||
|
||||
assign led = sw;
|
||||
|
||||
// UART
|
||||
assign uart_rts = 0;
|
||||
|
||||
taxi_axis_if #(.DATA_W(8)) axis_uart();
|
||||
|
||||
taxi_uart
|
||||
uut (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
|
||||
/*
|
||||
* AXI4-Stream input (sink)
|
||||
*/
|
||||
.s_axis_tx(axis_uart),
|
||||
|
||||
/*
|
||||
* AXI4-Stream output (source)
|
||||
*/
|
||||
.m_axis_rx(axis_uart),
|
||||
|
||||
/*
|
||||
* UART interface
|
||||
*/
|
||||
.rxd(uart_rxd),
|
||||
.txd(uart_txd),
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
.tx_busy(),
|
||||
.rx_busy(),
|
||||
.rx_overrun_error(),
|
||||
.rx_frame_error(),
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
.prescale(16'(125000000/115200/8))
|
||||
);
|
||||
|
||||
// BASE-T PHY
|
||||
assign phy_reset_n = !rst;
|
||||
|
||||
taxi_axis_if #(.DATA_W(8), .ID_W(8)) axis_eth();
|
||||
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_tx_cpl();
|
||||
|
||||
if (BASET_PHY_TYPE == "GMII") begin : baset_mac_gmii
|
||||
|
||||
taxi_eth_mac_1g_gmii_fifo #(
|
||||
.SIM(SIM),
|
||||
.VENDOR(VENDOR),
|
||||
.FAMILY(FAMILY),
|
||||
.PADDING_EN(1),
|
||||
.MIN_FRAME_LEN(64),
|
||||
.TX_FIFO_DEPTH(16384),
|
||||
.TX_FRAME_FIFO(1),
|
||||
.RX_FIFO_DEPTH(16384),
|
||||
.RX_FRAME_FIFO(1)
|
||||
)
|
||||
eth_mac_inst (
|
||||
.gtx_clk(clk),
|
||||
.gtx_rst(rst),
|
||||
.logic_clk(clk),
|
||||
.logic_rst(rst),
|
||||
|
||||
/*
|
||||
* Transmit interface (AXI stream)
|
||||
*/
|
||||
.s_axis_tx(axis_eth),
|
||||
.m_axis_tx_cpl(axis_tx_cpl),
|
||||
|
||||
/*
|
||||
* Receive interface (AXI stream)
|
||||
*/
|
||||
.m_axis_rx(axis_eth),
|
||||
|
||||
/*
|
||||
* GMII interface
|
||||
*/
|
||||
.gmii_rx_clk(phy_gmii_rx_clk),
|
||||
.gmii_rxd(phy_gmii_rxd),
|
||||
.gmii_rx_dv(phy_gmii_rx_dv),
|
||||
.gmii_rx_er(phy_gmii_rx_er),
|
||||
.gmii_tx_clk(phy_gmii_gtx_clk),
|
||||
.mii_tx_clk(phy_gmii_tx_clk),
|
||||
.gmii_txd(phy_gmii_txd),
|
||||
.gmii_tx_en(phy_gmii_tx_en),
|
||||
.gmii_tx_er(phy_gmii_tx_er),
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
.tx_error_underflow(),
|
||||
.tx_fifo_overflow(),
|
||||
.tx_fifo_bad_frame(),
|
||||
.tx_fifo_good_frame(),
|
||||
.rx_error_bad_frame(),
|
||||
.rx_error_bad_fcs(),
|
||||
.rx_fifo_overflow(),
|
||||
.rx_fifo_bad_frame(),
|
||||
.rx_fifo_good_frame(),
|
||||
.link_speed(),
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
.cfg_ifg(8'd12),
|
||||
.cfg_tx_enable(1'b1),
|
||||
.cfg_rx_enable(1'b1)
|
||||
);
|
||||
|
||||
assign phy_sgmii_txd = '0;
|
||||
assign phy_sgmii_tx_en = 1'b0;
|
||||
assign phy_sgmii_tx_er = 1'b0;
|
||||
|
||||
assign phy_rgmii_tx_clk = 1'b0;
|
||||
assign phy_rgmii_txd = '0;
|
||||
assign phy_rgmii_tx_ctl = 1'b0;
|
||||
|
||||
end else if (BASET_PHY_TYPE == "RGMII") begin : baset_mac_rgmii
|
||||
|
||||
taxi_eth_mac_1g_rgmii_fifo #(
|
||||
.SIM(SIM),
|
||||
.VENDOR(VENDOR),
|
||||
.FAMILY(FAMILY),
|
||||
.USE_CLK90(USE_CLK90),
|
||||
.PADDING_EN(1),
|
||||
.MIN_FRAME_LEN(64),
|
||||
.TX_FIFO_DEPTH(16384),
|
||||
.TX_FRAME_FIFO(1),
|
||||
.RX_FIFO_DEPTH(16384),
|
||||
.RX_FRAME_FIFO(1)
|
||||
)
|
||||
eth_mac_inst (
|
||||
.gtx_clk(clk),
|
||||
.gtx_clk90(clk90),
|
||||
.gtx_rst(rst),
|
||||
.logic_clk(clk),
|
||||
.logic_rst(rst),
|
||||
|
||||
/*
|
||||
* Transmit interface (AXI stream)
|
||||
*/
|
||||
.s_axis_tx(axis_eth),
|
||||
.m_axis_tx_cpl(axis_tx_cpl),
|
||||
|
||||
/*
|
||||
* Receive interface (AXI stream)
|
||||
*/
|
||||
.m_axis_rx(axis_eth),
|
||||
|
||||
/*
|
||||
* RGMII interface
|
||||
*/
|
||||
.rgmii_rx_clk(phy_rgmii_rx_clk),
|
||||
.rgmii_rxd(phy_rgmii_rxd),
|
||||
.rgmii_rx_ctl(phy_rgmii_rx_ctl),
|
||||
.rgmii_tx_clk(phy_rgmii_tx_clk),
|
||||
.rgmii_txd(phy_rgmii_txd),
|
||||
.rgmii_tx_ctl(phy_rgmii_tx_ctl),
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
.tx_error_underflow(),
|
||||
.tx_fifo_overflow(),
|
||||
.tx_fifo_bad_frame(),
|
||||
.tx_fifo_good_frame(),
|
||||
.rx_error_bad_frame(),
|
||||
.rx_error_bad_fcs(),
|
||||
.rx_fifo_overflow(),
|
||||
.rx_fifo_bad_frame(),
|
||||
.rx_fifo_good_frame(),
|
||||
.link_speed(),
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
.cfg_ifg(8'd12),
|
||||
.cfg_tx_enable(1'b1),
|
||||
.cfg_rx_enable(1'b1)
|
||||
);
|
||||
|
||||
assign phy_gmii_gtx_clk = 1'b0;
|
||||
assign phy_gmii_txd = '0;
|
||||
assign phy_gmii_tx_en = 1'b0;
|
||||
assign phy_gmii_tx_er = 1'b0;
|
||||
|
||||
assign phy_sgmii_txd = '0;
|
||||
assign phy_sgmii_tx_en = 1'b0;
|
||||
assign phy_sgmii_tx_er = 1'b0;
|
||||
|
||||
end else if (BASET_PHY_TYPE == "SGMII") begin : baset_mac_sgmii
|
||||
|
||||
taxi_eth_mac_1g_fifo #(
|
||||
.PADDING_EN(1),
|
||||
.MIN_FRAME_LEN(64),
|
||||
.TX_FIFO_DEPTH(16384),
|
||||
.TX_FRAME_FIFO(1),
|
||||
.RX_FIFO_DEPTH(16384),
|
||||
.RX_FRAME_FIFO(1)
|
||||
)
|
||||
eth_mac_inst (
|
||||
.rx_clk(phy_sgmii_clk),
|
||||
.rx_rst(phy_sgmii_rst),
|
||||
.tx_clk(phy_sgmii_clk),
|
||||
.tx_rst(phy_sgmii_rst),
|
||||
.logic_clk(clk),
|
||||
.logic_rst(rst),
|
||||
|
||||
/*
|
||||
* Transmit interface (AXI stream)
|
||||
*/
|
||||
.s_axis_tx(axis_eth),
|
||||
.m_axis_tx_cpl(axis_tx_cpl),
|
||||
|
||||
/*
|
||||
* Receive interface (AXI stream)
|
||||
*/
|
||||
.m_axis_rx(axis_eth),
|
||||
|
||||
/*
|
||||
* GMII interface
|
||||
*/
|
||||
.gmii_rxd(phy_sgmii_rxd),
|
||||
.gmii_rx_dv(phy_sgmii_rx_dv),
|
||||
.gmii_rx_er(phy_sgmii_rx_er),
|
||||
.gmii_txd(phy_sgmii_txd),
|
||||
.gmii_tx_en(phy_sgmii_tx_en),
|
||||
.gmii_tx_er(phy_sgmii_tx_er),
|
||||
|
||||
/*
|
||||
* Control
|
||||
*/
|
||||
.rx_clk_enable(phy_sgmii_clk_en),
|
||||
.tx_clk_enable(phy_sgmii_clk_en),
|
||||
.rx_mii_select(1'b0),
|
||||
.tx_mii_select(1'b0),
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
.tx_error_underflow(),
|
||||
.tx_fifo_overflow(),
|
||||
.tx_fifo_bad_frame(),
|
||||
.tx_fifo_good_frame(),
|
||||
.rx_error_bad_frame(),
|
||||
.rx_error_bad_fcs(),
|
||||
.rx_fifo_overflow(),
|
||||
.rx_fifo_bad_frame(),
|
||||
.rx_fifo_good_frame(),
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
.cfg_ifg(8'd12),
|
||||
.cfg_tx_enable(1'b1),
|
||||
.cfg_rx_enable(1'b1)
|
||||
);
|
||||
|
||||
assign phy_gmii_gtx_clk = 1'b0;
|
||||
assign phy_gmii_txd = '0;
|
||||
assign phy_gmii_tx_en = 1'b0;
|
||||
assign phy_gmii_tx_er = 1'b0;
|
||||
|
||||
assign phy_rgmii_tx_clk = 1'b0;
|
||||
assign phy_rgmii_txd = '0;
|
||||
assign phy_rgmii_tx_ctl = 1'b0;
|
||||
|
||||
end
|
||||
|
||||
// SFP+
|
||||
assign sfp_tx_disable_b = 1'b1;
|
||||
|
||||
taxi_axis_if #(.DATA_W(8), .ID_W(8)) axis_sfp_eth();
|
||||
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp_tx_cpl();
|
||||
|
||||
taxi_eth_mac_1g_fifo #(
|
||||
.PADDING_EN(1),
|
||||
.MIN_FRAME_LEN(64),
|
||||
.TX_FIFO_DEPTH(16384),
|
||||
.TX_FRAME_FIFO(1),
|
||||
.RX_FIFO_DEPTH(16384),
|
||||
.RX_FRAME_FIFO(1)
|
||||
)
|
||||
eth_mac_inst (
|
||||
.rx_clk(sfp_gmii_clk),
|
||||
.rx_rst(sfp_gmii_rst),
|
||||
.tx_clk(sfp_gmii_clk),
|
||||
.tx_rst(sfp_gmii_rst),
|
||||
.logic_clk(clk),
|
||||
.logic_rst(rst),
|
||||
|
||||
/*
|
||||
* Transmit interface (AXI stream)
|
||||
*/
|
||||
.s_axis_tx(axis_sfp_eth),
|
||||
.m_axis_tx_cpl(axis_sfp_tx_cpl),
|
||||
|
||||
/*
|
||||
* Receive interface (AXI stream)
|
||||
*/
|
||||
.m_axis_rx(axis_sfp_eth),
|
||||
|
||||
/*
|
||||
* GMII interface
|
||||
*/
|
||||
.gmii_rxd(sfp_gmii_rxd),
|
||||
.gmii_rx_dv(sfp_gmii_rx_dv),
|
||||
.gmii_rx_er(sfp_gmii_rx_er),
|
||||
.gmii_txd(sfp_gmii_txd),
|
||||
.gmii_tx_en(sfp_gmii_tx_en),
|
||||
.gmii_tx_er(sfp_gmii_tx_er),
|
||||
|
||||
/*
|
||||
* Control
|
||||
*/
|
||||
.rx_clk_enable(sfp_gmii_clk_en),
|
||||
.tx_clk_enable(sfp_gmii_clk_en),
|
||||
.rx_mii_select(1'b0),
|
||||
.tx_mii_select(1'b0),
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
.tx_error_underflow(),
|
||||
.tx_fifo_overflow(),
|
||||
.tx_fifo_bad_frame(),
|
||||
.tx_fifo_good_frame(),
|
||||
.rx_error_bad_frame(),
|
||||
.rx_error_bad_fcs(),
|
||||
.rx_fifo_overflow(),
|
||||
.rx_fifo_bad_frame(),
|
||||
.rx_fifo_good_frame(),
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
.cfg_ifg(8'd12),
|
||||
.cfg_tx_enable(1'b1),
|
||||
.cfg_rx_enable(1'b1)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
||||
57
example/KC705/fpga/tb/fpga_core/Makefile
Normal file
57
example/KC705/fpga/tb/fpga_core/Makefile
Normal file
@@ -0,0 +1,57 @@
|
||||
# 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
|
||||
|
||||
DUT = fpga_core
|
||||
COCOTB_TEST_MODULES = test_$(DUT)
|
||||
COCOTB_TOPLEVEL = $(DUT)
|
||||
MODULE = $(COCOTB_TEST_MODULES)
|
||||
TOPLEVEL = $(COCOTB_TOPLEVEL)
|
||||
VERILOG_SOURCES += ../../rtl/$(DUT).sv
|
||||
VERILOG_SOURCES += ../../lib/taxi/rtl/eth/taxi_eth_mac_1g_fifo.f
|
||||
VERILOG_SOURCES += ../../lib/taxi/rtl/eth/taxi_eth_mac_1g_gmii_fifo.f
|
||||
VERILOG_SOURCES += ../../lib/taxi/rtl/eth/taxi_eth_mac_1g_rgmii_fifo.f
|
||||
VERILOG_SOURCES += ../../lib/taxi/rtl/lss/taxi_uart.f
|
||||
VERILOG_SOURCES += ../../lib/taxi/rtl/sync/taxi_sync_reset.sv
|
||||
VERILOG_SOURCES += ../../lib/taxi/rtl/sync/taxi_sync_signal.sv
|
||||
VERILOG_SOURCES += ../../lib/taxi/rtl/io/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 := "\"kintex7\""
|
||||
export PARAM_USE_CLK90 := "1'b1"
|
||||
export PARAM_BASET_PHY_TYPE := "\"GMII\""
|
||||
export PARAM_SFP_INVERT := "1'b1"
|
||||
|
||||
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
|
||||
257
example/KC705/fpga/tb/fpga_core/test_fpga_core.py
Normal file
257
example/KC705/fpga/tb/fpga_core/test_fpga_core.py
Normal file
@@ -0,0 +1,257 @@
|
||||
#!/usr/bin/env python
|
||||
# SPDX-License-Identifier: MIT
|
||||
"""
|
||||
|
||||
Copyright (c) 2020-2025 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
import pytest
|
||||
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 GmiiFrame, GmiiSource, GmiiSink, GmiiPhy, RgmiiPhy
|
||||
from cocotbext.uart import UartSource, UartSink
|
||||
|
||||
|
||||
class TB:
|
||||
def __init__(self, dut, speed=1000e6):
|
||||
self.dut = dut
|
||||
|
||||
self.log = SimLog("cocotb.tb")
|
||||
self.log.setLevel(logging.DEBUG)
|
||||
|
||||
cocotb.start_soon(Clock(dut.phy_sgmii_clk, 8, units="ns").start())
|
||||
|
||||
if hasattr(dut, "baset_mac_gmii"):
|
||||
self.baset_phy = GmiiPhy(dut.phy_gmii_txd, dut.phy_gmii_tx_er, dut.phy_gmii_tx_en, dut.phy_gmii_tx_clk, dut.phy_gmii_gtx_clk,
|
||||
dut.phy_gmii_rxd, dut.phy_gmii_rx_er, dut.phy_gmii_rx_dv, dut.phy_gmii_rx_clk, speed=speed)
|
||||
elif hasattr(dut, "baset_mac_rgmii"):
|
||||
self.baset_phy = RgmiiPhy(dut.phy_rgmii_txd, dut.phy_rgmii_tx_ctl, dut.phy_rgmii_tx_clk,
|
||||
dut.phy_rgmii_rxd, dut.phy_rgmii_rx_ctl, dut.phy_rgmii_rx_clk, speed=speed)
|
||||
elif hasattr(dut, "baset_mac_sgmii"):
|
||||
self.sgmii_source = GmiiSource(dut.phy_sgmii_rxd, dut.phy_sgmii_rx_er, dut.phy_sgmii_rx_dv,
|
||||
dut.phy_sgmii_clk, dut.phy_sgmii_rst, dut.phy_sgmii_clk_en)
|
||||
self.sgmii_sink = GmiiSink(dut.phy_sgmii_txd, dut.phy_sgmii_tx_er, dut.phy_sgmii_tx_en,
|
||||
dut.phy_sgmii_clk, dut.phy_sgmii_rst, dut.phy_sgmii_clk_en)
|
||||
|
||||
cocotb.start_soon(Clock(dut.sfp_gmii_clk, 8, units="ns").start())
|
||||
|
||||
self.sfp_source = GmiiSource(dut.sfp_gmii_rxd, dut.sfp_gmii_rx_er, dut.sfp_gmii_rx_dv,
|
||||
dut.sfp_gmii_clk, dut.sfp_gmii_rst, dut.sfp_gmii_clk_en)
|
||||
self.sfp_sink = GmiiSink(dut.sfp_gmii_txd, dut.sfp_gmii_tx_er, dut.sfp_gmii_tx_en,
|
||||
dut.sfp_gmii_clk, dut.sfp_gmii_rst, dut.sfp_gmii_clk_en)
|
||||
|
||||
self.uart_source = UartSource(dut.uart_rxd, baud=115200, bits=8, stop_bits=1)
|
||||
self.uart_sink = UartSink(dut.uart_txd, baud=115200, bits=8, stop_bits=1)
|
||||
|
||||
dut.phy_sgmii_clk_en.setimmediatevalue(1)
|
||||
dut.sfp_gmii_clk_en.setimmediatevalue(1)
|
||||
|
||||
dut.btnu.setimmediatevalue(0)
|
||||
dut.btnl.setimmediatevalue(0)
|
||||
dut.btnd.setimmediatevalue(0)
|
||||
dut.btnr.setimmediatevalue(0)
|
||||
dut.btnc.setimmediatevalue(0)
|
||||
dut.sw.setimmediatevalue(0)
|
||||
dut.uart_rts.setimmediatevalue(0)
|
||||
|
||||
cocotb.start_soon(self._run_clk())
|
||||
|
||||
async def init(self):
|
||||
|
||||
self.dut.rst.setimmediatevalue(0)
|
||||
self.dut.phy_sgmii_rst.setimmediatevalue(0)
|
||||
self.dut.sfp_gmii_rst.setimmediatevalue(0)
|
||||
|
||||
for k in range(10):
|
||||
await RisingEdge(self.dut.clk)
|
||||
|
||||
self.dut.rst.value = 1
|
||||
self.dut.phy_sgmii_rst.value = 1
|
||||
self.dut.sfp_gmii_rst.value = 1
|
||||
|
||||
for k in range(10):
|
||||
await RisingEdge(self.dut.clk)
|
||||
|
||||
self.dut.rst.value = 0
|
||||
self.dut.phy_sgmii_rst.value = 0
|
||||
self.dut.sfp_gmii_rst.value = 0
|
||||
|
||||
async def _run_clk(self):
|
||||
t = Timer(2, 'ns')
|
||||
while True:
|
||||
self.dut.clk.value = 1
|
||||
await t
|
||||
self.dut.clk90.value = 1
|
||||
await t
|
||||
self.dut.clk.value = 0
|
||||
await t
|
||||
self.dut.clk90.value = 0
|
||||
await t
|
||||
|
||||
|
||||
async def uart_test(tb, source, sink):
|
||||
tb.log.info("Test UART")
|
||||
|
||||
tx_data = b"FPGA Ninja"
|
||||
|
||||
tb.log.info("UART TX: %s", tx_data)
|
||||
|
||||
await source.write(tx_data)
|
||||
|
||||
rx_data = bytearray()
|
||||
|
||||
while len(rx_data) < len(tx_data):
|
||||
rx_data.extend(await sink.read())
|
||||
|
||||
tb.log.info("UART RX: %s", rx_data)
|
||||
|
||||
tb.log.info("UART test done")
|
||||
|
||||
|
||||
async def mac_test(tb, source, sink):
|
||||
tb.log.info("Test MAC")
|
||||
|
||||
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(GmiiFrame.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()
|
||||
assert rx_frame.error is None
|
||||
|
||||
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(GmiiFrame.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()
|
||||
assert rx_frame.error is None
|
||||
|
||||
tb.log.info("MAC test done")
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def run_test(dut):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.init()
|
||||
|
||||
tb.log.info("Start UART test")
|
||||
|
||||
uart_test_cr = cocotb.start_soon(uart_test(tb, tb.uart_source, tb.uart_sink))
|
||||
|
||||
tb.log.info("Start BASE-T MAC loopback test")
|
||||
|
||||
if hasattr(dut, "baset_mac_gmii"):
|
||||
baset_test_cr = cocotb.start_soon(mac_test(tb, tb.baset_phy.rx, tb.baset_phy.tx))
|
||||
elif hasattr(dut, "baset_mac_rgmii"):
|
||||
baset_test_cr = cocotb.start_soon(mac_test(tb, tb.baset_phy.rx, tb.baset_phy.tx))
|
||||
elif hasattr(dut, "baset_mac_sgmii"):
|
||||
baset_test_cr = cocotb.start_soon(mac_test(tb, tb.sgmii_source, tb.sgmii_sink))
|
||||
|
||||
tb.log.info("Start SFP MAC loopback test")
|
||||
|
||||
sfp_test_cr = cocotb.start_soon(mac_test(tb, tb.sfp_source, tb.sfp_sink))
|
||||
|
||||
await Combine(uart_test_cr, baset_test_cr, sfp_test_cr)
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
tests_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
|
||||
lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib'))
|
||||
|
||||
|
||||
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())
|
||||
|
||||
|
||||
@pytest.mark.parametrize("phy_type", ["GMII", "RGMII", "SGMII"])
|
||||
def test_fpga_core(request, phy_type):
|
||||
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(lib_dir, "taxi", "rtl", "eth", "taxi_eth_mac_1g_fifo.f"),
|
||||
os.path.join(lib_dir, "taxi", "rtl", "eth", "taxi_eth_mac_1g_gmii_fifo.f"),
|
||||
os.path.join(lib_dir, "taxi", "rtl", "eth", "taxi_eth_mac_1g_rgmii_fifo.f"),
|
||||
os.path.join(lib_dir, "taxi", "rtl", "lss", "taxi_uart.f"),
|
||||
os.path.join(lib_dir, "taxi", "rtl", "sync", "taxi_sync_reset.sv"),
|
||||
os.path.join(lib_dir, "taxi", "rtl", "sync", "taxi_sync_signal.sv"),
|
||||
os.path.join(lib_dir, "taxi", "rtl", "io", "taxi_debounce_switch.sv"),
|
||||
]
|
||||
|
||||
verilog_sources = process_f_files(verilog_sources)
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['SIM'] = "1'b1"
|
||||
parameters['VENDOR'] = "\"XILINX\""
|
||||
parameters['FAMILY'] = "\"artix7\""
|
||||
parameters['USE_CLK90'] = "1'b1"
|
||||
parameters['BASET_PHY_TYPE'] = f"\"{phy_type}\""
|
||||
parameters['SFP_INVERT'] = "1'b1"
|
||||
|
||||
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