from migen.util.misc import xdir from migen.fhdl.std import * from migen.genlib.misc import optree from migen.genlib.record import * def _make_m2s(layout): r = [] for f in layout: if isinstance(f[1], (int, tuple)): r.append((f[0], f[1], DIR_M_TO_S)) else: r.append((f[0], _make_m2s(f[1]))) return r def _check_layout(layout, packetized): reserveds = ["stb", "ack", "payload"] if packetized: reserveds += ["sop", "eop"] for f in layout: if f[0] in reserveds: raise ValueError(f[0] + " cannot be used in Sink/Source layout") class _Endpoint(Record): def __init__(self, layout, packetized=False): self.packetized = packetized _check_layout(layout, packetized) endpoint_layout = [ ("payload", _make_m2s(layout)), ("stb", 1, DIR_M_TO_S), ("ack", 1, DIR_S_TO_M) ] if packetized: endpoint_layout += [ ("sop", 1, DIR_M_TO_S), ("eop", 1, DIR_M_TO_S) ] Record.__init__(self, endpoint_layout) def __getattr__(self, name): return getattr(object.__getattribute__(self, "payload"), name) class Source(_Endpoint): def connect(self, sink): return Record.connect(self, sink) class Sink(_Endpoint): def connect(self, source): return source.connect(self) def get_endpoints(obj, filt=_Endpoint): if hasattr(obj, "get_endpoints") and callable(obj.get_endpoints): return obj.get_endpoints(filt) r = dict() for k, v in xdir(obj, True): if isinstance(v, filt): r[k] = v return r def get_single_ep(obj, filt): eps = get_endpoints(obj, filt) if len(eps) != 1: raise ValueError("More than one endpoint") return list(eps.items())[0] class BinaryActor(Module): def __init__(self, *args, **kwargs): self.busy = Signal() sink = get_single_ep(self, Sink)[1] source = get_single_ep(self, Source)[1] self.build_binary_control(sink, source, *args, **kwargs) def build_binary_control(self, sink, source): raise NotImplementedError("Binary actor classes must overload build_binary_control_fragment") class CombinatorialActor(BinaryActor): def build_binary_control(self, sink, source): self.comb += [ source.stb.eq(sink.stb), sink.ack.eq(source.ack), self.busy.eq(0) ] if sink.packetized: self.comb += [ source.sop.eq(sink.sop), source.eop.eq(sink.eop) ] class SequentialActor(BinaryActor): def __init__(self, delay): self.trigger = Signal() BinaryActor.__init__(self, delay) def build_binary_control(self, sink, source, delay): ready = Signal() timer = Signal(max=delay+1) self.comb += ready.eq(timer == 0) self.sync += If(self.trigger, timer.eq(delay) ).Elif(~ready, timer.eq(timer - 1) ) mask = Signal() self.comb += [ source.stb.eq(ready & mask), self.trigger.eq(sink.stb & (source.ack | ~mask) & ready), sink.ack.eq(self.trigger), self.busy.eq(~ready) ] self.sync += [ If(self.trigger, mask.eq(1)), If(source.stb & source.ack, mask.eq(0)) ] if sink.packetized: self.comb += [ source.sop.eq(sink.sop), source.eop.eq(sink.eop) ] class PipelinedActor(BinaryActor): def __init__(self, latency): self.pipe_ce = Signal() BinaryActor.__init__(self, latency) def build_binary_control(self, sink, source, latency): busy = 0 valid = sink.stb for i in range(latency): valid_n = Signal() self.sync += If(self.pipe_ce, valid_n.eq(valid)) valid = valid_n busy = busy | valid self.comb += [ self.pipe_ce.eq(source.ack | ~valid), sink.ack.eq(self.pipe_ce), source.stb.eq(valid), self.busy.eq(busy) ] if sink.packetized: sop = sink.sop eop = sink.eop for i in range(latency): sop_n = Signal() eop_n = Signal() self.sync += \ If(self.pipe_ce, sop_n.eq(sop), eop_n.eq(eop) ) sop = sop_n eop = eop_n self.comb += [ source.eop.eq(eop), source.sop.eq(sop) ]