flow: refactor scheduling models

This commit is contained in:
Sebastien Bourdeauducq 2012-06-07 14:44:43 +02:00
parent 493b181af1
commit 680a34465d
5 changed files with 90 additions and 113 deletions

View File

@ -20,7 +20,7 @@ class For(Actor):
for n, bv in enumerate(self.d_bv)] for n, bv in enumerate(self.d_bv)]
l_source = [("d{0}".format(n), bv) l_source = [("d{0}".format(n), bv)
for n, bv in enumerate(self.d_bv)] for n, bv in enumerate(self.d_bv)]
Actor.__init__(self, SchedulingModel(SchedulingModel.DYNAMIC), Actor.__init__(self,
("sink", Sink, l_sink), ("sink", Sink, l_sink),
("source", Source, l_source)) ("source", Source, l_source))

View File

@ -2,25 +2,6 @@ from migen.fhdl.structure import *
from migen.corelogic.misc import optree from migen.corelogic.misc import optree
from migen.corelogic.record import * 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: class Endpoint:
def __init__(self, token): def __init__(self, token):
self.token = token self.token = token
@ -51,55 +32,8 @@ class Source(Endpoint):
def __repr__(self): def __repr__(self):
return "<Source " + str(self.token) + ">" 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: class Actor:
def __init__(self, scheduling_model, *endpoint_descriptions, endpoints=None): def __init__(self, *endpoint_descriptions, endpoints=None):
self.scheduling_model = scheduling_model
if endpoints is None: if endpoints is None:
self.endpoints = {} self.endpoints = {}
for desc in endpoint_descriptions: for desc in endpoint_descriptions:
@ -113,10 +47,6 @@ class Actor:
else: else:
self.endpoints = endpoints self.endpoints = endpoints
self.busy = Signal() 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): def token(self, ep):
return self.endpoints[ep].token return self.endpoints[ep].token
@ -131,27 +61,10 @@ class Actor:
return self.filter_endpoints(Source) return self.filter_endpoints(Source)
def get_control_fragment(self): def get_control_fragment(self):
def get_single_ep(l): raise NotImplementedError("Actor classes must overload get_control_fragment or get_fragment")
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")
def get_process_fragment(self): 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): def get_fragment(self):
return self.get_control_fragment() + self.get_process_fragment() return self.get_control_fragment() + self.get_process_fragment()
@ -159,6 +72,78 @@ class Actor:
def __repr__(self): def __repr__(self):
return "<" + self.__class__.__name__ + " " + repr(self.scheduling_model) + " " + repr(self.sinks()) + " " + repr(self.sources()) + ">" 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): def get_conn_fragment(source, sink):
assert isinstance(source, Source) assert isinstance(source, Source)
assert isinstance(sink, Sink) assert isinstance(sink, Sink)

View File

@ -4,11 +4,10 @@ from migen.flow.actor import *
from migen.corelogic.record import * from migen.corelogic.record import *
from migen.corelogic import divider from migen.corelogic import divider
class _SimpleBinary(Actor): class _SimpleBinary(CombinatorialActor):
def __init__(self, op, bv_op, bv_r): def __init__(self, op, bv_op, bv_r):
self.op = op self.op = op
Actor.__init__(self, CombinatorialActor.__init__(self,
SchedulingModel(SchedulingModel.COMBINATORIAL),
("operands", Sink, [("a", bv_op), ("b", bv_op)]), ("operands", Sink, [("a", bv_op), ("b", bv_op)]),
("result", Source, [("r", bv_r)])) ("result", Source, [("r", bv_r)]))
@ -58,11 +57,10 @@ class NE(_SimpleBinary):
def __init__(self, bv): def __init__(self, bv):
_SimpleBinary.__init__(self, "!=", bv, BV(1)) _SimpleBinary.__init__(self, "!=", bv, BV(1))
class DivMod(Actor): class DivMod(SequentialActor):
def __init__(self, width): def __init__(self, width):
self.div = divider.Divider(width) self.div = divider.Divider(width)
Actor.__init__(self, SequentialActor.__init__(self, width,
SchedulingModel(SchedulingModel.SEQUENTIAL, width),
("operands", Sink, [("dividend", self.div.dividend_i), ("divisor", self.div.divisor_i)]), ("operands", Sink, [("dividend", self.div.dividend_i), ("divisor", self.div.divisor_i)]),
("result", Source, [("quotient", self.div.quotient_o), ("remainder", self.div.remainder_o)])) ("result", Source, [("quotient", self.div.quotient_o), ("remainder", self.div.remainder_o)]))

