Add ML605 SGMII design

This commit is contained in:
Alex Forencich 2017-07-22 11:07:23 -07:00
parent eb47bea9a1
commit cf6a01fffe
23 changed files with 2209 additions and 0 deletions

View File

@ -0,0 +1,25 @@
# Targets
TARGETS:=
# Subdirectories
SUBDIRS = coregen fpga
SUBDIRS_CLEAN = $(patsubst %,%.clean,$(SUBDIRS))
# Rules
.PHONY: all
all: $(SUBDIRS) $(TARGETS)
.PHONY: $(SUBDIRS)
$(SUBDIRS):
cd $@ && $(MAKE)
.PHONY: $(SUBDIRS_CLEAN)
$(SUBDIRS_CLEAN):
cd $(@:.clean=) && $(MAKE) clean
.PHONY: clean
clean: $(SUBDIRS_CLEAN)
-rm -rf $(TARGETS)
program:
#djtgcfg prog -d Atlys --index 0 --file fpga/fpga.bit

View File

@ -0,0 +1,28 @@
# Verilog Ethernet ML605 SGMII Example Design
## Introduction
This example design targets the Xilinx ML605 FPGA board.
The design by default listens to UDP port 1234 at IP address 192.168.1.128 and
will echo back any packets received. The design will also respond correctly
to ARP requests.
Configure the PHY for SGMII by placing J66 and J67 across pins 2 and 3 and
opening J68.
FPGA: XC6SlX45-2CSG324
PHY: Marvell M88E1111
## How to build
Run make to build. Ensure that the Xilinx ISE toolchain components are
in PATH.
## How to test
Run make program to program the ML605 board with the Xilinx Impact software.
Then run netcat -u 192.168.1.128 1234 to open a UDP connection to port 1234.
Any text entered into netcat will be echoed back after pressing enter.

View File

@ -0,0 +1,24 @@
# UCF file for clock module domain crossing constraints
NET "phy_sgmii_txoutclk" TNM_NET = "txoutclk";
TIMESPEC "TS_txoutclk" = PERIOD "txoutclk" 8 ns HIGH 50 %;
NET "eth_pcspma/transceiver_inst/RXRECCLK" TNM_NET = "rxrecclk";
TIMESPEC "ts_rxrecclk" = PERIOD "rxrecclk" 8 ns;
# Identify clock domain crossing registers
INST "eth_pcspma/transceiver_inst/rx_elastic_buffer_inst/wr_addr_gray*" TNM = "wr_graycode";
INST "eth_pcspma/transceiver_inst/rx_elastic_buffer_inst/rd_addr_gray*" TNM = "rd_graycode";
# Control Gray Code delay and skew across clock boundary
TIMESPEC "ts_rx_skew_control1" = FROM "wr_graycode" TO "FFS" 14 ns DATAPATHONLY;
TIMESPEC "ts_rx_skew_control2" = FROM "rd_graycode" TO "FFS" 14 ns DATAPATHONLY;
# Constrain between Distributed Memory (output data) and the 1st set of flip-flops
INST "eth_pcspma/transceiver_inst/rx_elastic_buffer_inst/*rd_data*" TNM = "fifo_read";
TIMESPEC "ts_ram_read_false_path" = FROM "RAMS" TO "fifo_read" 6 ns DATAPATHONLY;
NET "clk_125mhz_int" TNM = "ffs_clk_125mhz_int";
NET "phy_sgmii_txoutclk" TNM = "ffs_sgmii_clk";
TIMESPEC "TS_clk_125mhz_int_to_sgmii_clk" = FROM "ffs_clk_125mhz_int" TO "ffs_sgmii_clk" 10 ns;
TIMESPEC "TS_sgmii_clk_to_clk_125mhz_int" = FROM "ffs_sgmii_clk" TO "ffs_clk_125mhz_int" 10 ns;

View File

@ -0,0 +1,191 @@
#############################################################################
# Author: Lane Brooks/Keith Fife
# Date: 04/28/2006
# License: GPL
# Desc: This is a Makefile intended to take a verilog rtl design
# through the Xilinx ISE tools to generate configuration files for
# Xilinx FPGAs. This file is generic and just a template. As such
# all design specific options such as synthesis files, fpga part type,
# prom part type, etc should be set in the top Makefile prior to
# including this file. Alternatively, all parameters can be passed
# in from the command line as well.
#
##############################################################################
#
# Parameter:
# SYN_FILES - Space seperated list of files to be synthesized
# PART - FPGA part (see Xilinx documentation)
# PROM - PROM part
# NGC_PATHS - Space seperated list of any dirs with pre-compiled ngc files.
# UCF_FILES - Space seperated list of user constraint files. Defaults to xilinx/$(FPGA_TOP).ucf
#
#
# Example Calling Makefile:
#
# SYN_FILES = fpga.v fifo.v clks.v
# PART = xc3s1000
# FPGA_TOP = fpga
# PROM = xc18v04
# NGC_PATH = ipLib1 ipLib2
# FPGA_ARCH = spartan6
# SPI_PROM_SIZE = (in bytes)
# include xilinx.mk
#############################################################################
#
# Command Line Example:
# make -f xilinx.mk PART=xc3s1000-4fg320 SYN_FILES="fpga.v test.v" FPGA_TOP=fpga
#
##############################################################################
#
# Required Setup:
#
# %.ucf - user constraint file. Needed by ngdbuild
#
# Optional Files:
# %.xcf - user constraint file. Needed by xst.
# %.ut - File for pin states needed by bitgen
.PHONY: clean bit prom fpga spi
# Mark the intermediate files as PRECIOUS to prevent make from
# deleting them (see make manual section 10.4).
.PRECIOUS: %.ngc %.ngd %_map.ncd %.ncd %.twr %.bit %_timesim.v
# include the local Makefile for project for any project specific targets
CONFIG ?= config.mk
-include ../$(CONFIG)
SYN_FILES_REL = $(patsubst %, ../%, $(SYN_FILES))
INC_FILES_REL = $(patsubst %, ../%, $(INC_FILES))
INC_PATHS_REL = $(patsubst %, ../%, $(INC_PATHS))
NGC_PATHS_REL = $(patsubst %, ../%, $(NGC_PATHS))
ifdef UCF_FILES
UCF_FILES_REL = $(patsubst %, ../%, $(UCF_FILES))
else
UCF_FILES_REL = $(FPGA_TOP).ucf
endif
fpga: $(FPGA_TOP).bit
mcs: $(FPGA_TOP).mcs
prom: $(FPGA_TOP).spi
spi: $(FPGA_TOP).spi
fpgasim: $(FPGA_TOP)_sim.v
########################### XST TEMPLATES ############################
# There are 2 files that XST uses for synthesis that we auto generate.
# The first is a project file which is just a list of all the verilog
# files. The second is the src file which passes XST all the options.
# See XST user manual for XST options.
%.ngc: $(SYN_FILES_REL) $(INC_FILES_REL)
rm -rf xst $*.prj $*.xst defines.v
touch defines.v
mkdir -p xst/tmp
for x in $(DEFS); do echo '`define' $$x >> defines.v; done
echo verilog work defines.v > $*.prj
for x in $(SYN_FILES_REL); do echo verilog work $$x >> $*.prj; done
@echo "set -tmpdir ./xst/tmp" >> $*.xst
@echo "set -xsthdpdir ./xst" >> $*.xst
@echo "run" >> $*.xst
@echo "-ifn $*.prj" >> $*.xst
@echo "-ifmt mixed" >> $*.xst
@echo "-top $*" >> $*.xst
@echo "-ofn $*" >> $*.xst
@echo "-ofmt NGC" >> $*.xst
@echo "-opt_mode Speed" >> $*.xst
@echo "-opt_level 1" >> $*.xst
# @echo "-verilog2001 YES" >> $*.xst
@echo "-keep_hierarchy NO" >> $*.xst
@echo "-p $(FPGA_PART)" >> $*.xst
xst -ifn $*.xst -ofn $*.log
########################### ISE TRANSLATE ############################
# ngdbuild will automatically use a ucf called %.ucf if one is found.
# We setup the dependancy such that %.ucf file is required. If any
# pre-compiled ncd files are needed, set the NGC_PATH variable as a space
# seperated list of directories that include the pre-compiled ngc files.
%.ngd: %.ngc $(UCF_FILES_REL)
ngdbuild -dd ngdbuild $(patsubst %,-sd %, $(NGC_PATHS_REL)) $(patsubst %,-uc %, $(UCF_FILES_REL)) -p $(FPGA_PART) $< $@
########################### ISE MAP ###################################
ifeq ($(FPGA_ARCH),spartan6)
MAP_OPTS= -register_duplication on -timing -xe n
else
MAP_OPTS= -cm speed -register_duplication on -timing -xe n -pr b
endif
%_map.ncd: %.ngd
map -p $(FPGA_PART) $(MAP_OPTS) -w -o $@ $< $*.pcf
# map -p $(FPGA_PART) -cm area -pr b -k 4 -c 100 -o $@ $< $*.pcf
########################### ISE PnR ###################################
%.ncd: %_map.ncd
par -w -ol high $< $@ $*.pcf
# par -w -ol std -t 1 $< $@ $*.pcf
##################### ISE Static Timing Analysis #####################
%.twr: %.ncd
-trce -e 3 -l 3 -u -xml $* $< -o $@ $*.pcf
%_sim.v: %.ncd
netgen -s 4 -pcf $*.pcf -sdf_anno true -ism -sdf_path netgen -w -dir . -ofmt verilog -sim $< $@
# netgen -ise "/home/lane/Second/xilinx/Second/Second" -intstyle ise -s 4 -pcf Second.pcf -sdf_anno true -sdf_path netgen/par -w -dir netgen/par -ofmt verilog -sim Second.ncd Second_timesim.v
########################### ISE Bitgen #############################
%.bit: %.twr
bitgen $(BITGEN_OPTIONS) -w $*.ncd $*.bit
mkdir -p rev
EXT=bit; COUNT=100; \
while [ -e rev/$*_rev$$COUNT.$$EXT ]; \
do let COUNT=COUNT+1; done; \
cp $@ rev/$*_rev$$COUNT.$$EXT; \
echo "Output: rev/$*_rev$$COUNT.$$EXT";
########################### ISE Promgen #############################
%.mcs: %.bit
promgen -spi -w -p mcs -s $(SPI_PROM_SIZE) -o $@ -u 0 $<
# promgen -w -p mcs -c FF -o $@ -u 0 $< -x $(PROM)
mkdir -p rev
EXT=mcs; COUNT=100; \
while [ -e rev/$*_rev$$COUNT.$$EXT ]; \
do let COUNT=COUNT+1; done; \
cp $@ rev/$*_rev$$COUNT.$$EXT; \
echo "Output: rev/$*_rev$$COUNT.$$EXT";
%.spi: %.mcs
objcopy -I ihex -O binary $< $@
EXT=spi; COUNT=100; \
while [ -e rev/$*_rev$$COUNT.$$EXT ]; \
do let COUNT=COUNT+1; done; \
cp $@ rev/$*_rev$$COUNT.$$EXT; \
tmpclean:
-rm -rf xst ngdbuild *_map.* *.ncd *.ngc *.log *.xst *.prj *.lso *~ *.pcf *.bld *.ngd *.xpi *_pad.* *.unroutes *.twx *.par *.twr *.pad *.drc *.bgn *.prm *.sig netgen *.v *.nlf *.xml
clean: tmpclean
-rm -rf *.bit *.mcs
# clean everything
distclean: clean
-rm -rf rev

