flow: use Module and new Record APIs
This commit is contained in:
parent
20bdd424c8
commit
692794a21f
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 "<Endpoint " + str(self.token) + ">"
|
||||
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 "<Sink " + str(self.token) + ">"
|
||||
class Source(_Endpoint):
|
||||
def connect(self, sink):
|
||||
return Record.connect(self, sink)
|
||||
|
||||
class Source(Endpoint):
|
||||
def __repr__(self):
|
||||
return "<Source " + str(self.token) + ">"
|
||||
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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue