536 lines
16 KiB
Makefile
Raw Normal View History

2022-09-19 08:51:11 +02:00
#=======================================================================
#
# Makefile
# --------
# Makefile for building, simulating, running all application_fpga
# HW targets as well as its firmware.
#
#
# Copyright (C) 2022-2024 - Tillitis AB
2022-09-19 08:51:11 +02:00
# SPDX-License-Identifier: GPL-2.0-only
#
#
# Please note: When creating a new cores and adding more testbenches,
# please update the tb target below to include it as well.
#
2022-09-19 08:51:11 +02:00
#=======================================================================
#-------------------------------------------------------------------
# Defines.
#-------------------------------------------------------------------
SHELL := /bin/bash
CUR_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
P := $(CUR_DIR)
YOSYS_PATH ?=
NEXTPNR_PATH ?=
ICESTORM_PATH ?=
# FPGA target frequency. Should be in sync with the clock frequency
# given by the parameters to the PLL in rtl/clk_reset_gen.v
TARGET_FREQ ?= 21
2022-10-11 17:25:00 +02:00
# Size in 32-bit words, must be divisible by 256 (pairs of EBRs, because 16
# bits wide; an EBR is 128 32-bits words)
2022-10-11 12:54:44 +02:00
BRAM_FW_SIZE ?= 1536
2022-09-19 08:51:11 +02:00
PIN_FILE ?= application_fpga_tk1.pcf
2022-09-19 08:51:11 +02:00
SIZE ?= llvm-size
OBJCOPY ?= llvm-objcopy
2022-09-19 08:51:11 +02:00
CC = clang
2022-09-19 08:51:11 +02:00
CFLAGS = \
-target riscv32-unknown-none-elf \
-march=rv32iczmmul \
-mabi=ilp32 \
-static \
-std=gnu99 \
-O2 \
-ffast-math \
-fno-common \
-fno-builtin-printf \
-fno-builtin-putchar \
-fno-builtin-memcpy \
-nostdlib \
-mno-relax \
-Wall \
-Wpedantic \
-Wno-language-extension-token \
-flto \
-g
2022-09-19 08:51:11 +02:00
AS = clang
ASFLAGS = \
-target riscv32-unknown-none-elf \
-march=rv32iczmmul \
-mabi=ilp32 \
-mno-relax
2022-09-19 08:51:11 +02:00
ICE40_SIM_CELLS = $(shell yosys-config --datdir/ice40/cells_sim.v)
2022-10-11 16:58:26 +02:00
# FPGA specific source files.
FPGA_VERILOG_SRCS = \
$(P)/rtl/application_fpga.v \
$(P)/core/clk_reset_gen/rtl/clk_reset_gen.v \
$(P)/core/trng/rtl/trng.v
# Testbench simulation specific source files.
SIM_VERILOG_SRCS = \
$(P)/tb/tb_application_fpga_sim.v \
$(P)/tb/application_fpga_sim.v \
$(P)/tb/reset_gen_sim.v \
$(P)/tb/trng_sim.v
2022-09-19 08:51:11 +02:00
2022-10-11 16:58:26 +02:00
# Verilator simulation specific source files.
VERILATOR_VERILOG_SRCS = \
$(P)/tb/application_fpga_sim.v \
$(P)/tb/reset_gen_sim.v \
$(P)/tb/trng_sim.v
2022-09-19 08:51:11 +02:00
# Common verilog source files.
2022-09-19 08:51:11 +02:00
VERILOG_SRCS = \
$(P)/core/ram/rtl/ram.v \
$(P)/core/rom/rtl/rom.v \
$(P)/core/fw_ram/rtl/fw_ram.v \
2022-09-19 08:51:11 +02:00
$(P)/core/timer/rtl/timer_core.v \
$(P)/core/timer/rtl/timer.v \
$(P)/core/uds/rtl/uds.v \
$(P)/core/uds/rtl/uds_rom.v \
2022-09-19 08:51:11 +02:00
$(P)/core/touch_sense/rtl/touch_sense.v \
2022-10-20 14:50:21 +02:00
$(P)/core/tk1/rtl/tk1.v \
$(P)/core/tk1/rtl/tk1_spi_master.v \
$(P)/core/tk1/rtl/udi_rom.v \
2022-09-19 08:51:11 +02:00
$(P)/core/uart/rtl/uart_core.v \
$(P)/core/uart/rtl/uart_fifo.v \
$(P)/core/uart/rtl/uart.v
2022-09-19 08:51:11 +02:00
# PicoRV32 verilog source file
PICORV32_SRCS = \
$(P)/core/picorv32/rtl/picorv32.v
2022-09-19 08:51:11 +02:00
FIRMWARE_DEPS = \
2022-10-20 14:50:21 +02:00
$(P)/fw/tk1_mem.h \
$(P)/fw/tk1/types.h \
$(P)/fw/tk1/lib.h \
$(P)/fw/tk1/proto.h \
$(P)/fw/tk1/assert.h \
$(P)/fw/tk1/led.h
2022-09-19 08:51:11 +02:00
FIRMWARE_OBJS = \
2022-10-20 14:50:21 +02:00
$(P)/fw/tk1/main.o \
$(P)/fw/tk1/start.o \
$(P)/fw/tk1/proto.o \
$(P)/fw/tk1/lib.o \
$(P)/fw/tk1/assert.o \
$(P)/fw/tk1/led.o \
2022-10-20 14:50:21 +02:00
$(P)/fw/tk1/blake2s/blake2s.o
2022-09-19 08:51:11 +02:00
FIRMWARE_SOURCES = \
$(P)/fw/tk1/main.c \
$(P)/fw/tk1/proto.c \
$(P)/fw/tk1/lib.c \
$(P)/fw/tk1/assert.c \
$(P)/fw/tk1/led.c \
$(P)/fw/tk1/blake2s/blake2s.c
2022-09-19 08:51:11 +02:00
TESTFW_OBJS = \
$(P)/fw/testfw/main.o \
$(P)/fw/testfw/start.o \
2022-10-20 14:50:21 +02:00
$(P)/fw/tk1/proto.o \
$(P)/fw/tk1/lib.o \
$(P)/fw/tk1/blake2s/blake2s.o
2022-09-19 08:51:11 +02:00
#-------------------------------------------------------------------
# All: Complete build of HW and FW.
#-------------------------------------------------------------------
all: application_fpga.bin
.PHONY: all
#-------------------------------------------------------------------
# The size_mismatch target make sure that we don't end up with an
# incorrect BRAM_FW_SIZE
# -------------------------------------------------------------------
2022-10-11 17:25:19 +02:00
%_size_mismatch: %.elf phony_explicit
@test $$($(SIZE) $< | awk 'NR==2{print $$4}') -le $$(( 32 / 8 * $(BRAM_FW_SIZE) )) \
|| { printf "The 'BRAM_FW_SIZE' variable needs to be increased\n"; \
[[ $< =~ testfw ]] && printf "Note that testfw fits if built with -Os\n"; \
false; }
2022-09-19 08:51:11 +02:00
2022-10-11 17:25:19 +02:00
# can't make implicit rule .PHONY
2022-10-11 20:46:21 +02:00
phony_explicit:
2022-10-11 17:25:19 +02:00
.PHONY: phony_explicit
2022-09-19 08:51:11 +02:00
#-------------------------------------------------------------------
# Personalization of the TKey
#-------------------------------------------------------------------
secret:
cd data;../tools/tpt/tpt.py
.PHONY: secret
2022-09-19 08:51:11 +02:00
#-------------------------------------------------------------------
# Firmware generation.
# Included in the bitstream.
#-------------------------------------------------------------------
LDFLAGS = -T $(P)/fw/tk1/firmware.lds
2022-09-19 08:51:11 +02:00
$(FIRMWARE_OBJS): $(FIRMWARE_DEPS)
$(TESTFW_OBJS): $(FIRMWARE_DEPS)
2022-10-20 14:50:21 +02:00
firmware.elf: $(FIRMWARE_OBJS) $(P)/fw/tk1/firmware.lds
2022-09-19 08:51:11 +02:00
$(CC) $(CFLAGS) $(FIRMWARE_OBJS) $(LDFLAGS) -o $@
simfirmware.elf: CFLAGS += -DSIMULATION
simfirmware.elf: $(FIRMWARE_OBJS) $(P)/fw/tk1/firmware.lds
$(CC) $(CFLAGS) $(FIRMWARE_OBJS) $(LDFLAGS) -o $@
qemu_firmware.elf: CFLAGS += -DQEMU_CONSOLE
qemu_firmware.elf: firmware.elf
mv firmware.elf qemu_firmware.elf
# Create compile_commands.json for clangd and LSP
.PHONY: clangd
clangd: compile_commands.json
compile_commands.json:
$(MAKE) clean
bear -- make qemu_firmware.elf
.PHONY: check
check:
clang-tidy -header-filter=.* -checks=cert-* $(FIRMWARE_SOURCES) -- $(CFLAGS)
.PHONY: splint
splint:
splint \
-nolib \
-predboolint \
+boolint \
-nullpass \
-unrecog \
-infloops \
-initallelements \
-type \
-unreachable \
-unqualifiedtrans \
-fullinitblock \
$(FIRMWARE_SOURCES)
2022-10-20 14:50:21 +02:00
testfw.elf: $(TESTFW_OBJS) $(P)/fw/tk1/firmware.lds
2022-09-19 08:51:11 +02:00
$(CC) $(CFLAGS) $(TESTFW_OBJS) $(LDFLAGS) -o $@
# Generate a fake BRAM file that will be filled in later after place-n-route
bram_fw.hex:
$(ICESTORM_PATH)icebram -v -g 32 $(BRAM_FW_SIZE) > $@
2022-10-11 17:25:19 +02:00
firmware.hex: firmware.bin firmware_size_mismatch
2022-09-19 08:51:11 +02:00
python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
simfirmware.hex: simfirmware.bin simfirmware_size_mismatch
python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
2022-10-11 17:25:19 +02:00
testfw.hex: testfw.bin testfw_size_mismatch
2022-09-19 08:51:11 +02:00
python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
.PHONY: check-binary-hashes
check-binary-hashes:
sha512sum firmware.bin
sha256sum application_fpga.bin
sha512sum -c firmware.bin.sha512
sha256sum -c application_fpga.bin.sha256
2022-09-19 08:51:11 +02:00
%.bin: %.elf
$(SIZE) $<
@test "$$($(SIZE) $< | awk 'NR==2{print $$2, $$3}')" = "0 0" \
|| { printf "Non-empty data or bss section!\n"; false; }
2022-09-19 08:51:11 +02:00
$(OBJCOPY) --input-target=elf32-littleriscv --output-target=binary $< $@
chmod -x $@
#-------------------------------------------------------------------
# Source linting.
#-------------------------------------------------------------------
LINT = verilator
# For Verilator 5.019 -Wno-GENUNNAMED needs to be added to LINT_FLAGS for the
# cell library.
LINT_FLAGS = \
+1364-2005ext+ \
--lint-only \
-Wall \
-Wno-DECLFILENAME \
-Wno-WIDTHEXPAND \
-Wno-UNOPTFLAT \
--timescale 1ns/1ns \
-DNO_ICE40_DEFAULT_ASSIGNMENTS
2022-09-19 08:51:11 +02:00
lint: $(FPGA_VERILOG_SRCS) \
$(SIM_VERILOG_SRCS) \
$(VERILOG_SRCS) \
$(PICORV32_SRCS) \
$(ICE40_SIM_CELLS)
2022-09-19 08:51:11 +02:00
$(LINT) $(LINT_FLAGS) \
-DBRAM_FW_SIZE=$(BRAM_FW_SIZE) \
-DFIRMWARE_HEX=\"$(P)/firmware.hex\" \
-DUDS_HEX=\"$(P)/data/uds.hex\" \
-DUDI_HEX=\"$(P)/data/udi.hex\" \
--top-module application_fpga \
config.vlt $^ \
>lint_issues.txt 2>&1 \
&& { rm -f lint_issues.txt; exit 0; } \
|| { cat lint_issues.txt; exit 1; }
2022-09-19 08:51:11 +02:00
.PHONY: lint
#-------------------------------------------------------------------
# Source formatting.
#-------------------------------------------------------------------
FORMAT = verible-verilog-format
FORMAT_FLAGS = \
--indentation_spaces=2 \
--wrap_end_else_clauses=true \
--inplace
CHECK_FORMAT_FLAGS = \
--indentation_spaces=2 \
--wrap_end_else_clauses=true \
--inplace \
--verify
fmt: $(FPGA_VERILOG_SRCS) $(SIM_VERILOG_SRCS) $(VERILATOR_VERILOG_SRCS) $(VERILOG_SRCS)
$(FORMAT) $(FORMAT_FLAGS) $^
.PHONY: fmt
# Temporary fix using grep, since the verible with --verify flag only returns
# error if the last file is malformatted.
checkfmt: $(FPGA_VERILOG_SRCS) $(SIM_VERILOG_SRCS) $(VERILATOR_VERILOG_SRCS) $(VERILOG_SRCS)
$(FORMAT) $(CHECK_FORMAT_FLAGS) $^ 2>&1 | \
grep "Needs formatting" && exit 1 || true
.PHONY: checkfmt
2022-09-19 08:51:11 +02:00
#-------------------------------------------------------------------
# Build Verilator compiled simulation for the design.
#-------------------------------------------------------------------
verilator: $(VERILATOR_VERILOG_SRCS) $(VERILOG_SRCS) $(PICORV32_SRCS) \
firmware.hex $(ICE40_SIM_CELLS) \
2022-09-19 08:51:11 +02:00
$(P)/tb/application_fpga_verilator.cc
verilator \
--timescale 1ns/1ns \
-DNO_ICE40_DEFAULT_ASSIGNMENTS \
-Wall \
-Wno-COMBDLY \
-Wno-lint \
-Wno-UNOPTFLAT \
-DBRAM_FW_SIZE=$(BRAM_FW_SIZE) \
-DFIRMWARE_HEX=\"$(P)/firmware.hex\" \
-DUDS_HEX=\"$(P)/data/uds.hex\" \
-DUDI_HEX=\"$(P)/data/udi.hex\" \
--cc \
--exe \
--Mdir verilated \
--top-module application_fpga_sim \
$(filter %.v, $^) \
$(filter %.cc, $^)
make -C verilated -f Vapplication_fpga_sim.mk
2022-09-19 08:51:11 +02:00
.PHONY: verilator
#-------------------------------------------------------------------
# Run all testbenches
#-------------------------------------------------------------------
tb:
make -C core/timer/toolruns sim-top
make -C core/tk1/toolruns sim-top
make -C core/touch_sense/toolruns sim-top
make -C core/trng/toolruns sim-top
make -C core/uart/toolruns sim-top
make -C core/uds/toolruns sim-top
.PHONY: tb
2022-09-19 08:51:11 +02:00
#-------------------------------------------------------------------
# Main FPGA build flow.
# Synthesis. Place & Route. Bitstream generation.
#-------------------------------------------------------------------
YOSYS_FLAG ?=
synth.json: $(FPGA_VERILOG_SRCS) $(VERILOG_SRCS) $(PICORV32_SRCS) bram_fw.hex \
$(P)/data/uds.hex $(P)/data/udi.hex
$(YOSYS_PATH)yosys \
-v3 \
-l synth.txt \
$(YOSYS_FLAG) \
-DBRAM_FW_SIZE=$(BRAM_FW_SIZE) \
2022-09-19 08:51:11 +02:00
-DFIRMWARE_HEX=\"$(P)/bram_fw.hex\" \
-p 'synth_ice40 -abc2 -device u -dff -dsp -top application_fpga -json $@' \
-p 'write_verilog -attr2comment synth.v' \
$(filter %.v, $^)
2022-09-19 08:51:11 +02:00
application_fpga_par.json: synth.json $(P)/data/$(PIN_FILE)
$(NEXTPNR_PATH)nextpnr-ice40 \
-l application_fpga_par.txt \
--freq $(TARGET_FREQ) \
--ignore-loops \
--up5k \
--package sg48 \
--json $< \
--pcf $(P)/data/$(PIN_FILE) \
--write $@ \
&& { exit 0; } \
|| { rm -f application_fpga_par.json; exit 1; }
application_fpga.asc: application_fpga_par.json $(P)/data/uds.hex $(P)/data/udi.hex
UDS_HEX="$(P)/data/uds.hex" \
UDI_HEX="$(P)/data/udi.hex" \
OUT_ASC=$@ \
$(NEXTPNR_PATH)nextpnr-ice40 \
--up5k \
--package sg48 \
--ignore-loops \
--json $< \
--run tools/patch_uds_udi.py
2022-09-19 08:51:11 +02:00
application_fpga.bin: application_fpga.asc bram_fw.hex firmware.hex
$(ICESTORM_PATH)icebram -v bram_fw.hex firmware.hex < $< > $<.tmp
$(ICESTORM_PATH)icepack $<.tmp $@
@-$(RM) $<.tmp
application_fpga_testfw.bin: application_fpga.asc bram_fw.hex testfw.hex
$(ICESTORM_PATH)icebram -v bram_fw.hex testfw.hex < $< > $<.tmp
$(ICESTORM_PATH)icepack $<.tmp $@
@-$(RM) $<.tmp
#-------------------------------------------------------------------
# Build testbench simulation for the design
#-------------------------------------------------------------------
tb_application_fpga: $(SIM_VERILOG_SRCS) \
$(VERILOG_SRCS) \
$(PICORV32_SRCS) \
$(ICE40_SIM_CELLS) \
simfirmware.hex
python3 ./tools/app_bin_to_spram_hex.py \
./tb/app.bin \
./tb/output_spram0.hex \
./tb/output_spram1.hex \
./tb/output_spram2.hex \
./tb/output_spram3.hex \
|| { echo -e "\n -- Put your app.bin to simulate in the \"tb\" directory\n"; false; }
verilator \
-j $(shell nproc --ignore=1) \
--binary \
--cc \
--exe \
--Mdir tb_verilated \
--trace-fst \
--trace-structs \
--top-module tb_application_fpga_sim \
--timescale 1ns/1ns \
--timing \
-Wno-WIDTHEXPAND \
-Wno-UNOPTFLAT \
-DNO_ICE40_DEFAULT_ASSIGNMENTS \
-DAPP_SIZE=$(shell ls -l tb/app.bin| awk '{print $$5}') \
-DBRAM_FW_SIZE=$(BRAM_FW_SIZE) \
-DFIRMWARE_HEX=\"$(P)/simfirmware.hex\" \
-DUDS_HEX=\"$(P)/data/uds.hex\" \
-DUDI_HEX=\"$(P)/data/udi.hex\" \
$(filter %.v, $^)
make -C tb_verilated -f Vtb_application_fpga_sim.mk
./tb_verilated/Vtb_application_fpga_sim \
&& { echo -e "\n -- Wave simulation saved to tb_application_fpga_sim.fst\n"; true; }
2022-09-19 08:51:11 +02:00
#-------------------------------------------------------------------
# FPGA device programming.
#-------------------------------------------------------------------
prog_flash: check-hardware application_fpga.bin
sudo tillitis-iceprog application_fpga.bin
2022-09-19 08:51:11 +02:00
.PHONY: prog_flash
prog_flash_testfw: check-hardware application_fpga_testfw.bin
sudo tillitis-iceprog application_fpga_testfw.bin
2022-09-19 08:51:11 +02:00
.PHONY: prog_flash_testfw
check-hardware:
@sudo tillitis-iceprog -t >/dev/null 2>&1 || \
{ echo "Programmer not plugged in or not accessible"; false; }
@if sudo tillitis-iceprog -t 2>&1 | grep -qi "^flash.id:\( 0x\(00\|ff\)\)\{4\}"; then \
echo "No USB stick in the programmer?"; false; else true; fi
.PHONY: check-hardware
2022-09-19 08:51:11 +02:00
#-------------------------------------------------------------------
# Post build analysis.
#-------------------------------------------------------------------
timing: application_fpga.asc $(P)/data/$(PIN_FILE)
$(ICESTORM_PATH)icetime -c 18 -tmd up5k -P sg48 -p $(P)/data/$(PIN_FILE) -t $<
2022-09-19 08:51:11 +02:00
view: tb_application_fpga_vcd
gtkwave $< application_fpga.gtkw
#-------------------------------------------------------------------
# Cleanup.
#-------------------------------------------------------------------
clean: clean_sim clean_fw clean_tb
2022-09-19 08:51:11 +02:00
rm -f bram_fw.hex
rm -f synth.{v,json,txt} application_fpga.{asc,bin} application_fpga_testfw.bin
rm -f application_fpga_par.{json,txt}
rm -f lint_issues.txt
2022-09-19 08:51:11 +02:00
rm -f tools/tpt/*.hex
rm -rf tools/tpt/__pycache__
.PHONY: clean
clean_fw:
rm -f firmware.{elf,elf.map,bin,hex}
rm -f $(FIRMWARE_OBJS)
rm -f testfw.{elf,elf.map,bin,hex}
rm -f $(TESTFW_OBJS)
rm -f qemu_firmware.elf
2022-09-19 08:51:11 +02:00
.PHONY: clean_fw
clean_sim:
rm -f simfirmware.{elf,elf.map,bin,hex}
rm -f tb_application_fpga_sim.fst
rm -f tb_application_fpga_sim.fst.hier
rm -f tb/output_spram*.hex
rm -rf tb_verilated
rm -rf verilated
.PHONY: clean_sim
clean_tb:
make -C core/timer/toolruns clean
make -C core/tk1/toolruns clean
make -C core/touch_sense/toolruns clean
make -C core/trng/toolruns clean
make -C core/uart/toolruns clean
make -C core/uds/toolruns clean
.PHONY: clean_tb
2022-09-19 08:51:11 +02:00
#-------------------------------------------------------------------
# Display info about targets.
#-------------------------------------------------------------------
help:
@echo ""
@echo "Build system for application_fpga FPGA design and firmware."
@echo ""
@echo "Supported targets:"
@echo "------------------"
@echo "all Build all targets."
@echo "check Run static analysis on firmware."
@echo "splint Run splint static analysis on firmware."
@echo "firmware.elf Build firmware ELF file."
@echo "firmware.hex Build firmware converted to hex, to be included in bitstream."
@echo "bram_fw.hex Build a fake BRAM file that will be filled in later after place-n-route."
@echo "verilator Build Verilator simulation program"
@echo "tb_application_fpga Build testbench simulation for the design"
@echo "lint Run lint on Verilog source files."
@echo "tb Run all testbenches"
@echo "prog_flash Program device flash with FGPA bitstream including firmware (using the RPi Pico-based programmer)."
@echo "prog_flash_testfw Program device flash as above, but with testfw."
@echo "clean Delete all generated files."
@echo "clean_fw Delete only generated files for firmware. Useful for fw devs."
@echo "clean_tb Delete only generated files for testbenches."
2022-09-19 08:51:11 +02:00
#=======================================================================
# EOF Makefile
#=======================================================================