diff options
Diffstat (limited to 'nandgame')
| -rw-r--r-- | nandgame/Makefile | 116 | ||||
| -rw-r--r-- | nandgame/logic_unit.sv | 32 | ||||
| -rw-r--r-- | nandgame/logic_unit_tb.sv | 58 | ||||
| -rw-r--r-- | nandgame/nandgame_types.v | 6 |
4 files changed, 212 insertions, 0 deletions
diff --git a/nandgame/Makefile b/nandgame/Makefile new file mode 100644 index 0000000..5e16703 --- /dev/null +++ b/nandgame/Makefile @@ -0,0 +1,116 @@ +MAKEFLAGS += --no-builtin-rules +MAKEFLAGS += --no-builtin-variables +.SUFFIXES: + +## Variables +PROGRAM ?= led +CST ?= tangnano9k.cst +FLASH_OPTS ?= +# https://github.com/YosysHQ/apicula/wiki/Nextpnr%E2%80%90Himbaechel-Gowin +# but +# https://github.com/YosysHQ/apicula/wiki/gowin_pack says something different. huh? +DEVICE_NAME ?= GW1NR-LV9QN88PC6/I5 +DEVICE_FAMILY ?= GW1N-9C + +# Can't use this for deps: +# -E $(PROGRAM).deps +# as yosys needs to have -o specified for this to work +# but I specify the command manually +# also, yosys inserts /tmp/ files which makes this useless. +YOSYS_OPTS = -Q -q -l $*.yosys.log -e "conflict|is used but has no driver" +NEXTPNR_OPTS = -q -l $*.pnr.log \ + --sdc clock.sdc \ + --placed-svg $*.plc.svg \ + --routed-svg $*.rt.svg +DEPS := $(wildcard *.dep) + +# this is "bad", as it runs the deps target every time +# probably because of the include below +# SOURCES := $(wildcard *.sv) +# DEPS := $(SOURCES:.sv=.dep) + + +## default target +all: $(PROGRAM).fs + +## dependencies + +tangnano9k.cst: + wget https://github.com/YosysHQ/apicula/raw/refs/heads/master/examples/tangnano9k.cst || \ + curl -LO https://github.com/YosysHQ/apicula/raw/refs/heads/master/examples/tangnano9k.cst + +## helper targets +.PHONY: clean flash show +show: $(PROGRAM).sv + yosys -p "read_verilog -sv $<; prep; show $(PROGRAM)" + +flash: $(PROGRAM).fs + openFPGALoader -b tangnano9k $(FLASH_OPTS) $(PROGRAM).fs + +clean: + rm -rf *.json *.fs *.svg *.log *.dep *.vvp *.lxt2 + +simu: $(PROGRAM).lxt2 + gtkwave $< >/dev/null 2>&1 + +simu2: verilator.$(PROGRAM)/dump.vvp + gtkwave $< >/dev/null 2>&1 + +lint: $(PROGRAM).sv + verilator --quiet --lint-only -Wall -Wno-PROCASSINIT $(PROGRAM).sv + +## Patterns + +# synthesize +%.json: %.sv +# sh resolvedeps.sh $< +# only used for dep-generation, output file is needed for dep file, but otherwise useless +# this must happen *without* synth_gowin, as this includes additional files, which ruin the depfile. + yosys -q $< -E $*.dep -o $@ && rm -f $@ + yosys -p "read_verilog -sv $<; synth_gowin -top $* -json $@" $(YOSYS_OPTS) + +# because yosys -E is buggy, or behaves differently than expected, +# use gawk to force-create deps. +%.dep: %.sv +# sh resolvedeps.sh $< + yosys $< -E $*.dep -o $*.json && rm -f $*.json + +# place and route? +%.pnr.json: %.json $(CST) + nextpnr-himbaechel --json $< --write $@ \ + --device $(DEVICE_NAME) --vopt family=$(DEVICE_FAMILY) \ + --vopt cst=$(CST) \ + $(NEXTPNR_OPTS) \ + || \ + nextpnr-gowin --json $< --write $@ \ + --device $(DEVICE_NAME) --family $(DEVICE_FAMILY) \ + --cst $(CST) \ + $(NEXTPNR_OPTS) + +# pack bitstream +%.fs: %.pnr.json + gowin_pack -d $(DEVICE_FAMILY) -o $@ $< + +### simulation + +%.lxt2: %.vvp + ./$< -lxt2 + +%.vvp: %.sv %_tb.sv + iverilog -DDUMP_FILE_NAME='"$*.lxt2"' -g2012 -o $*.vvp $*.sv $*_tb.sv + +# verilog unfortunately exits on any warning +# also on warnings "boohoo, you specified timings in some modules and not in others" +# since this is fucking annoying, I choose to ignore the exit code. +verilator.%: %.sv %_tb.sv + verilator --quiet -DDUMP_FILE_NAME='"dump.vvp"' --trace --timing --main --exe --Mdir verilator.$(*) $(*)_tb.sv || true + +# need to specify RM for some reason +# verilators makefiles doesn't specify the variable +verilator.%/dump.vvp: verilator.% + $(MAKE) -j4 -C verilator.$(*) -f V$(*).mk RM=rm + cd verilator.$(*) && ./V$(*) + +## inter-file dependencies +-include $(DEPS) +-include $($(wildcard *.fs:.fs=.dep) diff --git a/nandgame/logic_unit.sv b/nandgame/logic_unit.sv new file mode 100644 index 0000000..32b9691 --- /dev/null +++ b/nandgame/logic_unit.sv @@ -0,0 +1,32 @@ +// nandgame logic unit + +`timescale 1us/1us + +`include "nandgame_types.v" + +module logic_unit #( + parameter DATA_WIDTH = 16 +) ( + input [(DATA_WIDTH-1):0] X, + input [(DATA_WIDTH-1):0] Y, + input LogicCode operation, + + output logic [(DATA_WIDTH-1):0] RES +); + +// assign RES = operation == LOGIC_AND ? (X & Y) : +// operation == LOGIC_OR ? (X | Y) : +// operation == LOGIC_XOR ? (X ^ Y) : +// operation == LOGIC_NEGT ? (~X) : 0; + +always_comb begin + case (operation) + LOGIC_AND: RES = X & Y; + LOGIC_OR: RES = X | Y; + LOGIC_XOR: RES = X ^ Y; + LOGIC_NEGT: RES = ~X; + default: RES = 0; + endcase +end + +endmodule diff --git a/nandgame/logic_unit_tb.sv b/nandgame/logic_unit_tb.sv new file mode 100644 index 0000000..c1495c3 --- /dev/null +++ b/nandgame/logic_unit_tb.sv @@ -0,0 +1,58 @@ +`timescale 1us/1us + +`include "nandgame_types.v" + +module logic_unit_tb ( +); + +logic [15:0] in1; +logic [15:0] in2; +LogicCode opcode; +logic [15:0] result; + +logic_unit uut ( + .X(in1), + .Y(in2), + .operation(opcode), + .RES(result) +); + +string filename; +initial begin +`ifdef DUMP_FILE_NAME + filename=`DUMP_FILE_NAME; +`else + filename="logic_unit.lxt2"; +`endif + $dumpfile(filename); $dumpvars(); + +end + +initial begin + in1 = 16'b1010; + in2 = 16'b1100; + opcode = LOGIC_AND; + #1 + assert(result == 16'b1000); + #1 + in1 = 16'b1010; + in2 = 16'b1100; + opcode = LOGIC_OR; + #1 + assert(result == 16'b1110); + #1 + in1 = 16'b1010; + in2 = 16'b1100; + opcode = LOGIC_XOR; + #1 + assert(result == 16'b0110); + #1 + in1 = 16'b1010101010101010; + opcode = LOGIC_NEGT; + #1 + assert(result == 16'b0101010101010101); + #1 + $finish(); +end + +endmodule diff --git a/nandgame/nandgame_types.v b/nandgame/nandgame_types.v new file mode 100644 index 0000000..2104d37 --- /dev/null +++ b/nandgame/nandgame_types.v @@ -0,0 +1,6 @@ +typedef enum logic [1:0] { + LOGIC_AND = 2'b00, + LOGIC_OR = 2'b01, + LOGIC_XOR = 2'b10, + LOGIC_NEGT = 2'b11 +} LogicCode; |