View File

@ -0,0 +1,33 @@
# Tools
COREGEN:=coregen
XAW2VERILOG:=xaw2verilog
# Source
XCO:=gig_eth_pcs_pma_v11_5.xco
XAW:=
# Targets
TARGETS += $(XCO:.xco=)
TARGETS += $(XAW:.xaw=)
# Rules
.PHONY: all
all: $(TARGETS)
.PHONY: clean
clean:
-rm -rf $(TARGETS)
%: %.xco
$(eval $@_TMP := $(shell mktemp -d))
cp -a coregen.cgp $($@_TMP)
cp -a $< $($@_TMP)
cd $($@_TMP) && $(COREGEN) -p coregen.cgp -b $(notdir $<)
mv $($@_TMP) $@
%: %.xaw
$(eval $@_TMP := $(shell mktemp -d))
cp -a coregen.cgp $($@_TMP)
cp -a $< $($@_TMP)
cd $($@_TMP) && $(XAW2VERILOG) -st $(notdir $<) $(notdir $*)
mv $($@_TMP) $@

View File

@ -0,0 +1,22 @@
# Date: Wed Jun 21 16:05:33 2017
SET addpads = false
SET asysymbol = true
SET busformat = BusFormatAngleBracketNotRipped
SET createndf = false
SET designentry = Verilog
SET device = xc6vlx130t
SET devicefamily = virtex6
SET flowvendor = Other
SET formalverification = false
SET foundationsym = false
SET implementationfiletype = Ngc
SET package = ff1156
SET removerpms = false
SET simulationfiles = Behavioral
SET speedgrade = -1
SET verilogsim = true
SET vhdlsim = false
SET workingdirectory = ./tmp/
# CRC: 2db0eed3

View File

@ -0,0 +1,57 @@
##############################################################
#
# Xilinx Core Generator version 14.7
# Date: Wed Jun 21 16:07:22 2017
#
##############################################################
#
# This file contains the customisation parameters for a
# Xilinx CORE Generator IP GUI. It is strongly recommended
# that you do not manually alter this file as it may cause
# unexpected and unsupported behavior.
#
##############################################################
#
# Generated from component: xilinx.com:ip:gig_eth_pcs_pma:11.5
#
##############################################################
#
# BEGIN Project Options
SET addpads = false
SET asysymbol = true
SET busformat = BusFormatAngleBracketNotRipped
SET createndf = false
SET designentry = Verilog
SET device = xc6vlx130t
SET devicefamily = virtex6
SET flowvendor = Other
SET formalverification = false
SET foundationsym = false
SET implementationfiletype = Ngc
SET package = ff1156
SET removerpms = false
SET simulationfiles = Behavioral
SET speedgrade = -1
SET verilogsim = true
SET vhdlsim = false
# END Project Options
# BEGIN Select
SELECT Ethernet_1000BASE-X_PCS/PMA_or_SGMII xilinx.com:ip:gig_eth_pcs_pma:11.5
# END Select
# BEGIN Parameters
CSET auto_negotiation=true
CSET component_name=gig_eth_pcs_pma_v11_5
CSET enable_1588=false
CSET management_interface=false
CSET physical_interface=Transceiver
CSET sgmii_mode=10_100_1000
CSET sgmii_phy_mode=false
CSET standard=SGMII
CSET timing_sim=false
CSET transceiver_tile=A
# END Parameters
# BEGIN Extra information
MISC pkg_timestamp=2012-07-11T07:25:50Z
# END Extra information
GENERATE
# CRC: 7ca270ae

View File

@ -0,0 +1,94 @@
# User Constraints File for the Xilinx ML605 board, rev C
CONFIG PART = xc6vlx130t-1ff1156;
# 200MHz clock
NET "sys_clk_p" LOC = "J9" | IOSTANDARD=LVDS_25; # Bank = 34, IO_L0P_GC_34 (GCLK)
NET "sys_clk_n" LOC = "H9" | IOSTANDARD=LVDS_25; # Bank = 34, IO_L0N_GC_34 (GCLK)
NET "sys_clk_p" TNM_NET = "sys_clk_pin";
TIMESPEC "TS_sys_clk_pin" = PERIOD "sys_clk_pin" 200000 kHz;
# Light Emitting Diodes
NET "ledu" LOC = "AH27" | IOSTANDARD=LVCMOS25 | SLEW=QUIETIO | DRIVE=2; # Bank = 23, IO_L0P_23 (DS20)
NET "ledl" LOC = "AD21" | IOSTANDARD=LVCMOS25 | SLEW=QUIETIO | DRIVE=2; # Bank = 22, IO_L0N_22 (DS17)
NET "ledd" LOC = "AH28" | IOSTANDARD=LVCMOS25 | SLEW=QUIETIO | DRIVE=2; # Bank = 23, IO_L0N_23 (DS18)
NET "ledr" LOC = "AE21" | IOSTANDARD=LVCMOS25 | SLEW=QUIETIO | DRIVE=2; # Bank = 22, IO_L0P_22 (DS19)
NET "ledc" LOC = "AP24" | IOSTANDARD=LVCMOS25 | SLEW=QUIETIO | DRIVE=2; # Bank = 23, IO_L19N_23 (DS16)
NET "led<0>" LOC = "AC22" | IOSTANDARD=LVCMOS25 | SLEW=QUIETIO | DRIVE=2; # Bank = 24, IO_L19P_24 (DS12)
NET "led<1>" LOC = "AC24" | IOSTANDARD=LVCMOS25 | SLEW=QUIETIO | DRIVE=2; # Bank = 24, IO_L18N_24 (DS11)
NET "led<2>" LOC = "AE22" | IOSTANDARD=LVCMOS25 | SLEW=QUIETIO | DRIVE=2; # Bank = 24, IO_L17N_VRP_24 (DS9)
NET "led<3>" LOC = "AE23" | IOSTANDARD=LVCMOS25 | SLEW=QUIETIO | DRIVE=2; # Bank = 24, IO_L17P_VRN_24 (DS10)
NET "led<4>" LOC = "AB23" | IOSTANDARD=LVCMOS25 | SLEW=QUIETIO | DRIVE=2; # Bank = 24, IO_L16N_CSO_B_24 (DS15)
NET "led<5>" LOC = "AG23" | IOSTANDARD=LVCMOS25 | SLEW=QUIETIO | DRIVE=2; # Bank = 24, IO_L15N_RS1_24 (DS14)
NET "led<6>" LOC = "AE24" | IOSTANDARD=LVCMOS25 | SLEW=QUIETIO | DRIVE=2; # Bank = 24, IO_L11N_SRCC_24 (DS22)
NET "led<7>" LOC = "AD24" | IOSTANDARD=LVCMOS25 | SLEW=QUIETIO | DRIVE=2; # Bank = 24, IO_L11P_SRCC_24 (DS21)
# Reset Button: I/O Bank 2
NET "reset" LOC = "H10" | IOSTANDARD=LVCMOS15; # Bank = 35, IO_L6P_SM3P_35 (SW10)
# Push Buttons: I/O Bank 3
NET "btnu" LOC = "A19" | IOSTANDARD=LVCMOS15; # Bank = 26, IO_L15N_26 (SW5)
NET "btnl" LOC = "H17" | IOSTANDARD=LVCMOS15; # Bank = 36, IO_L3P_36 (SW8)
NET "btnd" LOC = "A18" | IOSTANDARD=LVCMOS15; # Bank = 26, IO_L15P_26 (SW6)
NET "btnr" LOC = "G17" | IOSTANDARD=LVCMOS15; # Bank = 36, IO_L3N_36 (SW7)
NET "btnc" LOC = "G26" | IOSTANDARD=LVCMOS15; # Bank = 25, IO_L6P_25 (SW9)
# Toggle Switches
NET "sw<0>" LOC = "D22" | IOSTANDARD=LVCMOS15; # Bank = 26, IO_L19N_26 (SW1.1)
NET "sw<1>" LOC = "C22" | IOSTANDARD=LVCMOS15; # Bank = 26, IO_L19P_26 (SW1.2)
NET "sw<2>" LOC = "L21" | IOSTANDARD=LVCMOS15; # Bank = 26, IO_L18N_26 (SW1.3)
NET "sw<3>" LOC = "L20" | IOSTANDARD=LVCMOS15; # Bank = 26, IO_L18P_26 (SW1.4)
NET "sw<4>" LOC = "C18" | IOSTANDARD=LVCMOS15; # Bank = 26, IO_L17N_26 (SW1.5)
NET "sw<5>" LOC = "B18" | IOSTANDARD=LVCMOS15; # Bank = 26, IO_L17P_26 (SW1.6)
NET "sw<6>" LOC = "K22" | IOSTANDARD=LVCMOS15; # Bank = 26, IO_L16N_26 (SW1.7)
NET "sw<7>" LOC = "K21" | IOSTANDARD=LVCMOS15; # Bank = 26, IO_L16P_26 (SW1.8)
# Marvell M88E1111 Tri-Mode Ethernet PHY (1000BASE-T)
# Interrupt, Reset, MDIO
#NET "phy_int_n" LOC = "AH14" | IOSTANDARD=LVCMOS25; # (E-INT)
NET "phy_reset_n" LOC = "AH13" | IOSTANDARD=LVCMOS25; # Bank = 33, IO_L18P_33 (E-RESET)
#NET "phy_mdc" LOC = "AP14" | IOSTANDARD=LVCMOS25; # (E-MDC)
#NET "phy_mdio" LOC = "AN14" | IOSTANDARD=LVCMOS25; # (E-MDIO)
# GMII Transmit
#NET "phy_gtx_clk" LOC = "AH12" | IOSTANDARD=LVCMOS25 | SLEW = FAST; # Bank = 33, IO_L16N_33 (E-GTXCLK)
#NET "phy_tx_clk" LOC = "AD12" | IOSTANDARD=LVCMOS25; # Bank = 33, IO_L10P_MRCC_33 (E-TXCLK)
#NET "phy_txd<0>" LOC = "AM11" | IOSTANDARD=LVCMOS25 | SLEW = FAST; # Bank = 33, IO_L7N_33 (E-TXD0)
#NET "phy_txd<1>" LOC = "AL11" | IOSTANDARD=LVCMOS25 | SLEW = FAST; # Bank = 33, IO_L7P_33 (E-TXD1)
#NET "phy_txd<2>" LOC = "AG10" | IOSTANDARD=LVCMOS25 | SLEW = FAST; # Bank = 33, IO_L6N_33 (E-TXD2)
#NET "phy_txd<3>" LOC = "AG11" | IOSTANDARD=LVCMOS25 | SLEW = FAST; # Bank = 33, IO_L6P_33 (E-TXD3)
#NET "phy_txd<4>" LOC = "AL10" | IOSTANDARD=LVCMOS25 | SLEW = FAST; # Bank = 33, IO_L5N_33 (E-TXD4)
#NET "phy_txd<5>" LOC = "AM10" | IOSTANDARD=LVCMOS25 | SLEW = FAST; # Bank = 33, IO_L5P_33 (E-TXD5)
#NET "phy_txd<6>" LOC = "AE11" | IOSTANDARD=LVCMOS25 | SLEW = FAST; # Bank = 33, IO_L4N_VREF_33 (E-TXD6)
#NET "phy_txd<7>" LOC = "AF11" | IOSTANDARD=LVCMOS25 | SLEW = FAST; # Bank = 33, IO_L4P_33 (E-TXD7)
#NET "phy_tx_en" LOC = "AJ10" | IOSTANDARD=LVCMOS25 | SLEW = FAST; # Bank = 33, IO_L8P_SRCC_33 (E-TXEN)
#NET "phy_tx_er" LOC = "AH10" | IOSTANDARD=LVCMOS25 | SLEW = FAST; # Bank = 33, IO_L8N_SRCC_33 (E-TXER)
# GMII Receive
#NET "phy_rx_clk" LOC = "AP11" | IOSTANDARD=LVCMOS25 | TNM_NET = "clk_rx_local"; # (E-RXCLK)
#NET "phy_rxd<0>" LOC = "AN13" | IOSTANDARD=LVCMOS25; # Bank = 33, IO_L15P_33 (E-RXD0)
#NET "phy_rxd<1>" LOC = "AF14" | IOSTANDARD=LVCMOS25; # Bank = 33, IO_L14N_VREF_33 (E-RXD1)
#NET "phy_rxd<2>" LOC = "AE14" | IOSTANDARD=LVCMOS25; # Bank = 33, IO_L14P_33 (E-RXD2)
#NET "phy_rxd<3>" LOC = "AN12" | IOSTANDARD=LVCMOS25; # Bank = 33, IO_L13N_33 (E-RXD3)
#NET "phy_rxd<4>" LOC = "AM12" | IOSTANDARD=LVCMOS25; # Bank = 33, IO_L13P_33 (E-RXD4)
#NET "phy_rxd<5>" LOC = "AD11" | IOSTANDARD=LVCMOS25; # Bank = 33, IO_L10N_MRCC_33 (E-RXD5)
#NET "phy_rxd<6>" LOC = "AC12" | IOSTANDARD=LVCMOS25; # Bank = 33, IO_L9N_MRCC_33 (E-RXD6)
#NET "phy_rxd<7>" LOC = "AC13" | IOSTANDARD=LVCMOS25; # Bank = 33, IO_L9P_MRCC_33 (E-RXD7)
#NET "phy_rx_dv" LOC = "AM13" | IOSTANDARD=LVCMOS25; # Bank = 33, IO_L15N_33 (E-RXDV)
#NET "phy_rx_er" LOC = "AG12" | IOSTANDARD=LVCMOS25; # Bank = 33, IO_L16P_33 (E-RXER)
# SGMII interface
NET "phy_sgmii_rx_p" LOC = "B5";
NET "phy_sgmii_rx_n" LOC = "B6";
NET "phy_sgmii_tx_p" LOC = "A3";
NET "phy_sgmii_tx_n" LOC = "A4";
NET "phy_sgmii_clk_p" LOC = "H6" | TNM_NET = "sgmii_mgtrefclk";
NET "phy_sgmii_clk_n" LOC = "H5";
# Timing constraints for Ethernet PHY
#TIMESPEC "TS_rx_clk_root" = PERIOD "clk_rx_local" 8000 ps HIGH 50 %;
TIMESPEC "TS_mgtrefclk" = PERIOD "sgmii_mgtrefclk" 8 ns HIGH 50 %;
# Silicon Labs CP2103
NET "uart_rxd" LOC = "J25" | IOSTANDARD=LVCMOS25; # Bank = 24, IO_L9P_MRCC_24 (U24.24)
NET "uart_txd" LOC = "J24" | IOSTANDARD=LVCMOS25; # Bank = 24, IO_L9N_MRCC_24 (U24.25)
NET "uart_rts" LOC = "T23" | IOSTANDARD=LVCMOS25; # Bank = 24, IO_L8N_SRCC_24 (U24.23)
NET "uart_cts" LOC = "T24" | IOSTANDARD=LVCMOS25; # Bank = 24, IO_L8P_SRCC_24 (U24.22)

