hdl.ast,back.rtlil: implement Cover.

Fixes #194.
This commit is contained in:
whitequark 2019-09-03 01:32:24 +00:00
parent 2e20622046
commit 943ce317af
7 changed files with 47 additions and 28 deletions

View file

@ -1,2 +1,2 @@
from .hdl.ast import AnyConst, AnySeq, Assert, Assume from .hdl.ast import AnyConst, AnySeq, Assert, Assume, Cover
from .hdl.ast import Past, Stable, Rose, Fell, Initial from .hdl.ast import Past, Stable, Rose, Fell, Initial

View file

@ -320,6 +320,9 @@ class _StatementCompiler(StatementVisitor):
def on_Assume(self, stmt): def on_Assume(self, stmt):
pass # :nocov: pass # :nocov:
def on_Cover(self, stmt):
raise NotImplementedError("Covers not yet implemented for Simulator backend.") # :nocov:
def on_Switch(self, stmt): def on_Switch(self, stmt):
test = self.rrhs_compiler(stmt.test) test = self.rrhs_compiler(stmt.test)
cases = [] cases = []

View file

@ -654,27 +654,20 @@ class _StatementCompiler(xfrm.StatementVisitor):
else: else:
self._case.assign(self.lhs_compiler(stmt.lhs), rhs_sigspec) self._case.assign(self.lhs_compiler(stmt.lhs), rhs_sigspec)
def on_Assert(self, stmt): def on_property(self, stmt):
self(stmt._check.eq(stmt.test)) self(stmt._check.eq(stmt.test))
self(stmt._en.eq(1)) self(stmt._en.eq(1))
en_wire = self.rhs_compiler(stmt._en) en_wire = self.rhs_compiler(stmt._en)
check_wire = self.rhs_compiler(stmt._check) check_wire = self.rhs_compiler(stmt._check)
self.state.rtlil.cell("$assert", ports={ self.state.rtlil.cell("$" + stmt._kind, ports={
"\\A": check_wire, "\\A": check_wire,
"\\EN": en_wire, "\\EN": en_wire,
}, src=src(stmt.src_loc)) }, src=src(stmt.src_loc))
def on_Assume(self, stmt): on_Assert = on_property
self(stmt._check.eq(stmt.test)) on_Assume = on_property
self(stmt._en.eq(1)) on_Cover = on_property
en_wire = self.rhs_compiler(stmt._en)
check_wire = self.rhs_compiler(stmt._check)
self.state.rtlil.cell("$assume", ports={
"\\A": check_wire,
"\\EN": en_wire,
}, src=src(stmt.src_loc))
def on_Switch(self, stmt): def on_Switch(self, stmt):
self._check_rhs(stmt.test) self._check_rhs(stmt.test)

View file

@ -15,7 +15,7 @@ __all__ = [
"Signal", "ClockSignal", "ResetSignal", "Signal", "ClockSignal", "ResetSignal",
"UserValue", "UserValue",
"Sample", "Past", "Stable", "Rose", "Fell", "Initial", "Sample", "Past", "Stable", "Rose", "Fell", "Initial",
"Statement", "Assign", "Assert", "Assume", "Switch", "Delay", "Tick", "Statement", "Assign", "Assert", "Assume", "Cover", "Switch", "Delay", "Tick",
"Passive", "ValueKey", "ValueDict", "ValueSet", "SignalKey", "SignalDict", "Passive", "ValueKey", "ValueDict", "ValueSet", "SignalKey", "SignalDict",
"SignalSet", "SignalSet",
] ]
@ -1080,6 +1080,11 @@ class Assume(Property):
_kind = "assume" _kind = "assume"
@final
class Cover(Property):
_kind = "cover"
# @final # @final
class Switch(Statement): class Switch(Statement):
def __init__(self, test, cases, *, src_loc=None, src_loc_at=0, case_src_locs={}): def __init__(self, test, cases, *, src_loc=None, src_loc_at=0, case_src_locs={}):

View file

@ -417,9 +417,9 @@ class Module(_ModuleBuilderRoot, Elaboratable):
self._pop_ctrl() self._pop_ctrl()
for assign in Statement.wrap(assigns): for assign in Statement.wrap(assigns):
if not compat_mode and not isinstance(assign, (Assign, Assert, Assume)): if not compat_mode and not isinstance(assign, (Assign, Assert, Assume, Cover)):
raise SyntaxError( raise SyntaxError(
"Only assignments, asserts, and assumes may be appended to d.{}" "Only assignments and property checks may be appended to d.{}"
.format(domain_name(domain))) .format(domain_name(domain)))
assign = SampleDomainInjector(domain)(assign) assign = SampleDomainInjector(domain)(assign)

View file

