flow: refactor scheduling models
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Thu, 7 Jun 2012 12:44:43 +0000 (14:44 +0200)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Thu, 7 Jun 2012 12:44:43 +0000 (14:44 +0200)
migen/actorlib/control.py
migen/flow/actor.py
migen/flow/ala.py
migen/flow/network.py
migen/flow/plumbing.py

index dffcb47daf6106d96e888b922195f02d2a7b4a9b..004d4f8e1d40439902af8ae6f7022baf7af5ee9e 100644 (file)
@@ -20,7 +20,7 @@ class For(Actor):
                        for n, bv in enumerate(self.d_bv)]
                l_source = [("d{0}".format(n), bv)
                        for n, bv in enumerate(self.d_bv)]
-               Actor.__init__(self, SchedulingModel(SchedulingModel.DYNAMIC),
+               Actor.__init__(self,
                        ("sink", Sink, l_sink),
                        ("source", Source, l_source))
        
index 0c7f762bbc7ed5a0151177df6517f979d872f3b6..7d70ba1fc749001671d0940234c2c473d6b4d59d 100644 (file)
@@ -2,25 +2,6 @@ from migen.fhdl.structure import *
 from migen.corelogic.misc import optree
 from migen.corelogic.record import *
 
-class SchedulingModel:
-       COMBINATORIAL, SEQUENTIAL, PIPELINE, DYNAMIC = range(4)
-       
-       def __init__(self, model, latency=1):
-               self.model = model
-               self.latency = latency
-       
-       def __repr__(self):
-               if self.model == SchedulingModel.COMBINATORIAL:
-                       return "<SchedulingModel: COMBINATORIAL>"
-               elif self.model == SchedulingModel.SEQUENTIAL:
-                       return "<SchedulingModel: SEQUENTIAL({0})>".format(self.latency)
-               elif self.model == SchedulingModel.PIPELINE:
-                       return "<SchedulingModel: PIPELINE({0})>".format(self.latency)
-               elif self.model == SchedulingModel.DYNAMIC:
-                       return "<SchedulingModel: DYNAMIC>"
-               else:
-                       raise AttributeError
-
 class Endpoint:
        def __init__(self, token):
                self.token = token
@@ -51,55 +32,8 @@ class Source(Endpoint):
        def __repr__(self):
                return "<Source " + str(self.token) + ">"
 
-def _control_fragment_comb(stb_i, ack_o, stb_o, ack_i, busy):
-       return Fragment([stb_o.eq(stb_i), ack_o.eq(ack_i), busy.eq(0)])
-
-def _control_fragment_seq(latency, stb_i, ack_o, stb_o, ack_i, busy, trigger):
-       ready = Signal()
-       timer = Signal(BV(bits_for(latency)))
-       comb = [ready.eq(timer == 0)]
-       sync = [
-               If(trigger,
-                       timer.eq(latency)
-               ).Elif(~ready,
-                       timer.eq(timer - 1)
-               )
-       ]
-       
-       mask = Signal()
-       comb += [
-               stb_o.eq(ready & mask),
-               trigger.eq(stb_i & (ack_i | ~mask) & ready),
-               ack_o.eq(trigger),
-               busy.eq(~ready)
-       ]
-       sync += [
-               If(trigger, mask.eq(1)),
-               If(stb_o & ack_i, mask.eq(0))
-       ]
-
-       return Fragment(comb, sync)
-
-def _control_fragment_pipe(latency, stb_i, ack_o, stb_o, ack_i, busy, pipe_ce):
-       valid = Signal(BV(latency))
-       if latency > 1:
-               sync = [If(pipe_ce, valid.eq(Cat(stb_i, valid[:latency-1])))]
-       else:
-               sync = [If(pipe_ce, valid.eq(stb_i))]
-       last_valid = valid[latency-1]
-       
-       comb = [
-               pipe_ce.eq(ack_i | ~last_valid),
-               ack_o.eq(pipe_ce),
-               stb_o.eq(last_valid),
-               busy.eq(optree("|", [valid[i] for i in range(latency)]))
-       ]
-       
-       return Fragment(comb, sync)
-
 class Actor:
-       def __init__(self, scheduling_model, *endpoint_descriptions, endpoints=None):
-               self.scheduling_model = scheduling_model
+       def __init__(self, *endpoint_descriptions, endpoints=None):
                if endpoints is None:
                        self.endpoints = {}
                        for desc in endpoint_descriptions:
@@ -113,11 +47,7 @@ class Actor:
                else:
                        self.endpoints = endpoints
                self.busy = Signal()
-               if self.scheduling_model.model == SchedulingModel.SEQUENTIAL:
-                       self.trigger = Signal()
-               elif self.scheduling_model.model == SchedulingModel.PIPELINE:
-                       self.pipe_ce = Signal()
-       
+
        def token(self, ep):
                return self.endpoints[ep].token
        
@@ -131,27 +61,10 @@ class Actor:
                return self.filter_endpoints(Source)
 
        def get_control_fragment(self):
-               def get_single_ep(l):
-                       if len(l) != 1:
-                               raise ValueError("Actors with automatic control fragment must 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())
-               stb_i = sink.stb
-               ack_o = sink.ack
-               stb_o = source.stb
-               ack_i = source.ack
-               if self.scheduling_model.model == SchedulingModel.COMBINATORIAL:
-                       return _control_fragment_comb(stb_i, ack_o, stb_o, ack_i, self.busy)
-               elif self.scheduling_model.model == SchedulingModel.SEQUENTIAL:
-                       return _control_fragment_seq(self.scheduling_model.latency, stb_i, ack_o, stb_o, ack_i, self.busy, self.trigger)
-               elif self.scheduling_model.model == SchedulingModel.PIPELINE:
-                       return _control_fragment_pipe(self.scheduling_model.latency, stb_i, ack_o, stb_o, ack_i, self.busy, self.pipe_ce)
-               elif self.scheduling_model.model == SchedulingModel.DYNAMIC:
-                       raise NotImplementedError("Actor classes with dynamic scheduling must overload get_control_fragment or get_fragment")
-       
+               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")
+               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()
@@ -159,6 +72,78 @@ class Actor:
        def __repr__(self):
                return "<" + self.__class__.__name__ + " " + repr(self.scheduling_model) + " " + repr(self.sinks()) + " " + repr(self.sources()) + ">"
 
+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)
+
+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)])
+
+class SequentialActor(BinaryActor):
+       def __init__(self, delay, *endpoint_descriptions, endpoints=None):
+               self.delay = delay
+               self.trigger = Signal()
+               BinaryActor.__init__(*endpoint_descriptions, endpoints=endpoints)
+
+       def get_binary_control_fragment(self, stb_i, ack_o, stb_o, ack_i):
+               ready = Signal()
+               timer = Signal(BV(bits_for(self.delay)))
+               comb = [ready.eq(timer == 0)]
+               sync = [
+                       If(self.trigger,
+                               timer.eq(self.delay)
+                       ).Elif(~ready,
+                               timer.eq(timer - 1)
+                       )
+               ]
+               
+               mask = Signal()
+               comb += [
+                       stb_o.eq(ready & mask),
+                       self.trigger.eq(stb_i & (ack_i | ~mask) & ready),
+                       ack_o.eq(self.trigger),
+                       busy.eq(~ready)
+               ]
+               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, endpoints=None):
+               self.latency = latency
+               self.pipe_ce = Signal()
+               BinaryActor.__init__(*endpoint_descriptions, endpoints=endpoints)
+
+       def get_binary_control_fragment(self, stb_i, ack_o, stb_o, ack_i):
+               valid = Signal(BV(self.latency))
+               if self.latency > 1:
+                       sync = [If(self.pipe_ce, valid.eq(Cat(stb_i, valid[:self.latency-1])))]
+               else:
+                       sync = [If(self.pipe_ce, valid.eq(stb_i))]
+               last_valid = valid[self.latency-1]
+               
+               comb = [
+                       self.pipe_ce.eq(ack_i | ~last_valid),
+                       ack_o.eq(self.pipe_ce),
+                       stb_o.eq(last_valid),
+                       busy.eq(optree("|", [valid[i] for i in range(self.latency)]))
+               ]
+               
+               return Fragment(comb, sync)
+               
 def get_conn_fragment(source, sink):
        assert isinstance(source, Source)
        assert isinstance(sink, Sink)
