flow: use Module and new Record APIs

This commit is contained in:
Sebastien Bourdeauducq 2013-04-10 19:12:42 +02:00
parent 20bdd424c8
commit 692794a21f
20 changed files with 481 additions and 551 deletions

View File

@ -1,5 +1,6 @@
from random import Random from random import Random
from migen.fhdl.module import Module
from migen.flow.network import * from migen.flow.network import *
from migen.flow.transactions import * from migen.flow.transactions import *
from migen.actorlib import dma_wishbone, dma_asmi from migen.actorlib import dma_wishbone, dma_asmi
@ -26,12 +27,22 @@ def adrgen_gen():
print("Address: " + str(i)) print("Address: " + str(i))
yield Token("address", {"a": 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(): def dumper_gen():
while True: while True:
t = Token("data", idle_wait=True) t = Token("data", idle_wait=True)
yield t yield t
print("Received: " + str(t.value["d"])) 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(): def trgen_gen():
for i in range(10): for i in range(10):
a = i a = i
@ -39,75 +50,78 @@ def trgen_gen():
print("Address: " + str(a) + " Data: " + str(d)) print("Address: " + str(a) + " Data: " + str(d))
yield Token("address_data", {"a": a, "d": d}) yield Token("address_data", {"a": a, "d": d})
def wishbone_sim(efragment, master, end_simulation): class SimTrGen(SimActor):
peripheral = wishbone.Target(MyModelWB()) def __init__(self):
tap = wishbone.Tap(peripheral.bus) self.address_data = Source([("a", 30), ("d", 32)])
interconnect = wishbone.InterconnectPointToPoint(master.bus, peripheral.bus) SimActor.__init__(self, trgen_gen())
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()
def asmi_sim(efragment, hub, end_simulation): class TBWishbone(Module):
def _end_simulation(s): def __init__(self, master):
s.interrupt = end_simulation(s) self.submodules.peripheral = wishbone.Target(MyModelWB())
peripheral = asmibus.Target(MyModelASMI(), hub) self.submodules.tap = wishbone.Tap(self.peripheral.bus)
tap = asmibus.Tap(hub) self.submodules.interconnect = wishbone.InterconnectPointToPoint(master.bus,
def _end_simulation(s): self.peripheral.bus)
s.interrupt = end_simulation(s)
fragment = efragment \ class TBWishboneReader(TBWishbone):
+ peripheral.get_fragment() \ def __init__(self):
+ tap.get_fragment() \ self.adrgen = SimAdrGen(30)
+ Fragment(sim=[_end_simulation]) self.reader = dma_wishbone.Reader()
sim = Simulator(fragment) self.dumper = SimDumper()
sim.run() 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(): def test_wb_reader():
print("*** Testing Wishbone reader") print("*** Testing Wishbone reader")
adrgen = SimActor(adrgen_gen(), ("address", Source, [("a", 30)])) Simulator(TBWishboneReader()).run()
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))
def test_wb_writer(): def test_wb_writer():
print("*** Testing Wishbone writer") print("*** Testing Wishbone writer")
trgen = SimActor(trgen_gen(), ("address_data", Source, [("a", 30), ("d", 32)])) Simulator(TBWishboneWriter()).run()
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))
def test_asmi_reader(nslots): def test_asmi_reader(nslots):
print("*** Testing ASMI reader (nslots={})".format(nslots)) print("*** Testing ASMI reader (nslots={})".format(nslots))
Simulator(TBAsmiReader(nslots)).run()
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))
test_wb_reader() test_wb_reader()
test_wb_writer() test_wb_writer()

View File

@ -8,7 +8,12 @@ def source_gen():
for i in range(10): for i in range(10):
v = i + 5 v = i + 5
print("==> " + str(v)) 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(): def sink_gen():
while True: while True:
@ -16,16 +21,20 @@ def sink_gen():
yield t yield t
print(t.value["value"]) print(t.value["value"])
class SimSink(SimActor):
def __init__(self):
self.sink = Sink([("value", 32)])
SimActor.__init__(self, sink_gen())
def main(): def main():
source = SimActor(source_gen(), ("source", Source, [("value", 32)])) source = SimSource()
loop = misc.IntSequence(32) loop = misc.IntSequence(32)
sink = SimActor(sink_gen(), ("sink", Sink, [("value", 32)])) sink = SimSink()
g = DataFlowGraph() g = DataFlowGraph()
g.add_connection(source, loop) g.add_connection(source, loop)
g.add_connection(loop, sink) g.add_connection(loop, sink)
comp = CompositeActor(g) comp = CompositeActor(g)
fragment = comp.get_fragment() sim = Simulator(comp)
sim = Simulator(fragment)
sim.run(500) sim.run(500)
main() main()

View File

@ -11,24 +11,34 @@ from migen.sim.generic import Simulator
from migen.flow import perftools from migen.flow import perftools
pack_factor = 5 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(): def source_gen():
for i in count(0): for i in count(0):
yield Token("source", {"value": i}) yield Token("source", {"value": i})
class SimSource(SimActor):
def __init__(self):
self.source = Source(base_layout)
SimActor.__init__(self, source_gen())
def sink_gen(): def sink_gen():
while True: while True:
t = Token("sink") t = Token("sink")
yield t yield t
print(t.value["value"]) print(t.value["value"])
def main(): class SimSink(SimActor):
base_layout = [("value", 32)] def __init__(self):
packed_layout = structuring.pack_layout(base_layout, pack_factor) self.sink = Sink(base_layout)
rawbits_layout = [("value", 32*pack_factor)] SimActor.__init__(self, sink_gen())
source = SimActor(source_gen(), ("source", Source, base_layout)) class TB(Module):
sink = SimActor(sink_gen(), ("sink", Sink, base_layout)) def __init__(self):
source = SimSource()
sink = SimSink()
# A tortuous way of passing integer tokens. # A tortuous way of passing integer tokens.
packer = structuring.Pack(base_layout, pack_factor) packer = structuring.Pack(base_layout, pack_factor)
@ -36,23 +46,22 @@ def main():
from_raw = structuring.Cast(rawbits_layout, packed_layout) from_raw = structuring.Cast(rawbits_layout, packed_layout)
unpacker = structuring.Unpack(pack_factor, base_layout) unpacker = structuring.Unpack(pack_factor, base_layout)
g = DataFlowGraph() self.g = DataFlowGraph()
g.add_connection(source, packer) self.g.add_connection(source, packer)
g.add_connection(packer, to_raw) self.g.add_connection(packer, to_raw)
g.add_connection(to_raw, from_raw) self.g.add_connection(to_raw, from_raw)
g.add_connection(from_raw, unpacker) self.g.add_connection(from_raw, unpacker)
g.add_connection(unpacker, sink) self.g.add_connection(unpacker, sink)
comp = CompositeActor(g) self.submodules.comp = CompositeActor(self.g)
reporter = perftools.DFGReporter(g) self.submodules.reporter = perftools.DFGReporter(self.g)
fragment = comp.get_fragment() + reporter.get_fragment() def main():
sim = Simulator(fragment) tb = TB()
sim.run(1000) sim = Simulator(tb).run(1000)
g_layout = nx.spectral_layout(g) g_layout = nx.spectral_layout(tb.g)
nx.draw(g, g_layout) nx.draw(tb.g, g_layout)
nx.draw_networkx_edge_labels(g, g_layout, reporter.get_edge_labels()) nx.draw_networkx_edge_labels(tb.g, g_layout, tb.reporter.get_edge_labels())
plt.show() plt.show()
main() main()

View File

@ -11,6 +11,11 @@ def number_gen():
for i in range(10): for i in range(10):
yield Token("result", {"r": i}) yield Token("result", {"r": i})
class SimNumberGen(SimActor):
def __init__(self):
self.result = Source(layout)
SimActor.__init__(self, number_gen())
def run_sim(ng): def run_sim(ng):
g = DataFlowGraph() g = DataFlowGraph()
d = Dumper(layout) d = Dumper(layout)
@ -23,7 +28,7 @@ def run_sim(ng):
def main(): def main():
print("Simulating native Python:") print("Simulating native Python:")
ng_native = SimActor(number_gen(), ("result", Source, layout)) ng_native = SimNumberGen()
run_sim(ng_native) run_sim(ng_native)
print("Simulating Pytholite:") print("Simulating Pytholite:")
@ -31,6 +36,7 @@ def main():
run_sim(ng_pytholite) run_sim(ng_pytholite)
print("Converting Pytholite to Verilog:") print("Converting Pytholite to Verilog:")
ng_pytholite = make_pytholite(number_gen, dataflow=[("result", Source, layout)])
print(verilog.convert(ng_pytholite)) print(verilog.convert(ng_pytholite))
main() main()

View File

@ -66,6 +66,9 @@ def main():
run_sim(ng_pytholite) run_sim(ng_pytholite)
print("Converting Pytholite to Verilog:") print("Converting Pytholite to Verilog:")
ng_pytholite = make_pytholite(gen,
dataflow=dataflow,
buses=buses)
print(verilog.convert(ng_pytholite.get_fragment())) print(verilog.convert(ng_pytholite.get_fragment()))
main() main()

View File

