Initial commit

This commit is contained in:
Alex Forencich 2018-09-25 19:50:57 -07:00
commit c57ef057ee
8 changed files with 6607 additions and 0 deletions

1
AUTHORS Normal file
View File

@ -0,0 +1 @@
Alex Forencich <alex@alexforencich.com>

19
COPYING Normal file
View File

@ -0,0 +1,19 @@
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.

1
README Symbolic link
View File

@ -0,0 +1 @@
README.md

35
README.md Normal file
View File

@ -0,0 +1,35 @@
# Verilog PCI Express Components Readme
For more information and updates: http://alexforencich.com/wiki/en/verilog/pcie/start
GitHub repository: https://github.com/alexforencich/verilog-pcie
## Introduction
Collection of PCI express related components. Includes full MyHDL testbench
with intelligent bus cosimulation endpoints.
## Documentation
### PCIe BFM
A MyHDL transaction layer PCI Express bus functional model (BFM) is included in pcie.py. This BFM implements an extensive event driven simulation of a complete PCI express system, including root complex, switches, devices, and functions. The BFM includes code to enumerate the bus, initialize configuration space registers and allocate BARs, pass messages between devices, and perform memory read and write operations. Any module can be connected to a cosimulated design, enabling testing of not only isolated components but also communication between multiple components such as device-to-device DMA and message passing.
### Common signals
### Common parameters
### Source Files
## Testing
Running the included testbenches requires MyHDL and Icarus Verilog. Make sure
that myhdl.vpi is installed properly for cosimulation to work correctly. The
testbenches can be run with a Python test runner like nose or py.test, or the
individual test scripts can be run with python directly.
### Testbench Files
tb/axis_ep.py : MyHDL AXI Stream endpoints
tb/pcie.py : MyHDL PCI Express BFM
tb/pcie_us.py : MyHDL Xilinx Ultrascale PCIe core model

3834
tb/pcie.py Normal file

File diff suppressed because it is too large Load Diff

1552
tb/pcie_us.py Normal file

File diff suppressed because it is too large Load Diff

250
tb/test_pcie.py Executable file
View File

