From 6c83fd8730e55de8b1daaac1deb111d3d9bd408e Mon Sep 17 00:00:00 2001 From: uvok Date: Fri, 9 Jan 2026 15:18:23 +0100 Subject: move stuff around --- Makefile | 122 -------------------------------------- README.txt | 2 +- clkdiv.v | 36 ----------- clock.sdc | 2 - debounce.v | 53 ----------------- debounce_tb.v | 76 ------------------------ fifo.v | 90 ---------------------------- fifo_tb.v | 72 ---------------------- fizzbuzz.v | 20 ------- fizzbuzz_tb.v | 48 --------------- led.v | 31 ---------- led_toggle.v | 32 ---------- led_toggle_bouncy.v | 25 -------- led_toggle_bouncy_tb.v | 50 ---------------- led_toggle_nonwork.v | 26 -------- led_toggle_tb.v | 59 ------------------ my_mem.tb.wtf.v | 119 ------------------------------------- my_mem.v | 49 --------------- my_mem_tb.v | 99 ------------------------------- nandgame/comb_mem.sv | 2 +- nandgame/computer.sv | 2 +- par_to_ser.v | 64 -------------------- par_to_ser_tb.v | 68 --------------------- par_to_ser_to_par_tb.v | 81 ------------------------- playground/Makefile | 122 ++++++++++++++++++++++++++++++++++++++ playground/clkdiv.v | 36 +++++++++++ playground/clock.sdc | 2 + playground/debounce.v | 53 +++++++++++++++++ playground/debounce_tb.v | 76 ++++++++++++++++++++++++ playground/fifo.v | 90 ++++++++++++++++++++++++++++ playground/fifo_tb.v | 72 ++++++++++++++++++++++ playground/fizzbuzz.v | 20 +++++++ playground/fizzbuzz_tb.v | 48 +++++++++++++++ playground/led.v | 31 ++++++++++ playground/led_toggle.v | 32 ++++++++++ playground/led_toggle_bouncy.v | 25 ++++++++ playground/led_toggle_bouncy_tb.v | 50 ++++++++++++++++ playground/led_toggle_nonwork.v | 26 ++++++++ playground/led_toggle_tb.v | 59 ++++++++++++++++++ playground/my_mem.tb.wtf.v | 119 +++++++++++++++++++++++++++++++++++++ playground/my_mem.v | 49 +++++++++++++++ playground/my_mem_tb.v | 99 +++++++++++++++++++++++++++++++ playground/par_to_ser.v | 64 ++++++++++++++++++++ playground/par_to_ser_tb.v | 68 +++++++++++++++++++++ playground/par_to_ser_to_par_tb.v | 81 +++++++++++++++++++++++++ playground/ser_to_par.v | 39 ++++++++++++ playground/ser_to_par_tb.v | 62 +++++++++++++++++++ playground/template.v | 14 +++++ playground/template_tb.v | 36 +++++++++++ playground/tst_delay.v | 17 ++++++ playground/tst_delay_tb.v | 53 +++++++++++++++++ ser_to_par.v | 39 ------------ ser_to_par_tb.v | 62 ------------------- template.v | 14 ----- template_tb.v | 36 ----------- tst_delay.v | 17 ------ tst_delay_tb.v | 53 ----------------- 57 files changed, 1446 insertions(+), 1446 deletions(-) delete mode 100644 Makefile delete mode 100644 clkdiv.v delete mode 100644 clock.sdc delete mode 100644 debounce.v delete mode 100644 debounce_tb.v delete mode 100644 fifo.v delete mode 100644 fifo_tb.v delete mode 100644 fizzbuzz.v delete mode 100644 fizzbuzz_tb.v delete mode 100644 led.v delete mode 100644 led_toggle.v delete mode 100644 led_toggle_bouncy.v delete mode 100644 led_toggle_bouncy_tb.v delete mode 100644 led_toggle_nonwork.v delete mode 100644 led_toggle_tb.v delete mode 100644 my_mem.tb.wtf.v delete mode 100644 my_mem.v delete mode 100644 my_mem_tb.v delete mode 100644 par_to_ser.v delete mode 100644 par_to_ser_tb.v delete mode 100644 par_to_ser_to_par_tb.v create mode 100644 playground/Makefile create mode 100644 playground/clkdiv.v create mode 100644 playground/clock.sdc create mode 100644 playground/debounce.v create mode 100644 playground/debounce_tb.v create mode 100644 playground/fifo.v create mode 100644 playground/fifo_tb.v create mode 100644 playground/fizzbuzz.v create mode 100644 playground/fizzbuzz_tb.v create mode 100644 playground/led.v create mode 100644 playground/led_toggle.v create mode 100644 playground/led_toggle_bouncy.v create mode 100644 playground/led_toggle_bouncy_tb.v create mode 100644 playground/led_toggle_nonwork.v create mode 100644 playground/led_toggle_tb.v create mode 100644 playground/my_mem.tb.wtf.v create mode 100644 playground/my_mem.v create mode 100644 playground/my_mem_tb.v create mode 100644 playground/par_to_ser.v create mode 100644 playground/par_to_ser_tb.v create mode 100644 playground/par_to_ser_to_par_tb.v create mode 100644 playground/ser_to_par.v create mode 100644 playground/ser_to_par_tb.v create mode 100644 playground/template.v create mode 100644 playground/template_tb.v create mode 100644 playground/tst_delay.v create mode 100644 playground/tst_delay_tb.v delete mode 100644 ser_to_par.v delete mode 100644 ser_to_par_tb.v delete mode 100644 template.v delete mode 100644 template_tb.v delete mode 100644 tst_delay.v delete mode 100644 tst_delay_tb.v diff --git a/Makefile b/Makefile deleted file mode 100644 index 0ed197e..0000000 --- a/Makefile +++ /dev/null @@ -1,122 +0,0 @@ -MAKEFLAGS += --no-builtin-rules -MAKEFLAGS += --no-builtin-variables -.SUFFIXES: - -## Variables -PROGRAM ?= led -CST ?= tangnano9k.cst - -HARDWARE_SUFFIX := .v -TESTBENCH_SUFFIX := _tb.v - -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 *$(HARDWARE_SUFFIX)) -# DEPS := $(SOURCES:$(HARDWARE_SUFFIX)=.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)$(HARDWARE_SUFFIX) - yosys -p "read_verilog $<; 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)$(HARDWARE_SUFFIX) - verilator --quiet --lint-only -Wall -Wno-PROCASSINIT $(PROGRAM)$(HARDWARE_SUFFIX) - -## Patterns - -# synthesize -%.json: %$(HARDWARE_SUFFIX) -# 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 $<; synth_gowin -top $* -json $@" $(YOSYS_OPTS) - -# because yosys -E is buggy, or behaves differently than expected, -# use gawk to force-create deps. -%.dep: %$(HARDWARE_SUFFIX) -# 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: %$(HARDWARE_SUFFIX) %$(TESTBENCH_SUFFIX) - iverilog -DDUMP_FILE_NAME='"$*.lxt2"' -g2012 -o $*.vvp $*$(HARDWARE_SUFFIX) $*$(TESTBENCH_SUFFIX) - -# 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.%: %$(HARDWARE_SUFFIX) %$(TESTBENCH_SUFFIX) - verilator --quiet -DDUMP_FILE_NAME='"dump.vvp"' --trace --timing --main --exe --Mdir verilator.$(*) $(*)$(TESTBENCH_SUFFIX) || true - -# need to specify RM for some reason -# verilators makefiles doesn't specify the variable -verilator.%/dump.vvp: verilator.% -# for whatever reason, some version of vlor started to append _tb. - ($(MAKE) -j4 -C verilator.$(*) -f V$(*).mk RM=rm || \ - $(MAKE) -j4 -C verilator.$(*) -f V$(*)_tb.mk RM=rm) - cd verilator.$(*) && (./V$(*) || ./V$(*)_tb) - -## inter-file dependencies --include $(DEPS) --include $($(wildcard *.fs:.fs=.dep) diff --git a/README.txt b/README.txt index 0865867..f040223 100644 --- a/README.txt +++ b/README.txt @@ -2,7 +2,7 @@ This is a collection of Verilog files. Written as I'm learning about the language and FPGAs. Contents: -- This directory +- playground: various stuff - nandgame: Implementation of the nandgame.com CPU Learnings: diff --git a/clkdiv.v b/clkdiv.v deleted file mode 100644 index b6f1419..0000000 --- a/clkdiv.v +++ /dev/null @@ -1,36 +0,0 @@ -`timescale 1us/1us - -module clkdiv ( - input rst_i, - input clk, // clk input - output reg o_divclk // divided output (must be a reg, b/c it needs to keep state) -); - -reg [23:0] counter; -// CLK is 27 MHz -// we want a 2Hz signal at the output -// and pin needs to *toggle twice* within one period -// 27MHz / 4 = 6750000 -localparam DIVISOR = 24'd6_749_999; - -always @(posedge clk or negedge rst_i) begin - if (!rst_i) - counter <= 24'd0; - else if (counter < DIVISOR) - counter <= counter + 1'b1; - else - counter <= 24'd0; -end - -always @(posedge clk or negedge rst_i) begin - if (!rst_i) - o_divclk <= 1'b0; - else if (counter == DIVISOR) - o_divclk <= ~o_divclk; - else - o_divclk <= o_divclk; -end - - -endmodule - diff --git a/clock.sdc b/clock.sdc deleted file mode 100644 index 5e64ad9..0000000 --- a/clock.sdc +++ /dev/null @@ -1,2 +0,0 @@ -create_clock -period 40.00 -name {clk} [get_ports {clk}] -create_clock -period 40.00 -name {clk_i} [get_ports {clk_i}] diff --git a/debounce.v b/debounce.v deleted file mode 100644 index 33dc22e..0000000 --- a/debounce.v +++ /dev/null @@ -1,53 +0,0 @@ -`timescale 1us/1us - -module debounce ( - input rst_i, - input clk_i, - input signal_i, - output reg signal_o -); - -// number of rising clock edges a signal needs to be stable -// for it to be output. -// (+1 for propagation). -parameter STABLE_PERIOD = 50; -parameter INIT_SIG_STATE = 1'b1; - -reg [31:0] clk_counter; -reg prev_state; - -always @(posedge clk_i or negedge rst_i) begin - if (!rst_i) begin - // Learning: I would like to set the output to the input on reset - // but then I get - // Warning: Async reset value `\signal_i' is not constant! - // and a synthesis error. - clk_counter <= 0; - prev_state <= INIT_SIG_STATE; - signal_o <= INIT_SIG_STATE; - end else begin - - if (signal_i != prev_state) begin - clk_counter <= 0; - prev_state <= signal_i; - end else begin - clk_counter <= clk_counter + 1; - end - - if (clk_counter === STABLE_PERIOD) begin - signal_o <= signal_i; - end - end -end - -// Learning? -// Apparently, (and obviously, when you think about it), -// it's not possible to drive a signal by two blocks -// always @(signal_i) begin -// if (signal_i != prev_state) begin -// clk_counter <= 0; -// prev_state <= signal_i; -// end -// end - -endmodule diff --git a/debounce_tb.v b/debounce_tb.v deleted file mode 100644 index fb9430c..0000000 --- a/debounce_tb.v +++ /dev/null @@ -1,76 +0,0 @@ -`timescale 1us/1us - -module debounce_tb; - -logic rst_i; -logic clk_i; -logic signal_i; -logic signal_o; - -integer i = 0; - -debounce #(.STABLE_PERIOD(5)) uut ( - .rst_i(rst_i), - .clk_i(clk_i), - .signal_i(signal_i), - .signal_o(signal_o) -); - -string filename; -initial begin -`ifdef DUMP_FILE_NAME - filename=`DUMP_FILE_NAME; -`else - filename="debounce.lxt2"; -`endif - $dumpfile(filename); $dumpvars(); - - clk_i = 0; - rst_i = 1'b1; - signal_i = 1'b1; - #1 - rst_i = 1'b0; - #1 - rst_i = 1'b1; -end - -always #10 clk_i = ~clk_i; - -initial begin - // initial key press - @(negedge clk_i); - signal_i = ~signal_i; - assert (signal_o == 1'b1); - - repeat(2) @(negedge clk_i); - - signal_i = ~signal_i; - assert (signal_o == 1'b1); - - // try bouncing - - repeat(2) @(negedge clk_i); - - for (i=0; i < 20; i = i + 1) begin - @(negedge clk_i); - signal_i = ~signal_i; - assert (signal_o == 1'b1); - end - @(negedge clk_i); - signal_i = ~signal_i; - assert (signal_o == 1'b1); - - repeat(10) @(negedge clk_i); - assert (signal_o == 1'b0); - - repeat(10) @(negedge clk_i); - signal_i = ~signal_i; - - repeat(10) @(negedge clk_i); - assert (signal_o == 1'b1); - - repeat(10) @(negedge clk_i); - $finish(); -end - -endmodule diff --git a/fifo.v b/fifo.v deleted file mode 100644 index bcc2d3f..0000000 --- a/fifo.v +++ /dev/null @@ -1,90 +0,0 @@ -`timescale 1us/1us - -`include "my_mem.v" - -module fifo #( - parameter DATA_WIDTH = 8, - parameter DATA_DEPTH = 1024 -) ( - input rst_i, - input clk_i, - - input write_i, - input read_i, - - output empty_o, - output full_o, - - //output data_valid_o, - - input [(DATA_WIDTH-1) : 0] data_i, - output reg [(DATA_WIDTH-1) : 0] data_o - -); - -localparam DATA_DEPTH_BITS = $clog2(DATA_DEPTH); - -// the -1 will make sure it fits -/* verilator lint_off WIDTHTRUNC */ -localparam [DATA_DEPTH_BITS-1:0] MAX_ADDRESS = (DATA_DEPTH - 1); -/* verilator lint_on WIDTHTRUNC */ - -// need to "count" to number *including* depth -reg [$clog2(DATA_DEPTH + 1)-1:0] r_count; -reg [DATA_DEPTH_BITS-1:0] r_read_addr; -reg [DATA_DEPTH_BITS-1:0] r_write_addr; - -assign empty_o = r_count == 0; -assign full_o = r_count == DATA_DEPTH; - -wire int_wr_en = write_i && !full_o; -wire int_rd_en = read_i && !empty_o; - -my_mem #( - .DATA_WIDTH(DATA_WIDTH), - .DATA_DEPTH(DATA_DEPTH) -) fifo_mem ( - .clk_i(clk_i), - .write_en_i(int_wr_en), - .read_en_i(int_rd_en), - .r_read_addr(r_read_addr), - .r_write_addr(r_write_addr), - - .data_i(data_i), - .data_o(data_o) -); - -initial begin - r_count = 0; - r_read_addr = 0; - r_write_addr = 0; -end - -always @(posedge clk_i or negedge rst_i) begin - if (!rst_i) - r_count <= 0; - else if (write_i && read_i) - // nothing to do - // count stays the same - ; - else if (write_i && !full_o) - r_count <= r_count + 1; - else if (read_i && !empty_o) - r_count <= r_count - 1; -end - -always @(posedge clk_i or negedge rst_i) begin - if (!rst_i) - r_read_addr <= 0; - else if (read_i && !empty_o) - r_read_addr <= (r_read_addr < MAX_ADDRESS) ? (r_read_addr + 1) : 0; -end - -always @(posedge clk_i or negedge rst_i) begin - if (!rst_i) - r_write_addr <= 0; - else if (write_i && !full_o) - r_write_addr <= (r_write_addr < MAX_ADDRESS) ? (r_write_addr + 1) : 0; -end - -endmodule diff --git a/fifo_tb.v b/fifo_tb.v deleted file mode 100644 index 38199a6..0000000 --- a/fifo_tb.v +++ /dev/null @@ -1,72 +0,0 @@ -`timescale 1us/1us - -module fifo_tb; - -reg clk_i; -reg rst_i; - -reg read_i, write_i; -reg [7:0] data_i; - -fifo #( - .DATA_WIDTH(8), - .DATA_DEPTH(8) -) uut ( - .clk_i(clk_i), - .rst_i(rst_i), - .write_i(write_i), - .read_i(read_i), - .data_i(data_i), - - .empty_o(), - .full_o(), - .data_o() -); - -string filename; -initial begin -`ifdef DUMP_FILE_NAME - filename=`DUMP_FILE_NAME; -`else - filename="fifo.lxt2"; -`endif - $dumpfile(filename); $dumpvars(); - clk_i = 0; - rst_i = 1'b1; - read_i = 0; - write_i = 0; - data_i = 0; -end - -always #10 clk_i = ~clk_i; - -initial begin - #15 - - for (integer run = 1; run < 3; run++) begin - - write_i = 1; - for (integer addr = 0; addr < 10; addr++) begin - - data_i = (run << 4) | addr; - #20 - ; - end - - write_i = 0; - read_i = 1; - - for (integer addr = 0; addr < 10; addr++) begin - #20 - ; - end - - read_i = 0; - #20 - ; - end - #100 - $finish(); -end - -endmodule diff --git a/fizzbuzz.v b/fizzbuzz.v deleted file mode 100644 index 0e34c58..0000000 --- a/fizzbuzz.v +++ /dev/null @@ -1,20 +0,0 @@ -`timescale 1us/1us - -module fizzbuzz ( - input [7:0] num_i, - output [7:0] num_o, - output fizz_o, - output buzz_o, - output fizzbuzz_o -); - -wire is_fizz, is_buzz; -assign is_fizz = num_i % 3 == 0; -assign is_buzz = num_i % 5 == 0; - -assign fizz_o = is_fizz && !is_buzz; -assign buzz_o = !is_fizz && is_buzz; -assign fizzbuzz_o = is_fizz && is_buzz; -assign num_o = (is_fizz || is_buzz) ? 0 : num_i; - -endmodule diff --git a/fizzbuzz_tb.v b/fizzbuzz_tb.v deleted file mode 100644 index 4d612ec..0000000 --- a/fizzbuzz_tb.v +++ /dev/null @@ -1,48 +0,0 @@ -`timescale 1us/1us - -module fizzbuzz_tb; - - -logic [7:0] number; -logic clk_i; - -logic [7:0] num_out; - -fizzbuzz uut ( - .num_i(number), - .num_o(num_out), - .fizz_o(), - .buzz_o(), - .fizzbuzz_o() -); - -string filename; -initial begin -`ifdef DUMP_FILE_NAME - filename=`DUMP_FILE_NAME; -`else - filename="fizzbuzz.lxt2"; -`endif - $dumpfile(filename); $dumpvars(); - - - clk_i = 0; - number = '0; -end - -always #10 begin - clk_i = ~clk_i; -end - -always @(negedge clk_i) begin - number <= number + 1; - // give iverilog some simulation time... - #1; - if (number == 3) assert(num_out == 0); - if (number == 5) assert(num_out == 0); - if (number == 15) assert(num_out == 0); - - if (number == 255) $finish; -end - -endmodule diff --git a/led.v b/led.v deleted file mode 100644 index e4f4281..0000000 --- a/led.v +++ /dev/null @@ -1,31 +0,0 @@ -`timescale 1us/1us - -`include "clkdiv.v" - -module led ( - input clk, // clk input - input rst_i, // reset input - output reg [5:0] led_o // 6 LEDS pin -); - -reg half_sec_clock; - -clkdiv half_sec_divider( - .rst_i(rst_i), - .clk(clk), - .o_divclk(half_sec_clock) -); - -always @(posedge half_sec_clock or negedge rst_i) begin - if (!rst_i) - led_o <= 6'b111111; - else -// else if (counter == 24'd1349_9999) // 0.5s delay - led_o[5:0] <= led_o[5:0] - 1; -// else -// led_o <= led_o; -end - - -endmodule - diff --git a/led_toggle.v b/led_toggle.v deleted file mode 100644 index 3c54ee4..0000000 --- a/led_toggle.v +++ /dev/null @@ -1,32 +0,0 @@ -`timescale 1us/1us - -// From the book -// bouncy variant - -`include "led_toggle_bouncy.v" -`include "debounce.v" - -module led_toggle ( - input rst_i, - input clk_i, - input key_i, - output [5:0] led -); -parameter STABLE_PERIOD = 50; - -wire outsig; - -debounce #(.STABLE_PERIOD(STABLE_PERIOD)) db( - .rst_i(rst_i), - .clk_i(clk_i), - .signal_i(key_i), - .signal_o(outsig) -); - -led_toggle_bouncy tgler( - .clk_i(clk_i), - .key_i(outsig), - .led(led) -); - -endmodule diff --git a/led_toggle_bouncy.v b/led_toggle_bouncy.v deleted file mode 100644 index b05b472..0000000 --- a/led_toggle_bouncy.v +++ /dev/null @@ -1,25 +0,0 @@ -`timescale 1us/1us - -// From the book -// bouncy variant - -module led_toggle_bouncy ( - input clk_i, - input key_i, - output [5:0] led -); - -reg r_LED_1 = 1'b1; -reg r_Switch_1 = 1'b1; - -always @(posedge clk_i) begin - r_Switch_1 <= key_i; - if (key_i == 1'b1 && r_Switch_1 == 1'b0) begin - r_LED_1 <= ~r_LED_1; - end -end - -assign led[0] = r_LED_1; -assign led[5:1] = 5'b11111; - -endmodule diff --git a/led_toggle_bouncy_tb.v b/led_toggle_bouncy_tb.v deleted file mode 100644 index 2c04484..0000000 --- a/led_toggle_bouncy_tb.v +++ /dev/null @@ -1,50 +0,0 @@ -`timescale 1us/1us - -module led_toggle_bouncy_tb; - -logic clk_i; -logic key_i; -logic [5:0] led; - -led_toggle_bouncy uut ( - .clk_i(clk_i), - .key_i(key_i), - .led(led) -); - -string filename; -initial begin -`ifdef DUMP_FILE_NAME - filename=`DUMP_FILE_NAME; -`else - filename="led_toggle_bouncy.lxt2"; -`endif - $dumpfile(filename); $dumpvars(); - - clk_i = 0; - key_i = 1'b1; -end - -always #10 clk_i = ~clk_i; - -initial begin - // initial key press - @(negedge clk_i); - key_i = ~key_i; - repeat(2) @(negedge clk_i); - key_i = ~key_i; - - // try bouncing - - repeat(2) @(negedge clk_i); - - for (integer i=0; i < 20; i = i + 1) begin - @(negedge clk_i); - key_i = ~key_i; - end - - repeat(5) @(negedge clk_i); - $finish(); -end - -endmodule diff --git a/led_toggle_nonwork.v b/led_toggle_nonwork.v deleted file mode 100644 index 5fe458f..0000000 --- a/led_toggle_nonwork.v +++ /dev/null @@ -1,26 +0,0 @@ -`timescale 1us/1us - -// -// NON-WORKING -// LED toggle example -// probably because LED is controlled by two blocks -// - -module led_toggle_nonwork( - input clk_i, - input key_i, - input rst_i, - output reg [5:0] led -); - -always @(negedge rst_i) begin - if (!rst_i) - led <= 6'b111111; -end - -always @(negedge key_i) begin - if (!key_i) - led[0] <= ~led[0]; -end - -endmodule diff --git a/led_toggle_tb.v b/led_toggle_tb.v deleted file mode 100644 index 78d4f21..0000000 --- a/led_toggle_tb.v +++ /dev/null @@ -1,59 +0,0 @@ -`timescale 1us/1us - -module led_toggle_tb; - -logic clk_i; -logic rst_i; -logic key_i; - -logic [5:0] led; - -led_toggle #(.STABLE_PERIOD(2)) uut ( - .rst_i(rst_i), - .clk_i(clk_i), - .key_i(key_i), - .led(led) -); - -string filename; -initial begin -`ifdef DUMP_FILE_NAME - filename=`DUMP_FILE_NAME; -`else - filename="led_toggle.lxt2"; -`endif - $dumpfile(filename); $dumpvars(); - clk_i = 0; - key_i = 1'b1; - #1 - rst_i = 0; - #1 - rst_i = 1; -end - -always #10 clk_i = ~clk_i; - - -initial begin - // initial key press - #13 - key_i = ~key_i; - repeat(2) @(negedge clk_i); - key_i = ~key_i; - - // try bouncing - - repeat(3) @(negedge clk_i); - - for (integer i=0; i < 19; i = i + 1) begin - @(negedge clk_i); - key_i = ~key_i; - end - repeat(10) @(negedge clk_i); - key_i = ~key_i; - - repeat(10) @(negedge clk_i); - $finish(); -end - -endmodule diff --git a/my_mem.tb.wtf.v b/my_mem.tb.wtf.v deleted file mode 100644 index 8b1aed6..0000000 --- a/my_mem.tb.wtf.v +++ /dev/null @@ -1,119 +0,0 @@ -// LLM generated, because I'm too lazy to do this manually - -`timescale 1us/1ns - -module my_mem_tb(); - - localparam DATA_WIDTH = 8; - localparam DATA_DEPTH = 16; - localparam ADDR_WIDTH = $clog2(DATA_DEPTH); - - // DUT signals - logic clk; - logic write_en_i; - logic read_en_i; - logic [ADDR_WIDTH-1:0] r_read_addr; - logic [ADDR_WIDTH-1:0] r_write_addr; - logic [DATA_WIDTH-1:0] data_i; - logic [DATA_WIDTH-1:0] data_o; - - // Instantiate DUT - my_mem #( - .DATA_WIDTH(DATA_WIDTH), - .DATA_DEPTH(DATA_DEPTH) - ) dut ( - .clk_i(clk), - .write_en_i(write_en_i), - .read_en_i(read_en_i), - .r_read_addr(r_read_addr), - .r_write_addr(r_write_addr), - .data_i(data_i), - .data_o(data_o) - ); - - string filename; - initial begin - `ifdef DUMP_FILE_NAME - filename=`DUMP_FILE_NAME; - `else - filename="my_mem.lxt2"; - `endif - $dumpfile(filename); $dumpvars(); - end - - // Clock generator - always #10 clk = ~clk; - - // Test sequence - initial begin - clk = 0; - write_en_i = 0; - read_en_i = 0; - r_read_addr = '0; - r_write_addr = '0; - data_i = '0; - - repeat (3) @(posedge clk); - - // ------------------------- - // Write some values - // ------------------------- - @(posedge clk); - @(posedge clk); - write_en_i = 1; - r_write_addr = 10; - data_i = 8'hA5; - - @(posedge clk); - r_write_addr = 11; - data_i = 8'h3C; - - @(posedge clk); - write_en_i = 0; - - // ------------------------- - // Read back values - // ------------------------- - - // asserts fail in iverilog if I use the posedge stuff, - // (but works in verilator). - // need an additional clock cycle delay. - - @(posedge clk); - @(posedge clk); - @(posedge clk); - @(posedge clk); - read_en_i = 1; - r_read_addr = 10; - - @(posedge clk); - @(posedge clk); - @(posedge clk); - @(posedge clk); - assert (data_o == 8'hA5) - else $error("ASSERTION FAILED: addr 10 expected 0xA5, got 0x%02h", data_o); - - @(posedge clk); - @(posedge clk); - @(posedge clk); - @(posedge clk); - r_read_addr = 11; - - @(posedge clk); - @(posedge clk); - @(posedge clk); - @(posedge clk); - assert (data_o == 8'h3C) - else $error("ASSERTION FAILED: addr 11 expected 0x3C, got 0x%02h", data_o); - - @(posedge clk); - @(posedge clk); - @(posedge clk); - @(posedge clk); - read_en_i = 0; - - repeat (3) @(posedge clk); - $finish; - end - -endmodule diff --git a/my_mem.v b/my_mem.v deleted file mode 100644 index 1153ec7..0000000 --- a/my_mem.v +++ /dev/null @@ -1,49 +0,0 @@ -`timescale 1us/1us - -`ifndef UVOK_MEMORY -`define UVOK_MEMORY - -module my_mem #( - parameter DATA_WIDTH = 8, - parameter DATA_DEPTH = 1024 -) ( - input clk_i, - - input write_en_i, - input read_en_i, - - input [$clog2(DATA_DEPTH)-1:0] r_read_addr, - input [$clog2(DATA_DEPTH)-1:0] r_write_addr, - - input [(DATA_WIDTH-1) : 0] data_i, - output reg [(DATA_WIDTH-1) : 0] data_o -); - -reg [(DATA_WIDTH-1) : 0] r_datastore [(DATA_DEPTH-1) : 0] /* verilator public */; - -`ifdef DEBUG -// for debugging simulations, as iverilog -// does't show r_datastore -reg [(DATA_WIDTH-1) : 0] r_cur_r_val; -reg [(DATA_WIDTH-1) : 0] r_cur_w_val; -`endif - -always @(posedge clk_i) begin - if (write_en_i) begin - r_datastore[r_write_addr] <= data_i; -`ifdef DEBUG - r_cur_w_val <= data_i; -`endif - end - - if (read_en_i) begin - data_o <= r_datastore[r_read_addr]; -`ifdef DEBUG - r_cur_r_val <= r_datastore[r_read_addr]; -`endif - end -end - -endmodule - -`endif diff --git a/my_mem_tb.v b/my_mem_tb.v deleted file mode 100644 index c8c2e12..0000000 --- a/my_mem_tb.v +++ /dev/null @@ -1,99 +0,0 @@ -// LLM generated, because I'm too lazy to do this manually - -`timescale 1us/1ns - -module my_mem_tb(); - - localparam DATA_WIDTH = 8; - localparam DATA_DEPTH = 16; - localparam ADDR_WIDTH = $clog2(DATA_DEPTH); - - // DUT signals - logic clk; - logic write_en_i; - logic read_en_i; - logic [ADDR_WIDTH-1:0] r_read_addr; - logic [ADDR_WIDTH-1:0] r_write_addr; - logic [DATA_WIDTH-1:0] data_i; - logic [DATA_WIDTH-1:0] data_o; - - // Instantiate DUT - my_mem #( - .DATA_WIDTH(DATA_WIDTH), - .DATA_DEPTH(DATA_DEPTH) - ) dut ( - .clk_i(clk), - .write_en_i(write_en_i), - .read_en_i(read_en_i), - .r_read_addr(r_read_addr), - .r_write_addr(r_write_addr), - .data_i(data_i), - .data_o(data_o) - ); - - string filename; - initial begin - `ifdef DUMP_FILE_NAME - filename=`DUMP_FILE_NAME; - `else - filename="my_mem.lxt2"; - `endif - $dumpfile(filename); $dumpvars(); - end - - // Clock generator - always #10 clk = ~clk; - - // Test sequence - initial begin - clk = 0; - write_en_i = 0; - read_en_i = 0; - r_read_addr = '0; - r_write_addr = '0; - data_i = '0; - - repeat (3) @(negedge clk); - - // ------------------------- - // Write some values - // ------------------------- - @(negedge clk); - write_en_i = 1; - r_write_addr = 10; - data_i = 8'hA5; - - @(negedge clk); - r_write_addr = 11; - data_i = 8'h3C; - - @(negedge clk); - write_en_i = 0; - - // ------------------------- - // Read back values - // ------------------------- - - @(negedge clk); - read_en_i = 1; - r_read_addr = 10; - - @(negedge clk); - assert (data_o == 8'hA5) - else $error("ASSERTION FAILED: addr 10 expected 0xA5, got 0x%02h", data_o); - - @(negedge clk); - r_read_addr = 11; - - @(negedge clk); - assert (data_o == 8'h3C) - else $error("ASSERTION FAILED: addr 11 expected 0x3C, got 0x%02h", data_o); - - @(negedge clk); - read_en_i = 0; - - repeat (3) @(negedge clk); - $finish; - end - -endmodule diff --git a/nandgame/comb_mem.sv b/nandgame/comb_mem.sv index fb87364..766552c 100644 --- a/nandgame/comb_mem.sv +++ b/nandgame/comb_mem.sv @@ -4,7 +4,7 @@ `timescale 1us/1us -`include "../my_mem.v" +`include "../playground/my_mem.v" `ifndef COMB_MEM `define COMB_MEM diff --git a/nandgame/computer.sv b/nandgame/computer.sv index 5f33698..b706d7f 100644 --- a/nandgame/computer.sv +++ b/nandgame/computer.sv @@ -2,7 +2,7 @@ `timescale 1us/1us -`include "../my_mem.v" +`include "../playground/my_mem.v" `include "comb_mem.sv" `include "instruction_decode.sv" `include "counter.sv" diff --git a/par_to_ser.v b/par_to_ser.v deleted file mode 100644 index ab754c9..0000000 --- a/par_to_ser.v +++ /dev/null @@ -1,64 +0,0 @@ -`timescale 1us/1us - -// parallel to serial converter - -module par_to_ser #( - parameter SHIFT_WIDTH = 8 -) ( - input rst_i, - input clk_i, - input data_valid_i, - input [(SHIFT_WIDTH-1):0] dat_i, - output reg dat_o, - output dat_valid_o -); - -// Learning: can't declate parameter here -// if I want to use it in the input/output list. -// parameter SHIFT_WIDTH = 8; - -reg [(SHIFT_WIDTH-1):0] send_data = {SHIFT_WIDTH{1'b1}}; -// want to count to number *including* width, add 1 -reg [$clog2(SHIFT_WIDTH + 1) - 1:0] count = 0; - -// yes, smaller than, the count *to* 8 still takes place -wire counting = (count != 0) && (count < SHIFT_WIDTH); -// sending is one byte longer -wire sending = (count != 0) && (count <= SHIFT_WIDTH); - -always @(posedge clk_i or negedge rst_i) begin - if (!rst_i) begin - dat_o <= 1'b1; - end else if (data_valid_i && count == 0) begin - dat_o <= dat_i[0]; - end else if (sending) begin - dat_o <= send_data[0]; - end -end - -always @(posedge clk_i or negedge rst_i) begin - if (!rst_i) begin - send_data <= {SHIFT_WIDTH{1'b1}}; - end else if (data_valid_i && count == 0) begin - send_data <= {1'b1, dat_i[(SHIFT_WIDTH-1):1]}; - end else if (sending) begin - // arbitrary decision: register is filled with a 1 - send_data <= {1'b1, send_data[(SHIFT_WIDTH-1):1]}; - end -end - -always @(posedge clk_i or negedge rst_i) begin - if (!rst_i) begin - count <= 0; - end else if (data_valid_i && count == 0) begin - count <= 1; - end else if (counting) begin - count <= count + 1; - end else begin - count <= 0; - end -end - -assign dat_valid_o = sending; - -endmodule diff --git a/par_to_ser_tb.v b/par_to_ser_tb.v deleted file mode 100644 index a30e282..0000000 --- a/par_to_ser_tb.v +++ /dev/null @@ -1,68 +0,0 @@ -`timescale 1us/1us - -module par_to_ser_tb; - -logic clk_i; -logic rst_i; -logic data_valid_i; -logic [7:0] dat_i; -logic dat_o; - -par_to_ser uut ( - .clk_i(clk_i), - .rst_i(rst_i), - .data_valid_i(data_valid_i), - .dat_i(dat_i), - .dat_o(dat_o), - .dat_valid_o() -); - -string filename; -initial begin -`ifdef DUMP_FILE_NAME - filename=`DUMP_FILE_NAME; -`else - filename="par_to_ser.lxt2"; -`endif - $dumpfile(filename); $dumpvars(); - clk_i = 0; - rst_i = 1'b1; - data_valid_i = 1'b0; - - #1 - rst_i = 1'b0; - #1 - rst_i = 1'b1; -end - -always #10 clk_i = ~clk_i; - -bit sollbit = 1'b0; - -initial begin - #13 - @(negedge clk_i); - - for (integer i = 0; i < 255; i++) begin - // clock data in - dat_i = i; - data_valid_i = 1'b1; - - @(negedge clk_i); - data_valid_i = 1'b0; - - for (integer j = 0; j < 8; j++) begin - sollbit = (i >> j) & 1; - assert(dat_o == sollbit) - else $error("Expected bit to be %d, but was %d", sollbit, dat_o); - - @(negedge clk_i); - end - - repeat(2) @(negedge clk_i); - end - - $finish(); -end - -endmodule diff --git a/par_to_ser_to_par_tb.v b/par_to_ser_to_par_tb.v deleted file mode 100644 index 9a4a3eb..0000000 --- a/par_to_ser_to_par_tb.v +++ /dev/null @@ -1,81 +0,0 @@ -// converts back and forth -// parallel > serial > parallel - -`timescale 1us/1us - -module par_to_ser_to_par_tb; - -logic clk_i; -logic rst_i; -logic data_valid_i; -logic [7:0] dat_i; - -logic dat_o; -logic [7:0] dat_o2; -logic send_valid; - -par_to_ser uut ( - .clk_i(clk_i), - .rst_i(rst_i), - .data_valid_i(data_valid_i), - .dat_i(dat_i), - .dat_o(dat_o), - .dat_valid_o(send_valid) -); - -ser_to_par uut2 ( - .clk_i(clk_i), - .rst_i(rst_i), - - .dat_valid_i(send_valid), - .dat_i(dat_o), - - .dat_o(dat_o2), - .dat_valid_o() -); - -string filename; -initial begin -`ifdef DUMP_FILE_NAME - filename=`DUMP_FILE_NAME; -`else - filename="par_to_ser_to_par.lxt2"; -`endif - $dumpfile(filename); $dumpvars(); - clk_i = 0; - rst_i = 1'b1; - data_valid_i = 1'b0; - - #1 - rst_i = 1'b0; - #1 - rst_i = 1'b1; -end - -always #10 clk_i = ~clk_i; - -initial begin - #13; - @(negedge clk_i); - - for (integer i = 0; i < 255; i++) begin - // clock data in - dat_i = i; - data_valid_i = 1'b1; - - // wait 1 cycle - @(negedge clk_i); - data_valid_i = 1'b0; - - // let module do its work - repeat(10) @(negedge clk_i); - - assert(i == dat_o2) - else $error("Expected output to be h%x, but was h%x", i, dat_o2); - - end - - $finish(); -end - -endmodule diff --git a/playground/Makefile b/playground/Makefile new file mode 100644 index 0000000..0ed197e --- /dev/null +++ b/playground/Makefile @@ -0,0 +1,122 @@ +MAKEFLAGS += --no-builtin-rules +MAKEFLAGS += --no-builtin-variables +.SUFFIXES: + +## Variables +PROGRAM ?= led +CST ?= tangnano9k.cst + +HARDWARE_SUFFIX := .v +TESTBENCH_SUFFIX := _tb.v + +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 *$(HARDWARE_SUFFIX)) +# DEPS := $(SOURCES:$(HARDWARE_SUFFIX)=.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)$(HARDWARE_SUFFIX) + yosys -p "read_verilog $<; 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)$(HARDWARE_SUFFIX) + verilator --quiet --lint-only -Wall -Wno-PROCASSINIT $(PROGRAM)$(HARDWARE_SUFFIX) + +## Patterns + +# synthesize +%.json: %$(HARDWARE_SUFFIX) +# 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 $<; synth_gowin -top $* -json $@" $(YOSYS_OPTS) + +# because yosys -E is buggy, or behaves differently than expected, +# use gawk to force-create deps. +%.dep: %$(HARDWARE_SUFFIX) +# 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: %$(HARDWARE_SUFFIX) %$(TESTBENCH_SUFFIX) + iverilog -DDUMP_FILE_NAME='"$*.lxt2"' -g2012 -o $*.vvp $*$(HARDWARE_SUFFIX) $*$(TESTBENCH_SUFFIX) + +# 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.%: %$(HARDWARE_SUFFIX) %$(TESTBENCH_SUFFIX) + verilator --quiet -DDUMP_FILE_NAME='"dump.vvp"' --trace --timing --main --exe --Mdir verilator.$(*) $(*)$(TESTBENCH_SUFFIX) || true + +# need to specify RM for some reason +# verilators makefiles doesn't specify the variable +verilator.%/dump.vvp: verilator.% +# for whatever reason, some version of vlor started to append _tb. + ($(MAKE) -j4 -C verilator.$(*) -f V$(*).mk RM=rm || \ + $(MAKE) -j4 -C verilator.$(*) -f V$(*)_tb.mk RM=rm) + cd verilator.$(*) && (./V$(*) || ./V$(*)_tb) + +## inter-file dependencies +-include $(DEPS) +-include $($(wildcard *.fs:.fs=.dep) diff --git a/playground/clkdiv.v b/playground/clkdiv.v new file mode 100644 index 0000000..b6f1419 --- /dev/null +++ b/playground/clkdiv.v @@ -0,0 +1,36 @@ +`timescale 1us/1us + +module clkdiv ( + input rst_i, + input clk, // clk input + output reg o_divclk // divided output (must be a reg, b/c it needs to keep state) +); + +reg [23:0] counter; +// CLK is 27 MHz +// we want a 2Hz signal at the output +// and pin needs to *toggle twice* within one period +// 27MHz / 4 = 6750000 +localparam DIVISOR = 24'd6_749_999; + +always @(posedge clk or negedge rst_i) begin + if (!rst_i) + counter <= 24'd0; + else if (counter < DIVISOR) + counter <= counter + 1'b1; + else + counter <= 24'd0; +end + +always @(posedge clk or negedge rst_i) begin + if (!rst_i) + o_divclk <= 1'b0; + else if (counter == DIVISOR) + o_divclk <= ~o_divclk; + else + o_divclk <= o_divclk; +end + + +endmodule + diff --git a/playground/clock.sdc b/playground/clock.sdc new file mode 100644 index 0000000..5e64ad9 --- /dev/null +++ b/playground/clock.sdc @@ -0,0 +1,2 @@ +create_clock -period 40.00 -name {clk} [get_ports {clk}] +create_clock -period 40.00 -name {clk_i} [get_ports {clk_i}] diff --git a/playground/debounce.v b/playground/debounce.v new file mode 100644 index 0000000..33dc22e --- /dev/null +++ b/playground/debounce.v @@ -0,0 +1,53 @@ +`timescale 1us/1us + +module debounce ( + input rst_i, + input clk_i, + input signal_i, + output reg signal_o +); + +// number of rising clock edges a signal needs to be stable +// for it to be output. +// (+1 for propagation). +parameter STABLE_PERIOD = 50; +parameter INIT_SIG_STATE = 1'b1; + +reg [31:0] clk_counter; +reg prev_state; + +always @(posedge clk_i or negedge rst_i) begin + if (!rst_i) begin + // Learning: I would like to set the output to the input on reset + // but then I get + // Warning: Async reset value `\signal_i' is not constant! + // and a synthesis error. + clk_counter <= 0; + prev_state <= INIT_SIG_STATE; + signal_o <= INIT_SIG_STATE; + end else begin + + if (signal_i != prev_state) begin + clk_counter <= 0; + prev_state <= signal_i; + end else begin + clk_counter <= clk_counter + 1; + end + + if (clk_counter === STABLE_PERIOD) begin + signal_o <= signal_i; + end + end +end + +// Learning? +// Apparently, (and obviously, when you think about it), +// it's not possible to drive a signal by two blocks +// always @(signal_i) begin +// if (signal_i != prev_state) begin +// clk_counter <= 0; +// prev_state <= signal_i; +// end +// end + +endmodule diff --git a/playground/debounce_tb.v b/playground/debounce_tb.v new file mode 100644 index 0000000..fb9430c --- /dev/null +++ b/playground/debounce_tb.v @@ -0,0 +1,76 @@ +`timescale 1us/1us + +module debounce_tb; + +logic rst_i; +logic clk_i; +logic signal_i; +logic signal_o; + +integer i = 0; + +debounce #(.STABLE_PERIOD(5)) uut ( + .rst_i(rst_i), + .clk_i(clk_i), + .signal_i(signal_i), + .signal_o(signal_o) +); + +string filename; +initial begin +`ifdef DUMP_FILE_NAME + filename=`DUMP_FILE_NAME; +`else + filename="debounce.lxt2"; +`endif + $dumpfile(filename); $dumpvars(); + + clk_i = 0; + rst_i = 1'b1; + signal_i = 1'b1; + #1 + rst_i = 1'b0; + #1 + rst_i = 1'b1; +end + +always #10 clk_i = ~clk_i; + +initial begin + // initial key press + @(negedge clk_i); + signal_i = ~signal_i; + assert (signal_o == 1'b1); + + repeat(2) @(negedge clk_i); + + signal_i = ~signal_i; + assert (signal_o == 1'b1); + + // try bouncing + + repeat(2) @(negedge clk_i); + + for (i=0; i < 20; i = i + 1) begin + @(negedge clk_i); + signal_i = ~signal_i; + assert (signal_o == 1'b1); + end + @(negedge clk_i); + signal_i = ~signal_i; + assert (signal_o == 1'b1); + + repeat(10) @(negedge clk_i); + assert (signal_o == 1'b0); + + repeat(10) @(negedge clk_i); + signal_i = ~signal_i; + + repeat(10) @(negedge clk_i); + assert (signal_o == 1'b1); + + repeat(10) @(negedge clk_i); + $finish(); +end + +endmodule diff --git a/playground/fifo.v b/playground/fifo.v new file mode 100644 index 0000000..bcc2d3f --- /dev/null +++ b/playground/fifo.v @@ -0,0 +1,90 @@ +`timescale 1us/1us + +`include "my_mem.v" + +module fifo #( + parameter DATA_WIDTH = 8, + parameter DATA_DEPTH = 1024 +) ( + input rst_i, + input clk_i, + + input write_i, + input read_i, + + output empty_o, + output full_o, + + //output data_valid_o, + + input [(DATA_WIDTH-1) : 0] data_i, + output reg [(DATA_WIDTH-1) : 0] data_o + +); + +localparam DATA_DEPTH_BITS = $clog2(DATA_DEPTH); + +// the -1 will make sure it fits +/* verilator lint_off WIDTHTRUNC */ +localparam [DATA_DEPTH_BITS-1:0] MAX_ADDRESS = (DATA_DEPTH - 1); +/* verilator lint_on WIDTHTRUNC */ + +// need to "count" to number *including* depth +reg [$clog2(DATA_DEPTH + 1)-1:0] r_count; +reg [DATA_DEPTH_BITS-1:0] r_read_addr; +reg [DATA_DEPTH_BITS-1:0] r_write_addr; + +assign empty_o = r_count == 0; +assign full_o = r_count == DATA_DEPTH; + +wire int_wr_en = write_i && !full_o; +wire int_rd_en = read_i && !empty_o; + +my_mem #( + .DATA_WIDTH(DATA_WIDTH), + .DATA_DEPTH(DATA_DEPTH) +) fifo_mem ( + .clk_i(clk_i), + .write_en_i(int_wr_en), + .read_en_i(int_rd_en), + .r_read_addr(r_read_addr), + .r_write_addr(r_write_addr), + + .data_i(data_i), + .data_o(data_o) +); + +initial begin + r_count = 0; + r_read_addr = 0; + r_write_addr = 0; +end + +always @(posedge clk_i or negedge rst_i) begin + if (!rst_i) + r_count <= 0; + else if (write_i && read_i) + // nothing to do + // count stays the same + ; + else if (write_i && !full_o) + r_count <= r_count + 1; + else if (read_i && !empty_o) + r_count <= r_count - 1; +end + +always @(posedge clk_i or negedge rst_i) begin + if (!rst_i) + r_read_addr <= 0; + else if (read_i && !empty_o) + r_read_addr <= (r_read_addr < MAX_ADDRESS) ? (r_read_addr + 1) : 0; +end + +always @(posedge clk_i or negedge rst_i) begin + if (!rst_i) + r_write_addr <= 0; + else if (write_i && !full_o) + r_write_addr <= (r_write_addr < MAX_ADDRESS) ? (r_write_addr + 1) : 0; +end + +endmodule diff --git a/playground/fifo_tb.v b/playground/fifo_tb.v new file mode 100644 index 0000000..38199a6 --- /dev/null +++ b/playground/fifo_tb.v @@ -0,0 +1,72 @@ +`timescale 1us/1us + +module fifo_tb; + +reg clk_i; +reg rst_i; + +reg read_i, write_i; +reg [7:0] data_i; + +fifo #( + .DATA_WIDTH(8), + .DATA_DEPTH(8) +) uut ( + .clk_i(clk_i), + .rst_i(rst_i), + .write_i(write_i), + .read_i(read_i), + .data_i(data_i), + + .empty_o(), + .full_o(), + .data_o() +); + +string filename; +initial begin +`ifdef DUMP_FILE_NAME + filename=`DUMP_FILE_NAME; +`else + filename="fifo.lxt2"; +`endif + $dumpfile(filename); $dumpvars(); + clk_i = 0; + rst_i = 1'b1; + read_i = 0; + write_i = 0; + data_i = 0; +end + +always #10 clk_i = ~clk_i; + +initial begin + #15 + + for (integer run = 1; run < 3; run++) begin + + write_i = 1; + for (integer addr = 0; addr < 10; addr++) begin + + data_i = (run << 4) | addr; + #20 + ; + end + + write_i = 0; + read_i = 1; + + for (integer addr = 0; addr < 10; addr++) begin + #20 + ; + end + + read_i = 0; + #20 + ; + end + #100 + $finish(); +end + +endmodule diff --git a/playground/fizzbuzz.v b/playground/fizzbuzz.v new file mode 100644 index 0000000..0e34c58 --- /dev/null +++ b/playground/fizzbuzz.v @@ -0,0 +1,20 @@ +`timescale 1us/1us + +module fizzbuzz ( + input [7:0] num_i, + output [7:0] num_o, + output fizz_o, + output buzz_o, + output fizzbuzz_o +); + +wire is_fizz, is_buzz; +assign is_fizz = num_i % 3 == 0; +assign is_buzz = num_i % 5 == 0; + +assign fizz_o = is_fizz && !is_buzz; +assign buzz_o = !is_fizz && is_buzz; +assign fizzbuzz_o = is_fizz && is_buzz; +assign num_o = (is_fizz || is_buzz) ? 0 : num_i; + +endmodule diff --git a/playground/fizzbuzz_tb.v b/playground/fizzbuzz_tb.v new file mode 100644 index 0000000..4d612ec --- /dev/null +++ b/playground/fizzbuzz_tb.v @@ -0,0 +1,48 @@ +`timescale 1us/1us + +module fizzbuzz_tb; + + +logic [7:0] number; +logic clk_i; + +logic [7:0] num_out; + +fizzbuzz uut ( + .num_i(number), + .num_o(num_out), + .fizz_o(), + .buzz_o(), + .fizzbuzz_o() +); + +string filename; +initial begin +`ifdef DUMP_FILE_NAME + filename=`DUMP_FILE_NAME; +`else + filename="fizzbuzz.lxt2"; +`endif + $dumpfile(filename); $dumpvars(); + + + clk_i = 0; + number = '0; +end + +always #10 begin + clk_i = ~clk_i; +end + +always @(negedge clk_i) begin + number <= number + 1; + // give iverilog some simulation time... + #1; + if (number == 3) assert(num_out == 0); + if (number == 5) assert(num_out == 0); + if (number == 15) assert(num_out == 0); + + if (number == 255) $finish; +end + +endmodule diff --git a/playground/led.v b/playground/led.v new file mode 100644 index 0000000..e4f4281 --- /dev/null +++ b/playground/led.v @@ -0,0 +1,31 @@ +`timescale 1us/1us + +`include "clkdiv.v" + +module led ( + input clk, // clk input + input rst_i, // reset input + output reg [5:0] led_o // 6 LEDS pin +); + +reg half_sec_clock; + +clkdiv half_sec_divider( + .rst_i(rst_i), + .clk(clk), + .o_divclk(half_sec_clock) +); + +always @(posedge half_sec_clock or negedge rst_i) begin + if (!rst_i) + led_o <= 6'b111111; + else +// else if (counter == 24'd1349_9999) // 0.5s delay + led_o[5:0] <= led_o[5:0] - 1; +// else +// led_o <= led_o; +end + + +endmodule + diff --git a/playground/led_toggle.v b/playground/led_toggle.v new file mode 100644 index 0000000..3c54ee4 --- /dev/null +++ b/playground/led_toggle.v @@ -0,0 +1,32 @@ +`timescale 1us/1us + +// From the book +// bouncy variant + +`include "led_toggle_bouncy.v" +`include "debounce.v" + +module led_toggle ( + input rst_i, + input clk_i, + input key_i, + output [5:0] led +); +parameter STABLE_PERIOD = 50; + +wire outsig; + +debounce #(.STABLE_PERIOD(STABLE_PERIOD)) db( + .rst_i(rst_i), + .clk_i(clk_i), + .signal_i(key_i), + .signal_o(outsig) +); + +led_toggle_bouncy tgler( + .clk_i(clk_i), + .key_i(outsig), + .led(led) +); + +endmodule diff --git a/playground/led_toggle_bouncy.v b/playground/led_toggle_bouncy.v new file mode 100644 index 0000000..b05b472 --- /dev/null +++ b/playground/led_toggle_bouncy.v @@ -0,0 +1,25 @@ +`timescale 1us/1us + +// From the book +// bouncy variant + +module led_toggle_bouncy ( + input clk_i, + input key_i, + output [5:0] led +); + +reg r_LED_1 = 1'b1; +reg r_Switch_1 = 1'b1; + +always @(posedge clk_i) begin + r_Switch_1 <= key_i; + if (key_i == 1'b1 && r_Switch_1 == 1'b0) begin + r_LED_1 <= ~r_LED_1; + end +end + +assign led[0] = r_LED_1; +assign led[5:1] = 5'b11111; + +endmodule diff --git a/playground/led_toggle_bouncy_tb.v b/playground/led_toggle_bouncy_tb.v new file mode 100644 index 0000000..2c04484 --- /dev/null +++ b/playground/led_toggle_bouncy_tb.v @@ -0,0 +1,50 @@ +`timescale 1us/1us + +module led_toggle_bouncy_tb; + +logic clk_i; +logic key_i; +logic [5:0] led; + +led_toggle_bouncy uut ( + .clk_i(clk_i), + .key_i(key_i), + .led(led) +); + +string filename; +initial begin +`ifdef DUMP_FILE_NAME + filename=`DUMP_FILE_NAME; +`else + filename="led_toggle_bouncy.lxt2"; +`endif + $dumpfile(filename); $dumpvars(); + + clk_i = 0; + key_i = 1'b1; +end + +always #10 clk_i = ~clk_i; + +initial begin + // initial key press + @(negedge clk_i); + key_i = ~key_i; + repeat(2) @(negedge clk_i); + key_i = ~key_i; + + // try bouncing + + repeat(2) @(negedge clk_i); + + for (integer i=0; i < 20; i = i + 1) begin + @(negedge clk_i); + key_i = ~key_i; + end + + repeat(5) @(negedge clk_i); + $finish(); +end + +endmodule diff --git a/playground/led_toggle_nonwork.v b/playground/led_toggle_nonwork.v new file mode 100644 index 0000000..5fe458f --- /dev/null +++ b/playground/led_toggle_nonwork.v @@ -0,0 +1,26 @@ +`timescale 1us/1us + +// +// NON-WORKING +// LED toggle example +// probably because LED is controlled by two blocks +// + +module led_toggle_nonwork( + input clk_i, + input key_i, + input rst_i, + output reg [5:0] led +); + +always @(negedge rst_i) begin + if (!rst_i) + led <= 6'b111111; +end + +always @(negedge key_i) begin + if (!key_i) + led[0] <= ~led[0]; +end + +endmodule diff --git a/playground/led_toggle_tb.v b/playground/led_toggle_tb.v new file mode 100644 index 0000000..78d4f21 --- /dev/null +++ b/playground/led_toggle_tb.v @@ -0,0 +1,59 @@ +`timescale 1us/1us + +module led_toggle_tb; + +logic clk_i; +logic rst_i; +logic key_i; + +logic [5:0] led; + +led_toggle #(.STABLE_PERIOD(2)) uut ( + .rst_i(rst_i), + .clk_i(clk_i), + .key_i(key_i), + .led(led) +); + +string filename; +initial begin +`ifdef DUMP_FILE_NAME + filename=`DUMP_FILE_NAME; +`else + filename="led_toggle.lxt2"; +`endif + $dumpfile(filename); $dumpvars(); + clk_i = 0; + key_i = 1'b1; + #1 + rst_i = 0; + #1 + rst_i = 1; +end + +always #10 clk_i = ~clk_i; + + +initial begin + // initial key press + #13 + key_i = ~key_i; + repeat(2) @(negedge clk_i); + key_i = ~key_i; + + // try bouncing + + repeat(3) @(negedge clk_i); + + for (integer i=0; i < 19; i = i + 1) begin + @(negedge clk_i); + key_i = ~key_i; + end + repeat(10) @(negedge clk_i); + key_i = ~key_i; + + repeat(10) @(negedge clk_i); + $finish(); +end + +endmodule diff --git a/playground/my_mem.tb.wtf.v b/playground/my_mem.tb.wtf.v new file mode 100644 index 0000000..8b1aed6 --- /dev/null +++ b/playground/my_mem.tb.wtf.v @@ -0,0 +1,119 @@ +// LLM generated, because I'm too lazy to do this manually + +`timescale 1us/1ns + +module my_mem_tb(); + + localparam DATA_WIDTH = 8; + localparam DATA_DEPTH = 16; + localparam ADDR_WIDTH = $clog2(DATA_DEPTH); + + // DUT signals + logic clk; + logic write_en_i; + logic read_en_i; + logic [ADDR_WIDTH-1:0] r_read_addr; + logic [ADDR_WIDTH-1:0] r_write_addr; + logic [DATA_WIDTH-1:0] data_i; + logic [DATA_WIDTH-1:0] data_o; + + // Instantiate DUT + my_mem #( + .DATA_WIDTH(DATA_WIDTH), + .DATA_DEPTH(DATA_DEPTH) + ) dut ( + .clk_i(clk), + .write_en_i(write_en_i), + .read_en_i(read_en_i), + .r_read_addr(r_read_addr), + .r_write_addr(r_write_addr), + .data_i(data_i), + .data_o(data_o) + ); + + string filename; + initial begin + `ifdef DUMP_FILE_NAME + filename=`DUMP_FILE_NAME; + `else + filename="my_mem.lxt2"; + `endif + $dumpfile(filename); $dumpvars(); + end + + // Clock generator + always #10 clk = ~clk; + + // Test sequence + initial begin + clk = 0; + write_en_i = 0; + read_en_i = 0; + r_read_addr = '0; + r_write_addr = '0; + data_i = '0; + + repeat (3) @(posedge clk); + + // ------------------------- + // Write some values + // ------------------------- + @(posedge clk); + @(posedge clk); + write_en_i = 1; + r_write_addr = 10; + data_i = 8'hA5; + + @(posedge clk); + r_write_addr = 11; + data_i = 8'h3C; + + @(posedge clk); + write_en_i = 0; + + // ------------------------- + // Read back values + // ------------------------- + + // asserts fail in iverilog if I use the posedge stuff, + // (but works in verilator). + // need an additional clock cycle delay. + + @(posedge clk); + @(posedge clk); + @(posedge clk); + @(posedge clk); + read_en_i = 1; + r_read_addr = 10; + + @(posedge clk); + @(posedge clk); + @(posedge clk); + @(posedge clk); + assert (data_o == 8'hA5) + else $error("ASSERTION FAILED: addr 10 expected 0xA5, got 0x%02h", data_o); + + @(posedge clk); + @(posedge clk); + @(posedge clk); + @(posedge clk); + r_read_addr = 11; + + @(posedge clk); + @(posedge clk); + @(posedge clk); + @(posedge clk); + assert (data_o == 8'h3C) + else $error("ASSERTION FAILED: addr 11 expected 0x3C, got 0x%02h", data_o); + + @(posedge clk); + @(posedge clk); + @(posedge clk); + @(posedge clk); + read_en_i = 0; + + repeat (3) @(posedge clk); + $finish; + end + +endmodule diff --git a/playground/my_mem.v b/playground/my_mem.v new file mode 100644 index 0000000..1153ec7 --- /dev/null +++ b/playground/my_mem.v @@ -0,0 +1,49 @@ +`timescale 1us/1us + +`ifndef UVOK_MEMORY +`define UVOK_MEMORY + +module my_mem #( + parameter DATA_WIDTH = 8, + parameter DATA_DEPTH = 1024 +) ( + input clk_i, + + input write_en_i, + input read_en_i, + + input [$clog2(DATA_DEPTH)-1:0] r_read_addr, + input [$clog2(DATA_DEPTH)-1:0] r_write_addr, + + input [(DATA_WIDTH-1) : 0] data_i, + output reg [(DATA_WIDTH-1) : 0] data_o +); + +reg [(DATA_WIDTH-1) : 0] r_datastore [(DATA_DEPTH-1) : 0] /* verilator public */; + +`ifdef DEBUG +// for debugging simulations, as iverilog +// does't show r_datastore +reg [(DATA_WIDTH-1) : 0] r_cur_r_val; +reg [(DATA_WIDTH-1) : 0] r_cur_w_val; +`endif + +always @(posedge clk_i) begin + if (write_en_i) begin + r_datastore[r_write_addr] <= data_i; +`ifdef DEBUG + r_cur_w_val <= data_i; +`endif + end + + if (read_en_i) begin + data_o <= r_datastore[r_read_addr]; +`ifdef DEBUG + r_cur_r_val <= r_datastore[r_read_addr]; +`endif + end +end + +endmodule + +`endif diff --git a/playground/my_mem_tb.v b/playground/my_mem_tb.v new file mode 100644 index 0000000..c8c2e12 --- /dev/null +++ b/playground/my_mem_tb.v @@ -0,0 +1,99 @@ +// LLM generated, because I'm too lazy to do this manually + +`timescale 1us/1ns + +module my_mem_tb(); + + localparam DATA_WIDTH = 8; + localparam DATA_DEPTH = 16; + localparam ADDR_WIDTH = $clog2(DATA_DEPTH); + + // DUT signals + logic clk; + logic write_en_i; + logic read_en_i; + logic [ADDR_WIDTH-1:0] r_read_addr; + logic [ADDR_WIDTH-1:0] r_write_addr; + logic [DATA_WIDTH-1:0] data_i; + logic [DATA_WIDTH-1:0] data_o; + + // Instantiate DUT + my_mem #( + .DATA_WIDTH(DATA_WIDTH), + .DATA_DEPTH(DATA_DEPTH) + ) dut ( + .clk_i(clk), + .write_en_i(write_en_i), + .read_en_i(read_en_i), + .r_read_addr(r_read_addr), + .r_write_addr(r_write_addr), + .data_i(data_i), + .data_o(data_o) + ); + + string filename; + initial begin + `ifdef DUMP_FILE_NAME + filename=`DUMP_FILE_NAME; + `else + filename="my_mem.lxt2"; + `endif + $dumpfile(filename); $dumpvars(); + end + + // Clock generator + always #10 clk = ~clk; + + // Test sequence + initial begin + clk = 0; + write_en_i = 0; + read_en_i = 0; + r_read_addr = '0; + r_write_addr = '0; + data_i = '0; + + repeat (3) @(negedge clk); + + // ------------------------- + // Write some values + // ------------------------- + @(negedge clk); + write_en_i = 1; + r_write_addr = 10; + data_i = 8'hA5; + + @(negedge clk); + r_write_addr = 11; + data_i = 8'h3C; + + @(negedge clk); + write_en_i = 0; + + // ------------------------- + // Read back values + // ------------------------- + + @(negedge clk); + read_en_i = 1; + r_read_addr = 10; + + @(negedge clk); + assert (data_o == 8'hA5) + else $error("ASSERTION FAILED: addr 10 expected 0xA5, got 0x%02h", data_o); + + @(negedge clk); + r_read_addr = 11; + + @(negedge clk); + assert (data_o == 8'h3C) + else $error("ASSERTION FAILED: addr 11 expected 0x3C, got 0x%02h", data_o); + + @(negedge clk); + read_en_i = 0; + + repeat (3) @(negedge clk); + $finish; + end + +endmodule diff --git a/playground/par_to_ser.v b/playground/par_to_ser.v new file mode 100644 index 0000000..ab754c9 --- /dev/null +++ b/playground/par_to_ser.v @@ -0,0 +1,64 @@ +`timescale 1us/1us + +// parallel to serial converter + +module par_to_ser #( + parameter SHIFT_WIDTH = 8 +) ( + input rst_i, + input clk_i, + input data_valid_i, + input [(SHIFT_WIDTH-1):0] dat_i, + output reg dat_o, + output dat_valid_o +); + +// Learning: can't declate parameter here +// if I want to use it in the input/output list. +// parameter SHIFT_WIDTH = 8; + +reg [(SHIFT_WIDTH-1):0] send_data = {SHIFT_WIDTH{1'b1}}; +// want to count to number *including* width, add 1 +reg [$clog2(SHIFT_WIDTH + 1) - 1:0] count = 0; + +// yes, smaller than, the count *to* 8 still takes place +wire counting = (count != 0) && (count < SHIFT_WIDTH); +// sending is one byte longer +wire sending = (count != 0) && (count <= SHIFT_WIDTH); + +always @(posedge clk_i or negedge rst_i) begin + if (!rst_i) begin + dat_o <= 1'b1; + end else if (data_valid_i && count == 0) begin + dat_o <= dat_i[0]; + end else if (sending) begin + dat_o <= send_data[0]; + end +end + +always @(posedge clk_i or negedge rst_i) begin + if (!rst_i) begin + send_data <= {SHIFT_WIDTH{1'b1}}; + end else if (data_valid_i && count == 0) begin + send_data <= {1'b1, dat_i[(SHIFT_WIDTH-1):1]}; + end else if (sending) begin + // arbitrary decision: register is filled with a 1 + send_data <= {1'b1, send_data[(SHIFT_WIDTH-1):1]}; + end +end + +always @(posedge clk_i or negedge rst_i) begin + if (!rst_i) begin + count <= 0; + end else if (data_valid_i && count == 0) begin + count <= 1; + end else if (counting) begin + count <= count + 1; + end else begin + count <= 0; + end +end + +assign dat_valid_o = sending; + +endmodule diff --git a/playground/par_to_ser_tb.v b/playground/par_to_ser_tb.v new file mode 100644 index 0000000..a30e282 --- /dev/null +++ b/playground/par_to_ser_tb.v @@ -0,0 +1,68 @@ +`timescale 1us/1us + +module par_to_ser_tb; + +logic clk_i; +logic rst_i; +logic data_valid_i; +logic [7:0] dat_i; +logic dat_o; + +par_to_ser uut ( + .clk_i(clk_i), + .rst_i(rst_i), + .data_valid_i(data_valid_i), + .dat_i(dat_i), + .dat_o(dat_o), + .dat_valid_o() +); + +string filename; +initial begin +`ifdef DUMP_FILE_NAME + filename=`DUMP_FILE_NAME; +`else + filename="par_to_ser.lxt2"; +`endif + $dumpfile(filename); $dumpvars(); + clk_i = 0; + rst_i = 1'b1; + data_valid_i = 1'b0; + + #1 + rst_i = 1'b0; + #1 + rst_i = 1'b1; +end + +always #10 clk_i = ~clk_i; + +bit sollbit = 1'b0; + +initial begin + #13 + @(negedge clk_i); + + for (integer i = 0; i < 255; i++) begin + // clock data in + dat_i = i; + data_valid_i = 1'b1; + + @(negedge clk_i); + data_valid_i = 1'b0; + + for (integer j = 0; j < 8; j++) begin + sollbit = (i >> j) & 1; + assert(dat_o == sollbit) + else $error("Expected bit to be %d, but was %d", sollbit, dat_o); + + @(negedge clk_i); + end + + repeat(2) @(negedge clk_i); + end + + $finish(); +end + +endmodule diff --git a/playground/par_to_ser_to_par_tb.v b/playground/par_to_ser_to_par_tb.v new file mode 100644 index 0000000..9a4a3eb --- /dev/null +++ b/playground/par_to_ser_to_par_tb.v @@ -0,0 +1,81 @@ +// converts back and forth +// parallel > serial > parallel + +`timescale 1us/1us + +module par_to_ser_to_par_tb; + +logic clk_i; +logic rst_i; +logic data_valid_i; +logic [7:0] dat_i; + +logic dat_o; +logic [7:0] dat_o2; +logic send_valid; + +par_to_ser uut ( + .clk_i(clk_i), + .rst_i(rst_i), + .data_valid_i(data_valid_i), + .dat_i(dat_i), + .dat_o(dat_o), + .dat_valid_o(send_valid) +); + +ser_to_par uut2 ( + .clk_i(clk_i), + .rst_i(rst_i), + + .dat_valid_i(send_valid), + .dat_i(dat_o), + + .dat_o(dat_o2), + .dat_valid_o() +); + +string filename; +initial begin +`ifdef DUMP_FILE_NAME + filename=`DUMP_FILE_NAME; +`else + filename="par_to_ser_to_par.lxt2"; +`endif + $dumpfile(filename); $dumpvars(); + clk_i = 0; + rst_i = 1'b1; + data_valid_i = 1'b0; + + #1 + rst_i = 1'b0; + #1 + rst_i = 1'b1; +end + +always #10 clk_i = ~clk_i; + +initial begin + #13; + @(negedge clk_i); + + for (integer i = 0; i < 255; i++) begin + // clock data in + dat_i = i; + data_valid_i = 1'b1; + + // wait 1 cycle + @(negedge clk_i); + data_valid_i = 1'b0; + + // let module do its work + repeat(10) @(negedge clk_i); + + assert(i == dat_o2) + else $error("Expected output to be h%x, but was h%x", i, dat_o2); + + end + + $finish(); +end + +endmodule diff --git a/playground/ser_to_par.v b/playground/ser_to_par.v new file mode 100644 index 0000000..f0a0c47 --- /dev/null +++ b/playground/ser_to_par.v @@ -0,0 +1,39 @@ +`timescale 1us/1us + +// serial to parallel converter +// Learning: +// I don't like this. +// I think I need a signal / way to say "I'm finished"? +// or generally, an enable pin. +// + +module ser_to_par #( + parameter SHIFT_WIDTH = 8 +) ( + input rst_i, + input clk_i, + + input dat_valid_i, + input dat_i, + + output reg[(SHIFT_WIDTH - 1):0] dat_o, + // ??? + output dat_valid_o +); + +reg [$clog2(SHIFT_WIDTH) - 1 : 0] count = {$clog2(SHIFT_WIDTH){1'b0}}; + +always @(posedge clk_i or negedge rst_i) begin + if (!rst_i) begin + dat_o <= 8'b0; + end else if(dat_valid_i) begin + // shift into highest bit first, so it is subsequently shifted down + dat_o[SHIFT_WIDTH - 1] <= dat_i; + dat_o[(SHIFT_WIDTH - 2):0] <= dat_o[(SHIFT_WIDTH - 1):1]; + count <= count + 1; + end +end + +assign dat_valid_o = count == 0; + +endmodule diff --git a/playground/ser_to_par_tb.v b/playground/ser_to_par_tb.v new file mode 100644 index 0000000..d39598e --- /dev/null +++ b/playground/ser_to_par_tb.v @@ -0,0 +1,62 @@ +`timescale 1us/1us + +module ser_to_par_tb; + +logic clk_i; +logic rst_i; +logic dat_i; +logic dat_valid; +logic [7:0] dat_o; + +ser_to_par uut ( + .clk_i(clk_i), + .rst_i(rst_i), + .dat_i(dat_i), + .dat_o(dat_o), + .dat_valid_i(dat_valid), + .dat_valid_o() +); + +string filename; +initial begin +`ifdef DUMP_FILE_NAME + filename=`DUMP_FILE_NAME; +`else + filename="ser_to_par.lxt2"; +`endif + $dumpfile(filename); $dumpvars(); + clk_i = 0; + rst_i = 1'b1; + dat_i = 1'b1; + dat_valid= 1'b0; + #1 + rst_i = 0; + #1 + rst_i = 1; +end + +always #10 clk_i = ~clk_i; + +initial begin + #13; + @(negedge clk_i); + + dat_valid = 1'b1; + // start data + dat_i = 1'b0; + @(negedge clk_i); + // - 1 clk cycle, 1 bit later: + dat_i = 1'b1; + + repeat (7) @(negedge clk_i); + dat_valid = 1'b0; + + // - 7 clk cycle, 7 bits later: + assert (dat_o == 8'hfe) + else $error("Excected dat_o to be hfe, was h%x", dat_o); + + @(negedge clk_i); + $finish(); +end + +endmodule diff --git a/playground/template.v b/playground/template.v new file mode 100644 index 0000000..e6f5280 --- /dev/null +++ b/playground/template.v @@ -0,0 +1,14 @@ +`timescale 1us/1us + +module template ( + input rst_i, + input clk_i +); + +always @(posedge clk_i or negedge rst_i) begin + if (!rst_i) begin + + end +end + +endmodule diff --git a/playground/template_tb.v b/playground/template_tb.v new file mode 100644 index 0000000..8bef3a1 --- /dev/null +++ b/playground/template_tb.v @@ -0,0 +1,36 @@ +`timescale 1us/1us + +module template_tb; + +reg clk_i; +reg rst_i; + +template uut ( + .clk_i(clk_i), + .rst_i(rst_i) +); + +string filename; +initial begin +`ifdef DUMP_FILE_NAME + filename=`DUMP_FILE_NAME; +`else + filename="template.lxt2"; +`endif + $dumpfile(filename); $dumpvars(); + clk_i = 0; + rst_i = 1'b1; + +end + +always #10 clk_i = ~clk_i; + +initial begin + #13 + @(negedge clk_i); + + #100 + $finish(); +end + +endmodule diff --git a/playground/tst_delay.v b/playground/tst_delay.v new file mode 100644 index 0000000..c4017bd --- /dev/null +++ b/playground/tst_delay.v @@ -0,0 +1,17 @@ +`timescale 1us/1us + +module tst_delay ( + input clk_i, + input data_i, + output reg data_o +); + +initial begin + data_o = 0; +end + +always @(posedge clk_i) begin + data_o <= data_i; +end + +endmodule diff --git a/playground/tst_delay_tb.v b/playground/tst_delay_tb.v new file mode 100644 index 0000000..5812068 --- /dev/null +++ b/playground/tst_delay_tb.v @@ -0,0 +1,53 @@ +// try to figure out how iverilog samples edges +`timescale 1us/1us + +module tst_delay_tb; + +reg clk_i; +reg data_i; +wire data_o; + +tst_delay uut ( + .clk_i(clk_i), + .data_i(data_i), + .data_o(data_o) +); + +string filename; +initial begin +`ifdef DUMP_FILE_NAME + filename=`DUMP_FILE_NAME; +`else + filename="tst_delay.lxt2"; +`endif + $dumpfile(filename); $dumpvars(); + clk_i = 0; + data_i = 0; +end + +always #10 clk_i = ~clk_i; + +initial begin + #9 + data_i = 1; + #2 + data_i = 0; + + /* verilator lint_off INITIALDLY */ + // note the <= assignment + #19 + data_i <= 1; + /* verilator lint_on INITIALDLY */ + + #1 + data_i = 0; + // note the = assignment + #19 + data_i = 1; + #1 + data_i = 0; + #40 + $finish(); +end + +endmodule diff --git a/ser_to_par.v b/ser_to_par.v deleted file mode 100644 index f0a0c47..0000000 --- a/ser_to_par.v +++ /dev/null @@ -1,39 +0,0 @@ -`timescale 1us/1us - -// serial to parallel converter -// Learning: -// I don't like this. -// I think I need a signal / way to say "I'm finished"? -// or generally, an enable pin. -// - -module ser_to_par #( - parameter SHIFT_WIDTH = 8 -) ( - input rst_i, - input clk_i, - - input dat_valid_i, - input dat_i, - - output reg[(SHIFT_WIDTH - 1):0] dat_o, - // ??? - output dat_valid_o -); - -reg [$clog2(SHIFT_WIDTH) - 1 : 0] count = {$clog2(SHIFT_WIDTH){1'b0}}; - -always @(posedge clk_i or negedge rst_i) begin - if (!rst_i) begin - dat_o <= 8'b0; - end else if(dat_valid_i) begin - // shift into highest bit first, so it is subsequently shifted down - dat_o[SHIFT_WIDTH - 1] <= dat_i; - dat_o[(SHIFT_WIDTH - 2):0] <= dat_o[(SHIFT_WIDTH - 1):1]; - count <= count + 1; - end -end - -assign dat_valid_o = count == 0; - -endmodule diff --git a/ser_to_par_tb.v b/ser_to_par_tb.v deleted file mode 100644 index d39598e..0000000 --- a/ser_to_par_tb.v +++ /dev/null @@ -1,62 +0,0 @@ -`timescale 1us/1us - -module ser_to_par_tb; - -logic clk_i; -logic rst_i; -logic dat_i; -logic dat_valid; -logic [7:0] dat_o; - -ser_to_par uut ( - .clk_i(clk_i), - .rst_i(rst_i), - .dat_i(dat_i), - .dat_o(dat_o), - .dat_valid_i(dat_valid), - .dat_valid_o() -); - -string filename; -initial begin -`ifdef DUMP_FILE_NAME - filename=`DUMP_FILE_NAME; -`else - filename="ser_to_par.lxt2"; -`endif - $dumpfile(filename); $dumpvars(); - clk_i = 0; - rst_i = 1'b1; - dat_i = 1'b1; - dat_valid= 1'b0; - #1 - rst_i = 0; - #1 - rst_i = 1; -end - -always #10 clk_i = ~clk_i; - -initial begin - #13; - @(negedge clk_i); - - dat_valid = 1'b1; - // start data - dat_i = 1'b0; - @(negedge clk_i); - // - 1 clk cycle, 1 bit later: - dat_i = 1'b1; - - repeat (7) @(negedge clk_i); - dat_valid = 1'b0; - - // - 7 clk cycle, 7 bits later: - assert (dat_o == 8'hfe) - else $error("Excected dat_o to be hfe, was h%x", dat_o); - - @(negedge clk_i); - $finish(); -end - -endmodule diff --git a/template.v b/template.v deleted file mode 100644 index e6f5280..0000000 --- a/template.v +++ /dev/null @@ -1,14 +0,0 @@ -`timescale 1us/1us - -module template ( - input rst_i, - input clk_i -); - -always @(posedge clk_i or negedge rst_i) begin - if (!rst_i) begin - - end -end - -endmodule diff --git a/template_tb.v b/template_tb.v deleted file mode 100644 index 8bef3a1..0000000 --- a/template_tb.v +++ /dev/null @@ -1,36 +0,0 @@ -`timescale 1us/1us - -module template_tb; - -reg clk_i; -reg rst_i; - -template uut ( - .clk_i(clk_i), - .rst_i(rst_i) -); - -string filename; -initial begin -`ifdef DUMP_FILE_NAME - filename=`DUMP_FILE_NAME; -`else - filename="template.lxt2"; -`endif - $dumpfile(filename); $dumpvars(); - clk_i = 0; - rst_i = 1'b1; - -end - -always #10 clk_i = ~clk_i; - -initial begin - #13 - @(negedge clk_i); - - #100 - $finish(); -end - -endmodule diff --git a/tst_delay.v b/tst_delay.v deleted file mode 100644 index c4017bd..0000000 --- a/tst_delay.v +++ /dev/null @@ -1,17 +0,0 @@ -`timescale 1us/1us - -module tst_delay ( - input clk_i, - input data_i, - output reg data_o -); - -initial begin - data_o = 0; -end - -always @(posedge clk_i) begin - data_o <= data_i; -end - -endmodule diff --git a/tst_delay_tb.v b/tst_delay_tb.v deleted file mode 100644 index 5812068..0000000 --- a/tst_delay_tb.v +++ /dev/null @@ -1,53 +0,0 @@ -// try to figure out how iverilog samples edges -`timescale 1us/1us - -module tst_delay_tb; - -reg clk_i; -reg data_i; -wire data_o; - -tst_delay uut ( - .clk_i(clk_i), - .data_i(data_i), - .data_o(data_o) -); - -string filename; -initial begin -`ifdef DUMP_FILE_NAME - filename=`DUMP_FILE_NAME; -`else - filename="tst_delay.lxt2"; -`endif - $dumpfile(filename); $dumpvars(); - clk_i = 0; - data_i = 0; -end - -always #10 clk_i = ~clk_i; - -initial begin - #9 - data_i = 1; - #2 - data_i = 0; - - /* verilator lint_off INITIALDLY */ - // note the <= assignment - #19 - data_i <= 1; - /* verilator lint_on INITIALDLY */ - - #1 - data_i = 0; - // note the = assignment - #19 - data_i = 1; - #1 - data_i = 0; - #40 - $finish(); -end - -endmodule -- cgit v1.2.3