View File

@ -7,8 +7,7 @@ from migen.corelogic.misc import optree
class CompositeActor(Actor): class CompositeActor(Actor):
def __init__(self, dfg): # TODO: endpoints def __init__(self, dfg): # TODO: endpoints
self.dfg = dfg self.dfg = dfg
Actor.__init__(self, Actor.__init__(self)
SchedulingModel(SchedulingModel.DYNAMIC))
def get_fragment(self): def get_fragment(self):
this_fragments = [get_conn_fragment(x[0].endpoints[x[2]["source"]], x[1].endpoints[x[2]["sink"]]) this_fragments = [get_conn_fragment(x[0].endpoints[x[2]["source"]], x[1].endpoints[x[2]["sink"]])

View File

@ -3,10 +3,9 @@ from migen.flow.actor import *
from migen.corelogic.record import * from migen.corelogic.record import *
from migen.corelogic.misc import optree from migen.corelogic.misc import optree
class Buffer(Actor): class Buffer(PipelinedActor):
def __init__(self, layout): def __init__(self, layout):
Actor.__init__(self, PipelinedActor.__init__(self, 1,
SchedulingModel(SchedulingModel.PIPELINE, 1),
("d", Sink, layout), ("q", Source, layout)) ("d", Sink, layout), ("q", Source, layout))
def get_process_fragment(self): def get_process_fragment(self):
@ -15,17 +14,15 @@ class Buffer(Actor):
sync = [If(self.pipe_ce, Cat(*sigs_q).eq(Cat(*sigs_d)))] sync = [If(self.pipe_ce, Cat(*sigs_q).eq(Cat(*sigs_d)))]
return Fragment(sync=sync) return Fragment(sync=sync)
class Combinator(Actor): class Combinator(CombinatorialActor):
def __init__(self, layout, *subrecords): def __init__(self, layout, *subrecords):
source = Record(layout) source = Record(layout)
subrecords = [source.subrecord(*subr) for subr in subrecords] subrecords = [source.subrecord(*subr) for subr in subrecords]
eps = [("sink{0}".format(n), Sink, r) eps = [("sink{0}".format(n), Sink, r)
for x in enumerate(subrecords)] for n, r in enumerate(subrecords)]
ep_source = ("source", Source, source) ep_source = ("source", Source, source)
eps.append(ep_source) eps.append(ep_source)
Actor.__init__(self, CombinatorialActor.__init__(self, *eps)
SchedulingModel(SchedulingModel.COMBINATORIAL),
*eps)
def get_fragment(self): def get_fragment(self):
source = self.endpoints["source"] source = self.endpoints["source"]
@ -35,7 +32,7 @@ class Combinator(Actor):
comb += [sink.ack.eq(source.ack & source.stb) for sink in sinks] comb += [sink.ack.eq(source.ack & source.stb) for sink in sinks]
return Fragment(comb) return Fragment(comb)
class Splitter(Actor): class Splitter(CombinatorialActor):
def __init__(self, layout, *subrecords): def __init__(self, layout, *subrecords):
sink = Record(layout) sink = Record(layout)
subrecords = [sink.subrecord(*subr) for subr in subrecords] subrecords = [sink.subrecord(*subr) for subr in subrecords]
@ -43,8 +40,6 @@ class Splitter(Actor):
for n, r in enumerate(subrecords)] for n, r in enumerate(subrecords)]
ep_sink = ("sink", Sink, sink) ep_sink = ("sink", Sink, sink)
eps.append(ep_sink) eps.append(ep_sink)
Actor.__init__(self, CombinatorialActor.__init__(self, *eps)
SchedulingModel(SchedulingModel.COMBINATORIAL),
*eps)
# TODO def get_fragment(self): # TODO def get_fragment(self):