diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..328167a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/work/ +*.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1de204d --- /dev/null +++ b/Makefile @@ -0,0 +1,125 @@ +.SECONDARY: + +SYNTH_TOOLCHAIN ?= symbiflow + +WORKDIR = $(PWD)/work +GHDL_WORKDIR = $(WORKDIR)/ghdl +SYMBIYOSYS_WORKDIR = $(WORKDIR)/symbiyosys +LITEX_WORKDIR = $(WORKDIR)/litex +SYNTH_WORKDIR = $(WORKDIR)/synth/$(SYNTH_TOOLCHAIN) + +SIM_DIR = sim +VHDL_DIR = vhdl + +WORKLIB_NAME = splink + +VHDL_FILES = $(wildcard $(VHDL_DIR)/*.vhdl) +VERILOG_FILES = $(LITEX_WORKDIR)/gateware/liteeth_core.v +SBY_FILES = + +SIM_ENTITY = splink_tb +SYNTH_ENTITY = arty_a7 +YOSYS_MODULE_NAME = arty_a7 + +GHDL = ghdl +VHDL_STD = 08 +GHDL_FLAGS = --std=$(VHDL_STD) --work=$(WORKLIB_NAME) --workdir=$(GHDL_WORKDIR) -g +SIM_RUN_FLAGS = --max-stack-alloc=0 --assert-level=warning --ieee-asserts=disable-at-0 + +GTKWAVE = gtkwave + +# synthesis + +XDC = $(PWD)/arty_a7_35.xdc + +PART = xc7a35tcsg324-1 + +YOSYS = yosys + +XRAY_DATABASE = /usr/share/xray/database/artix7 + +NEXTPNR = nextpnr-xilinx +BBASM = bbasm +FASM2FRAMES = fasm2frames +FRAMES2BIT = xc7frames2bit +OPENFPGALOADER = openFPGALoader + +GHDL_YOSYS_PLUGIN = ghdl + +SBY = sby -fd '$(SYMBIYOSYS_WORKDIR)' --yosys='$(YOSYS) -m $(GHDL_YOSYS_PLUGIN)' + +# ==================== +# END OF CONFIGURATION +# ==================== + +SIM_WAVE = $(SIM_DIR)/$(SIM_ENTITY).ghw +# for only capturing select signals +SIM_WAVEOPTS = $(SIM_DIR)/$(SIM_ENTITY).waveopt +SIM_WAVE_SAVE = $(SIM_DIR)/$(SIM_ENTITY).gtkw + +ifneq (,$(wildcard $(SIM_WAVEOPTS))) +SIM_RUN_FLAGS += --read-wave-opt=$(SIM_WAVEOPTS) +endif + +ifeq ($(SYNTH_TOOLCHAIN),symbiflow) +include Makefile.symbiflow +else ifeq ($(SYNTH_TOOLCHAIN),nextpnr) +include Makefile.nextpnr +else +$(error Bad PNR toolchain: expected one of symbiflow, nextpnr) +endif + +# ======= +# PHONIES +# ======= + +.PHONY: all simonly wave + +# default target +all: bitstream + +$(GHDL_WORKDIR)/work-obj$(VHDL_STD).cf: | $(GHDL_WORKDIR) + $(GHDL) import $(GHDL_FLAGS) $(VHDL_FILES) + +$(LITEX_WORKDIR)/gateware/liteeth_core.v: gen_liteeth.py + ./gen_liteeth.py --output-dir $(LITEX_WORKDIR) + +simonly: $(VHDL_FILES) | $(GHDL_WORKDIR)/work-obj$(VHDL_STD).cf + $(GHDL) make $(GHDL_FLAGS) $(SIM_ENTITY) + $(GHDL) run $(GHDL_FLAGS) $(SIM_ENTITY) $(SIM_RUN_FLAGS) + +wave: $(VHDL_FILES) + $(GHDL) make $(GHDL_FLAGS) $(SIM_ENTITY) + $(GHDL) run $(GHDL_FLAGS) $(SIM_ENTITY) $(SIM_RUN_FLAGS) --wave=$(SIM_WAVE) + $(GTKWAVE) $(SIM_WAVE) $(SIM_WAVE_SAVE) + +.PHONY: check check-formal +check: check-formal + +check-formal: + $(foreach f,$(SBY_FILES),$(SBY) $(f)) + +.PHONY: synth show bitstream flash +synth: $(SYNTH_OUTPUT_FILE) + +show: $(SYNTH_OUTPUT_FILE) + $(YOSYS) -p show $< + +bitstream: $(SYNTH_WORKDIR)/$(YOSYS_MODULE_NAME).bit + +flash: $(SYNTH_WORKDIR)/$(YOSYS_MODULE_NAME).bit + $(OPENFPGALOADER) -b arty $< + +.PHONY: clean +clean: + rm -rf $(WORKDIR) + +$(GHDL_WORKDIR) $(SYNTH_WORKDIR): + mkdir -p $@ + +.PHONY: echo-ghdl-flags echo-sim-run-flags +echo-ghdl-flags: + @echo $(GHDL_FLAGS) + +echo-sim-run-flags: + @echo $(SIM_RUN_FLAGS) diff --git a/Makefile.symbiflow b/Makefile.symbiflow new file mode 100644 index 0000000..a8d23d3 --- /dev/null +++ b/Makefile.symbiflow @@ -0,0 +1,23 @@ +SYNTH_OUTPUT_FILE = $(SYNTH_WORKDIR)/$(YOSYS_MODULE_NAME).eblif + +$(SYNTH_WORKDIR)/%.il: $(VHDL_FILES) $(VERILOG_FILES) | $(SYNTH_WORKDIR) $(GHDL_WORKDIR)/work-obj$(VHDL_STD).cf + $(GHDL) make $(GHDL_FLAGS) $(SYNTH_ENTITY) + $(YOSYS) -m $(GHDL_YOSYS_PLUGIN) -p 'read_verilog -defer $(VERILOG_FILES); ghdl $(GHDL_FLAGS) $(SYNTH_ENTITY); chformal -remove; check -assert; write_rtlil $@' + +$(SYNTH_WORKDIR)/%.eblif: $(SYNTH_WORKDIR)/%.il $(XDC) + cd $(SYNTH_WORKDIR) && symbiflow_synth -d artix7 -t $* -v $< -p $(PART) -x $(XDC) + +$(SYNTH_WORKDIR)/%.net: $(SYNTH_WORKDIR)/%.eblif + cd $(SYNTH_WORKDIR) && symbiflow_pack -d xc7a50t_test -e $< + +$(SYNTH_WORKDIR)/%.place: $(SYNTH_WORKDIR)/%.eblif $(SYNTH_WORKDIR)/%.net + cd $(SYNTH_WORKDIR) && symbiflow_place -d xc7a50t_test -e $< -n $(word 2,$^) -P $(PART) + +$(SYNTH_WORKDIR)/%.route: $(SYNTH_WORKDIR)/%.eblif $(SYNTH_WORKDIR)/%.place + cd $(SYNTH_WORKDIR) && symbiflow_route -d xc7a50t_test -e $< + +$(SYNTH_WORKDIR)/%.fasm: $(SYNTH_WORKDIR)/%.eblif $(SYNTH_WORKDIR)/%.route + cd $(SYNTH_WORKDIR) && symbiflow_write_fasm -d xc7a50t_test -e $< + +$(SYNTH_WORKDIR)/%.bit: $(SYNTH_WORKDIR)/%.fasm + cd $(SYNTH_WORKDIR) && symbiflow_write_bitstream -d artix7 -f $< -p $(PART) -b $@ diff --git a/arty_a7_35.xdc b/arty_a7_35.xdc new file mode 100644 index 0000000..d4106fb --- /dev/null +++ b/arty_a7_35.xdc @@ -0,0 +1,225 @@ +set_property LOC E3 [get_ports clock_100mhz] +set_property LOC A9 [get_ports uart_rx] +set_property LOC D10 [get_ports uart_tx] +set_property LOC C2 [get_ports n_reset] +set_property LOC G6 [get_ports {led0[2]}] +set_property LOC F6 [get_ports {led0[1]}] +set_property LOC E1 [get_ports {led0[0]}] +set_property LOC G3 [get_ports {led1[2]}] +set_property LOC J4 [get_ports {led1[1]}] +set_property LOC G4 [get_ports {led1[0]}] +set_property LOC J3 [get_ports {led2[2]}] +set_property LOC J2 [get_ports {led2[1]}] +set_property LOC H4 [get_ports {led2[0]}] +set_property LOC K1 [get_ports {led3[2]}] +set_property LOC H6 [get_ports {led3[1]}] +set_property LOC K2 [get_ports {led3[0]}] +set_property LOC A8 [get_ports {switches[0]}] +set_property LOC C11 [get_ports {switches[1]}] +set_property LOC C10 [get_ports {switches[2]}] +set_property LOC A10 [get_ports {switches[3]}] +set_property LOC D9 [get_ports {buttons[0]}] +set_property LOC C9 [get_ports {buttons[1]}] +set_property LOC B9 [get_ports {buttons[2]}] +set_property LOC B8 [get_ports {buttons[3]}] +set_property LOC H5 [get_ports {leds_simple[0]}] +set_property LOC J5 [get_ports {leds_simple[1]}] +set_property LOC T9 [get_ports {leds_simple[2]}] +set_property LOC T10 [get_ports {leds_simple[3]}] + +set_property LOC K13 [get_ports mii_mdio] +set_property LOC F16 [get_ports mii_mdc] +set_property LOC F15 [get_ports mii_rx_clk] +set_property LOC C17 [get_ports mii_rx_er] +set_property LOC G16 [get_ports mii_rx_dv] +set_property LOC D18 [get_ports {mii_rx_data[0]}] +set_property LOC E17 [get_ports {mii_rx_data[1]}] +set_property LOC E18 [get_ports {mii_rx_data[2]}] +set_property LOC G17 [get_ports {mii_rx_data[3]}] +set_property LOC H16 [get_ports mii_tx_clk] +set_property LOC H15 [get_ports mii_tx_en] +set_property LOC H14 [get_ports {mii_tx_data[0]}] +set_property LOC J14 [get_ports {mii_tx_data[1]}] +set_property LOC J13 [get_ports {mii_tx_data[2]}] +set_property LOC H17 [get_ports {mii_tx_data[3]}] +set_property LOC D17 [get_ports mii_col] +set_property LOC G14 [get_ports mii_crs] +set_property LOC C16 [get_ports mii_n_reset] +set_property LOC G18 [get_ports mii_clk_25mhz] + +set_property LOC G13 [get_ports {pmod_a[0]}] +set_property LOC B11 [get_ports {pmod_a[1]}] +set_property LOC A11 [get_ports {pmod_a[2]}] +set_property LOC D12 [get_ports {pmod_a[3]}] +set_property LOC D13 [get_ports {pmod_a[4]}] +set_property LOC B18 [get_ports {pmod_a[5]}] +set_property LOC A18 [get_ports {pmod_a[6]}] +set_property LOC K16 [get_ports {pmod_a[7]}] +set_property LOC E15 [get_ports {pmod_b[0]}] +set_property LOC E16 [get_ports {pmod_b[1]}] +set_property LOC D15 [get_ports {pmod_b[2]}] +set_property LOC C15 [get_ports {pmod_b[3]}] +set_property LOC J17 [get_ports {pmod_b[4]}] +set_property LOC J18 [get_ports {pmod_b[5]}] +set_property LOC K15 [get_ports {pmod_b[6]}] +set_property LOC J15 [get_ports {pmod_b[7]}] +set_property LOC U12 [get_ports {pmod_c[0]}] +set_property LOC V12 [get_ports {pmod_c[1]}] +set_property LOC V10 [get_ports {pmod_c[2]}] +set_property LOC V11 [get_ports {pmod_c[3]}] +set_property LOC U14 [get_ports {pmod_c[4]}] +set_property LOC V14 [get_ports {pmod_c[5]}] +set_property LOC T13 [get_ports {pmod_c[6]}] +set_property LOC U13 [get_ports {pmod_c[7]}] +set_property LOC D4 [get_ports {pmod_d[0]}] +set_property LOC D3 [get_ports {pmod_d[1]}] +set_property LOC F4 [get_ports {pmod_d[2]}] +set_property LOC F3 [get_ports {pmod_d[3]}] +set_property LOC E2 [get_ports {pmod_d[4]}] +set_property LOC D2 [get_ports {pmod_d[5]}] +set_property LOC H2 [get_ports {pmod_d[6]}] +set_property LOC G2 [get_ports {pmod_d[7]}] + +set_property LOC V15 [get_ports {ck_dig_l[0]}] +set_property LOC U16 [get_ports {ck_dig_l[1]}] +set_property LOC P14 [get_ports {ck_dig_l[2]}] +set_property LOC T11 [get_ports {ck_dig_l[3]}] +set_property LOC R12 [get_ports {ck_dig_l[4]}] +set_property LOC T14 [get_ports {ck_dig_l[5]}] +set_property LOC T15 [get_ports {ck_dig_l[6]}] +set_property LOC T16 [get_ports {ck_dig_l[7]}] +set_property LOC N15 [get_ports {ck_dig_l[8]}] +set_property LOC M16 [get_ports {ck_dig_l[9]}] +set_property LOC V17 [get_ports {ck_dig_l[10]}] +set_property LOC U18 [get_ports {ck_dig_l[11]}] +set_property LOC R17 [get_ports {ck_dig_l[12]}] +set_property LOC P17 [get_ports {ck_dig_l[13]}] + +set_property LOC U11 [get_ports {ck_dig_h[0]}] +set_property LOC V16 [get_ports {ck_dig_h[1]}] +set_property LOC M13 [get_ports {ck_dig_h[2]}] +set_property LOC R10 [get_ports {ck_dig_h[3]}] +set_property LOC R11 [get_ports {ck_dig_h[4]}] +set_property LOC R13 [get_ports {ck_dig_h[5]}] +set_property LOC R15 [get_ports {ck_dig_h[6]}] +set_property LOC P15 [get_ports {ck_dig_h[7]}] +set_property LOC R16 [get_ports {ck_dig_h[8]}] +set_property LOC N16 [get_ports {ck_dig_h[9]}] +set_property LOC N14 [get_ports {ck_dig_h[10]}] +set_property LOC U17 [get_ports {ck_dig_h[11]}] +set_property LOC T18 [get_ports {ck_dig_h[12]}] +set_property LOC R18 [get_ports {ck_dig_h[13]}] +set_property LOC P18 [get_ports {ck_dig_h[14]}] +set_property LOC N17 [get_ports {ck_dig_h[15]}] + +set_property IOSTANDARD LVCMOS33 [get_ports clock_100mhz] +set_property IOSTANDARD LVCMOS33 [get_ports uart_rx] +set_property IOSTANDARD LVCMOS33 [get_ports uart_tx] +set_property IOSTANDARD LVCMOS33 [get_ports n_reset] +set_property IOSTANDARD LVCMOS33 [get_ports {led0[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {led0[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {led0[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {led1[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {led1[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {led1[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {led2[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {led2[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {led2[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {led3[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {led3[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {led3[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {switches[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {switches[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {switches[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {switches[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports {buttons[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {buttons[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {buttons[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {buttons[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports {leds_simple[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {leds_simple[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {leds_simple[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {leds_simple[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports mii_mdio] +set_property IOSTANDARD LVCMOS33 [get_ports mii_mdc] +set_property IOSTANDARD LVCMOS33 [get_ports mii_rx_clk] +set_property IOSTANDARD LVCMOS33 [get_ports mii_rx_er] +set_property IOSTANDARD LVCMOS33 [get_ports mii_rx_dv] +set_property IOSTANDARD LVCMOS33 [get_ports {mii_rx_data[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {mii_rx_data[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {mii_rx_data[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {mii_rx_data[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports mii_tx_clk] +set_property IOSTANDARD LVCMOS33 [get_ports mii_tx_en] +set_property IOSTANDARD LVCMOS33 [get_ports {mii_tx_data[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {mii_tx_data[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {mii_tx_data[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {mii_tx_data[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports mii_col] +set_property IOSTANDARD LVCMOS33 [get_ports mii_crs] +set_property IOSTANDARD LVCMOS33 [get_ports mii_n_reset] +set_property IOSTANDARD LVCMOS33 [get_ports mii_clk_25mhz] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_a[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_a[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_a[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_a[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_a[4]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_a[5]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_a[6]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_a[7]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_b[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_b[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_b[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_b[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_b[4]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_b[5]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_b[6]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_b[7]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_c[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_c[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_c[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_c[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_c[4]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_c[5]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_c[6]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_c[7]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_d[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_d[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_d[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_d[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_d[4]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_d[5]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_d[6]}] +set_property IOSTANDARD LVCMOS33 [get_ports {pmod_d[7]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_l[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_l[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_l[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_l[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_l[4]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_l[5]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_l[6]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_l[7]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_l[8]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_l[9]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_l[10]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_l[11]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_l[12]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_l[13]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[4]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[5]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[6]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[7]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[8]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[9]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[10]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[11]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[12]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[13]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[14]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ck_dig_h[15]}] + +create_clock -name clk_100mhz -period 10.000 [get_nets clock_100mhz] diff --git a/gen_liteeth.py b/gen_liteeth.py new file mode 100755 index 0000000..f43ee95 --- /dev/null +++ b/gen_liteeth.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteEth. +# +# Copyright (c) 2015-2022 Florent Kermarrec +# Copyright (c) 2020 Xiretza +# Copyright (c) 2020 Stefan Schrijvers +# SPDX-License-Identifier: BSD-2-Clause + +import argparse +import os +import yaml + +from migen import * + +from litex.build.generic_platform import * +from litex.build.xilinx.platform import XilinxPlatform +from litex.build.lattice.platform import LatticePlatform + +from litex.soc.interconnect import wishbone +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * +from litex.soc.integration.soc import SoCRegion + +from liteeth.common import * + +from liteeth import phy as liteeth_phys +from liteeth.mac import LiteEthMAC +from liteeth.core import LiteEthUDPIPCore + +# IOs ---------------------------------------------------------------------------------------------- + +MAC_ADDRESS = 0x00183e02a914 +CLK_FREQ = int(125e6) + +_io = [ + # Clk / Rst + ("sys_clock", 0, Pins(1)), + ("sys_reset", 1, Pins(1)), + + # IP/MAC Address. + ("mac_address", 0, Pins(48)), + ("ip_address", 0, Pins(32)), + + # Interrupt + ("interrupt", 0, Pins(1)), + + # MII PHY Pads + ("mii_eth_clocks", 0, + Subsignal("tx", Pins(1)), + Subsignal("rx", Pins(1)), + ), + ("mii_eth", 0, + Subsignal("rst_n", Pins(1)), + Subsignal("mdio", Pins(1)), + Subsignal("mdc", Pins(1)), + Subsignal("rx_dv", Pins(1)), + Subsignal("rx_er", Pins(1)), + Subsignal("rx_data", Pins(4)), + Subsignal("tx_en", Pins(1)), + Subsignal("tx_data", Pins(4)), + Subsignal("col", Pins(1)), + Subsignal("crs", Pins(1)) + ), + + # RMII PHY Pads + ("rmii_eth_clocks", 0, + Subsignal("ref_clk", Pins(1)) + ), + ("rmii_eth", 0, + Subsignal("rst_n", Pins(1)), + Subsignal("rx_data", Pins(2)), + Subsignal("crs_dv", Pins(1)), + Subsignal("tx_en", Pins(1)), + Subsignal("tx_data", Pins(2)), + Subsignal("mdc", Pins(1)), + Subsignal("mdio", Pins(1)), + ), + + # GMII PHY Pads + ("gmii_eth_clocks", 0, + Subsignal("tx", Pins(1)), + Subsignal("gtx", Pins(1)), + Subsignal("rx", Pins(1)) + ), + ("gmii_eth", 0, + Subsignal("rst_n", Pins(1)), + Subsignal("int_n", Pins(1)), + Subsignal("mdio", Pins(1)), + Subsignal("mdc", Pins(1)), + Subsignal("rx_dv", Pins(1)), + Subsignal("rx_er", Pins(1)), + Subsignal("rx_data", Pins(8)), + Subsignal("tx_en", Pins(1)), + Subsignal("tx_er", Pins(1)), + Subsignal("tx_data", Pins(8)), + Subsignal("col", Pins(1)), + Subsignal("crs", Pins(1)) + ), + + # RGMII PHY Pads + ("rgmii_eth_clocks", 0, + Subsignal("tx", Pins(1)), + Subsignal("rx", Pins(1)) + ), + ("rgmii_eth", 0, + Subsignal("rst_n", Pins(1)), + Subsignal("int_n", Pins(1)), + Subsignal("mdio", Pins(1)), + Subsignal("mdc", Pins(1)), + Subsignal("rx_ctl", Pins(1)), + Subsignal("rx_data", Pins(4)), + Subsignal("tx_ctl", Pins(1)), + Subsignal("tx_data", Pins(4)) + ), +] + + +def get_udp_port_ios(name, data_width): + return [ + (f"{name}", 0, + Subsignal("ip_address", Pins(32)), + + # Sink. + Subsignal("sink_valid", Pins(1)), + Subsignal("sink_last", Pins(1)), + Subsignal("sink_ready", Pins(1)), + Subsignal("sink_data", Pins(data_width)), + + # Source. + Subsignal("source_valid", Pins(1)), + Subsignal("source_last", Pins(1)), + Subsignal("source_ready", Pins(1)), + Subsignal("source_data", Pins(data_width)), + ), + ] + + +class PHYCore(SoCMini): + def __init__(self, platform): + super().__init__(platform, clk_freq=CLK_FREQ) + + # CRG -------------------------------------------------------------------------------------- + self.submodules.crg = CRG( + platform.request("sys_clock"), + platform.request("sys_reset") + ) + + # PHY -------------------------------------------------------------------------------------- + phy = liteeth_phys.LiteEthPHYRMII + ethphy = phy( + refclk_cd=None, + clock_pads=platform.request("rmii_eth_clocks"), + pads=platform.request("rmii_eth") + ) + self.submodules.ethphy = ethphy + + # Timing constaints. + # Generate timing constraints to ensure the "keep" attribute is properly set on the various + # clocks. This also adds the constraints to the generated .xdc that can then be "imported" + # in the project using the core. + eth_rx_clk = getattr(ethphy, "crg", ethphy).cd_eth_rx.clk + eth_tx_clk = getattr(ethphy, "crg", ethphy).cd_eth_tx.clk + from liteeth.phy.model import LiteEthPHYModel + if not isinstance(ethphy, LiteEthPHYModel): + self.platform.add_period_constraint( + eth_rx_clk, + 1e9/phy.rx_clk_freq + ) + self.platform.add_period_constraint( + eth_tx_clk, + 1e9/phy.tx_clk_freq + ) + self.platform.add_false_path_constraints( + self.crg.cd_sys.clk, + eth_rx_clk, + eth_tx_clk + ) + + +class UDPCore(PHYCore): + def __init__(self, platform): + from liteeth.frontend.stream import LiteEthUDPStreamer + + super().__init__(platform) + + ip_address = platform.request("ip_address") + + # Core + self.submodules.core = LiteEthUDPIPCore( + self.ethphy, + mac_address=MAC_ADDRESS, + ip_address=ip_address, + clk_freq=CLK_FREQ, + dw=8, + with_sys_datapath=False, + ) + + # DHCP port + data_width = 32 + + platform.add_extension(get_udp_port_ios( + "dhcp", + data_width=data_width, + )) + dhcp_ios = platform.request("dhcp") + + dhcp_streamer = LiteEthUDPStreamer( + self.core.udp, + ip_address=dhcp_ios.ip_address, + udp_port=67, + data_width=data_width, + tx_fifo_depth=64, + rx_fifo_depth=64 + ) + self.submodules += dhcp_streamer + + self.comb += [ + # Connect UDP Sink IOs to UDP Steamer. + dhcp_streamer.sink.valid.eq(dhcp_ios.sink_valid), + dhcp_streamer.sink.last.eq(dhcp_ios.sink_last), + dhcp_ios.sink_ready.eq(dhcp_streamer.sink.ready), + dhcp_streamer.sink.data.eq(dhcp_ios.sink_data), + + # Connect UDP Streamer to UDP Source IOs. + dhcp_ios.source_valid.eq(dhcp_streamer.source.valid), + dhcp_ios.source_last.eq(dhcp_streamer.source.last), + dhcp_streamer.source.ready.eq(dhcp_ios.source_ready), + dhcp_ios.source_data.eq(dhcp_streamer.source.data), + ] + +# Build -------------------------------------------------------------------------------------------- + + +def main(): + parser = argparse.ArgumentParser( + description="splink LiteEth core generator" + ) + builder_args(parser) + parser.set_defaults(output_dir="build") + args = parser.parse_args() + + # Generate core -------------------------------------------------------------------------------- + platform = XilinxPlatform( + "xc7a35ticsg324-1L", + io=[], + toolchain="symbiflow" + ) + platform.add_extension(_io) + + soc = UDPCore(platform) + + builder_arguments = builder_argdict(args) + builder_arguments["compile_gateware"] = False + if builder_arguments["csr_csv"] is None: + builder_arguments["csr_csv"] = os.path.join( + builder_arguments["output_dir"], + "csr.csv" + ) + + builder = Builder(soc, **builder_arguments) + builder.build(build_name="liteeth_core") + + +if __name__ == "__main__": + main() diff --git a/vhdl/arty_a7.vhdl b/vhdl/arty_a7.vhdl new file mode 100644 index 0000000..93006d3 --- /dev/null +++ b/vhdl/arty_a7.vhdl @@ -0,0 +1,82 @@ +library ieee; +use ieee.std_logic_1164.all, + ieee.numeric_std.all; + +entity arty_a7 is + generic ( + IS_SIMULATION : std_logic := '0' + ); + port ( + n_reset : in std_logic; + buttons : in std_logic_vector(3 downto 0); + switches : in std_logic_vector(3 downto 0); + leds_simple : out std_logic_vector(3 downto 0); + led0, led1, led2, led3 : out std_logic_vector(2 downto 0); + + -- Pmod connectors - A+D standard, B+C high-speed. + -- Defined as inputs by default for safety, change + -- when necessary + pmod_a : in std_logic_vector(7 downto 0); + pmod_b : in std_logic_vector(7 downto 0); + pmod_c : in std_logic_vector(7 downto 0); + pmod_d : in std_logic_vector(7 downto 0); + + clock_100mhz : in std_logic; + + uart_rx : in std_logic; + uart_tx : out std_logic; + + mii_clk_25mhz : out std_logic; + mii_n_reset : out std_logic; + mii_mdio : inout std_logic; + mii_mdc : out std_logic; + mii_rx_clk : in std_logic; + mii_rx_er : in std_logic; + mii_rx_dv : in std_logic; + mii_rx_data : in std_logic_vector(3 downto 0); + mii_tx_clk : in std_logic; + mii_tx_en : out std_logic; + mii_tx_data : out std_logic_vector(3 downto 0); + mii_col : in std_logic; + mii_crs : in std_logic; + + ck_dig_l : inout std_logic_vector(13 downto 0); + ck_dig_h : inout std_logic_vector(41 downto 26) + ); +end arty_a7; + +architecture a of arty_a7 is + constant NUM_DRIVERS: positive := 16; + signal drivers: std_logic_vector(NUM_DRIVERS-1 downto 0); +begin + --leds_simple <= (others => '0'); + led0 <= (others => '0'); + led1 <= (others => '0'); + led2 <= (others => '0'); + led3 <= (others => '0'); + + uart_tx <= '0'; + + mii_clk_25mhz <= '0'; + mii_n_reset <= '0'; + mii_mdio <= 'Z'; + mii_mdc <= '0'; + mii_tx_en <= '0'; + mii_tx_data <= (others => '0'); + + ck_dig_l <= (others => 'Z'); + ck_dig_h <= (others => 'Z'); + + leds_simple <= drivers(3 downto 0); + + splink: entity work.splink + generic map ( + NUM_DRIVERS => NUM_DRIVERS + ) + port map ( + clk => clock_100mhz, + reset => not n_reset, + + drivers => drivers + ); +end architecture; diff --git a/vhdl/splink.vhdl b/vhdl/splink.vhdl new file mode 100644 index 0000000..32bf7da --- /dev/null +++ b/vhdl/splink.vhdl @@ -0,0 +1,36 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity splink is + generic ( + NUM_DRIVERS : positive := 16; + ROWS : positive := 100; + COLS : positive := 100 + ); + port ( + clk : in std_logic; + reset : in std_logic; + + drivers : out std_logic_vector(NUM_DRIVERS-1 downto 0) + ); +end entity; + +architecture a of splink is + signal count2: unsigned(3 downto 0); + signal count: natural range 0 to 10000000; +begin + process(clk) + begin + if rising_edge(clk) then + if count = 10000000 then + count <= 0; + count2 <= count2 + 1; + else + count <= count + 1; + end if; + end if; + end process; + + drivers <= (15 downto 4 => '0') & std_logic_vector(count2); +end architecture;