Variable Attributes

AVL provides similar functionality to the UVM field macros, without the unnecessary verbosity.

The is also avoids the long running arguments over whether the user should use the macros or not.

Only the most common attributes are supported, and the user is encouraged to use the Pythonic way of setting attributes.

  • Automatic inclusion in class comparison

  • Custom string formatting

Attributes can be:

Note

AVL implements no additional functionality to support copying.

If a user wishes to copy a class or variable the should follow the well understood Python copy library.

Naming Conventions

To keep things simple, all variables beginning with an underscore (“_”) are considered private and should not be accessed directly. Equally all private variables are excluded from all in-built support functions

This rule has been applied to all AVL base classes.

Printing / String Formatting

When using avl.Var variables, the user can set the string formatting of the variable as part of the class constructor.

For regualar Python variables the default string representation is used, unless a specific string format it registered.

By default all non-private class variables are included in the string representation of an avl.Object class.

AVL uses Tabulate to format the string representation of a class. By default the table is formatted using the “grid” format, but the user can customize.

However, not all tabulate table format support sub-tables nicely. The following formats are shown in the example below to work nicely and can be set by calling Object.set_table_fmt:

Format

grid (default)

fancy_grid

simple_grid

presto

psql

orgtbl

rst

jira

# Copyright 2024 Apheleia
#
# Description:
# Apheleia attributes example


import avl
import cocotb


class example_env(avl.Env):
    def __init__(self, name, parent):
        super().__init__(name, parent)

        # Python variables
        self.dec_var = 100
        self.hex_var = 100
        self.custom_var = 100
        self.hex_list = [100, 200, 300]
        self.hex_dict = {"A": 100, "B": 200, "C": 300}
        self.list_list = [[0,1], [2,3], [4,5]]
        self.simple_dict = {"A": 1, "B": 2, "C": 3}
        self.list_dict = {"X" : ["a", "b"], "Y" : [0]}
        self.mixed = [{"dict" : ["value1", "value2"]}, ["list0", "list1", avl.Uint32(100, fmt=bin)]]
        self.obj = avl.Object("obj", self)

        self.set_field_attributes("hex_var", fmt=hex)
        self.set_field_attributes("hex_list", fmt=hex)
        self.set_field_attributes("hex_dict", fmt=hex)
        self.set_field_attributes("custom_var", fmt=self.custom_fmt)

    def custom_fmt(self, value):
        return f"custom_var={value}"


@cocotb.test
async def test(dut):
    e = example_env("env", None)

    for f in [e._table_fmt_, "fancy_grid", "presto", "simple_grid", "psql", "orgtbl", "rst", "jira"]:
      print(f"\n\n{f}:\n\n")
      e.set_table_fmt(fmt=f)
      print(e)

    # Stick to grid - show transpose
    e.set_table_fmt(fmt="grid", transpose=True)
    print(e)

    # Show recurse
    e.set_table_fmt(recurse=False)
    print(e)

Expected output (grid format):

+-------------+----------------+
| name        | env            |
+-------------+----------------+
| dec_var     | 100            |
+-------------+----------------+
| hex_var     | 0x64           |
+-------------+----------------+
| custom_var  | custom_var=100 |
+-------------+----------------+
| hex_list    | 0x64           |
|             | 0xc8           |
|             | 0x12c          |
+-------------+----------------+
| hex_dict    | A: 0x64        |
|             | B: 0xc8        |
|             | C: 0x12c       |
+-------------+----------------+
| list_list   | -              |
|             |   0            |
|             |   1            |
|             | -              |
|             |   2            |
|             |   3            |
|             | -              |
|             |   4            |
|             |   5            |
+-------------+----------------+
| simple_dict | A: 1           |
|             | B: 2           |
|             | C: 3           |
+-------------+----------------+
| list_dict   | X:             |
|             |   a            |
|             |   b            |
|             | Y:             |
|             |   0            |
+-------------+----------------+
| mixed       | -              |
|             |   dict:        |
|             |     value1     |
|             |     value2     |
|             | -              |
|             |   list0        |
|             |   list1        |
|             |   0b1100100    |
+-------------+----------------+
| obj         | +------+-----+ |
|             | | name | obj | |
|             | +------+-----+ |
+-------------+----------------+

Transposing