@ -10,22 +10,31 @@ def source_gen():
print("Sending: " + str(i)) print("Sending: " + str(i))
yield Token("source", {"value": 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(): def sink_gen():
while True: while True:
t = Token("sink") t = Token("sink")
yield t yield t
print("Received: " + str(t.value["value"])) print("Received: " + str(t.value["value"]))
def main(): class SimSink(SimActor):
source = SimActor(source_gen(), ("source", Source, [("value", 32)])) def __init__(self):
sink = SimActor(sink_gen(), ("sink", Sink, [("value", 32)])) self.sink = Sink([("value", 32)])
g = DataFlowGraph() SimActor.__init__(self, sink_gen())
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()
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()

View File

@ -1,91 +1,83 @@
from migen.fhdl.structure import * from migen.fhdl.structure import *
from migen.fhdl.module import Module
from migen.flow.actor import * from migen.flow.actor import *
from migen.genlib.buffers import ReorderBuffer from migen.genlib.buffers import ReorderBuffer
class SequentialReader(Actor): class SequentialReader(Module):
def __init__(self, port): def __init__(self, port):
self.port = port assert(len(port.slots) == 1)
assert(len(self.port.slots) == 1) self.address = Sink([("a", port.hub.aw)])
Actor.__init__(self, self.data = Source([("d", port.hub.dw)])
("address", Sink, [("a", self.port.hub.aw)]), self.busy = Signal()
("data", Source, [("d", self.port.hub.dw)]))
###
def get_fragment(self):
sample = Signal() sample = Signal()
data_reg_loaded = Signal() data_reg_loaded = Signal()
data_reg = Signal(self.port.hub.dw) data_reg = Signal(port.hub.dw)
accept_new = Signal() accept_new = Signal()
# We check that len(self.port.slots) == 1 # We check that len(port.slots) == 1
# and therefore we can assume that self.port.ack # and therefore we can assume that port.ack
# goes low until the data phase. # goes low until the data phase.
comb = [ self.comb += [
self.busy.eq(~data_reg_loaded | ~self.port.ack), self.busy.eq(~data_reg_loaded | ~port.ack),
self.port.adr.eq(self.token("address").a), port.adr.eq(self.address.payload.a),
self.port.we.eq(0), port.we.eq(0),
accept_new.eq(~data_reg_loaded | self.endpoints["data"].ack), accept_new.eq(~data_reg_loaded | self.data.ack),
self.port.stb.eq(self.endpoints["address"].stb & accept_new), port.stb.eq(self.address.stb & accept_new),
self.endpoints["address"].ack.eq(self.port.ack & accept_new), self.address.ack.eq(port.ack & accept_new),
self.endpoints["data"].stb.eq(data_reg_loaded), self.data.stb.eq(data_reg_loaded),
self.token("data").d.eq(data_reg) self.data.payload.d.eq(data_reg)
] ]
sync = [ self.sync += [
If(self.endpoints["data"].ack, If(self.data.ack, data_reg_loaded.eq(0)),
data_reg_loaded.eq(0)
),
If(sample, If(sample,
data_reg_loaded.eq(1), 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(Module):
class OOOReader(Actor):
def __init__(self, port): def __init__(self, port):
self.port = port assert(len(port.slots) > 1)
assert(len(self.port.slots) > 1) self.address = Sink([("a", port.hub.aw)])
Actor.__init__(self, self.data = Source([("d", port.hub.dw)])
("address", Sink, [("a", self.port.hub.aw)]), self.busy = Signal() # TODO: drive busy
("data", Source, [("d", self.port.hub.dw)]))
def get_fragment(self): ###
tag_width = len(self.port.tag_call)
data_width = self.port.hub.dw tag_width = len(port.tag_call)
depth = len(self.port.slots) data_width = port.hub.dw
depth = len(port.slots)
rob = ReorderBuffer(tag_width, data_width, depth) rob = ReorderBuffer(tag_width, data_width, depth)
self.submodules += rob
comb = [ self.comb += [
self.port.adr.eq(self.token("address").a), port.adr.eq(self.address.payload.a),
self.port.we.eq(0), port.we.eq(0),
self.port.stb.eq(self.endpoints["address"].stb & rob.can_issue), port.stb.eq(self.address.stb & rob.can_issue),
self.endpoints["address"].ack.eq(self.port.ack & rob.can_issue), self.address.ack.eq(port.ack & rob.can_issue),
rob.issue.eq(self.endpoints["address"].stb & self.port.ack), rob.issue.eq(self.address.stb & port.ack),
rob.tag_issue.eq(self.port.base + self.port.tag_issue), 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), self.data.stb.eq(rob.can_read),
rob.read.eq(self.endpoints["data"].ack), rob.read.eq(self.data.ack),
self.token("data").d.eq(rob.data_read) self.data.payload.d.eq(rob.data_read)
] ]
sync = [ self.sync += [
# Data is announced one cycle in advance. # Data is announced one cycle in advance.
# Register the call to synchronize it with the data signal. # Register the call to synchronize it with the data signal.
rob.call.eq(self.port.call), rob.call.eq(port.call),
rob.tag_call.eq(self.port.tag_call) rob.tag_call.eq(port.tag_call)
] ]
return Fragment(comb, sync) + rob.get_fragment() def Reader(port):
class Reader:
def __init__(self, port):
if len(port.slots) == 1: if len(port.slots) == 1:
self.__class__ = SequentialReader return SequentialReader(port)
SequentialReader.__init__(self, port)
else: else:
self.__class__ = OOOReader return OOOReader(port)
OOOReader.__init__(self, port)

View File

@ -1,58 +1,55 @@
from migen.fhdl.structure import * from migen.fhdl.structure import *
from migen.fhdl.module import Module
from migen.bus import wishbone from migen.bus import wishbone
from migen.flow.actor import * from migen.flow.actor import *
class Reader(Actor): class Reader(Module):
def __init__(self): def __init__(self):
self.bus = wishbone.Interface() self.bus = wishbone.Interface()
Actor.__init__(self, self.address = Sink([("a", 30)])
("address", Sink, [("a", 30)]), self.data = Source([("d", 32)])
("data", Source, [("d", 32)])) self.busy = Signal()
###
def get_fragment(self):
bus_stb = Signal() bus_stb = Signal()
data_reg_loaded = Signal() data_reg_loaded = Signal()
data_reg = Signal(32) data_reg = Signal(32)
comb = [ self.comb += [
self.busy.eq(data_reg_loaded), self.busy.eq(data_reg_loaded),
self.bus.we.eq(0), 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.cyc.eq(bus_stb),
self.bus.stb.eq(bus_stb), self.bus.stb.eq(bus_stb),
self.bus.adr.eq(self.token("address").a), self.bus.adr.eq(self.address.payload.a),
self.endpoints["address"].ack.eq(self.bus.ack), self.address.ack.eq(self.bus.ack),
self.endpoints["data"].stb.eq(data_reg_loaded), self.data.stb.eq(data_reg_loaded),
self.token("data").d.eq(data_reg) self.data.payload.d.eq(data_reg)
] ]
sync = [ self.sync += [
If(self.endpoints["data"].ack, If(self.data.ack, data_reg_loaded.eq(0)),
data_reg_loaded.eq(0)
),
If(self.bus.ack, If(self.bus.ack,
data_reg_loaded.eq(1), data_reg_loaded.eq(1),
data_reg.eq(self.bus.dat_r) data_reg.eq(self.bus.dat_r)
) )
] ]
return Fragment(comb, sync) class Writer(Module):
class Writer(Actor):
def __init__(self): def __init__(self):
self.bus = wishbone.Interface() self.bus = wishbone.Interface()
Actor.__init__(self, self.address_data = Sink([("a", 30), ("d", 32)])
("address_data", Sink, [("a", 30), ("d", 32)])) self.busy = Signal()
def get_fragment(self): ###
comb = [
self.comb += [
self.busy.eq(0), self.busy.eq(0),
self.bus.we.eq(1), self.bus.we.eq(1),
self.bus.cyc.eq(self.endpoints["address_data"].stb), self.bus.cyc.eq(self.address_data.stb),
self.bus.stb.eq(self.endpoints["address_data"].stb), self.bus.stb.eq(self.address_data.stb),
self.bus.adr.eq(self.token("address_data").a), self.bus.adr.eq(self.address_data.payload.a),
self.bus.sel.eq(0xf), self.bus.sel.eq(0xf),
self.bus.dat_w.eq(self.token("address_data").d), self.bus.dat_w.eq(self.address_data.payload.d),
self.endpoints["address_data"].ack.eq(self.bus.ack) self.address_data.ack.eq(self.bus.ack)
] ]
return Fragment(comb)

View File

@ -1,68 +1,65 @@
from migen.fhdl.structure import * from migen.fhdl.structure import *
from migen.fhdl.module import Module
from migen.genlib.record import * from migen.genlib.record import *
from migen.genlib.fsm import * from migen.genlib.fsm import *
from migen.flow.actor import * from migen.flow.actor import *
# Generates integers from start to maximum-1 # Generates integers from start to maximum-1
class IntSequence(Actor): class IntSequence(Module):
def __init__(self, nbits, offsetbits=0, step=1): def __init__(self, nbits, offsetbits=0, step=1):
self.nbits = nbits parameters_layout = [("maximum", nbits)]
self.offsetbits = offsetbits if offsetbits:
self.step = step parameters_layout.append(("offset", offsetbits))
parameters_layout = [("maximum", self.nbits)] self.parameters = Sink(parameters_layout)
if self.offsetbits: self.source = Source([("value", max(nbits, offsetbits))])
parameters_layout.append(("offset", self.offsetbits)) self.busy = Signal()
Actor.__init__(self, ###
("parameters", Sink, parameters_layout),
("source", Source, [("value", max(self.nbits, self.offsetbits))]))
def get_fragment(self):
load = Signal() load = Signal()
ce = Signal() ce = Signal()
last = Signal() last = Signal()
maximum = Signal(self.nbits) maximum = Signal(nbits)
if self.offsetbits: if offsetbits:
offset = Signal(self.offsetbits) offset = Signal(offsetbits)
counter = Signal(self.nbits) counter = Signal(nbits)
if self.step > 1: if step > 1:
comb = [last.eq(counter + self.step >= maximum)] self.comb += last.eq(counter + step >= maximum)
else: else:
comb = [last.eq(counter + 1 == maximum)] self.comb += last.eq(counter + 1 == maximum)
sync = [ self.sync += [
If(load, If(load,
counter.eq(0), counter.eq(0),
maximum.eq(self.token("parameters").maximum), maximum.eq(self.parameters.payload.maximum),
offset.eq(self.token("parameters").offset) if self.offsetbits else None offset.eq(self.parameters.payload.offset) if offsetbits else None
).Elif(ce, ).Elif(ce,
If(last, If(last,
counter.eq(0) counter.eq(0)
).Else( ).Else(
counter.eq(counter + self.step) counter.eq(counter + step)
) )
) )
] ]
if self.offsetbits: if offsetbits:
comb.append(self.token("source").value.eq(counter + offset)) self.comb += self.source.payload.value.eq(counter + offset)
else: else:
comb.append(self.token("source").value.eq(counter)) self.comb += self.source.payload.value.eq(counter)
counter_fragment = Fragment(comb, sync)
fsm = FSM("IDLE", "ACTIVE") fsm = FSM("IDLE", "ACTIVE")
self.submodules += fsm
fsm.act(fsm.IDLE, fsm.act(fsm.IDLE,
load.eq(1), load.eq(1),
self.endpoints["parameters"].ack.eq(1), self.parameters.ack.eq(1),
If(self.endpoints["parameters"].stb, fsm.next_state(fsm.ACTIVE)) If(self.parameters.stb, fsm.next_state(fsm.ACTIVE))
) )
fsm.act(fsm.ACTIVE, fsm.act(fsm.ACTIVE,
self.busy.eq(1), self.busy.eq(1),
self.endpoints["source"].stb.eq(1), self.source.stb.eq(1),
If(self.endpoints["source"].ack, If(self.source.ack,
ce.eq(1), ce.eq(1),
If(last, fsm.next_state(fsm.IDLE)) If(last, fsm.next_state(fsm.IDLE))
) )
) )
return counter_fragment + fsm.get_fragment()

View File

@ -20,10 +20,10 @@ class TokenExchanger(Module):
def _process_transactions(self, s): def _process_transactions(self, s):
completed = set() completed = set()
for token in self.active: for token in self.active:
ep = self.actor.endpoints[token.endpoint] ep = getattr(self.actor, token.endpoint)
if isinstance(ep, Sink): if isinstance(ep, Sink):
if s.rd(ep.ack) and s.rd(ep.stb): 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) completed.add(token)
s.wr(ep.ack, 0) s.wr(ep.ack, 0)
elif isinstance(ep, Source): elif isinstance(ep, Source):
@ -38,11 +38,11 @@ class TokenExchanger(Module):
def _update_control_signals(self, s): def _update_control_signals(self, s):
for token in self.active: for token in self.active:
ep = self.actor.endpoints[token.endpoint] ep = getattr(self.actor, token.endpoint)
if isinstance(ep, Sink): if isinstance(ep, Sink):
s.wr(ep.ack, 1) s.wr(ep.ack, 1)
elif isinstance(ep, Source): elif isinstance(ep, Source):
s.multiwrite(ep.token, token.value) s.multiwrite(ep.payload, token.value)
s.wr(ep.stb, 1) s.wr(ep.stb, 1)
else: else:
raise TypeError raise TypeError
@ -56,9 +56,7 @@ class TokenExchanger(Module):
transactions = None transactions = None
if isinstance(transactions, Token): if isinstance(transactions, Token):
self.active = {transactions} self.active = {transactions}
elif isinstance(transactions, tuple) \ elif isinstance(transactions, (tuple, list, set)):
or isinstance(transactions, list) \
or isinstance(transactions, set):
self.active = set(transactions) self.active = set(transactions)
elif transactions is None: elif transactions is None:
self.active = set() self.active = set()
@ -77,20 +75,15 @@ class TokenExchanger(Module):
do_simulation.initialize = True do_simulation.initialize = True
class SimActor(Actor): class SimActor(Module):
def __init__(self, generator, *endpoint_descriptions, **misc): def __init__(self, generator):
Actor.__init__(self, *endpoint_descriptions, **misc) self.busy = Signal()
self.token_exchanger = TokenExchanger(generator, self) 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) s.wr(self.busy, self.token_exchanger.busy)
def get_fragment(self): def _dumper_gen(prefix):
return self.token_exchanger.get_fragment() + Fragment(sim=[self.update_busy])
class Dumper(SimActor):
def __init__(self, layout, prefix=""):
def dumper_gen():
while True: while True:
t = Token("result") t = Token("result")
yield t yield t
@ -99,5 +92,8 @@ class Dumper(SimActor):
else: else:
s = str(list(t.value.values())[0]) s = str(list(t.value.values())[0])
print(prefix + s) print(prefix + s)
SimActor.__init__(self, dumper_gen(),
("result", Sink, layout)) class Dumper(SimActor):
def __init__(self, layout, prefix=""):
self.result = Sink(layout)
SimActor.__init__(self, _dumper_gen(prefix))

View File

@ -47,41 +47,35 @@ def _create_csrs_assign(layout, target, atomic, prefix=""):
(MODE_EXTERNAL, MODE_SINGLE_SHOT, MODE_CONTINUOUS) = range(3) (MODE_EXTERNAL, MODE_SINGLE_SHOT, MODE_CONTINUOUS) = range(3)
class SingleGenerator(Actor): class SingleGenerator(Module):
def __init__(self, layout, mode): def __init__(self, layout, mode):
self._mode = mode self.source = Source(_convert_layout(layout))
Actor.__init__(self, ("source", Source, _convert_layout(layout))) self.busy = Signal()
self._csrs, self._assigns = _create_csrs_assign(layout, self._csrs, assigns = _create_csrs_assign(layout, self.source.payload,
self.token("source"), self._mode != MODE_SINGLE_SHOT) mode != MODE_SINGLE_SHOT)
if mode == MODE_EXTERNAL: if mode == MODE_EXTERNAL:
self.trigger = Signal() trigger = self.trigger = Signal()
elif mode == MODE_SINGLE_SHOT: elif mode == MODE_SINGLE_SHOT:
shoot = CSR() shoot = CSR()
self._csrs.insert(0, shoot) self._csrs.insert(0, shoot)
self.trigger = shoot.re trigger = shoot.re
elif mode == MODE_CONTINUOUS: elif mode == MODE_CONTINUOUS:
enable = CSRStorage() enable = CSRStorage()
self._csrs.insert(0, enable) self._csrs.insert(0, enable)
self.trigger = enable.storage trigger = enable.storage
else: else:
raise ValueError 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): def get_csrs(self):
return self._csrs return self._csrs
def get_fragment(self): class Collector(Module, AutoCSR):
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):
def __init__(self, layout, depth=1024): def __init__(self, layout, depth=1024):
Actor.__init__(self, ("sink", Sink, layout)) self.sink = Sink(layout)
self.busy = Signal()
self._depth = depth self._depth = depth
self._dw = sum(len(s) for s in self.token("sink").flatten()) self._dw = sum(len(s) for s in self.token("sink").flatten())
@ -90,12 +84,16 @@ class Collector(Actor, AutoCSR):
self._r_ra = CSRStorage(bits_for(self._depth-1)) self._r_ra = CSRStorage(bits_for(self._depth-1))
self._r_rd = CSRStatus(self._dw) self._r_rd = CSRStatus(self._dw)
def get_fragment(self): ###
mem = Memory(self._dw, self._depth) mem = Memory(self._dw, self._depth)
self.specials += mem
wp = mem.get_port(write_capable=True) wp = mem.get_port(write_capable=True)
rp = mem.get_port() rp = mem.get_port()
comb = [ self.comb += [
self.busy.eq(0),
If(self._r_wc.r != 0, If(self._r_wc.r != 0,
self.endpoints["sink"].ack.eq(1), self.endpoints["sink"].ack.eq(1),
If(self.endpoints["sink"].stb, If(self.endpoints["sink"].stb,
@ -113,5 +111,3 @@ class Collector(Actor, AutoCSR):
rp.adr.eq(self._r_ra.storage), rp.adr.eq(self._r_ra.storage),
self._r_rd.status.eq(rp.dat_r) self._r_rd.status.eq(rp.dat_r)
] ]
return Fragment(comb, specials={mem})

View File

@ -1,4 +1,5 @@
from migen.fhdl.structure import * from migen.fhdl.structure import *
from migen.fhdl.module import Module
from migen.flow.actor import * from migen.flow.actor import *
def _rawbits_layout(l): def _rawbits_layout(l):
@ -9,45 +10,42 @@ def _rawbits_layout(l):
class Cast(CombinatorialActor): class Cast(CombinatorialActor):
def __init__(self, layout_from, layout_to, reverse_from=False, reverse_to=False): def __init__(self, layout_from, layout_to, reverse_from=False, reverse_to=False):
self.reverse_from = reverse_from self.sink = Sink(_rawbits_layout(layout_from))
self.reverse_to = reverse_to self.source = Source(_rawbits_layout(layout_to))
CombinatorialActor.__init__(self, CombinatorialActor.__init__(self)
("sink", Sink, _rawbits_layout(layout_from)),
("source", Source, _rawbits_layout(layout_to)))
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_from = list(reversed(sigs_from))
sigs_to = self.token("source").flatten() sigs_to = self.source.payload.flatten()
if self.reverse_to: if reverse_to:
sigs_to = list(reversed(sigs_to)) sigs_to = list(reversed(sigs_to))
if sum(len(s) for s in sigs_from) != sum(len(s) for s in sigs_to): if sum(len(s) for s in sigs_from) != sum(len(s) for s in sigs_to):
raise TypeError raise TypeError
return Fragment([ self.comb += Cat(*sigs_to).eq(Cat(*sigs_from))
Cat(*sigs_to).eq(Cat(*sigs_from))
])
def pack_layout(l, n): def pack_layout(l, n):
return [("chunk"+str(i), l) for i in range(n)] return [("chunk"+str(i), l) for i in range(n)]
class Unpack(Actor): class Unpack(Module):
def __init__(self, n, layout_to): def __init__(self, n, layout_to):
self.n = n self.sink = Sink(pack_layout(layout_to, n))
Actor.__init__(self, self.source = Source(layout_to)
("sink", Sink, pack_layout(layout_to, n)), self.busy = Signal()
("source", Source, layout_to))
def get_fragment(self): ###
mux = Signal(max=self.n)
mux = Signal(max=n)
last = Signal() last = Signal()
comb = [ self.comb += [
last.eq(mux == (self.n-1)), last.eq(mux == (n-1)),
self.endpoints["source"].stb.eq(self.endpoints["sink"].stb), self.source.stb.eq(self.sink.stb),
self.endpoints["sink"].ack.eq(last & self.endpoints["source"].ack) self.sink.ack.eq(last & self.source.ack)
] ]
sync = [ self.sync += [
If(self.endpoints["source"].stb & self.endpoints["source"].ack, If(self.source.stb & self.source.ack,
If(last, If(last,
mux.eq(0) mux.eq(0)
).Else( ).Else(
@ -56,39 +54,36 @@ class Unpack(Actor):
) )
] ]
cases = {} cases = {}
for i in range(self.n): for i in range(n):
cases[i] = [self.token("source").raw_bits().eq(getattr(self.token("sink"), "chunk"+str(i)).raw_bits())] cases[i] = [self.source.payload.raw_bits().eq(getattr(self.sink.payload, "chunk"+str(i)).raw_bits())]
comb.append(Case(mux, cases).makedefault()) self.comb += Case(mux, cases).makedefault()
return Fragment(comb, sync)
class Pack(Actor): class Pack(Module):
def __init__(self, layout_from, n): def __init__(self, layout_from, n):
self.n = n self.sink = Sink(layout_from)
Actor.__init__(self, self.source = Source(pack_layout(layout_from, n))
("sink", Sink, layout_from), self.busy = Signal()
("source", Source, pack_layout(layout_from, n)))
def get_fragment(self): ###
demux = Signal(max=self.n)
demux = Signal(max=n)
load_part = Signal() load_part = Signal()
strobe_all = Signal() strobe_all = Signal()
cases = {} cases = {}
for i in range(self.n): for i in range(n):
cases[i] = [getattr(self.token("source"), "chunk"+str(i)).raw_bits().eq(self.token("sink").raw_bits())] cases[i] = [getattr(self.source.payload, "chunk"+str(i)).raw_bits().eq(self.sink.payload.raw_bits())]
comb = [ self.comb += [
self.busy.eq(strobe_all), self.busy.eq(strobe_all),
self.endpoints["sink"].ack.eq(~strobe_all | self.endpoints["source"].ack), self.sink.ack.eq(~strobe_all | self.source.ack),
self.endpoints["source"].stb.eq(strobe_all), self.source.stb.eq(strobe_all),
load_part.eq(self.endpoints["sink"].stb & self.endpoints["sink"].ack) load_part.eq(self.sink.stb & self.sink.ack)
] ]
sync = [ self.sync += [
If(self.endpoints["source"].ack, If(self.source.ack, strobe_all.eq(0)),
strobe_all.eq(0)
),
If(load_part, If(load_part,
Case(demux, cases), Case(demux, cases),
If(demux == (self.n - 1), If(demux == (n - 1),
demux.eq(0), demux.eq(0),
strobe_all.eq(1) strobe_all.eq(1)
).Else( ).Else(
@ -96,4 +91,3 @@ class Pack(Actor):
) )
) )
] ]
return Fragment(comb, sync)

View File

@ -1,173 +1,105 @@
from migen.fhdl.structure import * from migen.fhdl.structure import *
from migen.fhdl.module import Module
from migen.genlib.misc import optree from migen.genlib.misc import optree
from migen.genlib.record import * from migen.genlib.record import *
class Endpoint: def _make_m2s(layout):
def __init__(self, token): r = []
self.token = token for f in layout:
if isinstance(self, Sink): if isinstance(f[1], (int, tuple)):
self.stb = Signal(name="stb_i") r.append((f[0], f[1], DIR_M_TO_S))
self.ack = Signal(name="ack_o")
else: else:
self.stb = Signal(name="stb_o") r.append((f[0], _make_m2s(f[1])))
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 "<Endpoint " + str(self.token) + ">"
class Sink(Endpoint):
def __repr__(self):
return "<Sink " + str(self.token) + ">"
class Source(Endpoint):
def __repr__(self):
return "<Source " + str(self.token) + ">"
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
self.busy = Signal()
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 return r
class BinaryActor(Actor): class _Endpoint(Record):
def get_binary_control_fragment(self, stb_i, ack_o, stb_o, ack_i): def __init__(self, layout):
raise NotImplementedError("Binary actor classes must overload get_binary_control_fragment") full_layout = [
("payload", _make_m2s(layout)),
("stb", 1, DIR_M_TO_S),
("ack", 1, DIR_S_TO_M)
]
Record.__init__(self, full_layout)
def get_control_fragment(self): class Source(_Endpoint):
def get_single_ep(l): def connect(self, sink):
if len(l) != 1: return Record.connect(self, sink)
raise ValueError("Binary actors have exactly one sink and one source. Consider using plumbing actors.")
return self.endpoints[l[0]] class Sink(_Endpoint):
sink = get_single_ep(self.sinks()) def connect(self, source):
source = get_single_ep(self.sources()) return source.connect(self)
return self.get_binary_control_fragment(sink.stb, sink.ack, source.stb, source.ack)
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 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): class CombinatorialActor(BinaryActor):
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):
return Fragment([stb_o.eq(stb_i), ack_o.eq(ack_i), self.busy.eq(0)]) self.comb += [stb_o.eq(stb_i), ack_o.eq(ack_i), self.busy.eq(0)]
class SequentialActor(BinaryActor): class SequentialActor(BinaryActor):
def __init__(self, delay, *endpoint_descriptions, **misc): def __init__(self, delay):
self.delay = delay
self.trigger = Signal() 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() ready = Signal()
timer = Signal(max=self.delay+1) timer = Signal(max=delay+1)
comb = [ready.eq(timer == 0)] self.comb += ready.eq(timer == 0)
sync = [ self.sync += If(self.trigger,
If(self.trigger, timer.eq(delay)
timer.eq(self.delay)
).Elif(~ready, ).Elif(~ready,
timer.eq(timer - 1) timer.eq(timer - 1)
) )
]
mask = Signal() mask = Signal()
comb += [ self.comb += [
stb_o.eq(ready & mask), stb_o.eq(ready & mask),
self.trigger.eq(stb_i & (ack_i | ~mask) & ready), self.trigger.eq(stb_i & (ack_i | ~mask) & ready),
ack_o.eq(self.trigger), ack_o.eq(self.trigger),
busy.eq(~ready) self.busy.eq(~ready)
] ]
sync += [ self.sync += [
If(self.trigger, mask.eq(1)), If(self.trigger, mask.eq(1)),
If(stb_o & ack_i, mask.eq(0)) If(stb_o & ack_i, mask.eq(0))
] ]
return Fragment(comb, sync)
class PipelinedActor(BinaryActor): class PipelinedActor(BinaryActor):
def __init__(self, latency, *endpoint_descriptions, **misc): def __init__(self, latency):
self.latency = latency
self.pipe_ce = Signal() 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): def build_binary_control(self, stb_i, ack_o, stb_o, ack_i, latency):
valid = Signal(self.latency) valid = Signal(latency)
if self.latency > 1: if latency > 1:
sync = [If(self.pipe_ce, valid.eq(Cat(stb_i, valid[:self.latency-1])))] self.sync += If(self.pipe_ce, valid.eq(Cat(stb_i, valid[:latency-1])))
else: else:
sync = [If(self.pipe_ce, valid.eq(stb_i))] self.sync += If(self.pipe_ce, valid.eq(stb_i))
last_valid = valid[self.latency-1] last_valid = valid[latency-1]
self.comb += [
comb = [
self.pipe_ce.eq(ack_i | ~last_valid), self.pipe_ce.eq(ack_i | ~last_valid),
ack_o.eq(self.pipe_ce), ack_o.eq(self.pipe_ce),
stb_o.eq(last_valid), 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)

View File

@ -30,7 +30,7 @@ class DFGHook(Module):
def __init__(self, dfg, create): def __init__(self, dfg, create):
assert(not dfg.is_abstract()) assert(not dfg.is_abstract())
self.nodepair_to_ep = defaultdict(dict) 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_to_hook = self.nodepair_to_ep[(u, v)]
ep = data["source"] ep = data["source"]
h = create(u, ep, v) h = create(u, ep, v)

View File

@ -4,15 +4,13 @@ from migen.fhdl.structure import *
from migen.genlib.misc import optree from migen.genlib.misc import optree
from migen.flow.actor import * from migen.flow.actor import *
from migen.flow import plumbing from migen.flow import plumbing
from migen.flow.isd import DFGReporter
# Abstract actors mean that the actor class should be instantiated with the parameters # 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 # from the dictionary. They are needed to enable actor duplication or sharing during
# elaboration, and automatic parametrization of plumbing actors. # elaboration, and automatic parametrization of plumbing actors.
class AbstractActor(HUID): class AbstractActor:
def __init__(self, actor_class, parameters=dict(), name=None): def __init__(self, actor_class, parameters=dict(), name=None):
HUID.__init__(self)
self.actor_class = actor_class self.actor_class = actor_class
self.parameters = parameters self.parameters = parameters
self.name = name self.name = name
@ -27,6 +25,7 @@ class AbstractActor(HUID):
r += ">" r += ">"
return r return r
# TODO: rewrite this without networkx and without non-determinism
class DataFlowGraph(MultiDiGraph): class DataFlowGraph(MultiDiGraph):
def __init__(self): def __init__(self):
MultiDiGraph.__init__(self) MultiDiGraph.__init__(self)
@ -35,8 +34,6 @@ class DataFlowGraph(MultiDiGraph):
def add_connection(self, source_node, sink_node, 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_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 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, self.add_edge(source_node, sink_node,
source=source_ep, sink=sink_ep, source=source_ep, sink=sink_ep,
source_subr=source_subr, sink_subr=sink_subr) source_subr=source_subr, sink_subr=sink_subr)
@ -158,7 +155,7 @@ class DataFlowGraph(MultiDiGraph):
continue continue
other_ep = data["source"] other_ep = data["source"]
if other_ep is None: 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: elif a.actor_class in plumbing.layout_source:
edges = self.out_edges(a, data=True) edges = self.out_edges(a, data=True)
assert(len(edges) == 1) assert(len(edges) == 1)
@ -167,10 +164,10 @@ class DataFlowGraph(MultiDiGraph):
continue continue
other_ep = data["sink"] other_ep = data["sink"]
if other_ep is None: if other_ep is None:
other_ep = other.single_sink() other_ep = get_single_ep(other, Sink)[1]
else: else:
raise AssertionError raise AssertionError
layout = other.token(other_ep).layout layout = other_ep.payload.layout
a.parameters["layout"] = layout a.parameters["layout"] = layout
self.instantiate(a) self.instantiate(a)
@ -184,9 +181,9 @@ class DataFlowGraph(MultiDiGraph):
# 3. resolve default eps # 3. resolve default eps
for u, v, d in self.edges_iter(data=True): for u, v, d in self.edges_iter(data=True):
if d["source"] is None: if d["source"] is None:
d["source"] = u.single_source() d["source"] = get_single_ep(u, Source)[0]
if d["sink"] is None: 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. # Elaboration turns an abstract DFG into a physical one.
# Pass 1: eliminate subrecords and divergences # Pass 1: eliminate subrecords and divergences
@ -203,29 +200,14 @@ class DataFlowGraph(MultiDiGraph):
optimizer(self) optimizer(self)
self._instantiate_actors() self._instantiate_actors()
class CompositeActor(Actor): class CompositeActor(Module):
def __init__(self, dfg, debugger=False, debugger_nbits=48): def __init__(self, dfg):
dfg.elaborate() dfg.elaborate()
self.dfg = dfg self.busy = Signal()
if debugger: self.comb += [self.busy.eq(optree("|", [node.busy for node in dfg]))]
self.debugger = DFGReporter(self.dfg, debugger_nbits) for node in dfg:
Actor.__init__(self) self.submodules += node
for u, v, d in dfg.edges_iter(data=True):
def get_csrs(self): ep_src = getattr(u, d["source"])
if hasattr(self, "debugger"): ep_dst = getattr(v, d["sink"])
return self.debugger.get_csrs() self.comb += ep_src.connect(ep_dst)
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

View File

@ -39,7 +39,7 @@ class EndpointReporter(EndpointSimHook):
class DFGReporter(DFGHook): class DFGReporter(DFGHook):
def __init__(self, dfg): 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): def get_edge_labels(self):
d = dict() d = dict()

View File

@ -6,54 +6,52 @@ from migen.genlib.misc import optree
class Buffer(PipelinedActor): class Buffer(PipelinedActor):
def __init__(self, layout): def __init__(self, layout):
PipelinedActor.__init__(self, 1, self.d = Sink(layout)
("d", Sink, layout), ("q", Source, layout)) self.q = Source(layout)
PipelinedActor.__init__(self, 1)
self.sync += If(self.pipe_ce, self.q.payload.eq(self.d.payload))
def get_process_fragment(self): class Combinator(Module):
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)
class Combinator(Module, Actor):
def __init__(self, layout, subrecords): def __init__(self, layout, subrecords):
eps = [("source", Source, layout)] self.source = Source(layout)
eps += [("sink"+str(n), Sink, layout_partial(layout, r)) sinks = []
for n, r in enumerate(subrecords)] for n, r in enumerate(subrecords):
Actor.__init__(self, *eps) s = Sink(layout_partial(layout, *r))
setattr(self, "sink"+str(n), s)
sinks.append(s)
self.busy = Signal()
### ###
source = self.endpoints["source"] self.comb += [
sinks = [self.endpoints["sink"+str(n)] self.busy.eq(0),
for n in range(len(self.endpoints)-1)] self.source.stb.eq(optree("&", [sink.stb for sink in sinks]))
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 += [sink.ack.eq(self.source.ack & self.source.stb) for sink in sinks]
self.comb += [source.token.eq(sink.token) 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): def __init__(self, layout, subrecords):
eps = [("sink", Sink, layout)] self.sink = Sink(layout)
eps += [("source"+str(n), Source, layout_partial(layout, *r)) sources = []
for n, r in enumerate(subrecords)] for n, r in enumerate(subrecords):
Actor.__init__(self, *eps) 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()] self.comb += [source.payload.eq(self.sink.payload) for source in sources]
sink = self.endpoints[self.sinks()[0]]
self.comb += [source.token.eq(sink.token) for source in sources]
already_acked = Signal(len(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])), 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)])) [s.ack | already_acked[n] for n, s in enumerate(sources)]))
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. # Actors whose layout should be inferred from what their single sink is connected to.
layout_sink = {Buffer, Splitter} layout_sink = {Buffer, Splitter}