@ -196,6 +196,10 @@ class StatementVisitor(metaclass=ABCMeta):
def on_Assume(self, stmt): def on_Assume(self, stmt):
pass # :nocov: pass # :nocov:
@abstractmethod
def on_Cover(self, stmt):
pass # :nocov:
@abstractmethod @abstractmethod
def on_Switch(self, stmt): def on_Switch(self, stmt):
pass # :nocov: pass # :nocov:
@ -217,6 +221,8 @@ class StatementVisitor(metaclass=ABCMeta):
new_stmt = self.on_Assert(stmt) new_stmt = self.on_Assert(stmt)
elif type(stmt) is Assume: elif type(stmt) is Assume:
new_stmt = self.on_Assume(stmt) new_stmt = self.on_Assume(stmt)
elif type(stmt) is Cover:
new_stmt = self.on_Cover(stmt)
elif isinstance(stmt, Switch): elif isinstance(stmt, Switch):
# Uses `isinstance()` and not `type() is` because nmigen.compat requires it. # Uses `isinstance()` and not `type() is` because nmigen.compat requires it.
new_stmt = self.on_Switch(stmt) new_stmt = self.on_Switch(stmt)
@ -247,6 +253,9 @@ class StatementTransformer(StatementVisitor):
def on_Assume(self, stmt): def on_Assume(self, stmt):
return Assume(self.on_value(stmt.test), _check=stmt._check, _en=stmt._en) return Assume(self.on_value(stmt.test), _check=stmt._check, _en=stmt._en)
def on_Cover(self, stmt):
return Cover(self.on_value(stmt.test), _check=stmt._check, _en=stmt._en)
def on_Switch(self, stmt): def on_Switch(self, stmt):
cases = OrderedDict((k, self.on_statement(s)) for k, s in stmt.cases.items()) cases = OrderedDict((k, self.on_statement(s)) for k, s in stmt.cases.items())
return Switch(self.on_value(stmt.test), cases) return Switch(self.on_value(stmt.test), cases)
@ -396,11 +405,12 @@ class DomainCollector(ValueVisitor, StatementVisitor):
self.on_value(stmt.lhs) self.on_value(stmt.lhs)
self.on_value(stmt.rhs) self.on_value(stmt.rhs)
def on_Assert(self, stmt): def on_property(self, stmt):
self.on_value(stmt.test) self.on_value(stmt.test)
def on_Assume(self, stmt): on_Assert = on_property
self.on_value(stmt.test) on_Assume = on_property
on_Cover = on_property
def on_Switch(self, stmt): def on_Switch(self, stmt):
self.on_value(stmt.test) self.on_value(stmt.test)
@ -598,12 +608,13 @@ class SampleLowerer(FragmentTransformer, ValueTransformer, StatementTransformer)
class SwitchCleaner(StatementVisitor): class SwitchCleaner(StatementVisitor):
def on_Assign(self, stmt): def on_ignore(self, stmt):
return stmt return stmt
on_Assert = on_Assign on_Assign = on_ignore
on_Assert = on_ignore
on_Assume = on_Assign on_Assume = on_ignore
on_Cover = on_ignore
def on_Switch(self, stmt): def on_Switch(self, stmt):
cases = OrderedDict((k, self.on_statement(s)) for k, s in stmt.cases.items()) cases = OrderedDict((k, self.on_statement(s)) for k, s in stmt.cases.items())
@ -651,9 +662,14 @@ class LHSGroupAnalyzer(StatementVisitor):
if lhs_signals: if lhs_signals:
self.unify(*stmt._lhs_signals()) self.unify(*stmt._lhs_signals())
on_Assert = on_Assign def on_property(self, stmt):
lhs_signals = stmt._lhs_signals()
if lhs_signals:
self.unify(*stmt._lhs_signals())
on_Assume = on_Assign on_Assert = on_property
on_Assume = on_property
on_Cover = on_property
def on_Switch(self, stmt): def on_Switch(self, stmt):
for case_stmts in stmt.cases.values(): for case_stmts in stmt.cases.values():
@ -681,12 +697,14 @@ class LHSGroupFilter(SwitchCleaner):
if any_lhs_signal in self.signals: if any_lhs_signal in self.signals:
return stmt return stmt
def on_Assert(self, stmt): def on_property(self, stmt):
any_lhs_signal = next(iter(stmt._lhs_signals())) any_lhs_signal = next(iter(stmt._lhs_signals()))
if any_lhs_signal in self.signals: if any_lhs_signal in self.signals:
return stmt return stmt
on_Assume = on_Assert on_Assert = on_property
on_Assume = on_property
on_Cover = on_property
class _ControlInserter(FragmentTransformer): class _ControlInserter(FragmentTransformer):

View file

@ -74,7 +74,7 @@ class DSLTestCase(FHDLTestCase):
def test_d_asgn_wrong(self): def test_d_asgn_wrong(self):
m = Module() m = Module()
with self.assertRaises(SyntaxError, with self.assertRaises(SyntaxError,
msg="Only assignments, asserts, and assumes may be appended to d.sync"): msg="Only assignments and property checks may be appended to d.sync"):
m.d.sync += Switch(self.s1, {}) m.d.sync += Switch(self.s1, {})
def test_comb_wrong(self): def test_comb_wrong(self):