hdl.ast: add Past, Stable, Rose, Fell.

This commit is contained in:
whitequark 2019-01-17 04:31:27 +00:00
parent 16f90d3585
commit 8c96675580
6 changed files with 112 additions and 9 deletions

View file

@ -10,7 +10,8 @@ from ..tools import *
__all__ = [
"Value", "Const", "C", "AnyConst", "AnySeq", "Operator", "Mux", "Part", "Slice", "Cat", "Repl",
"Array", "ArrayProxy", "Sample",
"Array", "ArrayProxy",
"Sample", "Past", "Stable", "Rose", "Fell",
"Signal", "ClockSignal", "ResetSignal",
"Statement", "Assign", "Assert", "Assume", "Switch", "Delay", "Tick",
"Passive", "ValueKey", "ValueDict", "ValueSet", "SignalKey", "SignalDict",
@ -471,10 +472,10 @@ class Cat(Value):
return sum(len(part) for part in self.parts), False
def _lhs_signals(self):
return union(part._lhs_signals() for part in self.parts)
return union((part._lhs_signals() for part in self.parts), start=ValueSet())
def _rhs_signals(self):
return union(part._rhs_signals() for part in self.parts)
return union((part._rhs_signals() for part in self.parts), start=ValueSet())
def _as_const(self):
value = 0
@ -832,9 +833,15 @@ class ArrayProxy(Value):
class Sample(Value):
def __init__(self, value, clocks, domain):
"""Value from the past.
A ``Sample`` of an expression is equal to the value of the expression ``clocks`` clock edges
of the ``domain`` clock back. If that moment is before the beginning of time, it is equal
to the value of the expression calculated as if each signal had its reset value.
"""
def __init__(self, expr, clocks, domain):
super().__init__(src_loc_at=1)
self.value = Value.wrap(value)
self.value = Value.wrap(expr)
self.clocks = int(clocks)
self.domain = domain
if not isinstance(self.value, (Const, Signal)):
@ -855,6 +862,22 @@ class Sample(Value):
self.value, "<default>" if self.domain is None else self.domain, self.clocks)
def Past(expr, clocks=1, domain=None):
return Sample(expr, clocks, domain)
def Stable(expr, clocks=0, domain=None):
return Sample(expr, clocks + 1, domain) == Sample(expr, clocks, domain)
def Rose(expr, clocks=0, domain=None):
return ~Sample(expr, clocks + 1, domain) & Sample(expr, clocks, domain)
def Fell(expr, clocks=0, domain=None):
return Sample(expr, clocks + 1, domain) & ~Sample(expr, clocks, domain)
class _StatementList(list):
def __repr__(self):
return "({})".format(" ".join(map(repr, self)))

View file

@ -353,6 +353,7 @@ class Module(_ModuleBuilderRoot):
"Only assignments, asserts, and assumes may be appended to d.{}"
.format(domain_name(domain)))
assign = SampleDomainInjector(domain)(assign)
for signal in assign._lhs_signals():
if signal not in self._driving:
self._driving[signal] = domain
@ -384,7 +385,8 @@ class Module(_ModuleBuilderRoot):
fragment = Fragment()
for submodule, name in self._submodules:
fragment.add_subfragment(submodule.get_fragment(platform), name)
fragment.add_statements(self._statements)
statements = SampleDomainInjector("sync")(self._statements)
fragment.add_statements(statements)
for signal, domain in self._driving.items():
fragment.add_driver(signal, domain)
fragment.add_domains(self._domains)

View file

@ -363,9 +363,9 @@ class Fragment:
SignalSet(self.iter_ports("io")))
def prepare(self, ports=(), ensure_sync_exists=True):
from .xfrm import FragmentTransformer
from .xfrm import SampleLowerer
fragment = FragmentTransformer()(self)
fragment = SampleLowerer()(self)
fragment._propagate_domains(ensure_sync_exists)
fragment._resolve_hierarchy_conflicts()
fragment = fragment._insert_domain_resets()

View file

@ -13,7 +13,8 @@ from .rec import *
__all__ = ["ValueVisitor", "ValueTransformer",
"StatementVisitor", "StatementTransformer",
"FragmentTransformer",
"DomainRenamer", "DomainLowerer", "SampleLowerer",
"DomainRenamer", "DomainLowerer",
"SampleDomainInjector", "SampleLowerer",
"SwitchCleaner", "LHSGroupAnalyzer", "LHSGroupFilter",
"ResetInserter", "CEInserter"]
@ -340,6 +341,19 @@ class DomainLowerer(FragmentTransformer, ValueTransformer, StatementTransformer)
return cd.rst
class SampleDomainInjector(ValueTransformer, StatementTransformer):
def __init__(self, domain):
self.domain = domain
def on_Sample(self, value):
if value.domain is not None:
return value
return Sample(value.value, value.clocks, self.domain)
def __call__(self, stmts):
return self.on_statement(stmts)
class SampleLowerer(FragmentTransformer, ValueTransformer, StatementTransformer):
def __init__(self):
self.sample_cache = ValueDict()