@ -0,0 +1,250 @@
#!/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 pcie
class TestEP(pcie.MemoryEndpoint):
def __init__(self, *args, **kwargs):
super(TestEP, self).__init__(*args, **kwargs)
self.vendor_id = 0x1234
self.device_id = 0x5678
self.add_mem_region(1024)
self.add_prefetchable_mem_region(1024*1024)
self.add_io_region(32)
def bench():
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
# Outputs
# PCIe devices
rc = pcie.RootComplex()
ep = TestEP()
dev = pcie.Device(ep)
rc.make_port().connect(dev)
sw = pcie.Switch()
rc.make_port().connect(sw)
ep2 = TestEP()
dev2 = pcie.Device(ep2)
sw.make_port().connect(dev2)
ep3 = TestEP()
dev3 = pcie.Device(ep3)
sw.make_port().connect(dev3)
ep4 = TestEP()
dev4 = pcie.Device(ep4)
rc.make_port().connect(dev4)
@always(delay(2))
def clkgen():
clk.next = not clk
@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
yield clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate(enable_bus_mastering=True)
# val = yield from rc.config_read((0, 1, 0), 0x000, 4)
# print(val)
# val = yield from rc.config_read((1, 0, 0), 0x000, 4)
# print(val)
# yield rc.config_write((1, 0, 0), 0x010, b'\xff'*4*6)
# val = yield from rc.config_read((1, 0, 0), 0x010, 4*6)
# print(val)
for k in range(6):
print("0x%08x / 0x%08x" %(ep.bar[k], ep.bar_mask[k]))
print(sw.upstream_bridge.pri_bus_num)
print(sw.upstream_bridge.sec_bus_num)
print(sw.upstream_bridge.sub_bus_num)
print("0x%08x" % sw.upstream_bridge.io_base)
print("0x%08x" % sw.upstream_bridge.io_limit)
print("0x%08x" % sw.upstream_bridge.mem_base)
print("0x%08x" % sw.upstream_bridge.mem_limit)
print("0x%016x" % sw.upstream_bridge.prefetchable_mem_base)
print("0x%016x" % sw.upstream_bridge.prefetchable_mem_limit)
yield delay(100)
yield clk.posedge
print("test 2: IO and memory read/write")
current_test.next = 2
yield rc.io_write(0x80000000, bytearray(range(16)), 1000)
assert ep.read_region(3, 0, 16) == bytearray(range(16))
val = yield from rc.io_read(0x80000000, 16, 1000)
assert val == bytearray(range(16))
yield rc.mem_write(0x80000000, bytearray(range(16)), 1000)
yield delay(1000)
assert ep.read_region(0, 0, 16) == bytearray(range(16))
val = yield from rc.mem_read(0x80000000, 16, 1000)
assert val == bytearray(range(16))
yield rc.mem_write(0x8000000000000000, bytearray(range(16)), 1000)
yield delay(1000)
assert ep.read_region(1, 0, 16) == bytearray(range(16))
val = yield from rc.mem_read(0x8000000000000000, 16, 1000)
assert val == bytearray(range(16))
yield delay(100)
# yield clk.posedge
# print("test 3: Large read/write")
# current_test.next = 3
# yield 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: Root complex memory")
current_test.next = 4
mem_base, mem_data = rc.alloc_region(1024*1024)
io_base, io_data = rc.alloc_io_region(1024)
yield rc.io_write(io_base, bytearray(range(16)))
assert io_data[0:16] == bytearray(range(16))
val = yield from rc.io_read(io_base, 16)
assert val == bytearray(range(16))
yield rc.mem_write(mem_base, bytearray(range(16)))
assert mem_data[0:16] == bytearray(range(16))
val = yield from rc.mem_read(mem_base, 16)
assert val == bytearray(range(16))
yield delay(100)
yield clk.posedge
print("test 5: device-to-device DMA")
current_test.next = 5
yield ep.io_write(0x80001000, bytearray(range(16)), 10000)
assert ep2.read_region(3, 0, 16) == bytearray(range(16))
val = yield from ep.io_read(0x80001000, 16, 10000)
assert val == bytearray(range(16))
yield ep.mem_write(0x80100000, bytearray(range(16)), 10000)
yield delay(1000)
assert ep2.read_region(0, 0, 16) == bytearray(range(16))
val = yield from ep.mem_read(0x80100000, 16, 10000)
assert val == bytearray(range(16))
yield ep.mem_write(0x8000000000100000, bytearray(range(16)), 10000)
yield delay(1000)
assert ep2.read_region(1, 0, 16) == bytearray(range(16))
val = yield from ep.mem_read(0x8000000000100000, 16, 10000)
assert val == bytearray(range(16))
yield delay(100)
yield clk.posedge
print("test 6: device-to-root DMA")
current_test.next = 6
yield ep.io_write(io_base, bytearray(range(16)), 1000)
assert io_data[0:16] == bytearray(range(16))
val = yield from ep.io_read(io_base, 16, 1000)
assert val == bytearray(range(16))
yield ep.mem_write(mem_base, bytearray(range(16)), 1000)
yield delay(1000)
assert mem_data[0:16] == bytearray(range(16))
val = yield from ep.mem_read(mem_base, 16, 1000)
assert val == bytearray(range(16))
yield delay(100)
val = yield from rc.capability_read((1, 0, 0), pcie.PCIE_CAP_ID, 0x000, 4)
raise StopSimulation
return instances()
def test_bench():
os.chdir(os.path.dirname(os.path.abspath(__file__)))
#sim = Simulation(bench())
traceSignals.name = os.path.basename(__file__).rsplit('.',1)[0]
sim = Simulation(traceSignals(bench))
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

915
tb/test_pcie_us.py Executable file
View File

