ast, back.pysim: allow specifying user-defined decoders for signals.
authorwhitequark <cz@m-labs.hk>
Fri, 14 Dec 2018 09:02:29 +0000 (09:02 +0000)
committerwhitequark <cz@m-labs.hk>
Fri, 14 Dec 2018 09:02:29 +0000 (09:02 +0000)
nmigen/back/pysim.py
nmigen/compat/genlib/fsm.py
nmigen/fhdl/ast.py

index d740ebd26cc0777031d0e1ee2094919009679b3b..9716ff2a2f096d61a5ddb5323090f6e63db9d31f 100644 (file)
@@ -295,6 +295,14 @@ class Simulator:
                     self._vcd_signals[signal] = set()
                 name   = self._signal_name_in_fragment(fragment, signal)
                 suffix = None
+                if signal.decoder:
+                    var_type = "string"
+                    var_size = 1
+                    var_init = signal.decoder(signal.reset).replace(" ", "_")
+                else:
+                    var_type = "wire"
+                    var_size = signal.nbits
+                    var_init = signal.reset
                 while True:
                     try:
                         if suffix is None:
@@ -303,7 +311,7 @@ class Simulator:
                             name_suffix = "{}${}".format(name, suffix)
                         self._vcd_signals[signal].add(self._vcd_writer.register_var(
                             scope=".".join(self._fragments[fragment]), name=name_suffix,
-                            var_type="wire", size=signal.nbits, init=signal.reset))
+                            var_type=var_type, size=var_size, init=var_init))
                         if signal not in self._vcd_names:
                             self._vcd_names[signal] = \
                                 ".".join(self._fragments[fragment] + (name_suffix,))
@@ -356,10 +364,14 @@ class Simulator:
         if (old, new) == (0, 1) and signal in self._domain_triggers:
             domains.add(self._domain_triggers[signal])
 
-        if self._vcd_writer:
+        if self._vcd_writer and old != new:
             # Finally, dump the new value to the VCD file.
             for vcd_signal in self._vcd_signals[signal]:
-                self._vcd_writer.change(vcd_signal, self._timestamp / self._epsilon, new)
+                if signal.decoder:
+                    var_value = signal.decoder(new).replace(" ", "_")
+                else:
+                    var_value = new
+                self._vcd_writer.change(vcd_signal, self._timestamp / self._epsilon, var_value)
 
     def _commit_comb_signals(self, domains):
         """Perform the comb part of IR processes (aka RTLIL always)."""
index 548eb6aa1b7fc993c883aefefa8591aef87a61ea..b6d2c88abf5d680f641b421046c3fce7bbdf6146 100644 (file)
@@ -156,10 +156,9 @@ class FSM(CompatModule):
         self.encoding = dict((s, n) for n, s in enumerate(self.actions.keys()))
         self.decoding = {n: s for s, n in self.encoding.items()}
 
-        self.state = Signal(max=nstates, reset=self.encoding[self.reset_state])
-        self.state._enumeration = self.decoding
-        self.next_state = Signal(max=nstates)
-        self.next_state._enumeration = {n: "{}:{}".format(n, s) for n, s in self.decoding.items()}
+        decoder = lambda n: "{}/{}".format(self.decoding[n], n)
+        self.state = Signal(max=nstates, reset=self.encoding[self.reset_state], decoder=decoder)
+        self.next_state = Signal.like(self.state)
 
         for state, signal in self.before_leaving_signals.items():
             encoded = self.encoding[state]
index 3b514419792ea56a2b47c53daa26fce44d8c38e9..cbfa7999b8efe776ea8b1bf56f723f310c2e2863 100644 (file)
@@ -512,6 +512,9 @@ class Signal(Value, DUID):
         defaults to 0) and ``max`` (exclusive, defaults to 2).
     attrs : dict
         Dictionary of synthesis attributes.
+    decoder : function
+        A function converting integer signal values to human-readable strings (e.g. FSM state
+        names).
 
     Attributes
     ----------
@@ -524,7 +527,7 @@ class Signal(Value, DUID):
     """
 
     def __init__(self, shape=None, name=None, reset=0, reset_less=False, min=None, max=None,
-                 attrs=None, src_loc_at=0):
+                 attrs=None, decoder=None, src_loc_at=0):
         super().__init__(src_loc_at=src_loc_at)
 
         if name is None:
@@ -560,6 +563,7 @@ class Signal(Value, DUID):
         self.reset_less = bool(reset_less)
 
         self.attrs = OrderedDict(() if attrs is None else attrs)
+        self.decoder = decoder
 
     @classmethod
     def like(cls, other, src_loc_at=0, **kwargs):
@@ -573,7 +577,8 @@ class Signal(Value, DUID):
         kw = dict(shape=cls.wrap(other).shape(),
                   name=tracer.get_var_name(depth=2 + src_loc_at))
         if isinstance(other, cls):
-            kw.update(reset=other.reset, reset_less=other.reset_less, attrs=other.attrs)
+            kw.update(reset=other.reset, reset_less=other.reset_less,
+                      attrs=other.attrs, decoder=other.decoder)
         kw.update(kwargs)
         return cls(**kw, src_loc_at=1 + src_loc_at)