flow: insert splitters
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Sat, 16 Jun 2012 19:23:42 +0000 (21:23 +0200)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Sat, 16 Jun 2012 19:23:42 +0000 (21:23 +0200)
examples/dataflow/arithmetic.py
migen/flow/network.py
migen/flow/plumbing.py

index 28f42159fb7d5dce40c33b5df78570262575da78..414b06c4070d2309918fd2ffb9da9cb1b4044dd9 100644 (file)
@@ -29,31 +29,32 @@ class Dumper(SimActor):
                super().__init__(dumper_gen(),
                        ("result", Sink, [("r", BV(32))]))
 
+def draw(g):
+       if len(sys.argv) > 1 and sys.argv[1] == "draw":
+               nx.draw(g)
+               plt.show()
+
 def main():
        # Create graph
        g = DataFlowGraph()
-       a1 = ComposableSource(g, NumberGen())
-       a2 = ComposableSource(g, NumberGen())
-       a3 = ComposableSource(g, NumberGen())
-       c3 = (a1 + a2)*a3
-       g.add_connection(c3.actor_node, Dumper())
+       gen1 = ComposableSource(g, NumberGen())
+       gen2 = ComposableSource(g, NumberGen())
+       
+       ps = gen1 + gen2
+       result = ps*gen1 + ps*gen2
+       
+       g.add_connection(result.actor_node, Dumper())
 
-       a1.actor_node.actor.name = "gen1"
-       a2.actor_node.actor.name = "gen2"
-       a3.actor_node.actor.name = "gen3"
-       c3.actor_node.name = "result"
+       gen1.actor_node.actor.name = "gen1"
+       gen2.actor_node.actor.name = "gen2"
+       result.actor_node.name = "result"
        
        # Elaborate
-       draw = len(sys.argv) > 1 and sys.argv[1] == "draw"
        print("is_abstract before elaboration: " + str(g.is_abstract()))
-       if draw:
-               nx.draw(g)
-               plt.show()
+       draw(g)
        g.elaborate()
        print("is_abstract after elaboration : " + str(g.is_abstract()))
-       if draw:
-               nx.draw(g)
-               plt.show()
+       draw(g)
 
        # Simulate
        c = CompositeActor(g)
index 4bb14e5a60215f546fef491a0241e3e6e0509f45..6bf21a004edb81259939f9bb955e2a887263c1b3 100644 (file)
@@ -63,7 +63,11 @@ class DataFlowGraph(MultiDiGraph):
        
        def del_connections(self, source_node, sink_node, data_requirements):
                edges_to_delete = []
-               for key, data in self.get_edge_data(source_node, sink_node).items():
+               edge_data = self.get_edge_data(source_node, sink_node)
+               if edge_data is None:
+                       # the two nodes are already completely disconnected
+                       return
+               for key, data in edge_data.items():
                        if all(k not in data_requirements or data_requirements[k] == v
                          for k, v in data.items()):
                                edges_to_delete.append(key)
@@ -115,9 +119,9 @@ class DataFlowGraph(MultiDiGraph):
                return any(x.is_abstract() for x in self) \
                        or any(d["source_subr"] is not None or d["sink_subr"] is not None
                                for u, v, d in self.edges_iter(data=True)) \
-                       or self._list_divergences()
+                       or bool(self._list_divergences())
        
-       def _eliminate_subrecords(self):
+       def _eliminate_subrecords_and_divergences(self):
                # Insert combinators.
                for (dst_node, dst_endpoint), sources in self._sink_to_sources().items():
                        if len(sources) > 1 or sources[0][2] is not None:
@@ -135,10 +139,19 @@ class DataFlowGraph(MultiDiGraph):
                                # connect combinator_source -> sink
                                self.add_connection(combinator, dst_node, "source", dst_endpoint)
                # Insert splitters.