@ -0,0 +1,915 @@
#!/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_us
#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)[85:])
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(bool(1))
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)[60:])
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_num=Signal(intbv(0)[4:])
pcie_rq_seq_num_vld=Signal(bool(0))
pcie_rq_tag=Signal(intbv(0)[6:])
pcie_rq_tag_av=Signal(intbv(0)[2:])
pcie_rq_tag_vld=Signal(bool(0))
# Requester Completion Interface
m_axis_rc_tdata=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)[2:])
pcie_tfc_npd_av=Signal(intbv(0)[2:])
# Configuration Management Interface
cfg_mgmt_addr=Signal(intbv(0)[19:])
cfg_mgmt_write=Signal(bool(0))
cfg_mgmt_write_data=Signal(intbv(0)[32:])
cfg_mgmt_byte_enable=Signal(intbv(0)[4:])
cfg_mgmt_read=Signal(bool(0))
cfg_mgmt_read_data=Signal(intbv(0)[32:])
cfg_mgmt_read_write_done=Signal(bool(0))
cfg_mgmt_type1_cfg_reg_access=Signal(bool(0))
# Configuration Status Interface
cfg_phy_link_down=Signal(bool(0))
cfg_phy_link_status=Signal(intbv(0)[2:])
cfg_negotiated_width=Signal(intbv(0)[4:])
cfg_current_speed=Signal(intbv(0)[3:])
cfg_max_payload=Signal(intbv(0)[3:])
cfg_max_read_req=Signal(intbv(0)[3:])
cfg_function_status=Signal(intbv(0)[8:])
cfg_vf_status=Signal(intbv(0)[12:])
cfg_function_power_state=Signal(intbv(0)[6:])
cfg_vf_power_state=Signal(intbv(0)[18:])
cfg_link_power_state=Signal(intbv(0)[2:])
cfg_err_cor_out=Signal(bool(0))
cfg_err_nonfatal_out=Signal(bool(0))
cfg_err_fatal_out=Signal(bool(0))
cfg_ltr_enable=Signal(bool(0))
cfg_ltssm_state=Signal(intbv(0)[6:])
cfg_rcb_status=Signal(intbv(0)[2:])
cfg_dpa_substate_change=Signal(intbv(0)[2:])
cfg_obff_enable=Signal(intbv(0)[2:])
cfg_pl_status_change=Signal(bool(0))
cfg_tph_requester_enable=Signal(intbv(0)[2:])
cfg_tph_st_mode=Signal(intbv(0)[6:])
cfg_vf_tph_requester_enable=Signal(intbv(0)[6:])
cfg_vf_tph_st_mode=Signal(intbv(0)[18:])
# Configuration Received Message Interface
cfg_msg_received=Signal(bool(0))
cfg_msg_received_data=Signal(intbv(0)[8:])
cfg_msg_received_type=Signal(intbv(0)[5:])
# Configuration Transmit Message Interface
cfg_msg_transmit=Signal(bool(0))
cfg_msg_transmit_type=Signal(intbv(0)[3:])
cfg_msg_transmit_data=Signal(intbv(0)[32:])
cfg_msg_transmit_done=Signal(bool(0))
# Configuration Flow Control Interface
cfg_fc_ph=Signal(intbv(0)[8:])
cfg_fc_pd=Signal(intbv(0)[12:])
cfg_fc_nph=Signal(intbv(0)[8:])
cfg_fc_npd=Signal(intbv(0)[12:])
cfg_fc_cplh=Signal(intbv(0)[8:])
cfg_fc_cpld=Signal(intbv(0)[12:])
cfg_fc_sel=Signal(intbv(0)[3:])
# Per-Function Status Interface
cfg_per_func_status_control=Signal(intbv(0)[3:])
cfg_per_func_status_data=Signal(intbv(0)[16:])
# Configuration Control Interface
cfg_hot_reset_in=Signal(bool(0))
cfg_hot_reset_out=Signal(bool(0))
cfg_config_space_enable=Signal(bool(1))
cfg_per_function_update_done=Signal(bool(0))
cfg_per_function_number=Signal(intbv(0)[3:])
cfg_per_function_output_request=Signal(bool(0))
cfg_dsn=Signal(intbv(0)[64:])
cfg_ds_bus_number=Signal(intbv(0)[8:])
cfg_ds_device_number=Signal(intbv(0)[5:])
cfg_ds_function_number=Signal(intbv(0)[3:])
cfg_power_state_change_ack=Signal(bool(0))
cfg_power_state_change_interrupt=Signal(bool(0))
cfg_err_cor_in=Signal(bool(0))
cfg_err_uncor_in=Signal(bool(0))
cfg_flr_done=Signal(intbv(0)[2:])
cfg_vf_flr_done=Signal(intbv(0)[6:])
cfg_flr_in_process=Signal(intbv(0)[2:])
cfg_vf_flr_in_process=Signal(intbv(0)[6:])
cfg_req_pm_transition_l23_ready=Signal(bool(0))
cfg_link_training_enable=Signal(bool(1))
# Configuration Interrupt Controller Interface
cfg_interrupt_int=Signal(intbv(0)[4:])
cfg_interrupt_sent=Signal(bool(0))
cfg_interrupt_pending=Signal(intbv(0)[2:])
cfg_interrupt_msi_enable=Signal(intbv(0)[2:])
cfg_interrupt_msi_vf_enable=Signal(intbv(0)[6:])
cfg_interrupt_msi_int=Signal(intbv(0)[32:])
cfg_interrupt_msi_sent=Signal(bool(0))
cfg_interrupt_msi_fail=Signal(bool(0))
cfg_interrupt_msi_mmenable=Signal(intbv(0)[6:])
cfg_interrupt_msi_pending_status=Signal(intbv(0)[64:])
cfg_interrupt_msi_mask_update=Signal(bool(0))
cfg_interrupt_msi_select=Signal(intbv(0)[4:])
cfg_interrupt_msi_data=Signal(intbv(0)[32:])
cfg_interrupt_msix_enable=Signal(intbv(0)[2:])
cfg_interrupt_msix_mask=Signal(intbv(0)[2:])
cfg_interrupt_msix_vf_enable=Signal(intbv(0)[6:])
cfg_interrupt_msix_vf_mask=Signal(intbv(0)[6:])
cfg_interrupt_msix_address=Signal(intbv(0)[64:])
cfg_interrupt_msix_data=Signal(intbv(0)[32:])
cfg_interrupt_msix_int=Signal(bool(0))
cfg_interrupt_msix_sent=Signal(bool(0))
cfg_interrupt_msix_fail=Signal(bool(0))
cfg_interrupt_msi_attr=Signal(intbv(0)[3:])
cfg_interrupt_msi_tph_present=Signal(bool(0))
cfg_interrupt_msi_tph_type=Signal(intbv(0)[2:])
cfg_interrupt_msi_tph_st_tag=Signal(intbv(0)[9:])
cfg_interrupt_msi_function_number=Signal(intbv(0)[3:])
# Configuration Extend Interface
cfg_ext_read_received=Signal(bool(0))
cfg_ext_write_received=Signal(bool(0))
cfg_ext_register_number=Signal(intbv(0)[10:])
cfg_ext_function_number=Signal(intbv(0)[8:])
cfg_ext_write_data=Signal(intbv(0)[32:])
cfg_ext_write_byte_enable=Signal(intbv(0)[4:])
cfg_ext_read_data=Signal(intbv(0)[32:])
cfg_ext_read_data_valid=Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
user_lnk_up=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
pcie_perstn0_out=Signal(bool(0))
pcie_perstn1_in=Signal(bool(0))
pcie_perstn1_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_us.UltrascalePCIe()
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].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_num=pcie_rq_seq_num,
pcie_rq_seq_num_vld=pcie_rq_seq_num_vld,
pcie_rq_tag=pcie_rq_tag,
pcie_rq_tag_av=pcie_rq_tag_av,
pcie_rq_tag_vld=pcie_rq_tag_vld,
# 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_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_type1_cfg_reg_access=cfg_mgmt_type1_cfg_reg_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_ltr_enable=cfg_ltr_enable,
cfg_ltssm_state=cfg_ltssm_state,
cfg_rcb_status=cfg_rcb_status,
cfg_dpa_substate_change=cfg_dpa_substate_change,
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,
# Per-Function Status Interface
cfg_per_func_status_control=cfg_per_func_status_control,
cfg_per_func_status_data=cfg_per_func_status_data,
# 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_per_function_update_done=cfg_per_function_update_done,
cfg_per_function_number=cfg_per_function_number,
cfg_per_function_output_request=cfg_per_function_output_request,
cfg_dsn=cfg_dsn,
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_vf_enable=cfg_interrupt_msi_vf_enable,
cfg_interrupt_msi_int=cfg_interrupt_msi_int,
cfg_interrupt_msi_sent=cfg_interrupt_msi_sent,
cfg_interrupt_msi_fail=cfg_interrupt_msi_fail,
cfg_interrupt_msi_mmenable=cfg_interrupt_msi_mmenable,
cfg_interrupt_msi_pending_status=cfg_interrupt_msi_pending_status,
cfg_interrupt_msi_mask_update=cfg_interrupt_msi_mask_update,
cfg_interrupt_msi_select=cfg_interrupt_msi_select,
cfg_interrupt_msi_data=cfg_interrupt_msi_data,
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_sent=cfg_interrupt_msix_sent,
cfg_interrupt_msix_fail=cfg_interrupt_msix_fail,
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,
pcie_perstn0_out=pcie_perstn0_out,
pcie_perstn1_in=pcie_perstn1_in,
pcie_perstn1_out=pcie_perstn1_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_us.TLP_us().unpack_us_cq(pkt, dw)
print(tlp)
if ((tlp.fmt, tlp.type) == pcie.TLP_IO_READ):
print("IO read")
cpl = pcie_us.TLP_us()
cpl.set_completion(tlp, (0, 0, 0))
cpl.fmt, cpl.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, tlp.type) == pcie.TLP_IO_WRITE):
print("IO write")
cpl = pcie_us.TLP_us()
cpl.set_completion(tlp, (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, tlp.type) == pcie.TLP_MEM_READ or (tlp.fmt, tlp.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_us.TLP_us()
cpl.set_completion(tlp, (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, tlp.type) == pcie.TLP_MEM_WRITE or (tlp.fmt, tlp.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)
yield delay(100)
yield clk.posedge
print("test 2: IO and memory read/write")
current_test.next = 2
yield 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 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 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 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_us.TLP_us()
tlp.fmt, tlp.type = pcie.TLP_IO_WRITE
tlp.requester_id = (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_us.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_us.TLP_us()
tlp.fmt, tlp.type = pcie.TLP_IO_READ
tlp.requester_id = (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_us.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_us.TLP_us()
if addr > 0xffffffff:
tlp.fmt, tlp.type = pcie.TLP_MEM_WRITE_64
else:
tlp.fmt, tlp.type = pcie.TLP_MEM_WRITE
tlp.requester_id = (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_us.TLP_us()
if addr > 0xffffffff:
tlp.fmt, tlp.type = pcie.TLP_MEM_READ_64
else:
tlp.fmt, tlp.type = pcie.TLP_MEM_READ
tlp.requester_id = (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_us.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)
#print(dev.functions[0].capabilities)
#print(rc.tree.children[0].children[0].capabilities)
raise StopSimulation
return instances()
def test_bench():
os.chdir(os.path.dirname(os.path.abspath(__file__)))
#sim = Simulation(bench())
traceSignals.name = os.path.basename(__file__).rsplit('.',1)[0]
sim = Simulation(traceSignals(bench))
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()