actorlib/spi: SingleGenerator
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Tue, 9 Oct 2012 19:11:15 +0000 (21:11 +0200)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Tue, 9 Oct 2012 19:11:15 +0000 (21:11 +0200)
migen/actorlib/spi.py

index e5565a5dff0600aefb6a13a6f783c8dff67d63b5..f5906e0618f959931ecb19e9ecbebb24ea40c7c2 100644 (file)
@@ -4,6 +4,81 @@ from migen.fhdl.structure import *
 from migen.bank.description import *
 from migen.flow.actor import *
 
+# layout is a list of tuples, either:
+# - (name, bv, [reset value], [alignment bits])
+# - (name, sublayout)
+
+def _convert_layout(layout):
+       r = []
+       for element in layout:
+               if isinstance(element[1], list):
+                       r.append((element[0], _convert_layout(element[1])))
+               else:
+                       r.append((element[0], element[1]))
+       return r
+
+def _create_registers_assign(layout, target, atomic, prefix=""):
+       registers = []
+       assigns = []
+       for element in layout:
+               if isinstance(element[1], list):
+                       r_registers, r_assigns = _create_registers_assign(element[1],
+                               atomic,
+                               getattr(target, element[0]),
+                               element[0] + "_")
+                       registers += r_registers
+                       assigns += r_assigns
+               else:
+                       name = element[0]
+                       bv = element[1]
+                       if len(element) > 2:
+                               reset = element[2]
+                       else:
+                               reset = 0
+                       if len(element) > 3:
+                               alignment = element[3]
+                       else:
+                               alignment = 0
+                       reg = RegisterField(prefix + name, bv.width + alignment,
+                               reset=reset, atomic_write=atomic)
+                       registers.append(reg)
+                       assigns.append(getattr(target, name).eq(reg.field.r[alignment:]))
+       return registers, assigns
+
+(MODE_EXTERNAL, MODE_SINGLE_SHOT, MODE_CONTINUOUS) = range(3)
+
+class SingleGenerator(Actor):
+       def __init__(self, layout, mode):
+               self._mode = mode
+               super().__init__(("source", Source, _convert_layout(layout)))
+               self._registers, self._assigns = _create_registers_assign(layout,
+                       self.token("source"), self._mode != MODE_SINGLE_SHOT)
+               if mode == MODE_EXTERNAL:
+                       self.trigger = Signal()
+               elif mode == MODE_SINGLE_SHOT:
+                       shoot = RegisterRaw("shoot")
+                       self._registers.insert(0, shoot)
+                       self.trigger = shoot.re
+               elif mode == MODE_CONTINUOUS:
+                       enable = RegisterField("enable")
+                       self._registers.insert(0, enable)
+                       self.trigger = enable.field.r
+               else:
+                       raise ValueError
+       
+       def get_registers(self):
+               return self._registers
+       
+       def get_fragment(self):
+               stb = self.endpoints["source"].stb
+               ack = self.endpoints["source"].ack
+               comb = [
+                       self.busy.eq(stb)
+               ]
+               stmts = [stb.eq(self.trigger)] + self._assigns
+               sync = [If(ack | ~stb, *stmts)]
+               return Fragment(comb, sync)
+
 class Collector(Actor):
        def __init__(self, layout, depth=1024):
                super().__init__(("sink", Sink, layout))