Skip to content

Commit

Permalink
feat: factory test module
Browse files Browse the repository at this point in the history
  • Loading branch information
htfab authored and urish committed Sep 7, 2024
1 parent c68e70e commit a322f31
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 79 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -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)

Expand Down
24 changes: 19 additions & 5 deletions docs/info.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`).
60 changes: 30 additions & 30 deletions info.yaml
Original file line number Diff line number Diff line change
@@ -1,55 +1,55 @@
# 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)

# How many tiles your design occupies? A single tile is about 167x108 uM.
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
27 changes: 0 additions & 27 deletions src/project.v

This file was deleted.

40 changes: 40 additions & 0 deletions src/tt_um_factory_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* tt_um_factory_test.v
*
* Test user module
*
* Author: Sylvain Munaut <[email protected]>
*/

`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
2 changes: 1 addition & 1 deletion test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
4 changes: 2 additions & 2 deletions test/tb.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
58 changes: 45 additions & 13 deletions test/test.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# SPDX-FileCopyrightText: © 2024 Tiny Tapeout
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT

import cocotb
from cocotb.clock import Clock
from cocotb.triggers import ClockCycles


@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)
Expand All @@ -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

0 comments on commit a322f31

Please sign in to comment.