View File

@ -0,0 +1,81 @@
# FPGA settings
FPGA_PART = xc6vlx130t-1ff1156
FPGA_TOP = fpga
FPGA_ARCH = spartan6
# PROM settings
#PROM = xc18v04
#SPI_PROM_SIZE = (in bytes)
# Files for synthesis
SYN_FILES = rtl/fpga.v
SYN_FILES += rtl/fpga_core.v
SYN_FILES += rtl/debounce_switch.v
SYN_FILES += rtl/sync_reset.v
SYN_FILES += rtl/sync_signal.v
SYN_FILES += lib/eth/rtl/eth_mac_1g_fifo.v
SYN_FILES += lib/eth/rtl/eth_mac_1g.v
SYN_FILES += lib/eth/rtl/axis_gmii_rx.v
SYN_FILES += lib/eth/rtl/axis_gmii_tx.v
SYN_FILES += lib/eth/rtl/lfsr.v
SYN_FILES += lib/eth/rtl/eth_axis_rx.v
SYN_FILES += lib/eth/rtl/eth_axis_tx.v
SYN_FILES += lib/eth/rtl/udp_complete.v
SYN_FILES += lib/eth/rtl/udp_checksum_gen.v
SYN_FILES += lib/eth/rtl/udp.v
SYN_FILES += lib/eth/rtl/udp_ip_rx.v
SYN_FILES += lib/eth/rtl/udp_ip_tx.v
SYN_FILES += lib/eth/rtl/ip_complete.v
SYN_FILES += lib/eth/rtl/ip.v
SYN_FILES += lib/eth/rtl/ip_eth_rx.v
SYN_FILES += lib/eth/rtl/ip_eth_tx.v
SYN_FILES += lib/eth/rtl/ip_arb_mux_2.v
SYN_FILES += lib/eth/rtl/ip_mux_2.v
SYN_FILES += lib/eth/rtl/arp.v
SYN_FILES += lib/eth/rtl/arp_cache.v
SYN_FILES += lib/eth/rtl/arp_eth_rx.v
SYN_FILES += lib/eth/rtl/arp_eth_tx.v
SYN_FILES += lib/eth/rtl/eth_arb_mux_2.v
SYN_FILES += lib/eth/rtl/eth_mux_2.v
SYN_FILES += lib/eth/lib/axis/rtl/arbiter.v
SYN_FILES += lib/eth/lib/axis/rtl/priority_encoder.v
SYN_FILES += lib/eth/lib/axis/rtl/axis_fifo.v
SYN_FILES += lib/eth/lib/axis/rtl/axis_async_frame_fifo.v
SYN_FILES += coregen/gig_eth_pcs_pma_v11_5/gig_eth_pcs_pma_v11_5/example_design/sgmii_adapt/gig_eth_pcs_pma_v11_5_clk_gen.v
SYN_FILES += coregen/gig_eth_pcs_pma_v11_5/gig_eth_pcs_pma_v11_5/example_design/sgmii_adapt/gig_eth_pcs_pma_v11_5_johnson_cntr.v
SYN_FILES += coregen/gig_eth_pcs_pma_v11_5/gig_eth_pcs_pma_v11_5/example_design/sgmii_adapt/gig_eth_pcs_pma_v11_5_rx_rate_adapt.v
SYN_FILES += coregen/gig_eth_pcs_pma_v11_5/gig_eth_pcs_pma_v11_5/example_design/sgmii_adapt/gig_eth_pcs_pma_v11_5_sgmii_adapt.v
SYN_FILES += coregen/gig_eth_pcs_pma_v11_5/gig_eth_pcs_pma_v11_5/example_design/sgmii_adapt/gig_eth_pcs_pma_v11_5_tx_rate_adapt.v
SYN_FILES += coregen/gig_eth_pcs_pma_v11_5/gig_eth_pcs_pma_v11_5/example_design/transceiver/gig_eth_pcs_pma_v11_5_double_reset.v
SYN_FILES += coregen/gig_eth_pcs_pma_v11_5/gig_eth_pcs_pma_v11_5/example_design/transceiver/gig_eth_pcs_pma_v11_5_gtwizard_gtrxreset_seq.v
SYN_FILES += coregen/gig_eth_pcs_pma_v11_5/gig_eth_pcs_pma_v11_5/example_design/transceiver/gig_eth_pcs_pma_v11_5_rx_elastic_buffer.v
SYN_FILES += coregen/gig_eth_pcs_pma_v11_5/gig_eth_pcs_pma_v11_5/example_design/transceiver/gig_eth_pcs_pma_v11_5_v6_gtxwizard.v
SYN_FILES += coregen/gig_eth_pcs_pma_v11_5/gig_eth_pcs_pma_v11_5/example_design/transceiver/gig_eth_pcs_pma_v11_5_v6_gtxwizard_gtx.v
SYN_FILES += coregen/gig_eth_pcs_pma_v11_5/gig_eth_pcs_pma_v11_5/example_design/transceiver/gig_eth_pcs_pma_v11_5_v6_gtxwizard_top.v
SYN_FILES += coregen/gig_eth_pcs_pma_v11_5/gig_eth_pcs_pma_v11_5/example_design/gig_eth_pcs_pma_v11_5_block.v
SYN_FILES += coregen/gig_eth_pcs_pma_v11_5/gig_eth_pcs_pma_v11_5/example_design/gig_eth_pcs_pma_v11_5_reset_sync.v
SYN_FILES += coregen/gig_eth_pcs_pma_v11_5/gig_eth_pcs_pma_v11_5/example_design/gig_eth_pcs_pma_v11_5_sync_block.v
SYN_FILES += coregen/gig_eth_pcs_pma_v11_5/gig_eth_pcs_pma_v11_5.v
# UCF files
UCF_FILES = fpga.ucf
UCF_FILES += clock.ucf
# NGC paths for ngdbuild
NGC_PATHS = coregen/gig_eth_pcs_pma_v11_5
# Bitgen options
BITGEN_OPTIONS = -g StartupClk:Cclk -g ConfigRate:26
include ../common/xilinx.mk
program: $(FPGA_TOP).bit
echo "setmode -bscan" > program.cmd
echo "setcable -p auto" >> program.cmd
echo "identify" >> program.cmd
echo "assignfile -p 2 -file $(FPGA_TOP).bit" >> program.cmd
echo "program -p 2" >> program.cmd
echo "quit" >> program.cmd
impact -batch program.cmd

