hdl.ast: recognize a Enum used as decoder and format it better.
authorwhitequark <whitequark@whitequark.org>
Tue, 2 Jul 2019 19:02:16 +0000 (19:02 +0000)
committerwhitequark <whitequark@whitequark.org>
Tue, 2 Jul 2019 19:34:44 +0000 (19:34 +0000)
nmigen/hdl/ast.py
nmigen/test/test_hdl_ast.py

index 54393fe7c09218719912490fd4b3c426fd2db3e1..ef7d7c7ab9027f7b6da57ed495cb3f2c12bb4b54 100644 (file)
@@ -3,6 +3,7 @@ import builtins
 import traceback
 from collections import OrderedDict
 from collections.abc import Iterable, MutableMapping, MutableSet, MutableSequence
+from enum import Enum
 
 from .. import tracer
 from ..tools import *
@@ -575,9 +576,11 @@ class Signal(Value, DUID):
         defaults to 0) and ``max`` (exclusive, defaults to 2).
     attrs : dict
         Dictionary of synthesis attributes.
-    decoder : function
+    decoder : function or Enum
         A function converting integer signal values to human-readable strings (e.g. FSM state
-        names).
+        names). If an ``Enum`` subclass is passed, it is concisely decoded using format string
+        ``"{0.name:}/{0.value:}"``, or a number if the signal value is not a member of
+        the enumeration.
 
     Attributes
     ----------
@@ -627,7 +630,15 @@ class Signal(Value, DUID):
         self.reset_less = bool(reset_less)
 
         self.attrs = OrderedDict(() if attrs is None else attrs)
-        self.decoder = decoder
+        if isinstance(decoder, type) and issubclass(decoder, Enum):
+            def enum_decoder(value):
+                try:
+                    return "{0.name:}/{0.value:}".format(decoder(value))
+                except ValueError:
+                    return str(value)
+            self.decoder = enum_decoder
+        else:
+            self.decoder = decoder
 
     @classmethod
     def like(cls, other, name=None, name_suffix=None, src_loc_at=0, **kwargs):
index 9fbf6375e903b6a03c980efce9035cda75cd26f6..6ef1193c39336c0bb322f35006bc5e0559808f88 100644 (file)
@@ -1,3 +1,5 @@
+from enum import Enum
+
 from ..hdl.ast import *
 from .tools import *
 
@@ -486,6 +488,14 @@ class SignalTestCase(FHDLTestCase):
         s8 = Signal.like(s1, name_suffix="_ff")
         self.assertEqual(s8.name, "s1_ff")
 
+    def test_decoder(self):
+        class Color(Enum):
+            RED  = 1
+            BLUE = 2
+        s = Signal(decoder=Color)
+        self.assertEqual(s.decoder(1), "RED/1")
+        self.assertEqual(s.decoder(3), "3")
+
 
 class ClockSignalTestCase(FHDLTestCase):
     def test_domain(self):