Separate LFSR tests; test only main module
uio[4]: ""
uio[5]: ""
uio[6]: ""
- uio[7]: ""
+ uio[7]: "audio (output)"
# Do not change!
yaml_version: 6
} = str;
chargen chargen(
- .x(x + char_idx * 64),
+ .x(x + char_idx * 10'd64),
.y(y),
.character(str_chars[char_idx]),
.hpos(hpos),
assign words[3] = {C_T, C_A, C_E, C_P, C_E, C_R};
text text_gen(
- .x(100),
- .y(280),
+ .x(10'd100),
+ .y(10'd280),
.str(words[selector]),
.hpos(hpos),
.vpos(vpos),
+# Makefile
+# See https://docs.cocotb.org/en/stable/quickstart.html for more info
+
+# defaults
+SIM ?= icarus
+TOPLEVEL_LANG ?= verilog
+SRC_DIR = $(PWD)/../src
+PROJECT_SOURCES = project.v
+
+ifneq ($(GATES),yes)
+
+# RTL simulation:
+SIM_BUILD = sim_build/rtl
+VERILOG_SOURCES += $(addprefix $(SRC_DIR)/,$(PROJECT_SOURCES))
+COMPILE_ARGS += -I$(SRC_DIR)
+
+else
+
+# Gate level simulation:
+SIM_BUILD = sim_build/gl
+COMPILE_ARGS += -DGL_TEST
+COMPILE_ARGS += -DFUNCTIONAL
+COMPILE_ARGS += -DUSE_POWER_PINS
+COMPILE_ARGS += -DSIM
+COMPILE_ARGS += -DUNIT_DELAY=\#1
+VERILOG_SOURCES += $(PDK_ROOT)/sky130A/libs.ref/sky130_fd_sc_hd/verilog/primitives.v
+VERILOG_SOURCES += $(PDK_ROOT)/sky130A/libs.ref/sky130_fd_sc_hd/verilog/sky130_fd_sc_hd.v
+
+# this gets copied in by the GDS action workflow
+VERILOG_SOURCES += $(PWD)/gate_level_netlist.v
+
+endif
+
+# Include the testbench sources:
+VERILOG_SOURCES += $(PWD)/tb_lfsr.v
+TOPLEVEL = tb_lfsr
+
+# MODULE is the basename of the Python test file
+MODULE = test_lfsr
+
+# include cocotb's make rules to take care of the simulator setup
+include $(shell cocotb-config --makefiles)/Makefile.sim
[*]
[*] GTKWave Analyzer v3.4.0 (w)1999-2022 BSI
-[*] Wed Aug 28 04:41:58 2024
+[*] Thu Aug 29 04:46:09 2024
[*]
[dumpfile] "/home/chip/projects/tinytapeout/munch/test/tb.vcd"
-[dumpfile_mtime] "Wed Aug 28 04:34:55 2024"
-[dumpfile_size] 2596520
+[dumpfile_mtime] "Thu Aug 29 04:39:17 2024"
+[dumpfile_size] 163326
[savefile] "/home/chip/projects/tinytapeout/munch/test/tb.gtkw"
[timestart] 0
[size] 1711 925
-[pos] 37 -2
-*-37.534531 30000001 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[pos] -1 -1
+*-17.534531 120000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] tb.
[sst_width] 297
-[signals_width] 230
+[signals_width] 229
[sst_expanded] 1
[sst_vpaned_height] 270
@28
-tb.clock_gen.vsync
-tb.clock_gen.r_atick_clock[2:0]
-tb.clock_gen.audio_tick
-@23
-tb.clock_gen.r_pattern_clock[3:0]
+tb.clk
+tb.rst_n
+@200
+-uo_out
+@28
++{uo_out[7] (HSYNC)} (0)tb.uo_out[7:0]
++{uo_out[6] (B0)} (1)tb.uo_out[7:0]
++{uo_out[5] (G0)} (2)tb.uo_out[7:0]
++{uo_out[4] (R0)} (3)tb.uo_out[7:0]
++{uo_out[3] (VSYNC)} (4)tb.uo_out[7:0]
++{uo_out[2] (B1)} (5)tb.uo_out[7:0]
++{uo_out[1] (G1)} (6)tb.uo_out[7:0]
++{uo_out[0] (R1)} (7)tb.uo_out[7:0]
+@200
+-uio_out
+@28
++{uio_out[7] (audio)} (0)tb.uio_out[7:0]
[pattern_trace] 1
[pattern_trace] 0
+[*]
+[*] GTKWave Analyzer v3.4.0 (w)1999-2022 BSI
+[*] Thu Aug 29 03:43:44 2024
+[*]
+[dumpfile] "/home/chip/projects/tinytapeout/munch/test/tb_lfsr.vcd"
+[dumpfile_mtime] "Thu Aug 29 03:42:52 2024"
+[dumpfile_size] 147098
+[savefile] "/home/chip/projects/tinytapeout/munch/test/tb_lfsr.gtkw"
+[timestart] 0
+[size] 1340 716
+[pos] -1 -1
+*-17.000000 96300 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 276
+[signals_width] 190
+[sst_expanded] 1
+[sst_vpaned_height] 198
+@28
+tb_lfsr.clk
+tb_lfsr.rst_n
+@23
+tb_lfsr.lfsr_bits[10:0]
+[pattern_trace] 1
+[pattern_trace] 0
+`default_nettype none
+`timescale 1ns / 1ps
+
+module tb_lfsr ();
+
+ // Dump the signals to a VCD file. You can view it with gtkwave.
+ initial begin
+ $dumpfile("tb_lfsr.vcd");
+ $dumpvars(0, tb_lfsr);
+ #1;
+ end
+
+ // Wire up the inputs and outputs:
+ reg clk;
+ reg rst_n;
+ wire [5:0] bits;
+ wire [10:0] lfsr_bits;
+
+ lfsr lfsr_dev(
+ .clk(clk),
+ .rst_n(rst_n),
+ .bits(bits)
+ );
+
+ assign lfsr_bits = lfsr_dev.lfsr;
+
+endmodule
dut.rst_n.value = 1
@cocotb.test()
-async def test_lfsr(dut):
+async def test_munch(dut):
+ '''
+ Unfortunately this does not test much, as video and audio generation is
+ quite complex. But we do assert a few basic signals at the beginning as a
+ basic sanity check.
+ '''
dut._log.info("Start")
# Set the clock period to 40ns (25MHz)
await reset(dut)
- dut._log.info("Test LFSR module")
+ dut._log.info("Test munch module")
- await ClockCycles(dut.clk, 1)
+ await ClockCycles(dut.clk, 2)
+ # Should be a black pixel at the beginning of scan
+ assert dut.uo_out.value == 0b10001000
+ # Audio is on; PWM output is 50:50 with no output, so this will be high at
+ # the beginning even though two channels are outputting immediately.
+ assert dut.uio_out.value == 0b10000000
- for i in range(1, 2**11 - 1):
- await ClockCycles(dut.clk, 1)
- assert dut.munch.lfsr_dev.lfsr.value != 0
+ await ClockCycles(dut.clk, 3)
+ # Pixel should be black now
+ assert dut.uo_out.value == 0b10001000
- await ClockCycles(dut.clk, 1)
- assert dut.munch.lfsr_dev.lfsr.value == 0
+ # Should put us right at the border between front porch and hsync
+ await ClockCycles(dut.clk, 640 + 16 - 3)
+ assert dut.uo_out.value == 0b00001000
+
+ # border of hsync and back porch
+ await ClockCycles(dut.clk, 96)
+ assert dut.uo_out.value == 0b10001000
+
+ # and back at the beginning of the next line; green pixel again
+ await ClockCycles(dut.clk, 48)
+ assert dut.uo_out.value == 0b10001000
+# SPDX-FileCopyrightText: © 2024 Tiny Tapeout
+# SPDX-License-Identifier: Apache-2.0
+
+import cocotb
+from cocotb.clock import Clock
+from cocotb.triggers import ClockCycles, Timer
+
+async def reset(dut):
+ # Reset
+ dut._log.info("Reset")
+ dut.rst_n.value = 1
+ await ClockCycles(dut.clk, 1);
+ dut.rst_n.value = 0
+ await ClockCycles(dut.clk, 1);
+ dut.rst_n.value = 1
+
+@cocotb.test()
+async def test_lfsr(dut):
+ dut._log.info("Start")
+
+ # Set the clock period to 40ns (25MHz)
+ # Actual clock is 25.175 (39.722ns) but whatever
+ clock = Clock(dut.clk, 40, units="ns")
+ cocotb.start_soon(clock.start())
+
+ await reset(dut)
+
+ dut._log.info("Test LFSR module")
+
+ await ClockCycles(dut.clk, 1)
+
+ for i in range(1, 2**11 - 1):
+ await ClockCycles(dut.clk, 1)
+ assert dut.lfsr_bits.value != 0
+
+ await ClockCycles(dut.clk, 1)
+ assert dut.lfsr_bits.value == 0