View File

@ -34,7 +34,7 @@ def layout_get(layout, name):
for f in layout: for f in layout:
if f[0] == name: if f[0] == name:
return f return f
raise KeyError raise KeyError(name)
def layout_partial(layout, *elements): def layout_partial(layout, *elements):
r = [] r = []

View File

@ -17,7 +17,7 @@ class Pytholite(UnifiedIOObject):
if dataflow is not None: if dataflow is not None:
self.busy.reset = 1 self.busy.reset = 1
self.memory_ports = dict((mem, mem.get_port(write_capable=True, we_granularity=8)) 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): def get_fragment(self):
return UnifiedIOObject.get_fragment(self) + self.fragment return UnifiedIOObject.get_fragment(self) + self.fragment
@ -39,7 +39,7 @@ class _TokenPullExprCompiler(ExprCompiler):
if not isinstance(node.slice, ast.Index): if not isinstance(node.slice, ast.Index):
raise NotImplementedError raise NotImplementedError
field = ast.literal_eval(node.slice.value) field = ast.literal_eval(node.slice.value)
signal = getattr(self.ep.token, field) signal = getattr(self.ep.payload, field)
return signal return signal
@ -47,7 +47,7 @@ def _gen_df_io(compiler, modelname, to_model, from_model):
epname = ast.literal_eval(to_model["endpoint"]) epname = ast.literal_eval(to_model["endpoint"])
values = to_model["value"] values = to_model["value"]
idle_wait = ast.literal_eval(to_model["idle_wait"]) idle_wait = ast.literal_eval(to_model["idle_wait"])
ep = compiler.ioo.endpoints[epname] ep = getattr(compiler.ioo, epname)
if idle_wait: if idle_wait:
state = [compiler.ioo.busy.eq(0)] state = [compiler.ioo.busy.eq(0)]
else: else:
@ -76,7 +76,7 @@ def _gen_df_io(compiler, modelname, to_model, from_model):
raise NotImplementedError raise NotImplementedError
for akey, value in zip(values.keys, values.values): for akey, value in zip(values.keys, values.values):
key = ast.literal_eval(akey) 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.append(signal.eq(compiler.ec.visit_expr(value)))
state += [ state += [
ep.stb.eq(1), ep.stb.eq(1),

View File

@ -7,15 +7,14 @@ from migen.bus import wishbone, memory
from migen.bus.transactions import * from migen.bus.transactions import *
from migen.uio.trampoline import Trampoline from migen.uio.trampoline import Trampoline
class UnifiedIOObject(Actor): class UnifiedIOObject(Module):
def __init__(self, dataflow=None, buses={}): def __init__(self, dataflow=None, buses={}):
if dataflow is not None: 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.buses = buses
self._memories = set(v for v in self.buses.values() if isinstance(v, Memory)) self.specials += set(v for v in self.buses.values() if isinstance(v, Memory))
def get_fragment(self):
return Fragment(specials=self._memories)
(_WAIT_COMPLETE, _WAIT_POLL) = range(2) (_WAIT_COMPLETE, _WAIT_POLL) = range(2)
@ -24,12 +23,12 @@ class UnifiedIOSimulation(UnifiedIOObject):
self.generator = Trampoline(generator) self.generator = Trampoline(generator)
UnifiedIOObject.__init__(self, dataflow, buses) UnifiedIOObject.__init__(self, dataflow, buses)
self.callers = [] callers = []
self.busname_to_caller_id = {} self.busname_to_caller_id = {}
if dataflow is not None: 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(): for k, v in self.buses.items():
caller_id = len(self.callers) caller_id = len(callers)
self.busname_to_caller_id[k] = caller_id self.busname_to_caller_id[k] = caller_id
g = self.dispatch_g(caller_id) g = self.dispatch_g(caller_id)
if isinstance(v, wishbone.Interface): if isinstance(v, wishbone.Interface):
@ -38,7 +37,8 @@ class UnifiedIOSimulation(UnifiedIOObject):
caller = memory.Initiator(g, v) caller = memory.Initiator(g, v)
else: else:
raise NotImplementedError raise NotImplementedError
self.callers.append(caller) callers.append(caller)
self.submodules += callers
self.dispatch_state = _WAIT_COMPLETE self.dispatch_state = _WAIT_COMPLETE
self.dispatch_caller = 0 self.dispatch_caller = 0
@ -75,7 +75,3 @@ class UnifiedIOSimulation(UnifiedIOObject):
yield self.pending_transaction yield self.pending_transaction
else: else:
yield None yield None
def get_fragment(self):
f = UnifiedIOObject.get_fragment(self)
return sum([c.get_fragment() for c in self.callers], f)