1
0
mirror of https://github.com/corundum/corundum.git synced 2025-01-16 08:12:53 +08:00
corundum/tb/pcie_us.py
2018-10-15 00:05:37 -07:00

1567 lines
60 KiB
Python

"""
Copyright (c) 2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
import math
import struct
from myhdl import *
import axis_ep
from pcie import *
def dword_parity(d):
d ^= d >> 4
d ^= d >> 2
d ^= d >> 1
p = d & 0x1
p |= (d & 0x100) >> 7
p |= (d & 0x10000) >> 14
p |= (d & 0x1000000) >> 21
return p
class TLP_us(TLP):
def __init__(self, tlp=None):
super(TLP_us, self).__init__(tlp)
self.bar_id = 0
self.bar_aperture = 0
self.completer_id_enable = False
self.requester_id_enable = False
self.discontinue = False
if isinstance(tlp, TLP_us):
self.bar_id = tlp.bar_id
self.bar_aperture = tlp.bar_aperture
self.completer_id_enable = tlp.completer_id_enable
self.requester_id_enable = tlp.requester_id_enable
self.discontinue = tlp.discontinue
def pack_us_cq(self, dw):
pkt = axis_ep.AXIStreamFrame([])
if (self.fmt_type == TLP_IO_READ or self.fmt_type == TLP_IO_WRITE or
self.fmt_type == TLP_MEM_READ or self.fmt_type == TLP_MEM_READ_64 or
self.fmt_type == TLP_MEM_WRITE or self.fmt_type == TLP_MEM_WRITE_64):
# Completer Request descriptor
l = self.at & 0x3
l |= self.address & 0xfffffffc
pkt.data.append(l)
l = (self.address & 0xffffffff00000000) >> 32
pkt.data.append(l)
l = self.length & 0x7ff
if self.fmt_type == TLP_MEM_READ or self.fmt_type == TLP_MEM_READ_64:
l |= 0 << 11
elif self.fmt_type == TLP_MEM_WRITE or self.fmt_type == TLP_MEM_WRITE_64:
l |= 1 << 11
elif self.fmt_type == TLP_IO_READ:
l |= 2 << 11
elif self.fmt_type == TLP_IO_WRITE:
l |= 3 << 11
elif self.fmt_type == TLP_FETCH_ADD or self.fmt_type == TLP_FETCH_ADD_64:
l |= 4 << 11
elif self.fmt_type == TLP_SWAP or self.fmt_type == TLP_SWAP_64:
l |= 5 << 11
elif self.fmt_type == TLP_CAS or self.fmt_type == TLP_CAS_64:
l |= 6 << 11
elif self.fmt_type == TLP_MEM_READ_LOCKED or self.fmt_type == TLP_MEM_READ_LOCKED_64:
l |= 7 << 11
l |= int(self.requester_id) << 16
pkt.data.append(l)
l = (self.tag & 0xff)
l |= (self.completer_id.function & 0xff) << 8
l |= (self.bar_id & 0x7) << 16
l |= (self.bar_aperture & 0x3f) << 19
l |= (self.tc & 0x7) << 25
l |= (self.attr & 0x7) << 28
pkt.data.append(l)
# payload data
pkt.data += self.data
# compute byte enables
byte_en = [0]*4
if len(self.data) >= 1:
byte_en += [self.first_be]
if len(self.data) > 2:
byte_en += [0xf] * (len(self.data)-2)
if len(self.data) > 1:
byte_en += [self.last_be]
# compute parity
parity = [dword_parity(d) ^ 0xf for d in pkt.data]
# assemble sideband signal
pkt.user = []
for k in range(0, len(pkt.data), int(dw/32)):
u = 0
for l in range(int(dw/32)):
if k+l < len(byte_en):
u |= byte_en[k+l] << l*4+8
u |= parity[k+l] << l*4+53
else:
u |= 0xf<< l*4+53
if k == 0:
u |= (self.first_be & 0xf)
u |= (self.last_be & 0xf) << 4
u |= 1 << 40 # SOP
# TODO tph
pkt.user.append(u)
# TODO discontinue?
else:
raise Exception("Invalid packet type for interface")
return pkt
def unpack_us_cq(self, pkt, dw, check_parity=False):
req_type = (pkt.data[2] >> 11) & 0xf
if req_type == 0:
self.fmt_type = TLP_MEM_READ
elif req_type == 1:
self.fmt_type = TLP_MEM_WRITE
elif req_type == 2:
self.fmt_type = TLP_IO_READ
elif req_type == 3:
self.fmt_type = TLP_IO_WRITE
elif req_type == 4:
self.fmt_type = TLP_FETCH_ADD
elif req_type == 5:
self.fmt_type = TLP_SWAP
elif req_type == 6:
self.fmt_type = TLP_CAS
elif req_type == 7:
self.fmt_type = TLP_MEM_READ_LOCKED
else:
raise Exception("Invalid packet type")
self.length = pkt.data[2] & 0x7ff
self.requester_id = PcieId.from_int(pkt.data[2] >> 16)
self.tag = pkt.data[3] & 0xff
self.tc = (pkt.data[3] >> 25) & 0x7
self.attr = (pkt.data[3] >> 28) & 0x7
if req_type & 8 == 0:
# memory, IO, or atomic operation
self.at = pkt.data[0] & 3
self.address = (pkt.data[1] << 32) | (pkt.data[0] & 0xfffffffc)
if self.address > 0xffffffff:
if self.fmt == FMT_3DW:
self.fmt = FMT_4DW
elif self.fmt == FMT_3DW_DATA:
self.fmt = FMT_4DW_DATA
self.completer_id = PcieId(0, 0, (pkt.data[3] >> 8) & 0xff)
self.bar_id = (pkt.data[3] >> 16) & 7
self.bar_aperture = (pkt.data[3] >> 19) & 0x3f
self.first_be = pkt.user[0] & 0xf
self.last_be = (pkt.user[0] >> 4) & 0xf
self.data = pkt.data[4:]
# compute byte enables
byte_en = [0]*4
if len(self.data) >= 1:
byte_en += [self.first_be]
if len(self.data) > 2:
byte_en += [0xf] * (len(self.data)-2)
if len(self.data) > 1:
byte_en += [self.last_be]
# compute parity
parity = [dword_parity(d) ^ 0xf for d in pkt.data]
# check sideband components
assert pkt.user[0] & (1 << 40) # SOP
for k in range(0, len(pkt.data), int(dw/32)):
for l in range(int(dw/32)):
if k+l < len(byte_en):
assert (pkt.user[int(k/(dw/32))] >> l*4+8) & 0xf == byte_en[k+l]
if check_parity:
assert (pkt.user[int(k/(dw/32))] >> l*4+53) & 0xf == parity[k+l]
return self
def pack_us_cc(self, dw):
pkt = axis_ep.AXIStreamFrame([])
if (self.fmt_type == TLP_CPL or self.fmt_type == TLP_CPL_DATA or
self.fmt_type == TLP_CPL_LOCKED or self.fmt_type == TLP_CPL_LOCKED_DATA):
# Requester Completion descriptor
l = self.lower_address & 0x7f
l |= (self.at & 3) << 8
l |= (self.byte_count & 0x1fff) << 16
if self.fmt_type == TLP_CPL_LOCKED or self.fmt_type == TLP_CPL_LOCKED_DATA:
# TODO only for completions for locked read requests
l |= 1 << 29
# TODO request completed
pkt.data.append(l)
l = self.length & 0x7ff
l |= (self.status & 0x7) << 11
# TODO poisoned completion
l |= int(self.requester_id) << 16
pkt.data.append(l)
l = (self.tag & 0xff)
l |= int(self.completer_id) << 8
if self.completer_id_enable: l |= 1 << 24
l |= (self.tc & 0x7) << 25
l |= (self.attr & 0x7) << 28
pkt.data.append(l)
# payload data
pkt.data += self.data
# compute parity
parity = [dword_parity(d) ^ 0xf for d in pkt.data]
# assemble sideband signal
pkt.user = []
for k in range(0, len(pkt.data), int(dw/32)):
u = 0
if self.discontinue:
u |= 1
for l in range(int(dw/32)):
if k+l < len(parity):
u |= parity[k+l] << l*4+1
else:
u |= 0xf << l*4+1
pkt.user.append(u)
else:
raise Exception("Invalid packet type for interface")
return pkt
def unpack_us_cc(self, pkt, dw, check_parity=False):
self.fmt_type = TLP_CPL
self.lower_address = pkt.data[0] & 0x7f
self.at = (pkt.data[0] >> 8) & 3
self.byte_count = (pkt.data[0] >> 16) & 0x1fff
if pkt.data[0] & (1 << 29):
self.fmt_type = TLP_CPL_LOCKED
self.length = pkt.data[1] & 0x7ff
if self.length > 0:
self.fmt = FMT_3DW_DATA
self.status = (pkt.data[1] >> 11) & 7
self.requester_id = PcieId.from_int(pkt.data[1] >> 16)
self.completer_id = PcieId.from_int(pkt.data[2] >> 8)
self.completer_id_enable = pkt.data[2] >> 24 & 1 != 0
self.tag = pkt.data[2] & 0xff
self.tc = (pkt.data[2] >> 25) & 0x7
self.attr = (pkt.data[2] >> 28) & 0x7
if self.length > 0:
self.data = pkt.data[3:3+self.length]
# compute parity
parity = [dword_parity(d) ^ 0xf for d in pkt.data]
# check sideband components
for k in range(0, len(pkt.data), int(dw/32)):
if pkt.user[int(k/(dw/32))] & 1:
self.discontinue = True
for l in range(int(dw/32)):
if k+l < len(parity):
if check_parity:
assert (pkt.user[int(k/(dw/32))] >> l*4+1) & 0xf == parity[k+l]
return self
def pack_us_rq(self, dw):
pkt = axis_ep.AXIStreamFrame([])
if (self.fmt_type == TLP_IO_READ or self.fmt_type == TLP_IO_WRITE or
self.fmt_type == TLP_MEM_READ or self.fmt_type == TLP_MEM_READ_64 or
self.fmt_type == TLP_MEM_WRITE or self.fmt_type == TLP_MEM_WRITE_64 or
self.fmt_type == TLP_CFG_READ_0 or self.fmt_type == TLP_CFG_READ_1 or
self.fmt_type == TLP_CFG_WRITE_0 or self.fmt_type == TLP_CFG_WRITE_1):
# Completer Request descriptor
if (self.fmt_type == TLP_IO_READ or self.fmt_type == TLP_IO_WRITE or
self.fmt_type == TLP_MEM_READ or self.fmt_type == TLP_MEM_READ_64 or
self.fmt_type == TLP_MEM_WRITE or self.fmt_type == TLP_MEM_WRITE_64):
l = self.at & 0x3
l |= self.address & 0xfffffffc
pkt.data.append(l)
l = (self.address & 0xffffffff00000000) >> 32
pkt.data.append(l)
elif (self.fmt_type == TLP_CFG_READ_0 or self.fmt_type == TLP_CFG_READ_1 or
self.fmt_type == TLP_CFG_WRITE_0 or self.fmt_type == TLP_CFG_WRITE_1):
l = (self.register_number & 0x3ff) << 2
pkt.data.append(l)
pkt.data.append(0)
l = self.length & 0x7ff
if self.fmt_type == TLP_MEM_READ or self.fmt_type == TLP_MEM_READ_64:
l |= 0 << 11
elif self.fmt_type == TLP_MEM_WRITE or self.fmt_type == TLP_MEM_WRITE_64:
l |= 1 << 11
elif self.fmt_type == TLP_IO_READ:
l |= 2 << 11
elif self.fmt_type == TLP_IO_WRITE:
l |= 3 << 11
elif self.fmt_type == TLP_FETCH_ADD or self.fmt_type == TLP_FETCH_ADD_64:
l |= 4 << 11
elif self.fmt_type == TLP_SWAP or self.fmt_type == TLP_SWAP_64:
l |= 5 << 11
elif self.fmt_type == TLP_CAS or self.fmt_type == TLP_CAS_64:
l |= 6 << 11
elif self.fmt_type == TLP_MEM_READ_LOCKED or self.fmt_type == TLP_MEM_READ_LOCKED_64:
l |= 7 << 11
elif self.fmt_type == TLP_CFG_READ_0:
l |= 8 << 11
elif self.fmt_type == TLP_CFG_READ_1:
l |= 9 << 11
elif self.fmt_type == TLP_CFG_WRITE_0:
l |= 10 << 11
elif self.fmt_type == TLP_CFG_WRITE_1:
l |= 11 << 11
# TODO poisoned
l |= int(self.requester_id) << 16
pkt.data.append(l)
l = (self.tag & 0xff)
l |= int(self.completer_id) << 8
if self.requester_id_enable: l |= 1 << 24
l |= (self.tc & 0x7) << 25
l |= (self.attr & 0x7) << 28
# TODO force ecrc
pkt.data.append(l)
# payload data
pkt.data += self.data
# compute parity
parity = [dword_parity(d) ^ 0xf for d in pkt.data]
# assemble sideband signal
pkt.user = []
for k in range(0, len(pkt.data), int(dw/32)):
u = 0
if self.discontinue:
u |= 1 << 11
for l in range(int(dw/32)):
if k+l < len(parity):
u |= parity[k+l] << l*4+28
else:
u |= 0xf << l*4+28
if k == 0:
u |= (self.first_be & 0xf)
u |= (self.last_be & 0xf) << 4
# TODO seq_num
# TODO tph
# TODO addr_offset
pkt.user.append(u)
else:
raise Exception("Invalid packet type for interface")
return pkt
def unpack_us_rq(self, pkt, dw, check_parity=False):
req_type = (pkt.data[2] >> 11) & 0xf
if req_type == 0:
self.fmt_type = TLP_MEM_READ
elif req_type == 1:
self.fmt_type = TLP_MEM_WRITE
elif req_type == 2:
self.fmt_type = TLP_IO_READ
elif req_type == 3:
self.fmt_type = TLP_IO_WRITE
elif req_type == 4:
self.fmt_type = TLP_FETCH_ADD
elif req_type == 5:
self.fmt_type = TLP_SWAP
elif req_type == 6:
self.fmt_type = TLP_CAS
elif req_type == 7:
self.fmt_type = TLP_MEM_READ_LOCKED
elif req_type == 8:
self.fmt_type = TLP_CFG_READ_0
elif req_type == 9:
self.fmt_type = TLP_CFG_READ_1
elif req_type == 10:
self.fmt_type = TLP_CFG_WRITE_0
elif req_type == 11:
self.fmt_type = TLP_CFG_WRITE_1
else:
raise Exception("Invalid packet type")
self.length = pkt.data[2] & 0x7ff
# TODO poisoned
self.requester_id = PcieId.from_int(pkt.data[2] >> 16)
self.tag = pkt.data[3] & 0xff
self.tc = (pkt.data[3] >> 25) & 0x7
self.attr = (pkt.data[3] >> 28) & 0x7
if req_type < 12:
if req_type < 8:
# memory, IO, or atomic operation
self.at = pkt.data[0] & 3
self.address = (pkt.data[1] << 32) | (pkt.data[0] & 0xfffffffc)
if self.address > 0xffffffff:
if self.fmt == FMT_3DW:
self.fmt = FMT_4DW
elif self.fmt == FMT_3DW_DATA:
self.fmt = FMT_4DW_DATA
else:
self.register_number = (pkt.data[0] >> 2) & 0x3ff
self.completer_id = PcieId.from_int(pkt.data[3] >> 8)
self.requester_id_enable = pkt.data[3] >> 24 & 1 != 0
self.first_be = pkt.user[0] & 0xf
self.last_be = (pkt.user[0] >> 4) & 0xf
self.data = pkt.data[4:]
# compute parity
parity = [dword_parity(d) ^ 0xf for d in pkt.data]
# check sideband components
for k in range(0, len(pkt.data), int(dw/32)):
if pkt.user[int(k/(dw/32))] & (1 << 11):
self.discontinue = True
for l in range(int(dw/32)):
if k+l < len(parity):
if check_parity:
assert (pkt.user[int(k/(dw/32))] >> l*4+28) & 0xf == parity[k+l]
else:
raise Exception("TODO")
return self
def pack_us_rc(self, dw):
pkt = axis_ep.AXIStreamFrame([])
if (self.fmt_type == TLP_CPL or self.fmt_type == TLP_CPL_DATA or
self.fmt_type == TLP_CPL_LOCKED or self.fmt_type == TLP_CPL_LOCKED_DATA):
# Requester Completion descriptor
l = self.lower_address & 0xfff
# TODO error code
l |= (self.byte_count & 0x1fff) << 16
if self.fmt_type == TLP_CPL_LOCKED or self.fmt_type == TLP_CPL_LOCKED_DATA:
l |= 1 << 29
# TODO request completed
pkt.data.append(l)
l = self.length & 0x7ff
l |= (self.status & 0x7) << 11
# TODO poisoned completion
l |= int(self.requester_id) << 16
pkt.data.append(l)
l = (self.tag & 0xff)
l |= int(self.completer_id) << 8
l |= (self.tc & 0x7) << 25
l |= (self.attr & 0x7) << 28
pkt.data.append(l)
# payload data
pkt.data += self.data
# compute byte enables
byte_en = [0]*3
if len(self.data) >= 1:
byte_en += [self.first_be]
if len(self.data) > 2:
byte_en += [0xf] * (len(self.data)-2)
if len(self.data) > 1:
byte_en += [self.last_be]
# compute parity
parity = [dword_parity(d) ^ 0xf for d in pkt.data]
# assemble sideband signal
pkt.user = []
for k in range(0, len(pkt.data), int(dw/32)):
u = 0
for l in range(int(dw/32)):
if k+l < len(byte_en):
u |= byte_en[k+l] << l*4
u |= parity[k+l] << l*4+43
else:
u |= 0xf << l*4+43
if k == 0:
u |= 1 << 32 # is_sof_0
eof = 0
if k+int(dw/32) > len(byte_en):
eof = 1 | ((len(byte_en)-1) % int(dw/32)) << 1
u |= eof << 34 # is_eof_0
# TODO is_sof_1, is_eof_1 (straddle)
pkt.user.append(u)
# TODO discontinue
else:
raise Exception("Invalid packet type for interface")
return pkt
def unpack_us_rc(self, pkt, dw, check_parity=False):
self.fmt_type = TLP_CPL
self.lower_address = pkt.data[0] & 0xfff
# error code
self.byte_count = (pkt.data[0] >> 16) & 0x1fff
if pkt.data[0] & (1 << 29):
self.fmt_type = TLP_CPL_LOCKED
self.length = pkt.data[1] & 0x7ff
if self.length > 0:
self.fmt = FMT_3DW_DATA
self.status = (pkt.data[1] >> 11) & 7
self.requester_id = PcieId.from_int(pkt.data[1] >> 16)
self.completer_id = PcieId.from_int(pkt.data[2] >> 8)
self.tag = pkt.data[2] & 0xff
self.tc = (pkt.data[2] >> 25) & 0x7
self.attr = (pkt.data[2] >> 28) & 0x7
if self.length > 0:
self.data = pkt.data[3:3+self.length]
# compute byte enables
byte_en = [0]*3
if len(self.data) >= 1:
byte_en += [self.first_be]
if len(self.data) > 2:
byte_en += [0xf] * (len(self.data)-2)
if len(self.data) > 1:
byte_en += [self.last_be]
# compute parity
parity = [dword_parity(d) ^ 0xf for d in pkt.data]
# check sideband components
assert pkt.user[0] & (1 << 32) # is_sof_0
for k in range(0, len(pkt.data), int(dw/32)):
for l in range(int(dw/32)):
if k+l < len(byte_en):
assert (pkt.user[int(k/(dw/32))] >> l*4) & 0xf == byte_en[k+l]
if check_parity:
assert (pkt.user[int(k/(dw/32))] >> l*4+43) & 0xf == parity[k+l]
return self
def __eq__(self, other):
if isinstance(other, TLP_us):
return (
self.data == other.data and
self.fmt == other.fmt and
self.type == other.type and
self.tc == other.tc and
self.td == other.td and
self.ep == other.ep and
self.attr == other.attr and
self.at == other.at and
self.length == other.length and
self.completer_id == other.completer_id and
self.status == other.status and
self.bcm == other.bcm and
self.byte_count == other.byte_count and
self.requester_id == other.requester_id and
self.dest_id == other.dest_id and
self.tag == other.tag and
self.first_be == other.first_be and
self.last_be == other.last_be and
self.lower_address == other.lower_address and
self.address == other.address and
self.register_number == other.register_number
)
return False
def __repr__(self):
return (
('TLP_us(data=%s, ' % repr(self.data)) +
('fmt=0x%x, ' % self.fmt) +
('type=0x%x, ' % self.type) +
('tc=0x%x, ' % self.tc) +
('th=0x%x, ' % self.th) +
('td=0x%x, ' % self.td) +
('ep=0x%x, ' % self.ep) +
('attr=0x%x, ' % self.attr) +
('at=0x%x, ' % self.at) +
('length=0x%x, ' % self.length) +
('completer_id=%s, ' % repr(self.completer_id)) +
('status=0x%x, ' % self.status) +
('bcm=0x%x, ' % self.bcm) +
('byte_count=0x%x, ' % self.byte_count) +
('requester_id=%s, ' % repr(self.requester_id)) +
('dest_id=%s, ' % repr(self.dest_id)) +
('tag=0x%x, ' % self.tag) +
('first_be=0x%x, ' % self.first_be) +
('last_be=0x%x, ' % self.last_be) +
('lower_address=0x%x, ' % self.lower_address) +
('address=0x%x, ' % self.address) +
('register_number=0x%x)' % self.register_number)
)
class UltrascalePCIeFunction(Endpoint, MSICapability, MSIXCapability):
def __init__(self):
super(UltrascalePCIeFunction, self).__init__()
self.msi_64bit_address_capable = 1
self.msi_per_vector_mask_capable = 0
self.register_capability(PCIE_CAP_ID, offset=48)
self.register_capability(MSIX_CAP_ID, offset=44)
self.register_capability(PM_CAP_ID, offset=32)
self.register_capability(MSI_CAP_ID, offset=36)
class UltrascalePCIe(Device):
def __init__(self):
super(UltrascalePCIe, self).__init__()
self.has_logic = False
self.default_function = UltrascalePCIeFunction
self.dw = 256
# configuration options
self.pcie_generation = 3
self.pcie_link_width = 8
self.user_clk_frequency = 250e6
self.alignment = "dword"
self.straddle = False
self.enable_pf1 = False
self.enable_client_tag = True
self.enable_extended_tag = False
self.enable_parity = False
self.enable_rx_msg_interface = False
self.enable_sriov = False
self.enable_extended_configuration = False
self.enable_pf0_msi = False
self.enable_pf1_msi = False
self.cq_queue = []
self.cq_np_queue = []
self.cq_np_req_count = 0
self.rc_queue = []
self.msg_queue = []
self.config_space_enable = False
self.cq_source = axis_ep.AXIStreamSource()
self.cc_sink = axis_ep.AXIStreamSink()
self.rq_sink = axis_ep.AXIStreamSink()
self.rc_source = axis_ep.AXIStreamSource()
self.make_function()
def upstream_recv(self, tlp):
# logging
print("[%s] Got downstream TLP: %s" % (highlight(self.get_desc()), repr(tlp)))
if tlp.fmt_type == TLP_CFG_READ_0 or tlp.fmt_type == TLP_CFG_WRITE_0:
# config type 0
if not self.config_space_enable:
print("Configuraion space disabled")
cpl = TLP()
cpl.set_crs_completion(tlp, (self.bus_num, self.device_num, 0))
# logging
print("[%s] CRS Completion: %s" % (highlight(self.get_desc()), repr(cpl)))
yield self.upstream_send(cpl)
return
elif tlp.dest_id.device == self.device_num:
# capture address information
self.bus_num = tlp.dest_id.bus
for f in self.functions:
f.bus_num = self.bus_num
# pass TLP to function
for f in self.functions:
if f.function_num == tlp.dest_id.function:
yield f.upstream_recv(tlp)
return
#raise Exception("Function not found")
print("Function not found")
else:
print("Device number mismatch")
# Unsupported request
cpl = TLP()
cpl.set_ur_completion(tlp, (self.bus_num, self.device_num, 0))
# logging
print("[%s] UR Completion: %s" % (highlight(self.get_desc()), repr(cpl)))
yield self.upstream_send(cpl)
elif (tlp.fmt_type == TLP_CPL or tlp.fmt_type == TLP_CPL_DATA or
tlp.fmt_type == TLP_CPL_LOCKED or tlp.fmt_type == TLP_CPL_LOCKED_DATA):
# Completion
if tlp.requester_id.bus == self.bus_num and tlp.requester_id.device == self.device_num:
for f in self.functions:
if f.function_num == tlp.requester_id.function:
tlp = TLP_us(tlp)
self.rc_queue.append(tlp)
return
print("Function not found")
else:
print("Bus/device number mismatch")
elif (tlp.fmt_type == TLP_IO_READ or tlp.fmt_type == TLP_IO_WRITE):
# IO read/write
for f in self.functions:
bar = f.match_bar(tlp.address, True)
if len(bar) == 1:
tlp = TLP_us(tlp)
tlp.bar_id = bar[0][0]
tlp.bar_aperture = int(math.log2((~self.functions[0].bar_mask[bar[0][0]]&0xffffffff)+1))
tlp.completer_id = PcieId(self.bus_num, self.device_num, f.function_num)
self.cq_queue.append(tlp)
return
print("IO request did not match any BARs")
# Unsupported request
cpl = TLP()
cpl.set_ur_completion(tlp, (self.bus_num, self.device_num, 0))
# logging
print("[%s] UR Completion: %s" % (highlight(self.get_desc()), repr(cpl)))
yield self.upstream_send(cpl)
elif (tlp.fmt_type == TLP_MEM_READ or tlp.fmt_type == TLP_MEM_READ_64 or
tlp.fmt_type == TLP_MEM_WRITE or tlp.fmt_type == TLP_MEM_WRITE_64):
# Memory read/write
for f in self.functions:
bar = f.match_bar(tlp.address)
if len(bar) == 1:
tlp = TLP_us(tlp)
tlp.bar_id = bar[0][0]
if self.functions[0].bar[bar[0][0]] & 4:
tlp.bar_aperture = int(math.log2((~(self.functions[0].bar_mask[bar[0][0]] | (self.functions[0].bar_mask[bar[0][0]+1]<<32))&0xffffffffffffffff)+1))
else:
tlp.bar_aperture = int(math.log2((~self.functions[0].bar_mask[bar[0][0]]&0xffffffff)+1))
tlp.completer_id = PcieId(self.bus_num, self.device_num, f.function_num)
self.cq_queue.append(tlp)
return
print("Memory request did not match any BARs")
if tlp.fmt_type == TLP_MEM_READ or tlp.fmt_type == TLP_MEM_READ_64:
# Unsupported request
cpl = TLP()
cpl.set_ur_completion(tlp, PcieId(self.bus_num, self.device_num, 0))
# logging
print("[%s] UR Completion: %s" % (highlight(self.get_desc()), repr(cpl)))
yield self.upstream_send(cpl)
else:
raise Exception("TODO")
def create_logic(self,
# Completer reQuest Interface
m_axis_cq_tdata=None,
m_axis_cq_tuser=None,
m_axis_cq_tlast=None,
m_axis_cq_tkeep=None,
m_axis_cq_tvalid=None,
m_axis_cq_tready=None,
pcie_cq_np_req=Signal(bool(1)),
pcie_cq_np_req_count=Signal(intbv(0)[6:]),
# Completer Completion Interface
s_axis_cc_tdata=None,
s_axis_cc_tuser=None,
s_axis_cc_tlast=None,
s_axis_cc_tkeep=None,
s_axis_cc_tvalid=None,
s_axis_cc_tready=None,
# Requester reQuest Interface
s_axis_rq_tdata=None,
s_axis_rq_tuser=None,
s_axis_rq_tlast=None,
s_axis_rq_tkeep=None,
s_axis_rq_tvalid=None,
s_axis_rq_tready=None,
pcie_rq_seq_num=Signal(intbv(0)[4:]),
pcie_rq_seq_num_vld=Signal(bool(0)),
pcie_rq_tag=Signal(intbv(0)[6:]),
pcie_rq_tag_av=Signal(intbv(0)[2:]),
pcie_rq_tag_vld=Signal(bool(0)),
# Requester Completion Interface
m_axis_rc_tdata=None,
m_axis_rc_tuser=None,
m_axis_rc_tlast=None,
m_axis_rc_tkeep=None,
m_axis_rc_tvalid=None,
m_axis_rc_tready=None,
# Transmit Flow Control Interface
pcie_tfc_nph_av=Signal(intbv(0)[2:]),
pcie_tfc_npd_av=Signal(intbv(0)[2:]),
# Configuration Management Interface
cfg_mgmt_addr=Signal(intbv(0)[19:]),
cfg_mgmt_write=Signal(bool(0)),
cfg_mgmt_write_data=Signal(intbv(0)[32:]),
cfg_mgmt_byte_enable=Signal(intbv(0)[4:]),
cfg_mgmt_read=Signal(bool(0)),
cfg_mgmt_read_data=Signal(intbv(0)[32:]),
cfg_mgmt_read_write_done=Signal(bool(0)),
cfg_mgmt_type1_cfg_reg_access=Signal(bool(0)),
# Configuration Status Interface
cfg_phy_link_down=Signal(bool(0)),
cfg_phy_link_status=Signal(intbv(0)[2:]),
cfg_negotiated_width=Signal(intbv(0)[4:]),
cfg_current_speed=Signal(intbv(0)[3:]),
cfg_max_payload=Signal(intbv(0)[3:]),
cfg_max_read_req=Signal(intbv(0)[3:]),
cfg_function_status=Signal(intbv(0)[8:]),
cfg_vf_status=Signal(intbv(0)[12:]),
cfg_function_power_state=Signal(intbv(0)[6:]),
cfg_vf_power_state=Signal(intbv(0)[18:]),
cfg_link_power_state=Signal(intbv(0)[2:]),
cfg_err_cor_out=Signal(bool(0)),
cfg_err_nonfatal_out=Signal(bool(0)),
cfg_err_fatal_out=Signal(bool(0)),
cfg_ltr_enable=Signal(bool(0)),
cfg_ltssm_state=Signal(intbv(0)[6:]),
cfg_rcb_status=Signal(intbv(0)[2:]),
cfg_dpa_substate_change=Signal(intbv(0)[2:]),
cfg_obff_enable=Signal(intbv(0)[2:]),
cfg_pl_status_change=Signal(bool(0)),
cfg_tph_requester_enable=Signal(intbv(0)[2:]),
cfg_tph_st_mode=Signal(intbv(0)[6:]),
cfg_vf_tph_requester_enable=Signal(intbv(0)[6:]),
cfg_vf_tph_st_mode=Signal(intbv(0)[18:]),
# Configuration Received Message Interface
cfg_msg_received=Signal(bool(0)),
cfg_msg_received_data=Signal(intbv(0)[8:]),
cfg_msg_received_type=Signal(intbv(0)[5:]),
# Configuration Transmit Message Interface
cfg_msg_transmit=Signal(bool(0)),
cfg_msg_transmit_type=Signal(intbv(0)[3:]),
cfg_msg_transmit_data=Signal(intbv(0)[32:]),
cfg_msg_transmit_done=Signal(bool(0)),
# Configuration Flow Control Interface
cfg_fc_ph=Signal(intbv(0)[8:]),
cfg_fc_pd=Signal(intbv(0)[12:]),
cfg_fc_nph=Signal(intbv(0)[8:]),
cfg_fc_npd=Signal(intbv(0)[12:]),
cfg_fc_cplh=Signal(intbv(0)[8:]),
cfg_fc_cpld=Signal(intbv(0)[12:]),
cfg_fc_sel=Signal(intbv(0)[3:]),
# Per-Function Status Interface
cfg_per_func_status_control=Signal(intbv(0)[3:]),
cfg_per_func_status_data=Signal(intbv(0)[16:]),
# Configuration Control Interface
cfg_hot_reset_in=Signal(bool(0)),
cfg_hot_reset_out=Signal(bool(0)),
cfg_config_space_enable=Signal(bool(1)),
cfg_per_function_update_done=Signal(bool(0)),
cfg_per_function_number=Signal(intbv(0)[3:]),
cfg_per_function_output_request=Signal(bool(0)),
cfg_dsn=Signal(intbv(0)[64:]),
cfg_ds_bus_number=Signal(intbv(0)[8:]),
cfg_ds_device_number=Signal(intbv(0)[5:]),
cfg_ds_function_number=Signal(intbv(0)[3:]),
cfg_power_state_change_ack=Signal(bool(0)),
cfg_power_state_change_interrupt=Signal(bool(0)),
cfg_err_cor_in=Signal(bool(0)),
cfg_err_uncor_in=Signal(bool(0)),
cfg_flr_done=Signal(intbv(0)[2:]),
cfg_vf_flr_done=Signal(intbv(0)[6:]),
cfg_flr_in_process=Signal(intbv(0)[2:]),
cfg_vf_flr_in_process=Signal(intbv(0)[6:]),
cfg_req_pm_transition_l23_ready=Signal(bool(0)),
cfg_link_training_enable=Signal(bool(1)),
# Configuration Interrupt Controller Interface
cfg_interrupt_int=Signal(intbv(0)[4:]),
cfg_interrupt_sent=Signal(bool(0)),
cfg_interrupt_pending=Signal(intbv(0)[2:]),
cfg_interrupt_msi_enable=Signal(intbv(0)[2:]),
cfg_interrupt_msi_vf_enable=Signal(intbv(0)[6:]),
cfg_interrupt_msi_int=Signal(intbv(0)[32:]),
cfg_interrupt_msi_sent=Signal(bool(0)),
cfg_interrupt_msi_fail=Signal(bool(0)),
cfg_interrupt_msi_mmenable=Signal(intbv(0)[6:]),
cfg_interrupt_msi_pending_status=Signal(intbv(0)[64:]),
cfg_interrupt_msi_mask_update=Signal(bool(0)),
cfg_interrupt_msi_select=Signal(intbv(0)[4:]),
cfg_interrupt_msi_data=Signal(intbv(0)[32:]),
cfg_interrupt_msix_enable=Signal(intbv(0)[2:]),
cfg_interrupt_msix_mask=Signal(intbv(0)[2:]),
cfg_interrupt_msix_vf_enable=Signal(intbv(0)[6:]),
cfg_interrupt_msix_vf_mask=Signal(intbv(0)[6:]),
cfg_interrupt_msix_address=Signal(intbv(0)[64:]),
cfg_interrupt_msix_data=Signal(intbv(0)[32:]),
cfg_interrupt_msix_int=Signal(bool(0)),
cfg_interrupt_msix_sent=Signal(bool(0)),
cfg_interrupt_msix_fail=Signal(bool(0)),
cfg_interrupt_msi_attr=Signal(intbv(0)[3:]),
cfg_interrupt_msi_tph_present=Signal(bool(0)),
cfg_interrupt_msi_tph_type=Signal(intbv(0)[2:]),
cfg_interrupt_msi_tph_st_tag=Signal(intbv(0)[9:]),
cfg_interrupt_msi_function_number=Signal(intbv(0)[3:]),
# Configuration Extend Interface
cfg_ext_read_received=Signal(bool(0)),
cfg_ext_write_received=Signal(bool(0)),
cfg_ext_register_number=Signal(intbv(0)[10:]),
cfg_ext_function_number=Signal(intbv(0)[8:]),
cfg_ext_write_data=Signal(intbv(0)[32:]),
cfg_ext_write_byte_enable=Signal(intbv(0)[4:]),
cfg_ext_read_data=Signal(intbv(0)[32:]),
cfg_ext_read_data_valid=Signal(bool(0)),
# Clock and Reset Interface
user_clk=Signal(bool(0)),
user_reset=Signal(bool(0)),
user_lnk_up=Signal(bool(0)),
sys_clk=None,
sys_clk_gt=None,
sys_reset=None,
pcie_perstn0_out=Signal(bool(0)),
pcie_perstn1_in=Signal(bool(0)),
pcie_perstn1_out=Signal(bool(0))
):
# validate parameters and widths
self.dw = len(m_axis_cq_tdata)
assert self.dw in [64, 128, 256]
if self.user_clk_frequency < 1e6:
self.user_clk_frequency *= 1e6
assert self.pcie_generation in [1, 2, 3]
assert self.pcie_link_width in [1, 2, 4, 8]
assert self.user_clk_frequency in [62.5e6, 125e6, 250e6]
assert self.alignment in ["address", "dword"]
self.upstream_port.max_speed = self.pcie_generation
self.upstream_port.max_width = self.pcie_link_width
if self.dw != 256 or self.alignment != "dword":
# straddle only supported with 256-bit, DWORD-aligned interface
assert not self.straddle
# TODO change this when support added
assert self.alignment == 'dword'
assert not self.straddle
if self.pcie_generation == 1:
if self.pcie_link_width in [1, 2]:
assert self.dw == 64
assert self.user_clk_frequency in [62.5e6, 125e6, 250e6]
elif self.pcie_link_width == 4:
assert self.dw == 64
assert self.user_clk_frequency in [125e6, 250e6]
elif self.pcie_link_width == 8:
assert self.dw in [64, 128]
if self.dw == 64:
assert self.user_clk_frequency == 250e6
elif self.dw == 128:
assert self.user_clk_frequency == 125e6
elif self.pcie_generation == 2:
if self.pcie_link_width == 1:
assert self.dw == 64
assert self.user_clk_frequency in [62.5e6, 125e6, 250e6]
elif self.pcie_link_width == 2:
assert self.dw == 64
assert self.user_clk_frequency in [125e6, 250e6]
elif self.pcie_link_width == 4:
assert self.dw in [64, 128]
if self.dw == 64:
assert self.user_clk_frequency == 250e6
elif self.dw == 128:
assert self.user_clk_frequency == 125e6
elif self.pcie_link_width == 8:
assert self.dw in [128, 256]
if self.dw == 128:
assert self.user_clk_frequency == 250e6
elif self.dw == 256:
assert self.user_clk_frequency == 125e6
elif self.pcie_generation == 3:
if self.pcie_link_width == 1:
assert self.dw == 64
assert self.user_clk_frequency in [125e6, 250e6]
elif self.pcie_link_width == 2:
assert self.dw in [64, 128]
if self.dw == 64:
assert self.user_clk_frequency == 250e6
elif self.dw == 128:
assert self.user_clk_frequency == 125e6
elif self.pcie_link_width == 4:
assert self.dw in [128, 256]
if self.dw == 128:
assert self.user_clk_frequency == 250e6
elif self.dw == 256:
assert self.user_clk_frequency == 125e6
elif self.pcie_link_width == 8:
assert self.dw == 256
assert self.user_clk_frequency == 250e6
# Completer reQuest Interface
assert len(m_axis_cq_tdata) == self.dw
assert len(m_axis_cq_tuser) == 85
assert len(m_axis_cq_tlast) == 1
assert len(m_axis_cq_tkeep) == self.dw/32
assert len(m_axis_cq_tvalid) == 1
assert len(m_axis_cq_tready) == 1
assert len(pcie_cq_np_req) == 1
assert len(pcie_cq_np_req_count) == 6
# Completer Completion Interface
assert len(s_axis_cc_tdata) == self.dw
assert len(s_axis_cc_tuser) == 33
assert len(s_axis_cc_tlast) == 1
assert len(s_axis_cc_tkeep) == self.dw/32
assert len(s_axis_cc_tvalid) == 1
assert len(s_axis_cc_tready) == 1
# Requester reQuest Interface
assert len(s_axis_rq_tdata) == self.dw
assert len(s_axis_rq_tuser) == 60
assert len(s_axis_rq_tlast) == 1
assert len(s_axis_rq_tkeep) == self.dw/32
assert len(s_axis_rq_tvalid) == 1
assert len(s_axis_rq_tready) == 1
assert len(pcie_rq_seq_num) == 4
assert len(pcie_rq_seq_num_vld) == 1
assert len(pcie_rq_tag) >= 6
assert len(pcie_rq_tag_av) == 2
assert len(pcie_rq_tag_vld) == 1
# Requester Completion Interface
assert len(m_axis_rc_tdata) == self.dw
assert len(m_axis_rc_tuser) == 75
assert len(m_axis_rc_tlast) == 1
assert len(m_axis_rc_tkeep) == self.dw/32
assert len(m_axis_rc_tvalid) == 1
assert len(m_axis_rc_tready) == 1
# Transmit Flow Control Interface
assert len(pcie_tfc_nph_av) == 2
assert len(pcie_tfc_npd_av) == 2
# Configuration Management Interface
assert len(cfg_mgmt_addr) == 19
assert len(cfg_mgmt_write) == 1
assert len(cfg_mgmt_write_data) == 32
assert len(cfg_mgmt_byte_enable) == 4
assert len(cfg_mgmt_read) == 1
assert len(cfg_mgmt_read_data) == 32
assert len(cfg_mgmt_read_write_done) == 1
assert len(cfg_mgmt_type1_cfg_reg_access) == 1
# Configuration Status Interface
assert len(cfg_phy_link_down) == 1
assert len(cfg_phy_link_status) == 2
assert len(cfg_negotiated_width) == 4
assert len(cfg_current_speed) == 3
assert len(cfg_max_payload) == 3
assert len(cfg_max_read_req) == 3
assert len(cfg_function_status) == 8
assert len(cfg_vf_status) == 12
assert len(cfg_function_power_state) == 6
assert len(cfg_vf_power_state) == 18
assert len(cfg_link_power_state) == 2
assert len(cfg_err_cor_out) == 1
assert len(cfg_err_nonfatal_out) == 1
assert len(cfg_err_fatal_out) == 1
assert len(cfg_ltr_enable) == 1
assert len(cfg_ltssm_state) == 6
assert len(cfg_rcb_status) == 2
assert len(cfg_dpa_substate_change) == 2
assert len(cfg_obff_enable) == 2
assert len(cfg_pl_status_change) == 1
assert len(cfg_tph_requester_enable) == 2
assert len(cfg_tph_st_mode) == 6
assert len(cfg_vf_tph_requester_enable) == 6
assert len(cfg_vf_tph_st_mode) == 18
# Configuration Received Message Interface
assert len(cfg_msg_received) == 1
assert len(cfg_msg_received_data) == 8
assert len(cfg_msg_received_type) == 5
# Configuration Transmit Message Interface
assert len(cfg_msg_transmit) == 1
assert len(cfg_msg_transmit_type) == 3
assert len(cfg_msg_transmit_data) == 32
assert len(cfg_msg_transmit_done) == 1
# Configuration Flow Control Interface
assert len(cfg_fc_ph) == 8
assert len(cfg_fc_pd) == 12
assert len(cfg_fc_nph) == 8
assert len(cfg_fc_npd) == 12
assert len(cfg_fc_cplh) == 8
assert len(cfg_fc_cpld) == 12
assert len(cfg_fc_sel) == 3
# Per-Function Status Interface
assert len(cfg_per_func_status_control) == 3
assert len(cfg_per_func_status_data) == 16
# Configuration Control Interface
assert len(cfg_hot_reset_in) == 1
assert len(cfg_hot_reset_out) == 1
assert len(cfg_config_space_enable) == 1
assert len(cfg_per_function_update_done) == 1
assert len(cfg_per_function_number) == 3
assert len(cfg_per_function_output_request) == 1
assert len(cfg_dsn) == 64
assert len(cfg_ds_bus_number) == 8
assert len(cfg_ds_device_number) == 5
assert len(cfg_ds_function_number) == 3
assert len(cfg_power_state_change_ack) == 1
assert len(cfg_power_state_change_interrupt) == 1
assert len(cfg_err_cor_in) == 1
assert len(cfg_err_uncor_in) == 1
assert len(cfg_flr_done) == 2
assert len(cfg_vf_flr_done) == 6
assert len(cfg_flr_in_process) == 2
assert len(cfg_vf_flr_in_process) == 6
assert len(cfg_req_pm_transition_l23_ready) == 1
assert len(cfg_link_training_enable) == 1
# Configuration Interrupt Controller Interface
assert len(cfg_interrupt_int) == 4
assert len(cfg_interrupt_sent) == 1
assert len(cfg_interrupt_pending) == 2
assert len(cfg_interrupt_msi_enable) == 2
assert len(cfg_interrupt_msi_vf_enable) == 6
assert len(cfg_interrupt_msi_int) == 32
assert len(cfg_interrupt_msi_sent) == 1
assert len(cfg_interrupt_msi_fail) == 1
assert len(cfg_interrupt_msi_mmenable) == 6
assert len(cfg_interrupt_msi_pending_status) == 64
assert len(cfg_interrupt_msi_mask_update) == 1
assert len(cfg_interrupt_msi_select) == 4
assert len(cfg_interrupt_msi_data) == 32
assert len(cfg_interrupt_msix_enable) == 2
assert len(cfg_interrupt_msix_mask) == 2
assert len(cfg_interrupt_msix_vf_enable) == 6
assert len(cfg_interrupt_msix_vf_mask) == 6
assert len(cfg_interrupt_msix_address) == 64
assert len(cfg_interrupt_msix_data) == 32
assert len(cfg_interrupt_msix_int) == 1
assert len(cfg_interrupt_msix_sent) == 1
assert len(cfg_interrupt_msix_fail) == 1
assert len(cfg_interrupt_msi_attr) == 3
assert len(cfg_interrupt_msi_tph_present) == 1
assert len(cfg_interrupt_msi_tph_type) == 2
assert len(cfg_interrupt_msi_tph_st_tag) == 9
assert len(cfg_interrupt_msi_function_number) == 3
# Configuration Extend Interface
assert len(cfg_ext_read_received) == 1
assert len(cfg_ext_write_received) == 1
assert len(cfg_ext_register_number) == 10
assert len(cfg_ext_function_number) == 8
assert len(cfg_ext_write_data) == 32
assert len(cfg_ext_write_byte_enable) == 4
assert len(cfg_ext_read_data) == 32
assert len(cfg_ext_read_data_valid) == 1
# Clock and Reset Interface
assert len(user_clk) == 1
assert len(user_reset) == 1
assert len(user_lnk_up) == 1
assert len(sys_clk) == 1
assert len(sys_clk_gt) == 1
assert len(sys_reset) == 1
assert len(pcie_perstn0_out) == 1
assert len(pcie_perstn1_in) == 1
assert len(pcie_perstn1_out) == 1
assert not self.has_logic
self.has_logic = True
# sources and sinks
cq_source_logic = self.cq_source.create_logic(
user_clk,
user_reset,
tdata=m_axis_cq_tdata,
tuser=m_axis_cq_tuser,
tlast=m_axis_cq_tlast,
tkeep=m_axis_cq_tkeep,
tvalid=m_axis_cq_tvalid,
tready=m_axis_cq_tready,
name='cq_source'
)
cc_sink_logic = self.cc_sink.create_logic(
user_clk,
user_reset,
tdata=s_axis_cc_tdata,
tuser=s_axis_cc_tuser,
tlast=s_axis_cc_tlast,
tkeep=s_axis_cc_tkeep,
tvalid=s_axis_cc_tvalid,
tready=s_axis_cc_tready,
name='cc_sink'
)
rq_sink_logic = self.rq_sink.create_logic(
user_clk,
user_reset,
tdata=s_axis_rq_tdata,
tuser=s_axis_rq_tuser,
tlast=s_axis_rq_tlast,
tkeep=s_axis_rq_tkeep,
tvalid=s_axis_rq_tvalid,
tready=s_axis_rq_tready,
name='rq_sink'
)
rc_source_logic = self.rc_source.create_logic(
user_clk,
user_reset,
tdata=m_axis_rc_tdata,
tuser=m_axis_rc_tuser,
tlast=m_axis_rc_tlast,
tkeep=m_axis_rc_tkeep,
tvalid=m_axis_rc_tvalid,
tready=m_axis_rc_tready,
name='rc_source'
)
if self.user_clk_frequency == 62.5e6:
user_clk_period = 8
elif self.user_clk_frequency == 125e6:
user_clk_period = 4
else:
user_clk_period = 2
@always(delay(user_clk_period))
def clkgen():
user_clk.next = not user_clk
@instance
def reset_logic():
while True:
yield user_clk.posedge, sys_reset.negedge
if not sys_reset:
user_reset.next = 1
yield sys_reset.posedge
yield delay(20)
yield user_clk.posedge
user_reset.next = 0
@always_comb
def comb_logic():
pcie_perstn0_out.next = sys_reset
pcie_perstn1_out.next = pcie_perstn1_in
@instance
def logic():
while True:
yield user_clk.posedge, sys_reset.negedge
if not sys_reset:
self.cq_np_req_count = 0
elif pcie_cq_np_req:
if self.cq_np_req_count < 32:
self.cq_np_req_count += 1
# handle completer requests
# send any queued non-posted requests first
while self.cq_np_queue and self.cq_np_req_count > 0:
tlp = self.cq_np_queue.pop(0)
self.cq_np_req_count -= 1
self.cq_source.send(tlp.pack_us_cq(self.dw))
# handle new requests
while self.cq_queue:
tlp = self.cq_queue.pop(0)
if (tlp.fmt_type == TLP_IO_READ or tlp.fmt_type == TLP_IO_WRITE or
tlp.fmt_type == TLP_MEM_READ or tlp.fmt_type == TLP_MEM_READ_64):
# non-posted request
if self.cq_np_req_count > 0:
# have credit, can forward
self.cq_np_req_count -= 1
self.cq_source.send(tlp.pack_us_cq(self.dw))
else:
# no credits, put it in the queue
self.cq_np_queue.append(tlp)
else:
# posted request
self.cq_source.send(tlp.pack_us_cq(self.dw))
pcie_cq_np_req_count.next = self.cq_np_req_count
# handle completer completions
while not self.cc_sink.empty():
pkt = self.cc_sink.recv()
tlp = TLP_us().unpack_us_cc(pkt, self.dw, self.enable_parity)
if not tlp.completer_id_enable:
tlp.completer_id = PcieId(self.bus_num, self.device_num, tlp.completer_id.function)
if not tlp.discontinue:
yield self.send(TLP(tlp))
# handle requester requests
while not self.rq_sink.empty():
pkt = self.rq_sink.recv()
tlp = TLP_us().unpack_us_rq(pkt, self.dw, self.enable_parity)
if not tlp.requester_id_enable:
tlp.requester_id = PcieId(self.bus_num, self.device_num, tlp.requester_id.function)
if not tlp.discontinue:
if self.functions[tlp.requester_id.function].bus_master_enable:
yield self.send(TLP(tlp))
else:
print("Bus mastering disabled")
# TODO: internal response
# TODO pcie_rq_seq_num
# TODO pcie_rq_tag
# handle requester completions
while self.rc_queue:
tlp = self.rc_queue.pop(0)
self.rc_source.send(tlp.pack_us_rc(self.dw))
# transmit flow control
#pcie_tfc_nph_av
#pcie_tfc_npd_av
# configuration management
if cfg_mgmt_read_write_done:
cfg_mgmt_read_write_done.next = 0
elif cfg_mgmt_read:
if cfg_mgmt_addr & (1 << 18):
# internal register access
pass
else:
# PCI configuration register access
function = (cfg_mgmt_addr >> 10) & 0x7f
reg_num = cfg_mgmt_addr & 0x3ff
cfg_mgmt_read_data.next = self.functions[function].read_config_register(reg_num)
cfg_mgmt_read_write_done.next = 1
elif cfg_mgmt_write:
if cfg_mgmt_addr & (1 << 18):
# internal register access
pass
else:
# PCI configuration register access
function = (cfg_mgmt_addr >> 10) & 0x7f
reg_num = cfg_mgmt_addr & 0x3ff
self.functions[function].write_config_register(reg_num, cfg_mgmt_write_data, cfg_mgmt_byte_enable)
cfg_mgmt_read_write_done.next = 1
#cfg_mgmt_type1_cfg_reg_access
# configuration status
#cfg_phy_link_down
if not sys_reset:
cfg_phy_link_down.next = 1
user_lnk_up.next = 0
else:
cfg_phy_link_down.next = 0 # TODO
user_lnk_up.next = 1 # TODO
#cfg_phy_link_status
cfg_negotiated_width.next = self.functions[0].negotiated_link_width
cfg_current_speed.next = (1 << (self.functions[0].current_link_speed & 3)) >> 1
cfg_max_payload.next = self.functions[0].max_payload_size
cfg_max_read_req.next = self.functions[0].max_read_request_size
status = 0
if self.functions[0].bus_master_enable:
status |= 0x07
if self.functions[0].interrupt_disable:
status |= 0x08
if len(self.functions) > 1:
if self.functions[1].bus_master_enable:
status |= 0x70
if self.functions[1].interrupt_disable:
status |= 0x80
cfg_function_status.next = status
#cfg_vf_status
#cfg_function_power_state
#cfg_vf_power_state
#cfg_link_power_state
#cfg_err_cor_out
#cfg_err_nonfatal_out
#cfg_err_fatal_out
cfg_ltr_enable.next = self.functions[0].ltr_mechanism_enable
#cfg_ltssm_state
status = 0
if self.functions[0].read_completion_boundary:
status |= 1
if len(self.functions) > 1:
if self.functions[0].read_completion_boundary:
status |= 2
cfg_rcb_status.next = status
#cfg_dpa_substate_change
#cfg_obff_enable
#cfg_pl_status_change
#cfg_tph_requester_enable
#cfg_tph_st_mode
#cfg_vf_tph_requester_enable
#cfg_vf_tph_st_mode
# configuration received message
#cfg_msg_received
#cfg_msg_received_data
#cfg_msg_received_type
# configuration transmit message
#cfg_msg_transmit
#cfg_msg_transmit_type
#cfg_msg_transmit_data
#cfg_msg_transmit_done
# configuration flow control
#cfg_fc_ph
#cfg_fc_pd
#cfg_fc_nph
#cfg_fc_npd
#cfg_fc_cplh
#cfg_fc_cpld
#cfg_fc_sel
# per-function status
#cfg_per_func_status_control
#cfg_per_func_status_data
# configuration control
#cfg_hot_reset_in
#cfg_hot_reset_out
if not sys_reset:
self.config_space_enable = False
else:
self.config_space_enable = bool(cfg_config_space_enable)
#cfg_per_function_update_done
#cfg_per_function_number
#cfg_per_function_output_request
#cfg_dsn
#cfg_ds_bus_number
#cfg_ds_device_number
#cfg_ds_function_number
#cfg_power_state_change_ack
#cfg_power_state_change_interrupt
#cfg_err_cor_in
#cfg_err_uncor_in
#cfg_flr_done
#cfg_vf_flr_done
#cfg_flr_in_process
#cfg_vf_flr_in_process
#cfg_req_pm_transition_l23_ready
#cfg_link_training_enable
# configuration interrupt controller
# INTx
#cfg_interrupt_int
#cfg_interrupt_sent
#cfg_interrupt_pending
# MSI
#cfg_interrupt_msi_enable
#cfg_interrupt_msi_vf_enable
#cfg_interrupt_msi_int
#cfg_interrupt_msi_sent
#cfg_interrupt_msi_fail
#cfg_interrupt_msi_mmenable
#cfg_interrupt_msi_pending_status
#cfg_interrupt_msi_mask_update
#cfg_interrupt_msi_select
#cfg_interrupt_msi_data
# MSI-X
#cfg_interrupt_msix_enable
#cfg_interrupt_msix_mask
#cfg_interrupt_msix_vf_enable
#cfg_interrupt_msix_vf_mask
#cfg_interrupt_msix_address
#cfg_interrupt_msix_data
#cfg_interrupt_msix_int
#cfg_interrupt_msix_sent
#cfg_interrupt_msix_fail
# MSI/MSI-X
#cfg_interrupt_msi_attr
#cfg_interrupt_msi_tph_present
#cfg_interrupt_msi_tph_type
#cfg_interrupt_msi_tph_st_tag
#cfg_interrupt_msi_function_number
# configuration extend
#cfg_ext_read_received
#cfg_ext_write_received
#cfg_ext_register_number
#cfg_ext_function_number
#cfg_ext_write_data
#cfg_ext_write_byte_enable
#cfg_ext_read_data
#cfg_ext_read_data_valid
return instances()