diff --git a/README.md b/README.md index 68ba6ed..616cc3f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![](../../workflows/gds/badge.svg) ![](../../workflows/docs/badge.svg) ![](../../workflows/test/badge.svg) ![](../../workflows/fpga/badge.svg) -# Tiny Tapeout Verilog Project Template +# Tiny Tapeout Factory Test - [Read the documentation for project](docs/info.md) diff --git a/docs/info.md b/docs/info.md index ce1f04c..708a95f 100644 --- a/docs/info.md +++ b/docs/info.md @@ -9,12 +9,26 @@ You can also include images in this folder and reference them in the markdown. E ## How it works -Explain how your project works +The factory test module is a simple module that can be used to test all the I/O pins of the ASIC. -## How to test +It has three modes of operation: + +1. Mirroring the input pins to the output pins (when `rst_n` is low). +2. Mirroring the bidirectional pins to the output pins (when `rst_n` is high `sel` is low). +3. Outputing a counter on the output pins and the bidirectional pins (when `rst_n` is high and `sel` is high). + +The following table summarizes the modes: -Explain how to use your project +| `rst_n` | `sel` | Mode | uo_out value | uio pins | +|---------|-------|----------------------|--------------|----------| +| 0 | X | Input mirror | ui_in | High-Z | +| 1 | 0 | Bidirectional mirror | uio_in | High-Z | +| 1 | 1 | Counter | counter | counter | -## External hardware +The counter is an 8-bit counter that increments on every clock cycle, and resets when `rst_n` is low. + +## How to test -List external hardware used in your project (e.g. PMOD, LED display, etc), if any +1. Set `rst_n` low and observe that the input pins (`ui_in`) are output on the output pins (`uo_out`). +2. Set `rst_n` high and `sel` low and observe that the bidirectional pins (`uio_in`) are output on the output pins (`uo_out`). +3. Set `sel` high and observe that the counter is output on both the output pins (`uo_out`) and the bidirectional pins (`uio`). diff --git a/info.yaml b/info.yaml index 50bb751..cfe0405 100644 --- a/info.yaml +++ b/info.yaml @@ -1,9 +1,9 @@ # Tiny Tapeout project information project: - title: "" # Project title - author: "" # Your name - discord: "" # Your discord username, for communication and automatically assigning you a Tapeout role (optional) - description: "" # One line description of what your project does + title: "TinyTapeout 8 Factory Test" # Project title + author: "Tiny Tapeout" # Your name + discord: "" # Your discord username, for communication and automatically assigning you a Tapeout role (optional) + description: "Factory test module" # One line description of what your project does language: "Verilog" # other examples include SystemVerilog, Amaranth, VHDL, etc clock_hz: 0 # Clock frequency in Hz (or 0 if not applicable) @@ -11,45 +11,45 @@ project: tiles: "1x1" # Valid values: 1x1, 1x2, 2x2, 3x2, 4x2, 6x2 or 8x2 # Your top module name must start with "tt_um_". Make it unique by including your github username: - top_module: "tt_um_example" + top_module: "tt_um_factory_test" # List your project's source files here. # Source files must be in ./src and you must list each source file separately, one per line. # Don't forget to also update `PROJECT_SOURCES` in test/Makefile. source_files: - - "project.v" + - "tt_um_factory_test.v" # The pinout of your project. Leave unused pins blank. DO NOT delete or add any pins. pinout: # Inputs - ui[0]: "" - ui[1]: "" - ui[2]: "" - ui[3]: "" - ui[4]: "" - ui[5]: "" - ui[6]: "" - ui[7]: "" + ui[0]: "sel / in_a[0]" + ui[1]: "in_a[1]" + ui[2]: "in_a[2]" + ui[3]: "in_a[3]" + ui[4]: "in_a[4]" + ui[5]: "in_a[5]" + ui[6]: "in_a[6]" + ui[7]: "in_a[7]" # Outputs - uo[0]: "" - uo[1]: "" - uo[2]: "" - uo[3]: "" - uo[4]: "" - uo[5]: "" - uo[6]: "" - uo[7]: "" + uo[0]: "output[0] / counter[0]" + uo[1]: "output[1] / counter[1]" + uo[2]: "output[2] / counter[2]" + uo[3]: "output[3] / counter[3]" + uo[4]: "output[4] / counter[4]" + uo[5]: "output[5] / counter[5]" + uo[6]: "output[6] / counter[6]" + uo[7]: "output[7] / counter[7]" # Bidirectional pins - uio[0]: "" - uio[1]: "" - uio[2]: "" - uio[3]: "" - uio[4]: "" - uio[5]: "" - uio[6]: "" - uio[7]: "" + uio[0]: "in_b[0] / counter[0]" + uio[1]: "in_b[1] / counter[1]" + uio[2]: "in_b[2] / counter[2]" + uio[3]: "in_b[3] / counter[3]" + uio[4]: "in_b[4] / counter[4]" + uio[5]: "in_b[5] / counter[5]" + uio[6]: "in_b[6] / counter[6]" + uio[7]: "in_b[7] / counter[7]" # Do not change! yaml_version: 6 diff --git a/src/project.v b/src/project.v deleted file mode 100644 index cd6f740..0000000 --- a/src/project.v +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2024 Your Name - * SPDX-License-Identifier: Apache-2.0 - */ - -`default_nettype none - -module tt_um_example ( - input wire [7:0] ui_in, // Dedicated inputs - output wire [7:0] uo_out, // Dedicated outputs - input wire [7:0] uio_in, // IOs: Input path - output wire [7:0] uio_out, // IOs: Output path - output wire [7:0] uio_oe, // IOs: Enable path (active high: 0=input, 1=output) - input wire ena, // always 1 when the design is powered, so you can ignore it - input wire clk, // clock - input wire rst_n // reset_n - low to reset -); - - // All output pins must be assigned. If not used, assign to 0. - assign uo_out = ui_in + uio_in; // Example: ou_out is the sum of ui_in and uio_in - assign uio_out = 0; - assign uio_oe = 0; - - // List all unused inputs to prevent warnings - wire _unused = &{ena, clk, rst_n, 1'b0}; - -endmodule diff --git a/src/tt_um_factory_test.v b/src/tt_um_factory_test.v new file mode 100644 index 0000000..4fb10d7 --- /dev/null +++ b/src/tt_um_factory_test.v @@ -0,0 +1,40 @@ +/* + * tt_um_factory_test.v + * + * Test user module + * + * Author: Sylvain Munaut + */ + +`default_nettype none + +module tt_um_factory_test ( + input wire [7:0] ui_in, // Dedicated inputs + output wire [7:0] uo_out, // Dedicated outputs + input wire [7:0] uio_in, // IOs: Input path + output wire [7:0] uio_out, // IOs: Output path + output wire [7:0] uio_oe, // IOs: Enable path (active high: 0=input, 1=output) + input wire ena, // always 1 when the design is powered, so you can ignore it + input wire clk, // clock + input wire rst_n // reset_n - low to reset +); + + reg rst_n_i; + reg [7:0] cnt; + + always @(posedge clk or negedge rst_n) + if (~rst_n) rst_n_i <= 1'b0; + else rst_n_i <= 1'b1; + + always @(posedge clk or negedge rst_n_i) + if (~rst_n_i) cnt <= 0; + else cnt <= cnt + 1; + + assign uo_out = ~rst_n ? ui_in : ui_in[0] ? cnt : uio_in; + assign uio_out = ui_in[0] ? cnt : 8'h00; + assign uio_oe = rst_n && ui_in[0] ? 8'hff : 8'h00; + + // avoid linter warning about unused pins: + wire _unused_pins = ena; + +endmodule // tt_um_factory_test diff --git a/test/Makefile b/test/Makefile index 6fdbe36..6b00eac 100644 --- a/test/Makefile +++ b/test/Makefile @@ -5,7 +5,7 @@ SIM ?= icarus TOPLEVEL_LANG ?= verilog SRC_DIR = $(PWD)/../src -PROJECT_SOURCES = project.v +PROJECT_SOURCES = tt_um_factory_test.v ifneq ($(GATES),yes) diff --git a/test/tb.v b/test/tb.v index 2fc848c..65a69e6 100644 --- a/test/tb.v +++ b/test/tb.v @@ -23,8 +23,8 @@ module tb (); wire [7:0] uio_out; wire [7:0] uio_oe; - // Replace tt_um_example with your module name: - tt_um_example user_project ( + // Replace tt_um_factory_test with your module name: + tt_um_factory_test user_project ( // Include power ports for the Gate Level test: `ifdef GL_TEST diff --git a/test/test.py b/test/test.py index fa7f92c..e7b8cdd 100644 --- a/test/test.py +++ b/test/test.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: © 2024 Tiny Tapeout -# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT import cocotb from cocotb.clock import Clock @@ -7,7 +7,7 @@ @cocotb.test() -async def test_project(dut): +async def test_loopback(dut): dut._log.info("Start") # Set the clock period to 10 us (100 KHz) @@ -17,24 +17,56 @@ async def test_project(dut): # Reset dut._log.info("Reset") dut.ena.value = 1 + + # ui_in[0] == 0: Output is uio_in dut.ui_in.value = 0 dut.uio_in.value = 0 dut.rst_n.value = 0 await ClockCycles(dut.clk, 10) dut.rst_n.value = 1 - dut._log.info("Test project behavior") - - # Set the input values you want to test - dut.ui_in.value = 20 - dut.uio_in.value = 30 + for i in range(256): + dut.uio_in.value = i + await ClockCycles(dut.clk, 1) + assert dut.uo_out.value == i - # Wait for one clock cycle to see the output values + # When under reset: Output is uio_in, uio is in input mode + dut.rst_n.value = 0 await ClockCycles(dut.clk, 1) + assert dut.uio_oe.value == 0 + for i in range(256): + dut.ui_in.value = i + await ClockCycles(dut.clk, 1) + assert dut.uo_out.value == i + +@cocotb.test() +async def test_counter(dut): + dut._log.info("Start") + + # Set the clock period to 10 us (100 KHz) + clock = Clock(dut.clk, 10, units="us") + cocotb.start_soon(clock.start()) - # The following assersion is just an example of how to check the output values. - # Change it to match the actual expected output of your module: - assert dut.uo_out.value == 50 + # ui_in[0] == 1: bidirectional outputs enabled, put a counter on both output and bidirectional pins + dut.ui_in.value = 1 + dut.uio_in.value = 0 + dut.rst_n.value = 0 + await ClockCycles(dut.clk, 10) + dut.rst_n.value = 1 + await ClockCycles(dut.clk, 2) - # Keep testing the module by changing the input values, waiting for - # one or more clock cycles, and asserting the expected output values. + dut._log.info("Testing counter") + for i in range(256): + assert dut.uo_out.value == dut.uio_out.value + assert dut.uo_out.value == i + await ClockCycles(dut.clk, 1) + + dut._log.info("Testing reset") + for i in range(5): + assert dut.uo_out.value == i + await ClockCycles(dut.clk, 1) + dut.rst_n.value = 0 + await ClockCycles(dut.clk, 2) + dut.rst_n.value = 1 + await ClockCycles(dut.clk, 1) + assert dut.uo_out.value == 0