You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			73 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			73 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			Python
		
	
from collections import OrderedDict
 | 
						|
 | 
						|
from amaranth import *
 | 
						|
from amaranth.asserts import *
 | 
						|
from amaranth.utils import bits_for
 | 
						|
 | 
						|
 | 
						|
__all__ = ["Trigger", "Testbench"]
 | 
						|
 | 
						|
 | 
						|
class Trigger:
 | 
						|
    def __init__(self, cycle, name=None, src_loc_at=0):
 | 
						|
        if not isinstance(cycle, int) or cycle <= 0:
 | 
						|
            raise ValueError("Clock cycle must be a positive integer, not {!r}"
 | 
						|
                             .format(cycle))
 | 
						|
 | 
						|
        self.stb   = Signal(name=name, src_loc_at=1 + src_loc_at)
 | 
						|
        self.cycle = cycle
 | 
						|
 | 
						|
 | 
						|
class Testbench(Elaboratable):
 | 
						|
    def __init__(self, spec, dut):
 | 
						|
        self.spec = spec
 | 
						|
        self.dut  = dut
 | 
						|
 | 
						|
        self._triggers  = OrderedDict()
 | 
						|
        self._bmc_depth = None
 | 
						|
        self._frozen    = False
 | 
						|
 | 
						|
        for trigger in spec.triggers():
 | 
						|
            self.add_trigger(trigger)
 | 
						|
 | 
						|
    def freeze(self):
 | 
						|
        if not self._frozen:
 | 
						|
            self._bmc_depth = max(t.cycle for t in self.triggers()) + 1
 | 
						|
            self._frozen    = True
 | 
						|
 | 
						|
    def add_trigger(self, trigger):
 | 
						|
        if self._frozen:
 | 
						|
            raise ValueError("Testbench is frozen.")
 | 
						|
        if not isinstance(trigger, Trigger):
 | 
						|
            raise TypeError("Trigger must be an instance of Trigger, not {!r}"
 | 
						|
                            .format(trig))
 | 
						|
        self._triggers[id(trigger)] = trigger
 | 
						|
 | 
						|
    def triggers(self):
 | 
						|
        yield from self._triggers.values()
 | 
						|
 | 
						|
    @property
 | 
						|
    def bmc_depth(self):
 | 
						|
        self.freeze()
 | 
						|
        return self._bmc_depth
 | 
						|
 | 
						|
    def elaborate(self, platform):
 | 
						|
        m = Module()
 | 
						|
 | 
						|
        cycle = Signal(range(self.bmc_depth), reset=1)
 | 
						|
 | 
						|
        with m.If(cycle < self.bmc_depth - 1):
 | 
						|
            m.d.sync += cycle.eq(cycle + 1)
 | 
						|
 | 
						|
        for trigger in self.triggers():
 | 
						|
            m.d.comb += trigger.stb.eq(cycle == trigger.cycle)
 | 
						|
 | 
						|
        m.submodules.spec = self.spec
 | 
						|
        m.submodules.dut  = self.dut
 | 
						|
 | 
						|
        m.d.comb += self.spec.pfv.eq(self.dut.pfv)
 | 
						|
 | 
						|
        m.d.comb += Assume(ResetSignal() == Initial())
 | 
						|
 | 
						|
        return m
 |