From 680a34465d6b664b9c459595ffa9f27282aa0f16 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 7 Jun 2012 14:44:43 +0200 Subject: [PATCH] flow: refactor scheduling models --- migen/actorlib/control.py | 2 +- migen/flow/actor.py | 169 +++++++++++++++++--------------------- migen/flow/ala.py | 10 +-- migen/flow/network.py | 3 +- migen/flow/plumbing.py | 19 ++--- 5 files changed, 90 insertions(+), 113 deletions(-) diff --git a/migen/actorlib/control.py b/migen/actorlib/control.py index dffcb47da..004d4f8e1 100644 --- a/migen/actorlib/control.py +++ b/migen/actorlib/control.py @@ -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)) diff --git a/migen/flow/actor.py b/migen/flow/actor.py index 0c7f762bb..7d70ba1fc 100644 --- a/migen/flow/actor.py +++ b/migen/flow/actor.py @@ -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 "" - elif self.model == SchedulingModel.SEQUENTIAL: - return "".format(self.latency) - elif self.model == SchedulingModel.PIPELINE: - return "".format(self.latency) - elif self.model == SchedulingModel.DYNAMIC: - return "" - else: - raise AttributeError - class Endpoint: def __init__(self, token): self.token = token @@ -51,55 +32,8 @@ class Source(Endpoint): def __repr__(self): return "" -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) diff --git a/migen/flow/ala.py b/migen/flow/ala.py index 85edef558..ca0da7e57 100644 --- a/migen/flow/ala.py +++ b/migen/flow/ala.py @@ -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)])) diff --git a/migen/flow/network.py b/migen/flow/network.py index 6a9d3fb07..fc9c7214a 100644 --- a/migen/flow/network.py +++ b/migen/flow/network.py @@ -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"]]) diff --git a/migen/flow/plumbing.py b/migen/flow/plumbing.py index 3120055cf..25921f189 100644 --- a/migen/flow/plumbing.py +++ b/migen/flow/plumbing.py @@ -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):