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

2794 lines
101 KiB
Python
Raw Normal View History

2018-09-25 19:50:57 -07:00
"""
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 *
from pcie import *
2019-10-01 17:15:15 -07:00
REQ_MEM_READ = 0b0000
REQ_MEM_WRITE = 0b0001
REQ_IO_READ = 0b0010
REQ_IO_WRITE = 0b0011
REQ_MEM_FETCH_ADD = 0b0100
REQ_MEM_SWAP = 0b0101
REQ_MEM_CAS = 0b0110
REQ_MEM_READ_LOCKED = 0b0111
REQ_CFG_READ_0 = 0b1000
REQ_CFG_READ_1 = 0b1001
REQ_CFG_WRITE_0 = 0b1010
REQ_CFG_WRITE_1 = 0b1011
REQ_MSG = 0b1100
REQ_MSG_VENDOR = 0b1101
REQ_MSG_ATS = 0b1110
RC_ERROR_NORMAL_TERMINATION = 0b0000
RC_ERROR_POISONED = 0b0001
RC_ERROR_BAD_STATUS = 0b0010
RC_ERROR_INVALID_LENGTH = 0b0011
RC_ERROR_MISMATCH = 0b0100
RC_ERROR_INVALID_ADDRESS = 0b0101
RC_ERROR_INVALID_TAG = 0b0110
RC_ERROR_TIMEOUT = 0b1001
RC_ERROR_FLR = 0b1000
2018-09-25 19:50:57 -07:00
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
2019-10-12 18:01:39 -07:00
class USPcieFrame(object):
def __init__(self, frame=None):
self.data = []
self.byte_en = []
self.parity = []
self.first_be = 0
self.last_be = 0
self.discontinue = False
self.seq_num = 0
2019-10-12 18:01:39 -07:00
if isinstance(frame, USPcieFrame):
self.data = list(frame.data)
self.byte_en = list(frame.byte_en)
self.parity = list(frame.parity)
self.first_be = frame.first_be
self.last_be = frame.last_be
self.discontinue = frame.discontinue
self.seq_num = frame.seq_num
2019-10-12 18:01:39 -07:00
def update_parity(self):
self.parity = [dword_parity(d) ^ 0xf for d in self.data]
def check_parity(self):
return self.parity == [dword_parity(d) ^ 0xf for d in self.data]
def __eq__(self, other):
if isinstance(other, TLP_us):
return (
self.data == other.data and
self.byte_en == other.byte_en and
self.parity == other.parity and
self.first_be == other.first_be and
self.last_be == other.last_be and
self.discontinue == other.discontinue and
self.seq_num == other.seq_num
2019-10-12 18:01:39 -07:00
)
return False
def __repr__(self):
return (
('USPcieFrame(data=[{}], '.format(', '.join('{:#010x}'.format(x) for x in self.data))) +
('byte_en=[{}], '.format(', '.join(hex(x) for x in self.byte_en))) +
('parity=[{}], '.format(', '.join(hex(x) for x in self.parity))) +
('first_be={:#x}, '.format(self.first_be)) +
('last_be={:#x}, '.format(self.last_be)) +
('discontinue={}, '.format(self.discontinue)) +
('seq_num={})'.format(self.seq_num))
2019-10-12 18:01:39 -07:00
)
2018-09-25 19:50:57 -07:00
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
self.seq_num = 0
2019-10-01 17:17:42 -07:00
self.error_code = RC_ERROR_NORMAL_TERMINATION
2018-09-25 19:50:57 -07:00
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
self.seq_num = tlp.seq_num
2019-10-01 17:17:42 -07:00
self.error_code = tlp.error_code
2018-09-25 19:50:57 -07:00
2019-10-12 18:01:39 -07:00
def pack_us_cq(self):
pkt = USPcieFrame()
2018-09-25 19:50:57 -07:00
2018-09-30 19:14:19 -07:00
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):
2018-09-25 19:50:57 -07:00
# 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
2018-09-30 19:14:19 -07:00
if self.fmt_type == TLP_MEM_READ or self.fmt_type == TLP_MEM_READ_64:
2019-10-01 17:30:09 -07:00
l |= REQ_MEM_READ << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_MEM_WRITE or self.fmt_type == TLP_MEM_WRITE_64:
2019-10-01 17:30:09 -07:00
l |= REQ_MEM_WRITE << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_IO_READ:
2019-10-01 17:30:09 -07:00
l |= REQ_IO_READ << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_IO_WRITE:
2019-10-01 17:30:09 -07:00
l |= REQ_IO_WRITE << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_FETCH_ADD or self.fmt_type == TLP_FETCH_ADD_64:
2019-10-01 17:30:09 -07:00
l |= REQ_MEM_FETCH_ADD << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_SWAP or self.fmt_type == TLP_SWAP_64:
2019-10-01 17:30:09 -07:00
l |= REQ_MEM_SWAP << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_CAS or self.fmt_type == TLP_CAS_64:
2019-10-01 17:30:09 -07:00
l |= REQ_MEM_CAS << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_MEM_READ_LOCKED or self.fmt_type == TLP_MEM_READ_LOCKED_64:
2019-10-01 17:30:09 -07:00
l |= REQ_MEM_READ_LOCKED << 11
2018-10-01 15:41:00 -07:00
l |= int(self.requester_id) << 16
2018-09-25 19:50:57 -07:00
pkt.data.append(l)
l = (self.tag & 0xff)
2018-10-01 15:41:00 -07:00
l |= (self.completer_id.function & 0xff) << 8
2018-09-25 19:50:57 -07:00
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)
2019-10-12 18:01:39 -07:00
pkt.first_be = self.first_be
pkt.last_be = self.last_be
pkt.discontinue = self.discontinue
2018-09-25 19:50:57 -07:00
# payload data
pkt.data += self.data
# compute byte enables
2019-10-12 18:01:39 -07:00
pkt.byte_en = [0]*4
2018-09-25 19:50:57 -07:00
if len(self.data) >= 1:
2019-10-12 18:01:39 -07:00
pkt.byte_en += [self.first_be]
2018-09-25 19:50:57 -07:00
if len(self.data) > 2:
2019-10-12 18:01:39 -07:00
pkt.byte_en += [0xf] * (len(self.data)-2)
2018-09-25 19:50:57 -07:00
if len(self.data) > 1:
2019-10-12 18:01:39 -07:00
pkt.byte_en += [self.last_be]
2018-09-25 19:50:57 -07:00
# compute parity
2019-10-12 18:01:39 -07:00
pkt.update_parity()
2018-09-25 19:50:57 -07:00
else:
raise Exception("Invalid packet type for interface")
return pkt
2019-10-12 18:01:39 -07:00
def unpack_us_cq(self, pkt, check_parity=False):
2018-09-25 19:50:57 -07:00
req_type = (pkt.data[2] >> 11) & 0xf
2019-10-01 17:30:09 -07:00
if req_type == REQ_MEM_READ:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_MEM_READ
2019-10-01 17:30:09 -07:00
elif req_type == REQ_MEM_WRITE:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_MEM_WRITE
2019-10-01 17:30:09 -07:00
elif req_type == REQ_IO_READ:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_IO_READ
2019-10-01 17:30:09 -07:00
elif req_type == REQ_IO_WRITE:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_IO_WRITE
2019-10-01 17:30:09 -07:00
elif req_type == REQ_MEM_FETCH_ADD:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_FETCH_ADD
2019-10-01 17:30:09 -07:00
elif req_type == REQ_MEM_SWAP:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_SWAP
2019-10-01 17:30:09 -07:00
elif req_type == REQ_MEM_CAS:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_CAS
2019-10-01 17:30:09 -07:00
elif req_type == REQ_MEM_READ_LOCKED:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_MEM_READ_LOCKED
2018-09-25 19:50:57 -07:00
else:
raise Exception("Invalid packet type")
self.length = pkt.data[2] & 0x7ff
2018-10-01 15:41:00 -07:00
self.requester_id = PcieId.from_int(pkt.data[2] >> 16)
2018-09-25 19:50:57 -07:00
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
2018-10-01 15:41:00 -07:00
self.completer_id = PcieId(0, 0, (pkt.data[3] >> 8) & 0xff)
2018-09-25 19:50:57 -07:00
self.bar_id = (pkt.data[3] >> 16) & 7
self.bar_aperture = (pkt.data[3] >> 19) & 0x3f
2019-10-12 18:01:39 -07:00
self.first_be = pkt.first_be
self.last_be = pkt.last_be
self.discontinue = pkt.discontinue
2018-09-25 19:50:57 -07:00
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]
2019-10-12 18:01:39 -07:00
# check byte enables
assert byte_en == pkt.byte_en
2018-09-25 19:50:57 -07:00
2019-10-12 18:01:39 -07:00
# check parity
if check_parity:
assert pkt.check_parity()
2018-09-25 19:50:57 -07:00
return self
2019-10-12 18:01:39 -07:00
def pack_us_cc(self):
pkt = USPcieFrame()
2018-09-25 19:50:57 -07:00
2018-09-30 19:14:19 -07:00
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):
2018-09-25 19:50:57 -07:00
# Requester Completion descriptor
l = self.lower_address & 0x7f
l |= (self.at & 3) << 8
l |= (self.byte_count & 0x1fff) << 16
2018-09-30 19:14:19 -07:00
if self.fmt_type == TLP_CPL_LOCKED or self.fmt_type == TLP_CPL_LOCKED_DATA:
2018-09-25 19:50:57 -07:00
# 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
2018-10-01 15:41:00 -07:00
l |= int(self.requester_id) << 16
2018-09-25 19:50:57 -07:00
pkt.data.append(l)
l = (self.tag & 0xff)
2018-10-01 15:41:00 -07:00
l |= int(self.completer_id) << 8
2018-09-25 19:50:57 -07:00
if self.completer_id_enable: l |= 1 << 24
l |= (self.tc & 0x7) << 25
l |= (self.attr & 0x7) << 28
pkt.data.append(l)
2019-10-12 18:01:39 -07:00
pkt.discontinue = self.discontinue
2018-09-25 19:50:57 -07:00
# payload data
pkt.data += self.data
# compute parity
2019-10-12 18:01:39 -07:00
pkt.update_parity()
2018-09-25 19:50:57 -07:00
else:
raise Exception("Invalid packet type for interface")
return pkt
2019-10-12 18:01:39 -07:00
def unpack_us_cc(self, pkt, check_parity=False):
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_CPL
2018-09-25 19:50:57 -07:00
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):
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_CPL_LOCKED
2018-09-25 19:50:57 -07:00
self.length = pkt.data[1] & 0x7ff
if self.length > 0:
self.fmt = FMT_3DW_DATA
self.status = (pkt.data[1] >> 11) & 7
2018-10-01 15:41:00 -07:00
self.requester_id = PcieId.from_int(pkt.data[1] >> 16)
self.completer_id = PcieId.from_int(pkt.data[2] >> 8)
2018-09-25 19:50:57 -07:00
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
2019-10-12 18:01:39 -07:00
self.discontinue = pkt.discontinue
2018-09-25 19:50:57 -07:00
if self.length > 0:
self.data = pkt.data[3:3+self.length]
2019-10-12 18:01:39 -07:00
# check parity
if check_parity:
assert pkt.check_parity()
2018-09-25 19:50:57 -07:00
return self
2019-10-12 18:01:39 -07:00
def pack_us_rq(self):
pkt = USPcieFrame()
2018-09-25 19:50:57 -07:00
2018-09-30 19:14:19 -07:00
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):
2018-09-25 19:50:57 -07:00
# Completer Request descriptor
2018-09-30 19:14:19 -07:00
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):
2018-09-25 19:50:57 -07:00
l = self.at & 0x3
l |= self.address & 0xfffffffc
pkt.data.append(l)
l = (self.address & 0xffffffff00000000) >> 32
pkt.data.append(l)
2018-09-30 19:14:19 -07:00
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):
2018-09-25 19:50:57 -07:00
l = (self.register_number & 0x3ff) << 2
pkt.data.append(l)
pkt.data.append(0)
l = self.length & 0x7ff
2018-09-30 19:14:19 -07:00
if self.fmt_type == TLP_MEM_READ or self.fmt_type == TLP_MEM_READ_64:
2019-10-01 17:24:18 -07:00
l |= REQ_MEM_READ << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_MEM_WRITE or self.fmt_type == TLP_MEM_WRITE_64:
2019-10-01 17:24:18 -07:00
l |= REQ_MEM_WRITE << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_IO_READ:
2019-10-01 17:24:18 -07:00
l |= REQ_IO_READ << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_IO_WRITE:
2019-10-01 17:24:18 -07:00
l |= REQ_IO_WRITE << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_FETCH_ADD or self.fmt_type == TLP_FETCH_ADD_64:
2019-10-01 17:24:18 -07:00
l |= REQ_MEM_FETCH_ADD << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_SWAP or self.fmt_type == TLP_SWAP_64:
2019-10-01 17:24:18 -07:00
l |= REQ_MEM_SWAP << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_CAS or self.fmt_type == TLP_CAS_64:
2019-10-01 17:24:18 -07:00
l |= REQ_MEM_CAS << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_MEM_READ_LOCKED or self.fmt_type == TLP_MEM_READ_LOCKED_64:
2019-10-01 17:24:18 -07:00
l |= REQ_MEM_READ_LOCKED << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_CFG_READ_0:
2019-10-01 17:24:18 -07:00
l |= REQ_CFG_READ_0 << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_CFG_READ_1:
2019-10-01 17:24:18 -07:00
l |= REQ_CFG_READ_1 << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_CFG_WRITE_0:
2019-10-01 17:24:18 -07:00
l |= REQ_CFG_WRITE_0 << 11
2018-09-30 19:14:19 -07:00
elif self.fmt_type == TLP_CFG_WRITE_1:
2019-10-01 17:24:18 -07:00
l |= REQ_CFG_WRITE_1 << 11
2018-09-25 19:50:57 -07:00
# TODO poisoned
2018-10-01 15:41:00 -07:00
l |= int(self.requester_id) << 16
2018-09-25 19:50:57 -07:00
pkt.data.append(l)
l = (self.tag & 0xff)
2018-10-01 15:41:00 -07:00
l |= int(self.completer_id) << 8
2018-09-25 19:50:57 -07:00
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)
2019-10-12 18:01:39 -07:00
pkt.first_be = self.first_be
pkt.last_be = self.last_be
pkt.discontinue = self.discontinue
pkt.seq_num = self.seq_num
2018-09-25 19:50:57 -07:00
# payload data
pkt.data += self.data
# compute parity
2019-10-12 18:01:39 -07:00
pkt.update_parity()
2018-09-25 19:50:57 -07:00
else:
raise Exception("Invalid packet type for interface")
return pkt
2019-10-12 18:01:39 -07:00
def unpack_us_rq(self, pkt, check_parity=False):
2018-09-25 19:50:57 -07:00
req_type = (pkt.data[2] >> 11) & 0xf
2019-10-01 17:24:18 -07:00
if req_type == REQ_MEM_READ:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_MEM_READ
2019-10-01 17:24:18 -07:00
elif req_type == REQ_MEM_WRITE:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_MEM_WRITE
2019-10-01 17:24:18 -07:00
elif req_type == REQ_IO_READ:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_IO_READ
2019-10-01 17:24:18 -07:00
elif req_type == REQ_IO_WRITE:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_IO_WRITE
2019-10-01 17:24:18 -07:00
elif req_type == REQ_MEM_FETCH_ADD:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_FETCH_ADD
2019-10-01 17:24:18 -07:00
elif req_type == REQ_MEM_SWAP:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_SWAP
2019-10-01 17:24:18 -07:00
elif req_type == REQ_MEM_CAS:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_CAS
2019-10-01 17:24:18 -07:00
elif req_type == REQ_MEM_READ_LOCKED:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_MEM_READ_LOCKED
2019-10-01 17:24:18 -07:00
elif req_type == REQ_CFG_READ_0:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_CFG_READ_0
2019-10-01 17:24:18 -07:00
elif req_type == REQ_CFG_READ_1:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_CFG_READ_1
2019-10-01 17:24:18 -07:00
elif req_type == REQ_CFG_WRITE_0:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_CFG_WRITE_0
2019-10-01 17:24:18 -07:00
elif req_type == REQ_CFG_WRITE_1:
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_CFG_WRITE_1
2018-09-25 19:50:57 -07:00
else:
raise Exception("Invalid packet type")
self.length = pkt.data[2] & 0x7ff
# TODO poisoned
2018-10-01 15:41:00 -07:00
self.requester_id = PcieId.from_int(pkt.data[2] >> 16)
2018-09-25 19:50:57 -07:00
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
2018-10-01 15:41:00 -07:00
self.completer_id = PcieId.from_int(pkt.data[3] >> 8)
2018-09-25 19:50:57 -07:00
self.requester_id_enable = pkt.data[3] >> 24 & 1 != 0
2019-10-12 18:01:39 -07:00
self.first_be = pkt.first_be
self.last_be = pkt.last_be
self.discontinue = pkt.discontinue
2018-09-25 19:50:57 -07:00
self.seq_num = pkt.seq_num
2018-09-25 19:50:57 -07:00
self.data = pkt.data[4:]
2019-10-12 18:01:39 -07:00
# check parity
if check_parity:
assert pkt.check_parity()
2018-09-25 19:50:57 -07:00
else:
raise Exception("TODO")
return self
2019-10-12 18:01:39 -07:00
def pack_us_rc(self):
pkt = USPcieFrame()
2018-09-25 19:50:57 -07:00
2018-09-30 19:14:19 -07:00
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):
2018-09-25 19:50:57 -07:00
# Requester Completion descriptor
l = self.lower_address & 0xfff
2019-10-01 17:17:42 -07:00
l |= (self.error_code & 0xf) << 12
2018-09-25 19:50:57 -07:00
l |= (self.byte_count & 0x1fff) << 16
2018-09-30 19:14:19 -07:00
if self.fmt_type == TLP_CPL_LOCKED or self.fmt_type == TLP_CPL_LOCKED_DATA:
2018-09-25 19:50:57 -07:00
l |= 1 << 29
# TODO request completed
pkt.data.append(l)
l = self.length & 0x7ff
l |= (self.status & 0x7) << 11
# TODO poisoned completion
2018-10-01 15:41:00 -07:00
l |= int(self.requester_id) << 16
2018-09-25 19:50:57 -07:00
pkt.data.append(l)
2018-09-28 01:06:36 -07:00
l = (self.tag & 0xff)
2018-10-01 15:41:00 -07:00
l |= int(self.completer_id) << 8
2018-09-25 19:50:57 -07:00
l |= (self.tc & 0x7) << 25
l |= (self.attr & 0x7) << 28
pkt.data.append(l)
2019-10-12 18:01:39 -07:00
pkt.discontinue = self.discontinue
2018-09-25 19:50:57 -07:00
# payload data
pkt.data += self.data
# compute byte enables
2019-10-12 18:01:39 -07:00
pkt.byte_en = [0]*3
2018-09-25 19:50:57 -07:00
2019-10-11 14:16:44 -07:00
first_be = (0xf << (self.lower_address&3)) & 0xf
if self.byte_count+(self.lower_address&3) > self.length*4:
last_be = 0xf
else:
2019-10-12 18:01:39 -07:00
last_be = 0xf >> ((4-self.byte_count-self.lower_address)&3)
2019-10-11 14:16:44 -07:00
if len(self.data) == 1:
first_be = first_be & last_be
last_be = 0
2018-09-25 19:50:57 -07:00
if len(self.data) >= 1:
2019-10-12 18:01:39 -07:00
pkt.byte_en += [first_be]
2018-09-25 19:50:57 -07:00
if len(self.data) > 2:
2019-10-12 18:01:39 -07:00
pkt.byte_en += [0xf] * (len(self.data)-2)
2018-09-25 19:50:57 -07:00
if len(self.data) > 1:
2019-10-12 18:01:39 -07:00
pkt.byte_en += [last_be]
2018-09-25 19:50:57 -07:00
# compute parity
2019-10-12 18:01:39 -07:00
pkt.update_parity()
2018-09-25 19:50:57 -07:00
else:
raise Exception("Invalid packet type for interface")
return pkt
2019-10-12 18:01:39 -07:00
def unpack_us_rc(self, pkt, check_parity=False):
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_CPL
2018-09-25 19:50:57 -07:00
self.lower_address = pkt.data[0] & 0xfff
2019-10-01 17:17:42 -07:00
self.error_code = (pkt.data[0] >> 12) & 0xf
2018-09-25 19:50:57 -07:00
self.byte_count = (pkt.data[0] >> 16) & 0x1fff
if pkt.data[0] & (1 << 29):
2018-09-30 19:14:19 -07:00
self.fmt_type = TLP_CPL_LOCKED
2018-09-25 19:50:57 -07:00
self.length = pkt.data[1] & 0x7ff
if self.length > 0:
self.fmt = FMT_3DW_DATA
self.status = (pkt.data[1] >> 11) & 7
2018-10-01 15:41:00 -07:00
self.requester_id = PcieId.from_int(pkt.data[1] >> 16)
self.completer_id = PcieId.from_int(pkt.data[2] >> 8)
2018-09-25 19:50:57 -07:00
self.tag = pkt.data[2] & 0xff
self.tc = (pkt.data[2] >> 25) & 0x7
self.attr = (pkt.data[2] >> 28) & 0x7
2019-10-12 18:01:39 -07:00
self.discontinue = pkt.discontinue
2018-09-25 19:50:57 -07:00
if self.length > 0:
self.data = pkt.data[3:3+self.length]
# compute byte enables
byte_en = [0]*3
2019-10-11 14:16:44 -07:00
first_be = (0xf << (self.lower_address&3)) & 0xf
if self.byte_count+(self.lower_address&3) > self.length*4:
last_be = 0xf
else:
2019-10-12 18:01:39 -07:00
last_be = 0xf >> ((4-self.byte_count-self.lower_address)&3)
2019-10-11 14:16:44 -07:00
if len(self.data) == 1:
first_be = first_be & last_be
last_be = 0
2018-09-25 19:50:57 -07:00
if len(self.data) >= 1:
2019-10-11 14:16:44 -07:00
byte_en += [first_be]
2018-09-25 19:50:57 -07:00
if len(self.data) > 2:
byte_en += [0xf] * (len(self.data)-2)
if len(self.data) > 1:
2019-10-11 14:16:44 -07:00
byte_en += [last_be]
2018-09-25 19:50:57 -07:00
2019-10-12 18:01:39 -07:00
# check byte enables
assert byte_en == pkt.byte_en
2018-09-25 19:50:57 -07:00
2019-10-12 18:01:39 -07:00
# check parity
if check_parity:
assert pkt.check_parity()
2018-09-25 19:50:57 -07:00
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 (
2019-01-28 18:17:21 -08:00
('TLP_us(data=[%s], ' % ', '.join(hex(x) for x in self.data)) +
2018-09-25 19:50:57 -07:00
('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)
)
2019-10-12 18:01:39 -07:00
class CQSource(object):
def __init__(self):
self.active = False
self.has_logic = False
self.queue = []
def send(self, frame):
self.queue.append(USPcieFrame(frame))
def count(self):
return len(self.queue)
def empty(self):
return not self.queue
def create_logic(self,
clk,
rst,
tdata=None,
tkeep=Signal(bool(True)),
tvalid=Signal(bool(False)),
tready=Signal(bool(True)),
tlast=Signal(bool(False)),
tuser=Signal(intbv(0)),
pause=0,
name=None
):
assert len(tdata) in [64, 128, 256, 512]
2019-10-12 18:01:39 -07:00
assert len(tkeep)*32 == len(tdata)
if len(tdata) == 512:
assert len(tuser) == 183
else:
assert len(tdata) in [64, 128, 256]
assert len(tuser) in [85, 88]
2019-10-12 18:01:39 -07:00
assert not self.has_logic
self.has_logic = True
@instance
def logic():
frame = USPcieFrame()
data = []
byte_en = []
parity = []
self.active = False
first = True
while True:
yield clk.posedge, rst.posedge
if rst:
data = []
byte_en = []
parity = []
self.active = False
tdata.next = 0
tkeep.next = 0
tuser.next = 0
tvalid.next = False
tlast.next = False
first = True
else:
tvalid.next = self.active and (tvalid or not pause)
if tready and tvalid:
tvalid.next = False
self.active = False
if not data and self.queue:
frame = self.queue.pop(0)
data = list(frame.data)
byte_en = list(frame.byte_en)
parity = list(frame.parity)
if name is not None:
print("[%s] Sending frame %s" % (name, repr(frame)))
first = True
if data and not self.active:
d = 0
k = 0
u = 0
if len(tdata) == 512:
if first:
u |= (frame.first_be & 0xf)
u |= (frame.last_be & 0xf) << 8
u |= 0b01 << 80 # is_sop
u |= 0b00 << 82 # is_sop0_ptr
if frame.discontinue:
u |= 1 << 96 # discontinue
last_lane = 0
for i in range(len(tkeep)):
if data:
d |= data.pop(0) << i*32
k |= 1 << i
u |= byte_en.pop(0) << i*4+16
u |= parity.pop(0) << i*4+119
last_lane = i
else:
u |= 0xf << i*4+119
if not data:
u |= 0b01 << 86 # is_eop
u |= (last_lane & 0xf) << 88 # is_eop0_ptr
else:
if first:
u |= (frame.first_be & 0xf)
u |= (frame.last_be & 0xf) << 4
u |= 1 << 40 # sop
if frame.discontinue:
u |= 1 << 41 # discontinue
for i in range(len(tkeep)):
if data:
d |= data.pop(0) << i*32
k |= 1 << i
u |= byte_en.pop(0) << i*4+8
u |= parity.pop(0) << i*4+53
else:
u |= 0xf << i*4+53
2019-10-12 18:01:39 -07:00
tdata.next = d
tkeep.next = k
tuser.next = u
tvalid.next = not pause
tlast.next = len(data) == 0
self.active = True
first = False
return instances()
class CQSink(object):
def __init__(self):
self.has_logic = False
self.queue = []
self.read_queue = []
self.sync = Signal(intbv(0))
def recv(self):
if self.queue:
return self.queue.pop(0)
return None
def count(self):
return len(self.queue)
def empty(self):
return not self.queue
def wait(self, timeout=0):
if self.queue:
return
if timeout:
yield self.sync, delay(timeout)
else:
yield self.sync
def create_logic(self,
clk,
rst,
tdata=None,
tkeep=Signal(bool(True)),
tvalid=Signal(bool(False)),
tready=Signal(bool(True)),
tlast=Signal(bool(True)),
tuser=Signal(intbv(0)),
pause=0,
name=None
):
assert len(tdata) in [64, 128, 256, 512]
2019-10-12 18:01:39 -07:00
assert len(tkeep)*32 == len(tdata)
if len(tdata) == 512:
assert len(tuser) == 183
else:
assert len(tdata) in [64, 128, 256]
assert len(tuser) in [85, 88]
2019-10-12 18:01:39 -07:00
assert not self.has_logic
self.has_logic = True
tready_int = Signal(bool(False))
tvalid_int = Signal(bool(False))
@always_comb
def pause_logic():
tready.next = tready_int and not pause
tvalid_int.next = tvalid and not pause
@instance
def logic():
frame = USPcieFrame()
first = True
while True:
yield clk.posedge, rst.posedge
if rst:
tready_int.next = False
frame = USPcieFrame()
first = True
else:
tready_int.next = True
if tvalid_int:
# zero tkeep not allowed
assert int(tkeep) != 0
# tkeep must be contiguous
# i.e. 0b00011110 allowed, but 0b00011010 not allowed
b = int(tkeep)
while b & 1 == 0:
b = b >> 1
while b & 1 == 1:
b = b >> 1
assert b == 0
# tkeep must not have gaps across cycles
if not first:
# not first cycle; lowest bit must be set
assert int(tkeep) & 1
if not tlast:
# not last cycle; highest bit must be set
assert int(tkeep) & (1 << len(tkeep)-1)
d = int(tdata)
u = int(tuser)
if len(tdata) == 512:
if first:
frame.first_be = u & 0xf
frame.last_be = (u >> 8) & 0xf
if tuser & (1 << 96):
frame.discontinue = True
last_lane = 0
2019-10-12 18:01:39 -07:00
for i in range(len(tkeep)):
if tkeep & (1 << i):
frame.data.append((d >> (i*32)) & 0xffffffff)
frame.byte_en.append((u >> (i*4+16)) & 0xf)
frame.parity.append((u >> (i*4+119)) & 0xf)
last_lane = i
else:
if first:
frame.first_be = u & 0xf
frame.last_be = (u >> 4) & 0xf
2019-10-12 18:01:39 -07:00
if tuser & (1 << 41):
frame.discontinue = True
for i in range(len(tkeep)):
if tkeep & (1 << i):
frame.data.append((d >> (i*32)) & 0xffffffff)
frame.byte_en.append((u >> (i*4+8)) & 0xf)
frame.parity.append((u >> (i*4+53)) & 0xf)
2019-10-12 18:01:39 -07:00
first = False
if tlast:
self.queue.append(frame)
self.sync.next = not self.sync
if name is not None:
print("[%s] Got frame %s" % (name, repr(frame)))
frame = USPcieFrame()
first = True
return instances()
class CCSource(object):
def __init__(self):
self.active = False
self.has_logic = False
self.queue = []
def send(self, frame):
self.queue.append(USPcieFrame(frame))
def count(self):
return len(self.queue)
def empty(self):
return not self.queue
def create_logic(self,
clk,
rst,
tdata=None,
tkeep=Signal(bool(True)),
tvalid=Signal(bool(False)),
tready=Signal(bool(True)),
tlast=Signal(bool(False)),
tuser=Signal(intbv(0)),
pause=0,
name=None
):
assert len(tdata) in [64, 128, 256, 512]
2019-10-12 18:01:39 -07:00
assert len(tkeep)*32 == len(tdata)
if len(tdata) == 512:
assert len(tuser) == 81
else:
assert len(tdata) in [64, 128, 256]
assert len(tuser) == 33
2019-10-12 18:01:39 -07:00
assert not self.has_logic
self.has_logic = True
@instance
def logic():
frame = USPcieFrame()
data = []
parity = []
self.active = False
first = True
while True:
yield clk.posedge, rst.posedge
if rst:
data = []
parity = []
self.active = False
tdata.next = 0
tkeep.next = 0
tuser.next = 0
tvalid.next = False
tlast.next = False
first = True
else:
tvalid.next = self.active and (tvalid or not pause)
if tready and tvalid:
tvalid.next = False
self.active = False
if not data and self.queue:
frame = self.queue.pop(0)
data = list(frame.data)
parity = list(frame.parity)
if name is not None:
print("[%s] Sending frame %s" % (name, repr(frame)))
first = True
if data and not self.active:
d = 0
k = 0
u = 0
if len(tdata) == 512:
if first:
u |= 0b01 << 0 # is_sop
u |= 0b00 << 2 # is_sop0_ptr
if frame.discontinue:
u |= 1 << 16 # discontinue
last_lane = 0
for i in range(len(tkeep)):
if data:
d |= data.pop(0) << i*32
k |= 1 << i
u |= parity.pop(0) << i*4+17
last_lane = i
else:
u |= 0xf << i*4+17
if not data:
u |= 0b01 << 6 # is_eop
u |= (last_lane & 0xf) << 8 # is_eop0_ptr
else:
if frame.discontinue:
u |= 1 # discontinue
for i in range(len(tkeep)):
if data:
d |= data.pop(0) << i*32
k |= 1 << i
u |= parity.pop(0) << i*4+1
else:
u |= 0xf << i*4+1
2019-10-12 18:01:39 -07:00
tdata.next = d
tkeep.next = k
tuser.next = u
tvalid.next = not pause
tlast.next = len(data) == 0
self.active = True
first = False
return instances()
class CCSink(object):
def __init__(self):
self.has_logic = False
self.queue = []
self.read_queue = []
self.sync = Signal(intbv(0))
def recv(self):
if self.queue:
return self.queue.pop(0)
return None
def count(self):
return len(self.queue)
def empty(self):
return not self.queue
def wait(self, timeout=0):
if self.queue:
return
if timeout:
yield self.sync, delay(timeout)
else:
yield self.sync
def create_logic(self,
clk,
rst,
tdata=None,
tkeep=Signal(bool(True)),
tvalid=Signal(bool(False)),
tready=Signal(bool(True)),
tlast=Signal(bool(True)),
tuser=Signal(intbv(0)),
pause=0,
name=None
):
assert len(tdata) in [64, 128, 256, 512]
2019-10-12 18:01:39 -07:00
assert len(tkeep)*32 == len(tdata)
if len(tdata) == 512:
assert len(tuser) == 81
else:
assert len(tdata) in [64, 128, 256]
assert len(tuser) == 33
2019-10-12 18:01:39 -07:00
assert not self.has_logic
self.has_logic = True
tready_int = Signal(bool(False))
tvalid_int = Signal(bool(False))
@always_comb
def pause_logic():
tready.next = tready_int and not pause
tvalid_int.next = tvalid and not pause
@instance
def logic():
frame = USPcieFrame()
first = True
while True:
yield clk.posedge, rst.posedge
if rst:
tready_int.next = False
frame = USPcieFrame()
first = True
else:
tready_int.next = True
if tvalid_int:
# zero tkeep not allowed
assert int(tkeep) != 0
# tkeep must be contiguous
# i.e. 0b00011110 allowed, but 0b00011010 not allowed
b = int(tkeep)
while b & 1 == 0:
b = b >> 1
while b & 1 == 1:
b = b >> 1
assert b == 0
# tkeep must not have gaps across cycles
if not first:
# not first cycle; lowest bit must be set
assert int(tkeep) & 1
if not tlast:
# not last cycle; highest bit must be set
assert int(tkeep) & (1 << len(tkeep)-1)
d = int(tdata)
u = int(tuser)
if len(tdata) == 512:
if u & (1 << 16):
frame.discontinue = True
last_lane = 0
2019-10-12 18:01:39 -07:00
for i in range(len(tkeep)):
if tkeep & (1 << i):
frame.data.append((d >> (i*32)) & 0xffffffff)
frame.parity.append((u >> (i*4+17)) & 0xf)
last_lane = i
else:
if u & 1:
frame.discontinue = True
for i in range(len(tkeep)):
if tkeep & (1 << i):
frame.data.append((d >> (i*32)) & 0xffffffff)
frame.parity.append((u >> (i*4+1)) & 0xf)
2019-10-12 18:01:39 -07:00
first = False
if tlast:
self.queue.append(frame)
self.sync.next = not self.sync
if name is not None:
print("[%s] Got frame %s" % (name, repr(frame)))
frame = USPcieFrame()
first = True
return instances()
class RQSource(object):
def __init__(self):
self.active = False
self.has_logic = False
self.queue = []
def send(self, frame):
self.queue.append(USPcieFrame(frame))
def count(self):
return len(self.queue)
def empty(self):
return not self.queue
def create_logic(self,
clk,
rst,
tdata=None,
tkeep=Signal(bool(True)),
tvalid=Signal(bool(False)),
tready=Signal(bool(True)),
tlast=Signal(bool(False)),
tuser=Signal(intbv(0)),
pause=0,
name=None
):
assert len(tdata) in [64, 128, 256, 512]
2019-10-12 18:01:39 -07:00
assert len(tkeep)*32 == len(tdata)
if len(tdata) == 512:
assert len(tuser) == 137
else:
assert len(tdata) in [64, 128, 256]
assert len(tuser) in [60, 62]
2019-10-12 18:01:39 -07:00
assert not self.has_logic
self.has_logic = True
@instance
def logic():
frame = USPcieFrame()
data = []
parity = []
self.active = False
first = True
while True:
yield clk.posedge, rst.posedge
if rst:
data = []
parity = []
self.active = False
tdata.next = 0
tkeep.next = 0
tuser.next = 0
tvalid.next = False
tlast.next = False
first = True
else:
tvalid.next = self.active and (tvalid or not pause)
if tready and tvalid:
tvalid.next = False
self.active = False
if not data and self.queue:
frame = self.queue.pop(0)
data = list(frame.data)
parity = list(frame.parity)
if name is not None:
print("[%s] Sending frame %s" % (name, repr(frame)))
first = True
if data and not self.active:
d = 0
k = 0
u = 0
if len(tdata) == 512:
if first:
u |= (frame.first_be & 0xf)
u |= (frame.last_be & 0xf) << 8
u |= 0b01 << 20 # is_sop
u |= 0b00 << 22 # is_sop0_ptr
if frame.discontinue:
2019-11-23 00:20:21 -08:00
u |= 1 << 36 # discontinue
u |= (frame.seq_num & 0x3f) << 61
last_lane = 0
for i in range(len(tkeep)):
if data:
d |= data.pop(0) << i*32
k |= 1 << i
u |= parity.pop(0) << i*4+73
last_lane = i
else:
u |= 0xf << i*4+73
if not data:
u |= 0b01 << 26 # is_eop
u |= (last_lane & 0xf) << 28 # is_eop0_ptr
else:
if first:
u |= (frame.first_be & 0xf)
u |= (frame.last_be & 0xf) << 4
if frame.discontinue:
2019-11-23 00:20:21 -08:00
u |= 1 << 11 # discontinue
u |= (frame.seq_num & 0xf) << 24
if len(tuser) == 62:
u |= ((frame.seq_num >> 4) & 0x3) << 60
for i in range(len(tkeep)):
if data:
d |= data.pop(0) << i*32
k |= 1 << i
u |= parity.pop(0) << i*4+28
else:
u |= 0xf << i*4+28
2019-10-12 18:01:39 -07:00
# TODO seq_num
# TODO tph
tdata.next = d
tkeep.next = k
tuser.next = u
tvalid.next = not pause
tlast.next = len(data) == 0
self.active = True
first = False
return instances()
class RQSink(object):
def __init__(self):
self.has_logic = False
self.queue = []
self.read_queue = []
self.sync = Signal(intbv(0))
def recv(self):
if self.queue:
return self.queue.pop(0)
return None
def count(self):
return len(self.queue)
def empty(self):
return not self.queue
def wait(self, timeout=0):
if self.queue:
return
if timeout:
yield self.sync, delay(timeout)
else:
yield self.sync
def create_logic(self,
clk,
rst,
tdata=None,
tkeep=Signal(bool(True)),
tvalid=Signal(bool(False)),
tready=Signal(bool(True)),
tlast=Signal(bool(True)),
tuser=Signal(intbv(0)),
pause=0,
name=None
):
assert len(tdata) in [64, 128, 256, 512]
2019-10-12 18:01:39 -07:00
assert len(tkeep)*32 == len(tdata)
if len(tdata) == 512:
assert len(tuser) == 137
else:
assert len(tdata) in [64, 128, 256]
assert len(tuser) in [60, 62]
2019-10-12 18:01:39 -07:00
assert not self.has_logic
self.has_logic = True
tready_int = Signal(bool(False))
tvalid_int = Signal(bool(False))
@always_comb
def pause_logic():
tready.next = tready_int and not pause
tvalid_int.next = tvalid and not pause
@instance
def logic():
frame = USPcieFrame()
first = True
while True:
yield clk.posedge, rst.posedge
if rst:
tready_int.next = False
frame = USPcieFrame()
first = True
else:
tready_int.next = True
if tvalid_int:
# zero tkeep not allowed
assert int(tkeep) != 0
# tkeep must be contiguous
# i.e. 0b00011110 allowed, but 0b00011010 not allowed
b = int(tkeep)
while b & 1 == 0:
b = b >> 1
while b & 1 == 1:
b = b >> 1
assert b == 0
# tkeep must not have gaps across cycles
if not first:
# not first cycle; lowest bit must be set
assert int(tkeep) & 1
if not tlast:
# not last cycle; highest bit must be set
assert int(tkeep) & (1 << len(tkeep)-1)
d = int(tdata)
u = int(tuser)
if len(tdata) == 512:
if first:
frame.first_be = u & 0xf
frame.last_be = (u >> 8) & 0xf
if u & (1 << 36):
frame.discontinue = True
frame.seq_num = (u >> 61) & 0x3f
last_lane = 0
2019-10-12 18:01:39 -07:00
for i in range(len(tkeep)):
if tkeep & (1 << i):
frame.data.append((d >> (i*32)) & 0xffffffff)
frame.parity.append((u >> (i*4+73)) & 0xf)
last_lane = i
else:
if first:
frame.first_be = u & 0xf
frame.last_be = (u >> 4) & 0xf
2019-10-12 18:01:39 -07:00
if u & (1 << 11):
frame.discontinue = True
frame.seq_num = (u >> 24) & 0xf
if len(tuser) == 62:
frame.seq_num |= ((u >> 60) & 0x3) << 4
for i in range(len(tkeep)):
if tkeep & (1 << i):
frame.data.append((d >> (i*32)) & 0xffffffff)
frame.parity.append((u >> (i*4+28)) & 0xf)
2019-10-12 18:01:39 -07:00
first = False
if tlast:
self.queue.append(frame)
self.sync.next = not self.sync
if name is not None:
print("[%s] Got frame %s" % (name, repr(frame)))
frame = USPcieFrame()
first = True
return instances()
class RCSource(object):
def __init__(self):
self.active = False
self.has_logic = False
self.queue = []
def send(self, frame):
self.queue.append(USPcieFrame(frame))
def count(self):
return len(self.queue)
def empty(self):
return not self.queue
def create_logic(self,
clk,
rst,
tdata=None,
tkeep=Signal(bool(True)),
tvalid=Signal(bool(False)),
tready=Signal(bool(True)),
tlast=Signal(bool(False)),
tuser=Signal(intbv(0)),
pause=0,
name=None
):
assert len(tdata) in [64, 128, 256, 512]
2019-10-12 18:01:39 -07:00
assert len(tkeep)*32 == len(tdata)
if len(tdata) == 512:
assert len(tuser) == 161
else:
assert len(tdata) in [64, 128, 256]
assert len(tuser) == 75
2019-10-12 18:01:39 -07:00
assert not self.has_logic
self.has_logic = True
@instance
def logic():
frame = USPcieFrame()
data = []
byte_en = []
parity = []
self.active = False
first = True
while True:
yield clk.posedge, rst.posedge
if rst:
data = []
byte_en = []
parity = []
self.active = False
tdata.next = 0
tkeep.next = 0
tuser.next = 0
tvalid.next = False
tlast.next = False
first = True
else:
tvalid.next = self.active and (tvalid or not pause)
if tready and tvalid:
tvalid.next = False
self.active = False
if not data and self.queue:
frame = self.queue.pop(0)
data = list(frame.data)
byte_en = list(frame.byte_en)
parity = list(frame.parity)
if name is not None:
print("[%s] Sending frame %s" % (name, repr(frame)))
first = True
if data and not self.active:
d = 0
k = 0
u = 0
if len(tdata) == 512:
if first:
u |= 0b0001 << 64 # is_sop
u |= 0b00 << 68 # is_sop0_ptr
if frame.discontinue:
u |= 1 << 96 # discontinue
last_lane = 0
for i in range(len(tkeep)):
if data:
d |= data.pop(0) << i*32
k |= 1 << i
u |= byte_en.pop(0) << i*4
u |= parity.pop(0) << i*4+97
last_lane = i
else:
u |= 0xf << i*4+97
if not data:
u |= 0b0001 << 76 # is_eop
u |= last_lane << 80 # is_eop0_ptr
else:
if first:
u |= 1 << 32 # is_sof_0
if frame.discontinue:
u |= 1 << 42 # discontinue
last_lane = 0
for i in range(len(tkeep)):
if data:
d |= data.pop(0) << i*32
k |= 1 << i
u |= byte_en.pop(0) << i*4
u |= parity.pop(0) << i*4+43
last_lane = i
else:
u |= 0xf << i*4+43
if not data:
u |= (1 | last_lane << 1) << 34 # is_eof_0
2019-10-12 18:01:39 -07:00
tdata.next = d
tkeep.next = k
tuser.next = u
tvalid.next = not pause
tlast.next = len(data) == 0
self.active = True
first = False
return instances()
class RCSink(object):
def __init__(self):
self.has_logic = False
self.queue = []
self.read_queue = []
self.sync = Signal(intbv(0))
def recv(self):
if self.queue:
return self.queue.pop(0)
return None
def count(self):
return len(self.queue)
def empty(self):
return not self.queue
def wait(self, timeout=0):
if self.queue:
return
if timeout:
yield self.sync, delay(timeout)
else:
yield self.sync
def create_logic(self,
clk,
rst,
tdata=None,
tkeep=Signal(bool(True)),
tvalid=Signal(bool(False)),
tready=Signal(bool(True)),
tlast=Signal(bool(True)),
tuser=Signal(intbv(0)),
pause=0,
name=None
):
assert len(tdata) in [64, 128, 256, 512]
2019-10-12 18:01:39 -07:00
assert len(tkeep)*32 == len(tdata)
if len(tdata) == 512:
assert len(tuser) == 161
else:
assert len(tdata) in [64, 128, 256]
assert len(tuser) == 75
2019-10-12 18:01:39 -07:00
assert not self.has_logic
self.has_logic = True
tready_int = Signal(bool(False))
tvalid_int = Signal(bool(False))
@always_comb
def pause_logic():
tready.next = tready_int and not pause
tvalid_int.next = tvalid and not pause
@instance
def logic():
frame = USPcieFrame()
first = True
while True:
yield clk.posedge, rst.posedge
if rst:
tready_int.next = False
frame = USPcieFrame()
first = True
else:
tready_int.next = True
if tvalid_int:
# zero tkeep not allowed
assert int(tkeep) != 0
# tkeep must be contiguous
# i.e. 0b00011110 allowed, but 0b00011010 not allowed
b = int(tkeep)
while b & 1 == 0:
b = b >> 1
while b & 1 == 1:
b = b >> 1
assert b == 0
# tkeep must not have gaps across cycles
if not first:
# not first cycle; lowest bit must be set
assert int(tkeep) & 1
if not tlast:
# not last cycle; highest bit must be set
assert int(tkeep) & (1 << len(tkeep)-1)
d = int(tdata)
u = int(tuser)
if len(tdata) == 512:
if u & (1 << 96):
frame.discontinue = True
last_lane = 0
for i in range(len(tkeep)):
if tkeep & (1 << i):
frame.data.append((d >> (i*32)) & 0xffffffff)
frame.byte_en.append((u >> (i*4)) & 0xf)
frame.parity.append((u >> (i*4+97)) & 0xf)
last_lane = i
else:
if u & (1 << 42):
frame.discontinue = True
last_lane = 0
for i in range(len(tkeep)):
if tkeep & (1 << i):
frame.data.append((d >> (i*32)) & 0xffffffff)
frame.byte_en.append((u >> (i*4)) & 0xf)
frame.parity.append((u >> (i*4+43)) & 0xf)
last_lane = i
2019-10-12 18:01:39 -07:00
first = False
if tlast:
self.queue.append(frame)
self.sync.next = not self.sync
if name is not None:
print("[%s] Got frame %s" % (name, repr(frame)))
frame = USPcieFrame()
first = True
return instances()
2018-10-15 00:05:37 -07:00
class UltrascalePCIeFunction(Endpoint, MSICapability, MSIXCapability):
2018-09-25 19:50:57 -07:00
def __init__(self):
super(UltrascalePCIeFunction, self).__init__()
2018-10-15 00:05:37 -07:00
self.msi_64bit_address_capable = 1
self.msi_per_vector_mask_capable = 0
2019-02-28 23:46:39 -08:00
self.register_capability(PM_CAP_ID, offset=0x20)
self.register_capability(MSI_CAP_ID, offset=0x24)
self.register_capability(MSIX_CAP_ID, offset=0x2c)
self.register_capability(PCIE_CAP_ID, offset=0x30)
2018-09-25 19:50:57 -07:00
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
2019-10-12 18:01:39 -07:00
self.cq_source = CQSource()
self.cc_sink = CCSink()
self.rq_sink = RQSink()
self.rc_source = RCSource()
2018-09-25 19:50:57 -07:00
self.rq_seq_num = []
2018-09-25 19:50:57 -07:00
self.make_function()
def upstream_recv(self, tlp):
# logging
print("[%s] Got downstream TLP: %s" % (highlight(self.get_desc()), repr(tlp)))
2018-09-30 19:14:19 -07:00
if tlp.fmt_type == TLP_CFG_READ_0 or tlp.fmt_type == TLP_CFG_WRITE_0:
2018-09-25 19:50:57 -07:00
# 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)))
2018-10-23 21:24:39 -07:00
yield from self.upstream_send(cpl)
2018-09-25 19:50:57 -07:00
return
2018-10-01 15:41:00 -07:00
elif tlp.dest_id.device == self.device_num:
2018-09-25 19:50:57 -07:00
# capture address information
2018-10-01 15:41:00 -07:00
self.bus_num = tlp.dest_id.bus
2018-09-25 19:50:57 -07:00
for f in self.functions:
f.bus_num = self.bus_num
# pass TLP to function
for f in self.functions:
2018-10-01 15:41:00 -07:00
if f.function_num == tlp.dest_id.function:
2018-10-23 21:24:39 -07:00
yield from f.upstream_recv(tlp)
2018-09-25 19:50:57 -07:00
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)))
2018-10-23 21:24:39 -07:00
yield from self.upstream_send(cpl)
2018-09-30 19:14:19 -07:00
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):
2018-09-25 19:50:57 -07:00
# Completion
2018-10-01 15:41:00 -07:00
if tlp.requester_id.bus == self.bus_num and tlp.requester_id.device == self.device_num:
2018-09-25 19:50:57 -07:00
for f in self.functions:
2018-10-01 15:41:00 -07:00
if f.function_num == tlp.requester_id.function:
2018-09-25 19:50:57 -07:00
tlp = TLP_us(tlp)
2019-10-01 17:17:42 -07:00
tlp.error_code = RC_ERROR_NORMAL_TERMINATION
if tlp.status != CPL_STATUS_SC:
tlp.error = RC_ERROR_BAD_STATUS
2018-09-25 19:50:57 -07:00
self.rc_queue.append(tlp)
return
print("Function not found")
else:
print("Bus/device number mismatch")
2018-09-30 19:14:19 -07:00
elif (tlp.fmt_type == TLP_IO_READ or tlp.fmt_type == TLP_IO_WRITE):
2018-09-25 19:50:57 -07:00
# 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))
2018-10-01 15:41:00 -07:00
tlp.completer_id = PcieId(self.bus_num, self.device_num, f.function_num)
2018-09-25 19:50:57 -07:00
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)))
2018-10-23 21:24:39 -07:00
yield from self.upstream_send(cpl)
2018-09-30 19:14:19 -07:00
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):
2018-09-25 19:50:57 -07:00
# 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))
2018-10-01 15:41:00 -07:00
tlp.completer_id = PcieId(self.bus_num, self.device_num, f.function_num)
2018-09-25 19:50:57 -07:00
self.cq_queue.append(tlp)
return
print("Memory request did not match any BARs")
2018-09-30 19:14:19 -07:00
if tlp.fmt_type == TLP_MEM_READ or tlp.fmt_type == TLP_MEM_READ_64:
2018-09-25 19:50:57 -07:00
# Unsupported request
cpl = TLP()
2018-10-01 15:41:00 -07:00
cpl.set_ur_completion(tlp, PcieId(self.bus_num, self.device_num, 0))
2018-09-25 19:50:57 -07:00
# logging
print("[%s] UR Completion: %s" % (highlight(self.get_desc()), repr(cpl)))
2018-10-23 21:24:39 -07:00
yield from self.upstream_send(cpl)
2018-09-25 19:50:57 -07:00
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:]),
2018-10-15 13:41:29 -07:00
cfg_interrupt_msi_enable=Signal(intbv(0)[4:]),
cfg_interrupt_msi_vf_enable=Signal(intbv(0)[8:]),
cfg_interrupt_msi_mmenable=Signal(intbv(0)[12:]),
2018-09-25 19:50:57 -07:00
cfg_interrupt_msi_mask_update=Signal(bool(0)),
cfg_interrupt_msi_data=Signal(intbv(0)[32:]),
2018-10-16 18:02:28 -07:00
cfg_interrupt_msi_select=Signal(intbv(0)[4:]),
cfg_interrupt_msi_int=Signal(intbv(0)[32:]),
cfg_interrupt_msi_pending_status=Signal(intbv(0)[32:]),
2018-10-15 13:41:29 -07:00
cfg_interrupt_msi_pending_status_data_enable=Signal(bool(0)),
2018-10-16 18:02:28 -07:00
cfg_interrupt_msi_pending_status_function_num=Signal(intbv(0)[4:]),
cfg_interrupt_msi_sent=Signal(bool(0)),
cfg_interrupt_msi_fail=Signal(bool(0)),
2018-10-15 13:41:29 -07:00
cfg_interrupt_msix_enable=Signal(intbv(0)[4:]),
cfg_interrupt_msix_mask=Signal(intbv(0)[4:]),
cfg_interrupt_msix_vf_enable=Signal(intbv(0)[8:]),
cfg_interrupt_msix_vf_mask=Signal(intbv(0)[8:]),
2018-09-25 19:50:57 -07:00
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:]),
2018-10-15 13:41:29 -07:00
cfg_interrupt_msi_function_number=Signal(intbv(0)[4:]),
2018-09-25 19:50:57 -07:00
# 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)),
2018-10-15 14:17:00 -07:00
pcie_perstn1_out=Signal(bool(0)),
# debugging connections
cq_pause=Signal(bool(0)),
cc_pause=Signal(bool(0)),
rq_pause=Signal(bool(0)),
rc_pause=Signal(bool(0)),
2018-09-25 19:50:57 -07:00
):
# 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
2018-10-15 13:41:29 -07:00
assert len(cfg_interrupt_msi_enable) == 4
assert len(cfg_interrupt_msi_vf_enable) == 8
assert len(cfg_interrupt_msi_mmenable) == 12
2018-09-25 19:50:57 -07:00
assert len(cfg_interrupt_msi_mask_update) == 1
assert len(cfg_interrupt_msi_data) == 32
2018-10-16 18:02:28 -07:00
assert len(cfg_interrupt_msi_select) == 4
assert len(cfg_interrupt_msi_int) == 32
assert len(cfg_interrupt_msi_pending_status) == 32
2018-10-15 13:41:29 -07:00
assert len(cfg_interrupt_msi_pending_status_data_enable) == 1
2018-10-16 18:02:28 -07:00
assert len(cfg_interrupt_msi_pending_status_function_num) == 4
assert len(cfg_interrupt_msi_sent) == 1
assert len(cfg_interrupt_msi_fail) == 1
2018-10-15 13:41:29 -07:00
assert len(cfg_interrupt_msix_enable) == 4
assert len(cfg_interrupt_msix_mask) == 4
assert len(cfg_interrupt_msix_vf_enable) == 8
assert len(cfg_interrupt_msix_vf_mask) == 8
2018-09-25 19:50:57 -07:00
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
2018-10-15 13:41:29 -07:00
assert len(cfg_interrupt_msi_function_number) == 4
2018-09-25 19:50:57 -07:00
# 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,
2018-10-15 14:17:00 -07:00
name='cq_source',
pause=cq_pause
2018-09-25 19:50:57 -07:00
)
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,
2018-10-15 14:17:00 -07:00
name='cc_sink',
pause=cc_pause
2018-09-25 19:50:57 -07:00
)
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,
2018-10-15 14:17:00 -07:00
name='rq_sink',
pause=rq_pause
2018-09-25 19:50:57 -07:00
)
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,
2018-10-15 14:17:00 -07:00
name='rc_source',
pause=rc_pause
2018-09-25 19:50:57 -07:00
)
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
2019-10-12 18:01:39 -07:00
self.cq_source.send(tlp.pack_us_cq())
2018-09-25 19:50:57 -07:00
# handle new requests
while self.cq_queue:
tlp = self.cq_queue.pop(0)
2018-09-30 19:14:19 -07:00
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):
2018-09-25 19:50:57 -07:00
# non-posted request
if self.cq_np_req_count > 0:
# have credit, can forward
self.cq_np_req_count -= 1
2019-10-12 18:01:39 -07:00
self.cq_source.send(tlp.pack_us_cq())
2018-09-25 19:50:57 -07:00
else:
# no credits, put it in the queue
self.cq_np_queue.append(tlp)
else:
# posted request
2019-10-12 18:01:39 -07:00
self.cq_source.send(tlp.pack_us_cq())
2018-09-25 19:50:57 -07:00
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()
2019-10-12 18:01:39 -07:00
tlp = TLP_us().unpack_us_cc(pkt, self.enable_parity)
2018-09-25 19:50:57 -07:00
if not tlp.completer_id_enable:
2018-10-01 15:41:00 -07:00
tlp.completer_id = PcieId(self.bus_num, self.device_num, tlp.completer_id.function)
2018-09-25 19:50:57 -07:00
if not tlp.discontinue:
2018-10-23 21:24:39 -07:00
yield from self.send(TLP(tlp))
2018-09-25 19:50:57 -07:00
# handle requester requests
while not self.rq_sink.empty():
pkt = self.rq_sink.recv()
2019-10-12 18:01:39 -07:00
tlp = TLP_us().unpack_us_rq(pkt, self.enable_parity)
2018-09-25 19:50:57 -07:00
if not tlp.requester_id_enable:
2018-10-01 15:41:00 -07:00
tlp.requester_id = PcieId(self.bus_num, self.device_num, tlp.requester_id.function)
2018-09-25 19:50:57 -07:00
if not tlp.discontinue:
2018-10-01 15:41:00 -07:00
if self.functions[tlp.requester_id.function].bus_master_enable:
self.rq_seq_num.append(tlp.seq_num)
2018-10-23 21:24:39 -07:00
yield from self.send(TLP(tlp))
2018-09-25 19:50:57 -07:00
else:
print("Bus mastering disabled")
# TODO: internal response
# transmit sequence number
pcie_rq_seq_num_vld.next = 0
if self.rq_seq_num:
pcie_rq_seq_num.next = self.rq_seq_num.pop(0)
pcie_rq_seq_num_vld.next = 1
2018-09-25 19:50:57 -07:00
# TODO pcie_rq_tag
# handle requester completions
while self.rc_queue:
tlp = self.rc_queue.pop(0)
2019-10-12 18:01:39 -07:00
self.rc_source.send(tlp.pack_us_rc())
2018-09-25 19:50:57 -07:00
# transmit flow control
# TODO
pcie_tfc_nph_av.next = 0x3
pcie_tfc_npd_av.next = 0x3
2018-09-25 19:50:57 -07:00
# 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
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
2018-09-25 19:50:57 -07:00
#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
2018-09-25 19:50:57 -07:00
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
2018-09-25 19:50:57 -07:00
#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
2018-09-25 19:50:57 -07:00
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
2018-09-25 19:50:57 -07:00
#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
if (cfg_fc_sel == 0b000):
# Receive credits at link partner
# TODO
cfg_fc_ph.next = 0
cfg_fc_pd.next = 0
cfg_fc_nph.next = 0
cfg_fc_npd.next = 0
cfg_fc_cplh.next = 0
cfg_fc_cpld.next = 0
elif (cfg_fc_sel == 0b001):
# Receive credit limit
# TODO
cfg_fc_ph.next = 0x80
cfg_fc_pd.next = 0x800
cfg_fc_nph.next = 0x80
cfg_fc_npd.next = 0x800
cfg_fc_cplh.next = 0x80
cfg_fc_cpld.next = 0x800
elif (cfg_fc_sel == 0b010):
# Receive credits consumed
# TODO
cfg_fc_ph.next = 0
cfg_fc_pd.next = 0
cfg_fc_nph.next = 0
cfg_fc_npd.next = 0
cfg_fc_cplh.next = 0
cfg_fc_cpld.next = 0
elif (cfg_fc_sel == 0b011):
# Available space in receive buffer
# TODO
cfg_fc_ph.next = 0
cfg_fc_pd.next = 0
cfg_fc_nph.next = 0
cfg_fc_npd.next = 0
cfg_fc_cplh.next = 0
cfg_fc_cpld.next = 0
elif (cfg_fc_sel == 0b100):
# Transmit credits available
# TODO
cfg_fc_ph.next = 0x80
cfg_fc_pd.next = 0x800
cfg_fc_nph.next = 0x80
cfg_fc_npd.next = 0x800
cfg_fc_cplh.next = 0x80
cfg_fc_cpld.next = 0x800
elif (cfg_fc_sel == 0b101):
# Transmit credit limit
# TODO
cfg_fc_ph.next = 0x80
cfg_fc_pd.next = 0x800
cfg_fc_nph.next = 0x80
cfg_fc_npd.next = 0x800
cfg_fc_cplh.next = 0x80
cfg_fc_cpld.next = 0x800
elif (cfg_fc_sel == 0b110):
# Transmit credits consumed
# TODO
cfg_fc_ph.next = 0
cfg_fc_pd.next = 0
cfg_fc_nph.next = 0
cfg_fc_npd.next = 0
cfg_fc_cplh.next = 0
cfg_fc_cpld.next = 0
else:
# Reserved
cfg_fc_ph.next = 0
cfg_fc_pd.next = 0
cfg_fc_nph.next = 0
cfg_fc_npd.next = 0
cfg_fc_cplh.next = 0
cfg_fc_cpld.next = 0
2018-09-25 19:50:57 -07:00
# per-function status
#cfg_per_func_status_control
#cfg_per_func_status_data
# configuration control
#cfg_hot_reset_in
#cfg_hot_reset_out
2018-09-25 19:50:57 -07:00
if not sys_reset:
self.config_space_enable = False
else:
self.config_space_enable = bool(cfg_config_space_enable)
2018-09-25 19:50:57 -07:00
#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
2018-09-25 19:50:57 -07:00
# MSI
val = 0
if self.functions[0].msi_enable:
val |= 1
if len(self.functions) > 1:
if self.functions[1].msi_enable:
val |= 2
cfg_interrupt_msi_enable.next = val
2018-09-25 19:50:57 -07:00
#cfg_interrupt_msi_vf_enable
cfg_interrupt_msi_sent.next = 0
cfg_interrupt_msi_fail.next = 0
if (cfg_interrupt_msi_int):
n = int(cfg_interrupt_msi_int)
#bits = [i for i in range(n.bit_length()) if n >> i & 1]
bits = [i for i in range(32) if n >> i & 1]
if len(bits) == 1 and cfg_interrupt_msi_function_number < len(self.functions):
yield self.functions[cfg_interrupt_msi_function_number].issue_msi_interrupt(bits[0], attr=int(cfg_interrupt_msi_attr))
cfg_interrupt_msi_sent.next = 1
val = 0
val |= self.functions[0].msi_multiple_message_enable & 0x7
if len(self.functions) > 1:
val |= (self.functions[1].msi_multiple_message_enable & 0x7) << 3
cfg_interrupt_msi_mmenable.next = val
2018-09-25 19:50:57 -07:00
#cfg_interrupt_msi_mask_update
if cfg_interrupt_msi_select == 0b1111:
cfg_interrupt_msi_data.next = 0
else:
if cfg_interrupt_msi_select < len(self.functions):
cfg_interrupt_msi_data.next = self.functions[cfg_interrupt_msi_select].msi_mask_bits;
else:
cfg_interrupt_msi_data.next = 0
if cfg_interrupt_msi_pending_status_data_enable:
if cfg_interrupt_msi_pending_status_function_num < len(self.functions):
self.functions[cfg_interrupt_msi_pending_status_function_num].msi_pending_bits = int(cfg_interrupt_msi_pending_status)
2018-09-25 19:50:57 -07:00
# MSI-X
val = 0
if self.functions[0].msix_enable:
val |= 1
if len(self.functions) > 1:
if self.functions[1].msix_enable:
val |= 2
cfg_interrupt_msix_enable.next = val
val = 0
if self.functions[0].msix_function_mask:
val |= 1
if len(self.functions) > 1:
if self.functions[1].msix_function_mask:
val |= 2
cfg_interrupt_msix_mask.next = val
2018-09-25 19:50:57 -07:00
#cfg_interrupt_msix_vf_enable
#cfg_interrupt_msix_vf_mask
cfg_interrupt_msix_sent.next = 0
cfg_interrupt_msix_fail.next = 0
if cfg_interrupt_msix_int:
if cfg_interrupt_msi_function_number < len(self.functions):
yield self.functions[cfg_interrupt_msi_function_number].issue_msix_interrupt(int(cfg_interrupt_msix_address), int(cfg_interrupt_msix_data), attr=int(cfg_interrupt_msi_attr))
cfg_interrupt_msix_sent.next = 1
2018-09-25 19:50:57 -07:00
# MSI/MSI-X
#cfg_interrupt_msi_tph_present
#cfg_interrupt_msi_tph_type
#cfg_interrupt_msi_tph_st_tag
# 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()