Depending on the class contents to may be useful to transpose the table representation of the class. This can be done by setting the transpose argument to True when calling Object.set_table_fmt.

Expected output (grid format):

+------+---------+---------+----------------+----------+----------+-----------+-------------+-----------+-------------+----------------+
| name | dec_var | hex_var | custom_var     | hex_list | hex_dict | list_list | simple_dict | list_dict | mixed       | obj            |
+------+---------+---------+----------------+----------+----------+-----------+-------------+-----------+-------------+----------------+
| env  | 100     | 0x64    | custom_var=100 | 0x64     | A: 0x64  | -         | A: 1        | X:        | -           | +------+-----+ |
|      |         |         |                | 0xc8     | B: 0xc8  |   0       | B: 2        |   a       |   dict:     | | name | obj | |
|      |         |         |                | 0x12c    | C: 0x12c |   1       | C: 3        |   b       |     value1  | +------+-----+ |
|      |         |         |                |          |          | -         |             | Y:        |     value2  |                |
|      |         |         |                |          |          |   2       |             |   0       | -           |                |
|      |         |         |                |          |          |   3       |             |           |   list0     |                |
|      |         |         |                |          |          | -         |             |           |   list1     |                |
|      |         |         |                |          |          |   4       |             |           |   0b1100100 |                |
|      |         |         |                |          |          |   5       |             |           |             |                |
+------+---------+---------+----------------+----------+----------+-----------+-------------+-----------+-------------+----------------+

Recursion

AVL supports recursive printing of classes. This is useful when the class contains nested classes or variables. However, this can lead to very large output, so it can be dictated by setting the recurse argument to True when calling Object.set_table_fmt.

Expected output (grid format):

+------+---------+---------+----------------+----------+----------+-----------+-------------+-----------+-------------+--------------------------------+
| name | dec_var | hex_var | custom_var     | hex_list | hex_dict | list_list | simple_dict | list_dict | mixed       | obj                            |
+------+---------+---------+----------------+----------+----------+-----------+-------------+-----------+-------------+--------------------------------+
| env  | 100     | 0x64    | custom_var=100 | 0x64     | A: 0x64  | -         | A: 1        | X:        | -           | type(Object) at 0x7a13c9fd3440 |
|      |         |         |                | 0xc8     | B: 0xc8  |   0       | B: 2        |   a       |   dict:     |                                |
|      |         |         |                | 0x12c    | C: 0x12c |   1       | C: 3        |   b       |     value1  |                                |
|      |         |         |                |          |          | -         |             | Y:        |     value2  |                                |
|      |         |         |                |          |          |   2       |             |   0       | -           |                                |
|      |         |         |                |          |          |   3       |             |           |   list0     |                                |
|      |         |         |                |          |          | -         |             |           |   list1     |                                |
|      |         |         |                |          |          |   4       |             |           |   0b1100100 |                                |
|      |         |         |                |          |          |   5       |             |           |             |                                |
+------+---------+---------+----------------+----------+----------+-----------+-------------+-----------+-------------+--------------------------------+

Comparison

By default all non-private class variables are included in the comparison of two avl.Object classes.

In addition a bi-directional comparison is optionally performed (on by default). This ensures that all fields in both classes are compared i.e. if a field is missing from either class the comparison will fail.

# Copyright 2024 Apheleia
#
# Description:
# Apheleia attributes example


import avl
import cocotb


class a(avl.Object):
    def __init__(self, name, parent):
        super().__init__(name, parent)
        self.var_a = 0
        self.var_b = 1
        self.set_field_attributes("var_a", compare=False)


class example_env(avl.Env):
    def __init__(self, name, parent):
        super().__init__(name, parent)

        self.a0 = a("a", self)
        self.a1 = a("a", self)
        self.a1.var_a = 1  # Should generate an error if not for attribute

        assert self.a0.compare(self.a1, verbose=True)


@cocotb.test
async def test(dut):
    example_env("env", None)

Expected output:

0.00ns INFO     cocotb.regression                  running test (1/1)
 0.0ns INFO     None                               Field "name" comparison passed (a == a)
 0.0ns INFO     None                               Field "var_b" comparison passed (1 == 1)
 0.0ns INFO     None                               Field "name" comparison passed (a == a)
 0.0ns INFO     None                               Field "var_b" comparison passed (1 == 1)
0.00ns INFO     cocotb.regression                  test passed