diff --git a/examples/dataflow/dma.py b/examples/dataflow/dma.py index 322a61954..38d77300a 100644 --- a/examples/dataflow/dma.py +++ b/examples/dataflow/dma.py @@ -1,5 +1,6 @@ from random import Random +from migen.fhdl.module import Module from migen.flow.network import * from migen.flow.transactions import * from migen.actorlib import dma_wishbone, dma_asmi @@ -26,12 +27,22 @@ def adrgen_gen(): print("Address: " + str(i)) yield Token("address", {"a": i}) +class SimAdrGen(SimActor): + def __init__(self, nbits): + self.address = Source([("a", nbits)]) + SimActor.__init__(self, adrgen_gen()) + def dumper_gen(): while True: t = Token("data", idle_wait=True) yield t print("Received: " + str(t.value["d"])) +class SimDumper(SimActor): + def __init__(self): + self.data = Sink([("d", 32)]) + SimActor.__init__(self, dumper_gen()) + def trgen_gen(): for i in range(10): a = i @@ -39,75 +50,78 @@ def trgen_gen(): print("Address: " + str(a) + " Data: " + str(d)) yield Token("address_data", {"a": a, "d": d}) -def wishbone_sim(efragment, master, end_simulation): - peripheral = wishbone.Target(MyModelWB()) - tap = wishbone.Tap(peripheral.bus) - interconnect = wishbone.InterconnectPointToPoint(master.bus, peripheral.bus) - def _end_simulation(s): - s.interrupt = end_simulation(s) - fragment = efragment \ - + peripheral.get_fragment() \ - + tap.get_fragment() \ - + interconnect.get_fragment() \ - + Fragment(sim=[_end_simulation]) - sim = Simulator(fragment) - sim.run() +class SimTrGen(SimActor): + def __init__(self): + self.address_data = Source([("a", 30), ("d", 32)]) + SimActor.__init__(self, trgen_gen()) -def asmi_sim(efragment, hub, end_simulation): - def _end_simulation(s): - s.interrupt = end_simulation(s) - peripheral = asmibus.Target(MyModelASMI(), hub) - tap = asmibus.Tap(hub) - def _end_simulation(s): - s.interrupt = end_simulation(s) - fragment = efragment \ - + peripheral.get_fragment() \ - + tap.get_fragment() \ - + Fragment(sim=[_end_simulation]) - sim = Simulator(fragment) - sim.run() +class TBWishbone(Module): + def __init__(self, master): + self.submodules.peripheral = wishbone.Target(MyModelWB()) + self.submodules.tap = wishbone.Tap(self.peripheral.bus) + self.submodules.interconnect = wishbone.InterconnectPointToPoint(master.bus, + self.peripheral.bus) + +class TBWishboneReader(TBWishbone): + def __init__(self): + self.adrgen = SimAdrGen(30) + self.reader = dma_wishbone.Reader() + self.dumper = SimDumper() + g = DataFlowGraph() + g.add_connection(self.adrgen, self.reader) + g.add_connection(self.reader, self.dumper) + self.submodules.comp = CompositeActor(g) + TBWishbone.__init__(self, self.reader) + + def do_simulation(self, s): + s.interrupt = self.adrgen.token_exchanger.done and not s.rd(self.comp.busy) + +class TBWishboneWriter(TBWishbone): + def __init__(self): + self.trgen = SimTrGen() + self.writer = dma_wishbone.Writer() + g = DataFlowGraph() + g.add_connection(self.trgen, self.writer) + self.submodules.comp = CompositeActor(g) + TBWishbone.__init__(self, self.writer) + + def do_simulation(self, s): + s.interrupt = self.trgen.token_exchanger.done and not s.rd(self.comp.busy) + +class TBAsmi(Module): + def __init__(self, hub): + self.submodules.peripheral = asmibus.Target(MyModelASMI(), hub) + self.submodules.tap = asmibus.Tap(hub) + +class TBAsmiReader(TBAsmi): + def __init__(self, nslots): + self.submodules.hub = asmibus.Hub(32, 32) + port = self.hub.get_port(nslots) + self.hub.finalize() + + self.adrgen = SimAdrGen(32) + self.reader = dma_asmi.Reader(port) + self.dumper = SimDumper() + g = DataFlowGraph() + g.add_connection(self.adrgen, self.reader) + g.add_connection(self.reader, self.dumper) + self.submodules.comp = CompositeActor(g) + TBAsmi.__init__(self, self.hub) + + def do_simulation(self, s): + s.interrupt = self.adrgen.token_exchanger.done and not s.rd(self.comp.busy) def test_wb_reader(): print("*** Testing Wishbone reader") - adrgen = SimActor(adrgen_gen(), ("address", Source, [("a", 30)])) - reader = dma_wishbone.Reader() - dumper = SimActor(dumper_gen(), ("data", Sink, [("d", 32)])) - g = DataFlowGraph() - g.add_connection(adrgen, reader) - g.add_connection(reader, dumper) - comp = CompositeActor(g) - - wishbone_sim(comp.get_fragment(), reader, - lambda s: adrgen.token_exchanger.done and not s.rd(comp.busy)) + Simulator(TBWishboneReader()).run() def test_wb_writer(): print("*** Testing Wishbone writer") - trgen = SimActor(trgen_gen(), ("address_data", Source, [("a", 30), ("d", 32)])) - writer = dma_wishbone.Writer() - g = DataFlowGraph() - g.add_connection(trgen, writer) - comp = CompositeActor(g) - - wishbone_sim(comp.get_fragment(), writer, - lambda s: trgen.token_exchanger.done and not s.rd(comp.busy)) + Simulator(TBWishboneWriter()).run() def test_asmi_reader(nslots): print("*** Testing ASMI reader (nslots={})".format(nslots)) - - hub = asmibus.Hub(32, 32) - port = hub.get_port(nslots) - hub.finalize() - - adrgen = SimActor(adrgen_gen(), ("address", Source, [("a", 32)])) - reader = dma_asmi.Reader(port) - dumper = SimActor(dumper_gen(), ("data", Sink, [("d", 32)])) - g = DataFlowGraph() - g.add_connection(adrgen, reader) - g.add_connection(reader, dumper) - comp = CompositeActor(g) - - asmi_sim(hub.get_fragment() + comp.get_fragment(), hub, - lambda s: adrgen.token_exchanger.done and not s.rd(comp.busy)) + Simulator(TBAsmiReader(nslots)).run() test_wb_reader() test_wb_writer() diff --git a/examples/dataflow/misc.py b/examples/dataflow/misc.py index 14a6aa780..bb1df5b4b 100644 --- a/examples/dataflow/misc.py +++ b/examples/dataflow/misc.py @@ -8,7 +8,12 @@ def source_gen(): for i in range(10): v = i + 5 print("==> " + str(v)) - yield Token("source", {"value": v}) + yield Token("source", {"maximum": v}) + +class SimSource(SimActor): + def __init__(self): + self.source = Source([("maximum", 32)]) + SimActor.__init__(self, source_gen()) def sink_gen(): while True: @@ -16,16 +21,20 @@ def sink_gen(): yield t print(t.value["value"]) +class SimSink(SimActor): + def __init__(self): + self.sink = Sink([("value", 32)]) + SimActor.__init__(self, sink_gen()) + def main(): - source = SimActor(source_gen(), ("source", Source, [("value", 32)])) + source = SimSource() loop = misc.IntSequence(32) - sink = SimActor(sink_gen(), ("sink", Sink, [("value", 32)])) + sink = SimSink() g = DataFlowGraph() g.add_connection(source, loop) g.add_connection(loop, sink) comp = CompositeActor(g) - fragment = comp.get_fragment() - sim = Simulator(fragment) + sim = Simulator(comp) sim.run(500) main() diff --git a/examples/dataflow/structuring.py b/examples/dataflow/structuring.py index 4d2696113..7f3014682 100644 --- a/examples/dataflow/structuring.py +++ b/examples/dataflow/structuring.py @@ -11,48 +11,57 @@ from migen.sim.generic import Simulator from migen.flow import perftools pack_factor = 5 +base_layout = [("value", 32)] +packed_layout = structuring.pack_layout(base_layout, pack_factor) +rawbits_layout = [("value", 32*pack_factor)] def source_gen(): for i in count(0): yield Token("source", {"value": i}) +class SimSource(SimActor): + def __init__(self): + self.source = Source(base_layout) + SimActor.__init__(self, source_gen()) + def sink_gen(): while True: t = Token("sink") yield t print(t.value["value"]) +class SimSink(SimActor): + def __init__(self): + self.sink = Sink(base_layout) + SimActor.__init__(self, sink_gen()) + +class TB(Module): + def __init__(self): + source = SimSource() + sink = SimSink() + + # A tortuous way of passing integer tokens. + packer = structuring.Pack(base_layout, pack_factor) + to_raw = structuring.Cast(packed_layout, rawbits_layout) + from_raw = structuring.Cast(rawbits_layout, packed_layout) + unpacker = structuring.Unpack(pack_factor, base_layout) + + self.g = DataFlowGraph() + self.g.add_connection(source, packer) + self.g.add_connection(packer, to_raw) + self.g.add_connection(to_raw, from_raw) + self.g.add_connection(from_raw, unpacker) + self.g.add_connection(unpacker, sink) + self.submodules.comp = CompositeActor(self.g) + self.submodules.reporter = perftools.DFGReporter(self.g) + def main(): - base_layout = [("value", 32)] - packed_layout = structuring.pack_layout(base_layout, pack_factor) - rawbits_layout = [("value", 32*pack_factor)] + tb = TB() + sim = Simulator(tb).run(1000) - source = SimActor(source_gen(), ("source", Source, base_layout)) - sink = SimActor(sink_gen(), ("sink", Sink, base_layout)) - - # A tortuous way of passing integer tokens. - packer = structuring.Pack(base_layout, pack_factor) - to_raw = structuring.Cast(packed_layout, rawbits_layout) - from_raw = structuring.Cast(rawbits_layout, packed_layout) - unpacker = structuring.Unpack(pack_factor, base_layout) - - g = DataFlowGraph() - g.add_connection(source, packer) - g.add_connection(packer, to_raw) - g.add_connection(to_raw, from_raw) - g.add_connection(from_raw, unpacker) - g.add_connection(unpacker, sink) - comp = CompositeActor(g) - reporter = perftools.DFGReporter(g) - - fragment = comp.get_fragment() + reporter.get_fragment() - sim = Simulator(fragment) - sim.run(1000) - - g_layout = nx.spectral_layout(g) - nx.draw(g, g_layout) - nx.draw_networkx_edge_labels(g, g_layout, reporter.get_edge_labels()) + g_layout = nx.spectral_layout(tb.g) + nx.draw(tb.g, g_layout) + nx.draw_networkx_edge_labels(tb.g, g_layout, tb.reporter.get_edge_labels()) plt.show() - main() diff --git a/examples/pytholite/basic.py b/examples/pytholite/basic.py index c1b4b7805..621e61c94 100644 --- a/examples/pytholite/basic.py +++ b/examples/pytholite/basic.py @@ -11,6 +11,11 @@ def number_gen(): for i in range(10): yield Token("result", {"r": i}) +class SimNumberGen(SimActor): + def __init__(self): + self.result = Source(layout) + SimActor.__init__(self, number_gen()) + def run_sim(ng): g = DataFlowGraph() d = Dumper(layout) @@ -23,7 +28,7 @@ def run_sim(ng): def main(): print("Simulating native Python:") - ng_native = SimActor(number_gen(), ("result", Source, layout)) + ng_native = SimNumberGen() run_sim(ng_native) print("Simulating Pytholite:") @@ -31,6 +36,7 @@ def main(): run_sim(ng_pytholite) print("Converting Pytholite to Verilog:") + ng_pytholite = make_pytholite(number_gen, dataflow=[("result", Source, layout)]) print(verilog.convert(ng_pytholite)) main() diff --git a/examples/pytholite/uio.py b/examples/pytholite/uio.py index 9499200e8..3718acc2a 100644 --- a/examples/pytholite/uio.py +++ b/examples/pytholite/uio.py @@ -66,6 +66,9 @@ def main(): run_sim(ng_pytholite) print("Converting Pytholite to Verilog:") + ng_pytholite = make_pytholite(gen, + dataflow=dataflow, + buses=buses) print(verilog.convert(ng_pytholite.get_fragment())) main() diff --git a/examples/sim/dataflow.py b/examples/sim/dataflow.py index 8e2628c81..4c02b24fd 100644 --- a/examples/sim/dataflow.py +++ b/examples/sim/dataflow.py @@ -10,22 +10,31 @@ def source_gen(): print("Sending: " + str(i)) yield Token("source", {"value": i}) +class SimSource(SimActor): + def __init__(self): + self.source = Source([("value", 32)]) + SimActor.__init__(self, source_gen()) + def sink_gen(): while True: t = Token("sink") yield t print("Received: " + str(t.value["value"])) -def main(): - source = SimActor(source_gen(), ("source", Source, [("value", 32)])) - sink = SimActor(sink_gen(), ("sink", Sink, [("value", 32)])) - g = DataFlowGraph() - g.add_connection(source, sink) - comp = CompositeActor(g) - def end_simulation(s): - s.interrupt = source.token_exchanger.done - fragment = comp.get_fragment() + Fragment(sim=[end_simulation]) - sim = Simulator(fragment) - sim.run() +class SimSink(SimActor): + def __init__(self): + self.sink = Sink([("value", 32)]) + SimActor.__init__(self, sink_gen()) -main() +class TB(Module): + def __init__(self): + self.source = SimSource() + self.sink = SimSink() + g = DataFlowGraph() + g.add_connection(self.source, self.sink) + self.submodules.comp = CompositeActor(g) + + def do_simulation(self, s): + s.interrupt = self.source.token_exchanger.done + +Simulator(TB()).run() diff --git a/migen/actorlib/dma_asmi.py b/migen/actorlib/dma_asmi.py index 65d05ca8d..9ff46dedb 100644 --- a/migen/actorlib/dma_asmi.py +++ b/migen/actorlib/dma_asmi.py @@ -1,91 +1,83 @@ from migen.fhdl.structure import * +from migen.fhdl.module import Module from migen.flow.actor import * from migen.genlib.buffers import ReorderBuffer -class SequentialReader(Actor): +class SequentialReader(Module): def __init__(self, port): - self.port = port - assert(len(self.port.slots) == 1) - Actor.__init__(self, - ("address", Sink, [("a", self.port.hub.aw)]), - ("data", Source, [("d", self.port.hub.dw)])) + assert(len(port.slots) == 1) + self.address = Sink([("a", port.hub.aw)]) + self.data = Source([("d", port.hub.dw)]) + self.busy = Signal() - def get_fragment(self): + ### + sample = Signal() data_reg_loaded = Signal() - data_reg = Signal(self.port.hub.dw) - + data_reg = Signal(port.hub.dw) accept_new = Signal() - # We check that len(self.port.slots) == 1 - # and therefore we can assume that self.port.ack + # We check that len(port.slots) == 1 + # and therefore we can assume that port.ack # goes low until the data phase. - comb = [ - self.busy.eq(~data_reg_loaded | ~self.port.ack), - self.port.adr.eq(self.token("address").a), - self.port.we.eq(0), - accept_new.eq(~data_reg_loaded | self.endpoints["data"].ack), - self.port.stb.eq(self.endpoints["address"].stb & accept_new), - self.endpoints["address"].ack.eq(self.port.ack & accept_new), - self.endpoints["data"].stb.eq(data_reg_loaded), - self.token("data").d.eq(data_reg) + self.comb += [ + self.busy.eq(~data_reg_loaded | ~port.ack), + port.adr.eq(self.address.payload.a), + port.we.eq(0), + accept_new.eq(~data_reg_loaded | self.data.ack), + port.stb.eq(self.address.stb & accept_new), + self.address.ack.eq(port.ack & accept_new), + self.data.stb.eq(data_reg_loaded), + self.data.payload.d.eq(data_reg) ] - sync = [ - If(self.endpoints["data"].ack, - data_reg_loaded.eq(0) - ), + self.sync += [ + If(self.data.ack, data_reg_loaded.eq(0)), If(sample, data_reg_loaded.eq(1), - data_reg.eq(self.port.dat_r) + data_reg.eq(port.dat_r) ), - sample.eq(self.port.get_call_expression()) + sample.eq(port.get_call_expression()) ] - - return Fragment(comb, sync) -class OOOReader(Actor): +class OOOReader(Module): def __init__(self, port): - self.port = port - assert(len(self.port.slots) > 1) - Actor.__init__(self, - ("address", Sink, [("a", self.port.hub.aw)]), - ("data", Source, [("d", self.port.hub.dw)])) + assert(len(port.slots) > 1) + self.address = Sink([("a", port.hub.aw)]) + self.data = Source([("d", port.hub.dw)]) + self.busy = Signal() # TODO: drive busy - def get_fragment(self): - tag_width = len(self.port.tag_call) - data_width = self.port.hub.dw - depth = len(self.port.slots) + ### + + tag_width = len(port.tag_call) + data_width = port.hub.dw + depth = len(port.slots) rob = ReorderBuffer(tag_width, data_width, depth) + self.submodules += rob - comb = [ - self.port.adr.eq(self.token("address").a), - self.port.we.eq(0), - self.port.stb.eq(self.endpoints["address"].stb & rob.can_issue), - self.endpoints["address"].ack.eq(self.port.ack & rob.can_issue), - rob.issue.eq(self.endpoints["address"].stb & self.port.ack), - rob.tag_issue.eq(self.port.base + self.port.tag_issue), + self.comb += [ + port.adr.eq(self.address.payload.a), + port.we.eq(0), + port.stb.eq(self.address.stb & rob.can_issue), + self.address.ack.eq(port.ack & rob.can_issue), + rob.issue.eq(self.address.stb & port.ack), + rob.tag_issue.eq(port.base + port.tag_issue), - rob.data_call.eq(self.port.dat_r), + rob.data_call.eq(port.dat_r), - self.endpoints["data"].stb.eq(rob.can_read), - rob.read.eq(self.endpoints["data"].ack), - self.token("data").d.eq(rob.data_read) + self.data.stb.eq(rob.can_read), + rob.read.eq(self.data.ack), + self.data.payload.d.eq(rob.data_read) ] - sync = [ + self.sync += [ # Data is announced one cycle in advance. # Register the call to synchronize it with the data signal. - rob.call.eq(self.port.call), - rob.tag_call.eq(self.port.tag_call) + rob.call.eq(port.call), + rob.tag_call.eq(port.tag_call) ] - - return Fragment(comb, sync) + rob.get_fragment() -class Reader: - def __init__(self, port): - if len(port.slots) == 1: - self.__class__ = SequentialReader - SequentialReader.__init__(self, port) - else: - self.__class__ = OOOReader - OOOReader.__init__(self, port) +def Reader(port): + if len(port.slots) == 1: + return SequentialReader(port) + else: + return OOOReader(port) diff --git a/migen/actorlib/dma_wishbone.py b/migen/actorlib/dma_wishbone.py index d316a372a..c3551a3b3 100644 --- a/migen/actorlib/dma_wishbone.py +++ b/migen/actorlib/dma_wishbone.py @@ -1,58 +1,55 @@ from migen.fhdl.structure import * +from migen.fhdl.module import Module from migen.bus import wishbone from migen.flow.actor import * -class Reader(Actor): +class Reader(Module): def __init__(self): self.bus = wishbone.Interface() - Actor.__init__(self, - ("address", Sink, [("a", 30)]), - ("data", Source, [("d", 32)])) + self.address = Sink([("a", 30)]) + self.data = Source([("d", 32)]) + self.busy = Signal() + + ### - def get_fragment(self): bus_stb = Signal() - data_reg_loaded = Signal() data_reg = Signal(32) - comb = [ + self.comb += [ self.busy.eq(data_reg_loaded), self.bus.we.eq(0), - bus_stb.eq(self.endpoints["address"].stb & (~data_reg_loaded | self.endpoints["data"].ack)), + bus_stb.eq(self.address.stb & (~data_reg_loaded | self.data.ack)), self.bus.cyc.eq(bus_stb), self.bus.stb.eq(bus_stb), - self.bus.adr.eq(self.token("address").a), - self.endpoints["address"].ack.eq(self.bus.ack), - self.endpoints["data"].stb.eq(data_reg_loaded), - self.token("data").d.eq(data_reg) + self.bus.adr.eq(self.address.payload.a), + self.address.ack.eq(self.bus.ack), + self.data.stb.eq(data_reg_loaded), + self.data.payload.d.eq(data_reg) ] - sync = [ - If(self.endpoints["data"].ack, - data_reg_loaded.eq(0) - ), + self.sync += [ + If(self.data.ack, data_reg_loaded.eq(0)), If(self.bus.ack, data_reg_loaded.eq(1), data_reg.eq(self.bus.dat_r) ) ] - return Fragment(comb, sync) - -class Writer(Actor): +class Writer(Module): def __init__(self): self.bus = wishbone.Interface() - Actor.__init__(self, - ("address_data", Sink, [("a", 30), ("d", 32)])) + self.address_data = Sink([("a", 30), ("d", 32)]) + self.busy = Signal() - def get_fragment(self): - comb = [ + ### + + self.comb += [ self.busy.eq(0), self.bus.we.eq(1), - self.bus.cyc.eq(self.endpoints["address_data"].stb), - self.bus.stb.eq(self.endpoints["address_data"].stb), - self.bus.adr.eq(self.token("address_data").a), + self.bus.cyc.eq(self.address_data.stb), + self.bus.stb.eq(self.address_data.stb), + self.bus.adr.eq(self.address_data.payload.a), self.bus.sel.eq(0xf), - self.bus.dat_w.eq(self.token("address_data").d), - self.endpoints["address_data"].ack.eq(self.bus.ack) + self.bus.dat_w.eq(self.address_data.payload.d), + self.address_data.ack.eq(self.bus.ack) ] - return Fragment(comb) diff --git a/migen/actorlib/misc.py b/migen/actorlib/misc.py index b0799706c..f1d95acb6 100644 --- a/migen/actorlib/misc.py +++ b/migen/actorlib/misc.py @@ -1,68 +1,65 @@ from migen.fhdl.structure import * +from migen.fhdl.module import Module from migen.genlib.record import * from migen.genlib.fsm import * from migen.flow.actor import * # Generates integers from start to maximum-1 -class IntSequence(Actor): +class IntSequence(Module): def __init__(self, nbits, offsetbits=0, step=1): - self.nbits = nbits - self.offsetbits = offsetbits - self.step = step + parameters_layout = [("maximum", nbits)] + if offsetbits: + parameters_layout.append(("offset", offsetbits)) - parameters_layout = [("maximum", self.nbits)] - if self.offsetbits: - parameters_layout.append(("offset", self.offsetbits)) - - Actor.__init__(self, - ("parameters", Sink, parameters_layout), - ("source", Source, [("value", max(self.nbits, self.offsetbits))])) + self.parameters = Sink(parameters_layout) + self.source = Source([("value", max(nbits, offsetbits))]) + self.busy = Signal() + + ### - def get_fragment(self): load = Signal() ce = Signal() last = Signal() - maximum = Signal(self.nbits) - if self.offsetbits: - offset = Signal(self.offsetbits) - counter = Signal(self.nbits) + maximum = Signal(nbits) + if offsetbits: + offset = Signal(offsetbits) + counter = Signal(nbits) - if self.step > 1: - comb = [last.eq(counter + self.step >= maximum)] + if step > 1: + self.comb += last.eq(counter + step >= maximum) else: - comb = [last.eq(counter + 1 == maximum)] - sync = [ + self.comb += last.eq(counter + 1 == maximum) + self.sync += [ If(load, counter.eq(0), - maximum.eq(self.token("parameters").maximum), - offset.eq(self.token("parameters").offset) if self.offsetbits else None + maximum.eq(self.parameters.payload.maximum), + offset.eq(self.parameters.payload.offset) if offsetbits else None ).Elif(ce, If(last, counter.eq(0) ).Else( - counter.eq(counter + self.step) + counter.eq(counter + step) ) ) ] - if self.offsetbits: - comb.append(self.token("source").value.eq(counter + offset)) + if offsetbits: + self.comb += self.source.payload.value.eq(counter + offset) else: - comb.append(self.token("source").value.eq(counter)) - counter_fragment = Fragment(comb, sync) + self.comb += self.source.payload.value.eq(counter) fsm = FSM("IDLE", "ACTIVE") + self.submodules += fsm fsm.act(fsm.IDLE, load.eq(1), - self.endpoints["parameters"].ack.eq(1), - If(self.endpoints["parameters"].stb, fsm.next_state(fsm.ACTIVE)) + self.parameters.ack.eq(1), + If(self.parameters.stb, fsm.next_state(fsm.ACTIVE)) ) fsm.act(fsm.ACTIVE, self.busy.eq(1), - self.endpoints["source"].stb.eq(1), - If(self.endpoints["source"].ack, + self.source.stb.eq(1), + If(self.source.ack, ce.eq(1), If(last, fsm.next_state(fsm.IDLE)) ) ) - return counter_fragment + fsm.get_fragment() diff --git a/migen/actorlib/sim.py b/migen/actorlib/sim.py index 78abbeef1..8c6463b45 100644 --- a/migen/actorlib/sim.py +++ b/migen/actorlib/sim.py @@ -20,10 +20,10 @@ class TokenExchanger(Module): def _process_transactions(self, s): completed = set() for token in self.active: - ep = self.actor.endpoints[token.endpoint] + ep = getattr(self.actor, token.endpoint) if isinstance(ep, Sink): if s.rd(ep.ack) and s.rd(ep.stb): - token.value = s.multiread(ep.token) + token.value = s.multiread(ep.payload) completed.add(token) s.wr(ep.ack, 0) elif isinstance(ep, Source): @@ -38,11 +38,11 @@ class TokenExchanger(Module): def _update_control_signals(self, s): for token in self.active: - ep = self.actor.endpoints[token.endpoint] + ep = getattr(self.actor, token.endpoint) if isinstance(ep, Sink): s.wr(ep.ack, 1) elif isinstance(ep, Source): - s.multiwrite(ep.token, token.value) + s.multiwrite(ep.payload, token.value) s.wr(ep.stb, 1) else: raise TypeError @@ -56,9 +56,7 @@ class TokenExchanger(Module): transactions = None if isinstance(transactions, Token): self.active = {transactions} - elif isinstance(transactions, tuple) \ - or isinstance(transactions, list) \ - or isinstance(transactions, set): + elif isinstance(transactions, (tuple, list, set)): self.active = set(transactions) elif transactions is None: self.active = set() @@ -77,27 +75,25 @@ class TokenExchanger(Module): do_simulation.initialize = True -class SimActor(Actor): - def __init__(self, generator, *endpoint_descriptions, **misc): - Actor.__init__(self, *endpoint_descriptions, **misc) - self.token_exchanger = TokenExchanger(generator, self) +class SimActor(Module): + def __init__(self, generator): + self.busy = Signal() + self.submodules.token_exchanger = TokenExchanger(generator, self) - def update_busy(self, s): + def do_simulation(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]) + +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) 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)) + self.result = Sink(layout) + SimActor.__init__(self, _dumper_gen(prefix)) diff --git a/migen/actorlib/spi.py b/migen/actorlib/spi.py index 7b94fe45b..733e928a3 100644 --- a/migen/actorlib/spi.py +++ b/migen/actorlib/spi.py @@ -47,41 +47,35 @@ def _create_csrs_assign(layout, target, atomic, prefix=""): (MODE_EXTERNAL, MODE_SINGLE_SHOT, MODE_CONTINUOUS) = range(3) -class SingleGenerator(Actor): +class SingleGenerator(Module): def __init__(self, layout, mode): - self._mode = mode - Actor.__init__(self, ("source", Source, _convert_layout(layout))) - self._csrs, self._assigns = _create_csrs_assign(layout, - self.token("source"), self._mode != MODE_SINGLE_SHOT) + self.source = Source(_convert_layout(layout)) + self.busy = Signal() + self._csrs, assigns = _create_csrs_assign(layout, self.source.payload, + mode != MODE_SINGLE_SHOT) if mode == MODE_EXTERNAL: - self.trigger = Signal() + trigger = self.trigger = Signal() elif mode == MODE_SINGLE_SHOT: shoot = CSR() self._csrs.insert(0, shoot) - self.trigger = shoot.re + trigger = shoot.re elif mode == MODE_CONTINUOUS: enable = CSRStorage() self._csrs.insert(0, enable) - self.trigger = enable.storage + trigger = enable.storage else: raise ValueError + self.comb += self.busy.eq(self.source.stb) + stmts = [self.source.stb.eq(trigger)] + assigns + self.sync += [If(self.source.ack | ~self.source.stb, *stmts)] def get_csrs(self): return self._csrs - - 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, AutoCSR): +class Collector(Module, AutoCSR): def __init__(self, layout, depth=1024): - Actor.__init__(self, ("sink", Sink, layout)) + self.sink = Sink(layout) + self.busy = Signal() self._depth = depth self._dw = sum(len(s) for s in self.token("sink").flatten()) @@ -89,13 +83,17 @@ class Collector(Actor, AutoCSR): self._r_wc = CSRStorage(bits_for(self._depth), write_from_dev=True, atomic_write=True) self._r_ra = CSRStorage(bits_for(self._depth-1)) self._r_rd = CSRStatus(self._dw) + + ### - def get_fragment(self): mem = Memory(self._dw, self._depth) + self.specials += mem wp = mem.get_port(write_capable=True) rp = mem.get_port() - comb = [ + self.comb += [ + self.busy.eq(0), + If(self._r_wc.r != 0, self.endpoints["sink"].ack.eq(1), If(self.endpoints["sink"].stb, @@ -113,5 +111,3 @@ class Collector(Actor, AutoCSR): rp.adr.eq(self._r_ra.storage), self._r_rd.status.eq(rp.dat_r) ] - - return Fragment(comb, specials={mem}) diff --git a/migen/actorlib/structuring.py b/migen/actorlib/structuring.py index 0041806d0..dd917bbc2 100644 --- a/migen/actorlib/structuring.py +++ b/migen/actorlib/structuring.py @@ -1,4 +1,5 @@ from migen.fhdl.structure import * +from migen.fhdl.module import Module from migen.flow.actor import * def _rawbits_layout(l): @@ -9,45 +10,42 @@ def _rawbits_layout(l): class Cast(CombinatorialActor): def __init__(self, layout_from, layout_to, reverse_from=False, reverse_to=False): - self.reverse_from = reverse_from - self.reverse_to = reverse_to - CombinatorialActor.__init__(self, - ("sink", Sink, _rawbits_layout(layout_from)), - ("source", Source, _rawbits_layout(layout_to))) + self.sink = Sink(_rawbits_layout(layout_from)) + self.source = Source(_rawbits_layout(layout_to)) + CombinatorialActor.__init__(self) - def get_process_fragment(self): - sigs_from = self.token("sink").flatten() - if self.reverse_from: + ### + + sigs_from = self.sink.payload.flatten() + if reverse_from: sigs_from = list(reversed(sigs_from)) - sigs_to = self.token("source").flatten() - if self.reverse_to: + sigs_to = self.source.payload.flatten() + if reverse_to: sigs_to = list(reversed(sigs_to)) if sum(len(s) for s in sigs_from) != sum(len(s) for s in sigs_to): raise TypeError - return Fragment([ - Cat(*sigs_to).eq(Cat(*sigs_from)) - ]) + self.comb += Cat(*sigs_to).eq(Cat(*sigs_from)) def pack_layout(l, n): return [("chunk"+str(i), l) for i in range(n)] -class Unpack(Actor): +class Unpack(Module): def __init__(self, n, layout_to): - self.n = n - Actor.__init__(self, - ("sink", Sink, pack_layout(layout_to, n)), - ("source", Source, layout_to)) + self.sink = Sink(pack_layout(layout_to, n)) + self.source = Source(layout_to) + self.busy = Signal() - def get_fragment(self): - mux = Signal(max=self.n) + ### + + mux = Signal(max=n) last = Signal() - comb = [ - last.eq(mux == (self.n-1)), - self.endpoints["source"].stb.eq(self.endpoints["sink"].stb), - self.endpoints["sink"].ack.eq(last & self.endpoints["source"].ack) + self.comb += [ + last.eq(mux == (n-1)), + self.source.stb.eq(self.sink.stb), + self.sink.ack.eq(last & self.source.ack) ] - sync = [ - If(self.endpoints["source"].stb & self.endpoints["source"].ack, + self.sync += [ + If(self.source.stb & self.source.ack, If(last, mux.eq(0) ).Else( @@ -56,39 +54,36 @@ class Unpack(Actor): ) ] cases = {} - for i in range(self.n): - cases[i] = [self.token("source").raw_bits().eq(getattr(self.token("sink"), "chunk"+str(i)).raw_bits())] - comb.append(Case(mux, cases).makedefault()) - return Fragment(comb, sync) + for i in range(n): + cases[i] = [self.source.payload.raw_bits().eq(getattr(self.sink.payload, "chunk"+str(i)).raw_bits())] + self.comb += Case(mux, cases).makedefault() -class Pack(Actor): +class Pack(Module): def __init__(self, layout_from, n): - self.n = n - Actor.__init__(self, - ("sink", Sink, layout_from), - ("source", Source, pack_layout(layout_from, n))) + self.sink = Sink(layout_from) + self.source = Source(pack_layout(layout_from, n)) + self.busy = Signal() - def get_fragment(self): - demux = Signal(max=self.n) + ### + + demux = Signal(max=n) load_part = Signal() strobe_all = Signal() cases = {} - for i in range(self.n): - cases[i] = [getattr(self.token("source"), "chunk"+str(i)).raw_bits().eq(self.token("sink").raw_bits())] - comb = [ + for i in range(n): + cases[i] = [getattr(self.source.payload, "chunk"+str(i)).raw_bits().eq(self.sink.payload.raw_bits())] + self.comb += [ self.busy.eq(strobe_all), - self.endpoints["sink"].ack.eq(~strobe_all | self.endpoints["source"].ack), - self.endpoints["source"].stb.eq(strobe_all), - load_part.eq(self.endpoints["sink"].stb & self.endpoints["sink"].ack) + self.sink.ack.eq(~strobe_all | self.source.ack), + self.source.stb.eq(strobe_all), + load_part.eq(self.sink.stb & self.sink.ack) ] - sync = [ - If(self.endpoints["source"].ack, - strobe_all.eq(0) - ), + self.sync += [ + If(self.source.ack, strobe_all.eq(0)), If(load_part, Case(demux, cases), - If(demux == (self.n - 1), + If(demux == (n - 1), demux.eq(0), strobe_all.eq(1) ).Else( @@ -96,4 +91,3 @@ class Pack(Actor): ) ) ] - return Fragment(comb, sync) diff --git a/migen/flow/actor.py b/migen/flow/actor.py index 867a50096..2d7e134c6 100644 --- a/migen/flow/actor.py +++ b/migen/flow/actor.py @@ -1,173 +1,105 @@ from migen.fhdl.structure import * +from migen.fhdl.module import Module from migen.genlib.misc import optree from migen.genlib.record import * -class Endpoint: - def __init__(self, token): - self.token = token - if isinstance(self, Sink): - self.stb = Signal(name="stb_i") - self.ack = Signal(name="ack_o") +def _make_m2s(layout): + r = [] + for f in layout: + if isinstance(f[1], (int, tuple)): + r.append((f[0], f[1], DIR_M_TO_S)) else: - self.stb = Signal(name="stb_o") - self.ack = Signal(name="ack_i") - - def token_signal(self): - sigs = self.token.flatten() - assert(len(sigs) == 1) - return sigs[0] - - def __hash__(self): - return id(self) - - def __repr__(self): - return "" + r.append((f[0], _make_m2s(f[1]))) + return r +class _Endpoint(Record): + def __init__(self, layout): + full_layout = [ + ("payload", _make_m2s(layout)), + ("stb", 1, DIR_M_TO_S), + ("ack", 1, DIR_S_TO_M) + ] + Record.__init__(self, full_layout) -class Sink(Endpoint): - def __repr__(self): - return "" +class Source(_Endpoint): + def connect(self, sink): + return Record.connect(self, sink) -class Source(Endpoint): - def __repr__(self): - return "" +class Sink(_Endpoint): + def connect(self, source): + return source.connect(self) -class Actor(HUID): - def __init__(self, *endpoint_descriptions, endpoints=None): - HUID.__init__(self) - if endpoints is None: - self.endpoints = {} - for desc in endpoint_descriptions: - # desc: (name, Sink/Source, token layout or existing record) - if isinstance(desc[2], Record): - token = desc[2] - else: - token = Record(desc[2]) - ep = desc[1](token) - self.endpoints[desc[0]] = ep - else: - self.endpoints = endpoints - self.name = None +def get_endpoints(obj, filt=_Endpoint): + if hasattr(obj, "get_endpoints") and callable(obj.get_endpoints): + return obj.get_endpoints(filt) + r = dict() + for k, v in obj.__dict__.items(): + if isinstance(v, filt): + r[k] = v + return r + +def get_single_ep(obj, filt): + eps = get_endpoints(obj, filt) + if len(eps) != 1: + raise ValueError("More than one endpoint") + return list(eps.items())[0] + +class BinaryActor(Module): + def __init__(self, *args, **kwargs): self.busy = Signal() + sink = get_single_ep(self, Sink)[1] + source = get_single_ep(self, Source)[1] + self.build_binary_control(sink.stb, sink.ack, source.stb, source.ack, *args, **kwargs) - def token(self, ep): - return self.endpoints[ep].token - - def filter_endpoints(self, cl): - return sorted(k for k, v in self.endpoints.items() if isinstance(v, cl)) - - def sinks(self): - return self.filter_endpoints(Sink) - - def sources(self): - return self.filter_endpoints(Source) - - def single_sink(self): - eps = self.sinks() - assert(len(eps) == 1) - return eps[0] - - def single_source(self): - eps = self.sources() - assert(len(eps) == 1) - return eps[0] - - def get_control_fragment(self): - raise NotImplementedError("Actor classes must overload get_control_fragment or get_fragment") - - def get_process_fragment(self): - raise NotImplementedError("Actor classes must overload get_process_fragment or get_fragment") - - def get_fragment(self): - return self.get_control_fragment() + self.get_process_fragment() - - def __repr__(self): - r = "<" + self.__class__.__name__ - if self.name is not None: - r += ": " + self.name - r += ">" - return r - -class BinaryActor(Actor): - def get_binary_control_fragment(self, stb_i, ack_o, stb_o, ack_i): - raise NotImplementedError("Binary actor classes must overload get_binary_control_fragment") - - def get_control_fragment(self): - def get_single_ep(l): - if len(l) != 1: - raise ValueError("Binary actors have exactly one sink and one source. Consider using plumbing actors.") - return self.endpoints[l[0]] - sink = get_single_ep(self.sinks()) - source = get_single_ep(self.sources()) - return self.get_binary_control_fragment(sink.stb, sink.ack, source.stb, source.ack) + def build_binary_control(self, stb_i, ack_o, stb_o, ack_i): + raise NotImplementedError("Binary actor classes must overload build_binary_control_fragment") class CombinatorialActor(BinaryActor): - def get_binary_control_fragment(self, stb_i, ack_o, stb_o, ack_i): - return Fragment([stb_o.eq(stb_i), ack_o.eq(ack_i), self.busy.eq(0)]) + def build_binary_control(self, stb_i, ack_o, stb_o, ack_i): + self.comb += [stb_o.eq(stb_i), ack_o.eq(ack_i), self.busy.eq(0)] class SequentialActor(BinaryActor): - def __init__(self, delay, *endpoint_descriptions, **misc): - self.delay = delay + def __init__(self, delay): self.trigger = Signal() - BinaryActor.__init__(self, *endpoint_descriptions, **misc) + BinaryActor.__init__(self, delay) - def get_binary_control_fragment(self, stb_i, ack_o, stb_o, ack_i): + def build_binary_control(self, stb_i, ack_o, stb_o, ack_i, delay): ready = Signal() - timer = Signal(max=self.delay+1) - comb = [ready.eq(timer == 0)] - sync = [ - If(self.trigger, - timer.eq(self.delay) + timer = Signal(max=delay+1) + self.comb += ready.eq(timer == 0) + self.sync += If(self.trigger, + timer.eq(delay) ).Elif(~ready, timer.eq(timer - 1) ) - ] mask = Signal() - comb += [ + self.comb += [ stb_o.eq(ready & mask), self.trigger.eq(stb_i & (ack_i | ~mask) & ready), ack_o.eq(self.trigger), - busy.eq(~ready) + self.busy.eq(~ready) ] - sync += [ + self.sync += [ If(self.trigger, mask.eq(1)), If(stb_o & ack_i, mask.eq(0)) ] - return Fragment(comb, sync) - class PipelinedActor(BinaryActor): - def __init__(self, latency, *endpoint_descriptions, **misc): - self.latency = latency + def __init__(self, latency): self.pipe_ce = Signal() - BinaryActor.__init__(self, *endpoint_descriptions, **misc) + BinaryActor.__init__(self, latency) - def get_binary_control_fragment(self, stb_i, ack_o, stb_o, ack_i): - valid = Signal(self.latency) - if self.latency > 1: - sync = [If(self.pipe_ce, valid.eq(Cat(stb_i, valid[:self.latency-1])))] + def build_binary_control(self, stb_i, ack_o, stb_o, ack_i, latency): + valid = Signal(latency) + if latency > 1: + self.sync += If(self.pipe_ce, valid.eq(Cat(stb_i, valid[:latency-1]))) else: - sync = [If(self.pipe_ce, valid.eq(stb_i))] - last_valid = valid[self.latency-1] - - comb = [ + self.sync += If(self.pipe_ce, valid.eq(stb_i)) + last_valid = valid[latency-1] + self.comb += [ self.pipe_ce.eq(ack_i | ~last_valid), ack_o.eq(self.pipe_ce), stb_o.eq(last_valid), - self.busy.eq(optree("|", [valid[i] for i in range(self.latency)])) + self.busy.eq(optree("|", [valid[i] for i in range(latency)])) ] - - return Fragment(comb, sync) - -def get_conn_fragment(source, sink): - assert isinstance(source, Source) - assert isinstance(sink, Sink) - sigs_source = source.token.flatten() - sigs_sink = sink.token.flatten() - comb = [ - source.ack.eq(sink.ack), - sink.stb.eq(source.stb), - Cat(*sigs_sink).eq(Cat(*sigs_source)) - ] - return Fragment(comb) diff --git a/migen/flow/hooks.py b/migen/flow/hooks.py index 82ae60a58..7c20a0eb0 100644 --- a/migen/flow/hooks.py +++ b/migen/flow/hooks.py @@ -30,7 +30,7 @@ class DFGHook(Module): def __init__(self, dfg, create): assert(not dfg.is_abstract()) self.nodepair_to_ep = defaultdict(dict) - for hookn, (u, v, data) in dfg.edges_iter(data=True): + for hookn, (u, v, data) in enumerate(dfg.edges_iter(data=True)): ep_to_hook = self.nodepair_to_ep[(u, v)] ep = data["source"] h = create(u, ep, v) diff --git a/migen/flow/network.py b/migen/flow/network.py index 4f222143a..a9970a74a 100644 --- a/migen/flow/network.py +++ b/migen/flow/network.py @@ -4,15 +4,13 @@ from migen.fhdl.structure import * from migen.genlib.misc import optree from migen.flow.actor import * from migen.flow import plumbing -from migen.flow.isd import DFGReporter # Abstract actors mean that the actor class should be instantiated with the parameters # from the dictionary. They are needed to enable actor duplication or sharing during # elaboration, and automatic parametrization of plumbing actors. -class AbstractActor(HUID): +class AbstractActor: def __init__(self, actor_class, parameters=dict(), name=None): - HUID.__init__(self) self.actor_class = actor_class self.parameters = parameters self.name = name @@ -27,6 +25,7 @@ class AbstractActor(HUID): r += ">" return r +# TODO: rewrite this without networkx and without non-determinism class DataFlowGraph(MultiDiGraph): def __init__(self): MultiDiGraph.__init__(self) @@ -35,8 +34,6 @@ class DataFlowGraph(MultiDiGraph): def add_connection(self, source_node, sink_node, source_ep=None, sink_ep=None, # default: assume nodes have 1 source/sink and use that one source_subr=None, sink_subr=None): # default: use whole record - assert(isinstance(source_node, (Actor, AbstractActor))) - assert(isinstance(sink_node, (Actor, AbstractActor))) self.add_edge(source_node, sink_node, source=source_ep, sink=sink_ep, source_subr=source_subr, sink_subr=sink_subr) @@ -158,7 +155,7 @@ class DataFlowGraph(MultiDiGraph): continue other_ep = data["source"] if other_ep is None: - other_ep = other.single_source() + other_ep = get_single_ep(other, Source)[1] elif a.actor_class in plumbing.layout_source: edges = self.out_edges(a, data=True) assert(len(edges) == 1) @@ -167,10 +164,10 @@ class DataFlowGraph(MultiDiGraph): continue other_ep = data["sink"] if other_ep is None: - other_ep = other.single_sink() + other_ep = get_single_ep(other, Sink)[1] else: raise AssertionError - layout = other.token(other_ep).layout + layout = other_ep.payload.layout a.parameters["layout"] = layout self.instantiate(a) @@ -184,9 +181,9 @@ class DataFlowGraph(MultiDiGraph): # 3. resolve default eps for u, v, d in self.edges_iter(data=True): if d["source"] is None: - d["source"] = u.single_source() + d["source"] = get_single_ep(u, Source)[0] if d["sink"] is None: - d["sink"] = v.single_sink() + d["sink"] = get_single_ep(v, Sink)[0] # Elaboration turns an abstract DFG into a physical one. # Pass 1: eliminate subrecords and divergences @@ -203,29 +200,14 @@ class DataFlowGraph(MultiDiGraph): optimizer(self) self._instantiate_actors() -class CompositeActor(Actor): - def __init__(self, dfg, debugger=False, debugger_nbits=48): +class CompositeActor(Module): + def __init__(self, dfg): dfg.elaborate() - self.dfg = dfg - if debugger: - self.debugger = DFGReporter(self.dfg, debugger_nbits) - Actor.__init__(self) - - def get_csrs(self): - if hasattr(self, "debugger"): - return self.debugger.get_csrs() - else: - return [] - - def get_fragment(self): - comb = [self.busy.eq(optree("|", [node.busy for node in self.dfg]))] - fragment = Fragment(comb) - for node in self.dfg: - fragment += node.get_fragment() - for u, v, d in self.dfg.edges_iter(data=True): - ep_src = u.endpoints[d["source"]] - ep_dst = v.endpoints[d["sink"]] - fragment += get_conn_fragment(ep_src, ep_dst) - if hasattr(self, "debugger"): - fragment += self.debugger.get_fragment() - return fragment + self.busy = Signal() + self.comb += [self.busy.eq(optree("|", [node.busy for node in dfg]))] + for node in dfg: + self.submodules += node + for u, v, d in dfg.edges_iter(data=True): + ep_src = getattr(u, d["source"]) + ep_dst = getattr(v, d["sink"]) + self.comb += ep_src.connect(ep_dst) diff --git a/migen/flow/perftools.py b/migen/flow/perftools.py index ff4dcb8a9..9bb373392 100644 --- a/migen/flow/perftools.py +++ b/migen/flow/perftools.py @@ -39,7 +39,7 @@ class EndpointReporter(EndpointSimHook): class DFGReporter(DFGHook): def __init__(self, dfg): - DFGHook.__init__(self, dfg, lambda u, ep, v: EndpointReporter(u.endpoints[ep])) + DFGHook.__init__(self, dfg, lambda u, ep, v: EndpointReporter(getattr(u, ep))) def get_edge_labels(self): d = dict() diff --git a/migen/flow/plumbing.py b/migen/flow/plumbing.py index d19abc077..8edec8961 100644 --- a/migen/flow/plumbing.py +++ b/migen/flow/plumbing.py @@ -6,54 +6,52 @@ from migen.genlib.misc import optree class Buffer(PipelinedActor): def __init__(self, layout): - PipelinedActor.__init__(self, 1, - ("d", Sink, layout), ("q", Source, layout)) - - def get_process_fragment(self): - sigs_d = self.token("d").flatten() - sigs_q = self.token("q").flatten() - sync = [If(self.pipe_ce, Cat(*sigs_q).eq(Cat(*sigs_d)))] - return Fragment(sync=sync) + self.d = Sink(layout) + self.q = Source(layout) + PipelinedActor.__init__(self, 1) + self.sync += If(self.pipe_ce, self.q.payload.eq(self.d.payload)) -class Combinator(Module, Actor): +class Combinator(Module): def __init__(self, layout, subrecords): - eps = [("source", Source, layout)] - eps += [("sink"+str(n), Sink, layout_partial(layout, r)) - for n, r in enumerate(subrecords)] - Actor.__init__(self, *eps) + self.source = Source(layout) + sinks = [] + for n, r in enumerate(subrecords): + s = Sink(layout_partial(layout, *r)) + setattr(self, "sink"+str(n), s) + sinks.append(s) + self.busy = Signal() ### - source = self.endpoints["source"] - sinks = [self.endpoints["sink"+str(n)] - for n in range(len(self.endpoints)-1)] - self.comb += [source.stb.eq(optree("&", [sink.stb for sink in sinks]))] - self.comb += [sink.ack.eq(source.ack & source.stb) for sink in sinks] - self.comb += [source.token.eq(sink.token) for sink in sinks] + self.comb += [ + self.busy.eq(0), + self.source.stb.eq(optree("&", [sink.stb for sink in sinks])) + ] + self.comb += [sink.ack.eq(self.source.ack & self.source.stb) for sink in sinks] + self.comb += [self.source.payload.eq(sink.payload) for sink in sinks] -class Splitter(Module, Actor): +class Splitter(Module): def __init__(self, layout, subrecords): - eps = [("sink", Sink, layout)] - eps += [("source"+str(n), Source, layout_partial(layout, *r)) - for n, r in enumerate(subrecords)] - Actor.__init__(self, *eps) + self.sink = Sink(layout) + sources = [] + for n, r in enumerate(subrecords): + s = Source(layout_partial(layout, *r)) + setattr(self, "source"+str(n), s) + sources.append(s) + self.busy = Signal() ### - sources = [self.endpoints[e] for e in self.sources()] - sink = self.endpoints[self.sinks()[0]] - - self.comb += [source.token.eq(sink.token) for source in sources] - + self.comb += [source.payload.eq(self.sink.payload) for source in sources] already_acked = Signal(len(sources)) - self.sync += If(sink.stb, + self.sync += If(self.sink.stb, already_acked.eq(already_acked | Cat(*[s.ack for s in sources])), - If(sink.ack, already_acked.eq(0)) + If(self.sink.ack, already_acked.eq(0)) ) - self.comb += sink.ack.eq(optree("&", + self.comb += self.sink.ack.eq(optree("&", [s.ack | already_acked[n] for n, s in enumerate(sources)])) for n, s in enumerate(sources): - self.comb += s.stb.eq(sink.stb & ~already_acked[n]) + self.comb += s.stb.eq(self.sink.stb & ~already_acked[n]) # Actors whose layout should be inferred from what their single sink is connected to. layout_sink = {Buffer, Splitter} diff --git a/migen/genlib/record.py b/migen/genlib/record.py index f1a22c706..4d7906475 100644 --- a/migen/genlib/record.py +++ b/migen/genlib/record.py @@ -34,7 +34,7 @@ def layout_get(layout, name): for f in layout: if f[0] == name: return f - raise KeyError + raise KeyError(name) def layout_partial(layout, *elements): r = [] diff --git a/migen/pytholite/io.py b/migen/pytholite/io.py index 63c92a60b..c20cc467a 100644 --- a/migen/pytholite/io.py +++ b/migen/pytholite/io.py @@ -17,7 +17,7 @@ class Pytholite(UnifiedIOObject): if dataflow is not None: self.busy.reset = 1 self.memory_ports = dict((mem, mem.get_port(write_capable=True, we_granularity=8)) - for mem in self._memories) + for mem in self.buses.values() if isinstance(mem, Memory)) def get_fragment(self): return UnifiedIOObject.get_fragment(self) + self.fragment @@ -39,7 +39,7 @@ class _TokenPullExprCompiler(ExprCompiler): if not isinstance(node.slice, ast.Index): raise NotImplementedError field = ast.literal_eval(node.slice.value) - signal = getattr(self.ep.token, field) + signal = getattr(self.ep.payload, field) return signal @@ -47,7 +47,7 @@ def _gen_df_io(compiler, modelname, to_model, from_model): epname = ast.literal_eval(to_model["endpoint"]) values = to_model["value"] idle_wait = ast.literal_eval(to_model["idle_wait"]) - ep = compiler.ioo.endpoints[epname] + ep = getattr(compiler.ioo, epname) if idle_wait: state = [compiler.ioo.busy.eq(0)] else: @@ -76,7 +76,7 @@ def _gen_df_io(compiler, modelname, to_model, from_model): raise NotImplementedError for akey, value in zip(values.keys, values.values): key = ast.literal_eval(akey) - signal = getattr(ep.token, key) + signal = getattr(ep.payload, key) state.append(signal.eq(compiler.ec.visit_expr(value))) state += [ ep.stb.eq(1), diff --git a/migen/uio/ioo.py b/migen/uio/ioo.py index e6c954b55..e618c2c62 100644 --- a/migen/uio/ioo.py +++ b/migen/uio/ioo.py @@ -7,15 +7,14 @@ from migen.bus import wishbone, memory from migen.bus.transactions import * from migen.uio.trampoline import Trampoline -class UnifiedIOObject(Actor): +class UnifiedIOObject(Module): def __init__(self, dataflow=None, buses={}): if dataflow is not None: - Actor.__init__(self, *dataflow) + self.busy = Signal() + for name, cl, layout in dataflow: + setattr(self, name, cl(layout)) self.buses = buses - self._memories = set(v for v in self.buses.values() if isinstance(v, Memory)) - - def get_fragment(self): - return Fragment(specials=self._memories) + self.specials += set(v for v in self.buses.values() if isinstance(v, Memory)) (_WAIT_COMPLETE, _WAIT_POLL) = range(2) @@ -24,12 +23,12 @@ class UnifiedIOSimulation(UnifiedIOObject): self.generator = Trampoline(generator) UnifiedIOObject.__init__(self, dataflow, buses) - self.callers = [] + callers = [] self.busname_to_caller_id = {} if dataflow is not None: - self.callers.append(TokenExchanger(self.dispatch_g(0), self)) + callers.append(TokenExchanger(self.dispatch_g(0), self)) for k, v in self.buses.items(): - caller_id = len(self.callers) + caller_id = len(callers) self.busname_to_caller_id[k] = caller_id g = self.dispatch_g(caller_id) if isinstance(v, wishbone.Interface): @@ -38,7 +37,8 @@ class UnifiedIOSimulation(UnifiedIOObject): caller = memory.Initiator(g, v) else: raise NotImplementedError - self.callers.append(caller) + callers.append(caller) + self.submodules += callers self.dispatch_state = _WAIT_COMPLETE self.dispatch_caller = 0 @@ -75,7 +75,3 @@ class UnifiedIOSimulation(UnifiedIOObject): yield self.pending_transaction else: yield None - - def get_fragment(self): - f = UnifiedIOObject.get_fragment(self) - return sum([c.get_fragment() for c in self.callers], f)