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

198 lines
6.2 KiB
Python

from migen.fhdl.std import *
from migen.actorlib.structuring import *
from migen.genlib.fsm import FSM, NextState
from migen.genlib.misc import chooser
from misoclib.com.litepcie.core.packet.common import *
from misoclib.com.litepcie.core.switch.arbiter import Arbiter
def _encode_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(h_signal[start:end].eq(getattr(obj, k)))
return r
class HeaderInserter(Module):
def __init__(self, dw):
self.sink = sink = Sink(tlp_raw_layout(dw))
self.source = source = Source(phy_layout(dw))
###
fsm = FSM(reset_state="HEADER1")
self.submodules += fsm
sink_dat_r = Signal(dw)
sink_eop_r = Signal()
self.sync += \
If(sink.stb & sink.ack,
sink_dat_r.eq(sink.dat),
sink_eop_r.eq(sink.eop)
)
fsm.act("HEADER1",
sink.ack.eq(1),
If(sink.stb & sink.sop,
sink.ack.eq(0),
source.stb.eq(1),
source.sop.eq(1),
source.eop.eq(0),
source.dat.eq(sink.header[:64]),
source.be.eq(0xff),
If(source.stb & source.ack,
NextState("HEADER2"),
)
)
)
fsm.act("HEADER2",
source.stb.eq(1),
source.sop.eq(0),
source.eop.eq(sink.eop),
source.dat.eq(Cat(sink.header[64:96], reverse_bytes(sink.dat[:32]))),
source.be.eq(Cat(Signal(4, reset=0xf), reverse_bits(sink.be[:4]))),
If(source.stb & source.ack,
sink.ack.eq(1),
If(source.eop,
NextState("HEADER1")
).Else(
NextState("COPY")
)
)
)
fsm.act("COPY",
source.stb.eq(sink.stb | sink_eop_r),
source.sop.eq(0),
source.eop.eq(sink_eop_r),
source.dat.eq(Cat(reverse_bytes(sink_dat_r[32:64]), reverse_bytes(sink.dat[:32]))),
If(sink_eop_r,
source.be.eq(0x0f)
).Else(
source.be.eq(0xff)
),
If(source.stb & source.ack,
sink.ack.eq(~sink_eop_r),
If(source.eop,
NextState("HEADER1")
)
)
)
class Packetizer(Module):
def __init__(self, dw):
self.req_sink = req_sink = Sink(request_layout(dw))
self.cmp_sink = cmp_sink = Sink(completion_layout(dw))
self.source = Source(phy_layout(dw))
###
# format TLP request and encode it
tlp_req = Sink(tlp_request_layout(dw))
self.comb += [
tlp_req.stb.eq(req_sink.stb),
req_sink.ack.eq(tlp_req.ack),
tlp_req.sop.eq(req_sink.sop),
tlp_req.eop.eq(req_sink.eop),
If(req_sink.we,
Cat(tlp_req.type, tlp_req.fmt).eq(fmt_type_dict["mem_wr32"])
).Else(
Cat(tlp_req.type, tlp_req.fmt).eq(fmt_type_dict["mem_rd32"])
),
tlp_req.tc.eq(0),
tlp_req.td.eq(0),
tlp_req.ep.eq(0),
tlp_req.attr.eq(0),
tlp_req.length.eq(req_sink.len),
tlp_req.requester_id.eq(req_sink.req_id),
tlp_req.tag.eq(req_sink.tag),
If(req_sink.len > 1,
tlp_req.last_be.eq(0xf)
).Else(
tlp_req.last_be.eq(0x0)
),
tlp_req.first_be.eq(0xf),
tlp_req.address.eq(req_sink.adr[2:]),
tlp_req.dat.eq(req_sink.dat),
If(req_sink.we,
tlp_req.be.eq(0xff)
).Else(
tlp_req.be.eq(0x00)
),
]
tlp_raw_req = Sink(tlp_raw_layout(dw))
self.comb += [
tlp_raw_req.stb.eq(tlp_req.stb),
tlp_req.ack.eq(tlp_raw_req.ack),
tlp_raw_req.sop.eq(tlp_req.sop),
tlp_raw_req.eop.eq(tlp_req.eop),
_encode_header(tlp_request_header, tlp_raw_req.header, tlp_req),
tlp_raw_req.dat.eq(tlp_req.dat),
tlp_raw_req.be.eq(tlp_req.be),
]
# format TLP completion and encode it
tlp_cmp = Sink(tlp_completion_layout(dw))
self.comb += [
tlp_cmp.stb.eq(cmp_sink.stb),
cmp_sink.ack.eq(tlp_cmp.ack),
tlp_cmp.sop.eq(cmp_sink.sop),
tlp_cmp.eop.eq(cmp_sink.eop),
tlp_cmp.tc.eq(0),
tlp_cmp.td.eq(0),
tlp_cmp.ep.eq(0),
tlp_cmp.attr.eq(0),
tlp_cmp.length.eq(cmp_sink.len),
tlp_cmp.completer_id.eq(cmp_sink.cmp_id),
If(cmp_sink.err,
Cat(tlp_cmp.type, tlp_cmp.fmt).eq(fmt_type_dict["cpl"]),
tlp_cmp.status.eq(cpl_dict["ur"])
).Else(
Cat(tlp_cmp.type, tlp_cmp.fmt).eq(fmt_type_dict["cpld"]),
tlp_cmp.status.eq(cpl_dict["sc"])
),
tlp_cmp.bcm.eq(0),
tlp_cmp.byte_count.eq(cmp_sink.len*4),
tlp_cmp.requester_id.eq(cmp_sink.req_id),
tlp_cmp.tag.eq(cmp_sink.tag),
tlp_cmp.lower_address.eq(cmp_sink.adr),
tlp_cmp.dat.eq(cmp_sink.dat),
tlp_cmp.be.eq(0xff)
]
tlp_raw_cmp = Sink(tlp_raw_layout(dw))
self.comb += [
tlp_raw_cmp.stb.eq(tlp_cmp.stb),
tlp_cmp.ack.eq(tlp_raw_cmp.ack),
tlp_raw_cmp.sop.eq(tlp_cmp.sop),
tlp_raw_cmp.eop.eq(tlp_cmp.eop),
_encode_header(tlp_completion_header, tlp_raw_cmp.header, tlp_cmp),
tlp_raw_cmp.dat.eq(tlp_cmp.dat),
tlp_raw_cmp.be.eq(tlp_cmp.be),
]
# arbitrate
tlp_raw = Sink(tlp_raw_layout(dw))
self.submodules.arbitrer = Arbiter([tlp_raw_req, tlp_raw_cmp], tlp_raw)
# insert header
header_inserter = HeaderInserter(dw)
self.submodules += header_inserter
self.comb += [
Record.connect(tlp_raw, header_inserter.sink),
Record.connect(header_inserter.source, self.source)
]