From 5530091d920e26ee8796385d50189fcf44bde0e7 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 27 Jul 2023 22:19:35 +0200 Subject: [PATCH 01/14] tlp/common: Add configuration header/layout. --- litepcie/tlp/common.py | 43 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/litepcie/tlp/common.py b/litepcie/tlp/common.py index dbf7ba5..dcf1073 100644 --- a/litepcie/tlp/common.py +++ b/litepcie/tlp/common.py @@ -74,6 +74,32 @@ swap_field_bytes = False # No byte swapping required. ) +# Length of the TLP configuration header (in bytes). +tlp_configuration_header_length = 16 +# Define TLP request header fields. +tlp_configuration_header_fields = { + "fmt": HeaderField(byte=0*4, offset=29, width= 2), # Format. + "type": HeaderField(byte=0*4, offset=24, width= 5), # Type. + "td": HeaderField(byte=0*4, offset=15, width= 1), # TLP Digest. + "ep": HeaderField(byte=0*4, offset=14, width= 1), # Poisoned TLP. + + "requester_id": HeaderField(byte=1*4, offset=16, width=16), # Requester ID. + "tag": HeaderField(byte=1*4, offset= 8, width= 8), # Tag. + "first_be": HeaderField(byte=1*4, offset= 0, width= 4), # First Byte Enable. + + "bus_number": HeaderField(byte=2*4, offset=24, width=8), # Bus number. + "device_no": HeaderField(byte=2*4, offset=19, width=5), # Device number. + "func": HeaderField(byte=2*4, offset=16, width=3), # Function number. + "ext_reg": HeaderField(byte=2*4, offset= 8, width=3), # Extended Register. + "register_no": HeaderField(byte=2*4, offset= 2, width=6), # Register number. +} +# Define TLP configuration header. +tlp_configuration_header = Header( + fields = tlp_configuration_header_fields, + length = tlp_configuration_header_length, + swap_field_bytes = False # No byte swapping required. +) + # Length of the TLP request header (in bytes). tlp_request_header_length = 16 # Define TLP request header fields. @@ -206,6 +232,23 @@ def tlp_common_layout(data_width): return EndpointDescription(layout) +def tlp_configuration_layout(data_width): + """ + Generate a configuration TLP endpoint description. + + Parameters: + data_width (int): Width of the data (in bits). + + Returns: + EndpointDescription: Configuration TLP endpoint description. + """ + layout = tlp_configuration_header.get_layout() + [ + ("dat", data_width), # Data field. + ("be", data_width//8) # Byte Enable field. + ] + return EndpointDescription(layout) + + def tlp_request_layout(data_width): """ Generate a request TLP endpoint description. From 2ed8723ab51b29c8aececebc0a23956dc19e4b19 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 27 Jul 2023 22:21:14 +0200 Subject: [PATCH 02/14] common: Add configuration layout. --- litepcie/common.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/litepcie/common.py b/litepcie/common.py index 6f5be89..48617ad 100644 --- a/litepcie/common.py +++ b/litepcie/common.py @@ -38,6 +38,25 @@ def phy_layout(data_width): ] return EndpointDescription(layout) +def configuration_layout(data_width, address_width=32): + layout = [ + # Request Parameters. + ("req_id", 16), # Requester ID. + ("we", 1), # Configuration type; 0 : Read / 1 : Write. + ("bus_number", 8), # Configuration Bus number. + ("device_no", 5), # Configuration Device number. + ("func", 3), # Configuration Function number. + ("ext_reg", 3), # Configuration Extended Register. + ("register_no", 6), # Configuration Register number. + + # Data Stream. + ("dat", data_width), + + # Internal LitePCIe Routing/Identification. + ("channel", 8), # Crossbar's channel (Used for internal routing). + ] + return EndpointDescription(layout) + def request_layout(data_width, address_width=32): layout = [ # Request Parameters. From 24e0ae10854b3f707c4cb5e5e9dbd9b9e348e80b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 27 Jul 2023 22:22:33 +0200 Subject: [PATCH 03/14] tlp/depacketizer: Add conf_source and dispatch/decode. --- litepcie/tlp/depacketizer.py | 39 +++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/litepcie/tlp/depacketizer.py b/litepcie/tlp/depacketizer.py index 5a6843f..dc1fadc 100644 --- a/litepcie/tlp/depacketizer.py +++ b/litepcie/tlp/depacketizer.py @@ -296,9 +296,10 @@ def __init__(self): class LitePCIeTLPDepacketizer(LiteXModule): def __init__(self, data_width, endianness, address_mask=0): - self.sink = stream.Endpoint(phy_layout(data_width)) - self.req_source = stream.Endpoint(request_layout(data_width)) - self.cmp_source = stream.Endpoint(completion_layout(data_width)) + self.sink = stream.Endpoint(phy_layout(data_width)) + self.req_source = req_source = stream.Endpoint(request_layout(data_width)) + self.cmp_source = cmp_source = stream.Endpoint(completion_layout(data_width)) + self.conf_source = conf_source = stream.Endpoint(configuration_layout(data_width)) # # # @@ -316,7 +317,7 @@ def __init__(self, data_width, endianness, address_mask=0): # Dispatch data according to fmt/type ------------------------------------------------------ dispatch_source = stream.Endpoint(tlp_common_layout(data_width)) - dispatch_sinks = [stream.Endpoint(tlp_common_layout(data_width)) for i in range(3)] + dispatch_sinks = [stream.Endpoint(tlp_common_layout(data_width)) for i in range(4)] self.comb += dispatch_sinks[0b00].ready.eq(1) # Always ready when unknown. self.comb += [ @@ -345,14 +346,21 @@ def __init__(self, data_width, endianness, address_mask=0): fmt_type = Cat(dispatch_source.type, dispatch_source.fmt) self.comb += [ self.dispatcher.sel.eq(0b00), + # Memory Write/Read. If((fmt_type == fmt_type_dict["mem_rd32"]) | (fmt_type == fmt_type_dict["mem_wr32"]), self.dispatcher.sel.eq(0b01), ), + # Completion. If((fmt_type == fmt_type_dict["cpld"]) | (fmt_type == fmt_type_dict["cpl"]), self.dispatcher.sel.eq(0b10), ), + # Configuration. + If((fmt_type == fmt_type_dict["cfg_rd0"]) | + (fmt_type == fmt_type_dict["cfg_wr0"]), + self.dispatcher.sel.eq(0b11), + ), ] # Decode TLP request and format local request ---------------------------------------------- @@ -360,8 +368,7 @@ def __init__(self, data_width, endianness, address_mask=0): self.comb += dispatch_sinks[0b01].connect(tlp_req) self.comb += tlp_request_header.decode(header, tlp_req) - req_type = Cat(tlp_req.type, tlp_req.fmt) - req_source = self.req_source + req_type = Cat(tlp_req.type, tlp_req.fmt) self.comb += [ req_source.valid.eq(tlp_req.valid), req_source.we.eq(tlp_req.valid & (req_type == fmt_type_dict["mem_wr32"])), @@ -380,7 +387,6 @@ def __init__(self, data_width, endianness, address_mask=0): self.comb += dispatch_sinks[0b10].connect(tlp_cmp) self.comb += tlp_completion_header.decode(header, tlp_cmp) - cmp_source = self.cmp_source self.comb += [ cmp_source.valid.eq(tlp_cmp.valid), tlp_cmp.ready.eq(cmp_source.ready), @@ -395,3 +401,22 @@ def __init__(self, data_width, endianness, address_mask=0): cmp_source.tag.eq(tlp_cmp.tag), cmp_source.dat.eq(tlp_cmp.dat) ] + + + # Decode TLP configuration and format local configuraiton ---------------------------------- + self.tlp_conf = tlp_conf = stream.Endpoint(tlp_configuration_layout(data_width)) + self.comb += dispatch_sinks[0b11].connect(tlp_conf) + self.comb += tlp_configuration_header.decode(header, tlp_conf) + + self.comb += [ + conf_source.valid.eq(tlp_conf.valid), + tlp_conf.ready.eq(conf_source.ready), + conf_source.first.eq(tlp_conf.first), + conf_source.last.eq(tlp_conf.last), + conf_source.bus_number.eq(tlp_conf.bus_number), + conf_source.device_no.eq(tlp_conf.device_no), + conf_source.func.eq(tlp_conf.func), + conf_source.ext_reg.eq(tlp_conf.ext_reg), + conf_source.register_no.eq(tlp_conf.register_no), + req_source.dat.eq(tlp_req.dat) + ] From 64bbb667ece318e6fbcd1180c939fb3e0bb905f4 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 28 Jul 2023 12:35:50 +0200 Subject: [PATCH 04/14] tlp/depacketizer: Make it more modular and add capabilities parameter. By default, we generally only want Request/Completion TLPs support, but for other specific cases (ex PTM) we also want to handle Configuration TLPs. With these change, the module is made more modular to automatically adapt itself to the capabilities provided (and will also allow easily extending capabilities in the future, ex for PTM TLPs). --- litepcie/tlp/depacketizer.py | 223 ++++++++++++++++++++--------------- 1 file changed, 131 insertions(+), 92 deletions(-) diff --git a/litepcie/tlp/depacketizer.py b/litepcie/tlp/depacketizer.py index dc1fadc..d2981ac 100644 --- a/litepcie/tlp/depacketizer.py +++ b/litepcie/tlp/depacketizer.py @@ -295,15 +295,24 @@ def __init__(self): # LitePCIeTLPDepacketizer -------------------------------------------------------------------------- class LitePCIeTLPDepacketizer(LiteXModule): - def __init__(self, data_width, endianness, address_mask=0): - self.sink = stream.Endpoint(phy_layout(data_width)) - self.req_source = req_source = stream.Endpoint(request_layout(data_width)) - self.cmp_source = cmp_source = stream.Endpoint(completion_layout(data_width)) - self.conf_source = conf_source = stream.Endpoint(configuration_layout(data_width)) + def __init__(self, data_width, endianness, address_mask=0, capabilities=["REQUEST", "COMPLETION"]): + # Sink Endpoint. + self.sink = stream.Endpoint(phy_layout(data_width)) + + # Source Endpoints. + for c in capabilities: + assert c in ["REQUEST", "COMPLETION", "CONFIGURATION"] + if "REQUEST" in capabilities: + self.req_source = req_source = stream.Endpoint(request_layout(data_width)) + if "COMPLETION" in capabilities: + self.cmp_source = cmp_source = stream.Endpoint(completion_layout(data_width)) + if "CONFIGURATION" in capabilities: + self.conf_source = conf_source = stream.Endpoint(configuration_layout(data_width)) # # # - # Extract raw header ----------------------------------------------------------------------- + # Extract RAW Header from Sink ------------------------------------------------------------- + header_extracter_cls = { 64 : LitePCIeTLPHeaderExtracter64b, 128 : LitePCIeTLPHeaderExtracter128b, @@ -315,108 +324,138 @@ def __init__(self, data_width, endianness, address_mask=0): self.comb += self.sink.connect(header_extracter.sink) header = header_extracter.source.header - # Dispatch data according to fmt/type ------------------------------------------------------ - dispatch_source = stream.Endpoint(tlp_common_layout(data_width)) - dispatch_sinks = [stream.Endpoint(tlp_common_layout(data_width)) for i in range(4)] - self.comb += dispatch_sinks[0b00].ready.eq(1) # Always ready when unknown. + # Create Dispatcher ------------------------------------------------------------------------ + + # Dispatch Sources + dispatch_sources = {"DISCARD" : stream.Endpoint(tlp_common_layout(data_width))} + for source in capabilities: + dispatch_sources[source] = stream.Endpoint(tlp_common_layout(data_width)) + + def dispatch_source_sel(name): + for n, k in enumerate(dispatch_sources.keys()): + if k == name: + return n + return None + + # Dispatch Sink. + dispatch_sink = stream.Endpoint(tlp_common_layout(data_width)) + + # Dispatcher + self.dispatcher = Dispatcher( + master = dispatch_sink, + slaves = dispatch_sources.values() + ) + # Ensure DISCARD source is always ready. + self.comb += dispatch_sources["DISCARD"].ready.eq(1) + + # Connect Header Extracter to Dispatch Sink. self.comb += [ - dispatch_source.valid.eq(header_extracter.source.valid), - header_extracter.source.ready.eq(dispatch_source.ready), - dispatch_source.first.eq(header_extracter.source.first), - dispatch_source.last.eq(header_extracter.source.last), - tlp_common_header.decode(header, dispatch_source) + header_extracter.source.connect(dispatch_sink, keep={"valid", "ready", "first", "last"}), + tlp_common_header.decode(header, dispatch_sink) ] self.comb += dword_endianness_swap( src = header_extracter.source.dat, - dst = dispatch_source.dat, + dst = dispatch_sink.dat, data_width = data_width, endianness = endianness, mode = "dat", ) self.comb += dword_endianness_swap( src = header_extracter.source.be, - dst = dispatch_source.be, + dst = dispatch_sink.be, data_width = data_width, endianness = endianness, mode = "be", ) - self.dispatcher = Dispatcher(dispatch_source, dispatch_sinks) - - fmt_type = Cat(dispatch_source.type, dispatch_source.fmt) - self.comb += [ - self.dispatcher.sel.eq(0b00), - # Memory Write/Read. - If((fmt_type == fmt_type_dict["mem_rd32"]) | - (fmt_type == fmt_type_dict["mem_wr32"]), - self.dispatcher.sel.eq(0b01), - ), - # Completion. - If((fmt_type == fmt_type_dict["cpld"]) | - (fmt_type == fmt_type_dict["cpl"]), - self.dispatcher.sel.eq(0b10), - ), - # Configuration. - If((fmt_type == fmt_type_dict["cfg_rd0"]) | - (fmt_type == fmt_type_dict["cfg_wr0"]), - self.dispatcher.sel.eq(0b11), - ), - ] - - # Decode TLP request and format local request ---------------------------------------------- - self.tlp_req = tlp_req = stream.Endpoint(tlp_request_layout(data_width)) - self.comb += dispatch_sinks[0b01].connect(tlp_req) - self.comb += tlp_request_header.decode(header, tlp_req) - req_type = Cat(tlp_req.type, tlp_req.fmt) - self.comb += [ - req_source.valid.eq(tlp_req.valid), - req_source.we.eq(tlp_req.valid & (req_type == fmt_type_dict["mem_wr32"])), - tlp_req.ready.eq(req_source.ready), - req_source.first.eq(tlp_req.first), - req_source.last.eq(tlp_req.last), - req_source.adr.eq(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 ---------------------------------------- - self.tlp_cmp = tlp_cmp = stream.Endpoint(tlp_completion_layout(data_width)) - self.comb += dispatch_sinks[0b10].connect(tlp_cmp) - self.comb += tlp_completion_header.decode(header, tlp_cmp) - - self.comb += [ - cmp_source.valid.eq(tlp_cmp.valid), - tlp_cmp.ready.eq(cmp_source.ready), - cmp_source.first.eq(tlp_cmp.first), - cmp_source.last.eq(tlp_cmp.last), - cmp_source.len.eq(tlp_cmp.length), - cmp_source.end.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) - ] + # Create fmt_type for destination decoding. + fmt_type = Cat(dispatch_sink.type, dispatch_sink.fmt) + # Set default Dispatcher select to DISCARD Sink. + self.comb += self.dispatcher.sel.eq(dispatch_source_sel("DISCARD")) - # Decode TLP configuration and format local configuraiton ---------------------------------- - self.tlp_conf = tlp_conf = stream.Endpoint(tlp_configuration_layout(data_width)) - self.comb += dispatch_sinks[0b11].connect(tlp_conf) - self.comb += tlp_configuration_header.decode(header, tlp_conf) + # Decode/Dispatch TLP Requests ------------------------------------------------------------- - self.comb += [ - conf_source.valid.eq(tlp_conf.valid), - tlp_conf.ready.eq(conf_source.ready), - conf_source.first.eq(tlp_conf.first), - conf_source.last.eq(tlp_conf.last), - conf_source.bus_number.eq(tlp_conf.bus_number), - conf_source.device_no.eq(tlp_conf.device_no), - conf_source.func.eq(tlp_conf.func), - conf_source.ext_reg.eq(tlp_conf.ext_reg), - conf_source.register_no.eq(tlp_conf.register_no), - req_source.dat.eq(tlp_req.dat) - ] + if "REQUEST" in capabilities: + self.comb += [ + If((fmt_type == fmt_type_dict["mem_rd32"]) | + (fmt_type == fmt_type_dict["mem_wr32"]), + self.dispatcher.sel.eq(dispatch_source_sel("REQUEST")), + ) + ] + + self.tlp_req = tlp_req = stream.Endpoint(tlp_request_layout(data_width)) + self.comb += dispatch_sources["REQUEST"].connect(tlp_req) + self.comb += tlp_request_header.decode(header, tlp_req) + + req_type = Cat(tlp_req.type, tlp_req.fmt) + self.comb += [ + req_source.valid.eq(tlp_req.valid), + req_source.we.eq(tlp_req.valid & (req_type == fmt_type_dict["mem_wr32"])), + tlp_req.ready.eq(req_source.ready), + req_source.first.eq(tlp_req.first), + req_source.last.eq(tlp_req.last), + req_source.adr.eq(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/Dispatch TLP Completions ---------------------------------------------------------- + + if "COMPLETION" in capabilities: + self.comb += [ + If((fmt_type == fmt_type_dict["cpld"]) | + (fmt_type == fmt_type_dict["cpl"]), + self.dispatcher.sel.eq(dispatch_source_sel("COMPLETION")), + ) + ] + + self.tlp_cmp = tlp_cmp = stream.Endpoint(tlp_completion_layout(data_width)) + self.comb += dispatch_sources["COMPLETION"].connect(tlp_cmp) + self.comb += tlp_completion_header.decode(header, tlp_cmp) + + self.comb += [ + cmp_source.valid.eq(tlp_cmp.valid), + tlp_cmp.ready.eq(cmp_source.ready), + cmp_source.first.eq(tlp_cmp.first), + cmp_source.last.eq(tlp_cmp.last), + cmp_source.len.eq(tlp_cmp.length), + cmp_source.end.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) + ] + + + # Decode/Dispatch TLP Configurations ------------------------------------------------------- + + if "CONFIGURATION" in capabilities: + self.comb += [ + If((fmt_type == fmt_type_dict["cfg_rd0"]) | + (fmt_type == fmt_type_dict["cfg_wr0"]), + self.dispatcher.sel.eq(dispatch_source_sel("CONFIGURATION")), + ) + ] + + self.tlp_conf = tlp_conf = stream.Endpoint(tlp_configuration_layout(data_width)) + self.comb += dispatch_sources["CONFIGURATION"].connect(tlp_conf) + self.comb += tlp_configuration_header.decode(header, tlp_conf) + + self.comb += [ + conf_source.valid.eq(tlp_conf.valid), + tlp_conf.ready.eq(conf_source.ready), + conf_source.first.eq(tlp_conf.first), + conf_source.last.eq(tlp_conf.last), + conf_source.bus_number.eq(tlp_conf.bus_number), + conf_source.device_no.eq(tlp_conf.device_no), + conf_source.func.eq(tlp_conf.func), + conf_source.ext_reg.eq(tlp_conf.ext_reg), + conf_source.register_no.eq(tlp_conf.register_no), + conf_source.dat.eq(tlp_conf.dat) + ] From 126520ec242adcfe16ad9216eb6659410befa895 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 28 Jul 2023 13:32:12 +0200 Subject: [PATCH 05/14] tlp/common: Cosmetic cleanup. --- litepcie/tlp/common.py | 66 +++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/litepcie/tlp/common.py b/litepcie/tlp/common.py index dcf1073..f0cc1f2 100644 --- a/litepcie/tlp/common.py +++ b/litepcie/tlp/common.py @@ -16,46 +16,46 @@ # Format (fmt) field of different types of TLPs. fmt_dict = { - "mem_rd32": 0b00, # Memory Read Request (32-bit). - "mem_rd64": 0b01, # Memory Read Request (64-bit). - "mem_wr32": 0b10, # Memory Write Request (32-bit). - "mem_wr64": 0b11, # Memory Write Request (64-bit). - "cpld": 0b10, # Completion with Data. - "cpl": 0b00, # Completion without Data. - "cfg_rd0": 0b00, # Configuration Read Request (Type 0). - "cfg_wr0": 0b10, # Configuration Write Request (Type 0). + "mem_rd32" : 0b00, # Memory Read Request (32-bit). + "mem_rd64" : 0b01, # Memory Read Request (64-bit). + "mem_wr32" : 0b10, # Memory Write Request (32-bit). + "mem_wr64" : 0b11, # Memory Write Request (64-bit). + "cpld" : 0b10, # Completion with Data. + "cpl" : 0b00, # Completion without Data. + "cfg_rd0" : 0b00, # Configuration Read Request (Type 0). + "cfg_wr0" : 0b10, # Configuration Write Request (Type 0). } # Type (type) field of different types of TLPs. type_dict = { - "mem_rd32": 0b00000, # Memory Read Request (32-bit). - "mem_rd64": 0b00000, # Memory Read Request (64-bit). - "mem_wr32": 0b00000, # Memory Write Request (32-bit). - "mem_wr64": 0b00000, # Memory Write Request (64-bit). - "cpld": 0b01010, # Completion with Data. - "cpl": 0b01010, # Completion without Data. - "cfg_rd0": 0b00101, # Configuration Read Request (Type 0). - "cfg_wr0": 0b00101, # Configuration Write Request (Type 0). + "mem_rd32" : 0b00000, # Memory Read Request (32-bit). + "mem_rd64" : 0b00000, # Memory Read Request (64-bit). + "mem_wr32" : 0b00000, # Memory Write Request (32-bit). + "mem_wr64" : 0b00000, # Memory Write Request (64-bit). + "cpld" : 0b01010, # Completion with Data. + "cpl" : 0b01010, # Completion without Data. + "cfg_rd0" : 0b00101, # Configuration Read Request (Type 0). + "cfg_wr0" : 0b00101, # Configuration Write Request (Type 0). } # Format and Type fields for different types of TLPs. fmt_type_dict = { - "mem_rd32": 0b00_00000, # Memory Read Request (32-bit). - "mem_rd64": 0b01_00000, # Memory Read Request (64-bit). - "mem_wr32": 0b10_00000, # Memory Write Request (32-bit). - "mem_wr64": 0b11_00000, # Memory Write Request (64-bit). - "cpld": 0b10_01010, # Completion with Data. - "cpl": 0b00_01010, # Completion without Data. - "cfg_rd0": 0b00_00101, # Configuration Read Request (Type 0). - "cfg_wr0": 0b10_00101, # Configuration Write Request (Type 0). + "mem_rd32" : 0b00_00000, # Memory Read Request (32-bit). + "mem_rd64" : 0b01_00000, # Memory Read Request (64-bit). + "mem_wr32" : 0b10_00000, # Memory Write Request (32-bit). + "mem_wr64" : 0b11_00000, # Memory Write Request (64-bit). + "cpld" : 0b10_01010, # Completion with Data. + "cpl" : 0b00_01010, # Completion without Data. + "cfg_rd0" : 0b00_00101, # Configuration Read Request (Type 0). + "cfg_wr0" : 0b10_00101, # Configuration Write Request (Type 0). } # Completion Status (cpl) field of Completion TLPs. cpl_dict = { - "sc": 0b000, # Successful Completion. - "ur": 0b001, # Unsupported Request. - "crs": 0b010, # Configuration Request Retry Status. - "ca": 0b011, # Completer Abort. + "sc" : 0b000, # Successful Completion. + "ur" : 0b001, # Unsupported Request. + "crs" : 0b010, # Configuration Request Retry Status. + "ca" : 0b011, # Completer Abort. } # Headers ------------------------------------------------------------------------------------------ @@ -87,11 +87,11 @@ "tag": HeaderField(byte=1*4, offset= 8, width= 8), # Tag. "first_be": HeaderField(byte=1*4, offset= 0, width= 4), # First Byte Enable. - "bus_number": HeaderField(byte=2*4, offset=24, width=8), # Bus number. - "device_no": HeaderField(byte=2*4, offset=19, width=5), # Device number. - "func": HeaderField(byte=2*4, offset=16, width=3), # Function number. - "ext_reg": HeaderField(byte=2*4, offset= 8, width=3), # Extended Register. - "register_no": HeaderField(byte=2*4, offset= 2, width=6), # Register number. + "bus_number": HeaderField(byte=2*4, offset=24, width= 8), # Bus number. + "device_no": HeaderField(byte=2*4, offset=19, width= 5), # Device number. + "func": HeaderField(byte=2*4, offset=16, width= 3), # Function number. + "ext_reg": HeaderField(byte=2*4, offset= 8, width= 3), # Extended Register. + "register_no": HeaderField(byte=2*4, offset= 2, width= 6), # Register number. } # Define TLP configuration header. tlp_configuration_header = Header( From ebecc3f7229269fc90ffa132717e80859ed72d0b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 28 Jul 2023 15:28:33 +0200 Subject: [PATCH 06/14] tlp/common: Add PTM fmt/type and header definition. --- litepcie/tlp/common.py | 63 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/litepcie/tlp/common.py b/litepcie/tlp/common.py index f0cc1f2..69069a4 100644 --- a/litepcie/tlp/common.py +++ b/litepcie/tlp/common.py @@ -24,6 +24,8 @@ "cpl" : 0b00, # Completion without Data. "cfg_rd0" : 0b00, # Configuration Read Request (Type 0). "cfg_wr0" : 0b10, # Configuration Write Request (Type 0). + "ptm_req" : 0b01, # PTM Request. + "ptm_res" : 0b11, # PTM Response. } # Type (type) field of different types of TLPs. @@ -36,6 +38,8 @@ "cpl" : 0b01010, # Completion without Data. "cfg_rd0" : 0b00101, # Configuration Read Request (Type 0). "cfg_wr0" : 0b00101, # Configuration Write Request (Type 0). + "ptm_req" : 0b10100, # PTM Request. + "ptm_res" : 0b10100, # PTM Response. } # Format and Type fields for different types of TLPs. @@ -48,6 +52,8 @@ "cpl" : 0b00_01010, # Completion without Data. "cfg_rd0" : 0b00_00101, # Configuration Read Request (Type 0). "cfg_wr0" : 0b10_00101, # Configuration Write Request (Type 0). + "ptm_req" : 0b01_10100, # PTM Request. + "ptm_res" : 0b11_10100, # PTM Response. } # Completion Status (cpl) field of Completion TLPs. @@ -154,6 +160,30 @@ swap_field_bytes = False # No byte swapping required. ) +# Length of the TLP PTM header (in bytes). +tlp_ptm_header_length = 8 +# Define TLP request header fields. +tlp_ptm_header_fields = { + "fmt": HeaderField(byte=0*4, offset=29, width= 2), # Format. + "type": HeaderField(byte=0*4, offset=24, width= 5), # Type. + "tc": HeaderField(byte=0*4, offset=20, width= 3), # Traffic Class. + "ln": HeaderField(byte=0*4, offset=17, width= 1), # ?. + "th": HeaderField(byte=0*4, offset=16, width= 1), # ?. + "td": HeaderField(byte=0*4, offset=15, width= 1), # TLP Digest. + "ep": HeaderField(byte=0*4, offset=14, width= 1), # Poisoned TLP. + "attr": HeaderField(byte=0*4, offset=12, width= 2), # Attributes. + "length": HeaderField(byte=0*4, offset= 0, width=10), # Length. + + "requester_id": HeaderField(byte=1*4, offset=16, width=16), # Requester ID. + "message_code": HeaderField(byte=1*4, offset=0, width= 8), # Message Code. +} +# Define TLP PTM header. +tlp_ptm_header = Header( + fields = tlp_ptm_header_fields, + length = tlp_ptm_header_length, + swap_field_bytes = False # No byte swapping required. +) + # Helpers ------------------------------------------------------------------------------------------ def dword_endianness_swap(src, dst, data_width, endianness, mode="dat", ndwords=None): @@ -266,6 +296,39 @@ def tlp_request_layout(data_width): return EndpointDescription(layout) +def tlp_completion_layout(data_width): + """ + Generate a completion TLP endpoint description. + + Parameters: + data_width (int): Width of the data (in bits). + + Returns: + EndpointDescription: Completion TLP endpoint description. + """ + layout = tlp_completion_header.get_layout() + [ + ("dat", data_width), # Data field. + ("be", data_width//8) # Byte Enable field. + ] + return EndpointDescription(layout) + +def tlp_ptm_request_layout(data_width): + """ + Generate a request TLP endpoint description. + + Parameters: + data_width (int): Width of the data (in bits). + + Returns: + EndpointDescription: Request TLP endpoint description. + """ + layout = tlp_request_header.get_layout() + [ + ("dat", data_width), # Data field. + ("be", data_width//8) # Byte Enable field. + ] + return EndpointDescription(layout) + + def tlp_completion_layout(data_width): """ Generate a completion TLP endpoint description. From 8c567cd212c683330fdec7e163703179a4a56225 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 28 Jul 2023 15:31:23 +0200 Subject: [PATCH 07/14] tlp/common: Cosmetic cleanup. --- litepcie/tlp/common.py | 116 ++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/litepcie/tlp/common.py b/litepcie/tlp/common.py index 69069a4..1a479b6 100644 --- a/litepcie/tlp/common.py +++ b/litepcie/tlp/common.py @@ -70,8 +70,8 @@ tlp_common_header_length = 16 # Define TLP common header fields. tlp_common_header_fields = { - "fmt": HeaderField(byte=0*4, offset=29, width=2), # Format. - "type": HeaderField(byte=0*4, offset=24, width=5), # Type. + "fmt" : HeaderField(byte=0*4, offset=29, width=2), # Format. + "type" : HeaderField(byte=0*4, offset=24, width=5), # Type. } # Define TLP common header tlp_common_header = Header( @@ -84,20 +84,20 @@ tlp_configuration_header_length = 16 # Define TLP request header fields. tlp_configuration_header_fields = { - "fmt": HeaderField(byte=0*4, offset=29, width= 2), # Format. - "type": HeaderField(byte=0*4, offset=24, width= 5), # Type. - "td": HeaderField(byte=0*4, offset=15, width= 1), # TLP Digest. - "ep": HeaderField(byte=0*4, offset=14, width= 1), # Poisoned TLP. - - "requester_id": HeaderField(byte=1*4, offset=16, width=16), # Requester ID. - "tag": HeaderField(byte=1*4, offset= 8, width= 8), # Tag. - "first_be": HeaderField(byte=1*4, offset= 0, width= 4), # First Byte Enable. - - "bus_number": HeaderField(byte=2*4, offset=24, width= 8), # Bus number. - "device_no": HeaderField(byte=2*4, offset=19, width= 5), # Device number. - "func": HeaderField(byte=2*4, offset=16, width= 3), # Function number. - "ext_reg": HeaderField(byte=2*4, offset= 8, width= 3), # Extended Register. - "register_no": HeaderField(byte=2*4, offset= 2, width= 6), # Register number. + "fmt" : HeaderField(byte=0*4, offset=29, width= 2), # Format. + "type" : HeaderField(byte=0*4, offset=24, width= 5), # Type. + "td" : HeaderField(byte=0*4, offset=15, width= 1), # TLP Digest. + "ep" : HeaderField(byte=0*4, offset=14, width= 1), # Poisoned TLP. + + "requester_id" : HeaderField(byte=1*4, offset=16, width=16), # Requester ID. + "tag" : HeaderField(byte=1*4, offset= 8, width= 8), # Tag. + "first_be" : HeaderField(byte=1*4, offset= 0, width= 4), # First Byte Enable. + + "bus_number" : HeaderField(byte=2*4, offset=24, width= 8), # Bus number. + "device_no" : HeaderField(byte=2*4, offset=19, width= 5), # Device number. + "func" : HeaderField(byte=2*4, offset=16, width= 3), # Function number. + "ext_reg" : HeaderField(byte=2*4, offset= 8, width= 3), # Extended Register. + "register_no" : HeaderField(byte=2*4, offset= 2, width= 6), # Register number. } # Define TLP configuration header. tlp_configuration_header = Header( @@ -110,20 +110,20 @@ tlp_request_header_length = 16 # Define TLP request header fields. tlp_request_header_fields = { - "fmt": HeaderField(byte=0*4, offset=29, width= 2), # Format. - "type": HeaderField(byte=0*4, offset=24, width= 5), # Type. - "tc": HeaderField(byte=0*4, offset=20, width= 3), # Traffic Class. - "td": HeaderField(byte=0*4, offset=15, width= 1), # TLP Digest. - "ep": HeaderField(byte=0*4, offset=14, width= 1), # Poisoned TLP. - "attr": HeaderField(byte=0*4, offset=12, width= 2), # Attributes. - "length": HeaderField(byte=0*4, offset= 0, width=10), # Length. - - "requester_id": HeaderField(byte=1*4, offset=16, width=16), # Requester ID. - "tag": HeaderField(byte=1*4, offset= 8, width= 8), # Tag. - "last_be": HeaderField(byte=1*4, offset= 4, width= 4), # Last Byte Enable. - "first_be": HeaderField(byte=1*4, offset= 0, width= 4), # First Byte Enable. - - "address": HeaderField(byte=2*4, offset= 0, width=64), # Address. + "fmt" : HeaderField(byte=0*4, offset=29, width= 2), # Format. + "type" : HeaderField(byte=0*4, offset=24, width= 5), # Type. + "tc" : HeaderField(byte=0*4, offset=20, width= 3), # Traffic Class. + "td" : HeaderField(byte=0*4, offset=15, width= 1), # TLP Digest. + "ep" : HeaderField(byte=0*4, offset=14, width= 1), # Poisoned TLP. + "attr" : HeaderField(byte=0*4, offset=12, width= 2), # Attributes. + "length" : HeaderField(byte=0*4, offset= 0, width=10), # Length. + + "requester_id" : HeaderField(byte=1*4, offset=16, width=16), # Requester ID. + "tag" : HeaderField(byte=1*4, offset= 8, width= 8), # Tag. + "last_be" : HeaderField(byte=1*4, offset= 4, width= 4), # Last Byte Enable. + "first_be" : HeaderField(byte=1*4, offset= 0, width= 4), # First Byte Enable. + + "address" : HeaderField(byte=2*4, offset= 0, width=64), # Address. } # Define TLP request header. tlp_request_header = Header( @@ -136,22 +136,22 @@ tlp_completion_header_length = 16 # Define TLP completion header fields. tlp_completion_header_fields = { - "fmt": HeaderField(byte=0*4, offset=29, width= 2), # Format. - "type": HeaderField(byte=0*4, offset=24, width= 5), # Type. - "tc": HeaderField(byte=0*4, offset=20, width= 3), # Traffic Class. - "td": HeaderField(byte=0*4, offset=15, width= 1), # TLP Digest. - "ep": HeaderField(byte=0*4, offset=14, width= 1), # Poisoned TLP. - "attr": HeaderField(byte=0*4, offset=12, width= 2), # Attributes. - "length": HeaderField(byte=0*4, offset= 0, width=10), # Length. - - "completer_id": HeaderField(byte=1*4, offset=16, width=16), # Completer ID. - "status": HeaderField(byte=1*4, offset=13, width= 3), # Completion Status. - "bcm": HeaderField(byte=1*4, offset=12, width= 1), # Byte Count Mismatch. - "byte_count": HeaderField(byte=1*4, offset= 0, width=12), # Byte Count. - - "requester_id": HeaderField(byte=2*4, offset=16, width=16), # Requester ID. - "tag": HeaderField(byte=2*4, offset= 8, width= 8), # Tag. - "lower_address": HeaderField(byte=2*4, offset= 0, width= 7), # Lower Address. + "fmt" : HeaderField(byte=0*4, offset=29, width= 2), # Format. + "type" : HeaderField(byte=0*4, offset=24, width= 5), # Type. + "tc" : HeaderField(byte=0*4, offset=20, width= 3), # Traffic Class. + "td" : HeaderField(byte=0*4, offset=15, width= 1), # TLP Digest. + "ep" : HeaderField(byte=0*4, offset=14, width= 1), # Poisoned TLP. + "attr" : HeaderField(byte=0*4, offset=12, width= 2), # Attributes. + "length" : HeaderField(byte=0*4, offset= 0, width=10), # Length. + + "completer_id" : HeaderField(byte=1*4, offset=16, width=16), # Completer ID. + "status" : HeaderField(byte=1*4, offset=13, width= 3), # Completion Status. + "bcm" : HeaderField(byte=1*4, offset=12, width= 1), # Byte Count Mismatch. + "byte_count" : HeaderField(byte=1*4, offset= 0, width=12), # Byte Count. + + "requester_id" : HeaderField(byte=2*4, offset=16, width=16), # Requester ID. + "tag" : HeaderField(byte=2*4, offset= 8, width= 8), # Tag. + "lower_address" : HeaderField(byte=2*4, offset= 0, width= 7), # Lower Address. } # Define TLP completion header. tlp_completion_header = Header( @@ -164,18 +164,18 @@ tlp_ptm_header_length = 8 # Define TLP request header fields. tlp_ptm_header_fields = { - "fmt": HeaderField(byte=0*4, offset=29, width= 2), # Format. - "type": HeaderField(byte=0*4, offset=24, width= 5), # Type. - "tc": HeaderField(byte=0*4, offset=20, width= 3), # Traffic Class. - "ln": HeaderField(byte=0*4, offset=17, width= 1), # ?. - "th": HeaderField(byte=0*4, offset=16, width= 1), # ?. - "td": HeaderField(byte=0*4, offset=15, width= 1), # TLP Digest. - "ep": HeaderField(byte=0*4, offset=14, width= 1), # Poisoned TLP. - "attr": HeaderField(byte=0*4, offset=12, width= 2), # Attributes. - "length": HeaderField(byte=0*4, offset= 0, width=10), # Length. - - "requester_id": HeaderField(byte=1*4, offset=16, width=16), # Requester ID. - "message_code": HeaderField(byte=1*4, offset=0, width= 8), # Message Code. + "fmt" : HeaderField(byte=0*4, offset=29, width= 2), # Format. + "type" : HeaderField(byte=0*4, offset=24, width= 5), # Type. + "tc" : HeaderField(byte=0*4, offset=20, width= 3), # Traffic Class. + "ln" : HeaderField(byte=0*4, offset=17, width= 1), # ?. + "th" : HeaderField(byte=0*4, offset=16, width= 1), # ?. + "td" : HeaderField(byte=0*4, offset=15, width= 1), # TLP Digest. + "ep" : HeaderField(byte=0*4, offset=14, width= 1), # Poisoned TLP. + "attr" : HeaderField(byte=0*4, offset=12, width= 2), # Attributes. + "length" : HeaderField(byte=0*4, offset= 0, width=10), # Length. + + "requester_id" : HeaderField(byte=1*4, offset=16, width=16), # Requester ID. + "message_code" : HeaderField(byte=1*4, offset=0, width= 8), # Message Code. } # Define TLP PTM header. tlp_ptm_header = Header( From ea40d1ed42d2a7dee67f0d416a8dc8e9da74fce4 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 28 Jul 2023 15:45:07 +0200 Subject: [PATCH 08/14] common: Add ptm_layout (and fix tlp_ptm_layout). --- litepcie/common.py | 15 +++++++++++++++ litepcie/tlp/common.py | 25 ++++--------------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/litepcie/common.py b/litepcie/common.py index 48617ad..61649fd 100644 --- a/litepcie/common.py +++ b/litepcie/common.py @@ -95,6 +95,21 @@ def completion_layout(data_width, address_width=32): ] return EndpointDescription(layout) +def ptm_layout(data_width): + layout = [ + ("requester_id", 16), # Requester ID. + ("length", 16), # Length. + ("message_code", 16), # Message Code. + + # Data Stream. + ("dat", data_width), + + # Internal LitePCIe Routing/Identification. + ("channel", 8), # Crossbar's channel (Used for internal routing). + ] + return EndpointDescription(layout) + + def msi_layout(): return [("dat", 8)] diff --git a/litepcie/tlp/common.py b/litepcie/tlp/common.py index 1a479b6..08cb682 100644 --- a/litepcie/tlp/common.py +++ b/litepcie/tlp/common.py @@ -312,34 +312,17 @@ def tlp_completion_layout(data_width): ] return EndpointDescription(layout) -def tlp_ptm_request_layout(data_width): +def tlp_ptm_layout(data_width): """ - Generate a request TLP endpoint description. - - Parameters: - data_width (int): Width of the data (in bits). - - Returns: - EndpointDescription: Request TLP endpoint description. - """ - layout = tlp_request_header.get_layout() + [ - ("dat", data_width), # Data field. - ("be", data_width//8) # Byte Enable field. - ] - return EndpointDescription(layout) - - -def tlp_completion_layout(data_width): - """ - Generate a completion TLP endpoint description. + Generate a PTM TLP endpoint description. Parameters: data_width (int): Width of the data (in bits). Returns: - EndpointDescription: Completion TLP endpoint description. + EndpointDescription: PTM TLP endpoint description. """ - layout = tlp_completion_header.get_layout() + [ + layout = tlp_ptm_header.get_layout() + [ ("dat", data_width), # Data field. ("be", data_width//8) # Byte Enable field. ] From ee4b2d79af6df8f8fcfaaf915e001443df350a5f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 28 Jul 2023 15:46:43 +0200 Subject: [PATCH 09/14] tlp/depacketizer: Add PTM capability. --- litepcie/tlp/depacketizer.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/litepcie/tlp/depacketizer.py b/litepcie/tlp/depacketizer.py index d2981ac..c6375b2 100644 --- a/litepcie/tlp/depacketizer.py +++ b/litepcie/tlp/depacketizer.py @@ -301,13 +301,15 @@ def __init__(self, data_width, endianness, address_mask=0, capabilities=["REQUES # Source Endpoints. for c in capabilities: - assert c in ["REQUEST", "COMPLETION", "CONFIGURATION"] + assert c in ["REQUEST", "COMPLETION", "CONFIGURATION", "PTM"] if "REQUEST" in capabilities: self.req_source = req_source = stream.Endpoint(request_layout(data_width)) if "COMPLETION" in capabilities: self.cmp_source = cmp_source = stream.Endpoint(completion_layout(data_width)) if "CONFIGURATION" in capabilities: self.conf_source = conf_source = stream.Endpoint(configuration_layout(data_width)) + if "PTM" in capabilities: + self.ptm_source = ptm_source = stream.Endpoint(ptm_layout(data_width)) # # # @@ -459,3 +461,28 @@ def dispatch_source_sel(name): conf_source.register_no.eq(tlp_conf.register_no), conf_source.dat.eq(tlp_conf.dat) ] + + # Decode/Dispatch TLP PTM Requests/Responses ----------------------------------------------- + + if "PTM" in capabilities: + self.comb += [ + If((fmt_type == fmt_type_dict["ptm_req"]) | + (fmt_type == fmt_type_dict["ptm_res"]), + self.dispatcher.sel.eq(dispatch_source_sel("PTM")), + ) + ] + + self.tlp_ptm = tlp_ptm = stream.Endpoint(tlp_ptm_layout(data_width)) + self.comb += dispatch_sources["PTM"].connect(tlp_ptm) + self.comb += tlp_ptm_header.decode(header, tlp_ptm) + + self.comb += [ + ptm_source.valid.eq(tlp_ptm.valid), + tlp_ptm.ready.eq(ptm_source.ready), + ptm_source.first.eq(tlp_ptm.first), + ptm_source.last.eq(tlp_ptm.last), + ptm_source.requester_id.eq(tlp_ptm.requester_id), + ptm_source.length.eq(tlp_ptm.length), + ptm_source.message_code.eq(tlp_ptm.message_code), + ptm_source.dat.eq(tlp_ptm.dat) + ] From 4a6bb5a7e8e6a6fc34f6eeb1aed98d4997250126 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 28 Jul 2023 15:56:03 +0200 Subject: [PATCH 10/14] tlp/depacketizer: Make it more modular and add capabilities parameter. By default, we generally only want Request/Completion TLPs support, but for other specific cases (ex PTM) we also want to handle PTM TLPs. With these change, the module is made more modular to automatically adapt itself to the capabilities provided (and will also allow easily extending capabilities in the future, ex for PTM TLPs). --- litepcie/tlp/packetizer.py | 259 ++++++++++++++++++++----------------- 1 file changed, 137 insertions(+), 122 deletions(-) diff --git a/litepcie/tlp/packetizer.py b/litepcie/tlp/packetizer.py index 5e9e634..13a8287 100644 --- a/litepcie/tlp/packetizer.py +++ b/litepcie/tlp/packetizer.py @@ -763,152 +763,167 @@ def __init__(self, fmt): # LitePCIeTLPPacketizer ---------------------------------------------------------------------------- class LitePCIeTLPPacketizer(LiteXModule): - def __init__(self, data_width, endianness, address_width=32): + def __init__(self, data_width, endianness, address_width=32, capabilities=["REQUEST", "COMPLETION"]): assert data_width%32 == 0 assert address_width in [32, 64] if address_width == 64: assert data_width in [64, 128, 256, 512] - self.req_sink = req_sink = stream.Endpoint(request_layout(data_width, address_width)) - self.cmp_sink = cmp_sink = stream.Endpoint(completion_layout(data_width)) + for c in capabilities: + assert c in ["REQUEST", "COMPLETION"] + # Sink Endpoints. + if "REQUEST" in capabilities: + self.req_sink = req_sink = stream.Endpoint(request_layout(data_width, address_width)) + if "COMPLETION" in capabilities: + self.cmp_sink = cmp_sink = stream.Endpoint(completion_layout(data_width)) + # Source Endpoints. self.source = stream.Endpoint(phy_layout(data_width)) # # # - # Format TLP request and encode it --------------------------------------------------------- - self.tlp_req = tlp_req = stream.Endpoint(tlp_request_layout(data_width)) - self.comb += [ - tlp_req.valid.eq(req_sink.valid), - req_sink.ready.eq(tlp_req.ready), - tlp_req.first.eq(req_sink.first), - tlp_req.last.eq(req_sink.last), - - tlp_req.type.eq(0b00000), - If(req_sink.we, - tlp_req.fmt.eq( fmt_dict[ f"mem_wr32"]), - ).Else( - tlp_req.fmt.eq( fmt_dict[ f"mem_rd32"]), - ), - tlp_req.address.eq(req_sink.adr), - ] - if address_width == 64: + # Format and Encode TLP Requests ----------------------------------------------------------- + + if "REQUEST" in capabilities: + self.tlp_req = tlp_req = stream.Endpoint(tlp_request_layout(data_width)) self.comb += [ - # Use WR64/RD64 only when 64-bit Address's MSB != 0, else use WR32/RD32. - If(req_sink.adr[32:] != 0, - # Address's MSB on DW2, LSB on DW3 with 64-bit addressing: Requires swap due to - # Packetizer's behavior. - tlp_req.address[:32].eq(req_sink.adr[32:]), - tlp_req.address[32:].eq(req_sink.adr[:32]), - If(req_sink.we, - tlp_req.fmt.eq( fmt_dict[ f"mem_wr64"]), - ).Else( - tlp_req.fmt.eq( fmt_dict[ f"mem_rd64"]), - ), - ) + tlp_req.valid.eq(req_sink.valid), + req_sink.ready.eq(tlp_req.ready), + tlp_req.first.eq(req_sink.first), + tlp_req.last.eq(req_sink.last), + + tlp_req.type.eq(0b00000), + If(req_sink.we, + tlp_req.fmt.eq( fmt_dict[ f"mem_wr32"]), + ).Else( + tlp_req.fmt.eq( fmt_dict[ f"mem_rd32"]), + ), + tlp_req.address.eq(req_sink.adr), ] + if address_width == 64: + self.comb += [ + # Use WR64/RD64 only when 64-bit Address's MSB != 0, else use WR32/RD32. + If(req_sink.adr[32:] != 0, + # Address's MSB on DW2, LSB on DW3 with 64-bit addressing: Requires swap due to + # Packetizer's behavior. + tlp_req.address[:32].eq(req_sink.adr[32:]), + tlp_req.address[32:].eq(req_sink.adr[:32]), + If(req_sink.we, + tlp_req.fmt.eq( fmt_dict[ f"mem_wr64"]), + ).Else( + tlp_req.fmt.eq( fmt_dict[ f"mem_rd64"]), + ), + ) + ] - self.comb += [ - 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.dat.eq(req_sink.dat), - If(req_sink.we, - If(req_sink.len == 1, - tlp_req.be.eq(0xf) + self.comb += [ + 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.dat.eq(req_sink.dat), + If(req_sink.we, + If(req_sink.len == 1, + tlp_req.be.eq(0xf) + ).Else( + tlp_req.be.eq(2**(data_width//8)-1) + ) ).Else( - tlp_req.be.eq(2**(data_width//8)-1) + tlp_req.be.eq(0x00) ) - ).Else( - tlp_req.be.eq(0x00) + ] + + tlp_raw_req = stream.Endpoint(tlp_raw_layout(data_width)) + tlp_raw_req_header = Signal(len(tlp_raw_req.header)) + self.comb += [ + tlp_req.connect(tlp_raw_req, omit={*tlp_request_header_fields.keys()}), + tlp_raw_req.fmt.eq(tlp_req.fmt), + tlp_request_header.encode(tlp_req, tlp_raw_req_header), + ] + self.comb += dword_endianness_swap( + src = tlp_raw_req_header, + dst = tlp_raw_req.header, + data_width = data_width, + endianness = endianness, + mode = "dat", + ndwords = 4 ) - ] - tlp_raw_req = stream.Endpoint(tlp_raw_layout(data_width)) - tlp_raw_req_header = Signal(len(tlp_raw_req.header)) - self.comb += [ - tlp_req.connect(tlp_raw_req, omit={*tlp_request_header_fields.keys()}), - tlp_raw_req.fmt.eq(tlp_req.fmt), - tlp_request_header.encode(tlp_req, tlp_raw_req_header), - ] - self.comb += dword_endianness_swap( - src = tlp_raw_req_header, - dst = tlp_raw_req.header, - data_width = data_width, - endianness = endianness, - mode = "dat", - ndwords = 4 - ) + # Format and Encode TLP Completions -------------------------------------------------------- - # Format TLP completion and encode it ------------------------------------------------------ - self.tlp_cmp = tlp_cmp = stream.Endpoint(tlp_completion_layout(data_width)) - self.comb += [ - tlp_cmp.valid.eq(cmp_sink.valid), - cmp_sink.ready.eq(tlp_cmp.ready), - tlp_cmp.first.eq(cmp_sink.first), - tlp_cmp.last.eq(cmp_sink.last), - - 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, - tlp_cmp.type.eq(type_dict["cpl"]), - tlp_cmp.fmt.eq( fmt_dict["cpl"]), - tlp_cmp.status.eq(cpl_dict["ur"]) - ).Else( - tlp_cmp.type.eq(type_dict["cpld"]), - tlp_cmp.fmt.eq( fmt_dict["cpld"]), - tlp_cmp.status.eq(cpl_dict["sc"]) - ), - tlp_cmp.bcm.eq(0), - tlp_cmp.byte_count.eq(cmp_sink.len*4), + if "COMPLETION" in capabilities: + self.tlp_cmp = tlp_cmp = stream.Endpoint(tlp_completion_layout(data_width)) + self.comb += [ + tlp_cmp.valid.eq(cmp_sink.valid), + cmp_sink.ready.eq(tlp_cmp.ready), + tlp_cmp.first.eq(cmp_sink.first), + tlp_cmp.last.eq(cmp_sink.last), + + 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, + tlp_cmp.type.eq(type_dict["cpl"]), + tlp_cmp.fmt.eq( fmt_dict["cpl"]), + tlp_cmp.status.eq(cpl_dict["ur"]) + ).Else( + tlp_cmp.type.eq(type_dict["cpld"]), + tlp_cmp.fmt.eq( fmt_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.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), - If(cmp_sink.last & cmp_sink.first, - tlp_cmp.be.eq(0xf) - ).Else( - tlp_cmp.be.eq(2**(data_width//8)-1) - ), - ] + tlp_cmp.dat.eq(cmp_sink.dat), + If(cmp_sink.last & cmp_sink.first, + tlp_cmp.be.eq(0xf) + ).Else( + tlp_cmp.be.eq(2**(data_width//8)-1) + ), + ] - tlp_raw_cmp = stream.Endpoint(tlp_raw_layout(data_width)) - tlp_raw_cmp_header = Signal(len(tlp_raw_cmp.header)) - self.comb += [ - tlp_cmp.connect(tlp_raw_cmp, omit={*tlp_completion_header_fields.keys()}), - tlp_raw_cmp.fmt.eq(tlp_cmp.fmt), - tlp_completion_header.encode(tlp_cmp, tlp_raw_cmp_header), - ] - self.comb += dword_endianness_swap( - src = tlp_raw_cmp_header, - dst = tlp_raw_cmp.header, - data_width = data_width, - endianness = endianness, - mode = "dat", - ndwords = 4 - ) + tlp_raw_cmp = stream.Endpoint(tlp_raw_layout(data_width)) + tlp_raw_cmp_header = Signal(len(tlp_raw_cmp.header)) + self.comb += [ + tlp_cmp.connect(tlp_raw_cmp, omit={*tlp_completion_header_fields.keys()}), + tlp_raw_cmp.fmt.eq(tlp_cmp.fmt), + tlp_completion_header.encode(tlp_cmp, tlp_raw_cmp_header), + ] + self.comb += dword_endianness_swap( + src = tlp_raw_cmp_header, + dst = tlp_raw_cmp.header, + data_width = data_width, + endianness = endianness, + mode = "dat", + ndwords = 4 + ) # Arbitrate -------------------------------------------------------------------------------- + tlp_raws = [] + if "REQUEST" in capabilities: + tlp_raws.append(tlp_raw_req) + if "COMPLETION" in capabilities: + tlp_raws.append(tlp_raw_cmp) tlp_raw = stream.Endpoint(tlp_raw_layout(data_width)) self.arbitrer = Arbiter( - masters = [tlp_raw_req, tlp_raw_cmp], + masters = tlp_raws, slave = tlp_raw ) From f6fd8d755fea18c137df8f9456f644737c94be42 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 28 Jul 2023 16:10:27 +0200 Subject: [PATCH 11/14] tlp/packetizer: Add PTM capability. --- litepcie/common.py | 2 ++ litepcie/tlp/packetizer.py | 56 +++++++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/litepcie/common.py b/litepcie/common.py index 61649fd..1c02b90 100644 --- a/litepcie/common.py +++ b/litepcie/common.py @@ -97,6 +97,8 @@ def completion_layout(data_width, address_width=32): def ptm_layout(data_width): layout = [ + ("request", 1), # Request. + ("response", 1), # Response. ("requester_id", 16), # Requester ID. ("length", 16), # Length. ("message_code", 16), # Message Code. diff --git a/litepcie/tlp/packetizer.py b/litepcie/tlp/packetizer.py index 13a8287..c106f8c 100644 --- a/litepcie/tlp/packetizer.py +++ b/litepcie/tlp/packetizer.py @@ -769,12 +769,14 @@ def __init__(self, data_width, endianness, address_width=32, capabilities=["REQU if address_width == 64: assert data_width in [64, 128, 256, 512] for c in capabilities: - assert c in ["REQUEST", "COMPLETION"] + assert c in ["REQUEST", "COMPLETION", "PTM"] # Sink Endpoints. if "REQUEST" in capabilities: self.req_sink = req_sink = stream.Endpoint(request_layout(data_width, address_width)) if "COMPLETION" in capabilities: self.cmp_sink = cmp_sink = stream.Endpoint(completion_layout(data_width)) + if "PTM" in capabilities: + self.ptm_sink = ptm_sink = stream.Endpoint(ptm_layout(data_width)) # Source Endpoints. self.source = stream.Endpoint(phy_layout(data_width)) @@ -914,6 +916,56 @@ def __init__(self, data_width, endianness, address_width=32, capabilities=["REQU ndwords = 4 ) + # Format and Encode TLP Completions -------------------------------------------------------- + + if "PTM" in capabilities: + self.tlp_ptm = tlp_ptm = stream.Endpoint(tlp_ptm_layout(data_width)) + self.comb += [ + tlp_ptm.valid.eq(ptm_sink.valid), + ptm_sink.ready.eq(tlp_ptm.ready), + tlp_ptm.first.eq(ptm_sink.first), + tlp_ptm.last.eq(ptm_sink.last), + + tlp_ptm.tc.eq(0), # CHECKME. + tlp_ptm.ln.eq(0), # CHECKME. + tlp_ptm.th.eq(0), # CHECKME. + tlp_ptm.td.eq(0), # CHECKME. + tlp_ptm.ep.eq(0), # CHECKME. + tlp_ptm.attr.eq(0), # CHECKME. + tlp_ptm.length.eq(ptm_sink.length), + + tlp_ptm.requester_id.eq(ptm_sink.requester_id), + tlp_ptm.message_code.eq(ptm_sink.message_code), + + If(ptm_sink.request, + tlp_ptm.type.eq(type_dict["ptm_req"]), + tlp_ptm.fmt.eq( fmt_dict["ptm_req"]), + ), + If(ptm_sink.response, + tlp_ptm.type.eq(type_dict["ptm_res"]), + tlp_ptm.fmt.eq( fmt_dict["ptm_res"]), + ), + + tlp_ptm.dat.eq(ptm_sink.dat), + tlp_ptm.be.eq(2**(data_width//8)-1), # CHECKME. + ] + + tlp_raw_ptm = stream.Endpoint(tlp_raw_layout(data_width)) + tlp_raw_ptm_header = Signal(len(tlp_raw_ptm.header)) + self.comb += [ + tlp_ptm.connect(tlp_raw_ptm, omit={*tlp_ptm_header_fields.keys()}), + tlp_raw_ptm.fmt.eq(tlp_ptm.fmt), + tlp_ptm_header.encode(tlp_ptm, tlp_raw_ptm_header), + ] + self.comb += dword_endianness_swap( + src = tlp_raw_ptm_header, + dst = tlp_raw_ptm.header, + data_width = data_width, + endianness = endianness, + mode = "dat", + ndwords = 4 + ) + # Arbitrate -------------------------------------------------------------------------------- tlp_raws = [] @@ -921,6 +973,8 @@ def __init__(self, data_width, endianness, address_width=32, capabilities=["REQU tlp_raws.append(tlp_raw_req) if "COMPLETION" in capabilities: tlp_raws.append(tlp_raw_cmp) + if "PTM" in capabilities: + tlp_raws.append(tlp_raw_ptm) tlp_raw = stream.Endpoint(tlp_raw_layout(data_width)) self.arbitrer = Arbiter( masters = tlp_raws, From e84afcf0a0b7752166e5e45e3338f6c58c393a19 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 28 Jul 2023 16:27:26 +0200 Subject: [PATCH 12/14] core/endpoint: Add PTM support and with_ptm parameter. --- litepcie/core/endpoint.py | 51 +++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/litepcie/core/endpoint.py b/litepcie/core/endpoint.py index d85816b..e761705 100644 --- a/litepcie/core/endpoint.py +++ b/litepcie/core/endpoint.py @@ -15,17 +15,31 @@ # LitePCIe Endpoint -------------------------------------------------------------------------------- class LitePCIeEndpoint(Module): - def __init__(self, phy, max_pending_requests=4, address_width=32, endianness="big", cmp_bufs_buffered=True): + def __init__(self, phy, max_pending_requests=4, address_width=32, endianness="big", + cmp_bufs_buffered = True, + with_ptm = False, + ): self.phy = phy self.max_pending_requests = max_pending_requests # # # # TLP Packetizer / Depacketizer ------------------------------------------------------------ + if hasattr(phy, "sink") and hasattr(phy, "source"): # Shared Request/Completion channels - depacketizer = LitePCIeTLPDepacketizer(phy.data_width, endianness, phy.bar0_mask) - packetizer = LitePCIeTLPPacketizer(phy.data_width, endianness, address_width) + depacketizer = LitePCIeTLPDepacketizer( + data_width = phy.data_width, + endianness = endianness, + address_mask = phy.bar0_mask, + capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), + ) + packetizer = LitePCIeTLPPacketizer( + data_width = phy.data_width, + endianness = endianness, + address_width = address_width, + capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), + ) self.submodules.depacketizer = depacketizer self.submodules.packetizer = packetizer self.comb += [ @@ -38,10 +52,30 @@ def __init__(self, phy, max_pending_requests=4, address_width=32, endianness="bi cmp_source = depacketizer.cmp_source else: # Separate Request/Completion channels - cmp_depacketizer = LitePCIeTLPDepacketizer(phy.data_width, endianness, phy.bar0_mask) - req_depacketizer = LitePCIeTLPDepacketizer(phy.data_width, endianness, phy.bar0_mask) - cmp_packetizer = LitePCIeTLPPacketizer(phy.data_width, endianness, address_width) - req_packetizer = LitePCIeTLPPacketizer(phy.data_width, endianness, address_width) + cmp_depacketizer = LitePCIeTLPDepacketizer( + data_width = phy.data_width, + endianness = endianness, + address_mask = phy.bar0_mask, + capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), # FIXME: Remove REQUEST?. + ) + req_depacketizer = LitePCIeTLPDepacketizer( + data_width = phy.data_width, + endianness = endianness, + address_mask = phy.bar0_mask, + capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), # FIXME: Remove COMPLETION?. + ) + cmp_packetizer = LitePCIeTLPPacketizer( + data_width = phy.data_width, + endianness = endianness, + address_width = address_width, + capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), # FIXME: Remove REQUEST?. + ) + req_packetizer = LitePCIeTLPPacketizer( + data_width = phy.data_width, + endianness = endianness, + address_width = address_width, + capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), # FIXME: Remove COMPLETION?. + ) self.submodules.cmp_depacketizer = cmp_depacketizer self.submodules.req_depacketizer = req_depacketizer self.submodules.cmp_packetizer = cmp_packetizer @@ -58,6 +92,7 @@ def __init__(self, phy, max_pending_requests=4, address_width=32, endianness="bi cmp_source = cmp_depacketizer.cmp_source # Crossbar --------------------------------------------------------------------------------- + crossbar = LitePCIeCrossbar( data_width = phy.data_width, address_width = address_width, @@ -67,12 +102,14 @@ def __init__(self, phy, max_pending_requests=4, address_width=32, endianness="bi self.submodules.crossbar = crossbar # Slave: HOST initiates the transactions --------------------------------------------------- + self.comb += [ req_source.connect(crossbar.phy_slave.sink), crossbar.phy_slave.source.connect(cmp_sink), ] # Master: FPGA initiates the transactions -------------------------------------------------- + self.comb += [ crossbar.phy_master.source.connect(req_sink), cmp_source.connect(crossbar.phy_master.sink), From 202792dbe642e5421efdfa37bf0ced3dc87ba62a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 28 Jul 2023 16:30:47 +0200 Subject: [PATCH 13/14] core/endpoint: Switch to LiteXModule to simplify code. --- litepcie/core/endpoint.py | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/litepcie/core/endpoint.py b/litepcie/core/endpoint.py index e761705..1109eab 100644 --- a/litepcie/core/endpoint.py +++ b/litepcie/core/endpoint.py @@ -1,11 +1,13 @@ # # This file is part of LitePCIe. # -# Copyright (c) 2015-2022 Florent Kermarrec +# Copyright (c) 2015-2023 Florent Kermarrec # SPDX-License-Identifier: BSD-2-Clause from migen import * +from litex.gen import * + from litex.soc.interconnect.csr import * from litepcie.tlp.depacketizer import LitePCIeTLPDepacketizer @@ -14,7 +16,7 @@ # LitePCIe Endpoint -------------------------------------------------------------------------------- -class LitePCIeEndpoint(Module): +class LitePCIeEndpoint(LiteXModule): def __init__(self, phy, max_pending_requests=4, address_width=32, endianness="big", cmp_bufs_buffered = True, with_ptm = False, @@ -28,20 +30,18 @@ def __init__(self, phy, max_pending_requests=4, address_width=32, endianness="bi if hasattr(phy, "sink") and hasattr(phy, "source"): # Shared Request/Completion channels - depacketizer = LitePCIeTLPDepacketizer( + self.depacketizer = depacketizer = LitePCIeTLPDepacketizer( data_width = phy.data_width, endianness = endianness, address_mask = phy.bar0_mask, capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), ) - packetizer = LitePCIeTLPPacketizer( + self.packetizer = packetizer = LitePCIeTLPPacketizer( data_width = phy.data_width, endianness = endianness, address_width = address_width, capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), ) - self.submodules.depacketizer = depacketizer - self.submodules.packetizer = packetizer self.comb += [ phy.source.connect(depacketizer.sink), packetizer.source.connect(phy.sink) @@ -52,34 +52,30 @@ def __init__(self, phy, max_pending_requests=4, address_width=32, endianness="bi cmp_source = depacketizer.cmp_source else: # Separate Request/Completion channels - cmp_depacketizer = LitePCIeTLPDepacketizer( + self.cmp_depacketizer = cmp_depacketizer = LitePCIeTLPDepacketizer( data_width = phy.data_width, endianness = endianness, address_mask = phy.bar0_mask, capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), # FIXME: Remove REQUEST?. ) - req_depacketizer = LitePCIeTLPDepacketizer( + self.req_depacketizer = req_depacketizer = LitePCIeTLPDepacketizer( data_width = phy.data_width, endianness = endianness, address_mask = phy.bar0_mask, capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), # FIXME: Remove COMPLETION?. ) - cmp_packetizer = LitePCIeTLPPacketizer( + self.cmp_packetizer = cmp_packetizer = LitePCIeTLPPacketizer( data_width = phy.data_width, endianness = endianness, address_width = address_width, capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), # FIXME: Remove REQUEST?. ) - req_packetizer = LitePCIeTLPPacketizer( + self.req_packetizer = req_packetizer = LitePCIeTLPPacketizer( data_width = phy.data_width, endianness = endianness, address_width = address_width, capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), # FIXME: Remove COMPLETION?. ) - self.submodules.cmp_depacketizer = cmp_depacketizer - self.submodules.req_depacketizer = req_depacketizer - self.submodules.cmp_packetizer = cmp_packetizer - self.submodules.req_packetizer = req_packetizer self.comb += [ phy.cmp_source.connect(cmp_depacketizer.sink), phy.req_source.connect(req_depacketizer.sink), @@ -93,13 +89,12 @@ def __init__(self, phy, max_pending_requests=4, address_width=32, endianness="bi # Crossbar --------------------------------------------------------------------------------- - crossbar = LitePCIeCrossbar( + self.crossbar = crossbar = LitePCIeCrossbar( data_width = phy.data_width, address_width = address_width, max_pending_requests = max_pending_requests, - cmp_bufs_buffered = cmp_bufs_buffered + cmp_bufs_buffered = cmp_bufs_buffered, ) - self.submodules.crossbar = crossbar # Slave: HOST initiates the transactions --------------------------------------------------- From 33c52fc2b339464bf89e6b7f5e7f9e6ccfc2e06b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 28 Jul 2023 16:32:34 +0200 Subject: [PATCH 14/14] core/enpoint: Adjust Ultrascale(+) packetizer/depacketizer capabilities now that possible. --- litepcie/core/endpoint.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/litepcie/core/endpoint.py b/litepcie/core/endpoint.py index 1109eab..df70978 100644 --- a/litepcie/core/endpoint.py +++ b/litepcie/core/endpoint.py @@ -56,25 +56,25 @@ def __init__(self, phy, max_pending_requests=4, address_width=32, endianness="bi data_width = phy.data_width, endianness = endianness, address_mask = phy.bar0_mask, - capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), # FIXME: Remove REQUEST?. + capabilities = ["COMPLETION"] + (["PTM"] if with_ptm else []), ) self.req_depacketizer = req_depacketizer = LitePCIeTLPDepacketizer( data_width = phy.data_width, endianness = endianness, address_mask = phy.bar0_mask, - capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), # FIXME: Remove COMPLETION?. + capabilities = ["REQUEST"] + (["PTM"] if with_ptm else []), ) self.cmp_packetizer = cmp_packetizer = LitePCIeTLPPacketizer( data_width = phy.data_width, endianness = endianness, address_width = address_width, - capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), # FIXME: Remove REQUEST?. + capabilities = ["COMPLETION"] + (["PTM"] if with_ptm else []), ) self.req_packetizer = req_packetizer = LitePCIeTLPPacketizer( data_width = phy.data_width, endianness = endianness, address_width = address_width, - capabilities = ["REQUEST", "COMPLETION"] + (["PTM"] if with_ptm else []), # FIXME: Remove COMPLETION?. + capabilities = ["REQUEST"] + (["PTM"] if with_ptm else []), ) self.comb += [ phy.cmp_source.connect(cmp_depacketizer.sink),