2012-06-08 11:54:03 -04:00
|
|
|
from migen.fhdl.structure import *
|
2013-03-15 14:41:30 -04:00
|
|
|
from migen.fhdl.module import Module
|
2012-06-08 11:54:03 -04:00
|
|
|
from migen.flow.actor import *
|
2012-12-14 09:55:38 -05:00
|
|
|
from migen.flow.transactions import *
|
2012-06-08 11:54:03 -04:00
|
|
|
|
|
|
|
# Generators yield None or a tuple of Tokens.
|
|
|
|
# Tokens for Sink endpoints are pulled and the "value" field filled in.
|
|
|
|
# Tokens for Source endpoints are pushed according to their "value" field.
|
|
|
|
#
|
|
|
|
# NB: the possibility to push several tokens at once is important to interact
|
|
|
|
# with actors that only accept a group of tokens when all of them are available.
|
2013-03-15 14:41:30 -04:00
|
|
|
class TokenExchanger(Module):
|
2012-11-17 13:46:28 -05:00
|
|
|
def __init__(self, generator, actor):
|
2012-06-08 11:54:03 -04:00
|
|
|
self.generator = generator
|
2012-11-17 13:46:28 -05:00
|
|
|
self.actor = actor
|
2012-06-08 11:56:52 -04:00
|
|
|
self.active = set()
|
2012-12-14 13:16:22 -05:00
|
|
|
self.busy = True
|
2012-06-08 11:54:03 -04:00
|
|
|
self.done = False
|
|
|
|
|
|
|
|
def _process_transactions(self, s):
|
2012-06-08 11:56:52 -04:00
|
|
|
completed = set()
|
2012-06-08 11:54:03 -04:00
|
|
|
for token in self.active:
|
2013-04-10 13:12:42 -04:00
|
|
|
ep = getattr(self.actor, token.endpoint)
|
2012-06-08 11:54:03 -04:00
|
|
|
if isinstance(ep, Sink):
|
2013-03-12 17:27:19 -04:00
|
|
|
if s.rd(ep.ack) and s.rd(ep.stb):
|
2013-04-10 13:12:42 -04:00
|
|
|
token.value = s.multiread(ep.payload)
|
2013-03-12 17:27:19 -04:00
|
|
|
completed.add(token)
|
|
|
|
s.wr(ep.ack, 0)
|
2012-06-08 11:54:03 -04:00
|
|
|
elif isinstance(ep, Source):
|
2013-03-12 17:27:19 -04:00
|
|
|
if s.rd(ep.ack) and s.rd(ep.stb):
|
|
|
|
completed.add(token)
|
|
|
|
s.wr(ep.stb, 0)
|
2012-06-08 11:54:03 -04:00
|
|
|
else:
|
|
|
|
raise TypeError
|
2012-06-08 11:56:52 -04:00
|
|
|
self.active -= completed
|
2012-12-14 13:16:22 -05:00
|
|
|
if not self.active:
|
|
|
|
self.busy = True
|
2013-03-12 17:27:19 -04:00
|
|
|
|
|
|
|
def _update_control_signals(self, s):
|
|
|
|
for token in self.active:
|
2013-04-10 13:12:42 -04:00
|
|
|
ep = getattr(self.actor, token.endpoint)
|
2013-03-12 17:27:19 -04:00
|
|
|
if isinstance(ep, Sink):
|
|
|
|
s.wr(ep.ack, 1)
|
|
|
|
elif isinstance(ep, Source):
|
2013-04-10 13:12:42 -04:00
|
|
|
s.multiwrite(ep.payload, token.value)
|
2013-03-12 17:27:19 -04:00
|
|
|
s.wr(ep.stb, 1)
|
|
|
|
else:
|
|
|
|
raise TypeError
|
|
|
|
|
2012-06-08 11:54:03 -04:00
|
|
|
def _next_transactions(self):
|
|
|
|
try:
|
|
|
|
transactions = next(self.generator)
|
|
|
|
except StopIteration:
|
|
|
|
self.done = True
|
2012-12-14 13:16:22 -05:00
|
|
|
self.busy = False
|
2012-06-08 11:54:03 -04:00
|
|
|
transactions = None
|
|
|
|
if isinstance(transactions, Token):
|
2012-06-08 11:56:52 -04:00
|
|
|
self.active = {transactions}
|
2013-04-10 13:12:42 -04:00
|
|
|
elif isinstance(transactions, (tuple, list, set)):
|
2012-06-08 11:56:52 -04:00
|
|
|
self.active = set(transactions)
|
2012-06-08 11:54:03 -04:00
|
|
|
elif transactions is None:
|
2012-06-20 16:39:52 -04:00
|
|
|
self.active = set()
|
2012-06-08 11:54:03 -04:00
|
|
|
else:
|
|
|
|
raise TypeError
|
2012-12-14 17:56:03 -05:00
|
|
|
if self.active and all(transaction.idle_wait for transaction in self.active):
|
2012-12-14 13:16:22 -05:00
|
|
|
self.busy = False
|
2013-03-12 17:27:19 -04:00
|
|
|
|
2012-06-08 11:54:03 -04:00
|
|
|
def do_simulation(self, s):
|
|
|
|
if not self.done:
|
|
|
|
if self.active:
|
|
|
|
self._process_transactions(s)
|
2013-03-12 17:27:19 -04:00
|
|
|
if not self.active:
|
|
|
|
self._next_transactions()
|
|
|
|
self._update_control_signals(s)
|
|
|
|
|
|
|
|
do_simulation.initialize = True
|
2012-11-17 08:15:51 -05:00
|
|
|
|
2013-04-10 13:12:42 -04:00
|
|
|
class SimActor(Module):
|
|
|
|
def __init__(self, generator):
|
|
|
|
self.busy = Signal()
|
|
|
|
self.submodules.token_exchanger = TokenExchanger(generator, self)
|
2012-11-17 08:15:51 -05:00
|
|
|
|
2013-04-10 13:12:42 -04:00
|
|
|
def do_simulation(self, s):
|
2012-12-14 13:16:22 -05:00
|
|
|
s.wr(self.busy, self.token_exchanger.busy)
|
2013-04-10 13:12:42 -04:00
|
|
|
|
|
|
|
def _dumper_gen(prefix):
|
|
|
|
while True:
|
|
|
|
t = Token("result")
|
|
|
|
yield t
|
|
|
|
if len(t.value) > 1:
|
|
|
|
s = str(t.value)
|
|
|
|
else:
|
|
|
|
s = str(list(t.value.values())[0])
|
|
|
|
print(prefix + s)
|
2012-11-23 18:00:07 -05:00
|
|
|
|
|
|
|
class Dumper(SimActor):
|
|
|
|
def __init__(self, layout, prefix=""):
|
2013-04-10 13:12:42 -04:00
|
|
|
self.result = Sink(layout)
|
|
|
|
SimActor.__init__(self, _dumper_gen(prefix))
|