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