Ideas on how to create factory for blocks/ signals

Hi ,

Suppose I have 3 myhdl.blocks dut1, dut2, dut3, of which I want to test many times in various combinations. Each of the duts take several signal arguments (have several ports). My problem is this. While creating the tests, I have to initialize the signals and instantiate the blocks repeatedly, and this leads to code duplication. For example,

I’d like some ideas on how to make a factory function that automatically does all the initializations and instantiations, so that I can just call factory_func(), return all the signals and blocks, and then write my test.

Here is what I did:

Is this acceptable?

Personally, I won’t combine the definition of my top-level ports
with the tests in the class. I would simply define the signals
in a class and define the tests outside. You will need to duplicate
the dut instatiation but that is minor.

Often what I will do is create a dictionary of the top-level ports
to be used:

myblock_portmap = dict(sig1=Signal(bool(0)), ...)

and then in the test simply resuse the dict

tbdut = myblock(**myblock_portmap)

The top-level ports are only defined onces and the instantiation
is minimal (not a big deal to repeat).

The above can be used in multiple tests, this will have some down
sides in that the signals might not be reinitialized. Depending
on the usage you could run into trouble.

In you case you would want to some thing slightly different where
you have a signal in multiple portmaps:

sig1 = Signal()
blk1_portmap = dict(sig1=sig1, sig3=Signal())
blk2_portmap = dict(sig1=sig1, sig2=Signal())

My usage typically is slightly different, I often attached a
default dictionary portmap to the blocks and subblocks

myblock.portmap = dict(...)

This portmap is fixed (static) it works well for top-levels that
are specific to a certain hardware but not as useful for subblocks
where the ports are more dynamic. In addition, I will use a
thin PortMap object

class PortMap(dict):
    def __init__(self, **ports):
        for k, v in ports.items():
            self.__dict__[k] = v
        super(PortMap, self).__init__(**ports)

# usage in the test
pm = portmap = PortMap(sig1=Signal(bool(0)), sig3=Signal(bool(0)))
dut = myblock(**portmap)

@instance
def tbstim():
    pm.sig1.next = False
    pm.sig3.next = True

I faced the same issue. I looked into pytest fixtures for it. https://pytest.org/latest/fixture.html

My code after using it: https://github.com/ravijain056/GEMAC/blob/dev/test/test_mangement.py

@cfelton Whats your say on using fixtures? Please review the code.

@Ravi_Jain yes, I think using the test fixture is a reasonable approach.