171 lines
5.9 KiB
Python
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)
|
|
]
|