mirror of
https://github.com/corundum/corundum.git
synced 2025-02-06 08:38:23 +08:00
Add Ultrascale Plus PCIe hard IP core model and testbench
This commit is contained in:
parent
1d79a4375b
commit
f1348db2f7
998
tb/pcie_usp.py
Normal file
998
tb/pcie_usp.py
Normal 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
925
tb/test_pcie_usp.py
Executable 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()
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user