diff --git a/example/ML605/fpga/Makefile b/example/ML605/fpga/Makefile new file mode 100644 index 000000000..f504bd06f --- /dev/null +++ b/example/ML605/fpga/Makefile @@ -0,0 +1,25 @@ +# Targets +TARGETS:= + +# Subdirectories +SUBDIRS = fpga +SUBDIRS_CLEAN = $(patsubst %,%.clean,$(SUBDIRS)) + +# Rules +.PHONY: all +all: $(SUBDIRS) $(TARGETS) + +.PHONY: $(SUBDIRS) +$(SUBDIRS): + cd $@ && $(MAKE) + +.PHONY: $(SUBDIRS_CLEAN) +$(SUBDIRS_CLEAN): + cd $(@:.clean=) && $(MAKE) clean + +.PHONY: clean +clean: $(SUBDIRS_CLEAN) + -rm -rf $(TARGETS) + +program: + #djtgcfg prog -d Atlys --index 0 --file fpga/fpga.bit diff --git a/example/ML605/fpga/README.md b/example/ML605/fpga/README.md new file mode 100644 index 000000000..887a41197 --- /dev/null +++ b/example/ML605/fpga/README.md @@ -0,0 +1,25 @@ +# Verilog Ethernet ML605 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. + +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. + + diff --git a/example/ML605/fpga/clock.ucf b/example/ML605/fpga/clock.ucf new file mode 100644 index 000000000..713379c40 --- /dev/null +++ b/example/ML605/fpga/clock.ucf @@ -0,0 +1,6 @@ +# UCF file for clock module domain crossing constraints + +NET "clk_125mhz_int" TNM = "ffs_clk_125mhz_int"; +NET "core_inst/gmii_rx_clk" TNM = "ffs_gmii_rx_clk"; +TIMESPEC "TS_clk_125mhz_int_to_gmii_rx_clk" = FROM "ffs_clk_125mhz_int" TO "ffs_gmii_rx_clk" 10 ns; +TIMESPEC "TS_gmii_rx_clk_to_clk_125mhz_int" = FROM "ffs_gmii_rx_clk" TO "ffs_clk_125mhz_int" 10 ns; diff --git a/example/ML605/fpga/common/xilinx.mk b/example/ML605/fpga/common/xilinx.mk new file mode 100644 index 000000000..f10a45f8e --- /dev/null +++ b/example/ML605/fpga/common/xilinx.mk @@ -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 + diff --git a/example/ML605/fpga/fpga.ucf b/example/ML605/fpga/fpga.ucf new file mode 100644 index 000000000..6ce175d2f --- /dev/null +++ b/example/ML605/fpga/fpga.ucf @@ -0,0 +1,85 @@ +# 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_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) + +# Timing constraints for Ethernet PHY +TIMESPEC "TS_rx_clk_root" = PERIOD "clk_rx_local" 8000 ps 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) diff --git a/example/ML605/fpga/fpga/Makefile b/example/ML605/fpga/fpga/Makefile new file mode 100644 index 000000000..eaa29656c --- /dev/null +++ b/example/ML605/fpga/fpga/Makefile @@ -0,0 +1,72 @@ + +# 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/iddr.v +SYN_FILES += lib/eth/rtl/oddr.v +SYN_FILES += lib/eth/rtl/ssio_sdr_in.v +SYN_FILES += lib/eth/rtl/ssio_sdr_out.v +SYN_FILES += lib/eth/rtl/gmii_phy_if.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/eth_mac_1g_rx.v +SYN_FILES += lib/eth/rtl/eth_mac_1g_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/dcm_i100_o125/dcm_i100_o125.v + +# UCF files +UCF_FILES = fpga.ucf +UCF_FILES += clock.ucf + +# NGC paths for ngdbuild +#NGC_PATHS = coregen/dcm_i100_o125 + +# 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 + diff --git a/example/ML605/fpga/lib/eth b/example/ML605/fpga/lib/eth new file mode 120000 index 000000000..11a54ed36 --- /dev/null +++ b/example/ML605/fpga/lib/eth @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/example/ML605/fpga/rtl/debounce_switch.v b/example/ML605/fpga/rtl/debounce_switch.v new file mode 100644 index 000000000..ab84126ec --- /dev/null +++ b/example/ML605/fpga/rtl/debounce_switch.v @@ -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 diff --git a/example/ML605/fpga/rtl/fpga.v b/example/ML605/fpga/rtl/fpga.v new file mode 100644 index 000000000..083be485a --- /dev/null +++ b/example/ML605/fpga/rtl/fpga.v @@ -0,0 +1,278 @@ +/* + +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 GMII + */ + input wire phy_rx_clk, + input wire [7:0] phy_rxd, + input wire phy_rx_dv, + input wire phy_rx_er, + output wire phy_gtx_clk, + output wire [7:0] phy_txd, + output wire phy_tx_en, + output wire phy_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 +); + +// 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; + +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 GMII + */ + .phy_rx_clk(phy_rx_clk), + .phy_rxd(phy_rxd), + .phy_rx_dv(phy_rx_dv), + .phy_rx_er(phy_rx_er), + .phy_gtx_clk(phy_gtx_clk), + .phy_txd(phy_txd), + .phy_tx_en(phy_tx_en), + .phy_tx_er(phy_tx_er), + .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 diff --git a/example/ML605/fpga/rtl/fpga_core.v b/example/ML605/fpga/rtl/fpga_core.v new file mode 100644 index 000000000..c2fda6a19 --- /dev/null +++ b/example/ML605/fpga/rtl/fpga_core.v @@ -0,0 +1,608 @@ +/* + +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 # +( + parameter TARGET = "XILINX" +) +( + /* + * 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 GMII + */ + input wire phy_rx_clk, + input wire [7:0] phy_rxd, + input wire phy_rx_dv, + input wire phy_rx_er, + output wire phy_gtx_clk, + output wire [7:0] phy_txd, + output wire phy_tx_en, + output wire phy_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 +); + +// GMII between MAC and PHY IF +wire gmii_rx_clk; +wire gmii_rx_rst; +wire [7:0] gmii_rxd; +wire gmii_rx_dv; +wire gmii_rx_er; + +wire gmii_tx_clk; +wire gmii_tx_rst; +wire [7:0] gmii_txd; +wire gmii_tx_en; +wire gmii_tx_er; + +// 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 + valid_last <= tx_udp_payload_tvalid; + if (tx_udp_payload_tvalid & ~valid_last) begin + led_reg <= tx_udp_payload_tdata; + 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; + +gmii_phy_if #( + .TARGET(TARGET), + .IODDR_STYLE("IODDR"), + .CLOCK_INPUT_STYLE("BUFR") +) +gmii_phy_if_inst ( + .clk(clk_125mhz), + .rst(rst_125mhz), + + .mac_gmii_rx_clk(gmii_rx_clk), + .mac_gmii_rx_rst(gmii_rx_rst), + .mac_gmii_rxd(gmii_rxd), + .mac_gmii_rx_dv(gmii_rx_dv), + .mac_gmii_rx_er(gmii_rx_er), + .mac_gmii_tx_clk(gmii_tx_clk), + .mac_gmii_tx_rst(gmii_tx_rst), + .mac_gmii_txd(gmii_txd), + .mac_gmii_tx_en(gmii_tx_en), + .mac_gmii_tx_er(gmii_tx_er), + + .phy_gmii_rx_clk(phy_rx_clk), + .phy_gmii_rxd(phy_rxd), + .phy_gmii_rx_dv(phy_rx_dv), + .phy_gmii_rx_er(phy_rx_er), + .phy_gmii_tx_clk(phy_gtx_clk), + .phy_gmii_txd(phy_txd), + .phy_gmii_tx_en(phy_tx_en), + .phy_gmii_tx_er(phy_tx_er) +); + +eth_mac_1g_fifo #( + .ENABLE_PADDING(1), + .MIN_FRAME_LENGTH(64), + .TX_FIFO_ADDR_WIDTH(12), + .RX_FIFO_ADDR_WIDTH(12) +) +eth_mac_1g_fifo_inst ( + .rx_clk(gmii_rx_clk), + .rx_rst(gmii_rx_rst), + .tx_clk(gmii_tx_clk), + .tx_rst(gmii_tx_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(gmii_rxd), + .gmii_rx_dv(gmii_rx_dv), + .gmii_rx_er(gmii_rx_er), + .gmii_txd(gmii_txd), + .gmii_tx_en(gmii_tx_en), + .gmii_tx_er(gmii_tx_er), + + .rx_error_bad_frame(rx_error_bad_frame), + .rx_error_bad_fcs(rx_error_bad_fcs), + + .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 diff --git a/example/ML605/fpga/rtl/sync_reset.v b/example/ML605/fpga/rtl/sync_reset.v new file mode 100644 index 000000000..558a67605 --- /dev/null +++ b/example/ML605/fpga/rtl/sync_reset.v @@ -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 diff --git a/example/ML605/fpga/rtl/sync_signal.v b/example/ML605/fpga/rtl/sync_signal.v new file mode 100644 index 000000000..1b8a32328 --- /dev/null +++ b/example/ML605/fpga/rtl/sync_signal.v @@ -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 diff --git a/example/ML605/fpga/tb/arp_ep.py b/example/ML605/fpga/tb/arp_ep.py new file mode 120000 index 000000000..7b3d3ed97 --- /dev/null +++ b/example/ML605/fpga/tb/arp_ep.py @@ -0,0 +1 @@ +../lib/eth/tb/arp_ep.py \ No newline at end of file diff --git a/example/ML605/fpga/tb/axis_ep.py b/example/ML605/fpga/tb/axis_ep.py new file mode 120000 index 000000000..385bb0300 --- /dev/null +++ b/example/ML605/fpga/tb/axis_ep.py @@ -0,0 +1 @@ +../lib/eth/tb/axis_ep.py \ No newline at end of file diff --git a/example/ML605/fpga/tb/eth_ep.py b/example/ML605/fpga/tb/eth_ep.py new file mode 120000 index 000000000..bac19feea --- /dev/null +++ b/example/ML605/fpga/tb/eth_ep.py @@ -0,0 +1 @@ +../lib/eth/tb/eth_ep.py \ No newline at end of file diff --git a/example/ML605/fpga/tb/gmii_ep.py b/example/ML605/fpga/tb/gmii_ep.py new file mode 120000 index 000000000..754166f2f --- /dev/null +++ b/example/ML605/fpga/tb/gmii_ep.py @@ -0,0 +1 @@ +../lib/eth/tb/gmii_ep.py \ No newline at end of file diff --git a/example/ML605/fpga/tb/ip_ep.py b/example/ML605/fpga/tb/ip_ep.py new file mode 120000 index 000000000..6dfa928a7 --- /dev/null +++ b/example/ML605/fpga/tb/ip_ep.py @@ -0,0 +1 @@ +../lib/eth/tb/ip_ep.py \ No newline at end of file diff --git a/example/ML605/fpga/tb/test_fpga_core.py b/example/ML605/fpga/tb/test_fpga_core.py new file mode 100755 index 000000000..a4d621023 --- /dev/null +++ b/example/ML605/fpga/tb/test_fpga_core.py @@ -0,0 +1,316 @@ +#!/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/iddr.v") +srcs.append("../lib/eth/rtl/oddr.v") +srcs.append("../lib/eth/rtl/ssio_sdr_in.v") +srcs.append("../lib/eth/rtl/ssio_sdr_out.v") +srcs.append("../lib/eth/rtl/gmii_phy_if.v") +srcs.append("../lib/eth/rtl/eth_mac_1g_fifo.v") +srcs.append("../lib/eth/rtl/eth_mac_1g.v") +srcs.append("../lib/eth/rtl/eth_mac_1g_rx.v") +srcs.append("../lib/eth/rtl/eth_mac_1g_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 + TARGET = "SIM" + + # 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_rx_clk = Signal(bool(0)) + phy_rxd = Signal(intbv(0)[8:]) + phy_rx_dv = Signal(bool(0)) + phy_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_gtx_clk = Signal(bool(0)) + phy_txd = Signal(intbv(0)[8:]) + phy_tx_en = Signal(bool(0)) + phy_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_rx_clk, + rst, + txd=phy_rxd, + tx_en=phy_rx_dv, + tx_er=phy_rx_er, + name='gmii_source' + ) + + gmii_sink = gmii_ep.GMIISink() + + gmii_sink_logic = gmii_sink.create_logic( + phy_gtx_clk, + rst, + rxd=phy_txd, + rx_dv=phy_tx_en, + rx_er=phy_tx_er, + 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_rx_clk=phy_rx_clk, + phy_rxd=phy_rxd, + phy_rx_dv=phy_rx_dv, + phy_rx_er=phy_rx_er, + phy_gtx_clk=phy_gtx_clk, + phy_txd=phy_txd, + phy_tx_en=phy_tx_en, + phy_tx_er=phy_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_rx_clk.next = not phy_rx_clk + + @instance + def check(): + yield delay(100) + yield clk.posedge + rst.next = 1 + rst_125mhz.next = 1 + yield clk.posedge + rst.next = 0 + rst_125mhz.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, check + +def test_bench(): + sim = Simulation(bench()) + sim.run() + +if __name__ == '__main__': + print("Running test...") + test_bench() diff --git a/example/ML605/fpga/tb/test_fpga_core.v b/example/ML605/fpga/tb/test_fpga_core.v new file mode 100644 index 000000000..10a0e8341 --- /dev/null +++ b/example/ML605/fpga/tb/test_fpga_core.v @@ -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 +parameter TARGET = "SIM"; + +// 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_rx_clk = 0; +reg [7:0] phy_rxd = 0; +reg phy_rx_dv = 0; +reg phy_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 phy_gtx_clk; +wire [7:0] phy_txd; +wire phy_tx_en; +wire phy_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_rx_clk, + phy_rxd, + phy_rx_dv, + phy_rx_er, + uart_txd, + uart_rts + ); + $to_myhdl( + ledu, + ledl, + ledd, + ledr, + ledc, + led, + phy_gtx_clk, + phy_txd, + phy_tx_en, + phy_tx_er, + phy_reset_n, + uart_rxd, + uart_cts + ); + + // dump file + $dumpfile("test_fpga_core.lxt"); + $dumpvars(0, test_fpga_core); +end + +fpga_core #( + .TARGET(TARGET) +) +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_rx_clk(phy_rx_clk), + .phy_rxd(phy_rxd), + .phy_rx_dv(phy_rx_dv), + .phy_rx_er(phy_rx_er), + .phy_gtx_clk(phy_gtx_clk), + .phy_txd(phy_txd), + .phy_tx_en(phy_tx_en), + .phy_tx_er(phy_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 diff --git a/example/ML605/fpga/tb/udp_ep.py b/example/ML605/fpga/tb/udp_ep.py new file mode 120000 index 000000000..073c5d3c6 --- /dev/null +++ b/example/ML605/fpga/tb/udp_ep.py @@ -0,0 +1 @@ +../lib/eth/tb/udp_ep.py \ No newline at end of file