-               # TODO
-       
-       def _eliminate_divergences(self):
-               pass # TODO
+               for (src_node, src_endpoint), sinks in self._source_to_sinks().items():
+                       if len(sinks) > 1 or sinks[0][2] is not None:
+                               subrecords = [src_subrecord for dst_node, dst_endpoint, src_subrecord in sinks]
+                               splitter = ActorNode(plumbing.Splitter, {"subrecords": subrecords})
+                               # disconnect source -> sink1 ... source -> sinkn
+                               # connect splitter_source1 -> sink1 ... splitter_sourcen -> sinkn
+                               for n, (dst_node, dst_endpoint, src_subrecord) in enumerate(sinks):
+                                       self.del_connections(src_node, dst_node,
+                                               {"source": src_endpoint, "sink": dst_endpoint})
+                                       self.add_connection(splitter, dst_node,
+                                               "source{0}".format(n), dst_endpoint)
+                               # connect source -> splitter_sink
+                               self.add_connection(src_node, splitter, src_endpoint, "sink")
        
        def _infer_plumbing_layout(self):
                while True:
@@ -182,17 +195,16 @@ class DataFlowGraph(MultiDiGraph):
                                d["sink"] = sink_eps[0]
        
        # Elaboration turns an abstract DFG into a concrete one.
-       #   Pass 1: eliminate subrecords by inserting Combinator/Splitter actors
-       #   Pass 2: eliminate divergences by inserting Distributor actors
-       #   Pass 3: run optimizer (e.g. share and duplicate actors)
-       #   Pass 4: instantiate all abstract actors and explicit "None" endpoints
+       #   Pass 1: eliminate subrecords and divergences
+       #           by inserting Combinator/Splitter actors
+       #   Pass 2: run optimizer (e.g. share and duplicate actors)
+       #   Pass 3: instantiate all abstract actors and explicit "None" endpoints
        def elaborate(self, optimizer=None):
                if self.elaborated:
                        return
                self.elaborated = True
                
-               self._eliminate_subrecords()
-               self._eliminate_divergences()
+               self._eliminate_subrecords_and_divergences()
                if optimizer is not None:
                        optimizer(self)
                self._instantiate_actors()
index b69c90db79743ed0888e24d5cf300af740a56ed0..9d5736f498a3b7945408d8a578b0f08686902012 100644 (file)
@@ -35,20 +35,39 @@ class Combinator(CombinatorialActor):
 class Splitter(CombinatorialActor):
        def __init__(self, layout, subrecords):
                sink = Record(layout)
-               subrecords = [sink.subrecord(*subr) for subr in subrecords]
+               subr = []
+               for s in subrecords:
+                       if s is None:
+                               subr.append(sink)
+                       else:
+                               subr.append(sink.subrecord(*s))
                eps = [("source{0}".format(n), Source, r)
-                       for n, r in enumerate(subrecords)]
+                       for n, r in enumerate(subr)]
                ep_sink = ("sink", Sink, sink)
                eps.append(ep_sink)
                super().__init__(*eps)
                
-       # TODO def get_fragment(self):
-
-class Distributor:
-       pass # TODO
+       def get_fragment(self):
+               sources = [self.endpoints[e] for e in self.sources()]
+               sink = self.endpoints[self.sinks()[0]]
+               
+               already_acked = Signal(BV(len(sources)))
+               sync = [
+                       If(sink.stb,
+                               already_acked.eq(already_acked | Cat(*[s.ack for s in sources])),
+                               If(sink.ack, already_acked.eq(0))
+                       )
+               ]
+               comb = [
+                       sink.ack.eq(optree("&",
+                               [s.ack | already_acked[n] for n, s in enumerate(sources)]))
+               ]
+               for n, s in enumerate(sources):
+                       comb.append(s.stb.eq(sink.stb & ~already_acked[n]))
+               return Fragment(comb, sync)
 
 # Actors whose layout should be inferred from what their single sink is connected to.
-layout_sink = {Buffer, Splitter, Distributor}
+layout_sink = {Buffer, Splitter}
 # Actors whose layout should be inferred from what their single source is connected to.
 layout_source = {Buffer, Combinator}
 # All actors.