From e6779c8060475bb646dc928dd1349a6302fc8f55 Mon Sep 17 00:00:00 2001 From: Ties Stuij Date: Mon, 17 Oct 2022 20:23:08 +0100 Subject: [PATCH 1/3] add initial J1b support for ULX3S board This patch adds initial J1b support for the ULX3S board, which is based on the Lattice ECP5 FPGA and can be programmed with either the Trellis (Yosys) or Diamond (vendor) toolchain. Currently only the J1b core and UART are hooked up. So no LEDs, GPIO ports, buttons, SDRAM, etc.. support yet. You can connect to the core with the `shell.py` script, and you can replicate the bootstap process: compiling swapforth.fs, writing out a new nuc.hex file containing the new words and creating a new bitstream containing the new `.hex` file. Flashing that on the ULX3S seems to replicate a functioning Forth system. The `bram` and `ram16k` modules were split out from the `xilinx-top.v` file into `ram.v` to foster some code reuse. Thanks to improved handling of bram within Yosys, the modules could be reused as is. Note that the changes weren't tested on either the Diamond or Xilinx toolchains. The changes to Xilinx parts were minimal so hopefully no regression was introduced. As for Diamond, it made sense to me to include the Makefile-related parts needed to compile for Diamond to aid others wanting to make this work. --- j1b/ulx3s/Makefile | 28 ++ j1b/ulx3s/README.md | 18 ++ j1b/ulx3s/makefile.diamond | 31 ++ j1b/ulx3s/scripts/diamond_main.mk | 285 +++++++++++++++++ j1b/ulx3s/scripts/diamond_path.mk | 6 + j1b/ulx3s/scripts/trellis_main.mk | 231 ++++++++++++++ j1b/ulx3s/scripts/trellis_main_sv.mk | 207 ++++++++++++ j1b/ulx3s/scripts/trellis_path.mk | 12 + j1b/ulx3s/ulx3s_v20_segpdi.lpf | 457 +++++++++++++++++++++++++++ j1b/verilog/ram.v | 83 +++++ j1b/verilog/ulx3s_top.v | 141 +++++++++ j1b/verilog/xilinx-top.v | 83 ----- j1b/xilinx/Makefile | 9 +- 13 files changed, 1507 insertions(+), 84 deletions(-) create mode 100644 j1b/ulx3s/Makefile create mode 100644 j1b/ulx3s/README.md create mode 100644 j1b/ulx3s/makefile.diamond create mode 100644 j1b/ulx3s/scripts/diamond_main.mk create mode 100644 j1b/ulx3s/scripts/diamond_path.mk create mode 100644 j1b/ulx3s/scripts/trellis_main.mk create mode 100644 j1b/ulx3s/scripts/trellis_main_sv.mk create mode 100644 j1b/ulx3s/scripts/trellis_path.mk create mode 100644 j1b/ulx3s/ulx3s_v20_segpdi.lpf create mode 100644 j1b/verilog/ram.v create mode 100644 j1b/verilog/ulx3s_top.v diff --git a/j1b/ulx3s/Makefile b/j1b/ulx3s/Makefile new file mode 100644 index 0000000..31c11b6 --- /dev/null +++ b/j1b/ulx3s/Makefile @@ -0,0 +1,28 @@ +# ******* project, board and chip name ******* +PROJECT = swapforth +BOARD = ulx3s +# 12 25 45 85 +FPGA_SIZE = 85 + +# ******* design files ******* +CONSTRAINTS = ulx3s_v20_segpdi.lpf +TOP_MODULE = ulx3s_top +PREFIX = ../verilog +TOP_MODULE_FILE = $(PREFIX)/$(TOP_MODULE).v + +VERILOG_FILES = \ +$(TOP_MODULE_FILE) \ +$(PREFIX)/j1.v \ +$(PREFIX)/ram.v \ +$(PREFIX)/uart.v \ +$(PREFIX)/stack.v \ + +# *.vhd those files will be converted to *.v files with vhdl2vl (warning overwriting/deleting) +VHDL_FILES = \ + +YOSYS_OPTIONS = -abc9 +NEXTPNR_OPTIONS = --timing-allow-fail + +SCRIPTS = scripts +include $(SCRIPTS)/trellis_path.mk +include $(SCRIPTS)/trellis_main.mk diff --git a/j1b/ulx3s/README.md b/j1b/ulx3s/README.md new file mode 100644 index 0000000..262c787 --- /dev/null +++ b/j1b/ulx3s/README.md @@ -0,0 +1,18 @@ +The ULX3S board is based upon the Lattice ECP5 FPGA. It's a it's a prototype +board with lots of features in a small form factor. For more info, see +https://ulx3s.github.io. + +Currently the only tested toolchain is Trellis (or rather the tools associated +with Trellis). + +As with the other supported platforms, have the Trellis tools installed, and run +make in this directory to create a bitstream. Run fujprog to install it over +USB: + + fujprog ulx3s_85f_swapforth.bit + +Now you can use `shell.py` in the parent directory to attach to the Forth +process over UART. The Verilator bootstrap process will also work for ULX3S. + +Currently only J1b itself and UART are supported. Support for low-hanging fruit +like GPIOs, buttons and LEDs should follow shortly. diff --git a/j1b/ulx3s/makefile.diamond b/j1b/ulx3s/makefile.diamond new file mode 100644 index 0000000..2cb63d3 --- /dev/null +++ b/j1b/ulx3s/makefile.diamond @@ -0,0 +1,31 @@ +# ******* project, board and chip name ******* +PROJECT = swapforth_hex +BOARD = ulx3s +# 12 25 45 85 +FPGA_SIZE = 12 +FPGA_PACKAGE = 6bg381c +# config flash: 1:SPI (standard), 4:QSPI (quad) +FLASH_SPI = 4 +# chip: is25lp032d is25lp128f s25fl164k +FLASH_CHIP = is25lp128f + +# ******* design files ******* +CONSTRAINTS = ulx3s_v20_segpdi.lpf +TOP_MODULE = ulx3s_top +PREFIX = ../verilog +TOP_MODULE_FILE = $(PREFIX)/$(TOP_MODULE).v + +VERILOG_FILES = \ +$(TOP_MODULE_FILE) \ +$(PREFIX)/j1.v \ +$(PREFIX)/ram.v \ +$(PREFIX)/uart.v \ +$(PREFIX)/stack.v \ + +# *.vhd those files will be converted to *.v files with vhdl2vl (warning overwriting/deleting) +VHDL_FILES = \ + +SCRIPTS = ../../../../scripts/ +include $(SCRIPTS)/trellis_path.mk +include $(SCRIPTS)/diamond_path.mk +include $(SCRIPTS)/diamond_main.mk diff --git a/j1b/ulx3s/scripts/diamond_main.mk b/j1b/ulx3s/scripts/diamond_main.mk new file mode 100644 index 0000000..6b17b54 --- /dev/null +++ b/j1b/ulx3s/scripts/diamond_main.mk @@ -0,0 +1,285 @@ +# ******* project, board and chip name ******* +PROJECT ?= project +BOARD ?= board +FPGA_SIZE ?= 12 +FPGA_CHIP ?= lfe5u-$(FPGA_SIZE)f +FPGA_PACKAGE ?= 6bg381c +# config flash: 1:SPI (standard), 4:QSPI (quad) +FLASH_SPI ?= 1 +# chip: is25lp032d is25lp128f s25fl164k +FLASH_CHIP ?= is25lp032d + +# ******* design files ******* +CONSTRAINTS ?= board_constraints.lpf +STRATEGY ?= $(SCRIPTS)/ulx3s.sty +TOP_MODULE ?= top +TOP_MODULE_FILE ?= $(TOP_MODULE).v +VERILOG_FILES ?= $(TOP_MODULE_FILE) +VHDL_FILES ?= +SBX_FILES ?= + +# ******* tools installation paths ******* +# include $(SCRIPTS)/trellis_path.mk +# https://github.com/ldoolitt/vhd2vl +#VHDL2VL ?= /mt/scratch/tmp/openfpga/vhd2vl/src/vhd2vl +# https://github.com/YosysHQ/yosys +#YOSYS ?= /mt/scratch/tmp/openfpga/yosys/yosys +# https://github.com/YosysHQ/nextpnr +#NEXTPNR-ECP5 ?= /mt/scratch/tmp/openfpga/nextpnr/nextpnr-ecp5 +# https://github.com/SymbiFlow/prjtrellis +#TRELLIS ?= /mt/scratch/tmp/openfpga/prjtrellis + +ifeq ($(FPGA_CHIP), lfe5u-12f) + CHIP_ID=0x21111043 + MASK_FILE=LFE5U-45F.msk +endif +ifeq ($(FPGA_CHIP), lfe5u-25f) + CHIP_ID=0x41111043 + MASK_FILE=LFE5U-45F.msk +endif +ifeq ($(FPGA_CHIP), lfe5u-45f) + CHIP_ID=0x41112043 + MASK_FILE=LFE5U-45F.msk +endif +ifeq ($(FPGA_CHIP), lfe5u-85f) + CHIP_ID=0x41113043 + MASK_FILE=LFE5U-85F.msk +endif + +#ifeq ($(FPGA_SIZE), 12) +# FPGA_K=25 +# IDCODE_CHIPID=--idcode $(CHIP_ID) +#else + FPGA_K=$(FPGA_SIZE) + IDCODE_CHIPID= +#endif + +FPGA_CHIP_EQUIVALENT ?= lfe5u-$(FPGA_K)f + +# open source synthesis tools +ECPPLL ?= $(TRELLIS)/libtrellis/ecppll +ECPPACK ?= $(TRELLIS)/libtrellis/ecppack +TRELLISDB ?= $(TRELLIS)/database +LIBTRELLIS ?= $(TRELLIS)/libtrellis +BIT2SVF ?= $(TRELLIS)/tools/bit_to_svf.py +#BASECFG ?= $(TRELLIS)/misc/basecfgs/empty_$(FPGA_CHIP_EQUIVALENT).config +# yosys options, sometimes those can be used: -noccu2 -nomux -nodram +YOSYS_OPTIONS ?= + +# clock generator +CLK0_NAME ?= clk0 +CLK0_FILE_NAME ?= clocks/$(CLK0_NAME).v +CLK0_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0 +CLK1_NAME ?= clk1 +CLK1_FILE_NAME ?= clocks/$(CLK1_NAME).v +CLK1_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0 +CLK2_NAME ?= clk2 +CLK2_FILE_NAME ?= clocks/$(CLK2_NAME).v +CLK2_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0 +CLK3_NAME ?= clk3 +CLK3_FILE_NAME ?= clocks/$(CLK3_NAME).v +CLK3_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0 + +# closed source synthesis tools +# include $(SCRIPTS)/diamond_path.mk +#DIAMOND_BASE ?= /usr/local/diamond +ifneq ($(wildcard $(DIAMOND_BASE)),) + DIAMOND_BIN := $(shell find ${DIAMOND_BASE}/ -maxdepth 2 -name bin | sort -rn | head -1) + DIAMONDC := $(shell find ${DIAMOND_BIN}/ -name diamondc) + DDTCMD := $(shell find ${DIAMOND_BIN}/ -name ddtcmd) + MASK_PATH := $(shell find ${DIAMOND_BASE}/ -maxdepth 5 -name xpga -type d)/ecp5 +endif + +#PROJ_FILE := $(shell ls *.ldf | head -1) +#PROJ_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 4) +#IMPL_NAME := $(shell fgrep default_implementation ${PROJ_FILE} | cut -d'"' -f 8) +#IMPL_DIR := $(shell fgrep default_strategy ${PROJ_FILE} | cut -d'"' -f 4) + +# programming tools +UJPROG ?= fujprog +OPENFPGALOADER ?= openFPGALoader +OPENFPGALOADER_OPTIONS ?= --board ulx3s +FLEAFPGA_JTAG ?= FleaFPGA-JTAG +OPENOCD ?= openocd +OPENOCD_INTERFACE ?= $(SCRIPTS)/ft231x.ocd +DFU_UTIL ?= dfu-util +TINYFPGASP ?= tinyfpgasp + +# helper scripts directory +SCRIPTS ?= scripts + +# rest of the include makefile +FPGA_CHIP_UPPERCASE := $(shell echo $(FPGA_CHIP) | tr '[:lower:]' '[:upper:]') +FPGA_PACKAGE_UPPERCASE := $(shell echo $(FPGA_PACKAGE) | tr '[:lower:]' '[:upper:]') + +BITSTREAM ?= $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit +#BITSTREAM ?= $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf $(BOARD)_$(FPGA_SIZE)f_$(PROJECT)_flash_$(FLASH_CHIP).vme + +all: $(BITSTREAM) + +# VHDL to VERILOG conversion +#%.v: %.vhd +# $(VHDL2VL) $< $@ + +#*.v: *.vhdl +# $(VHDL2VL) $< $@ + +#$(PROJECT).ys: makefile +# $(SCRIPTS)/ysgen.sh $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES) > $@ +# echo "hierarchy -top ${TOP_MODULE}" >> $@ +# echo "synth_ecp5 -noccu2 -nomux -nodram -json ${PROJECT}.json" >> $@ + +#$(PROJECT).json: $(PROJECT).ys $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES) +# $(YOSYS) $(PROJECT).ys + +$(PROJECT).json: $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES) + $(YOSYS) \ + -p "hierarchy -top ${TOP_MODULE}" \ + -p "synth_ecp5 ${YOSYS_OPTIONS} -json ${PROJECT}.json" \ + $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES) + +$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config: $(PROJECT).json $(BASECFG) + $(NEXTPNR-ECP5) --$(FPGA_K)k --json $(PROJECT).json --lpf $(CONSTRAINTS) --basecfg $(BASECFG) --textcfg $@ + +#$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config +# LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPACK) $(IDCODE_CHIPID) --db $(TRELLISDB) --input $< --bit $@ + +# generate LDF project file for diamond +$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).ldf: $(SCRIPTS)/project.ldf $(SCRIPTS)/ldf.xsl $(SCRIPTS)/$(BOARD)_sram.xcf + xsltproc \ + --stringparam FPGA_DEVICE $(FPGA_CHIP_UPPERCASE)-$(FPGA_PACKAGE_UPPERCASE) \ + --stringparam CONSTRAINTS_FILE $(CONSTRAINTS) \ + --stringparam STRATEGY_FILE $(STRATEGY) \ + --stringparam XCF_FILE $(SCRIPTS)/$(BOARD)_sram.xcf \ + --stringparam TOP_MODULE $(TOP_MODULE) \ + --stringparam TOP_MODULE_FILE $(TOP_MODULE_FILE) \ + --stringparam VHDL_FILES "$(VHDL_FILES)" \ + --stringparam VERILOG_FILES "$(VERILOG_FILES)" \ + --stringparam SBX_FILES "$(SBX_FILES)" \ + $(SCRIPTS)/ldf.xsl $(SCRIPTS)/project.ldf > $@ + +project/project_project.bit: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).ldf $(VERILOG_FILES) $(VHDL_FILES) + echo prj_project open $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).ldf \; prj_run Export -task Bitgen | ${DIAMONDC} + +$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit: project/project_project.bit + ln -sf project/project_project.bit $@ + +$(CLK0_FILE_NAME): + LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPLL) $(CLK0_OPTIONS) --file $@ + +$(CLK1_FILE_NAME): + LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPLL) $(CLK1_OPTIONS) --file $@ + +$(CLK2_FILE_NAME): + LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPLL) $(CLK2_OPTIONS) --file $@ + +$(CLK3_FILE_NAME): + LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPLL) $(CLK3_OPTIONS) --file $@ + +# generate sram programming XCF file for DDTCMD +$(BOARD)_$(FPGA_SIZE)f.xcf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(SCRIPTS)/$(BOARD)_sram.xcf $(SCRIPTS)/xcf.xsl + xsltproc \ + --stringparam FPGA_CHIP $(FPGA_CHIP_UPPERCASE) \ + --stringparam CHIP_ID $(CHIP_ID) \ + --stringparam BITSTREAM_FILE $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit \ + $(SCRIPTS)/xcf.xsl $(SCRIPTS)/$(BOARD)_sram.xcf > $@ + +# run DDTCMD to generate sram VME file +$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme: $(BOARD)_$(FPGA_SIZE)f.xcf $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + LANG=C ${DDTCMD} -oft -fullvme -if $(BOARD)_$(FPGA_SIZE)f.xcf -nocompress -noheader -of $@ + +# run DDTCMD to generate SVF file +$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf: $(BOARD)_$(FPGA_SIZE)f.xcf $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if $(BOARD)_$(FPGA_SIZE)f.xcf -of $@ + +# run DDTCMD to generate flash MCS file +$(BOARD)_$(FPGA_SIZE)f_$(PROJECT)_flash.mcs: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + LANG=C ${DDTCMD} -dev $(FPGA_CHIP_UPPERCASE) \ + -if $< -oft -int -quad $(FPGA_SPI) -of $@ + +# generate flash programming XCF file for DDTCMD +$(BOARD)_$(FPGA_SIZE)f_flash_$(FLASH_CHIP).xcf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(SCRIPTS)/$(BOARD)_flash_$(FLASH_CHIP).xcf $(SCRIPTS)/xcf.xsl + xsltproc \ + --stringparam FPGA_CHIP $(FPGA_CHIP_UPPERCASE) \ + --stringparam CHIP_ID $(CHIP_ID) \ + --stringparam MASK_FILE $(MASK_PATH)/$(MASK_FILE) \ + --stringparam BITSTREAM_FILE $(BOARD)_$(FPGA_SIZE)f_$(PROJECT)_flash.mcs \ + $(SCRIPTS)/xcf.xsl $(SCRIPTS)/$(BOARD)_flash_$(FLASH_CHIP).xcf > $@ + +# run DDTCMD to generate flash VME file +$(BOARD)_$(FPGA_SIZE)f_$(PROJECT)_flash_$(FLASH_CHIP).vme: $(BOARD)_$(FPGA_SIZE)f_flash_$(FLASH_CHIP).xcf $(BOARD)_$(FPGA_SIZE)f_$(PROJECT)_flash.mcs + LANG=C ${DDTCMD} -oft -fullvme -if $(BOARD)_$(FPGA_SIZE)f_flash_$(FLASH_CHIP).xcf -nocompress -noheader -of $@ + +# generate SVF file by prjtrellis python script +#$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit +# $(BIT2SVF) $< $@ + +#$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config +# LD_LIBRARY_PATH=$(LIBTRELLIS) $(ECPPACK) $(IDCODE_CHIPID) --db $(TRELLISDB) $< --freq 62.0 --svf-rowsize 8000 --svf $@ + +# program SRAM with ujrprog (temporary) +prog: program +program: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + $(UJPROG) $< + +# program SRAM with OPENFPGALOADER +prog_ofl: program_ofl +program_ofl: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + $(OPENFPGALOADER) $(OPENFPGALOADER_OPTIONS) $< + +# program SRAM with FleaFPGA-JTAG (temporary) +program_flea: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme + $(FLEAFPGA_JTAG) $< + +# program FLASH over US1 port with ujprog (permanently) +flash: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + $(UJPROG) -j flash $< + +# program FLASH uver US1 with FleaFPGA-JTAG (permanent) +flash_flea: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT)_flash_$(FLASH_CHIP).vme + $(FLEAFPGA_JTAG) $< + +# program FLASH over US2 port with DFU bootloader (permanently) +flash_dfu: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + $(DFU_UTIL) -a 0 -D $< + $(DFU_UTIL) -a 0 -e + +# program FLASH over US2 port with tinyfpgasp bootloader (permanently) +flash_tiny: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + $(TINYFPGASP) -w $< + +# generate chip-specific openocd programming file +$(BOARD)_$(FPGA_SIZE)f.ocd: $(SCRIPTS)/ecp5-ocd.sh + $(SCRIPTS)/ecp5-ocd.sh $(CHIP_ID) $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf > $@ + +# program SRAM with OPENOCD +prog_ocd: program_ocd +program_ocd: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf $(BOARD)_$(FPGA_SIZE)f.ocd + $(OPENOCD) --file=$(OPENOCD_INTERFACE) --file=$(BOARD)_$(FPGA_SIZE)f.ocd + +JUNK = *~ +#JUNK += $(PROJECT).ys +JUNK += $(PROJECT).json +JUNK += $(VHDL_TO_VERILOG_FILES) +JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config +JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).ldf +JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit +JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme +JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf +JUNK += $(BOARD)_$(FPGA_SIZE)f.xcf +JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT)_flash.mcs +JUNK += $(BOARD)_$(FPGA_SIZE)f_flash_$(FLASH_CHIP).xcf +JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT)_flash_$(FLASH_CHIP).vme +JUNK += $(BOARD)_$(FPGA_SIZE)f.ocd +JUNK += $(CLK0_FILE_NAME) $(CLK1_FILE_NAME) $(CLK2_FILE_NAME) $(CLK3_FILE_NAME) +# diamond junk +JUNK += ${IMPL_DIR} .recovery ._Real_._Math_.vhd *.sty reportview.xml +JUNK += dummy_sym.sort project_tcl.html promote.xml .run_manager.ini +JUNK += generate_core.tcl generate_ngd.tcl msg_file.log + +JUNK_DIR = project +JUNK_DIR += project_tcr.dir + +clean: + rm -rf $(JUNK_DIR) + rm -f $(JUNK) diff --git a/j1b/ulx3s/scripts/diamond_path.mk b/j1b/ulx3s/scripts/diamond_path.mk new file mode 100644 index 0000000..89418c3 --- /dev/null +++ b/j1b/ulx3s/scripts/diamond_path.mk @@ -0,0 +1,6 @@ +# the path of your diamond installation +DIAMOND_BASE ?= /usr/local/diamond + +# it is a directory that looks like this: +# ls /usr/local/diamond +# 3.7_x64 diff --git a/j1b/ulx3s/scripts/trellis_main.mk b/j1b/ulx3s/scripts/trellis_main.mk new file mode 100644 index 0000000..99b046c --- /dev/null +++ b/j1b/ulx3s/scripts/trellis_main.mk @@ -0,0 +1,231 @@ +# ******* project, board and chip name ******* +PROJECT ?= project +BOARD ?= board +FPGA_PREFIX ?= +# 12 25 45 85 um-85 um5g-85 +FPGA_SIZE ?= 12 +FPGA_CHIP ?= lfe5u-$(FPGA_SIZE)f +FPGA_PACKAGE ?= CABGA381 +# 2.4 4.8 9.7 19.4 38.8 62.0 +FLASH_READ_MHZ ?= 62.0 +# fast-read dual-spi qspi +FLASH_READ_MODE ?= fast-read + +# ******* design files ******* +CONSTRAINTS ?= board_constraints.lpf +TOP_MODULE ?= top +VERILOG_FILES ?= $(TOP_MODULE).v +# implicit list of *.vhd VHDL files to be converted to verilog *.v +# files here are list as *.v but user should +# edit original source which has *.vhd extension (vhdl_blink.vhd) +VHDL_FILES ?= + +# ******* tools installation paths ******* +# https://github.com/ldoolitt/vhd2vl +#VHDL2VL ?= /mt/scratch/tmp/openfpga/vhd2vl/src/vhd2vl +# https://github.com/YosysHQ/yosys +#YOSYS ?= /mt/scratch/tmp/openfpga/yosys/yosys +# https://github.com/YosysHQ/nextpnr +#NEXTPNR-ECP5 ?= /mt/scratch/tmp/openfpga/nextpnr/nextpnr-ecp5 +# https://github.com/SymbiFlow/prjtrellis +#TRELLIS ?= /mt/scratch/tmp/openfpga/prjtrellis + +# open source synthesis tools +TRELLISDB ?= $(TRELLIS)/database +LIBTRELLIS ?= $(TRELLIS)/libtrellis +ECPPLL ?= LANG=C ecppll # LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(TRELLIS)/libtrellis/ecppll +ECPPACK ?= LANG=C ecppack # LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(TRELLIS)/libtrellis/ecppack --db $(TRELLISDB) +BIT2SVF ?= $(TRELLIS)/tools/bit_to_svf.py +#BASECFG ?= $(TRELLIS)/misc/basecfgs/empty_$(FPGA_CHIP_EQUIVALENT).config +# yosys options, sometimes those can be used: -noccu2 -nomux -nodram +YOSYS_OPTIONS ?= +# nextpnr options +NEXTPNR_OPTIONS ?= + +ifeq ($(FPGA_CHIP), lfe5u-12f) + CHIP_ID=0x21111043 +endif +ifeq ($(FPGA_CHIP), lfe5u-25f) + CHIP_ID=0x41111043 +endif +ifeq ($(FPGA_CHIP), lfe5u-45f) + CHIP_ID=0x41112043 +endif +ifeq ($(FPGA_CHIP), lfe5u-85f) + CHIP_ID=0x41113043 +endif + +#ifeq ($(FPGA_SIZE), 12) +# FPGA_K=$(FPGA_PREFIX)25 +# IDCODE_CHIPID=--idcode $(CHIP_ID) +#else + FPGA_K=$(FPGA_PREFIX)$(FPGA_SIZE) + IDCODE_CHIPID= +#endif + + +FPGA_CHIP_EQUIVALENT ?= lfe5u-$(FPGA_K)f + +# clock generator +CLK0_NAME ?= clk0 +CLK0_FILE_NAME ?= clocks/$(CLK0_NAME).v +CLK0_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0 +CLK1_NAME ?= clk1 +CLK1_FILE_NAME ?= clocks/$(CLK1_NAME).v +CLK1_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0 +CLK2_NAME ?= clk2 +CLK2_FILE_NAME ?= clocks/$(CLK2_NAME).v +CLK2_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0 +CLK3_NAME ?= clk3 +CLK3_FILE_NAME ?= clocks/$(CLK3_NAME).v +CLK3_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0 + +# closed source synthesis tools +#DIAMOND_BASE := /usr/local/diamond +ifneq ($(wildcard $(DIAMOND_BASE)),) + DIAMOND_BIN := $(shell find ${DIAMOND_BASE}/ -maxdepth 2 -name bin | sort -rn | head -1) + DIAMONDC := $(shell find ${DIAMOND_BIN}/ -name diamondc) + DDTCMD := $(shell find ${DIAMOND_BIN}/ -name ddtcmd) +endif + +# programming tools +UJPROG ?= fujprog +OPENFPGALOADER ?= openFPGALoader +OPENFPGALOADER_OPTIONS ?= --board ulx3s +FLEAFPGA_JTAG ?= FleaFPGA-JTAG +OPENOCD ?= openocd +OPENOCD_INTERFACE ?= $(SCRIPTS)/ft231x.ocd +DFU_UTIL ?= dfu-util +TINYFPGASP ?= tinyfpgasp + +# helper scripts directory +SCRIPTS ?= scripts + +# rest of the include makefile +FPGA_CHIP_UPPERCASE := $(shell echo $(FPGA_CHIP) | tr '[:lower:]' '[:upper:]') + + +#all: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf +all: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf + +# VHDL to VERILOG conversion +# convert all *.vhd filenames to .v extension +VHDL_TO_VERILOG_FILES = $(VHDL_FILES:.vhd=.v) +# implicit conversion rule +%.v: %.vhd + $(VHDL2VL) $< $@ + +#*.v: *.vhdl +# $(VHDL2VL) $< $@ + +#$(PROJECT).ys: makefile +# $(SCRIPTS)/ysgen.sh $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES) > $@ +# echo "hierarchy -top ${TOP_MODULE}" >> $@ +# echo "synth_ecp5 -noccu2 -nomux -nodram -json ${PROJECT}.json" >> $@ + +#$(PROJECT).json: $(PROJECT).ys $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES) +# $(YOSYS) $(PROJECT).ys + +$(PROJECT).json: $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES) + $(YOSYS) \ + -p "read -sv $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES)" \ + -p "hierarchy -top ${TOP_MODULE}" \ + -p "synth_ecp5 ${YOSYS_OPTIONS} -json ${PROJECT}.json" + +$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config: $(PROJECT).json $(BASECFG) + $(NEXTPNR-ECP5) $(NEXTPNR_OPTIONS) --$(FPGA_K)k --package $(FPGA_PACKAGE) --json $(PROJECT).json --lpf $(CONSTRAINTS) --textcfg $@ + +$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config + $(ECPPACK) $(IDCODE_CHIPID) --compress --freq $(FLASH_READ_MHZ) --input $< --bit $@ +# $(ECPPACK) $(IDCODE_CHIPID) --compress --freq $(FLASH_READ_MHZ) --spimode $(FLASH_READ_MODE) --input $< --bit $@ + +$(CLK0_FILE_NAME): + $(ECPPLL) $(CLK0_OPTIONS) --file $@ + +$(CLK1_FILE_NAME): + $(ECPPLL) $(CLK1_OPTIONS) --file $@ + +$(CLK2_FILE_NAME): + $(ECPPLL) $(CLK2_OPTIONS) --file $@ + +$(CLK3_FILE_NAME): + $(ECPPLL) $(CLK3_OPTIONS) --file $@ + +# generate XCF programming file for DDTCMD +$(BOARD)_$(FPGA_SIZE)f.xcf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(SCRIPTS)/$(BOARD)_sram.xcf $(SCRIPTS)/xcf.xsl $(DTD_FILE) + xsltproc \ + --stringparam FPGA_CHIP $(FPGA_CHIP_UPPERCASE) \ + --stringparam CHIP_ID $(CHIP_ID) \ + --stringparam BITSTREAM_FILE $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit \ + $(SCRIPTS)/xcf.xsl $(SCRIPTS)/$(BOARD)_sram.xcf > $@ + +# run DDTCMD to generate VME file +$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme: $(BOARD)_$(FPGA_SIZE)f.xcf $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + LANG=C ${DDTCMD} -oft -fullvme -if $(BOARD)_$(FPGA_SIZE)f.xcf -nocompress -noheader -of $@ + +# run DDTCMD to generate SVF file +#$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf: $(BOARD)_$(FPGA_SIZE)f.xcf $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit +# LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if $(BOARD)_$(FPGA_SIZE)f.xcf -of $@ + +# generate SVF file by prjtrellis python script +#$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit +# $(BIT2SVF) $< $@ + +$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config + $(ECPPACK) $(IDCODE_CHIPID) $< --compress --freq $(FLASH_READ_MHZ) --svf-rowsize 800000 --svf $@ +# $(ECPPACK) $(IDCODE_CHIPID) $< --compress --freq $(FLASH_READ_MHZ) --spimode $(FLASH_READ_MODE) --svf-rowsize 800000 --svf $@ + +# program SRAM with ujrprog (temporary) +prog: program +program: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + $(UJPROG) $< + +# program SRAM with OPENFPGALOADER +prog_ofl: program_ofl +program_ofl: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + $(OPENFPGALOADER) $(OPENFPGALOADER_OPTIONS) $< + +# program SRAM with FleaFPGA-JTAG (temporary) +program_flea: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme + $(FLEAFPGA_JTAG) $< + +# program FLASH over US1 port with ujprog (permanently) +flash: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + $(UJPROG) -j flash $< + +# program FLASH over US1 port with openFPGALoader (permanently) +flash_ofl: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + $(OPENFPGALOADER) $(OPENFPGALOADER_OPTIONS) -f $< + +# program FLASH over US2 port with DFU bootloader (permanently) +flash_dfu: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + $(DFU_UTIL) -a 0 -D $< + $(DFU_UTIL) -a 0 -e + +# program FLASH over US2 port with tinyfpgasp bootloader (permanently) +flash_tiny: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + $(TINYFPGASP) -w $< + +# generate chip-specific openocd programming file +$(BOARD)_$(FPGA_SIZE)f.ocd: $(SCRIPTS)/ecp5-ocd.sh + $(SCRIPTS)/ecp5-ocd.sh $(CHIP_ID) $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf > $@ + +# program SRAM with OPENOCD +prog_ocd: program_ocd +program_ocd: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf $(BOARD)_$(FPGA_SIZE)f.ocd + $(OPENOCD) --file=$(OPENOCD_INTERFACE) --file=$(BOARD)_$(FPGA_SIZE)f.ocd + +JUNK = *~ +#JUNK += $(PROJECT).ys +JUNK += $(PROJECT).json +JUNK += $(VHDL_TO_VERILOG_FILES) +JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config +JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit +JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme +JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf +JUNK += $(BOARD)_$(FPGA_SIZE)f.xcf +JUNK += $(BOARD)_$(FPGA_SIZE)f.ocd +JUNK += $(CLK0_FILE_NAME) $(CLK1_FILE_NAME) $(CLK2_FILE_NAME) $(CLK3_FILE_NAME) + +clean: + rm -f $(JUNK) diff --git a/j1b/ulx3s/scripts/trellis_main_sv.mk b/j1b/ulx3s/scripts/trellis_main_sv.mk new file mode 100644 index 0000000..7da4e27 --- /dev/null +++ b/j1b/ulx3s/scripts/trellis_main_sv.mk @@ -0,0 +1,207 @@ +# ******* project, board and chip name ******* +PROJECT ?= project +BOARD ?= board +FPGA_PREFIX ?= +FPGA_SIZE ?= 12 +FPGA_CHIP ?= lfe5u-$(FPGA_SIZE)f +FPGA_PACKAGE ?= CABGA381 + +# ******* design files ******* +CONSTRAINTS ?= board_constraints.lpf +TOP_MODULE ?= top +VERILOG_FILES ?= +SYSTEMVERILOG_FILES ?= +# implicit list of *.vhd VHDL files to be converted to verilog *.v +# files here are list as *.v but user should +# edit original source which has *.vhd extension (vhdl_blink.vhd) +VHDL_FILES ?= + +# ******* tools installation paths ******* +# https://github.com/ldoolitt/vhd2vl +#VHDL2VL ?= /mt/scratch/tmp/openfpga/vhd2vl/src/vhd2vl +# https://github.com/YosysHQ/yosys +#YOSYS ?= /mt/scratch/tmp/openfpga/yosys/yosys +# https://github.com/YosysHQ/nextpnr +#NEXTPNR-ECP5 ?= /mt/scratch/tmp/openfpga/nextpnr/nextpnr-ecp5 +# https://github.com/SymbiFlow/prjtrellis +#TRELLIS ?= /mt/scratch/tmp/openfpga/prjtrellis + +# open source synthesis tools +TRELLISDB ?= $(TRELLIS)/database +LIBTRELLIS ?= $(TRELLIS)/libtrellis +ECPPLL ?= LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(TRELLIS)/libtrellis/ecppll +ECPPACK ?= LANG=C LD_LIBRARY_PATH=$(LIBTRELLIS) $(TRELLIS)/libtrellis/ecppack --db $(TRELLISDB) +BIT2SVF ?= $(TRELLIS)/tools/bit_to_svf.py +#BASECFG ?= $(TRELLIS)/misc/basecfgs/empty_$(FPGA_CHIP_EQUIVALENT).config +# yosys options, sometimes those can be used: -noccu2 -nomux -nodram +YOSYS_OPTIONS ?= +# nextpnr options +NEXTPNR_OPTIONS ?= + +ifeq ($(FPGA_CHIP), lfe5u-12f) + CHIP_ID=0x21111043 +endif +ifeq ($(FPGA_CHIP), lfe5u-25f) + CHIP_ID=0x41111043 +endif +ifeq ($(FPGA_CHIP), lfe5u-45f) + CHIP_ID=0x41112043 +endif +ifeq ($(FPGA_CHIP), lfe5u-85f) + CHIP_ID=0x41113043 +endif + +ifeq ($(FPGA_SIZE), 12) + FPGA_K=$(FPGA_PREFIX)25 + IDCODE_CHIPID=--idcode $(CHIP_ID) +else + FPGA_K=$(FPGA_PREFIX)$(FPGA_SIZE) + IDCODE_CHIPID= +endif + +FPGA_CHIP_EQUIVALENT ?= lfe5u-$(FPGA_K)f + + +# clock generator +CLK0_NAME ?= clk0 +CLK0_FILE_NAME ?= clocks/$(CLK0_NAME).v +CLK0_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0 +CLK1_NAME ?= clk1 +CLK1_FILE_NAME ?= clocks/$(CLK1_NAME).v +CLK1_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0 +CLK2_NAME ?= clk2 +CLK2_FILE_NAME ?= clocks/$(CLK2_NAME).v +CLK2_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0 +CLK3_NAME ?= clk3 +CLK3_FILE_NAME ?= clocks/$(CLK3_NAME).v +CLK3_OPTIONS ?= --input 25 --output 100 --s1 50 --p1 0 --s2 25 --p2 0 --s3 125 --p3 0 + +# closed source synthesis tools +#DIAMOND_BASE := /usr/local/diamond +ifneq ($(wildcard $(DIAMOND_BASE)),) + DIAMOND_BIN := $(shell find ${DIAMOND_BASE}/ -maxdepth 2 -name bin | sort -rn | head -1) + DIAMONDC := $(shell find ${DIAMOND_BIN}/ -name diamondc) + DDTCMD := $(shell find ${DIAMOND_BIN}/ -name ddtcmd) +endif + +# programming tools +TINYFPGASP ?= tinyfpgasp +FLEAFPGA_JTAG ?= FleaFPGA-JTAG +OPENOCD ?= openocd +OPENOCD_INTERFACE ?= $(SCRIPTS)/ft231x.ocd +UJPROG ?= ujprog + +# helper scripts directory +SCRIPTS ?= scripts + +# rest of the include makefile +FPGA_CHIP_UPPERCASE := $(shell echo $(FPGA_CHIP) | tr '[:lower:]' '[:upper:]') + + +#all: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf +all: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf + +# VHDL to VERILOG conversion +# convert all *.vhd filenames to .v extension +VHDL_TO_VERILOG_FILES = $(VHDL_FILES:.vhd=.v) +# implicit conversion rule +%.v: %.vhd + $(VHDL2VL) $< $@ + +#*.v: *.vhdl +# $(VHDL2VL) $< $@ + +#$(PROJECT).ys: makefile +# $(SCRIPTS)/ysgen.sh $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES) > $@ +# echo "hierarchy -top ${TOP_MODULE}" >> $@ +# echo "synth_ecp5 -noccu2 -nomux -nodram -json ${PROJECT}.json" >> $@ + +#$(PROJECT).json: $(PROJECT).ys $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES) +# $(YOSYS) $(PROJECT).ys + +$(PROJECT).json: $(VERILOG_FILES) $(SYSTEMVERILOG_FILES) $(VHDL_TO_VERILOG_FILES) + $(YOSYS) \ + -p "read -vlog2k $(VERILOG_FILES) $(VHDL_TO_VERILOG_FILES)" \ + -p "read -sv $(SYSTEMVERILOG_FILES)" \ + -p "hierarchy -top ${TOP_MODULE}" \ + -p "synth_ecp5 ${YOSYS_OPTIONS} -json ${PROJECT}.json" + +$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config: $(PROJECT).json $(BASECFG) + $(NEXTPNR-ECP5) $(NEXTPNR_OPTIONS) --$(FPGA_K)k --package $(FPGA_PACKAGE) --json $(PROJECT).json --lpf $(CONSTRAINTS) --textcfg $@ + +$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config + $(ECPPACK) $(IDCODE_CHIPID) --compress --input $< --bit $@ + +$(CLK0_FILE_NAME): + $(ECPPLL) $(CLK0_OPTIONS) --file $@ + +$(CLK1_FILE_NAME): + $(ECPPLL) $(CLK1_OPTIONS) --file $@ + +$(CLK2_FILE_NAME): + $(ECPPLL) $(CLK2_OPTIONS) --file $@ + +$(CLK3_FILE_NAME): + $(ECPPLL) $(CLK3_OPTIONS) --file $@ + +# generate XCF programming file for DDTCMD +$(BOARD)_$(FPGA_SIZE)f.xcf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit $(SCRIPTS)/$(BOARD)_sram.xcf $(SCRIPTS)/xcf.xsl $(DTD_FILE) + xsltproc \ + --stringparam FPGA_CHIP $(FPGA_CHIP_UPPERCASE) \ + --stringparam CHIP_ID $(CHIP_ID) \ + --stringparam BITSTREAM_FILE $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit \ + $(SCRIPTS)/xcf.xsl $(SCRIPTS)/$(BOARD)_sram.xcf > $@ + +# run DDTCMD to generate VME file +$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme: $(BOARD)_$(FPGA_SIZE)f.xcf $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + LANG=C ${DDTCMD} -oft -fullvme -if $(BOARD)_$(FPGA_SIZE)f.xcf -nocompress -noheader -of $@ + +# run DDTCMD to generate SVF file +#$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf: $(BOARD)_$(FPGA_SIZE)f.xcf $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit +# LANG=C ${DDTCMD} -oft -svfsingle -revd -maxdata 8 -if $(BOARD)_$(FPGA_SIZE)f.xcf -of $@ + +# generate SVF file by prjtrellis python script +#$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit +# $(BIT2SVF) $< $@ + +$(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config + $(ECPPACK) $(IDCODE_CHIPID) $< --freq 62.0 --svf-rowsize 800000 --svf $@ + +# program SRAM with ujrprog (temporary) +program: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + $(UJPROG) $< + +# program SRAM with FleaFPGA-JTAG (temporary) +program_flea: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme + $(FLEAFPGA_JTAG) $< + +# program FLASH over US1 port with ujprog bootloader (permanently) +flash: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + $(UJPROG) -j flash $< + +# program FLASH over US2 port with tinyfpgasp bootloader (permanently) +flash_tiny: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit + $(TINYFPGASP) -w $< + +# generate chip-specific openocd programming file +$(BOARD)_$(FPGA_SIZE)f.ocd: makefile $(SCRIPTS)/ecp5-ocd.sh + $(SCRIPTS)/ecp5-ocd.sh $(CHIP_ID) $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf > $@ + +# program SRAM with OPENOCD +program_ocd: $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf $(BOARD)_$(FPGA_SIZE)f.ocd + $(OPENOCD) --file=$(OPENOCD_INTERFACE) --file=$(BOARD)_$(FPGA_SIZE)f.ocd + +JUNK = *~ +#JUNK += $(PROJECT).ys +JUNK += $(PROJECT).json +JUNK += $(VHDL_TO_VERILOG_FILES) +JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).config +JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).bit +JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).vme +JUNK += $(BOARD)_$(FPGA_SIZE)f_$(PROJECT).svf +JUNK += $(BOARD)_$(FPGA_SIZE)f.xcf +JUNK += $(BOARD)_$(FPGA_SIZE)f.ocd +JUNK += $(CLK0_FILE_NAME) $(CLK1_FILE_NAME) $(CLK2_FILE_NAME) $(CLK3_FILE_NAME) + +clean: + rm -f $(JUNK) diff --git a/j1b/ulx3s/scripts/trellis_path.mk b/j1b/ulx3s/scripts/trellis_path.mk new file mode 100644 index 0000000..28ddf37 --- /dev/null +++ b/j1b/ulx3s/scripts/trellis_path.mk @@ -0,0 +1,12 @@ +# ******* tools installation paths ******* +# https://github.com/SymbiFlow/prjtrellis +TRELLIS ?= /mt/scratch/tmp/openfpga/prjtrellis +# https://github.com/ldoolitt/vhd2vl +VHDL2VL ?= vhd2vl +# https://github.com/YosysHQ/yosys +YOSYS ?= yosys +# https://github.com/YosysHQ/nextpnr +NEXTPNR-ECP5 ?= nextpnr-ecp5 +# trellis ecppack +ECPPACK ?= LANG=C ecppack +ECPPLL ?= LANG=C ecppll diff --git a/j1b/ulx3s/ulx3s_v20_segpdi.lpf b/j1b/ulx3s/ulx3s_v20_segpdi.lpf new file mode 100644 index 0000000..6379d18 --- /dev/null +++ b/j1b/ulx3s/ulx3s_v20_segpdi.lpf @@ -0,0 +1,457 @@ +BLOCK RESETPATHS; +BLOCK ASYNCPATHS; +## ULX3S v2.x.x and v3.0.x + +# The clock "usb" and "gpdi" sheet +LOCATE COMP "clk_25mhz" SITE "G2"; +IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33; +FREQUENCY PORT "clk_25mhz" 25 MHZ; + +# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash +# write to FLASH possible any time from JTAG: +SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=ENABLE SLAVE_PARALLEL_PORT=DISABLE; +# write to FLASH possible from user bitstream: +# SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE; + +## USBSERIAL FTDI-FPGA serial port "usb" sheet +LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi +LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi +LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives +LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives +LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives +IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33; + +## LED indicators "blinkey" and "gpio" sheet +LOCATE COMP "led[7]" SITE "H3"; +LOCATE COMP "led[6]" SITE "E1"; +LOCATE COMP "led[5]" SITE "E2"; +LOCATE COMP "led[4]" SITE "D1"; +LOCATE COMP "led[3]" SITE "D2"; +LOCATE COMP "led[2]" SITE "C1"; +LOCATE COMP "led[1]" SITE "C2"; +LOCATE COMP "led[0]" SITE "B2"; +IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet +LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic) +LOCATE COMP "btn[1]" SITE "R1"; # FIRE1 +LOCATE COMP "btn[2]" SITE "T1"; # FIRE2 +LOCATE COMP "btn[3]" SITE "R18"; # UP W1->R18 +LOCATE COMP "btn[4]" SITE "V1"; # DOWN +LOCATE COMP "btn[5]" SITE "U1"; # LEFT +LOCATE COMP "btn[6]" SITE "H16"; # RIGHT Y2->H16 +IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; + +## DIP switch "blinkey", "gpio" sheet +LOCATE COMP "sw[0]" SITE "E8"; # SW1 +LOCATE COMP "sw[1]" SITE "D8"; # SW2 +LOCATE COMP "sw[2]" SITE "D7"; # SW3 +LOCATE COMP "sw[3]" SITE "E7"; # SW4 +IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; + +## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet +LOCATE COMP "oled_clk" SITE "P4"; +LOCATE COMP "oled_mosi" SITE "P3"; +LOCATE COMP "oled_dc" SITE "P1"; +LOCATE COMP "oled_resn" SITE "P2"; +LOCATE COMP "oled_csn" SITE "N2"; +IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## SPI Flash chip "flash" sheet +LOCATE COMP "flash_csn" SITE "R2"; +LOCATE COMP "flash_clk" SITE "U3"; +LOCATE COMP "flash_mosi" SITE "W2"; +LOCATE COMP "flash_miso" SITE "V2"; +LOCATE COMP "flash_holdn" SITE "W1"; +LOCATE COMP "flash_wpn" SITE "Y2"; +#LOCATE COMP "flash_csspin" SITE "AJ3"; +#LOCATE COMP "flash_initn" SITE "AG4"; +#LOCATE COMP "flash_done" SITE "AJ4"; +#LOCATE COMP "flash_programn" SITE "AH4"; +#LOCATE COMP "flash_cfg_select[0]" SITE "AM4"; +#LOCATE COMP "flash_cfg_select[1]" SITE "AL4"; +#LOCATE COMP "flash_cfg_select[2]" SITE "AK4"; +IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_holdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_wpn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; + +## SD card "sdcard", "usb" sheet +LOCATE COMP "sd_clk" SITE "H2"; # sd_clk WiFi_GPIO14 +LOCATE COMP "sd_cmd" SITE "J1"; # sd_cmd_di (MOSI) WiFi GPIO15 +LOCATE COMP "sd_d[0]" SITE "J3"; # sd_dat0_do (MISO) WiFi GPIO2 +LOCATE COMP "sd_d[1]" SITE "H1"; # sd_dat1_irq WiFi GPIO4 +LOCATE COMP "sd_d[2]" SITE "K1"; # sd_dat2 WiFi_GPIO12 +LOCATE COMP "sd_d[3]" SITE "K2"; # sd_dat3_csn WiFi_GPIO13 +LOCATE COMP "sd_wp" SITE "P5"; # not connected +LOCATE COMP "sd_cdn" SITE "N5"; # not connected +IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement +IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## ADC SPI (MAX11123) "analog", "ram" sheet +LOCATE COMP "adc_csn" SITE "R17"; +LOCATE COMP "adc_mosi" SITE "R16"; +LOCATE COMP "adc_miso" SITE "U16"; +LOCATE COMP "adc_sclk" SITE "P17"; +IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## Audio 4-bit DAC "analog", "gpio" sheet +# 4-bit mode can drive down to 75 ohm load impedance. +# Lower impedance leads to IO overload, +# FPGA will stop working and need reboot. +# For standard 17 ohm earphones on PCB v1.7: +# use bits 2,3 as input (High-Z) and drive only bits 0,1. +# PCB v2.1.2 can use full 4 bits and 16mA drive for 17 ohm earphones. +LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio) +LOCATE COMP "audio_l[2]" SITE "C3"; +LOCATE COMP "audio_l[1]" SITE "D3"; +LOCATE COMP "audio_l[0]" SITE "E4"; +LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio) +LOCATE COMP "audio_r[2]" SITE "D5"; +LOCATE COMP "audio_r[1]" SITE "B5"; +LOCATE COMP "audio_r[0]" SITE "A3"; +LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio) +LOCATE COMP "audio_v[2]" SITE "F5"; +LOCATE COMP "audio_v[1]" SITE "F2"; +LOCATE COMP "audio_v[0]" SITE "H5"; +IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; + +## WiFi ESP-32 "wifi", "usb", "flash" sheet +# other pins are shared with GP/GN, SD card and JTAG +LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi +LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi +LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi +LOCATE COMP "wifi_gpio0" SITE "L2"; +LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED +LOCATE COMP "wifi_gpio16" SITE "L1"; # Serial1 RX +LOCATE COMP "wifi_gpio17" SITE "N3"; # Serial1 TX +# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active +IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio5" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## PCB antenna 433 MHz (may be also used for FM) "usb" sheet +LOCATE COMP "ant_433mhz" SITE "G1"; +IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +## Second USB port "US2" going directly into FPGA "usb", "ram" sheet +LOCATE COMP "usb_fpga_dp" SITE "E16"; # single ended or differential input only +LOCATE COMP "usb_fpga_dn" SITE "F16"; +IOBUF PORT "usb_fpga_dp" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=16; +IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=16; +LOCATE COMP "usb_fpga_bd_dp" SITE "D15"; # single-ended bidirectional +LOCATE COMP "usb_fpga_bd_dn" SITE "E15"; +IOBUF PORT "usb_fpga_bd_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "usb_fpga_bd_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "usb_fpga_pu_dp" SITE "B12"; # pull up/down control +LOCATE COMP "usb_fpga_pu_dn" SITE "C12"; +IOBUF PORT "usb_fpga_pu_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "usb_fpga_pu_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; + +## JTAG ESP-32 "usb" sheet +# connected to FT231X and ESP-32 +# commented out because those are dedicated pins, not directly useable as GPIO +# but could be used by some vendor-specific JTAG bridging (boundary scan) module +#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives +#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits +#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives +#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives +#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## SDRAM "ram" sheet +LOCATE COMP "sdram_clk" SITE "F19"; +LOCATE COMP "sdram_cke" SITE "F20"; +LOCATE COMP "sdram_csn" SITE "P20"; +LOCATE COMP "sdram_wen" SITE "T20"; +LOCATE COMP "sdram_rasn" SITE "R20"; +LOCATE COMP "sdram_casn" SITE "T19"; +LOCATE COMP "sdram_a[0]" SITE "M20"; +LOCATE COMP "sdram_a[1]" SITE "M19"; +LOCATE COMP "sdram_a[2]" SITE "L20"; +LOCATE COMP "sdram_a[3]" SITE "L19"; +LOCATE COMP "sdram_a[4]" SITE "K20"; +LOCATE COMP "sdram_a[5]" SITE "K19"; +LOCATE COMP "sdram_a[6]" SITE "K18"; +LOCATE COMP "sdram_a[7]" SITE "J20"; +LOCATE COMP "sdram_a[8]" SITE "J19"; +LOCATE COMP "sdram_a[9]" SITE "H20"; +LOCATE COMP "sdram_a[10]" SITE "N19"; +LOCATE COMP "sdram_a[11]" SITE "G20"; +LOCATE COMP "sdram_a[12]" SITE "G19"; +LOCATE COMP "sdram_ba[0]" SITE "P19"; +LOCATE COMP "sdram_ba[1]" SITE "N20"; +LOCATE COMP "sdram_dqm[0]" SITE "U19"; +LOCATE COMP "sdram_dqm[1]" SITE "E20"; +LOCATE COMP "sdram_d[0]" SITE "J16"; +LOCATE COMP "sdram_d[1]" SITE "L18"; +LOCATE COMP "sdram_d[2]" SITE "M18"; +LOCATE COMP "sdram_d[3]" SITE "N18"; +LOCATE COMP "sdram_d[4]" SITE "P18"; +LOCATE COMP "sdram_d[5]" SITE "T18"; +LOCATE COMP "sdram_d[6]" SITE "T17"; +LOCATE COMP "sdram_d[7]" SITE "U20"; +LOCATE COMP "sdram_d[8]" SITE "E19"; +LOCATE COMP "sdram_d[9]" SITE "D20"; +LOCATE COMP "sdram_d[10]" SITE "D19"; +LOCATE COMP "sdram_d[11]" SITE "C20"; +LOCATE COMP "sdram_d[12]" SITE "E18"; +LOCATE COMP "sdram_d[13]" SITE "F18"; +LOCATE COMP "sdram_d[14]" SITE "J18"; +LOCATE COMP "sdram_d[15]" SITE "J17"; +IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +# GPDI differential interface (Video) "gpdi" sheet +LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue + +LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue - +LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green + +LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green - +LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red + +LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Red - +LOCATE COMP "gpdi_dp[3]" SITE "A17"; # Clock + +LOCATE COMP "gpdi_dn[3]" SITE "B18"; # Clock - +LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet + +LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet - +LOCATE COMP "gpdi_cec" SITE "A18"; +LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC +LOCATE COMP "gpdi_scl" SITE "E12"; # I2C shared with RTC C12->E12 +IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dp[3]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dn[3]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet +# Pins enumerated gp[0-27], gn[0-27]. +# With differential mode enabled on Lattice, +# gp[] (+) are used, gn[] (-) are ignored from design +# as they handle inverted signal by default. +# To enable differential, rename LVCMOS33->LVCMOS33D +LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0 +LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0 +LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1 +LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1 +LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2 +LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2 +LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3 +LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3 +LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4 +LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4 +LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5 +LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5 +LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6 +LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6 +IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7 +LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7 +LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8 +LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8 +LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9 +LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9 +LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 WIFI_GPIO27 +LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10 +LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 WIFI_GPIO25 +LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 WIFI_GPIO26 +LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 WIFI_GPIO32 +LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 WIFI_GPIO33 +LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 WIFI_GPIO34 +LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 WIFI_GPIO35 +IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14 +LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14 +LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15 +LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15 +LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16 +LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16 +LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17 +LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17 +LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18 +LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18 +LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19 +LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19 +LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20 +LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20 +IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21 +LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21 +LOCATE COMP "gp[22]" SITE "B15"; # J2_25+ GP22 D15->B15 +LOCATE COMP "gn[22]" SITE "C15"; # J2_25- GN22 E15->C15 +LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23 +LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23 +LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24 +LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24 +LOCATE COMP "gp[25]" SITE "D14"; # J2_31+ GP25 B15->D14 +LOCATE COMP "gn[25]" SITE "E14"; # J2_31- GN25 C15->E14 +LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26 +LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26 +LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27 +LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27 +IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## PROGRAMN (reload bitstream from FLASH, exit from bootloader) +# PCB v2.0.5 and higher +LOCATE COMP "user_programn" SITE "M4"; +IOBUF PORT "user_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5) +# on PCB v1.7 shutdown is not connected to FPGA +LOCATE COMP "shutdown" SITE "G16"; # FPGA receives +IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; diff --git a/j1b/verilog/ram.v b/j1b/verilog/ram.v new file mode 100644 index 0000000..6c5edb9 --- /dev/null +++ b/j1b/verilog/ram.v @@ -0,0 +1,83 @@ +`default_nettype none + +module bram_tdp #( + parameter DATA = 72, + parameter ADDR = 10 +) ( + // Port A + input wire a_clk, + input wire a_wr, + input wire [ADDR-1:0] a_addr, + input wire [DATA-1:0] a_din, + output reg [DATA-1:0] a_dout, + + // Port B + input wire b_clk, + input wire b_wr, + input wire [ADDR-1:0] b_addr, + input wire [DATA-1:0] b_din, + output reg [DATA-1:0] b_dout +); + +// Shared memory +reg [DATA-1:0] mem [(2**ADDR)-1:0]; + initial begin + $readmemh("../build/nuc.hex", mem); + end + +// Port A +always @(posedge a_clk) begin + a_dout <= mem[a_addr]; + if(a_wr) begin + a_dout <= a_din; + mem[a_addr] <= a_din; + end +end + +// Port B +always @(posedge b_clk) begin + b_dout <= mem[b_addr]; + if(b_wr) begin + b_dout <= b_din; + mem[b_addr] <= b_din; + end +end + +endmodule + +// A 32Kbyte RAM (8192x32) with two ports: +// port a, 32 bits read/write +// port b, 16 bits read-only, lower 16K only + +module ram16k( + input wire clk, + + input wire[15:0] a_addr, + output wire[31:0] a_q, + input wire[31:0] a_d, + input wire a_wr, + + input wire[12:0] b_addr, + output wire[15:0] b_q); + + wire [31:0] insn32; + + bram_tdp #(.DATA(32), .ADDR(13)) nram ( + .a_clk(clk), + .a_wr(a_wr), + .a_addr(a_addr[14:2]), + .a_din(a_d), + .a_dout(a_q), + + .b_clk(clk), + .b_wr(1'b0), + .b_addr({1'b0, b_addr[12:1]}), + .b_din(32'd0), + .b_dout(insn32)); + + reg ba_; + always @(posedge clk) + ba_ <= b_addr[0]; + assign b_q = ba_ ? insn32[31:16] : insn32[15:0]; + +endmodule diff --git a/j1b/verilog/ulx3s_top.v b/j1b/verilog/ulx3s_top.v new file mode 100644 index 0000000..321ec80 --- /dev/null +++ b/j1b/verilog/ulx3s_top.v @@ -0,0 +1,141 @@ +`default_nettype none + +module ulx3s_top( + input wire clk_25mhz, + input wire [6:0] btn, + output wire [7:0] led, + + input wire ftdi_txd, + output wire ftdi_rxd, + + output wire wifi_gpio0 + ); + + // Tie GPIO0, keep board from rebooting + assign wifi_gpio0 = 1'b1; + + // no leds on for now + assign led = 0; + + wire resetq = btn[0]; + + localparam MHZ = 25; + wire fclk = clk_25mhz; + + reg [63:0] counter; + always @(posedge fclk) + counter <= counter + 64'd1; + + reg [31:0] ms; + reg [17:0] subms; + localparam [17:0] lim = (MHZ * 1000) - 1; + always @(posedge fclk) begin + subms <= (subms == lim) ? 18'd0 : (subms + 18'd1); + if (subms == lim) + ms <= ms + 32'd1; + end + + // ------------------------------------------------------------------------ + + wire uart0_valid, uart0_busy; + wire [7:0] uart0_data; + wire uart0_rd, uart0_wr; + reg [31:0] uart_baud = 32'd115200; + wire UART0_RX; + buart #(.CLKFREQ(MHZ * 1000000)) _uart0 ( + .clk(fclk), + .resetq(resetq), + .baud(uart_baud), + .rx(ftdi_txd), + .tx(ftdi_rxd), + .rd(uart0_rd), + .wr(uart0_wr), + .valid(uart0_valid), + .busy(uart0_busy), + .tx_data(dout_[7:0]), + .rx_data(uart0_data)); + + wire [15:0] mem_addr; + wire [31:0] mem_din; + wire mem_wr; + wire [31:0] dout; + reg [31:0] din; + + wire [12:0] code_addr; + wire [15:0] insn; + + wire io_rd, io_wr; + + j1 _j1 ( + .clk(fclk), + .resetq(resetq), + + .io_rd(io_rd), + .io_wr(io_wr), + .mem_addr(mem_addr), + .mem_wr(mem_wr), + .mem_din(mem_din), + .dout(dout), + .io_din(din), + + .code_addr(code_addr), + .insn(insn) + ); + + ram16k ram(.clk(fclk), + .a_addr(mem_addr), + .a_q(mem_din), + .a_wr(mem_wr), + .a_d(dout), + .b_addr(code_addr), + .b_q(insn)); + + reg io_wr_, io_rd_; + reg [15:0] mem_addr_; + reg [31:0] dout_; + always @(posedge fclk) + {io_wr_, io_rd_, mem_addr_, dout_} <= {io_wr, io_rd, mem_addr, dout}; + + /* READ WRITE + 00xx GPIO rd GPIO wr + 01xx GPIO direction + + 1008 baudrate baudrate + 1000 UART RX UART TX + 2000 UART status + + 1010 master freq snapshot clock + 1014 clock[31:0] + 1018 clock[63:32] + 101c millisecond uptime + + */ + + reg [63:0] counter_; + + always @(posedge fclk) begin + casez (mem_addr) + 16'h1008: din <= uart_baud; + 16'h1000: din <= {24'd0, uart0_data}; + 16'h2000: din <= {30'd0, uart0_valid, !uart0_busy}; + + 16'h1010: din <= MHZ * 1000000; + 16'h1014: din <= counter_[31:0]; + 16'h1018: din <= counter_[63:32]; + 16'h101c: din <= ms; + + default: din <= 32'bx; + endcase + + if (io_wr_) begin + casez (mem_addr_) + 16'h1008: uart_baud <= dout_; + 16'h1010: counter_ <= counter; + endcase + end + end + + assign uart0_wr = io_wr_ & (mem_addr_ == 16'h1000); + assign uart0_rd = io_rd_ & (mem_addr_ == 16'h1000); + +endmodule diff --git a/j1b/verilog/xilinx-top.v b/j1b/verilog/xilinx-top.v index 8d92f44..6e4b1e4 100644 --- a/j1b/verilog/xilinx-top.v +++ b/j1b/verilog/xilinx-top.v @@ -1,88 +1,5 @@ `default_nettype none -module bram_tdp #( - parameter DATA = 72, - parameter ADDR = 10 -) ( - // Port A - input wire a_clk, - input wire a_wr, - input wire [ADDR-1:0] a_addr, - input wire [DATA-1:0] a_din, - output reg [DATA-1:0] a_dout, - - // Port B - input wire b_clk, - input wire b_wr, - input wire [ADDR-1:0] b_addr, - input wire [DATA-1:0] b_din, - output reg [DATA-1:0] b_dout -); - -// Shared memory -reg [DATA-1:0] mem [(2**ADDR)-1:0]; - initial begin - $readmemh("../build/nuc.hex", mem); - end - -// Port A -always @(posedge a_clk) begin - a_dout <= mem[a_addr]; - if(a_wr) begin - a_dout <= a_din; - mem[a_addr] <= a_din; - end -end - -// Port B -always @(posedge b_clk) begin - b_dout <= mem[b_addr]; - if(b_wr) begin - b_dout <= b_din; - mem[b_addr] <= b_din; - end -end - -endmodule - -// A 32Kbyte RAM (8192x32) with two ports: -// port a, 32 bits read/write -// port b, 16 bits read-only, lower 16K only - -module ram16k( - input wire clk, - - input wire[15:0] a_addr, - output wire[31:0] a_q, - input wire[31:0] a_d, - input wire a_wr, - - input wire[12:0] b_addr, - output wire[15:0] b_q); - - wire [31:0] insn32; - - bram_tdp #(.DATA(32), .ADDR(13)) nram ( - .a_clk(clk), - .a_wr(a_wr), - .a_addr(a_addr[14:2]), - .a_din(a_d), - .a_dout(a_q), - - .b_clk(clk), - .b_wr(1'b0), - .b_addr({1'b0, b_addr[12:1]}), - .b_din(32'd0), - .b_dout(insn32)); - - reg ba_; - always @(posedge clk) - ba_ <= b_addr[0]; - assign b_q = ba_ ? insn32[31:16] : insn32[15:0]; - -endmodule - - module top( input wire CLK, input wire DUO_SW1, diff --git a/j1b/xilinx/Makefile b/j1b/xilinx/Makefile index 23db1a6..5360868 100644 --- a/j1b/xilinx/Makefile +++ b/j1b/xilinx/Makefile @@ -6,7 +6,14 @@ part = xc6slx9-2-tqg144 top_module = top flashsize = 2048 -vfiles = ../verilog/xilinx-top.v ../verilog/uart.v ../verilog/j1.v ../verilog/stack.v # ../verilog/vga.v +vfiles = \ +../verilog/xilinx-top.v \ +../verilog/j1.v \ +../verilog/ram.v \ +../verilog/uart.v \ +../verilog/stack.v \ +# ../verilog/vga.v \ + ifiles = ../build/nuc.hex include xilinx.mk From 9a92f21ba9c119b0875a5c2dabdf7d867edd7fc4 Mon Sep 17 00:00:00 2001 From: Ties Stuij Date: Fri, 28 Oct 2022 15:48:16 +0100 Subject: [PATCH 2/3] add support for reading of buttons, writing to leds on ULX3S Also added to ULX3S readme for memory map layout updates and examples. --- j1b/ulx3s/README.md | 42 +++++++++++++++++++++++++++++++++++++++-- j1b/verilog/ulx3s_top.v | 17 +++++++++-------- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/j1b/ulx3s/README.md b/j1b/ulx3s/README.md index 262c787..98cf900 100644 --- a/j1b/ulx3s/README.md +++ b/j1b/ulx3s/README.md @@ -14,5 +14,43 @@ USB: Now you can use `shell.py` in the parent directory to attach to the Forth process over UART. The Verilator bootstrap process will also work for ULX3S. -Currently only J1b itself and UART are supported. Support for low-hanging fruit -like GPIOs, buttons and LEDs should follow shortly. +Currently only J1b itself, UART, buttons and LEDs are supported. Support for +low-hanging fruit like GPIOs should follow shortly. + + +PWR button resets the board + +memory map: + +0x0400: buttons (excluding PWR) +direction: in +each button occupies one bit in the bottom 6 bits + +as per silkscreen labels on the board: +| 32 - 6 | 5 | 4 | 3 | 2 | 1 | 0 | + unused RIGHT LEFT DOWN UP F2 F1 + +example: + + $0400 io@ . + + + +0x0404: leds +direction: out +each led occupies one bit in the bottom 8 bits + +as per silkscreen labels on the board: +| 32 - 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + unused D7 D6 D5 D4 D3 D2 D1 D0 + +example: + : led-counter / interpret LEDs as a byte + 0 begin + dup $0404 io! / write to LEDs, initially 0 + 1+ / increment bits every loop + 200 ms / wait for 1/5th of a second + again + ; + led-counter + diff --git a/j1b/verilog/ulx3s_top.v b/j1b/verilog/ulx3s_top.v index 321ec80..ea0cd0f 100644 --- a/j1b/verilog/ulx3s_top.v +++ b/j1b/verilog/ulx3s_top.v @@ -2,6 +2,7 @@ module ulx3s_top( input wire clk_25mhz, + input wire [6:0] btn, output wire [7:0] led, @@ -14,9 +15,6 @@ module ulx3s_top( // Tie GPIO0, keep board from rebooting assign wifi_gpio0 = 1'b1; - // no leds on for now - assign led = 0; - wire resetq = btn[0]; localparam MHZ = 25; @@ -97,26 +95,28 @@ module ulx3s_top( {io_wr_, io_rd_, mem_addr_, dout_} <= {io_wr, io_rd, mem_addr, dout}; /* READ WRITE - 00xx GPIO rd GPIO wr - 01xx GPIO direction + 0400 buttons rd + 0404 LEDs wr - 1008 baudrate baudrate 1000 UART RX UART TX - 2000 UART status + 1008 baudrate baudrate 1010 master freq snapshot clock 1014 clock[31:0] 1018 clock[63:32] 101c millisecond uptime + 2000 UART status */ reg [63:0] counter_; always @(posedge fclk) begin casez (mem_addr) - 16'h1008: din <= uart_baud; + 16'h0400: din <= {27'd0, btn[6:1]}; + 16'h1000: din <= {24'd0, uart0_data}; + 16'h1008: din <= uart_baud; 16'h2000: din <= {30'd0, uart0_valid, !uart0_busy}; 16'h1010: din <= MHZ * 1000000; @@ -129,6 +129,7 @@ module ulx3s_top( if (io_wr_) begin casez (mem_addr_) + 16'h0404: led <= dout_; 16'h1008: uart_baud <= dout_; 16'h1010: counter_ <= counter; endcase From d435d84fd26ba28d42f3f536bc7709d1450f305f Mon Sep 17 00:00:00 2001 From: Ties Stuij Date: Tue, 1 Nov 2022 17:01:10 +0000 Subject: [PATCH 3/3] add support for in/out GPIO pins on ULX3S The ULX3S has 2x28 IO pins that can be used either individually or as differential pairs. Currently we're going to assume an individual setup (you can configure their behaviour in the .lpf file). The convention is to see them as gp[27] (GPIO positive) and gn[27] (GPIO negative) arrays; this is how they're numbered on the board itself. Note that positive and negative moniker are irrelevant in the current configuration as the ports aren't set up as differential pairs. To work with this convention, we split out the GPIO address space into 0x00XX and 0x02XX for setting in/output values of gp and gn pins respectively, and use 0x01XX and 0x3XX for setting the direction of the gn and gp pins. --- j1b/ulx3s/README.md | 42 ++++++++++++++++++++++++++------- j1b/verilog/ulx3s_top.v | 51 +++++++++++++++++++++++++++++++++-------- 2 files changed, 76 insertions(+), 17 deletions(-) diff --git a/j1b/ulx3s/README.md b/j1b/ulx3s/README.md index 98cf900..fe6fb56 100644 --- a/j1b/ulx3s/README.md +++ b/j1b/ulx3s/README.md @@ -14,16 +14,45 @@ USB: Now you can use `shell.py` in the parent directory to attach to the Forth process over UART. The Verilator bootstrap process will also work for ULX3S. -Currently only J1b itself, UART, buttons and LEDs are supported. Support for -low-hanging fruit like GPIOs should follow shortly. +Currently the J1b itself, UART, buttons, LEDs and GPIO ports are supported. +PWR button resets the board. -PWR button resets the board memory map: +0x00XX: gp GPIOs +read/write +either write bit to or read bit from address corresponding to the gp pin numbers +on the board + +0x01XX: gp GPIO in/out direction +read/write +set direction of corresponding gp pin; 0 = input (default), 1 = output + +example: + $001b io@ \ read gn[27] + OUTPUT $011b io! \ set direction of gn[27] to output + 1 $001b io! \ set gn[27] to high + + +0x02XX: gn GPIOs +read/write +either write bit to or read bit from address corresponding to the gn pin numbers +on the board + +0x03XX: gn GPIO in/out direction +read/write +set direction of corresponding gn pin; 0 = input (default), 1 = output + +example: + $021b io@ \ read gn[27] + OUTPUT $031b io! \ set direction of gn[27] to output + 1 $021b io! \ set gn[27] to high + + 0x0400: buttons (excluding PWR) -direction: in +read each button occupies one bit in the bottom 6 bits as per silkscreen labels on the board: @@ -31,13 +60,11 @@ as per silkscreen labels on the board: unused RIGHT LEFT DOWN UP F2 F1 example: - $0400 io@ . - 0x0404: leds -direction: out +write each led occupies one bit in the bottom 8 bits as per silkscreen labels on the board: @@ -53,4 +80,3 @@ example: again ; led-counter - diff --git a/j1b/verilog/ulx3s_top.v b/j1b/verilog/ulx3s_top.v index ea0cd0f..0a89ddc 100644 --- a/j1b/verilog/ulx3s_top.v +++ b/j1b/verilog/ulx3s_top.v @@ -5,6 +5,8 @@ module ulx3s_top( input wire [6:0] btn, output wire [7:0] led, + output wire [3:0] audio_l, audio_r, audio_v, + inout wire [27:0] gp, gn, input wire ftdi_txd, output wire ftdi_rxd, @@ -95,6 +97,11 @@ module ulx3s_top( {io_wr_, io_rd_, mem_addr_, dout_} <= {io_wr, io_rd, mem_addr, dout}; /* READ WRITE + 00xx GP rd GP wr + 01xx GP direction GP direction + 02xx GN rd GN wr + 03xx GP direction GN direction + 0400 buttons rd 0404 LEDs wr @@ -111,31 +118,57 @@ module ulx3s_top( reg [63:0] counter_; + reg [27:0] gp_o; + wire [27:0] gp_i; + reg [27:0] gp_dir; // 1:output, 0:input + reg [27:0] gn_o; + wire [27:0] gn_i; + reg [27:0] gn_dir; // 1:output, 0:input + always @(posedge fclk) begin casez (mem_addr) - 16'h0400: din <= {27'd0, btn[6:1]}; + 16'h00??: din <= gp_i[mem_addr[6:0]]; + 16'h01??: din <= gp_dir[mem_addr[6:0]]; + 16'h02??: din <= gn_i[mem_addr[6:0]]; + 16'h03??: din <= gn_dir[mem_addr[6:0]]; - 16'h1000: din <= {24'd0, uart0_data}; - 16'h1008: din <= uart_baud; - 16'h2000: din <= {30'd0, uart0_valid, !uart0_busy}; + 16'h0400: din <= {27'd0, btn[6:1]}; - 16'h1010: din <= MHZ * 1000000; - 16'h1014: din <= counter_[31:0]; - 16'h1018: din <= counter_[63:32]; - 16'h101c: din <= ms; + 16'h1000: din <= {24'd0, uart0_data}; + 16'h1008: din <= uart_baud; + 16'h2000: din <= {30'd0, uart0_valid, !uart0_busy}; - default: din <= 32'bx; + 16'h1010: din <= MHZ * 1000000; + 16'h1014: din <= counter_[31:0]; + 16'h1018: din <= counter_[63:32]; + 16'h101c: din <= ms; + + default: din <= 32'bx; endcase if (io_wr_) begin casez (mem_addr_) + 16'h00??: gp_o[mem_addr_[6:0]] <= dout_[0]; + 16'h01??: gp_dir[mem_addr_[6:0]] <= dout_[0]; + 16'h02??: gn_o[mem_addr_[6:0]] <= dout_[0]; + 16'h03??: gn_dir[mem_addr_[6:0]] <= dout_[0]; + 16'h0404: led <= dout_; + 16'h1008: uart_baud <= dout_; 16'h1010: counter_ <= counter; endcase end end + genvar i; + for (i = 0; i <= 27; i = i + 1) begin + assign gp[i] = gp_dir[i] ? gp_o[i] : 1'bz; + assign gp_i[i] = gp[i]; + assign gn[i] = gn_dir[i] ? gn_o[i] : 1'bz; + assign gn_i[i] = gn[i]; + end + assign uart0_wr = io_wr_ & (mem_addr_ == 16'h1000); assign uart0_rd = io_rd_ & (mem_addr_ == 16'h1000);