summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoruvok2026-01-01 15:32:54 +0100
committeruvok2026-01-01 15:32:54 +0100
commit981f86a5b3ea6a05925c807bac26986e0c876dcf (patch)
treed7caeb81fdd8d362ca6e4af79fa4c15e8f67d4dd
parent4792fb03e5d39da03633e71ff4b5375709bfb1d5 (diff)
Add nandgame files
need/want systemverilog
-rw-r--r--nandgame/Makefile116
-rw-r--r--nandgame/logic_unit.sv32
-rw-r--r--nandgame/logic_unit_tb.sv58
-rw-r--r--nandgame/nandgame_types.v6
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;