soc/interconnect/packet: add > 8-bit support to Packetizer/Depacketizer

With high speed link (10gbps XGMII ethernet for example), stream data_width is generally
> 8-bit which make header/data un-aligned on bytes boundaries. The change allows the
Packetizer/Depacketizer to work on stream with a data_width > 8-bit.
This commit is contained in:
Vamsi K Vytla 2019-11-15 11:22:49 +01:00 committed by Florent Kermarrec
parent 5f151152ca
commit 5c19b133ac
1 changed files with 152 additions and 53 deletions

View File

@ -155,21 +155,24 @@ class Header:
class Packetizer(Module): class Packetizer(Module):
def __init__(self, sink_description, source_description, header): def __init__(self, sink_description, source_description, header):
self.sink = sink = stream.Endpoint(sink_description) self.sink = sink = stream.Endpoint(sink_description)
self.source = source = stream.Endpoint(source_description) self.source = source = stream.Endpoint(source_description)
self.header = Signal(header.length*8) self.header = Signal(header.length*8)
# # # # # #
dw = len(self.sink.data) dw = len(self.sink.data)
cw = dw // 8
header_reg = Signal(header.length*8, reset_less=True) header_reg = Signal(header.length*8, reset_less=True)
header_words = (header.length*8)//dw header_words = (header.length*8)//dw
load = Signal() header_residue = header.length % cw
shift = Signal() if header_residue:
counter = Signal(max=max(header_words, 2)) header_leftover = Signal(header_residue*8)
load = Signal()
shift = Signal()
counter = Signal(max=max(header_words, 2))
counter_reset = Signal() counter_reset = Signal()
counter_ce = Signal() counter_ce = Signal()
self.sync += \ self.sync += \
If(counter_reset, If(counter_reset,
counter.eq(0) counter.eq(0)
@ -195,52 +198,102 @@ class Packetizer(Module):
fsm = FSM(reset_state="IDLE") fsm = FSM(reset_state="IDLE")
self.submodules += fsm self.submodules += fsm
self.transitioning = transitioning = Signal() # TODO: Perhaps fsm already has a transitioning signal
if header_words == 1: # TODO: What is the recommended way to delay a record, a FIFO?
last_buf, valid_buf = Signal(), Signal()
self.data_buf = data_buf = Signal(len(sink.data))
if header_words == 1 and header_residue == 0:
idle_next_state = "COPY" idle_next_state = "COPY"
elif header_words == 1 and header_residue:
idle_next_state = "STAGGERCOPY"
else: else:
idle_next_state = "SEND-HEADER" idle_next_state = "SEND_HEADER"
fsm.act("IDLE", fsm.act("IDLE",
sink.ready.eq(1), sink.ready.eq(1),
counter_reset.eq(1), counter_reset.eq(1),
If(sink.valid, If(sink.valid,
sink.ready.eq(0), sink.ready.eq(0),
source.valid.eq(1), source.valid.eq(1),
source.last.eq(0), source.last.eq(0),
source.data.eq(self.header[:dw]), source.data.eq(self.header[:dw]),
If(source.valid & source.ready, If(source.valid & source.ready,
load.eq(1), load.eq(1),
NextState(idle_next_state) NextValue(transitioning, 1),
) NextState(idle_next_state)
)
) )
) )
# if header_residue and header_words >= 2:
# self.sync += [header_leftover.eq(header_reg[2*dw:(2*dw+header_residue*8)]),
# ]
self.sync += [last_buf.eq(sink.last),
data_buf.eq(sink.data),
valid_buf.eq(sink.valid),
]
if header_words != 1: if header_words != 1:
fsm.act("SEND-HEADER", fsm.act("SEND_HEADER",
source.valid.eq(1), source.valid.eq(1),
source.last.eq(0), source.last.eq(0),
source.data.eq(header_reg[dw:2*dw]), source.data.eq(header_reg[dw:2*dw]),
If(source.valid & source.ready, If(source.valid & source.ready,
shift.eq(1), shift.eq(1),
counter_ce.eq(1), counter_ce.eq(1),
If(counter == header_words-2, If(counter == header_words-2,
NextState("COPY") shift.eq(0),
) counter_ce.eq(1 if header_residue else 0),
NextValue(transitioning, 1),
NextState("STAGGERCOPY" if header_residue else "COPY")
)
) )
) )
if hasattr(sink, "error"): if hasattr(sink, "error"):
self.comb += source.error.eq(sink.error) self.comb += source.error.eq(sink.error)
fsm.act("COPY", if hasattr(sink, "last_be"):
source.valid.eq(sink.valid), # header_lengh + last_be
source.last.eq(sink.last), cw = dw//8
source.data.eq(sink.data), rotate_by = header.length % cw
If(source.valid & source.ready, x = [sink.last_be[(i + rotate_by) % cw] for i in range(cw)]
sink.ready.eq(1), self.comb += source.last_be.eq(Cat(*x))
If(source.last, if header_residue:
NextState("IDLE") header_offset_multiplier = hom = 1 if header_words == 1 else 2
) fsm.act("STAGGERCOPY",
source.valid.eq(valid_buf),
source.last.eq(last_buf),
If(transitioning,
source.data.eq(Cat(header_reg[hom*dw:hom*dw+header_residue*8],
sink.data[:(cw-header_residue)*8]))
).Else(
source.data.eq(Cat(data_buf[(cw-header_residue)*8:],
sink.data[:(cw-header_residue)*8]))
),
If(source.valid & source.ready,
sink.ready.eq(1),
If(sink.valid,
NextValue(transitioning, 0)
),
If(source.last,
NextState("IDLE")
)
),
) )
) else:
fsm.act("COPY",
source.valid.eq(sink.valid),
source.last.eq(sink.last),
source.data.eq(sink.data),
If(source.valid & source.ready,
NextValue(transitioning, 0),
sink.ready.eq(1),
If(source.last,
NextState("IDLE")
)
),
)
# Depacketizer ------------------------------------------------------------------------------------- # Depacketizer -------------------------------------------------------------------------------------
@ -254,13 +307,16 @@ class Depacketizer(Module):
dw = len(sink.data) dw = len(sink.data)
cw = dw // 8
header_reg = Signal(header.length*8, reset_less=True) header_reg = Signal(header.length*8, reset_less=True)
header_words = (header.length*8)//dw header_words = (header.length*8)//dw
header_residue = header.length % cw
shift = Signal() shift = Signal()
counter = Signal(max=max(header_words, 2)) counter = Signal(max=max(header_words, 2))
counter_reset = Signal() counter_reset = Signal()
counter_ce = Signal() counter_ce = Signal()
self.sync += \ self.sync += \
If(counter_reset, If(counter_reset,
counter.eq(0) counter.eq(0)
@ -268,23 +324,30 @@ class Depacketizer(Module):
counter.eq(counter + 1) counter.eq(counter + 1)
) )
if header_words == 1: if header_words == 1 and header_residue == 0:
self.sync += \ self.sync += \
If(shift, If(shift,
header_reg.eq(sink.data) header_reg.eq(sink.data)
) )
else: else:
self.sync += \ self.sync += \
If(shift, If(shift,
header_reg.eq(Cat(header_reg[dw:], sink.data)) header_reg.eq(Cat(header_reg[dw:], sink.data))
) )
self.comb += self.header.eq(header_reg) self.comb += self.header.eq(header_reg)
fsm = FSM(reset_state="IDLE") fsm = FSM(reset_state="IDLE")
self.submodules += fsm self.submodules += fsm
# TODO: Perhaps fsm already has a transitioning signal
self.transitioning = transitioning = Signal()
if header_words == 1: last_buf, valid_buf = Signal(), Signal()
self.data_buf = data_buf = Signal(len(sink.data))
if header_words == 1 and header_residue == 0:
idle_next_state = "COPY" idle_next_state = "COPY"
elif header_words == 1 and header_residue:
idle_next_state = "STAGGERCOPY"
else: else:
idle_next_state = "RECEIVE_HEADER" idle_next_state = "RECEIVE_HEADER"
@ -292,10 +355,16 @@ class Depacketizer(Module):
sink.ready.eq(1), sink.ready.eq(1),
counter_reset.eq(1), counter_reset.eq(1),
If(sink.valid, If(sink.valid,
shift.eq(1), shift.eq(1),
NextState(idle_next_state) NextValue(transitioning, 1),
NextState(idle_next_state)
) )
) )
self.sync += [If(sink.ready, data_buf.eq(sink.data)),
valid_buf.eq(sink.valid),
]
if header_words != 1: if header_words != 1:
fsm.act("RECEIVE_HEADER", fsm.act("RECEIVE_HEADER",
sink.ready.eq(1), sink.ready.eq(1),
@ -303,27 +372,57 @@ class Depacketizer(Module):
counter_ce.eq(1), counter_ce.eq(1),
shift.eq(1), shift.eq(1),
If(counter == header_words-2, If(counter == header_words-2,
NextState("COPY") counter_ce.eq(1 if header_residue else 0),
NextValue(transitioning, 1),
NextState("STAGGERCOPY" if header_residue else "COPY")
) )
) )
) )
no_payload = Signal() no_payload = Signal()
self.sync += \ self.sync += \
If(fsm.before_entering("COPY"), If(fsm.before_entering("COPY") | fsm.before_entering("STAGGERCOPY"),
no_payload.eq(sink.last) no_payload.eq(sink.last)
) )
if hasattr(sink, "error"): if hasattr(sink, "error"):
self.comb += source.error.eq(sink.error) self.comb += source.error.eq(sink.error)
if hasattr(sink, "last_be"):
# header_lengh + last_be
cw = dw//8
x = [sink.last_be[(i - (cw - header_residue)) % cw] for i in range(cw)]
self.comb += source.last_be.eq(Cat(*x))
self.comb += [ self.comb += [
source.last.eq(sink.last | no_payload),
source.data.eq(sink.data),
header.decode(self.header, source) header.decode(self.header, source)
] ]
fsm.act("COPY", if header_residue:
sink.ready.eq(source.ready), fsm.act("STAGGERCOPY",
source.valid.eq(sink.valid | no_payload), source.last.eq(sink.last | no_payload),
If(source.valid & source.ready & source.last, sink.ready.eq(source.ready),
NextState("IDLE") source.valid.eq(sink.valid & ~transitioning | no_payload),
If(sink.valid & source.ready,
If(transitioning,
NextValue(header_reg, Cat(header_reg[header_residue*8:],
sink.data[:header_residue*8]))
).Else(
source.data.eq(Cat(data_buf[header_residue*8:],
sink.data[:header_residue*8])),
),
NextValue(transitioning, 0)
),
If(source.valid & source.ready & source.last,
NextState("IDLE")
),
) )
) else:
fsm.act("COPY",
source.last.eq(sink.last | no_payload),
source.data.eq(sink.data),
sink.ready.eq(source.ready),
source.valid.eq(sink.valid | no_payload),
If(source.valid & source.ready,
NextValue(transitioning, 0),
If(source.last,
NextState("IDLE")
)
)
)