From 452c60e0c37b6342d609029fd76f576878ff3ad9 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 12 Feb 2015 23:36:57 +0100 Subject: [PATCH] endpoints: add param_layout parameter (required to pass parameter data with converters and will allow logic optimizations) --- doc/dataflow.rst | 8 ++++++++ migen/actorlib/fifo.py | 10 +++++++++- migen/actorlib/structuring.py | 20 ++++++++++++++++++++ migen/flow/actor.py | 17 +++++++++++++---- migen/flow/plumbing.py | 8 +++++++- 5 files changed, 57 insertions(+), 6 deletions(-) diff --git a/doc/dataflow.rst b/doc/dataflow.rst index c8478f048..c435eddf9 100644 --- a/doc/dataflow.rst +++ b/doc/dataflow.rst @@ -69,6 +69,14 @@ Accessing the endpoints is done by manipulating the signals inside the ``Source` * A signal object ``ack``. * The data payload ``payload``, which is a record with the layout given to the endpoint constructor. +Endpoints can also be used to manipulate packets, this is done by setting packetized parameter to True which adds: + +* A signal object ``sop`` (Start Of Packet). +* A signal object ``eop`` (End Of Packet). + +When used in packetized mode, packet parameters (signals that do no change for the duration of a packet) should to be declared in +param_layout. Declaring these signals in payload_layout will works in most cases but will prevent logic optimizations. + Busy signal =========== diff --git a/migen/actorlib/fifo.py b/migen/actorlib/fifo.py index 5663e61dc..36312eb8d 100644 --- a/migen/actorlib/fifo.py +++ b/migen/actorlib/fifo.py @@ -11,7 +11,13 @@ class _FIFOActor(Module): ### description = self.sink.description - fifo_layout = [("payload", description.payload_layout)] + fifo_layout = [ + ("payload", description.payload_layout), + # Note : Can be optimized by passing parameters + # in another fifo. We will only have one + # data per packet. + ("param", description.param_layout) + ] if description.packetized: fifo_layout += [("sop", 1), ("eop", 1)] @@ -21,9 +27,11 @@ class _FIFOActor(Module): self.sink.ack.eq(self.fifo.writable), self.fifo.we.eq(self.sink.stb), self.fifo.din.payload.eq(self.sink.payload), + self.fifo.din.param.eq(self.sink.param), self.source.stb.eq(self.fifo.readable), self.source.payload.eq(self.fifo.dout.payload), + self.source.param.eq(self.fifo.dout.param), self.fifo.re.eq(self.source.ack) ] if description.packetized: diff --git a/migen/actorlib/structuring.py b/migen/actorlib/structuring.py index de733a266..1ad971c82 100644 --- a/migen/actorlib/structuring.py +++ b/migen/actorlib/structuring.py @@ -66,6 +66,11 @@ class Unpack(Module): cases[i] = [source.payload.raw_bits().eq(getattr(sink.payload, "chunk"+str(chunk)).raw_bits())] self.comb += Case(mux, cases).makedefault() + for f in description_from.param_layout: + src = getattr(self.sink, f[0]) + dst = getattr(self.source, f[0]) + self.comb += dst.eq(src) + if description_from.packetized: self.comb += [ source.sop.eq(sink.sop & first), @@ -97,6 +102,11 @@ class Pack(Module): load_part.eq(sink.stb & sink.ack) ] + for f in description_to.param_layout: + src = getattr(self.sink, f[0]) + dst = getattr(self.source, f[0]) + self.comb += dst.eq(src) + if description_to.packetized: demux_last = ((demux == (n - 1)) | sink.eop) else: @@ -146,6 +156,11 @@ class Chunkerize(CombinatorialActor): dst = getattr(getattr(self.source, "chunk"+str(chunk)), f[0]) self.comb += dst.eq(src[i*flen(src)//n:(i+1)*flen(src)//n]) + for f in self.sink.description.param_layout: + src = getattr(self.sink, f[0]) + dst = getattr(self.source, f[0]) + self.comb += dst.eq(src) + class Unchunkerize(CombinatorialActor): def __init__(self, layout_from, n, layout_to, reverse=False): if isinstance(layout_from, EndpointDescription): @@ -168,6 +183,11 @@ class Unchunkerize(CombinatorialActor): dst = getattr(self.source, f[0]) self.comb += dst[i*flen(dst)//n:(i+1)*flen(dst)//n].eq(src) + for f in self.sink.description.param_layout: + src = getattr(self.sink, f[0]) + dst = getattr(self.source, f[0]) + self.comb += dst.eq(src) + class Converter(Module): def __init__(self, layout_from, layout_to, reverse=False): self.sink = Sink(layout_from) diff --git a/migen/flow/actor.py b/migen/flow/actor.py index cc539256f..58ddcb402 100644 --- a/migen/flow/actor.py +++ b/migen/flow/actor.py @@ -13,18 +13,24 @@ def _make_m2s(layout): return r class EndpointDescription: - def __init__(self, payload_layout, packetized=False): + def __init__(self, payload_layout, param_layout=[], packetized=False): self.payload_layout = payload_layout + self.param_layout = param_layout self.packetized = packetized def get_full_layout(self): - reserved = {"stb", "ack", "payload", "sop", "eop", "description"} - for f in self.payload_layout: + reserved = {"stb", "ack", "payload", "param", "sop", "eop", "description"} + attributed = set() + for f in self.payload_layout + self.param_layout: + if f[0] in attributed: + raise ValueError(f[0] + " already attributed in payload or param layout") if f[0] in reserved: raise ValueError(f[0] + " cannot be used in endpoint layout") + attributed.add(f[0]) full_layout = [ ("payload", _make_m2s(self.payload_layout)), + ("param", _make_m2s(self.param_layout)), ("stb", 1, DIR_M_TO_S), ("ack", 1, DIR_S_TO_M) ] @@ -45,7 +51,10 @@ class _Endpoint(Record): Record.__init__(self, self.description.get_full_layout()) def __getattr__(self, name): - return getattr(object.__getattribute__(self, "payload"), name) + try: + return getattr(object.__getattribute__(self, "payload"), name) + except: + return getattr(object.__getattribute__(self, "param"), name) class Source(_Endpoint): def connect(self, sink): diff --git a/migen/flow/plumbing.py b/migen/flow/plumbing.py index 1ca13f818..6e4f81aa3 100644 --- a/migen/flow/plumbing.py +++ b/migen/flow/plumbing.py @@ -8,7 +8,11 @@ class Buffer(PipelinedActor): self.d = Sink(layout) self.q = Source(layout) PipelinedActor.__init__(self, 1) - self.sync += If(self.pipe_ce, self.q.payload.eq(self.d.payload)) + self.sync += \ + If(self.pipe_ce, + self.q.payload.eq(self.d.payload), + self.q.param.eq(self.d.param) + ) class Combinator(Module): def __init__(self, layout, subrecords): @@ -28,6 +32,7 @@ class Combinator(Module): ] self.comb += [sink.ack.eq(self.source.ack & self.source.stb) for sink in sinks] self.comb += [self.source.payload.eq(sink.payload) for sink in sinks] + self.comb += [self.source.param.eq(sink.param) for sink in sinks] class Splitter(Module): def __init__(self, layout, subrecords): @@ -42,6 +47,7 @@ class Splitter(Module): ### self.comb += [source.payload.eq(self.sink.payload) for source in sources] + self.comb += [source.param.eq(self.sink.param) for source in sources] already_acked = Signal(len(sources)) self.sync += If(self.sink.stb, already_acked.eq(already_acked | Cat(*[s.ack for s in sources])),