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
|
2019-11-25 18:07:49 -08:00
|
|
|
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
|
2019-11-25 18:07:49 -08:00
|
|
|
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
|
2019-11-25 18:07:49 -08:00
|
|
|
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)) +
|
2019-11-25 18:07:49 -08:00
|
|
|
('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
|
2019-11-25 18:07:49 -08:00
|
|
|
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
|
2019-11-25 18:07:49 -08:00
|
|
|
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
|
|
|
|
|
2019-11-25 18:07:49 -08:00
|
|
|
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
|
|
|
|
2019-11-25 18:07:49 -08: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
|
|
|
|
):
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
assert len(tdata) in [64, 128, 256, 512]
|
2019-10-12 18:01:39 -07:00
|
|
|
assert len(tkeep)*32 == len(tdata)
|
2019-10-14 15:45:41 -07:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
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
|
|
|
|
):
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
assert len(tdata) in [64, 128, 256, 512]
|
2019-10-12 18:01:39 -07:00
|
|
|
assert len(tkeep)*32 == len(tdata)
|
2019-10-14 15:45:41 -07:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
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
|
|
|
|
2019-10-14 15:45:41 -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
|
|
|
|
2019-10-14 15:45:41 -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
|
|
|
|
):
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
assert len(tdata) in [64, 128, 256, 512]
|
2019-10-12 18:01:39 -07:00
|
|
|
assert len(tkeep)*32 == len(tdata)
|
2019-10-14 15:45:41 -07:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
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
|
|
|
|
):
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
assert len(tdata) in [64, 128, 256, 512]
|
2019-10-12 18:01:39 -07:00
|
|
|
assert len(tkeep)*32 == len(tdata)
|
2019-10-14 15:45:41 -07:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
if len(tdata) == 512:
|
|
|
|
if u & (1 << 16):
|
|
|
|
frame.discontinue = True
|
|
|
|
|
|
|
|
last_lane = 0
|
2019-10-12 18:01:39 -07:00
|
|
|
|
2019-10-14 15:45:41 -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
|
|
|
|
):
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
assert len(tdata) in [64, 128, 256, 512]
|
2019-10-12 18:01:39 -07:00
|
|
|
assert len(tkeep)*32 == len(tdata)
|
2019-10-14 15:45:41 -07:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
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
|
2019-10-14 15:45:41 -07:00
|
|
|
|
2019-11-25 18:07:49 -08:00
|
|
|
u |= (frame.seq_num & 0x3f) << 61
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
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
|
2019-10-14 15:45:41 -07:00
|
|
|
|
2019-11-25 18:07:49 -08:00
|
|
|
u |= (frame.seq_num & 0xf) << 24
|
|
|
|
|
|
|
|
if len(tuser) == 62:
|
|
|
|
u |= ((frame.seq_num >> 4) & 0x3) << 60
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
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
|
|
|
|
):
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
assert len(tdata) in [64, 128, 256, 512]
|
2019-10-12 18:01:39 -07:00
|
|
|
assert len(tkeep)*32 == len(tdata)
|
2019-10-14 15:45:41 -07:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
if len(tdata) == 512:
|
|
|
|
if first:
|
|
|
|
frame.first_be = u & 0xf
|
|
|
|
frame.last_be = (u >> 8) & 0xf
|
|
|
|
|
|
|
|
if u & (1 << 36):
|
|
|
|
frame.discontinue = True
|
|
|
|
|
2019-11-25 18:07:49 -08:00
|
|
|
frame.seq_num = (u >> 61) & 0x3f
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
last_lane = 0
|
2019-10-12 18:01:39 -07:00
|
|
|
|
2019-10-14 15:45:41 -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
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
if u & (1 << 11):
|
|
|
|
frame.discontinue = True
|
|
|
|
|
2019-11-25 18:07:49 -08:00
|
|
|
frame.seq_num = (u >> 24) & 0xf
|
|
|
|
|
|
|
|
if len(tuser) == 62:
|
|
|
|
frame.seq_num |= ((u >> 60) & 0x3) << 4
|
|
|
|
|
2019-10-14 15:45:41 -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+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
|
|
|
|
):
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
assert len(tdata) in [64, 128, 256, 512]
|
2019-10-12 18:01:39 -07:00
|
|
|
assert len(tkeep)*32 == len(tdata)
|
2019-10-14 15:45:41 -07:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
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
|
|
|
|
):
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
assert len(tdata) in [64, 128, 256, 512]
|
2019-10-12 18:01:39 -07:00
|
|
|
assert len(tkeep)*32 == len(tdata)
|
2019-10-14 15:45:41 -07:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2019-10-14 15:45:41 -07:00
|
|
|
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
|
|
|
|
2019-11-25 18:07:49 -08: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:
|
2019-11-25 18:07:49 -08:00
|
|
|
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
|
|
|
|
|
2019-11-25 18:07:49 -08:00
|
|
|
# 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
|
2019-12-06 19:16:05 -08:00
|
|
|
# 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-10-15 14:18:27 -07:00
|
|
|
|
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-10-15 14:18:27 -07:00
|
|
|
|
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-10-15 14:18:27 -07:00
|
|
|
|
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-10-15 14:18:27 -07:00
|
|
|
|
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-10-15 14:18:27 -07:00
|
|
|
|
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
|
2019-12-06 19:16:05 -08:00
|
|
|
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-10-15 14:18:27 -07:00
|
|
|
|
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-10-15 14:18:27 -07:00
|
|
|
|
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-10-15 14:18:27 -07:00
|
|
|
|
2018-09-25 19:50:57 -07:00
|
|
|
# MSI
|
2018-10-15 14:18:27 -07:00
|
|
|
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
|
2018-10-15 14:18:27 -07:00
|
|
|
|
|
|
|
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
|
2018-10-15 14:18:27 -07:00
|
|
|
|
|
|
|
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
|
2018-10-15 14:18:27 -07:00
|
|
|
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
|
2018-10-15 14:18:27 -07:00
|
|
|
|
|
|
|
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()
|
|
|
|
|