I always wanted to write scapy-like framework for PCIE TLP serialization and This is a quick and dirty prototype I wrote at 1 AM. So, Don’t judge me.
The final output of the serializer would be as follows. basically, something similar to scapy or wireshark breakdown of header fields.
name:memwr32 size:96 0000000000000000000000100000000000000000100000001100000001111111100000000000000010010000000000000
name:hdr size:32 000000000000000000000010000000000
name:RESERVED size:1 0
name:FMT size:2 00
name:TYPE size:5 00000
name:RESERVED size:1 0
name:TC size:3 000
name:RESERVED size:4 0000
name:TD size:1 0
name:EP size:1 0
name:ATTR size:2 00
name:AT size:2 00
name:LENGTH size:10 10000000000
name:requestID size:16 0000000100000001
name:BUS size:8 00000001
name:DEVICE size:4 0000
name:FUNCTION size:4 0001
name:TAG size:8 10000000
name:LASTDWBE size:4 1111
name:STDWBE size:4 1111
name:ADDR size:32 00000000000000010010000000000000
The PCIE TLP (Tranaction Layer Packet) header depends on type of transaction: Memory, I/O, Configuration, and Messages. Also, there is routing type which depends on type of transaction:
- Address: used with Memory and IO
- ID: used with configuration
- implicit: used with messages
This the header format for Memory Read 32bit address.
I wanted scalable infrastructure to create difference types of headers. So, I wrote Field
base-class which contains value
attribute
53 class Field:
54 def __init__(self, name, size, value=0x0):
55 self.name = name
56 self.size = size
57 self.value = value
The attribute value
is important because it can work raw int value or parent field containing sub-fields
79 def binary(self):
80 v = ""
81 if type(self.value) is list:
82 for f in self.value:
83 v += f.binary()
84 else:
85 v = f'{self.value:0{self.size}b}'
86 return v
This is the full code for Memory 32bit Address Header.
from enum import Enum
import collections
class Field:
def __init__(self, name, size, value=0x0):
self.name = name
self.size = size
self.value = value
def _printf(self, lvl):
space = lvl * " "
print(f"{space}name:{self.name} size:{self.size} {self.binary()}")
if type(self.value) is list:
for i in self.value:
i._printf(lvl+1)
def printf(self):
self._printf(0)
def binary(self):
v = ""
if type(self.value) is list:
for f in self.value:
v += f.binary()
else:
v = f'{self.value:0{self.size}b}'
return v
def __getattr__(self,name):
for i in self.value:
if i.name == name:
return i
raise AttributeError("can't get attribute")
class TLPHdr(Field):
def __init__(self):
super(TLPHdr, self).__init__("hdr", 4 * 8, value=[])
self.value.append(Field("RESERVED", 1, 0x0))
self.value.append(Field("FMT", 2))
self.value.append(Field("TYPE", 5))
self.value.append(Field("RESERVED", 1, 0x0))
self.value.append(Field("TC", 3))
self.value.append(Field("RESERVED", 4, 0x0))
self.value.append(Field("TD", 1))
self.value.append(Field("EP", 1))
self.value.append(Field("ATTR", 2))
self.value.append(Field("AT", 2))
self.value.append(Field("LENGTH", 10))
class RequestID(Field):
def __init__(self):
super(RequestID, self).__init__("requestID", 2 * 8, value=[])
self.value.append(Field("BUS", 8, 0x0))
self.value.append(Field("DEVICE", 4, 0x0))
self.value.append(Field("FUNCTION", 4, 0x0))
class MemWr32(Field):
def __init__(self, bus, device, function, tag, addr, length):
super(MemWr32, self).__init__("memwr32", 4 * 8 * 3,value=[])
self.value.append(TLPHdr())
self.value.append(RequestID())
self.value.append(Field("TAG", 8))
self.value.append(Field("LASTDWBE", 4))
self.value.append(Field("STDWBE", 4))
self.value.append(Field("ADDR", 32))
self.TAG.value = tag
self.LASTDWBE.value = int ("1111", base=2)
self.STDWBE.value = int ("1111", base=2)
self.ADDR.value = addr
self.hdr.FMT.value = int ("00", base=2)
self.hdr.TYPE.value = int ("00000", base=2)
self.hdr.TC.value = int ("0", base=2)
self.hdr.EP.value = int ("0", base=2)
self.hdr.ATTR.value = int ("0", base=2)
self.hdr.AT.value = int ("0", base=2)
self.hdr.LENGTH.value = int(length/4)
self.requestID.BUS.value = bus
self.requestID.DEVICE.value = device
self.requestID.FUNCTION.value = function
m = MemWr32( bus=1, device=0,function=1, tag=0x80, addr=0x12000, length=4096)
m.printf()