Skip to main content
This guide walks you through the process of adding a new hardware module to the Tiny TPU project, including creating the module, tests, and integrating with the build system.

Overview

Adding a new module involves five main steps:
  1. Create the SystemVerilog module file
  2. Create a dump file for waveform generation
  3. Write cocotb tests
  4. Update the Makefile
  5. Run tests and view waveforms

Step-by-step process

1

Create the module file

Create your new SystemVerilog module in the src/ directory:
touch src/<MODULE_NAME>.sv
Implement your module following the existing code style and conventions in the codebase. Ensure your module:
  • Has clear input/output port definitions
  • Includes proper reset logic
  • Uses the fixed-point format (Q8.8) where applicable
  • Follows SystemVerilog 2012 syntax
2

Create the dump file

Create a dump file in the test/ directory to generate VCD waveforms:
test/dump_<MODULE_NAME>.sv
module dump();
initial begin
  $dumpfile("waveforms/<MODULE_NAME>.vcd");
  $dumpvars(0, <MODULE_NAME>);
end
endmodule
This file instructs iverilog to dump all signals from your module to a VCD file for visualization.
3

Create the test file

Create a cocotb test file in the test/ directory:
touch test/test_<MODULE_NAME>.py
Write your tests using cocotb. Here’s a basic template:
test/test_<MODULE_NAME>.py
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, ClockCycles

def to_fixed(val, frac_bits=8):
    return int(round(val * (1 << frac_bits))) & 0xFFFF

def from_fixed(val, frac_bits=8):
    if val >= (1 << 15):
        val -= (1 << 16)
    return float(val) / (1 << frac_bits)

@cocotb.test()
async def test_<MODULE_NAME>(dut):
    """Test your module."""
    
    # Create clock
    clock = Clock(dut.clk, 10, units="ns")
    cocotb.start_soon(clock.start())
    
    # Reset
    dut.rst.value = 1
    await RisingEdge(dut.clk)
    dut.rst.value = 0
    await RisingEdge(dut.clk)
    
    # Your test logic here
    # ...
Look at existing test files like test/test_pe.py for examples of comprehensive testing patterns.
4

Update the Makefile

Add your module to the build system by editing the Makefile:1. Add to SOURCES variable:
Makefile
SOURCES = src/pe.sv \
          src/systolic.sv \
          src/<MODULE_NAME>.sv \
          # ... other sources
2. Create a test target:
Makefile
test_<MODULE_NAME>: $(SIM_BUILD_DIR)
	$(IVERILOG) -o $(SIM_VVP) -s <MODULE_NAME> -s dump -g2012 $(SOURCES) test/dump_<MODULE_NAME>.sv
	PYTHONOPTIMIZE=$(NOASSERT) MODULE=test_<MODULE_NAME> $(VVP) -M $(COCOTB_LIBS) -m libcocotbvpi_icarus $(SIM_VVP)
	! grep failure results.xml
	mv <MODULE_NAME>.vcd waveforms/ 2>/dev/null || true
Make sure to use tabs (not spaces) for indentation in Makefile targets.
5

Run the test

Build and test your new module:
make test_<MODULE_NAME>
The test will:
  • Compile your module with iverilog
  • Run the cocotb test
  • Generate a VCD waveform file
  • Check for test failures in results.xml
6

View waveforms

After the test completes successfully, view the generated waveforms:
gtkwave waveforms/<MODULE_NAME>.vcd
Or use the Makefile shorthand:
make show_<MODULE_NAME>
See the waveforms guide for tips on configuring GTKwave for fixed-point viewing.

Example modules

Here are some existing modules you can reference:
  • src/pe.sv - Processing Element (simple module)
  • src/systolic.sv - Systolic Array (complex module with multiple instances)
  • src/vpu.sv - Vector Processing Unit (module with sub-components)
  • src/unified_buffer.sv - Unified Buffer (memory module)

Best practices

All arithmetic in Tiny TPU uses Q8.8 fixed-point format (8 integer bits, 8 fractional bits). Use the helper functions in tests:
  • to_fixed(val) - Convert float to fixed-point
  • from_fixed(val) - Convert fixed-point to float
Write tests that cover:
  • Normal operation
  • Edge cases (zero, negative, maximum values)
  • Reset behavior
  • Pipeline stages and timing
  • Module files: <module_name>.sv
  • Test files: test_<module_name>.py
  • Dump files: dump_<module_name>.sv
  • Makefile targets: test_<module_name>
Add comments in your SystemVerilog code explaining:
  • Module purpose and function
  • Port descriptions
  • Pipeline stages
  • Timing requirements

Next steps

Testing

Learn more about the testing framework

Waveforms

Configure GTKwave for better visualization

Build docs developers (and LLMs) love