# ============================================================================ # mgpr832 — simulate the 8 x 32-bit 1W2R register card with Icarus Verilog # # The card model in src/mgpr832.v is generated from the KiCad netlist and # instantiates the device models from the sibling 74FAST project, so this # build reaches outside the directory for its parts library. # # Usage: # make regenerate if needed, compile, run the testbench # make gen regenerate src/mgpr832.v from mgpr832.net # make build compile without running # make wave run and write build/mgpr832.vcd # make clean remove build/ # make help this list # ============================================================================ FAST_DIR := ../74FAST SRC_DIR := src TB_DIR := tb TOOLS_DIR := tools BUILD_DIR := build NETLIST := mgpr832.net TOP := mgpr832 IVERILOG := iverilog VVP := vvp PYTHON := python3 # Which device models to compile, read from the netlist rather than listed # here: the card uses a handful of the parts in 74FAST/src, and which handful # changes whenever the schematic gains a part. Deriving it means adding a chip # to the design cannot leave this list stale, and the netlist is safe to read # at parse time because it is an input to this build, never an output of it. # (kept on one line: a backslash continuation inside $(shell ...) truncates # the command, and sh then chokes on the unterminated quote) PARTS := $(shell grep -o '(value "74F[0-9]*")' $(NETLIST) | tr -cd '0-9F\n' | sed 's/^74F/f/' | sort -u) PART_SRCS := $(addprefix $(FAST_DIR)/$(SRC_DIR)/,$(addsuffix .v,$(PARTS))) # -gspecify is load-bearing, exactly as in 74FAST's own Makefile: the device # models carry their data sheet propagation delays in specify blocks, which # Icarus parses but silently drops without it. This testbench checks end-to-end # delays that are sums of those per-device values, so dropping them turns every # timing check into a measured 0.00 ns. -Ttyp picks the typ arm of the # min:typ:max triples, which is what the expected sums are built from. # # -I$(FAST_DIR)/$(TB_DIR) is what lets the testbench `include "tb_common.vh"` # from the 74FAST project, and -g2012 is for the SystemVerilog $fatal that file # uses. -Wall is on, minus implicit-port-width noise from the scalar device # ports being driven from vectors. IVFLAGS := -g2012 -gspecify -Ttyp -Wall -I$(FAST_DIR)/$(TB_DIR) ifeq ($(V),1) Q := else Q := @ endif .PHONY: all test gen build wave clean help all: test gen: $(SRC_DIR)/$(TOP).v # The generated model is a build product of the netlist, but it is checked in # and readable, so it is regenerated only when the netlist or generator moves. $(SRC_DIR)/$(TOP).v: $(NETLIST) $(TOOLS_DIR)/netlist2v.py $(Q)echo " GEN $@" $(Q)mkdir -p $(@D) $(Q)$(PYTHON) $(TOOLS_DIR)/netlist2v.py $(NETLIST) $@ build: $(BUILD_DIR)/$(TOP).vvp $(BUILD_DIR)/$(TOP).vvp: $(TB_DIR)/$(TOP)_tb.v $(SRC_DIR)/$(TOP).v $(PART_SRCS) \ $(FAST_DIR)/$(TB_DIR)/tb_common.vh $(Q)echo " IVERILOG $(TOP)" $(Q)mkdir -p $(@D) $(Q)$(IVERILOG) $(IVFLAGS) -s $(TOP)_tb -o $@ \ $(TB_DIR)/$(TOP)_tb.v $(SRC_DIR)/$(TOP).v $(PART_SRCS) # A run passes only if it prints TEST PASSED: a testbench left waiting on an # event that never arrives exits 0 having printed no verdict at all, so a zero # status on its own proves nothing. Same rule as 74FAST's Makefile. test: $(BUILD_DIR)/$(TOP).vvp $(Q)$(VVP) $< > $(BUILD_DIR)/$(TOP).log 2>&1; \ if grep -q "TEST PASSED" $(BUILD_DIR)/$(TOP).log; then \ echo " PASS $(TOP)"; \ else \ echo " FAIL $(TOP) (full output in $(BUILD_DIR)/$(TOP).log)"; \ cat $(BUILD_DIR)/$(TOP).log | sed 's/^/ /'; \ exit 1; \ fi wave: $(BUILD_DIR)/$(TOP).vvp $(Q)$(VVP) $< +vcd=$(BUILD_DIR)/$(TOP).vcd clean: $(Q)rm -rf $(BUILD_DIR) help: @echo "targets:" @echo " test compile and run the testbench (default)" @echo " gen regenerate $(SRC_DIR)/$(TOP).v from $(NETLIST)" @echo " build compile without running" @echo " wave run and write $(BUILD_DIR)/$(TOP).vcd" @echo " clean remove $(BUILD_DIR)/" @echo @echo "options:" @echo " V=1 echo the iverilog/vvp command lines"