add Display prototype function display-patch
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 27 Sep 2021 16:52:24 +0000 (17:52 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 27 Sep 2021 16:52:24 +0000 (17:52 +0100)
nmigen/back/rtlil.py
nmigen/hdl/ast.py
nmigen/hdl/dsl.py
nmigen/hdl/xfrm.py
nmigen/sim/_pyrtl.py

index 21986392366e547d62d99b426ae7e7b8d360715c..ad7bc7829e4f1f9bf291ead88d439d50e861a895 100644 (file)
@@ -744,6 +744,9 @@ class _StatementCompiler(xfrm.StatementVisitor):
     on_Assume = on_property
     on_Cover  = on_property
 
+    def on_Display(self, stmt):
+        pass
+
     def on_Switch(self, stmt):
         self._check_rhs(stmt.test)
 
index 685924ac2f9481e12cb2d9424db4e619ec71d14a..d2066750fcb897d5c80a0877ae0bd2bc63a2d120 100644 (file)
@@ -19,7 +19,7 @@ __all__ = [
     "UserValue", "ValueCastable",
     "Sample", "Past", "Stable", "Rose", "Fell", "Initial",
     "Statement", "Switch",
-    "Property", "Assign", "Assert", "Assume", "Cover",
+    "Property", "Assign", "Assert", "Assume", "Cover", "Display",
     "ValueKey", "ValueDict", "ValueSet", "SignalKey", "SignalDict", "SignalSet",
 ]
 
@@ -1458,7 +1458,6 @@ class Property(Statement, MustUse):
     def __repr__(self):
         return "({} {!r})".format(self._kind, self.test)
 
-
 @final
 class Assert(Property):
     _kind = "assert"
@@ -1473,6 +1472,29 @@ class Assume(Property):
 class Cover(Property):
     _kind = "cover"
 
+@final
+class Display(Statement):
+    _MustUse__warning = UnusedProperty
+
+    def __init__(self, text, *args):
+        super().__init__(src_loc_at=0)
+        self.text = text
+        self.args = args
+        self.test = Signal()
+        self._check = Signal(reset_less=True)
+        self._check.src_loc = self.src_loc
+        self._en = Signal(reset_less=True)
+        self._en.src_loc = self.src_loc
+
+    def _lhs_signals(self):
+        return SignalSet((self._en, self._check))
+
+    def _rhs_signals(self):
+        return self.test._rhs_signals()
+
+    def __repr__(self):
+        return "(display {!r})".format(self.text)
+
 
 # @final
 class Switch(Statement):
index 564d8b8aed62a7f87bf3d37e4bd7b6fef46a18bc..cf40c66aec61855033b3d8800078f4687351a2df 100644 (file)
@@ -484,7 +484,7 @@ class Module(_ModuleBuilderRoot, Elaboratable):
             self._pop_ctrl()
 
         for stmt in Statement.cast(assigns):
-            if not compat_mode and not isinstance(stmt, (Assign, Assert, Assume, Cover)):
+            if not compat_mode and not isinstance(stmt, (Assign, Assert, Assume, Cover, Display)):
                 raise SyntaxError(
                     "Only assignments and property checks may be appended to d.{}"
                     .format(domain_name(domain)))
index 97f8c5312c61f36976bf146ab35786bae7e6ec9b..4e043f77c01c7974acc62107360d2cad5eb44e82 100644 (file)
@@ -190,6 +190,10 @@ class StatementVisitor(metaclass=ABCMeta):
     def on_Cover(self, stmt):
         pass # :nocov:
 
+    @abstractmethod
+    def on_Display(self, stmt):
+        pass # :nocov:
+
     @abstractmethod
     def on_Switch(self, stmt):
         pass # :nocov:
@@ -213,6 +217,8 @@ class StatementVisitor(metaclass=ABCMeta):
             new_stmt = self.on_Assume(stmt)
         elif type(stmt) is Cover:
             new_stmt = self.on_Cover(stmt)
+        elif type(stmt) is Display:
+            new_stmt = self.on_Display(stmt)
         elif isinstance(stmt, Switch):
             # Uses `isinstance()` and not `type() is` because nmigen.compat requires it.
             new_stmt = self.on_Switch(stmt)
@@ -248,6 +254,12 @@ class StatementTransformer(StatementVisitor):
     def on_Cover(self, stmt):
         return Cover(self.on_value(stmt.test), _check=stmt._check, _en=stmt._en)
 
+    def on_Display(self, stmt):
+        # args = [self.on_value(arg) for arg in stmt.args]
+        # return Display(stmt.text, *args)
+        stmt.args = [self.on_value(arg) for arg in stmt.args]
+        return stmt
+
     def on_Switch(self, stmt):
         cases = OrderedDict((k, self.on_statement(s)) for k, s in stmt.cases.items())
         return Switch(self.on_value(stmt.test), cases)
@@ -401,6 +413,7 @@ class DomainCollector(ValueVisitor, StatementVisitor):
     on_Assert = on_property
     on_Assume = on_property
     on_Cover  = on_property
+    on_Display = on_property
 
     def on_Switch(self, stmt):
         self.on_value(stmt.test)
@@ -606,6 +619,7 @@ class SwitchCleaner(StatementVisitor):
     on_Assert = on_ignore
     on_Assume = on_ignore
     on_Cover  = on_ignore
+    on_Display = on_ignore
 
     def on_Switch(self, stmt):
         cases = OrderedDict((k, self.on_statement(s)) for k, s in stmt.cases.items())
@@ -661,6 +675,7 @@ class LHSGroupAnalyzer(StatementVisitor):
     on_Assert = on_property
     on_Assume = on_property
     on_Cover  = on_property
+    on_Display = on_property
 
     def on_Switch(self, stmt):
         for case_stmts in stmt.cases.values():
@@ -696,6 +711,7 @@ class LHSGroupFilter(SwitchCleaner):
     on_Assert = on_property
     on_Assume = on_property
     on_Cover  = on_property
+    on_Display = on_property
 
 
 class _ControlInserter(FragmentTransformer):
index 13d515f25cb4a6a297726d29901268b8a6a94a59..f041d408494e3d3900b481d76cfa8627822fbc3d 100644 (file)
@@ -369,6 +369,13 @@ class _StatementCompiler(StatementVisitor, _Compiler):
     def on_Cover(self, stmt):
         raise NotImplementedError # :nocov:
 
+    def on_Display(self, stmt):
+        args = []
+        for i in range(len(stmt.args)):
+            arg = self.emitter.def_var(f"args{i}", f"{self.rhs(stmt.args[i])} & {(1 << len(stmt.args[i])) - 1}")
+            args.append(arg)
+        self.emitter.append(f"print(\"{stmt.text}\" % tuple([{','.join(args)}]))")
+
     @classmethod
     def compile(cls, state, stmt):
         output_indexes = [state.get_signal(signal) for signal in stmt._lhs_signals()]