endpoints: add param_layout parameter (required to pass parameter data with converters and will allow logic optimizations)
This commit is contained in:
parent
319465445d
commit
452c60e0c3
|
@ -69,6 +69,14 @@ Accessing the endpoints is done by manipulating the signals inside the ``Source`
|
||||||
* A signal object ``ack``.
|
* A signal object ``ack``.
|
||||||
* The data payload ``payload``, which is a record with the layout given to the endpoint constructor.
|
* 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
|
Busy signal
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,13 @@ class _FIFOActor(Module):
|
||||||
###
|
###
|
||||||
|
|
||||||
description = self.sink.description
|
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:
|
if description.packetized:
|
||||||
fifo_layout += [("sop", 1), ("eop", 1)]
|
fifo_layout += [("sop", 1), ("eop", 1)]
|
||||||
|
|
||||||
|
@ -21,9 +27,11 @@ class _FIFOActor(Module):
|
||||||
self.sink.ack.eq(self.fifo.writable),
|
self.sink.ack.eq(self.fifo.writable),
|
||||||
self.fifo.we.eq(self.sink.stb),
|
self.fifo.we.eq(self.sink.stb),
|
||||||
self.fifo.din.payload.eq(self.sink.payload),
|
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.stb.eq(self.fifo.readable),
|
||||||
self.source.payload.eq(self.fifo.dout.payload),
|
self.source.payload.eq(self.fifo.dout.payload),
|
||||||
|
self.source.param.eq(self.fifo.dout.param),
|
||||||
self.fifo.re.eq(self.source.ack)
|
self.fifo.re.eq(self.source.ack)
|
||||||
]
|
]
|
||||||
if description.packetized:
|
if description.packetized:
|
||||||
|
|
|
@ -66,6 +66,11 @@ class Unpack(Module):
|
||||||
cases[i] = [source.payload.raw_bits().eq(getattr(sink.payload, "chunk"+str(chunk)).raw_bits())]
|
cases[i] = [source.payload.raw_bits().eq(getattr(sink.payload, "chunk"+str(chunk)).raw_bits())]
|
||||||
self.comb += Case(mux, cases).makedefault()
|
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:
|
if description_from.packetized:
|
||||||
self.comb += [
|
self.comb += [
|
||||||
source.sop.eq(sink.sop & first),
|
source.sop.eq(sink.sop & first),
|
||||||
|
@ -97,6 +102,11 @@ class Pack(Module):
|
||||||
load_part.eq(sink.stb & sink.ack)
|
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:
|
if description_to.packetized:
|
||||||
demux_last = ((demux == (n - 1)) | sink.eop)
|
demux_last = ((demux == (n - 1)) | sink.eop)
|
||||||
else:
|
else:
|
||||||
|
@ -146,6 +156,11 @@ class Chunkerize(CombinatorialActor):
|
||||||
dst = getattr(getattr(self.source, "chunk"+str(chunk)), f[0])
|
dst = getattr(getattr(self.source, "chunk"+str(chunk)), f[0])
|
||||||
self.comb += dst.eq(src[i*flen(src)//n:(i+1)*flen(src)//n])
|
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):
|
class Unchunkerize(CombinatorialActor):
|
||||||
def __init__(self, layout_from, n, layout_to, reverse=False):
|
def __init__(self, layout_from, n, layout_to, reverse=False):
|
||||||
if isinstance(layout_from, EndpointDescription):
|
if isinstance(layout_from, EndpointDescription):
|
||||||
|
@ -168,6 +183,11 @@ class Unchunkerize(CombinatorialActor):
|
||||||
dst = getattr(self.source, f[0])
|
dst = getattr(self.source, f[0])
|
||||||
self.comb += dst[i*flen(dst)//n:(i+1)*flen(dst)//n].eq(src)
|
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):
|
class Converter(Module):
|
||||||
def __init__(self, layout_from, layout_to, reverse=False):
|
def __init__(self, layout_from, layout_to, reverse=False):
|
||||||
self.sink = Sink(layout_from)
|
self.sink = Sink(layout_from)
|
||||||
|
|
|
@ -13,18 +13,24 @@ def _make_m2s(layout):
|
||||||
return r
|
return r
|
||||||
|
|
||||||
class EndpointDescription:
|
class EndpointDescription:
|
||||||
def __init__(self, payload_layout, packetized=False):
|
def __init__(self, payload_layout, param_layout=[], packetized=False):
|
||||||
self.payload_layout = payload_layout
|
self.payload_layout = payload_layout
|
||||||
|
self.param_layout = param_layout
|
||||||
self.packetized = packetized
|
self.packetized = packetized
|
||||||
|
|
||||||
def get_full_layout(self):
|
def get_full_layout(self):
|
||||||
reserved = {"stb", "ack", "payload", "sop", "eop", "description"}
|
reserved = {"stb", "ack", "payload", "param", "sop", "eop", "description"}
|
||||||
for f in self.payload_layout:
|
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:
|
if f[0] in reserved:
|
||||||
raise ValueError(f[0] + " cannot be used in endpoint layout")
|
raise ValueError(f[0] + " cannot be used in endpoint layout")
|
||||||
|
attributed.add(f[0])
|
||||||
|
|
||||||
full_layout = [
|
full_layout = [
|
||||||
("payload", _make_m2s(self.payload_layout)),
|
("payload", _make_m2s(self.payload_layout)),
|
||||||
|
("param", _make_m2s(self.param_layout)),
|
||||||
("stb", 1, DIR_M_TO_S),
|
("stb", 1, DIR_M_TO_S),
|
||||||
("ack", 1, DIR_S_TO_M)
|
("ack", 1, DIR_S_TO_M)
|
||||||
]
|
]
|
||||||
|
@ -45,7 +51,10 @@ class _Endpoint(Record):
|
||||||
Record.__init__(self, self.description.get_full_layout())
|
Record.__init__(self, self.description.get_full_layout())
|
||||||
|
|
||||||
def __getattr__(self, name):
|
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):
|
class Source(_Endpoint):
|
||||||
def connect(self, sink):
|
def connect(self, sink):
|
||||||
|
|
|
@ -8,7 +8,11 @@ class Buffer(PipelinedActor):
|
||||||
self.d = Sink(layout)
|
self.d = Sink(layout)
|
||||||
self.q = Source(layout)
|
self.q = Source(layout)
|
||||||
PipelinedActor.__init__(self, 1)
|
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):
|
class Combinator(Module):
|
||||||
def __init__(self, layout, subrecords):
|
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 += [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.payload.eq(sink.payload) for sink in sinks]
|
||||||
|
self.comb += [self.source.param.eq(sink.param) for sink in sinks]
|
||||||
|
|
||||||
class Splitter(Module):
|
class Splitter(Module):
|
||||||
def __init__(self, layout, subrecords):
|
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.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))
|
already_acked = Signal(len(sources))
|
||||||
self.sync += If(self.sink.stb,
|
self.sync += If(self.sink.stb,
|
||||||
already_acked.eq(already_acked | Cat(*[s.ack for s in sources])),
|
already_acked.eq(already_acked | Cat(*[s.ack for s in sources])),
|
||||||
|
|
Loading…
Reference in New Issue