index 85edef558980f988166098ecc712dec17fe3f80e..ca0da7e573c030db131fb9bb839859053db92be0 100644 (file)
@@ -4,11 +4,10 @@ from migen.flow.actor import *
 from migen.corelogic.record import *
 from migen.corelogic import divider
 
-class _SimpleBinary(Actor):
+class _SimpleBinary(CombinatorialActor):
        def __init__(self, op, bv_op, bv_r):
                self.op = op
-               Actor.__init__(self,
-                       SchedulingModel(SchedulingModel.COMBINATORIAL),
+               CombinatorialActor.__init__(self,
                        ("operands", Sink, [("a", bv_op), ("b", bv_op)]),
                        ("result", Source, [("r", bv_r)]))
 
@@ -58,11 +57,10 @@ class NE(_SimpleBinary):
        def __init__(self, bv):
                _SimpleBinary.__init__(self, "!=", bv, BV(1))
 
-class DivMod(Actor):
+class DivMod(SequentialActor):
        def __init__(self, width):
                self.div = divider.Divider(width)
-               Actor.__init__(self,
-                       SchedulingModel(SchedulingModel.SEQUENTIAL, width),
+               SequentialActor.__init__(self, width,
                        ("operands", Sink, [("dividend", self.div.dividend_i), ("divisor", self.div.divisor_i)]),
                        ("result", Source, [("quotient", self.div.quotient_o), ("remainder", self.div.remainder_o)]))
 
index 6a9d3fb07c1c352f5b464fd0b89081489d1da4ad..fc9c7214a2aafe383a30234f4361b0464505e816 100644 (file)
@@ -7,8 +7,7 @@ from migen.corelogic.misc import optree
 class CompositeActor(Actor):
        def __init__(self, dfg): # TODO: endpoints
                self.dfg = dfg
-               Actor.__init__(self,
-                       SchedulingModel(SchedulingModel.DYNAMIC))
+               Actor.__init__(self)
        
        def get_fragment(self):
                this_fragments = [get_conn_fragment(x[0].endpoints[x[2]["source"]], x[1].endpoints[x[2]["sink"]])
index 3120055cfbd163233bd958b89480f782e9014d7e..25921f189c4096d89de1a50e50d13ff068227506 100644 (file)
@@ -3,10 +3,9 @@ from migen.flow.actor import *
 from migen.corelogic.record import *
 from migen.corelogic.misc import optree
 
-class Buffer(Actor):
+class Buffer(PipelinedActor):
        def __init__(self, layout):
-               Actor.__init__(self,
-                       SchedulingModel(SchedulingModel.PIPELINE, 1),
+               PipelinedActor.__init__(self, 1,
                        ("d", Sink, layout), ("q", Source, layout))
        
        def get_process_fragment(self):
@@ -15,17 +14,15 @@ class Buffer(Actor):
                sync = [If(self.pipe_ce, Cat(*sigs_q).eq(Cat(*sigs_d)))]
                return Fragment(sync=sync)
 
-class Combinator(Actor):
+class Combinator(CombinatorialActor):
        def __init__(self, layout, *subrecords):
                source = Record(layout)
                subrecords = [source.subrecord(*subr) for subr in subrecords]
                eps = [("sink{0}".format(n), Sink, r)
-                       for x in enumerate(subrecords)]
+                       for n, r in enumerate(subrecords)]
                ep_source = ("source", Source, source)
                eps.append(ep_source)
-               Actor.__init__(self,
-                       SchedulingModel(SchedulingModel.COMBINATORIAL),
-                       *eps)
+               CombinatorialActor.__init__(self, *eps)
 
        def get_fragment(self):
                source = self.endpoints["source"]
@@ -35,7 +32,7 @@ class Combinator(Actor):
                comb += [sink.ack.eq(source.ack & source.stb) for sink in sinks]
                return Fragment(comb)
 
-class Splitter(Actor):
+class Splitter(CombinatorialActor):
        def __init__(self, layout, *subrecords):
                sink = Record(layout)
                subrecords = [sink.subrecord(*subr) for subr in subrecords]
@@ -43,8 +40,6 @@ class Splitter(Actor):
                        for n, r in enumerate(subrecords)]
                ep_sink = ("sink", Sink, sink)
                eps.append(ep_sink)
-               Actor.__init__(self,
-                       SchedulingModel(SchedulingModel.COMBINATORIAL),
-                       *eps)
+               CombinatorialActor.__init__(self, *eps)
                
        # TODO def get_fragment(self):