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
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:
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
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()
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)
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)]))
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)]))
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):
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"]
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]
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):