litex/misoclib/com/litepcie/core/packet/depacketizer.py

171 lines
5.9 KiB
Python

from migen.fhdl.std import *
from migen.actorlib.structuring import *
from migen.genlib.fsm import FSM, NextState
from misoclib.com.litepcie.core.packet.common import *
from misoclib.com.litepcie.core.switch.dispatcher import Dispatcher
def _decode_header(h_dict, h_signal, obj):
r = []
for k, v in sorted(h_dict.items()):
start = v.word*32+v.offset
end = start+v.width
r.append(getattr(obj, k).eq(h_signal[start:end]))
return r
class HeaderExtracter(Module):
def __init__(self, dw):
self.sink = Sink(phy_layout(dw))
self.source = Source(tlp_raw_layout(dw))
###
sink, source = self.sink, self.source
sop = Signal()
shift = Signal()
sink_dat_r = Signal(dw)
sink_be_r = Signal(dw//8)
fsm = FSM(reset_state="HEADER1")
self.submodules += fsm
fsm.act("HEADER1",
sink.ack.eq(1),
If(sink.stb,
shift.eq(1),
NextState("HEADER2")
)
)
fsm.act("HEADER2",
sink.ack.eq(1),
If(sink.stb,
shift.eq(1),
If(sink.eop,
sink.ack.eq(0),
NextState("TERMINATE"),
).Else(
NextState("COPY")
)
)
)
self.sync += [
If(shift, self.source.header.eq(Cat(self.source.header[64:], sink.dat))),
If(sink.stb & sink.ack,
sink_dat_r.eq(sink.dat),
sink_be_r.eq(sink.be)
)
]
fsm.act("COPY",
sink.ack.eq(source.ack),
source.stb.eq(sink.stb),
source.sop.eq(sop),
source.eop.eq(sink.eop),
source.dat.eq(Cat(reverse_bytes(sink_dat_r[32:]), reverse_bytes(sink.dat[:32]))),
source.be.eq(Cat(reverse_bits(sink_be_r[4:]), reverse_bits(sink.be[:4]))),
If(source.stb & source.ack & source.eop,
NextState("HEADER1")
)
)
self.sync += \
If(fsm.before_entering("COPY"),
sop.eq(1)
).Elif(source.stb & source.ack,
sop.eq(0)
)
fsm.act("TERMINATE",
sink.ack.eq(source.ack),
source.stb.eq(1),
source.sop.eq(1),
source.eop.eq(1),
source.dat.eq(reverse_bytes(sink.dat[32:])),
source.be.eq(reverse_bits(sink.be[4:])),
If(source.stb & source.ack & source.eop,
NextState("HEADER1")
)
)
class Depacketizer(Module):
def __init__(self, dw, address_mask=0):
self.sink = Sink(phy_layout(dw))
self.req_source = Source(request_layout(dw))
self.cmp_source = Source(completion_layout(dw))
###
# extract raw header
header_extracter = HeaderExtracter(dw)
self.submodules += header_extracter
self.comb += Record.connect(self.sink, header_extracter.sink)
header = header_extracter.source.header
# dispatch data according to fmt/type
dispatch_source = Source(tlp_common_layout(dw))
dispatch_sinks = [Sink(tlp_common_layout(dw)) for i in range(2)]
self.comb += [
dispatch_source.stb.eq(header_extracter.source.stb),
header_extracter.source.ack.eq(dispatch_source.ack),
dispatch_source.sop.eq(header_extracter.source.sop),
dispatch_source.eop.eq(header_extracter.source.eop),
dispatch_source.dat.eq(header_extracter.source.dat),
dispatch_source.be.eq(header_extracter.source.be),
_decode_header(tlp_common_header, header, dispatch_source)
]
self.submodules.dispatcher = Dispatcher(dispatch_source, dispatch_sinks)
fmt_type = Cat(dispatch_source.type, dispatch_source.fmt)
self.comb += \
If((fmt_type == fmt_type_dict["mem_rd32"]) | (fmt_type == fmt_type_dict["mem_wr32"]),
self.dispatcher.sel.eq(0),
).Elif((fmt_type == fmt_type_dict["cpld"]) | (fmt_type == fmt_type_dict["cpl"]),
self.dispatcher.sel.eq(1),
)
# decode TLP request and format local request
tlp_req = Source(tlp_request_layout(dw))
self.comb += Record.connect(dispatch_sinks[0], tlp_req)
self.comb += _decode_header(tlp_request_header, header, tlp_req)
req_source = self.req_source
self.comb += [
req_source.stb.eq(tlp_req.stb),
req_source.we.eq(tlp_req.stb & (Cat(tlp_req.type, tlp_req.fmt) == fmt_type_dict["mem_wr32"])),
tlp_req.ack.eq(req_source.ack),
req_source.sop.eq(tlp_req.sop),
req_source.eop.eq(tlp_req.eop),
req_source.adr.eq(Cat(Signal(2), tlp_req.address & (~address_mask))),
req_source.len.eq(tlp_req.length),
req_source.req_id.eq(tlp_req.requester_id),
req_source.tag.eq(tlp_req.tag),
req_source.dat.eq(tlp_req.dat),
]
# decode TLP completion and format local completion
tlp_cmp = Source(tlp_completion_layout(dw))
self.comb += Record.connect(dispatch_sinks[1], tlp_cmp)
self.comb += _decode_header(tlp_completion_header, header, tlp_cmp)
cmp_source = self.cmp_source
self.comb += [
cmp_source.stb.eq(tlp_cmp.stb),
tlp_cmp.ack.eq(cmp_source.ack),
cmp_source.sop.eq(tlp_cmp.sop),
cmp_source.eop.eq(tlp_cmp.eop),
cmp_source.len.eq(tlp_cmp.length),
cmp_source.last.eq(tlp_cmp.length == (tlp_cmp.byte_count[2:])),
cmp_source.adr.eq(tlp_cmp.lower_address),
cmp_source.req_id.eq(tlp_cmp.requester_id),
cmp_source.cmp_id.eq(tlp_cmp.completer_id),
cmp_source.err.eq(tlp_cmp.status != 0),
cmp_source.tag.eq(tlp_cmp.tag),
cmp_source.dat.eq(tlp_cmp.dat)
]