fsm: support complex targets in NextValue. Closes #27.
authorSebastien Bourdeauducq <sb@m-labs.hk>
Tue, 22 Sep 2015 08:55:24 +0000 (16:55 +0800)
committerSebastien Bourdeauducq <sb@m-labs.hk>
Tue, 22 Sep 2015 08:55:24 +0000 (16:55 +0800)
examples/basic/fsm.py
migen/genlib/fsm.py

index dff6f4d533aeaa2049aed2462fe5c62c656d2794..ca235bfef89ceb665fd7ee087289d35485164d46 100644 (file)
@@ -5,6 +5,7 @@ class Example(Module):
     def __init__(self):
         self.s = Signal()
         self.counter = Signal(8)
+        x = Array(Signal(name="a") for i in range(7))
 
         myfsm = FSM()
         self.submodules += myfsm
@@ -16,6 +17,7 @@ class Example(Module):
         myfsm.act("BAR",
             self.s.eq(0),
             NextValue(self.counter, self.counter + 1),
+            NextValue(x[self.counter], 89),
             NextState("FOO")
         )
 
index 52451145bcaa840a131be315431ecbf3d9f4b94b..5bfa3575667359fb91d7fd2413523da110d7aeef 100644 (file)
@@ -1,6 +1,7 @@
 from collections import OrderedDict
 
 from migen.fhdl.structure import *
+from migen.fhdl.structure import _Slice, _ArrayProxy
 from migen.fhdl.module import Module, FinalizeError
 from migen.fhdl.visit import NodeTransformer
 from migen.fhdl.bitcontainer import value_bits_sign
@@ -21,18 +22,46 @@ class NextState:
 
 
 class NextValue:
-    def __init__(self, register, value):
-        self.register = register
+    def __init__(self, target, value):
+        self.target = target
         self.value = value
 
 
+def _target_eq(a, b):
+    if type(a) != type(b):
+        return False
+    ty = type(a)
+    if ty == Constant:
+        return a.value == b.value
+    elif ty == Signal:
+        return a is b
+    elif ty == Cat:
+        return all(_target_eq(x, y) for x, y in zip(a.l, b.l))
+    elif ty == _Slice:
+        return (_target_eq(a.value, b.value)
+                    and a.start == b.start
+                    and a.end == b.end)
+    elif ty == _ArrayProxy:
+        return (all(_target_eq(x, y) for x, y in zip(a.choices, b.choices))
+                    and _target_eq(a.key, b.key))
+    else:
+        raise ValueError("NextValue cannot be used with target type '{}'"
+                         .format(ty))
+
+
 class _LowerNext(NodeTransformer):
     def __init__(self, next_state_signal, encoding, aliases):
         self.next_state_signal = next_state_signal
         self.encoding = encoding
         self.aliases = aliases
-        # register -> next_value_ce, next_value
-        self.registers = OrderedDict()
+        # (target, next_value_ce, next_value)
+        self.registers = []
+
+    def _get_register_control(self, target):
+        for x in self.registers:
+            if _target_eq(target, x[0]):
+                return x
+        raise KeyError
 
     def visit_unknown(self, node):
         if isinstance(node, NextState):
@@ -43,12 +72,12 @@ class _LowerNext(NodeTransformer):
             return self.next_state_signal.eq(self.encoding[actual_state])
         elif isinstance(node, NextValue):
             try:
-                next_value_ce, next_value = self.registers[node.register]
+                next_value_ce, next_value = self._get_register_control(node.target)
             except KeyError:
-                related = node.register if isinstance(node.register, Signal) else None
-                next_value = Signal(bits_sign=value_bits_sign(node.register), related=related)
+                related = node.target if isinstance(node.target, Signal) else None
+                next_value = Signal(bits_sign=value_bits_sign(node.target), related=related)
                 next_value_ce = Signal(related=related)
-                self.registers[node.register] = next_value_ce, next_value
+                self.registers.append((node.target, next_value_ce, next_value))
             return next_value.eq(node.value), next_value_ce.eq(1)
         else:
             return node
@@ -133,7 +162,7 @@ class FSM(Module):
             Case(self.state, cases).makedefault(self.encoding[self.reset_state])
         ]
         self.sync += self.state.eq(self.next_state)
-        for register, (next_value_ce, next_value) in ln.registers.items():
+        for register, next_value_ce, next_value in ln.registers:
             self.sync += If(next_value_ce, register.eq(next_value))
 
         # drive entering/leaving signals