AVL Templates
One of the biggest obstacles with UVM is the sheer amount of code required to construct simple testbenches.
Using templates, AVL aims to reduce this overhead without enforcing a specific structure, or methodology on the user.
By default AVL provides a avl.Templates.vanilla template for an environment, containing a configurable number of agents and a scoreboard. Each of the agents can be configured to be active or passive.
By overriding variables and types using the factory a testbench can be created with minimal effort and code.
Example
The provided adder example shows how simple it is to extend a template to create a testbench.
# Copyright 2024 Apheleia
#
# Description:
# Apheleia phase example
import avl
import avl.templates
import cocotb
from cocotb.triggers import RisingEdge
class adder_item(avl.SequenceItem):
def __init__(self, name, parent_sequence):
super().__init__(name, parent_sequence)
self.a = avl.Uint8(0, fmt=str)
self.b = avl.Uint8(0, fmt=str)
self.c = avl.Logic(0, fmt=str, auto_random=False, width=9)
def randomize(self):
super().randomize()
self.c.value = self.a.value + self.b.value
class adder_driver(avl.templates.VanillaDriver):
async def reset(self):
self.hdl.valid_in.value = 0
self.hdl.a.value = 0
self.hdl.b.value = 0
async def clear(self):
await RisingEdge(self.clk)
await self.reset()
async def run_phase(self):
await self.reset()
await RisingEdge(self.hdl.clk)
while True:
item = await self.seq_item_port.blocking_get()
while True:
await RisingEdge(self.hdl.clk)
if self.rst.value == 0:
await self.reset()
else:
break
self.hdl.valid_in.value = 1
self.hdl.a.value = item.a.value
self.hdl.b.value = item.b.value
item.set_event("done")
cocotb.start_soon(self.clear())
class adder_monitor(avl.templates.VanillaMonitor):
async def collect_result(self, item):
await RisingEdge(self.hdl.clk)
if self.hdl.valid_out.value != 1:
self.error(f"Expected valid_out to be 1, got {self.hdl.valid_out.value}")
item.c.value = int(self.hdl.c.value)
self.item_export.write(item)
async def run_phase(self):
while True:
await RisingEdge(self.clk)
if self.rst.value == 0:
continue
if self.hdl.valid_in.value == 1:
item = adder_item("item", None)
item.a.value = int(self.hdl.a.value)
item.b.value = int(self.hdl.b.value)
cocotb.start_soon(self.collect_result(item))
@cocotb.test
async def test(dut):
# Create the environment
avl.Factory.set_variable("*.hdl", dut)
avl.Factory.set_variable("*.clk", dut.clk)
avl.Factory.set_variable("*.rst", dut.rst_n)
avl.Factory.set_variable("env.cfg.timeout_ns", 100000)
avl.Factory.set_variable("*.n_items", 1000)
avl.Factory.set_override_by_type(avl.templates.VanillaDriver, adder_driver)
avl.Factory.set_override_by_type(avl.templates.VanillaMonitor, adder_monitor)
avl.Factory.set_override_by_type(avl.SequenceItem, adder_item)
e = avl.templates.VanillaEnv("env", None)
await e.start()