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

Add Ultrascale Plus PCIe hard IP core model and testbench

This commit is contained in:
Alex Forencich 2019-07-15 17:18:39 -07:00
parent 1d79a4375b
commit f1348db2f7
2 changed files with 1923 additions and 0 deletions

998
tb/pcie_usp.py Normal file
View File

@ -0,0 +1,998 @@
"""
Copyright (c) 2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
import math
import struct
from myhdl import *
import axis_ep
from pcie_us import *
class UltrascalePlusPCIeFunction(Endpoint, MSICapability, MSIXCapability):
def __init__(self):
super(UltrascalePlusPCIeFunction, self).__init__()
self.msi_64bit_address_capable = 1
self.msi_per_vector_mask_capable = 0
self.register_capability(PM_CAP_ID, offset=0x10)
self.register_capability(MSI_CAP_ID, offset=0x12)
self.register_capability(MSIX_CAP_ID, offset=0x18)
self.register_capability(PCIE_CAP_ID, offset=0x1c)
class UltrascalePlusPCIe(Device):
def __init__(self):
super(UltrascalePlusPCIe, self).__init__()
self.has_logic = False
self.default_function = UltrascalePlusPCIeFunction
self.dw = 256
# configuration options
self.pcie_generation = 3
self.pcie_link_width = 8
self.user_clk_frequency = 250e6
self.alignment = "dword"
self.cq_cc_straddle = False
self.rq_rc_straddle = False
self.rc_4tlp_straddle = False
self.enable_pf1 = False
self.enable_client_tag = True
self.enable_extended_tag = False
self.enable_parity = False
self.enable_rx_msg_interface = False
self.enable_sriov = False
self.enable_extended_configuration = False
self.enable_pf0_msi = False
self.enable_pf1_msi = False
self.cq_queue = []
self.cq_np_queue = []
self.cq_np_req_count = 0
self.rc_queue = []
self.msg_queue = []
self.config_space_enable = False
self.cq_source = axis_ep.AXIStreamSource()
self.cc_sink = axis_ep.AXIStreamSink()
self.rq_sink = axis_ep.AXIStreamSink()
self.rc_source = axis_ep.AXIStreamSource()
self.make_function()
def upstream_recv(self, tlp):
# logging
print("[%s] Got downstream TLP: %s" % (highlight(self.get_desc()), repr(tlp)))
if tlp.fmt_type == TLP_CFG_READ_0 or tlp.fmt_type == TLP_CFG_WRITE_0:
# config type 0
if not self.config_space_enable:
print("Configuraion space disabled")
cpl = TLP()
cpl.set_crs_completion(tlp, (self.bus_num, self.device_num, 0))
# logging
print("[%s] CRS Completion: %s" % (highlight(self.get_desc()), repr(cpl)))
yield from self.upstream_send(cpl)
return
elif tlp.dest_id.device == self.device_num:
# capture address information
self.bus_num = tlp.dest_id.bus
for f in self.functions:
f.bus_num = self.bus_num
# pass TLP to function
for f in self.functions:
if f.function_num == tlp.dest_id.function:
yield from f.upstream_recv(tlp)
return
#raise Exception("Function not found")
print("Function not found")
else:
print("Device number mismatch")
# Unsupported request
cpl = TLP()
cpl.set_ur_completion(tlp, (self.bus_num, self.device_num, 0))
# logging
print("[%s] UR Completion: %s" % (highlight(self.get_desc()), repr(cpl)))
yield from self.upstream_send(cpl)
elif (tlp.fmt_type == TLP_CPL or tlp.fmt_type == TLP_CPL_DATA or
tlp.fmt_type == TLP_CPL_LOCKED or tlp.fmt_type == TLP_CPL_LOCKED_DATA):
# Completion
if tlp.requester_id.bus == self.bus_num and tlp.requester_id.device == self.device_num:
for f in self.functions:
if f.function_num == tlp.requester_id.function:
tlp = TLP_us(tlp)
self.rc_queue.append(tlp)
return
print("Function not found")
else:
print("Bus/device number mismatch")
elif (tlp.fmt_type == TLP_IO_READ or tlp.fmt_type == TLP_IO_WRITE):
# IO read/write
for f in self.functions:
bar = f.match_bar(tlp.address, True)
if len(bar) == 1:
tlp = TLP_us(tlp)
tlp.bar_id = bar[0][0]
tlp.bar_aperture = int(math.log2((~self.functions[0].bar_mask[bar[0][0]]&0xffffffff)+1))
tlp.completer_id = PcieId(self.bus_num, self.device_num, f.function_num)
self.cq_queue.append(tlp)
return
print("IO request did not match any BARs")
# Unsupported request
cpl = TLP()
cpl.set_ur_completion(tlp, (self.bus_num, self.device_num, 0))
# logging
print("[%s] UR Completion: %s" % (highlight(self.get_desc()), repr(cpl)))
yield from self.upstream_send(cpl)
elif (tlp.fmt_type == TLP_MEM_READ or tlp.fmt_type == TLP_MEM_READ_64 or
tlp.fmt_type == TLP_MEM_WRITE or tlp.fmt_type == TLP_MEM_WRITE_64):
# Memory read/write
for f in self.functions:
bar = f.match_bar(tlp.address)
if len(bar) == 1:
tlp = TLP_us(tlp)
tlp.bar_id = bar[0][0]
if self.functions[0].bar[bar[0][0]] & 4:
tlp.bar_aperture = int(math.log2((~(self.functions[0].bar_mask[bar[0][0]] | (self.functions[0].bar_mask[bar[0][0]+1]<<32))&0xffffffffffffffff)+1))
else:
tlp.bar_aperture = int(math.log2((~self.functions[0].bar_mask[bar[0][0]]&0xffffffff)+1))
tlp.completer_id = PcieId(self.bus_num, self.device_num, f.function_num)
self.cq_queue.append(tlp)
return
print("Memory request did not match any BARs")
if tlp.fmt_type == TLP_MEM_READ or tlp.fmt_type == TLP_MEM_READ_64:
# Unsupported request
cpl = TLP()
cpl.set_ur_completion(tlp, PcieId(self.bus_num, self.device_num, 0))
# logging
print("[%s] UR Completion: %s" % (highlight(self.get_desc()), repr(cpl)))
yield from self.upstream_send(cpl)
else:
raise Exception("TODO")
def create_logic(self,
# Completer reQuest Interface
m_axis_cq_tdata=None,
m_axis_cq_tuser=None,
m_axis_cq_tlast=None,
m_axis_cq_tkeep=None,
m_axis_cq_tvalid=None,
m_axis_cq_tready=None,
pcie_cq_np_req=Signal(intbv(1)[2:]),
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_num0=Signal(intbv(0)[6:]),
pcie_rq_seq_num_vld0=Signal(bool(0)),
pcie_rq_seq_num1=Signal(intbv(0)[6:]),
pcie_rq_seq_num_vld1=Signal(bool(0)),
pcie_rq_tag0=Signal(intbv(0)[8:]),
pcie_rq_tag1=Signal(intbv(0)[8:]),
pcie_rq_tag_av=Signal(intbv(0)[4:]),
pcie_rq_tag_vld0=Signal(bool(0)),
pcie_rq_tag_vld1=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)[4:]),
pcie_tfc_npd_av=Signal(intbv(0)[4:]),
# Configuration Management Interface
cfg_mgmt_addr=Signal(intbv(0)[10:]),
cfg_mgmt_function_number=Signal(intbv(0)[8:]),
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_debug_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)[3:]),
cfg_current_speed=Signal(intbv(0)[2:]),
cfg_max_payload=Signal(intbv(0)[2:]),
cfg_max_read_req=Signal(intbv(0)[3:]),
cfg_function_status=Signal(intbv(0)[16:]),
cfg_vf_status=Signal(intbv(0)[504:]),
cfg_function_power_state=Signal(intbv(0)[12:]),
cfg_vf_power_state=Signal(intbv(0)[756:]),
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_local_err_out=Signal(intbv(0)[5:]),
cfg_local_err_valid=Signal(bool(0)),
cfg_rx_pm_state=Signal(intbv(0)[2:]),
cfg_tx_pm_state=Signal(intbv(0)[2:]),
cfg_ltssm_state=Signal(intbv(0)[6:]),
cfg_rcb_status=Signal(intbv(0)[4:]),
cfg_obff_enable=Signal(intbv(0)[2:]),
cfg_pl_status_change=Signal(bool(0)),
cfg_tph_requester_enable=Signal(intbv(0)[4:]),
cfg_tph_st_mode=Signal(intbv(0)[12:]),
cfg_vf_tph_requester_enable=Signal(intbv(0)[252:]),
cfg_vf_tph_st_mode=Signal(intbv(0)[756:]),
# 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:]),
# 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_dsn=Signal(intbv(0)[64:]),
cfg_ds_port_number=Signal(intbv(0)[8:]),
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)[4:]),
cfg_vf_flr_done=Signal(intbv(0)[1:]),
cfg_flr_in_process=Signal(intbv(0)[4:]),
cfg_vf_flr_in_process=Signal(intbv(0)[252:]),
cfg_req_pm_transition_l23_ready=Signal(bool(0)),
cfg_link_training_enable=Signal(bool(1)),
# Configuration Interrupt Controller Interface
cfg_interrupt_int=Signal(intbv(0)[4:]),
cfg_interrupt_sent=Signal(bool(0)),
cfg_interrupt_pending=Signal(intbv(0)[2:]),
cfg_interrupt_msi_enable=Signal(intbv(0)[4:]),
cfg_interrupt_msi_mmenable=Signal(intbv(0)[12:]),
cfg_interrupt_msi_mask_update=Signal(bool(0)),
cfg_interrupt_msi_data=Signal(intbv(0)[32:]),
cfg_interrupt_msi_select=Signal(intbv(0)[2:]),
cfg_interrupt_msi_int=Signal(intbv(0)[32:]),
cfg_interrupt_msi_pending_status=Signal(intbv(0)[32:]),
cfg_interrupt_msi_pending_status_data_enable=Signal(bool(0)),
cfg_interrupt_msi_pending_status_function_num=Signal(intbv(0)[2:]),
cfg_interrupt_msi_sent=Signal(bool(0)),
cfg_interrupt_msi_fail=Signal(bool(0)),
cfg_interrupt_msix_enable=Signal(intbv(0)[4:]),
cfg_interrupt_msix_mask=Signal(intbv(0)[4:]),
cfg_interrupt_msix_vf_enable=Signal(intbv(0)[252:]),
cfg_interrupt_msix_vf_mask=Signal(intbv(0)[252:]),
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_vec_pending=Signal(intbv(0)[2:]),
cfg_interrupt_msix_vec_pending_status=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)[8:]),
cfg_interrupt_msi_function_number=Signal(intbv(0)[8:]),
# 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,
phy_rdy_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)),
):
# validate parameters and widths
self.dw = len(m_axis_cq_tdata)
assert self.dw in [64, 128, 256, 512]
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, 16]
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 or wider, DWORD-aligned interface
assert not self.cq_cc_straddle
assert not self.rq_rc_straddle
if self.dw != 512:
assert not self.rc_4tlp_straddle
# TODO change this when support added
assert self.alignment == 'dword'
assert not self.cq_cc_straddle
assert not self.rq_rc_straddle
assert not self.rc_4tlp_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_link_width == 16:
assert self.dw == 128
assert self.user_clk_frequency == 250e6
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_link_width == 16:
assert self.dw == 256
assert self.user_clk_frequency == 250e6
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
elif self.pcie_link_width == 16:
assert self.dw == 512
assert self.user_clk_frequency == 250e6
# Completer reQuest Interface
assert len(m_axis_cq_tdata) == self.dw
assert len(m_axis_cq_tuser) == 88
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) == 2
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) == 62
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_num0) == 6
assert len(pcie_rq_seq_num_vld0) == 1
assert len(pcie_rq_seq_num1) == 6
assert len(pcie_rq_seq_num_vld1) == 1
assert len(pcie_rq_tag0) >= 8
assert len(pcie_rq_tag1) >= 8
assert len(pcie_rq_tag_av) == 4
assert len(pcie_rq_tag_vld0) == 1
assert len(pcie_rq_tag_vld1) == 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) == 4
assert len(pcie_tfc_npd_av) == 4
# Configuration Management Interface
assert len(cfg_mgmt_addr) == 10
assert len(cfg_mgmt_function_number) == 8
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_debug_access) == 1
# Configuration Status Interface
assert len(cfg_phy_link_down) == 1
assert len(cfg_phy_link_status) == 2
assert len(cfg_negotiated_width) == 3
assert len(cfg_current_speed) == 2
assert len(cfg_max_payload) == 2
assert len(cfg_max_read_req) == 3
assert len(cfg_function_status) == 16
assert len(cfg_vf_status) == 504
assert len(cfg_function_power_state) == 12
assert len(cfg_vf_power_state) == 756
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_local_err_out) == 5
assert len(cfg_local_err_valid) == 1
assert len(cfg_rx_pm_state) == 2
assert len(cfg_tx_pm_state) == 2
assert len(cfg_ltssm_state) == 6
assert len(cfg_rcb_status) == 4
assert len(cfg_obff_enable) == 2
assert len(cfg_pl_status_change) == 1
assert len(cfg_tph_requester_enable) == 4
assert len(cfg_tph_st_mode) == 12
assert len(cfg_vf_tph_requester_enable) == 252
assert len(cfg_vf_tph_st_mode) == 756
# 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
# 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_dsn) == 64
assert len(cfg_ds_port_number) == 8
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) == 4
assert len(cfg_vf_flr_done) == 1
assert len(cfg_flr_in_process) == 4
assert len(cfg_vf_flr_in_process) == 252
assert len(cfg_req_pm_transition_l23_ready) == 1
assert len(cfg_link_training_enable) == 1
# Configuration Interrupt Controller Interface
assert len(cfg_interrupt_int) == 4
assert len(cfg_interrupt_sent) == 1
assert len(cfg_interrupt_pending) == 2
assert len(cfg_interrupt_msi_enable) == 4
assert len(cfg_interrupt_msi_mmenable) == 12
assert len(cfg_interrupt_msi_mask_update) == 1
assert len(cfg_interrupt_msi_data) == 32
assert len(cfg_interrupt_msi_select) == 2
assert len(cfg_interrupt_msi_int) == 32
assert len(cfg_interrupt_msi_pending_status) == 32
assert len(cfg_interrupt_msi_pending_status_data_enable) == 1
assert len(cfg_interrupt_msi_pending_status_function_num) == 2
assert len(cfg_interrupt_msi_sent) == 1
assert len(cfg_interrupt_msi_fail) == 1
assert len(cfg_interrupt_msix_enable) == 4
assert len(cfg_interrupt_msix_mask) == 4
assert len(cfg_interrupt_msix_vf_enable) == 252
assert len(cfg_interrupt_msix_vf_mask) == 252
assert len(cfg_interrupt_msix_address) == 64
assert len(cfg_interrupt_msix_data) == 32
assert len(cfg_interrupt_msix_vec_pending) == 2
assert len(cfg_interrupt_msix_vec_pending_status) == 1
assert len(cfg_interrupt_msix_int) == 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) == 8
assert len(cfg_interrupt_msi_function_number) == 8
# 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(phy_rdy_out) == 1
assert not self.has_logic
self.has_logic = True
# sources and sinks
cq_source_logic = self.cq_source.create_logic(
user_clk,
user_reset,
tdata=m_axis_cq_tdata,
tuser=m_axis_cq_tuser,
tlast=m_axis_cq_tlast,
tkeep=m_axis_cq_tkeep,
tvalid=m_axis_cq_tvalid,
tready=m_axis_cq_tready,
name='cq_source',
pause=cq_pause
)
cc_sink_logic = self.cc_sink.create_logic(
user_clk,
user_reset,
tdata=s_axis_cc_tdata,
tuser=s_axis_cc_tuser,
tlast=s_axis_cc_tlast,
tkeep=s_axis_cc_tkeep,
tvalid=s_axis_cc_tvalid,
tready=s_axis_cc_tready,
name='cc_sink',
pause=cc_pause
)
rq_sink_logic = self.rq_sink.create_logic(
user_clk,
user_reset,
tdata=s_axis_rq_tdata,
tuser=s_axis_rq_tuser,
tlast=s_axis_rq_tlast,
tkeep=s_axis_rq_tkeep,
tvalid=s_axis_rq_tvalid,
tready=s_axis_rq_tready,
name='rq_sink',
pause=rq_pause
)
rc_source_logic = self.rc_source.create_logic(
user_clk,
user_reset,
tdata=m_axis_rc_tdata,
tuser=m_axis_rc_tuser,
tlast=m_axis_rc_tlast,
tkeep=m_axis_rc_tkeep,
tvalid=m_axis_rc_tvalid,
tready=m_axis_rc_tready,
name='rc_source',
pause=rc_pause
)
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
@instance
def logic():
while True:
yield user_clk.posedge, sys_reset.negedge
if not sys_reset:
self.cq_np_req_count = 0
elif pcie_cq_np_req:
if self.cq_np_req_count < 32:
self.cq_np_req_count += 1
# handle completer requests
# send any queued non-posted requests first
while self.cq_np_queue and self.cq_np_req_count > 0:
tlp = self.cq_np_queue.pop(0)
self.cq_np_req_count -= 1
self.cq_source.send(tlp.pack_us_cq(self.dw))
# handle new requests
while self.cq_queue:
tlp = self.cq_queue.pop(0)
if (tlp.fmt_type == TLP_IO_READ or tlp.fmt_type == TLP_IO_WRITE or
tlp.fmt_type == TLP_MEM_READ or tlp.fmt_type == TLP_MEM_READ_64):
# non-posted request
if self.cq_np_req_count > 0:
# have credit, can forward
self.cq_np_req_count -= 1
self.cq_source.send(tlp.pack_us_cq(self.dw))
else:
# no credits, put it in the queue
self.cq_np_queue.append(tlp)
else:
# posted request
self.cq_source.send(tlp.pack_us_cq(self.dw))
pcie_cq_np_req_count.next = self.cq_np_req_count
# handle completer completions
while not self.cc_sink.empty():
pkt = self.cc_sink.recv()
tlp = TLP_us().unpack_us_cc(pkt, self.dw, self.enable_parity)
if not tlp.completer_id_enable:
tlp.completer_id = PcieId(self.bus_num, self.device_num, tlp.completer_id.function)
if not tlp.discontinue:
yield from self.send(TLP(tlp))
# handle requester requests
while not self.rq_sink.empty():
pkt = self.rq_sink.recv()
tlp = TLP_us().unpack_us_rq(pkt, self.dw, self.enable_parity)
if not tlp.requester_id_enable:
tlp.requester_id = PcieId(self.bus_num, self.device_num, tlp.requester_id.function)
if not tlp.discontinue:
if self.functions[tlp.requester_id.function].bus_master_enable:
yield from self.send(TLP(tlp))
else:
print("Bus mastering disabled")
# TODO: internal response
# TODO pcie_rq_seq_num
# TODO pcie_rq_tag
# handle requester completions
while self.rc_queue:
tlp = self.rc_queue.pop(0)
self.rc_source.send(tlp.pack_us_rc(self.dw))
# transmit flow control
#pcie_tfc_nph_av
#pcie_tfc_npd_av
# configuration management
# TODO four cycle delay
function = cfg_mgmt_function_number
reg_num = cfg_mgmt_addr
if cfg_mgmt_read_write_done:
cfg_mgmt_read_write_done.next = 0
elif cfg_mgmt_read:
cfg_mgmt_read_data.next = self.functions[function].read_config_register(reg_num)
cfg_mgmt_read_write_done.next = 1
elif cfg_mgmt_write:
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_debug_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
#cfg_phy_link_status
cfg_negotiated_width.next = min(max((self.functions[0].negotiated_link_width).bit_length()-1, 0), 4)
cfg_current_speed.next = min(max(self.functions[0].current_link_speed-1, 0), 3)
cfg_max_payload.next = self.functions[0].max_payload_size & 3
cfg_max_read_req.next = self.functions[0].max_read_request_size
status = 0
for k in range(len(self.functions)):
if self.functions[k].bus_master_enable:
status |= 0x07 << k*4
if self.functions[k].interrupt_disable:
status |= 0x08 << k*4
cfg_function_status.next = status
#cfg_vf_status
#cfg_function_power_state
#cfg_vf_power_state
#cfg_link_power_state
#cfg_err_cor_out
#cfg_err_nonfatal_out
#cfg_err_fatal_out
#cfg_local_err_out
#cfg_local_err_valid
#cfg_rx_pm_state
#cfg_tx_pm_state
#cfg_ltssm_state
status = 0
for k in range(len(self.functions)):
if self.functions[k].read_completion_boundary:
status |= 1 << k
cfg_rcb_status.next = status
#cfg_obff_enable
#cfg_pl_status_change
#cfg_tph_requester_enable
#cfg_tph_st_mode
#cfg_vf_tph_requester_enable
#cfg_vf_tph_st_mode
# configuration received message
#cfg_msg_received
#cfg_msg_received_data
#cfg_msg_received_type
# configuration transmit message
#cfg_msg_transmit
#cfg_msg_transmit_type
#cfg_msg_transmit_data
#cfg_msg_transmit_done
# configuration flow control
#cfg_fc_ph
#cfg_fc_pd
#cfg_fc_nph
#cfg_fc_npd
#cfg_fc_cplh
#cfg_fc_cpld
#cfg_fc_sel
# configuration control
#cfg_hot_reset_in
#cfg_hot_reset_out
if not sys_reset:
self.config_space_enable = False
else:
self.config_space_enable = bool(cfg_config_space_enable)
#cfg_dsn
#cfg_ds_port_number
#cfg_ds_bus_number
#cfg_ds_device_number
#cfg_ds_function_number
#cfg_power_state_change_ack
#cfg_power_state_change_interrupt
#cfg_err_cor_in
#cfg_err_uncor_in
#cfg_flr_done
#cfg_vf_flr_done
#cfg_flr_in_process
#cfg_vf_flr_in_process
#cfg_req_pm_transition_l23_ready
#cfg_link_training_enable
# configuration interrupt controller
# INTx
#cfg_interrupt_int
#cfg_interrupt_sent
#cfg_interrupt_pending
# MSI
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
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
#cfg_interrupt_msi_mask_update
if cfg_interrupt_msi_select == 0b1111:
cfg_interrupt_msi_data.next = 0
else:
if cfg_interrupt_msi_select < len(self.functions):
cfg_interrupt_msi_data.next = self.functions[cfg_interrupt_msi_select].msi_mask_bits;
else:
cfg_interrupt_msi_data.next = 0
if cfg_interrupt_msi_pending_status_data_enable:
if cfg_interrupt_msi_pending_status_function_num < len(self.functions):
self.functions[cfg_interrupt_msi_pending_status_function_num].msi_pending_bits = int(cfg_interrupt_msi_pending_status)
# MSI-X
val = 0
if self.functions[0].msix_enable:
val |= 1
if len(self.functions) > 1:
if self.functions[1].msix_enable:
val |= 2
cfg_interrupt_msix_enable.next = val
val = 0
if self.functions[0].msix_function_mask:
val |= 1
if len(self.functions) > 1:
if self.functions[1].msix_function_mask:
val |= 2
cfg_interrupt_msix_mask.next = val
#cfg_interrupt_msix_vf_enable
#cfg_interrupt_msix_vf_mask
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_msi_sent.next = 1
# 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()

925
tb/test_pcie_usp.py Executable file
View File

@ -0,0 +1,925 @@
#!/usr/bin/env python
"""
Copyright (c) 2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
from myhdl import *
import struct
import os
import axis_ep
import pcie
import pcie_usp
#pcie.trace_routing = True
def bench():
# Parameters
dw = 128
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
# Outputs
# Completer reQuest Interface
m_axis_cq_tdata=Signal(intbv(0)[dw:])
m_axis_cq_tuser=Signal(intbv(0)[88:])
m_axis_cq_tlast=Signal(bool(0))
m_axis_cq_tkeep=Signal(intbv(0)[int(dw/32):])
m_axis_cq_tvalid=Signal(bool(0))
m_axis_cq_tready=Signal(bool(0))
pcie_cq_np_req=Signal(intbv(3)[2:])
pcie_cq_np_req_count=Signal(intbv(0)[6:])
# Completer Completion Interface
s_axis_cc_tdata=Signal(intbv(0)[dw:])
s_axis_cc_tuser=Signal(intbv(0)[33:])
s_axis_cc_tlast=Signal(bool(0))
s_axis_cc_tkeep=Signal(intbv(0)[int(dw/32):])
s_axis_cc_tvalid=Signal(bool(0))
s_axis_cc_tready=Signal(bool(0))
# Requester reQuest Interface
s_axis_rq_tdata=Signal(intbv(0)[dw:])
s_axis_rq_tuser=Signal(intbv(0)[62:])
s_axis_rq_tlast=Signal(bool(0))
s_axis_rq_tkeep=Signal(intbv(0)[int(dw/32):])
s_axis_rq_tvalid=Signal(bool(0))
s_axis_rq_tready=Signal(bool(0))
pcie_rq_seq_num0=Signal(intbv(0)[6:])
pcie_rq_seq_num_vld0=Signal(bool(0))
pcie_rq_seq_num1=Signal(intbv(0)[6:])
pcie_rq_seq_num_vld1=Signal(bool(0))
pcie_rq_tag0=Signal(intbv(0)[8:])
pcie_rq_tag1=Signal(intbv(0)[8:])
pcie_rq_tag_av=Signal(intbv(0)[4:])
pcie_rq_tag_vld0=Signal(bool(0))
pcie_rq_tag_vld1=Signal(bool(0))
# Requester Completion Interface
m_axis_rc_tdata=Signal(intbv(0)[dw:])
m_axis_rc_tuser=Signal(intbv(0)[75:])
m_axis_rc_tlast=Signal(bool(0))
m_axis_rc_tkeep=Signal(intbv(0)[int(dw/32):])
m_axis_rc_tvalid=Signal(bool(0))
m_axis_rc_tready=Signal(bool(0))
# Transmit Flow Control Interface
pcie_tfc_nph_av=Signal(intbv(0)[4:])
pcie_tfc_npd_av=Signal(intbv(0)[4:])
# Configuration Management Interface
cfg_mgmt_addr=Signal(intbv(0)[10:])
cfg_mgmt_function_number=Signal(intbv(0)[8:])
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_debug_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)[3:])
cfg_current_speed=Signal(intbv(0)[2:])
cfg_max_payload=Signal(intbv(0)[2:])
cfg_max_read_req=Signal(intbv(0)[3:])
cfg_function_status=Signal(intbv(0)[16:])
cfg_vf_status=Signal(intbv(0)[504:])
cfg_function_power_state=Signal(intbv(0)[12:])
cfg_vf_power_state=Signal(intbv(0)[756:])
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_local_err_out=Signal(intbv(0)[5:])
cfg_local_err_valid=Signal(bool(0))
cfg_rx_pm_state=Signal(intbv(0)[2:])
cfg_tx_pm_state=Signal(intbv(0)[2:])
cfg_ltssm_state=Signal(intbv(0)[6:])
cfg_rcb_status=Signal(intbv(0)[4:])
cfg_obff_enable=Signal(intbv(0)[2:])
cfg_pl_status_change=Signal(bool(0))
cfg_tph_requester_enable=Signal(intbv(0)[4:])
cfg_tph_st_mode=Signal(intbv(0)[12:])
cfg_vf_tph_requester_enable=Signal(intbv(0)[252:])
cfg_vf_tph_st_mode=Signal(intbv(0)[756:])
# 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:])
# 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_dsn=Signal(intbv(0)[64:])
cfg_ds_port_number=Signal(intbv(0)[8:])
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)[4:])
cfg_vf_flr_done=Signal(intbv(0)[1:])
cfg_flr_in_process=Signal(intbv(0)[4:])
cfg_vf_flr_in_process=Signal(intbv(0)[252:])
cfg_req_pm_transition_l23_ready=Signal(bool(0))
cfg_link_training_enable=Signal(bool(1))
# Configuration Interrupt Controller Interface
cfg_interrupt_int=Signal(intbv(0)[4:])
cfg_interrupt_sent=Signal(bool(0))
cfg_interrupt_pending=Signal(intbv(0)[2:])
cfg_interrupt_msi_enable=Signal(intbv(0)[4:])
cfg_interrupt_msi_mmenable=Signal(intbv(0)[12:])
cfg_interrupt_msi_mask_update=Signal(bool(0))
cfg_interrupt_msi_data=Signal(intbv(0)[32:])
cfg_interrupt_msi_select=Signal(intbv(0)[2:])
cfg_interrupt_msi_int=Signal(intbv(0)[32:])
cfg_interrupt_msi_pending_status=Signal(intbv(0)[32:])
cfg_interrupt_msi_pending_status_data_enable=Signal(bool(0))
cfg_interrupt_msi_pending_status_function_num=Signal(intbv(0)[2:])
cfg_interrupt_msi_sent=Signal(bool(0))
cfg_interrupt_msi_fail=Signal(bool(0))
cfg_interrupt_msix_enable=Signal(intbv(0)[4:])
cfg_interrupt_msix_mask=Signal(intbv(0)[4:])
cfg_interrupt_msix_vf_enable=Signal(intbv(0)[252:])
cfg_interrupt_msix_vf_mask=Signal(intbv(0)[252:])
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_vec_pending=Signal(intbv(0)[2:])
cfg_interrupt_msix_vec_pending_status=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)[8:])
cfg_interrupt_msi_function_number=Signal(intbv(0)[8:])
# 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=Signal(bool(0))
sys_reset=Signal(bool(0))
phy_rdy_out=Signal(bool(0))
# sources and sinks
cq_sink = axis_ep.AXIStreamSink()
cq_sink_logic = cq_sink.create_logic(
user_clk,
user_reset,
tdata=m_axis_cq_tdata,
tuser=m_axis_cq_tuser,
tlast=m_axis_cq_tlast,
tkeep=m_axis_cq_tkeep,
tvalid=m_axis_cq_tvalid,
tready=m_axis_cq_tready,
name='cq_sink'
)
cc_source = axis_ep.AXIStreamSource()
cc_source_logic = cc_source.create_logic(
user_clk,
user_reset,
tdata=s_axis_cc_tdata,
tuser=s_axis_cc_tuser,
tlast=s_axis_cc_tlast,
tkeep=s_axis_cc_tkeep,
tvalid=s_axis_cc_tvalid,
tready=s_axis_cc_tready,
name='cc_source'
)
rq_source = axis_ep.AXIStreamSource()
rq_source_logic = rq_source.create_logic(
user_clk,
user_reset,
tdata=s_axis_rq_tdata,
tuser=s_axis_rq_tuser,
tlast=s_axis_rq_tlast,
tkeep=s_axis_rq_tkeep,
tvalid=s_axis_rq_tvalid,
tready=s_axis_rq_tready,
name='rq_source'
)
rc_sink = axis_ep.AXIStreamSink()
rc_sink_logic = rc_sink.create_logic(
user_clk,
user_reset,
tdata=m_axis_rc_tdata,
tuser=m_axis_rc_tuser,
tlast=m_axis_rc_tlast,
tkeep=m_axis_rc_tkeep,
tvalid=m_axis_rc_tvalid,
tready=m_axis_rc_tready,
name='rc_sink'
)
# PCIe devices
rc = pcie.RootComplex()
mem_base, mem_data = rc.alloc_region(1024*1024)
io_base, io_data = rc.alloc_io_region(1024)
dev = pcie_usp.UltrascalePlusPCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 4
dev.user_clock_frequency = 256e6
regions = [None]*6
regions[0] = bytearray(1024)
regions[1] = bytearray(1024*1024)
regions[3] = bytearray(1024)
dev.functions[0].msi_multiple_message_capable = 5
dev.functions[0].configure_bar(0, len(regions[0]))
dev.functions[0].configure_bar(1, len(regions[1]), True, True)
dev.functions[0].configure_bar(3, len(regions[3]), False, False, True)
rc.make_port().connect(dev)
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=m_axis_cq_tdata,
m_axis_cq_tuser=m_axis_cq_tuser,
m_axis_cq_tlast=m_axis_cq_tlast,
m_axis_cq_tkeep=m_axis_cq_tkeep,
m_axis_cq_tvalid=m_axis_cq_tvalid,
m_axis_cq_tready=m_axis_cq_tready,
pcie_cq_np_req=pcie_cq_np_req,
pcie_cq_np_req_count=pcie_cq_np_req_count,
# Completer Completion Interface
s_axis_cc_tdata=s_axis_cc_tdata,
s_axis_cc_tuser=s_axis_cc_tuser,
s_axis_cc_tlast=s_axis_cc_tlast,
s_axis_cc_tkeep=s_axis_cc_tkeep,
s_axis_cc_tvalid=s_axis_cc_tvalid,
s_axis_cc_tready=s_axis_cc_tready,
# Requester reQuest Interface
s_axis_rq_tdata=s_axis_rq_tdata,
s_axis_rq_tuser=s_axis_rq_tuser,
s_axis_rq_tlast=s_axis_rq_tlast,
s_axis_rq_tkeep=s_axis_rq_tkeep,
s_axis_rq_tvalid=s_axis_rq_tvalid,
s_axis_rq_tready=s_axis_rq_tready,
pcie_rq_seq_num0=pcie_rq_seq_num0,
pcie_rq_seq_num_vld0=pcie_rq_seq_num_vld0,
pcie_rq_seq_num1=pcie_rq_seq_num1,
pcie_rq_seq_num_vld1=pcie_rq_seq_num_vld1,
pcie_rq_tag0=pcie_rq_tag0,
pcie_rq_tag1=pcie_rq_tag1,
pcie_rq_tag_av=pcie_rq_tag_av,
pcie_rq_tag_vld0=pcie_rq_tag_vld0,
pcie_rq_tag_vld1=pcie_rq_tag_vld1,
# Requester Completion Interface
m_axis_rc_tdata=m_axis_rc_tdata,
m_axis_rc_tuser=m_axis_rc_tuser,
m_axis_rc_tlast=m_axis_rc_tlast,
m_axis_rc_tkeep=m_axis_rc_tkeep,
m_axis_rc_tvalid=m_axis_rc_tvalid,
m_axis_rc_tready=m_axis_rc_tready,
# Transmit Flow Control Interface
pcie_tfc_nph_av=pcie_tfc_nph_av,
pcie_tfc_npd_av=pcie_tfc_npd_av,
# Configuration Management Interface
cfg_mgmt_addr=cfg_mgmt_addr,
cfg_mgmt_function_number=cfg_mgmt_function_number,
cfg_mgmt_write=cfg_mgmt_write,
cfg_mgmt_write_data=cfg_mgmt_write_data,
cfg_mgmt_byte_enable=cfg_mgmt_byte_enable,
cfg_mgmt_read=cfg_mgmt_read,
cfg_mgmt_read_data=cfg_mgmt_read_data,
cfg_mgmt_read_write_done=cfg_mgmt_read_write_done,
cfg_mgmt_debug_access=cfg_mgmt_debug_access,
# Configuration Status Interface
cfg_phy_link_down=cfg_phy_link_down,
cfg_phy_link_status=cfg_phy_link_status,
cfg_negotiated_width=cfg_negotiated_width,
cfg_current_speed=cfg_current_speed,
cfg_max_payload=cfg_max_payload,
cfg_max_read_req=cfg_max_read_req,
cfg_function_status=cfg_function_status,
cfg_vf_status=cfg_vf_status,
cfg_function_power_state=cfg_function_power_state,
cfg_vf_power_state=cfg_vf_power_state,
cfg_link_power_state=cfg_link_power_state,
cfg_err_cor_out=cfg_err_cor_out,
cfg_err_nonfatal_out=cfg_err_nonfatal_out,
cfg_err_fatal_out=cfg_err_fatal_out,
cfg_local_err_out=cfg_local_err_out,
cfg_local_err_valid=cfg_local_err_valid,
cfg_rx_pm_state=cfg_rx_pm_state,
cfg_tx_pm_state=cfg_tx_pm_state,
cfg_ltssm_state=cfg_ltssm_state,
cfg_rcb_status=cfg_rcb_status,
cfg_obff_enable=cfg_obff_enable,
cfg_pl_status_change=cfg_pl_status_change,
cfg_tph_requester_enable=cfg_tph_requester_enable,
cfg_tph_st_mode=cfg_tph_st_mode,
cfg_vf_tph_requester_enable=cfg_vf_tph_requester_enable,
cfg_vf_tph_st_mode=cfg_vf_tph_st_mode,
# Configuration Received Message Interface
cfg_msg_received=cfg_msg_received,
cfg_msg_received_data=cfg_msg_received_data,
cfg_msg_received_type=cfg_msg_received_type,
# Configuration Transmit Message Interface
cfg_msg_transmit=cfg_msg_transmit,
cfg_msg_transmit_type=cfg_msg_transmit_type,
cfg_msg_transmit_data=cfg_msg_transmit_data,
cfg_msg_transmit_done=cfg_msg_transmit_done,
# Configuration Flow Control Interface
cfg_fc_ph=cfg_fc_ph,
cfg_fc_pd=cfg_fc_pd,
cfg_fc_nph=cfg_fc_nph,
cfg_fc_npd=cfg_fc_npd,
cfg_fc_cplh=cfg_fc_cplh,
cfg_fc_cpld=cfg_fc_cpld,
cfg_fc_sel=cfg_fc_sel,
# Configuration Control Interface
cfg_hot_reset_in=cfg_hot_reset_in,
cfg_hot_reset_out=cfg_hot_reset_out,
cfg_config_space_enable=cfg_config_space_enable,
cfg_dsn=cfg_dsn,
cfg_ds_port_number=cfg_ds_port_number,
cfg_ds_bus_number=cfg_ds_bus_number,
cfg_ds_device_number=cfg_ds_device_number,
cfg_ds_function_number=cfg_ds_function_number,
cfg_power_state_change_ack=cfg_power_state_change_ack,
cfg_power_state_change_interrupt=cfg_power_state_change_interrupt,
cfg_err_cor_in=cfg_err_cor_in,
cfg_err_uncor_in=cfg_err_uncor_in,
cfg_flr_done=cfg_flr_done,
cfg_vf_flr_done=cfg_vf_flr_done,
cfg_flr_in_process=cfg_flr_in_process,
cfg_vf_flr_in_process=cfg_vf_flr_in_process,
cfg_req_pm_transition_l23_ready=cfg_req_pm_transition_l23_ready,
cfg_link_training_enable=cfg_link_training_enable,
# Configuration Interrupt Controller Interface
cfg_interrupt_int=cfg_interrupt_int,
cfg_interrupt_sent=cfg_interrupt_sent,
cfg_interrupt_pending=cfg_interrupt_pending,
cfg_interrupt_msi_enable=cfg_interrupt_msi_enable,
cfg_interrupt_msi_mmenable=cfg_interrupt_msi_mmenable,
cfg_interrupt_msi_mask_update=cfg_interrupt_msi_mask_update,
cfg_interrupt_msi_data=cfg_interrupt_msi_data,
cfg_interrupt_msi_select=cfg_interrupt_msi_select,
cfg_interrupt_msi_int=cfg_interrupt_msi_int,
cfg_interrupt_msi_pending_status=cfg_interrupt_msi_pending_status,
cfg_interrupt_msi_pending_status_data_enable=cfg_interrupt_msi_pending_status_data_enable,
cfg_interrupt_msi_pending_status_function_num=cfg_interrupt_msi_pending_status_function_num,
cfg_interrupt_msi_sent=cfg_interrupt_msi_sent,
cfg_interrupt_msi_fail=cfg_interrupt_msi_fail,
cfg_interrupt_msix_enable=cfg_interrupt_msix_enable,
cfg_interrupt_msix_mask=cfg_interrupt_msix_mask,
cfg_interrupt_msix_vf_enable=cfg_interrupt_msix_vf_enable,
cfg_interrupt_msix_vf_mask=cfg_interrupt_msix_vf_mask,
cfg_interrupt_msix_address=cfg_interrupt_msix_address,
cfg_interrupt_msix_data=cfg_interrupt_msix_data,
cfg_interrupt_msix_int=cfg_interrupt_msix_int,
cfg_interrupt_msix_vec_pending=cfg_interrupt_msix_vec_pending,
cfg_interrupt_msix_vec_pending_status=cfg_interrupt_msix_vec_pending_status,
cfg_interrupt_msi_attr=cfg_interrupt_msi_attr,
cfg_interrupt_msi_tph_present=cfg_interrupt_msi_tph_present,
cfg_interrupt_msi_tph_type=cfg_interrupt_msi_tph_type,
cfg_interrupt_msi_tph_st_tag=cfg_interrupt_msi_tph_st_tag,
cfg_interrupt_msi_function_number=cfg_interrupt_msi_function_number,
# Configuration Extend Interface
cfg_ext_read_received=cfg_ext_read_received,
cfg_ext_write_received=cfg_ext_write_received,
cfg_ext_register_number=cfg_ext_register_number,
cfg_ext_function_number=cfg_ext_function_number,
cfg_ext_write_data=cfg_ext_write_data,
cfg_ext_write_byte_enable=cfg_ext_write_byte_enable,
cfg_ext_read_data=cfg_ext_read_data,
cfg_ext_read_data_valid=cfg_ext_read_data_valid,
# Clock and Reset Interface
user_clk=user_clk,
user_reset=user_reset,
user_lnk_up=user_lnk_up,
sys_clk=sys_clk,
sys_clk_gt=sys_clk,
sys_reset=sys_reset,
phy_rdy_out=phy_rdy_out
)
@always(delay(5))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
@instance
def user_logic():
while True:
yield clk.posedge
# handle completer request
if not cq_sink.empty():
pkt = cq_sink.recv()
tlp = pcie_usp.TLP_us().unpack_us_cq(pkt, dw)
print(tlp)
if (tlp.fmt_type == pcie.TLP_IO_READ):
print("IO read")
cpl = pcie_usp.TLP_us()
cpl.set_completion(tlp, pcie_usp.PcieId(0, 0, 0))
cpl.fmt_type = pcie.TLP_CPL_DATA
region = tlp.bar_id
addr = tlp.address & 0xffff # TODO
offset = 0
start_offset = None
mask = tlp.first_be
# perform operation
data = bytearray(4)
for k in range(4):
if mask & (1 << k):
if start_offset is None:
start_offset = offset
else:
if start_offset is not None and offset != start_offset:
data[start_offset:offset] = regions[region][addr+start_offset:addr+offset]
start_offset = None
offset += 1
if start_offset is not None and offset != start_offset:
data[start_offset:offset] = regions[region][addr+start_offset:addr+offset]
cpl.set_data(data)
cpl.byte_count = 4
cpl.length = 1
cc_source.send(cpl.pack_us_cc(dw))
elif (tlp.fmt_type == pcie.TLP_IO_WRITE):
print("IO write")
cpl = pcie_usp.TLP_us()
cpl.set_completion(tlp, pcie_usp.PcieId(0, 0, 0))
region = tlp.bar_id
addr = tlp.address & 0xffff # TODO
offset = 0
start_offset = None
mask = tlp.first_be
# perform operation
data = tlp.get_data()
for k in range(4):
if mask & (1 << k):
if start_offset is None:
start_offset = offset
else:
if start_offset is not None and offset != start_offset:
regions[region][addr+start_offset:addr+offset] = data[start_offset:offset]
start_offset = None
offset += 1
if start_offset is not None and offset != start_offset:
regions[region][addr+start_offset:addr+offset] = data[start_offset:offset]
cc_source.send(cpl.pack_us_cc(dw))
if (tlp.fmt_type == pcie.TLP_MEM_READ or tlp.fmt_type == pcie.TLP_MEM_READ_64):
print("Memory read")
# perform operation
region = tlp.bar_id
addr = tlp.address & 0xffff # TODO
offset = 0
length = tlp.length
# perform read
data = regions[region][addr:addr+length*4]
# prepare completion TLP(s)
n = 0
offset = 0
addr = tlp.address + offset
length = tlp.length*4
while n < length:
cpl = pcie_usp.TLP_us()
cpl.set_completion(tlp, pcie_usp.PcieId(0, 0, 0))
byte_length = length-n
cpl.byte_count = byte_length
byte_length = min(byte_length, 128 << dev.functions[0].max_payload_size) # max payload size
if byte_length > 128:
byte_length -= (addr + byte_length) % 128 # RCB align
byte_length = min(byte_length, 0x1000 - (addr & 0xfff)) # 4k align
cpl.lower_address = addr & 0x7f
cpl.set_data(data[offset+n:offset+n+byte_length])
print("Completion: %s" % (repr(cpl)))
cc_source.send(cpl.pack_us_cc(dw))
n += byte_length
addr += byte_length
if (tlp.fmt_type == pcie.TLP_MEM_WRITE or tlp.fmt_type == pcie.TLP_MEM_WRITE_64):
print("Memory write")
# perform operation
region = tlp.bar_id
addr = tlp.address & 0xffff # TODO
offset = 0
start_offset = None
mask = tlp.first_be
length = tlp.length
# perform write
data = tlp.get_data()
# first dword
for k in range(4):
if mask & (1 << k):
if start_offset is None:
start_offset = offset
else:
if start_offset is not None and offset != start_offset:
regions[region][addr+start_offset:addr+offset] = data[start_offset:offset]
start_offset = None
offset += 1
if length > 1:
# middle dwords
if start_offset is None:
start_offset = offset
offset += length*4
# last dword
mask = tlp.last_be
for k in range(4):
if mask & (1 << k):
if start_offset is None:
start_offset = offset
else:
if start_offset is not None and offset != start_offset:
regions[region][addr+start_offset:addr+offset] = data[start_offset:offset]
start_offset = None
offset += 1
if start_offset is not None and offset != start_offset:
regions[region][addr+start_offset:addr+offset] = data[start_offset:offset]
# haldle requester completion
#if not rc_sink.empty():
# pkt = rc_sink.recv()
@instance
def check():
yield delay(100)
yield clk.posedge
rst.next = 1
yield clk.posedge
rst.next = 0
yield clk.posedge
yield delay(100)
yield clk.posedge
current_tag = 1
yield clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate(enable_bus_mastering=True, configure_msi=True)
yield delay(100)
yield clk.posedge
print("test 2: IO and memory read/write")
current_test.next = 2
yield from rc.io_write(0x80000000, bytearray(range(16)), 100)
assert regions[3][0:16] == bytearray(range(16))
val = yield from rc.io_read(0x80000000, 16, 100)
assert val == bytearray(range(16))
yield from rc.mem_write(0x80000000, bytearray(range(16)), 100)
yield delay(100)
assert regions[0][0:16] == bytearray(range(16))
val = yield from rc.mem_read(0x80000000, 16, 100)
assert val == bytearray(range(16))
yield from rc.mem_write(0x8000000000000000, bytearray(range(16)), 100)
yield delay(100)
assert regions[1][0:16] == bytearray(range(16))
val = yield from rc.mem_read(0x8000000000000000, 16, 100)
assert val == bytearray(range(16))
yield delay(100)
# yield clk.posedge
# print("test 3: Large read/write")
# current_test.next = 3
# yield from rc.mem_write(0x8000000000000000, bytearray(range(256))*32, 100)
# yield delay(100)
# assert ep.read_region(1, 0, 256*32) == bytearray(range(256))*32
# val = yield from rc.mem_read(0x8000000000000000, 256*32, 100)
# assert val == bytearray(range(256))*32
# yield delay(100)
yield clk.posedge
print("test 4: DMA")
current_test.next = 4
#yield ep.io_write(io_base, bytearray(range(16)), 100)
data = bytearray(range(16))
addr = io_base
n = 0
while n < len(data):
tlp = pcie_usp.TLP_us()
tlp.fmt_type = pcie.TLP_IO_WRITE
tlp.requester_id = pcie_usp.PcieId(dev.bus_num, dev.device_num, 0)
tlp.tag = current_tag
first_pad = addr % 4
byte_length = min(len(data)-n, 4-first_pad)
tlp.set_be_data(addr, data[n:n+byte_length])
tlp.address = addr & ~3
current_tag = (current_tag % 31) + 1
rq_source.send(tlp.pack_us_rq(dw))
yield rc_sink.wait(100)
pkt = rc_sink.recv()
if not pkt:
raise Exception("Timeout")
cpl = pcie_usp.TLP_us().unpack_us_rc(pkt, dw)
if cpl.status != pcie.CPL_STATUS_SC:
raise Exception("Unsuccessful completion")
n += byte_length
addr += byte_length
assert io_data[0:16] == bytearray(range(16))
#val = yield from ep.io_read(io_base, 16, 100)
length = 16
data = b''
addr = io_base
n = 0
while n < length:
tlp = pcie_usp.TLP_us()
tlp.fmt_type = pcie.TLP_IO_READ
tlp.requester_id = pcie_usp.PcieId(dev.bus_num, dev.device_num, 0)
tlp.tag = current_tag
first_pad = addr % 4
byte_length = min(length-n, 4-first_pad)
tlp.set_be(addr, byte_length)
tlp.address = addr & ~3
current_tag = (current_tag % 31) + 1
rq_source.send(tlp.pack_us_rq(dw))
yield rc_sink.wait(100)
pkt = rc_sink.recv()
if not pkt:
raise Exception("Timeout")
cpl = pcie_usp.TLP_us().unpack_us_rc(pkt, dw)
if cpl.status != pcie.CPL_STATUS_SC:
raise Exception("Unsuccessful completion")
else:
d = struct.pack('<L', cpl.data[0])
data += d[first_pad:]
n += byte_length
addr += byte_length
data = data[:length]
assert val == bytearray(range(16))
#yield ep.mem_write(mem_base, bytearray(range(16)), 100)
data = bytearray(range(16))
addr = io_base
n = 0
while n < len(data):
tlp = pcie_usp.TLP_us()
if addr > 0xffffffff:
tlp.fmt_type = pcie.TLP_MEM_WRITE_64
else:
tlp.fmt_type = pcie.TLP_MEM_WRITE
tlp.requester_id = pcie_usp.PcieId(dev.bus_num, dev.device_num, 0)
tlp.tag = current_tag
first_pad = addr % 4
byte_length = len(data)-n
byte_length = min(byte_length, (128 << dev.functions[0].max_payload_size)-first_pad) # max payload size
byte_length = min(byte_length, 0x1000 - (addr & 0xfff)) # 4k align
tlp.set_be_data(addr, data[n:n+byte_length])
tlp.address = addr & ~3
current_tag = (current_tag % 31) + 1
rq_source.send(tlp.pack_us_rq(dw))
n += byte_length
addr += byte_length
yield delay(100)
assert mem_data[0:16] == bytearray(range(16))
#val = yield from ep.mem_read(mem_base, 16, 100)
length = 16
data = b''
addr = mem_base
n = 0
while n < length:
tlp = pcie_usp.TLP_us()
if addr > 0xffffffff:
tlp.fmt_type = pcie.TLP_MEM_READ_64
else:
tlp.fmt_type = pcie.TLP_MEM_READ
tlp.requester_id = pcie_usp.PcieId(dev.bus_num, dev.device_num, 0)
tlp.tag = current_tag
first_pad = addr % 4
byte_length = length-n
byte_length = min(byte_length, (128 << dev.functions[0].max_read_request_size)-first_pad) # max read request size
byte_length = min(byte_length, 0x1000 - (addr & 0xfff)) # 4k align
tlp.set_be(addr, byte_length)
tlp.address = addr & ~3
current_tag = (current_tag % 31) + 1
rq_source.send(tlp.pack_us_rq(dw))
m = 0
while m < byte_length:
yield rc_sink.wait(100)
pkt = rc_sink.recv()
if not pkt:
raise Exception("Timeout")
cpl = pcie_usp.TLP_us().unpack_us_rc(pkt, dw)
if cpl.status != pcie.CPL_STATUS_SC:
raise Exception("Unsuccessful completion")
else:
dw_len = cpl.length
if dw_len == 0:
dw_len = 1024
d = bytearray()
for k in range(dw_len):
d.extend(struct.pack('<L', cpl.data[k]))
offset = cpl.lower_address&3
data += d[offset:offset+cpl.byte_count]
m += len(d)-offset
n += byte_length
addr += byte_length
assert val == bytearray(range(16))
yield delay(100)
yield clk.posedge
print("test 5: MSI")
current_test.next = 5
yield user_clk.posedge
cfg_interrupt_msi_int.next = 1 << 4
yield user_clk.posedge
cfg_interrupt_msi_int.next = 0
yield rc.msi_get_signal(dev.functions[0].get_id(), 4)
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
os.chdir(os.path.dirname(os.path.abspath(__file__)))
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()