uio: add simulation I/O object
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Sat, 17 Nov 2012 18:55:33 +0000 (19:55 +0100)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Sat, 17 Nov 2012 18:55:33 +0000 (19:55 +0100)
migen/uio/ioo.py

index 934cbf32e7a6c13d929e44cf72bd7d65eba58705..72dbb391e68d3c740999960528dd0cec732d79e2 100644 (file)
@@ -7,3 +7,63 @@ class UnifiedIOObject(Actor):
                if dataflow is not None:
                        super().__init__(*dataflow)
                self.buses = buses
+
+(_WAIT_COMPLETE, _WAIT_POLL) = range(2)
+
+class UnifiedIOSimulation(UnifiedIOObject):
+       def __init__(self, generator, dataflow=None, buses={}):
+               self.generator = generator
+               super().__init__(dataflow, buses)
+               
+               self.callers = []
+               self.busname_to_caller_id = {}
+               if dataflow is not None:
+                       self.callers.append(TokenExchanger(self.demux_g(0), self))
+               for k, v in self.buses.items():
+                       caller_id = len(self.callers)
+                       self.busname_to_caller_id[k] = caller_id
+                       g = self.demux_g(caller_id)
+                       if isinstance(v, wishbone.Interface):
+                               caller = wishbone.Initiator(g, v)
+                       else:
+                               raise NotImplementedError
+                       self.callers.append(caller)
+               
+               self.dispatch_state = _WAIT_COMPLETE
+               self.dispatch_caller = 0
+               self.pending_transaction = None
+       
+       def identify_transaction(self, t):
+               if isinstance(t, Token):
+                       return 0
+               elif isinstance(t, TRead) or isinstance(t, TWrite):
+                       if t.busname is None:
+                               if len(self.busname_to_caller_id) != 1:
+                                       raise TypeError
+                               else:
+                                       return list(self.busname_to_caller_id.values())[0]
+                       else:
+                               return self.busname_to_caller_id[t.busname]
+               else:
+                       raise TypeError
+       
+       def dispatch_g(self, caller_id):
+               while True:
+                       if self.dispatch_state == _WAIT_COMPLETE and self.dispatch_caller == caller_id:
+                               transaction = next(self.generator)
+                               tr_cid = self.identify_transaction(transaction)
+                               self.dispatch_caller = tr_cid
+                               if tr_cid == caller_id:
+                                       yield transaction
+                               else:
+                                       self.pending_transaction = transaction
+                                       self.dispatch_state = _WAIT_POLL
+                                       yield None
+                       elif self.dispatch_state == _WAIT_POLL and self.dispatch_caller == caller_id:
+                               self.dispatch_state = _WAIT_COMPLETE
+                               yield self.pending_transaction
+                       else:
+                               yield None
+       
+       def get_fragment(self):
+               return sum([c.get_fragment() for c in self.callers], Fragment())