from migen.fhdl.structure import * from migen.flow.actor import * from migen.flow.transactions import * from migen.sim.generic import PureSimulable # 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. class TokenExchanger(PureSimulable): def __init__(self, generator, actor): self.generator = generator self.actor = actor self.active = set() self.busy = True self.done = False def _process_transactions(self, s): completed = set() for token in self.active: ep = self.actor.endpoints[token.endpoint] if isinstance(ep, Sink): if s.rd(ep.ack): if s.rd(ep.stb): token.value = s.multiread(ep.token) completed.add(token) s.wr(ep.ack, 0) else: s.wr(ep.ack, 1) elif isinstance(ep, Source): if s.rd(ep.stb): if s.rd(ep.ack): completed.add(token) s.wr(ep.stb, 0) else: s.wr(ep.stb, 1) s.multiwrite(ep.token, token.value) else: raise TypeError self.active -= completed if not self.active: self.busy = True def _next_transactions(self): try: transactions = next(self.generator) except StopIteration: self.done = True self.busy = False transactions = None if isinstance(transactions, Token): self.active = {transactions} elif isinstance(transactions, tuple) \ or isinstance(transactions, list) \ or isinstance(transactions, set): self.active = set(transactions) elif transactions is None: self.active = set() else: raise TypeError if self.active and all(transaction.idle_wait for transaction in self.active): self.busy = False def do_simulation(self, s): if not self.done: if not self.active: self._next_transactions() if self.active: self._process_transactions(s) class SimActor(Actor): def __init__(self, generator, *endpoint_descriptions, **misc): Actor.__init__(self, *endpoint_descriptions, **misc) self.token_exchanger = TokenExchanger(generator, self) def update_busy(self, s): s.wr(self.busy, self.token_exchanger.busy) def get_fragment(self): return self.token_exchanger.get_fragment() + Fragment(sim=[self.update_busy]) class Dumper(SimActor): def __init__(self, layout, prefix=""): def dumper_gen(): 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) SimActor.__init__(self, dumper_gen(), ("result", Sink, layout))