View File

@ -0,0 +1 @@
../../../../

View File

@ -0,0 +1,89 @@
/*
Copyright (c) 2014-2017 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog-2001
`timescale 1 ns / 1 ps
/*
* Synchronizes switch and button inputs with a slow sampled shift register
*/
module debounce_switch #(
parameter WIDTH=1, // width of the input and output signals
parameter N=3, // length of shift register
parameter RATE=125000 // clock division factor
)(
input wire clk,
input wire rst,
input wire [WIDTH-1:0] in,
output wire [WIDTH-1:0] out
);
reg [23:0] cnt_reg = 24'd0;
reg [N-1:0] debounce_reg[WIDTH-1:0];
reg [WIDTH-1:0] state;
/*
* The synchronized output is the state register
*/
assign out = state;
integer k;
always @(posedge clk or posedge rst) begin
if (rst) begin
cnt_reg <= 0;
state <= 0;
for (k = 0; k < WIDTH; k = k + 1) begin
debounce_reg[k] <= 0;
end
end else begin
if (cnt_reg < RATE) begin
cnt_reg <= cnt_reg + 24'd1;
end else begin
cnt_reg <= 24'd0;
end
if (cnt_reg == 24'd0) begin
for (k = 0; k < WIDTH; k = k + 1) begin
debounce_reg[k] <= {debounce_reg[k][N-2:0], in[k]};
end
end
for (k = 0; k < WIDTH; k = k + 1) begin
if (|debounce_reg[k] == 0) begin
state[k] <= 0;
end else if (&debounce_reg[k] == 1) begin
state[k] <= 1;
end else begin
state[k] <= state[k];
end
end
end
end
endmodule

View File

@ -0,0 +1,398 @@
/*
Copyright (c) 2014-2017 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* FPGA top-level module
*/
module fpga (
/*
* Clock: 200MHz
* Reset: Push button, active high
*/
input wire sys_clk_p,
input wire sys_clk_n,
input wire reset,
/*
* GPIO
*/
input wire btnu,
input wire btnl,
input wire btnd,
input wire btnr,
input wire btnc,
input wire [7:0] sw,
output wire ledu,
output wire ledl,
output wire ledd,
output wire ledr,
output wire ledc,
output wire [7:0] led,
/*
* Ethernet: 1000BASE-T SGMII
*/
input wire phy_sgmii_rx_p,
input wire phy_sgmii_rx_n,
output wire phy_sgmii_tx_p,
output wire phy_sgmii_tx_n,
input wire phy_sgmii_clk_p,
input wire phy_sgmii_clk_n,
output wire phy_reset_n,
/*
* Silicon Labs CP2103 USB UART
*/
output wire uart_rxd,
input wire uart_txd,
input wire uart_rts,
output wire uart_cts
);
// Clock and reset
wire sys_clk_ibufg;
wire sys_clk_bufg;
wire clk_125mhz_mmcm_out;
// Internal 125 MHz clock
wire clk_125mhz_int;
wire rst_125mhz_int;
wire mmcm_rst = reset;
wire mmcm_locked;
wire mmcm_clkfb;
IBUFGDS
clk_ibufgds_inst(
.I(sys_clk_p),
.IB(sys_clk_n),
.O(sys_clk_ibufg)
);
// MMCM instance
// 200 MHz in, 125 MHz out
// PFD range: 10 MHz to 450 MHz
// VCO range: 600 MHz to 1200 MHz
// M = 5, D = 1 sets Fvco = 1000 MHz (in range)
// Divide by 8 to get output frequency of 125 MHz
MMCM_BASE #(
.BANDWIDTH("OPTIMIZED"),
.CLKOUT0_DIVIDE_F(8),
.CLKOUT0_DUTY_CYCLE(0.5),
.CLKOUT0_PHASE(0),
.CLKOUT1_DIVIDE(1),
.CLKOUT1_DUTY_CYCLE(0.5),
.CLKOUT1_PHASE(0),
.CLKOUT2_DIVIDE(1),
.CLKOUT2_DUTY_CYCLE(0.5),
.CLKOUT2_PHASE(0),
.CLKOUT3_DIVIDE(1),
.CLKOUT3_DUTY_CYCLE(0.5),
.CLKOUT3_PHASE(0),
.CLKOUT4_DIVIDE(1),
.CLKOUT4_DUTY_CYCLE(0.5),
.CLKOUT4_PHASE(0),
.CLKOUT5_DIVIDE(1),
.CLKOUT5_DUTY_CYCLE(0.5),
.CLKOUT5_PHASE(0),
.CLKOUT6_DIVIDE(1),
.CLKOUT6_DUTY_CYCLE(0.5),
.CLKOUT6_PHASE(0),
.CLKFBOUT_MULT_F(5),
.CLKFBOUT_PHASE(0),
.DIVCLK_DIVIDE(1),
.REF_JITTER1(0.100),
.CLKIN1_PERIOD(5.0),
.STARTUP_WAIT("FALSE"),
.CLKOUT4_CASCADE("FALSE")
)
clk_mmcm_inst (
.CLKIN1(sys_clk_ibufg),
.CLKFBIN(mmcm_clkfb),
.RST(mmcm_rst),
.PWRDWN(1'b0),
.CLKOUT0(clk_125mhz_mmcm_out),
.CLKOUT0B(),
.CLKOUT1(),
.CLKOUT1B(),
.CLKOUT2(),
.CLKOUT2B(),
.CLKOUT3(),
.CLKOUT3B(),
.CLKOUT4(),
.CLKOUT5(),
.CLKOUT6(),
.CLKFBOUT(mmcm_clkfb),
.CLKFBOUTB(),
.LOCKED(mmcm_locked)
);
BUFG
clk_125mhz_bufg_inst (
.I(clk_125mhz_mmcm_out),
.O(clk_125mhz_int)
);
sync_reset #(
.N(4)
)
sync_reset_125mhz_inst (
.clk(clk_125mhz_int),
.rst(~mmcm_locked),
.sync_reset_out(rst_125mhz_int)
);
// GPIO
wire btnu_int;
wire btnl_int;
wire btnd_int;
wire btnr_int;
wire btnc_int;
wire [7:0] sw_int;
wire ledu_int;
wire ledl_int;
wire ledd_int;
wire ledr_int;
wire ledc_int;
wire [7:0] led_int;
wire uart_rxd_int;
wire uart_txd_int;
wire uart_rts_int;
wire uart_cts_int;
debounce_switch #(
.WIDTH(13),
.N(4),
.RATE(125000)
)
debounce_switch_inst (
.clk(clk_125mhz_int),
.rst(rst_125mhz_int),
.in({btnu,
btnl,
btnd,
btnr,
btnc,
sw}),
.out({btnu_int,
btnl_int,
btnd_int,
btnr_int,
btnc_int,
sw_int})
);
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})
);
assign ledu = ledu_int;
assign ledl = ledl_int;
assign ledd = ledd_int;
assign ledr = ledr_int;
assign ledc = ledc_int;
//assign led = led_int;
assign uart_rxd = uart_rxd_int;
assign uart_cts = uart_cts_int;
// SGMII interface to PHY
wire phy_gmii_clk_int;
wire phy_gmii_rst_int;
wire phy_gmii_clk_en_int;
wire [7:0] phy_gmii_txd_int;
wire phy_gmii_tx_en_int;
wire phy_gmii_tx_er_int;
wire [7:0] phy_gmii_rxd_int;
wire phy_gmii_rx_dv_int;
wire phy_gmii_rx_er_int;
wire phy_sgmii_mgtrefclk;
wire phy_sgmii_txoutclk;
wire phy_sgmii_userclk2;
IBUFDS_GTXE1
phy_sgmii_ibufds_mgtrefclk (
.CEB (1'b0),
.I (phy_sgmii_clk_p),
.IB (phy_sgmii_clk_n),
.O (phy_sgmii_mgtrefclk),
.ODIV2 ()
);
BUFG
phy_sgmii_bufg_userclk2 (
.I (phy_sgmii_txoutclk),
.O (phy_sgmii_userclk2)
);
assign phy_gmii_clk_int = phy_sgmii_userclk2;
sync_reset #(
.N(4)
)
sync_reset_pcspma_inst (
.clk(phy_gmii_clk_int),
.rst(rst_125mhz_int),
.sync_reset_out(phy_gmii_rst_int)
);
wire [15:0] pcspma_status_vector;
wire pcspma_status_link_status = pcspma_status_vector[0];
wire pcspma_status_link_synchronization = pcspma_status_vector[1];
wire pcspma_status_rudi_c = pcspma_status_vector[2];
wire pcspma_status_rudi_i = pcspma_status_vector[3];
wire pcspma_status_rudi_invalid = pcspma_status_vector[4];
wire pcspma_status_rxdisperr = pcspma_status_vector[5];
wire pcspma_status_rxnotintable = pcspma_status_vector[6];
wire pcspma_status_phy_link_status = pcspma_status_vector[7];
wire [1:0] pcspma_status_remote_fault_encdg = pcspma_status_vector[9:8];
wire [1:0] pcspma_status_speed = pcspma_status_vector[11:10];
wire pcspma_status_duplex = pcspma_status_vector[12];
wire pcspma_status_remote_fault = pcspma_status_vector[13];
wire [1:0] pcspma_status_pause = pcspma_status_vector[15:14];
wire [4:0] pcspma_config_vector;
assign pcspma_config_vector[4] = 1'b1; // autonegotiation enable
assign pcspma_config_vector[3] = 1'b0; // isolate
assign pcspma_config_vector[2] = 1'b0; // power down
assign pcspma_config_vector[1] = 1'b0; // loopback enable
assign pcspma_config_vector[0] = 1'b0; // unidirectional enable
wire [15:0] pcspma_an_config_vector;
assign pcspma_an_config_vector[15] = 1'b1; // SGMII link status
assign pcspma_an_config_vector[14] = 1'b1; // SGMII Acknowledge
assign pcspma_an_config_vector[13:12] = 2'b01; // full duplex
assign pcspma_an_config_vector[11:10] = 2'b10; // SGMII speed
assign pcspma_an_config_vector[9] = 1'b0; // reserved
assign pcspma_an_config_vector[8:7] = 2'b00; // pause frames - SGMII reserved
assign pcspma_an_config_vector[6] = 1'b0; // reserved
assign pcspma_an_config_vector[5] = 1'b0; // full duplex - SGMII reserved
assign pcspma_an_config_vector[4:1] = 4'b0000; // reserved
assign pcspma_an_config_vector[0] = 1'b1; // SGMII
gig_eth_pcs_pma_v11_5_block
eth_pcspma (
// Transceiver Interface
.mgtrefclk (phy_sgmii_mgtrefclk),
.gtx_reset_clk (clk_125mhz_int),
.txp (phy_sgmii_tx_p),
.txn (phy_sgmii_tx_n),
.rxp (phy_sgmii_rx_p),
.rxn (phy_sgmii_rx_n),
.txoutclk (phy_sgmii_txoutclk),
.userclk2 (phy_sgmii_userclk2),
.pma_reset (rst_125mhz_int),
// GMII Interface
.sgmii_clk_r (),
.sgmii_clk_f (),
.sgmii_clk_en (phy_gmii_clk_en_int),
.gmii_txd (phy_gmii_txd_int),
.gmii_tx_en (phy_gmii_tx_en_int),
.gmii_tx_er (phy_gmii_tx_er_int),
.gmii_rxd (phy_gmii_rxd_int),
.gmii_rx_dv (phy_gmii_rx_dv_int),
.gmii_rx_er (phy_gmii_rx_er_int),
.gmii_isolate (),
// Management: Alternative to MDIO Interface
.configuration_vector (pcspma_config_vector),
.an_interrupt (),
.an_adv_config_vector (pcspma_an_config_vector),
.an_restart_config (1'b0),
.link_timer_value (9'd50),
// Speed Control
.speed_is_10_100 (pcspma_status_speed != 2'b10),
.speed_is_100 (pcspma_status_speed == 2'b01),
// General IO's
.status_vector (pcspma_status_vector),
.reset (rst_125mhz_int),
.signal_detect (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[7] ? (sw[6] ? pcspma_status_vector[15:8] : pcspma_status_vector[7:0]) : led_int;
fpga_core
core_inst (
/*
* Clock: 125MHz
* Synchronous reset
*/
.clk_125mhz(clk_125mhz_int),
.rst_125mhz(rst_125mhz_int),
/*
* GPIO
*/
.btnu(btnu_int),
.btnl(btnl_int),
.btnd(btnd_int),
.btnr(btnr_int),
.btnc(btnc_int),
.sw(sw_int),
.ledu(ledu_int),
.ledl(ledl_int),
.ledd(ledd_int),
.ledr(ledr_int),
.ledc(ledc_int),
.led(led_int),
/*
* Ethernet: 1000BASE-T SGMII
*/
.phy_gmii_clk(phy_gmii_clk_int),
.phy_gmii_rst(phy_gmii_rst_int),
.phy_gmii_clk_en(phy_gmii_clk_en_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_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),
/*
* UART: 115200 bps, 8N1
*/
.uart_rxd(uart_rxd_int),
.uart_txd(uart_txd_int),
.uart_rts(uart_rts_int),
.uart_cts(uart_cts_int)
);
endmodule

View File

@ -0,0 +1,579 @@
/*
Copyright (c) 2014-2017 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* FPGA core logic
*/
module fpga_core
(
/*
* Clock: 125MHz
* Synchronous reset
*/
input wire clk_125mhz,
input wire rst_125mhz,
/*
* GPIO
*/
input wire btnu,
input wire btnl,
input wire btnd,
input wire btnr,
input wire btnc,
input wire [7:0] sw,
output wire ledu,
output wire ledl,
output wire ledd,
output wire ledr,
output wire ledc,
output wire [7:0] led,
/*
* Ethernet: 1000BASE-T SGMII
*/
input wire phy_gmii_clk,
input wire phy_gmii_rst,
input wire phy_gmii_clk_en,
input wire [7:0] phy_gmii_rxd,
input wire phy_gmii_rx_dv,
input wire phy_gmii_rx_er,
output wire [7:0] phy_gmii_txd,
output wire phy_gmii_tx_en,
output wire phy_gmii_tx_er,
output wire phy_reset_n,
/*
* Silicon Labs CP2103 USB UART
*/
output wire uart_rxd,
input wire uart_txd,
input wire uart_rts,
output wire uart_cts
);
// AXI between MAC and Ethernet modules
wire [7:0] rx_axis_tdata;
wire rx_axis_tvalid;
wire rx_axis_tready;
wire rx_axis_tlast;
wire rx_axis_tuser;
wire [7:0] tx_axis_tdata;
wire tx_axis_tvalid;
wire tx_axis_tready;
wire tx_axis_tlast;
wire tx_axis_tuser;
// Ethernet frame between Ethernet modules and UDP stack
wire rx_eth_hdr_ready;
wire rx_eth_hdr_valid;
wire [47:0] rx_eth_dest_mac;
wire [47:0] rx_eth_src_mac;
wire [15:0] rx_eth_type;
wire [7:0] rx_eth_payload_tdata;
wire rx_eth_payload_tvalid;
wire rx_eth_payload_tready;
wire rx_eth_payload_tlast;
wire rx_eth_payload_tuser;
wire tx_eth_hdr_ready;
wire tx_eth_hdr_valid;
wire [47:0] tx_eth_dest_mac;
wire [47:0] tx_eth_src_mac;
wire [15:0] tx_eth_type;
wire [7:0] tx_eth_payload_tdata;
wire tx_eth_payload_tvalid;
wire tx_eth_payload_tready;
wire tx_eth_payload_tlast;
wire tx_eth_payload_tuser;
// IP frame connections
wire rx_ip_hdr_valid;
wire rx_ip_hdr_ready;
wire [47:0] rx_ip_eth_dest_mac;
wire [47:0] rx_ip_eth_src_mac;
wire [15:0] rx_ip_eth_type;
wire [3:0] rx_ip_version;
wire [3:0] rx_ip_ihl;
wire [5:0] rx_ip_dscp;
wire [1:0] rx_ip_ecn;
wire [15:0] rx_ip_length;
wire [15:0] rx_ip_identification;
wire [2:0] rx_ip_flags;
wire [12:0] rx_ip_fragment_offset;
wire [7:0] rx_ip_ttl;
wire [7:0] rx_ip_protocol;
wire [15:0] rx_ip_header_checksum;
wire [31:0] rx_ip_source_ip;
wire [31:0] rx_ip_dest_ip;
wire [7:0] rx_ip_payload_tdata;
wire rx_ip_payload_tvalid;
wire rx_ip_payload_tready;
wire rx_ip_payload_tlast;
wire rx_ip_payload_tuser;
wire tx_ip_hdr_valid;
wire tx_ip_hdr_ready;
wire [5:0] tx_ip_dscp;
wire [1:0] tx_ip_ecn;
wire [15:0] tx_ip_length;
wire [7:0] tx_ip_ttl;
wire [7:0] tx_ip_protocol;
wire [31:0] tx_ip_source_ip;
wire [31:0] tx_ip_dest_ip;
wire [7:0] tx_ip_payload_tdata;
wire tx_ip_payload_tvalid;
wire tx_ip_payload_tready;
wire tx_ip_payload_tlast;
wire tx_ip_payload_tuser;
// UDP frame connections
wire rx_udp_hdr_valid;
wire rx_udp_hdr_ready;
wire [47:0] rx_udp_eth_dest_mac;
wire [47:0] rx_udp_eth_src_mac;
wire [15:0] rx_udp_eth_type;
wire [3:0] rx_udp_ip_version;
wire [3:0] rx_udp_ip_ihl;
wire [5:0] rx_udp_ip_dscp;
wire [1:0] rx_udp_ip_ecn;
wire [15:0] rx_udp_ip_length;
wire [15:0] rx_udp_ip_identification;
wire [2:0] rx_udp_ip_flags;
wire [12:0] rx_udp_ip_fragment_offset;
wire [7:0] rx_udp_ip_ttl;
wire [7:0] rx_udp_ip_protocol;
wire [15:0] rx_udp_ip_header_checksum;
wire [31:0] rx_udp_ip_source_ip;
wire [31:0] rx_udp_ip_dest_ip;
wire [15:0] rx_udp_source_port;
wire [15:0] rx_udp_dest_port;
wire [15:0] rx_udp_length;
wire [15:0] rx_udp_checksum;
wire [7:0] rx_udp_payload_tdata;
wire rx_udp_payload_tvalid;
wire rx_udp_payload_tready;
wire rx_udp_payload_tlast;
wire rx_udp_payload_tuser;
wire tx_udp_hdr_valid;
wire tx_udp_hdr_ready;
wire [5:0] tx_udp_ip_dscp;
wire [1:0] tx_udp_ip_ecn;
wire [7:0] tx_udp_ip_ttl;
wire [31:0] tx_udp_ip_source_ip;
wire [31:0] tx_udp_ip_dest_ip;
wire [15:0] tx_udp_source_port;
wire [15:0] tx_udp_dest_port;
wire [15:0] tx_udp_length;
wire [15:0] tx_udp_checksum;
wire [7:0] tx_udp_payload_tdata;
wire tx_udp_payload_tvalid;
wire tx_udp_payload_tready;
wire tx_udp_payload_tlast;
wire tx_udp_payload_tuser;
wire [7:0] rx_fifo_udp_payload_tdata;
wire rx_fifo_udp_payload_tvalid;
wire rx_fifo_udp_payload_tready;
wire rx_fifo_udp_payload_tlast;
wire rx_fifo_udp_payload_tuser;
wire [7:0] tx_fifo_udp_payload_tdata;
wire tx_fifo_udp_payload_tvalid;
wire tx_fifo_udp_payload_tready;
wire tx_fifo_udp_payload_tlast;
wire tx_fifo_udp_payload_tuser;
// Configuration
wire [47:0] local_mac = 48'h02_00_00_00_00_00;
wire [31:0] local_ip = {8'd192, 8'd168, 8'd1, 8'd128};
wire [31:0] gateway_ip = {8'd192, 8'd168, 8'd1, 8'd1};
wire [31:0] subnet_mask = {8'd255, 8'd255, 8'd255, 8'd0};
// IP ports not used
assign rx_ip_hdr_ready = 1;
assign rx_ip_payload_tready = 1;
assign tx_ip_hdr_valid = 0;
assign tx_ip_dscp = 0;
assign tx_ip_ecn = 0;
assign tx_ip_length = 0;
assign tx_ip_ttl = 0;
assign tx_ip_protocol = 0;
assign tx_ip_source_ip = 0;
assign tx_ip_dest_ip = 0;
assign tx_ip_payload_tdata = 0;
assign tx_ip_payload_tvalid = 0;
assign tx_ip_payload_tlast = 0;
assign tx_ip_payload_tuser = 0;
// Loop back UDP
wire match_cond = rx_udp_dest_port == 1234;
wire no_match = ~match_cond;
reg match_cond_reg = 0;
reg no_match_reg = 0;
always @(posedge clk_125mhz) begin
if (rst_125mhz) begin
match_cond_reg <= 0;
no_match_reg <= 0;
end else begin
if (rx_udp_payload_tvalid) begin
if ((~match_cond_reg & ~no_match_reg) |
(rx_udp_payload_tvalid & rx_udp_payload_tready & rx_udp_payload_tlast)) begin
match_cond_reg <= match_cond;
no_match_reg <= no_match;
end
end else begin
match_cond_reg <= 0;
no_match_reg <= 0;
end
end
end
assign tx_udp_hdr_valid = rx_udp_hdr_valid & match_cond;
assign rx_udp_hdr_ready = (tx_eth_hdr_ready & match_cond) | no_match;
assign tx_udp_ip_dscp = 0;
assign tx_udp_ip_ecn = 0;
assign tx_udp_ip_ttl = 64;
assign tx_udp_ip_source_ip = local_ip;
assign tx_udp_ip_dest_ip = rx_udp_ip_source_ip;
assign tx_udp_source_port = rx_udp_dest_port;
assign tx_udp_dest_port = rx_udp_source_port;
assign tx_udp_length = rx_udp_length;
assign tx_udp_checksum = 0;
//assign tx_udp_payload_tdata = rx_udp_payload_tdata;
//assign tx_udp_payload_tvalid = rx_udp_payload_tvalid;
//assign rx_udp_payload_tready = tx_udp_payload_tready;
//assign tx_udp_payload_tlast = rx_udp_payload_tlast;
//assign tx_udp_payload_tuser = rx_udp_payload_tuser;
assign tx_udp_payload_tdata = tx_fifo_udp_payload_tdata;
assign tx_udp_payload_tvalid = tx_fifo_udp_payload_tvalid;
assign tx_fifo_udp_payload_tready = tx_udp_payload_tready;
assign tx_udp_payload_tlast = tx_fifo_udp_payload_tlast;
assign tx_udp_payload_tuser = tx_fifo_udp_payload_tuser;
assign rx_fifo_udp_payload_tdata = rx_udp_payload_tdata;
assign rx_fifo_udp_payload_tvalid = rx_udp_payload_tvalid & match_cond_reg;
assign rx_udp_payload_tready = (rx_fifo_udp_payload_tready & match_cond_reg) | no_match_reg;
assign rx_fifo_udp_payload_tlast = rx_udp_payload_tlast;
assign rx_fifo_udp_payload_tuser = rx_udp_payload_tuser;
// Place first payload byte onto LEDs
reg valid_last = 0;
reg [7:0] led_reg = 0;
always @(posedge clk_125mhz) begin
if (rst_125mhz) begin
led_reg <= 0;
end else begin
if (tx_udp_payload_tvalid) begin
if (~valid_last) begin
led_reg <= tx_udp_payload_tdata;
valid_last <= 1'b1;
end
if (tx_udp_payload_tlast) begin
valid_last <= 1'b0;
end
end
end
end
//assign led = sw;
assign ledu = 0;
assign ledl = 0;
assign ledd = 0;
assign ledr = 0;
assign ledc = 0;
assign led = led_reg;
assign phy_reset_n = ~rst_125mhz;
assign uart_rxd = 0;
assign uart_cts = 0;
eth_mac_1g_fifo #(
.ENABLE_PADDING(1),
.MIN_FRAME_LENGTH(64),
.TX_FIFO_ADDR_WIDTH(12),
.RX_FIFO_ADDR_WIDTH(12)
)
eth_mac_inst (
.rx_clk(phy_gmii_clk),
.rx_rst(phy_gmii_rst),
.tx_clk(phy_gmii_clk),
.tx_rst(phy_gmii_rst),
.logic_clk(clk_125mhz),
.logic_rst(rst_125mhz),
.tx_axis_tdata(tx_axis_tdata),
.tx_axis_tvalid(tx_axis_tvalid),
.tx_axis_tready(tx_axis_tready),
.tx_axis_tlast(tx_axis_tlast),
.tx_axis_tuser(tx_axis_tuser),
.rx_axis_tdata(rx_axis_tdata),
.rx_axis_tvalid(rx_axis_tvalid),
.rx_axis_tready(rx_axis_tready),
.rx_axis_tlast(rx_axis_tlast),
.rx_axis_tuser(rx_axis_tuser),
.gmii_rxd(phy_gmii_rxd),
.gmii_rx_dv(phy_gmii_rx_dv),
.gmii_rx_er(phy_gmii_rx_er),
.gmii_txd(phy_gmii_txd),
.gmii_tx_en(phy_gmii_tx_en),
.gmii_tx_er(phy_gmii_tx_er),
.rx_clk_enable(phy_gmii_clk_en),
.tx_clk_enable(phy_gmii_clk_en),
.rx_mii_select(1'b0),
.tx_mii_select(1'b0),
.tx_fifo_overflow(),
.tx_fifo_bad_frame(),
.tx_fifo_good_frame(),
.rx_error_bad_frame(rx_error_bad_frame),
.rx_error_bad_fcs(rx_error_bad_fcs),
.rx_fifo_overflow(),
.rx_fifo_bad_frame(),
.rx_fifo_good_frame(),
.ifg_delay(12)
);
eth_axis_rx
eth_axis_rx_inst (
.clk(clk_125mhz),
.rst(rst_125mhz),
// AXI input
.input_axis_tdata(rx_axis_tdata),
.input_axis_tvalid(rx_axis_tvalid),
.input_axis_tready(rx_axis_tready),
.input_axis_tlast(rx_axis_tlast),
.input_axis_tuser(rx_axis_tuser),
// Ethernet frame output
.output_eth_hdr_valid(rx_eth_hdr_valid),
.output_eth_hdr_ready(rx_eth_hdr_ready),
.output_eth_dest_mac(rx_eth_dest_mac),
.output_eth_src_mac(rx_eth_src_mac),
.output_eth_type(rx_eth_type),
.output_eth_payload_tdata(rx_eth_payload_tdata),
.output_eth_payload_tvalid(rx_eth_payload_tvalid),
.output_eth_payload_tready(rx_eth_payload_tready),
.output_eth_payload_tlast(rx_eth_payload_tlast),
.output_eth_payload_tuser(rx_eth_payload_tuser),
// Status signals
.busy(),
.error_header_early_termination()
);
eth_axis_tx
eth_axis_tx_inst (
.clk(clk_125mhz),
.rst(rst_125mhz),
// Ethernet frame input
.input_eth_hdr_valid(tx_eth_hdr_valid),
.input_eth_hdr_ready(tx_eth_hdr_ready),
.input_eth_dest_mac(tx_eth_dest_mac),
.input_eth_src_mac(tx_eth_src_mac),
.input_eth_type(tx_eth_type),
.input_eth_payload_tdata(tx_eth_payload_tdata),
.input_eth_payload_tvalid(tx_eth_payload_tvalid),
.input_eth_payload_tready(tx_eth_payload_tready),
.input_eth_payload_tlast(tx_eth_payload_tlast),
.input_eth_payload_tuser(tx_eth_payload_tuser),
// AXI output
.output_axis_tdata(tx_axis_tdata),
.output_axis_tvalid(tx_axis_tvalid),
.output_axis_tready(tx_axis_tready),
.output_axis_tlast(tx_axis_tlast),
.output_axis_tuser(tx_axis_tuser),
// Status signals
.busy()
);
udp_complete
udp_complete_inst (
.clk(clk_125mhz),
.rst(rst_125mhz),
// Ethernet frame input
.input_eth_hdr_valid(rx_eth_hdr_valid),
.input_eth_hdr_ready(rx_eth_hdr_ready),
.input_eth_dest_mac(rx_eth_dest_mac),
.input_eth_src_mac(rx_eth_src_mac),
.input_eth_type(rx_eth_type),
.input_eth_payload_tdata(rx_eth_payload_tdata),
.input_eth_payload_tvalid(rx_eth_payload_tvalid),
.input_eth_payload_tready(rx_eth_payload_tready),
.input_eth_payload_tlast(rx_eth_payload_tlast),
.input_eth_payload_tuser(rx_eth_payload_tuser),
// Ethernet frame output
.output_eth_hdr_valid(tx_eth_hdr_valid),
.output_eth_hdr_ready(tx_eth_hdr_ready),
.output_eth_dest_mac(tx_eth_dest_mac),
.output_eth_src_mac(tx_eth_src_mac),
.output_eth_type(tx_eth_type),
.output_eth_payload_tdata(tx_eth_payload_tdata),
.output_eth_payload_tvalid(tx_eth_payload_tvalid),
.output_eth_payload_tready(tx_eth_payload_tready),
.output_eth_payload_tlast(tx_eth_payload_tlast),
.output_eth_payload_tuser(tx_eth_payload_tuser),
// IP frame input
.input_ip_hdr_valid(tx_ip_hdr_valid),
.input_ip_hdr_ready(tx_ip_hdr_ready),
.input_ip_dscp(tx_ip_dscp),
.input_ip_ecn(tx_ip_ecn),
.input_ip_length(tx_ip_length),
.input_ip_ttl(tx_ip_ttl),
.input_ip_protocol(tx_ip_protocol),
.input_ip_source_ip(tx_ip_source_ip),
.input_ip_dest_ip(tx_ip_dest_ip),
.input_ip_payload_tdata(tx_ip_payload_tdata),
.input_ip_payload_tvalid(tx_ip_payload_tvalid),
.input_ip_payload_tready(tx_ip_payload_tready),
.input_ip_payload_tlast(tx_ip_payload_tlast),
.input_ip_payload_tuser(tx_ip_payload_tuser),
// IP frame output
.output_ip_hdr_valid(rx_ip_hdr_valid),
.output_ip_hdr_ready(rx_ip_hdr_ready),
.output_ip_eth_dest_mac(rx_ip_eth_dest_mac),
.output_ip_eth_src_mac(rx_ip_eth_src_mac),
.output_ip_eth_type(rx_ip_eth_type),
.output_ip_version(rx_ip_version),
.output_ip_ihl(rx_ip_ihl),
.output_ip_dscp(rx_ip_dscp),
.output_ip_ecn(rx_ip_ecn),
.output_ip_length(rx_ip_length),
.output_ip_identification(rx_ip_identification),
.output_ip_flags(rx_ip_flags),
.output_ip_fragment_offset(rx_ip_fragment_offset),
.output_ip_ttl(rx_ip_ttl),
.output_ip_protocol(rx_ip_protocol),
.output_ip_header_checksum(rx_ip_header_checksum),
.output_ip_source_ip(rx_ip_source_ip),
.output_ip_dest_ip(rx_ip_dest_ip),
.output_ip_payload_tdata(rx_ip_payload_tdata),
.output_ip_payload_tvalid(rx_ip_payload_tvalid),
.output_ip_payload_tready(rx_ip_payload_tready),
.output_ip_payload_tlast(rx_ip_payload_tlast),
.output_ip_payload_tuser(rx_ip_payload_tuser),
// UDP frame input
.input_udp_hdr_valid(tx_udp_hdr_valid),
.input_udp_hdr_ready(tx_udp_hdr_ready),
.input_udp_ip_dscp(tx_udp_ip_dscp),
.input_udp_ip_ecn(tx_udp_ip_ecn),
.input_udp_ip_ttl(tx_udp_ip_ttl),
.input_udp_ip_source_ip(tx_udp_ip_source_ip),
.input_udp_ip_dest_ip(tx_udp_ip_dest_ip),
.input_udp_source_port(tx_udp_source_port),
.input_udp_dest_port(tx_udp_dest_port),
.input_udp_length(tx_udp_length),
.input_udp_checksum(tx_udp_checksum),
.input_udp_payload_tdata(tx_udp_payload_tdata),
.input_udp_payload_tvalid(tx_udp_payload_tvalid),
.input_udp_payload_tready(tx_udp_payload_tready),
.input_udp_payload_tlast(tx_udp_payload_tlast),
.input_udp_payload_tuser(tx_udp_payload_tuser),
// UDP frame output
.output_udp_hdr_valid(rx_udp_hdr_valid),
.output_udp_hdr_ready(rx_udp_hdr_ready),
.output_udp_eth_dest_mac(rx_udp_eth_dest_mac),
.output_udp_eth_src_mac(rx_udp_eth_src_mac),
.output_udp_eth_type(rx_udp_eth_type),
.output_udp_ip_version(rx_udp_ip_version),
.output_udp_ip_ihl(rx_udp_ip_ihl),
.output_udp_ip_dscp(rx_udp_ip_dscp),
.output_udp_ip_ecn(rx_udp_ip_ecn),
.output_udp_ip_length(rx_udp_ip_length),
.output_udp_ip_identification(rx_udp_ip_identification),
.output_udp_ip_flags(rx_udp_ip_flags),
.output_udp_ip_fragment_offset(rx_udp_ip_fragment_offset),
.output_udp_ip_ttl(rx_udp_ip_ttl),
.output_udp_ip_protocol(rx_udp_ip_protocol),
.output_udp_ip_header_checksum(rx_udp_ip_header_checksum),
.output_udp_ip_source_ip(rx_udp_ip_source_ip),
.output_udp_ip_dest_ip(rx_udp_ip_dest_ip),
.output_udp_source_port(rx_udp_source_port),
.output_udp_dest_port(rx_udp_dest_port),
.output_udp_length(rx_udp_length),
.output_udp_checksum(rx_udp_checksum),
.output_udp_payload_tdata(rx_udp_payload_tdata),
.output_udp_payload_tvalid(rx_udp_payload_tvalid),
.output_udp_payload_tready(rx_udp_payload_tready),
.output_udp_payload_tlast(rx_udp_payload_tlast),
.output_udp_payload_tuser(rx_udp_payload_tuser),
// Status signals
.ip_rx_busy(),
.ip_tx_busy(),
.udp_rx_busy(),
.udp_tx_busy(),
.ip_rx_error_header_early_termination(),
.ip_rx_error_payload_early_termination(),
.ip_rx_error_invalid_header(),
.ip_rx_error_invalid_checksum(),
.ip_tx_error_payload_early_termination(),
.ip_tx_error_arp_failed(),
.udp_rx_error_header_early_termination(),
.udp_rx_error_payload_early_termination(),
.udp_tx_error_payload_early_termination(),
// Configuration
.local_mac(local_mac),
.local_ip(local_ip),
.gateway_ip(gateway_ip),
.subnet_mask(subnet_mask),
.clear_arp_cache(0)
);
axis_fifo #(
.ADDR_WIDTH(12),
.DATA_WIDTH(8)
)
udp_payload_fifo (
.clk(clk_125mhz),
.rst(rst_125mhz),
// AXI input
.input_axis_tdata(rx_fifo_udp_payload_tdata),
.input_axis_tvalid(rx_fifo_udp_payload_tvalid),
.input_axis_tready(rx_fifo_udp_payload_tready),
.input_axis_tlast(rx_fifo_udp_payload_tlast),
.input_axis_tuser(rx_fifo_udp_payload_tuser),
// AXI output
.output_axis_tdata(tx_fifo_udp_payload_tdata),
.output_axis_tvalid(tx_fifo_udp_payload_tvalid),
.output_axis_tready(tx_fifo_udp_payload_tready),
.output_axis_tlast(tx_fifo_udp_payload_tlast),
.output_axis_tuser(tx_fifo_udp_payload_tuser)
);
endmodule

View File

@ -0,0 +1,52 @@
/*
Copyright (c) 2014-2017 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog-2001
`timescale 1 ns / 1 ps
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
* using a pipeline of N registers.
*/
module sync_reset #(
parameter N=2 // depth of synchronizer
)(
input wire clk,
input wire rst,
output wire sync_reset_out
);
reg [N-1:0] sync_reg = {N{1'b1}};
assign sync_reset_out = sync_reg[N-1];
always @(posedge clk or posedge rst) begin
if (rst)
sync_reg <= {N{1'b1}};
else
sync_reg <= {sync_reg[N-2:0], 1'b0};
end
endmodule

View File

@ -0,0 +1,58 @@
/*
Copyright (c) 2014-2017 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog-2001
`timescale 1 ns / 1 ps
/*
* Synchronizes an asyncronous signal to a given clock by using a pipeline of
* two registers.
*/
module sync_signal #(
parameter WIDTH=1, // width of the input and output signals
parameter N=2 // depth of synchronizer
)(
input wire clk,
input wire [WIDTH-1:0] in,
output wire [WIDTH-1:0] out
);
reg [WIDTH-1:0] sync_reg[N-1:0];
/*
* The synchronized output is the last register in the pipeline.
*/
assign out = sync_reg[N-1];
integer k;
always @(posedge clk) begin
sync_reg[0] <= in;
for (k = 1; k < N; k = k + 1) begin
sync_reg[k] <= sync_reg[k-1];
end
end
endmodule

View File

@ -0,0 +1 @@
../lib/eth/tb/arp_ep.py

View File

@ -0,0 +1 @@
../lib/eth/tb/axis_ep.py

View File

@ -0,0 +1 @@
../lib/eth/tb/eth_ep.py

View File

@ -0,0 +1 @@
../lib/eth/tb/gmii_ep.py

View File

@ -0,0 +1 @@
../lib/eth/tb/ip_ep.py

View File

@ -0,0 +1,328 @@
#!/usr/bin/env python
"""
Copyright (c) 2015-2017 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
from myhdl import *
import os
import eth_ep
import arp_ep
import udp_ep
import gmii_ep
module = 'fpga_core'
testbench = 'test_%s' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("../lib/eth/rtl/eth_mac_1g_fifo.v")
srcs.append("../lib/eth/rtl/eth_mac_1g.v")
srcs.append("../lib/eth/rtl/axis_gmii_rx.v")
srcs.append("../lib/eth/rtl/axis_gmii_tx.v")
srcs.append("../lib/eth/rtl/lfsr.v")
srcs.append("../lib/eth/rtl/eth_axis_rx.v")
srcs.append("../lib/eth/rtl/eth_axis_tx.v")
srcs.append("../lib/eth/rtl/udp_complete.v")
srcs.append("../lib/eth/rtl/udp_checksum_gen.v")
srcs.append("../lib/eth/rtl/udp.v")
srcs.append("../lib/eth/rtl/udp_ip_rx.v")
srcs.append("../lib/eth/rtl/udp_ip_tx.v")
srcs.append("../lib/eth/rtl/ip_complete.v")
srcs.append("../lib/eth/rtl/ip.v")
srcs.append("../lib/eth/rtl/ip_eth_rx.v")
srcs.append("../lib/eth/rtl/ip_eth_tx.v")
srcs.append("../lib/eth/rtl/ip_arb_mux_2.v")
srcs.append("../lib/eth/rtl/ip_mux_2.v")
srcs.append("../lib/eth/rtl/arp.v")
srcs.append("../lib/eth/rtl/arp_cache.v")
srcs.append("../lib/eth/rtl/arp_eth_rx.v")
srcs.append("../lib/eth/rtl/arp_eth_tx.v")
srcs.append("../lib/eth/rtl/eth_arb_mux_2.v")
srcs.append("../lib/eth/rtl/eth_mux_2.v")
srcs.append("../lib/eth/lib/axis/rtl/arbiter.v")
srcs.append("../lib/eth/lib/axis/rtl/priority_encoder.v")
srcs.append("../lib/eth/lib/axis/rtl/axis_fifo.v")
srcs.append("../lib/eth/lib/axis/rtl/axis_async_frame_fifo.v")
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
clk_125mhz = Signal(bool(0))
rst_125mhz = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
btnu = Signal(bool(0))
btnl = Signal(bool(0))
btnd = Signal(bool(0))
btnr = Signal(bool(0))
btnc = Signal(bool(0))
sw = Signal(intbv(0)[8:])
phy_gmii_clk = Signal(bool(0))
phy_gmii_rst = Signal(bool(0))
phy_gmii_clk_en = Signal(bool(0))
phy_gmii_rxd = Signal(intbv(0)[8:])
phy_gmii_rx_dv = Signal(bool(0))
phy_gmii_rx_er = Signal(bool(0))
uart_txd = Signal(bool(0))
uart_rts = Signal(bool(0))
# Outputs
ledu = Signal(bool(0))
ledl = Signal(bool(0))
ledd = Signal(bool(0))
ledr = Signal(bool(0))
ledc = Signal(bool(0))
led = Signal(intbv(0)[8:])
phy_gmii_txd = Signal(intbv(0)[8:])
phy_gmii_tx_en = Signal(bool(0))
phy_gmii_tx_er = Signal(bool(0))
phy_reset_n = Signal(bool(0))
uart_rxd = Signal(bool(0))
uart_cts = Signal(bool(0))
# sources and sinks
gmii_source = gmii_ep.GMIISource()
gmii_source_logic = gmii_source.create_logic(
phy_gmii_clk,
phy_gmii_rst,
txd=phy_gmii_rxd,
tx_en=phy_gmii_rx_dv,
tx_er=phy_gmii_rx_er,
clk_enable=phy_gmii_clk_en,
name='gmii_source'
)
gmii_sink = gmii_ep.GMIISink()
gmii_sink_logic = gmii_sink.create_logic(
phy_gmii_clk,
phy_gmii_rst,
rxd=phy_gmii_txd,
rx_dv=phy_gmii_tx_en,
rx_er=phy_gmii_tx_er,
clk_enable=phy_gmii_clk_en,
name='gmii_sink'
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk_125mhz=clk_125mhz,
rst_125mhz=rst_125mhz,
current_test=current_test,
btnu=btnu,
btnl=btnl,
btnd=btnd,
btnr=btnr,
btnc=btnc,
sw=sw,
ledu=ledu,
ledl=ledl,
ledd=ledd,
ledr=ledr,
ledc=ledc,
led=led,
phy_gmii_clk=phy_gmii_clk,
phy_gmii_rst=phy_gmii_rst,
phy_gmii_clk_en=phy_gmii_clk_en,
phy_gmii_rxd=phy_gmii_rxd,
phy_gmii_rx_dv=phy_gmii_rx_dv,
phy_gmii_rx_er=phy_gmii_rx_er,
phy_gmii_txd=phy_gmii_txd,
phy_gmii_tx_en=phy_gmii_tx_en,
phy_gmii_tx_er=phy_gmii_tx_er,
phy_reset_n=phy_reset_n,
uart_rxd=uart_rxd,
uart_txd=uart_txd,
uart_rts=uart_rts,
uart_cts=uart_cts
)
@always(delay(4))
def clkgen():
clk.next = not clk
clk_125mhz.next = not clk_125mhz
phy_gmii_clk.next = not phy_gmii_clk
clk_enable_rate = Signal(int(0))
clk_enable_div = Signal(int(0))
@always(clk.posedge)
def clk_enable_gen():
if clk_enable_div.next > 0:
phy_gmii_clk_en.next = 0
clk_enable_div.next = clk_enable_div - 1
else:
phy_gmii_clk_en.next = 1
clk_enable_div.next = clk_enable_rate - 1
@instance
def check():
yield delay(100)
yield clk.posedge
rst.next = 1
rst_125mhz.next = 1
phy_gmii_rst.next = 1
yield clk.posedge
rst.next = 0
rst_125mhz.next = 0
phy_gmii_rst.next = 0
yield clk.posedge
yield delay(100)
yield clk.posedge
# testbench stimulus
yield clk.posedge
print("test 1: test UDP RX packet")
current_test.next = 1
test_frame = udp_ep.UDPFrame()
test_frame.eth_dest_mac = 0x020000000000
test_frame.eth_src_mac = 0xDAD1D2D3D4D5
test_frame.eth_type = 0x0800
test_frame.ip_version = 4
test_frame.ip_ihl = 5
test_frame.ip_dscp = 0
test_frame.ip_ecn = 0
test_frame.ip_length = None
test_frame.ip_identification = 0
test_frame.ip_flags = 2
test_frame.ip_fragment_offset = 0
test_frame.ip_ttl = 64
test_frame.ip_protocol = 0x11
test_frame.ip_header_checksum = None
test_frame.ip_source_ip = 0xc0a80181
test_frame.ip_dest_ip = 0xc0a80180
test_frame.udp_source_port = 5678
test_frame.udp_dest_port = 1234
test_frame.payload = bytearray(range(32))
test_frame.build()
gmii_source.send(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+test_frame.build_eth().build_axis_fcs().data)
# wait for ARP request packet
while gmii_sink.empty():
yield clk.posedge
rx_frame = gmii_sink.recv()
check_eth_frame = eth_ep.EthFrame()
check_eth_frame.parse_axis_fcs(rx_frame.data[8:])
check_frame = arp_ep.ARPFrame()
check_frame.parse_eth(check_eth_frame)
print(check_frame)
assert check_frame.eth_dest_mac == 0xFFFFFFFFFFFF
assert check_frame.eth_src_mac == 0x020000000000
assert check_frame.eth_type == 0x0806
assert check_frame.arp_htype == 0x0001
assert check_frame.arp_ptype == 0x0800
assert check_frame.arp_hlen == 6
assert check_frame.arp_plen == 4
assert check_frame.arp_oper == 1
assert check_frame.arp_sha == 0x020000000000
assert check_frame.arp_spa == 0xc0a80180
assert check_frame.arp_tha == 0x000000000000
assert check_frame.arp_tpa == 0xc0a80181
# generate response
arp_frame = arp_ep.ARPFrame()
arp_frame.eth_dest_mac = 0x020000000000
arp_frame.eth_src_mac = 0xDAD1D2D3D4D5
arp_frame.eth_type = 0x0806
arp_frame.arp_htype = 0x0001
arp_frame.arp_ptype = 0x0800
arp_frame.arp_hlen = 6
arp_frame.arp_plen = 4
arp_frame.arp_oper = 2
arp_frame.arp_sha = 0xDAD1D2D3D4D5
arp_frame.arp_spa = 0xc0a80181
arp_frame.arp_tha = 0x020000000000
arp_frame.arp_tpa = 0xc0a80180
gmii_source.send(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+arp_frame.build_eth().build_axis_fcs().data)
while gmii_sink.empty():
yield clk.posedge
rx_frame = gmii_sink.recv()
check_eth_frame = eth_ep.EthFrame()
check_eth_frame.parse_axis_fcs(rx_frame.data[8:])
check_frame = udp_ep.UDPFrame()
check_frame.parse_eth(check_eth_frame)
print(check_frame)
assert check_frame.eth_dest_mac == 0xDAD1D2D3D4D5
assert check_frame.eth_src_mac == 0x020000000000
assert check_frame.eth_type == 0x0800
assert check_frame.ip_version == 4
assert check_frame.ip_ihl == 5
assert check_frame.ip_dscp == 0
assert check_frame.ip_ecn == 0
assert check_frame.ip_identification == 0
assert check_frame.ip_flags == 2
assert check_frame.ip_fragment_offset == 0
assert check_frame.ip_ttl == 64
assert check_frame.ip_protocol == 0x11
assert check_frame.ip_source_ip == 0xc0a80180
assert check_frame.ip_dest_ip == 0xc0a80181
assert check_frame.udp_source_port == 1234
assert check_frame.udp_dest_port == 5678
assert check_frame.payload.data == bytearray(range(32))
assert gmii_source.empty()
assert gmii_sink.empty()
yield delay(100)
raise StopSimulation
return dut, gmii_source_logic, gmii_sink_logic, clkgen, clk_enable_gen, check
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,143 @@
/*
Copyright (c) 2015-2017 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for fpga_core
*/
module test_fpga_core;
// Parameters
// Inputs
reg clk_125mhz = 0;
reg rst_125mhz = 0;
reg [7:0] current_test = 0;
reg btnu = 0;
reg btnl = 0;
reg btnd = 0;
reg btnr = 0;
reg btnc = 0;
reg [7:0] sw = 0;
reg phy_gmii_clk = 0;
reg phy_gmii_rst = 0;
reg phy_gmii_clk_en = 0;
reg [7:0] phy_gmii_rxd = 0;
reg phy_gmii_rx_dv = 0;
reg phy_gmii_rx_er = 0;
reg uart_txd = 0;
reg uart_rts = 0;
// Outputs
wire ledu;
wire ledl;
wire ledd;
wire ledr;
wire ledc;
wire [7:0] led;
wire [7:0] phy_gmii_txd;
wire phy_gmii_tx_en;
wire phy_gmii_tx_er;
wire phy_reset_n;
wire uart_rxd;
wire uart_cts;
initial begin
// myhdl integration
$from_myhdl(
clk_125mhz,
rst_125mhz,
current_test,
btnu,
btnl,
btnd,
btnr,
btnc,
sw,
phy_gmii_clk,
phy_gmii_rst,
phy_gmii_clk_en,
phy_gmii_rxd,
phy_gmii_rx_dv,
phy_gmii_rx_er,
uart_txd,
uart_rts
);
$to_myhdl(
ledu,
ledl,
ledd,
ledr,
ledc,
led,
phy_gmii_txd,
phy_gmii_tx_en,
phy_gmii_tx_er,
phy_reset_n,
uart_rxd,
uart_cts
);
// dump file
$dumpfile("test_fpga_core.lxt");
$dumpvars(0, test_fpga_core);
end
fpga_core
UUT (
.clk_125mhz(clk_125mhz),
.rst_125mhz(rst_125mhz),
.btnu(btnu),
.btnl(btnl),
.btnd(btnd),
.btnr(btnr),
.btnc(btnc),
.sw(sw),
.ledu(ledu),
.ledl(ledl),
.ledd(ledd),
.ledr(ledr),
.ledc(ledc),
.led(led),
.phy_gmii_clk(phy_gmii_clk),
.phy_gmii_rst(phy_gmii_rst),
.phy_gmii_clk_en(phy_gmii_clk_en),
.phy_gmii_rxd(phy_gmii_rxd),
.phy_gmii_rx_dv(phy_gmii_rx_dv),
.phy_gmii_rx_er(phy_gmii_rx_er),
.phy_gmii_txd(phy_gmii_txd),
.phy_gmii_tx_en(phy_gmii_tx_en),
.phy_gmii_tx_er(phy_gmii_tx_er),
.phy_reset_n(phy_reset_n),
.uart_rxd(uart_rxd),
.uart_txd(uart_txd),
.uart_rts(uart_rts),
.uart_cts(uart_cts)
);
endmodule

View File

@ -0,0 +1 @@
../lib/eth/tb/udp_ep.py