1
0
mirror of https://github.com/corundum/corundum.git synced 2025-01-30 08:32:52 +08:00

added pcie as a subproject

git-subtree-dir: fpga/lib/pcie
git-subtree-mainline: 5ad725bd0ff04fe7fe7ab9983c0c3e64355e0dd2
git-subtree-split: 1d79a4375b42a8dad274b3e0a757f833400d556e
This commit is contained in:
Alex Forencich 2019-07-15 14:55:57 -07:00
commit dcea219303
98 changed files with 34647 additions and 0 deletions

6
fpga/lib/pcie/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
*~
*.lxt
*.pyc
*.vvp
*.kate-swp

1
fpga/lib/pcie/AUTHORS Normal file
View File

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

19
fpga/lib/pcie/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
fpga/lib/pcie/README Symbolic link
View File

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

146
fpga/lib/pcie/README.md Normal file
View File

@ -0,0 +1,146 @@
# 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, including support for configuration spaces, capabilities and
extended capabilities, and memory and IO operations between devices. The BFM
includes code to enumerate the bus, initialize configuration space registers
and allocate BARs, route messages between devices, perform memory read and
write operations, allocate DMA accessible memory regions in the root complex,
and handle message signaled interrupts. Any module can be connected to a
cosimulated design, enabling testing of not only isolated components and
host-device communication but also communication between multiple components
such as device-to-device DMA and message passing.
A MyHDL model of the Xilinx Ultrascale PCIe hard core is included in
pcie_us.py. This module can be used in combination with the PCIe BFM to test
a MyHDL or Verilog design that targets a Xilinx Ultrascale FPGA. The model
currently only supports operation as a device, not as a root port.
### arbiter module
General-purpose parametrizable arbiter. Supports priority and round-robin
arbitration. Supports blocking until request release or acknowledge.
### axis_arb_mux module
Frame-aware AXI stream arbitrated muliplexer with parametrizable data width
and port count. Supports priority and round-robin arbitration.
### pcie_axi_dma_desc_mux module
Descriptor multiplexer/demultiplexer for PCIe AXI DMA module. Enables sharing
the PCIe AXI DMA module between multiple request sources, interleaving
requests and distributing responses.
### pcie_tag_manager module
PCIe in-flight tag manager.
### pcie_us_axi_dma module
PCIe AXI DMA module for Xilinx Ultrascale series FPGAs. Supports 64, 128, and 256 bit datapaths. Parametrizable AXI burst length. Wrapper for pcie_us_axi_dma_rd and pcie_us_axi_dma_wr
### pcie_us_axi_dma_rd module
PCIe AXI DMA module for Xilinx Ultrascale series FPGAs. Supports 64, 128, and 256 bit datapaths. Parametrizable AXI burst length.
### pcie_us_axi_dma_wr module
PCIe AXI DMA module for Xilinx Ultrascale series FPGAs. Supports 64, 128, and 256 bit datapaths. Parametrizable AXI burst length.
### pcie_us_axi_master module
PCIe AXI master module for Xilinx Ultrascale series FPGAs. Supports 64, 128, and 256 bit datapaths. Parametrizable AXI burst length. Wrapper for pcie_us_axi_master_rd and pcie_us_axi_master_wr.
### pcie_us_axi_master_rd module
PCIe AXI master module for Xilinx Ultrascale series FPGAs. Supports 64, 128, and 256 bit datapaths. Parametrizable AXI burst length.
### pcie_us_axi_master_wr module
PCIe AXI master module for Xilinx Ultrascale series FPGAs. Supports 64, 128, and 256 bit datapaths. Parametrizable AXI burst length.
### pcie_us_axil_master module
PCIe AXI lite master module for Xilinx Ultrascale series FPGAs. Supports 64, 128, and 256 bit PCIe interfaces.
### pcie_us_axis_cq_demux module
Demux module for Xilinx Ultrascale CQ interface. Can be used to route
incoming requests based on function, BAR, and other fields. Supports 64, 128,
and 256 bit datapaths.
### pcie_us_axis_rc_demux module
Demux module for Xilinx Ultrascale RC interface. Can be used to route
incoming completions based on the requester ID (function). Supports 64, 128,
and 256 bit datapaths.
### pcie_us_cfg module
Configuration shim for Xilinx Ultrascale series FPGAs.
### pcie_us_msi module
MSI shim for Xilinx Ultrascale series FPGAs.
### priority_encoder module
Parametrizable priority encoder.
### pulse_merge module
Parametrizable pulse merge module. Combines several single-cycle pulse status
signals together.
### Common signals
### Common parameters
### Source Files
arbiter.v : Parametrizable arbiter
axis_arb_mux.v : Parametrizable AXI stream mux
pcie_axi_dma_desc_mux.v : Descriptor mux for DMA engine
pcie_tag_manager.v : PCIe in-flight tag manager
pcie_us_axi_dma.v : PCIe AXI DMA module with Xilinx Ultrascale interface
pcie_us_axi_dma_rd.v : PCIe AXI DMA read module with Xilinx Ultrascale interface
pcie_us_axi_dma_wr.v : PCIe AXI DMA write module with Xilinx Ultrascale interface
pcie_us_axi_master.v : AXI Master module with Xilinx Ultrascale interface
pcie_us_axi_master_rd.v : AXI Master read module with Xilinx Ultrascale interface
pcie_us_axi_master_wr.v : AXI Master write module with Xilinx Ultrascale interface
pcie_us_axil_master.v : AXI Lite Master module with Xilinx Ultrascale interface
pcie_us_axis_cq_demux.v : Parametrizable AXI stream CQ demux
pcie_us_axis_rc_demux.v : Parametrizable AXI stream RC demux
pcie_us_cfg.v : Configuration shim for Xilinx Ultrascale devices
pcie_us_msi.v : MSI shim for Xilinx Ultrascale devices
priority_encoder.v : Parametrizable priority encoder
pulse_merge : Parametrizable pulse merge module
## 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

View File

@ -0,0 +1,25 @@
# Targets
TARGETS:=
# Subdirectories
SUBDIRS = fpga
SUBDIRS_CLEAN = $(patsubst %,%.clean,$(SUBDIRS))
# Rules
.PHONY: all
all: $(SUBDIRS) $(TARGETS)
.PHONY: $(SUBDIRS)
$(SUBDIRS):
cd $@ && $(MAKE)
.PHONY: $(SUBDIRS_CLEAN)
$(SUBDIRS_CLEAN):
cd $(@:.clean=) && $(MAKE) clean
.PHONY: clean
clean: $(SUBDIRS_CLEAN)
-rm -rf $(TARGETS)
program:
#djtgcfg prog -d Atlys --index 0 --file fpga/fpga.bit

View File

@ -0,0 +1,26 @@
# Verilog Ethernet ExaNIC X10 Example Design
## Introduction
This example design targets the Exablaze ExaNIC X10 FPGA board.
The design implements the PCIe AXI lite master module, the PCIe AXI master
module, and the PCIe AXI DMA module. A very simple Linux driver is included
to test the FPGA design.
FPGA: xcku035-fbva676-2-c
## How to build
Run make to build. Ensure that the Xilinx Vivado toolchain components are
in PATH.
Run make to build the driver. Ensure the headers for the running kernel are
installed, otherwise the driver cannot be compiled.
## How to test
Run make program to program the ExaNIC X10 board with Vivado. Then load the
driver with insmod example.ko. Check dmesg for the output.

View File

@ -0,0 +1,118 @@
###################################################################
#
# Xilinx Vivado FPGA Makefile
#
# Copyright (c) 2016 Alex Forencich
#
###################################################################
#
# Parameters:
# FPGA_TOP - Top module name
# FPGA_FAMILY - FPGA family (e.g. VirtexUltrascale)
# FPGA_DEVICE - FPGA device (e.g. xcvu095-ffva2104-2-e)
# SYN_FILES - space-separated list of source files
# INC_FILES - space-separated list of include files
# XDC_FILES - space-separated list of timing constraint files
# XCI_FILES - space-separated list of IP XCI files
#
# Example:
#
# FPGA_TOP = fpga
# FPGA_FAMILY = VirtexUltrascale
# FPGA_DEVICE = xcvu095-ffva2104-2-e
# SYN_FILES = rtl/fpga.v
# XDC_FILES = fpga.xdc
# XCI_FILES = ip/pcspma.xci
# include ../common/vivado.mk
#
###################################################################
# phony targets
.PHONY: clean fpga
# prevent make from deleting intermediate files and reports
.PRECIOUS: %.xpr %.bit %.mcs %.prm
.SECONDARY:
CONFIG ?= config.mk
-include ../$(CONFIG)
SYN_FILES_REL = $(patsubst %, ../%, $(SYN_FILES))
INC_FILES_REL = $(patsubst %, ../%, $(INC_FILES))
XCI_FILES_REL = $(patsubst %, ../%, $(XCI_FILES))
ifdef XDC_FILES
XDC_FILES_REL = $(patsubst %, ../%, $(XDC_FILES))
else
XDC_FILES_REL = $(FPGA_TOP).xdc
endif
###################################################################
# Main Targets
#
# all: build everything
# clean: remove output files and project files
###################################################################
all: fpga
fpga: $(FPGA_TOP).bit
tmpclean:
-rm -rf *.log *.jou *.cache *.hw *.ip_user_files *.runs *.xpr *.html *.xml *.sim *.srcs *.str .Xil defines.v
-rm -rf create_project.tcl run_synth.tcl run_impl.tcl generate_bit.tcl
clean: tmpclean
-rm -rf *.bit program.tcl generate_mcs.tcl *.mcs *.prm flash.tcl
distclean: clean
-rm -rf rev
###################################################################
# Target implementations
###################################################################
# Vivado project file
%.xpr: Makefile $(XCI_FILES_REL)
rm -rf defines.v
touch defines.v
for x in $(DEFS); do echo '`define' $$x >> defines.v; done
echo "create_project -force -part $(FPGA_PART) $*" > create_project.tcl
echo "add_files -fileset sources_1 defines.v" >> create_project.tcl
for x in $(SYN_FILES_REL); do echo "add_files -fileset sources_1 $$x" >> create_project.tcl; done
for x in $(XDC_FILES_REL); do echo "add_files -fileset constrs_1 $$x" >> create_project.tcl; done
for x in $(XCI_FILES_REL); do echo "import_ip $$x" >> create_project.tcl; done
echo "exit" >> create_project.tcl
vivado -nojournal -nolog -mode batch -source create_project.tcl
# synthesis run
%.runs/synth_1/%.dcp: %.xpr $(SYN_FILES_REL) $(INC_FILES_REL) $(XDC_FILES_REL)
echo "open_project $*.xpr" > run_synth.tcl
echo "reset_run synth_1" >> run_synth.tcl
echo "launch_runs synth_1" >> run_synth.tcl
echo "wait_on_run synth_1" >> run_synth.tcl
echo "exit" >> run_synth.tcl
vivado -nojournal -nolog -mode batch -source run_synth.tcl
# implementation run
%.runs/impl_1/%_routed.dcp: %.runs/synth_1/%.dcp
echo "open_project $*.xpr" > run_impl.tcl
echo "reset_run impl_1" >> run_impl.tcl
echo "launch_runs impl_1" >> run_impl.tcl
echo "wait_on_run impl_1" >> run_impl.tcl
echo "exit" >> run_impl.tcl
vivado -nojournal -nolog -mode batch -source run_impl.tcl
# bit file
%.bit: %.runs/impl_1/%_routed.dcp
echo "open_project $*.xpr" > generate_bit.tcl
echo "open_run impl_1" >> generate_bit.tcl
echo "write_bitstream -force $*.bit" >> generate_bit.tcl
echo "exit" >> generate_bit.tcl
vivado -nojournal -nolog -mode batch -source generate_bit.tcl
mkdir -p rev
EXT=bit; COUNT=100; \
while [ -e rev/$*_rev$$COUNT.$$EXT ]; \
do COUNT=$$((COUNT+1)); done; \
cp $@ rev/$*_rev$$COUNT.$$EXT; \
echo "Output: rev/$*_rev$$COUNT.$$EXT";

View File

@ -0,0 +1,11 @@
# object files to build
obj-m += example.o
example-objs += example_driver.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

View File

@ -0,0 +1,371 @@
/*
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.
*/
#include "example_driver.h"
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci-aspm.h>
#include <linux/delay.h>
MODULE_DESCRIPTION("verilog-pcie example driver");
MODULE_AUTHOR("Alex Forencich");
MODULE_LICENSE("Dual MIT/GPL");
MODULE_VERSION(DRIVER_VERSION);
MODULE_SUPPORTED_DEVICE(DRIVER_NAME);
static int edev_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
static void edev_remove(struct pci_dev *pdev);
static void edev_shutdown(struct pci_dev *pdev);
static int enumerate_bars(struct example_dev *edev, struct pci_dev *pdev);
static int map_bars(struct example_dev *edev, struct pci_dev *pdev);
static void free_bars(struct example_dev *edev, struct pci_dev *pdev);
static const struct pci_device_id pci_ids[] = {
{ PCI_DEVICE(0x1234, 0x0001) },
{ 0 /* end */ }
};
MODULE_DEVICE_TABLE(pci, pci_ids);
static irqreturn_t edev_intr(int irq, void *data)
{
struct example_dev *edev = data;
struct device *dev = &edev->pdev->dev;
edev->irqcount++;
dev_info(dev, "Interrupt");
return IRQ_HANDLED;
}
static int edev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int ret = 0;
struct example_dev *edev;
struct device *dev = &pdev->dev;
int k;
dev_info(dev, "edev probe");
dev_info(dev, " vendor: 0x%04x", pdev->vendor);
dev_info(dev, " device: 0x%04x", pdev->device);
dev_info(dev, " class: 0x%06x", pdev->class);
dev_info(dev, " pci id: %02x:%02x.%02x", pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
if (!(edev = devm_kzalloc(dev, sizeof(struct example_dev), GFP_KERNEL))) {
return -ENOMEM;
}
edev->pdev = pdev;
pci_set_drvdata(pdev, edev);
// Allocate DMA buffer
edev->dma_region_len = 16*1024;
edev->dma_region = dma_alloc_coherent(dev, edev->dma_region_len, &edev->dma_region_addr, GFP_KERNEL | __GFP_ZERO);
if (!edev->dma_region)
{
dev_err(dev, "Failed to allocate DMA buffer");
ret = -ENOMEM;
goto fail_dma_alloc;
}
dev_info(dev, "Allocated DMA region virt %p, phys %p", edev->dma_region, (void *)edev->dma_region_addr);
// Disable ASPM
pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM);
// Enable device
ret = pci_enable_device_mem(pdev);
if (ret)
{
dev_err(dev, "Failed to enable PCI device");
//ret = -ENODEV;
goto fail_enable_device;
}
// Enable bus mastering for DMA
pci_set_master(pdev);
// Reserve regions
ret = pci_request_regions(pdev, DRIVER_NAME);
if (ret)
{
dev_err(dev, "Failed to reserve regions");
//ret = -EBUSY;
goto fail_regions;
}
// Enumerate BARs
enumerate_bars(edev, pdev);
// Map BARs
ret = map_bars(edev, pdev);
if (ret)
{
dev_err(dev, "Failed to map BARs");
goto fail_map_bars;
}
// Allocate MSI IRQs
ret = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
if (ret < 0)
{
dev_err(dev, "Failed to allocate IRQs");
goto fail_map_bars;
}
// Set up interrupt
ret = pci_request_irq(pdev, 0, edev_intr, 0, edev, "edev");
if (ret < 0)
{
dev_err(dev, "Failed to request IRQ");
goto fail_irq;
}
// Dump counters
dev_info(dev, "TLP counters");
dev_info(dev, "RQ: %d", ioread32(edev->bar[0]+0x000400));
dev_info(dev, "RC: %d", ioread32(edev->bar[0]+0x000404));
dev_info(dev, "CQ: %d", ioread32(edev->bar[0]+0x000408));
dev_info(dev, "CC: %d", ioread32(edev->bar[0]+0x00040C));
// Read/write test
dev_info(dev, "write to BAR1");
iowrite32(0x11223344, edev->bar[1]);
dev_info(dev, "read from BAR1");
dev_info(dev, "%08x", ioread32(edev->bar[1]));
// Dump counters
dev_info(dev, "TLP counters");
dev_info(dev, "RQ: %d", ioread32(edev->bar[0]+0x000400));
dev_info(dev, "RC: %d", ioread32(edev->bar[0]+0x000404));
dev_info(dev, "CQ: %d", ioread32(edev->bar[0]+0x000408));
dev_info(dev, "CC: %d", ioread32(edev->bar[0]+0x00040C));
// PCIe DMA test
dev_info(dev, "write test data");
for (k = 0; k < 256; k++)
{
((char *)edev->dma_region)[k] = k;
}
dev_info(dev, "read test data");
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, edev->dma_region, 256, true);
dev_info(dev, "check DMA enable");
dev_info(dev, "%08x", ioread32(edev->bar[0]+0x000000));
dev_info(dev, "enable DMA");
iowrite32(0x1, edev->bar[0]+0x000000);
dev_info(dev, "check DMA enable");
dev_info(dev, "%08x", ioread32(edev->bar[0]+0x000000));
dev_info(dev, "start copy to card");
iowrite32((edev->dma_region_addr+0x0000)&0xffffffff, edev->bar[0]+0x000100);
iowrite32(((edev->dma_region_addr+0x0000) >> 32)&0xffffffff, edev->bar[0]+0x000104);
iowrite32(0x100, edev->bar[0]+0x000108);
iowrite32(0, edev->bar[0]+0x00010C);
iowrite32(0x100, edev->bar[0]+0x000110);
iowrite32(0xAA, edev->bar[0]+0x000114);
msleep(1);
dev_info(dev, "Read status");
dev_info(dev, "%08x", ioread32(edev->bar[0]+0x000118));
dev_info(dev, "start copy to host");
iowrite32((edev->dma_region_addr+0x0200)&0xffffffff, edev->bar[0]+0x000200);
iowrite32(((edev->dma_region_addr+0x0200) >> 32)&0xffffffff, edev->bar[0]+0x000204);
iowrite32(0x100, edev->bar[0]+0x000208);
iowrite32(0, edev->bar[0]+0x00020C);
iowrite32(0x100, edev->bar[0]+0x000210);
iowrite32(0x55, edev->bar[0]+0x000214);
msleep(1);
dev_info(dev, "Read status");
dev_info(dev, "%08x", ioread32(edev->bar[0]+0x000218));
dev_info(dev, "read test data");
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, edev->dma_region+0x0200, 256, true);
// Dump counters
dev_info(dev, "TLP counters");
dev_info(dev, "RQ: %d", ioread32(edev->bar[0]+0x000400));
dev_info(dev, "RC: %d", ioread32(edev->bar[0]+0x000404));
dev_info(dev, "CQ: %d", ioread32(edev->bar[0]+0x000408));
dev_info(dev, "CC: %d", ioread32(edev->bar[0]+0x00040C));
// probe complete
return 0;
// error handling
fail_irq:
pci_free_irq_vectors(pdev);
fail_map_bars:
free_bars(edev, pdev);
pci_release_regions(pdev);
fail_regions:
pci_clear_master(pdev);
pci_disable_device(pdev);
fail_enable_device:
dma_free_coherent(dev, edev->dma_region_len, edev->dma_region, edev->dma_region_addr);
fail_dma_alloc:
return ret;
}
static void edev_remove(struct pci_dev *pdev)
{
struct example_dev *edev;
struct device *dev = &pdev->dev;
dev_info(dev, "edev remove");
if (!(edev = pci_get_drvdata(pdev))) {
return;
}
pci_free_irq(pdev, 0, edev);
pci_free_irq_vectors(pdev);
free_bars(edev, pdev);
pci_release_regions(pdev);
pci_clear_master(pdev);
pci_disable_device(pdev);
dma_free_coherent(dev, edev->dma_region_len, edev->dma_region, edev->dma_region_addr);
}
static void edev_shutdown(struct pci_dev *pdev)
{
struct example_dev *edev = pci_get_drvdata(pdev);
struct device *dev = &pdev->dev;
dev_info(dev, "edev shutdown");
if (!edev) {
return;
}
// ensure DMA is disabled on shutdown
pci_clear_master(pdev);
}
static int enumerate_bars(struct example_dev *edev, struct pci_dev *pdev)
{
struct device *dev = &pdev->dev;
int i;
for (i = 0; i < DEV_BAR_CNT; i++)
{
resource_size_t bar_start = pci_resource_start(pdev, i);
if (bar_start)
{
resource_size_t bar_end = pci_resource_end(pdev, i);
unsigned long bar_flags = pci_resource_flags(pdev, i);
dev_info(dev, "BAR[%d] 0x%08llx-0x%08llx flags 0x%08lx",
i, bar_start, bar_end, bar_flags);
}
}
return 0;
}
static int map_bars(struct example_dev *edev, struct pci_dev *pdev)
{
struct device *dev = &pdev->dev;
int i;
for (i = 0; i < DEV_BAR_CNT; i++)
{
resource_size_t bar_start = pci_resource_start(pdev, i);
resource_size_t bar_end = pci_resource_end(pdev, i);
resource_size_t bar_len = bar_end - bar_start + 1;
edev->bar_len[i] = bar_len;
if (!bar_start || !bar_end)
{
edev->bar_len[i] = 0;
continue;
}
if (bar_len < 1)
{
dev_warn(dev, "BAR[%d] is less than 1 byte", i);
continue;
}
edev->bar[i] = pci_ioremap_bar(pdev, i);
if (!edev->bar[i])
{
dev_err(dev, "Could not map BAR[%d]", i);
return -1;
}
dev_info(dev, "BAR[%d] mapped at 0x%p with length %llu", i, edev->bar[i], bar_len);
}
return 0;
}
static void free_bars(struct example_dev *edev, struct pci_dev *pdev)
{
struct device *dev = &pdev->dev;
int i;
for (i = 0; i < DEV_BAR_CNT; i++)
{
if (edev->bar[i])
{
pci_iounmap(pdev, edev->bar[i]);
edev->bar[i] = NULL;
dev_info(dev, "Unmapped BAR[%d]", i);
}
}
}
static struct pci_driver pci_driver = {
.name = DRIVER_NAME,
.id_table = pci_ids,
.probe = edev_probe,
.remove = edev_remove,
.shutdown = edev_shutdown
};
static int __init edev_init(void)
{
return pci_register_driver(&pci_driver);
}
static void __exit edev_exit(void)
{
pci_unregister_driver(&pci_driver);
}
module_init(edev_init);
module_exit(edev_exit);

View File

@ -0,0 +1,50 @@
/*
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.
*/
#ifndef EXAMPLE_DRIVER_H
#define EXAMPLE_DRIVER_H
#include <linux/kernel.h>
#define DRIVER_NAME "edev"
#define DRIVER_VERSION "0.1"
#define DEV_BAR_CNT 2
struct example_dev {
struct pci_dev *pdev;
// BAR pointers
void * __iomem bar[DEV_BAR_CNT];
resource_size_t bar_len[DEV_BAR_CNT];
// DMA buffer
size_t dma_region_len;
void *dma_region;
dma_addr_t dma_region_addr;
int irqcount;
};
#endif /* EXAMPLE_DRIVER_H */

View File

@ -0,0 +1,153 @@
# XDC constraints for the ExaNIC X10
# part: xcku035-fbva676-2-e
# General configuration
set_property CFGBVS GND [current_design]
set_property CONFIG_VOLTAGE 1.8 [current_design]
set_property BITSTREAM.GENERAL.COMPRESS true [current_design]
set_property BITSTREAM.CONFIG.UNUSEDPIN Pullup [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]
set_property BITSTREAM.CONFIG.BPI_SYNC_MODE Type2 [current_design]
set_property CONFIG_MODE BPI16 [current_design]
# 100 MHz system clock
#set_property -dict {LOC D18 IOSTANDARD LVDS} [get_ports clk_100mhz_p]
#set_property -dict {LOC C18 IOSTANDARD LVDS} [get_ports clk_100mhz_n]
#create_clock -period 10 -name clk_100mhz [get_ports clk_100mhz_p]
# LEDs
set_property -dict {LOC A25 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {sfp_1_led[0]}]
set_property -dict {LOC A24 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {sfp_1_led[1]}]
set_property -dict {LOC E23 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {sfp_2_led[0]}]
set_property -dict {LOC D26 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {sfp_2_led[1]}]
set_property -dict {LOC C23 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {sma_led[0]}]
set_property -dict {LOC D23 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {sma_led[1]}]
# GPIO
#set_property -dict {LOC W26 IOSTANDARD LVCMOS18} [get_ports gpio[0]]
#set_property -dict {LOC Y26 IOSTANDARD LVCMOS18} [get_ports gpio[1]]
#set_property -dict {LOC AB26 IOSTANDARD LVCMOS18} [get_ports gpio[2]]
#set_property -dict {LOC AC26 IOSTANDARD LVCMOS18} [get_ports gpio[3]]
# SMA
#set_property -dict {LOC B17 IOSTANDARD LVCMOS18} [get_ports sma_in]
#set_property -dict {LOC B16 IOSTANDARD LVCMOS18} [get_ports sma_out]
#set_property -dict {LOC B19 IOSTANDARD LVCMOS18} [get_ports sma_out_en]
#set_property -dict {LOC C16 IOSTANDARD LVCMOS18} [get_ports sma_term_en]
# SFP+ Interface
#set_property -dict {LOC D2 } [get_ports sfp_1_rx_p] ;# MGTHTXN0_227 GTHE3_CHANNEL_X0Y12 / GTHE3_COMMON_X0Y3
#set_property -dict {LOC D1 } [get_ports sfp_1_rx_n] ;# MGTHTXP0_227 GTHE3_CHANNEL_X0Y12 / GTHE3_COMMON_X0Y3
#set_property -dict {LOC E4 } [get_ports sfp_1_tx_p] ;# MGTHTXN0_227 GTHE3_CHANNEL_X0Y12 / GTHE3_COMMON_X0Y3
#set_property -dict {LOC E3 } [get_ports sfp_1_tx_n] ;# MGTHTXP0_227 GTHE3_CHANNEL_X0Y12 / GTHE3_COMMON_X0Y3
#set_property -dict {LOC C4 } [get_ports sfp_2_rx_p] ;# MGTHTXN1_227 GTHE3_CHANNEL_X0Y13 / GTHE3_COMMON_X0Y3
#set_property -dict {LOC C3 } [get_ports sfp_2_rx_n] ;# MGTHTXP1_227 GTHE3_CHANNEL_X0Y13 / GTHE3_COMMON_X0Y3
#set_property -dict {LOC D6 } [get_ports sfp_2_tx_p] ;# MGTHTXN1_227 GTHE3_CHANNEL_X0Y13 / GTHE3_COMMON_X0Y3
#set_property -dict {LOC D5 } [get_ports sfp_2_tx_n] ;# MGTHTXP1_227 GTHE3_CHANNEL_X0Y13 / GTHE3_COMMON_X0Y3
#set_property -dict {LOC H6 } [get_ports sfp_mgt_refclk_p] ;# MGTREFCLK0P_227 from X2
#set_property -dict {LOC H5 } [get_ports sfp_mgt_refclk_n] ;# MGTREFCLK0N_227 from X2
#set_property -dict {LOC AA12 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports sfp_1_tx_disable]
#set_property -dict {LOC W14 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports sfp_2_tx_disable]
#set_property -dict {LOC C24 IOSTANDARD LVCMOS18 PULLUP true} [get_ports sfp_1_npres]
#set_property -dict {LOC D24 IOSTANDARD LVCMOS18 PULLUP true} [get_ports sfp_2_npres]
#set_property -dict {LOC W13 IOSTANDARD LVCMOS18 PULLUP true} [get_ports sfp_1_los]
#set_property -dict {LOC AB12 IOSTANDARD LVCMOS18 PULLUP true} [get_ports sfp_2_los]
#set_property -dict {LOC B25 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports sfp_1_rs]
#set_property -dict {LOC D25 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports sfp_2_rs]
#set_property -dict {LOC W11 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12 PULLUP true} [get_ports sfp_i2c_scl]
#set_property -dict {LOC Y11 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12 PULLUP true} [get_ports sfp_1_i2c_sda]
#set_property -dict {LOC Y13 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12 PULLUP true} [get_ports sfp_2_i2c_sda]
# 161.1328125 MHz MGT reference clock
#create_clock -period 6.206 -name sfp_mgt_refclk [get_ports sfp_mgt_refclk_p]
# I2C interface
#set_property -dict {LOC B26 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12 PULLUP true} [get_ports eeprom_i2c_scl]
#set_property -dict {LOC C26 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12 PULLUP true} [get_ports eeprom_i2c_sda]
# PCIe Interface
set_property -dict {LOC AF2 } [get_ports {pcie_rx_p[7]}] ;# MGTHTXN0_224 GTHE3_CHANNEL_X0Y0 / GTHE3_COMMON_X0Y0
#set_property -dict {LOC AF1 } [get_ports {pcie_rx_n[7]}] ;# MGTHTXP0_224 GTHE3_CHANNEL_X0Y0 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AF6 } [get_ports {pcie_tx_p[7]}] ;# MGTHTXN0_224 GTHE3_CHANNEL_X0Y0 / GTHE3_COMMON_X0Y0
#set_property -dict {LOC AF5 } [get_ports {pcie_tx_n[7]}] ;# MGTHTXP0_224 GTHE3_CHANNEL_X0Y0 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AE4 } [get_ports {pcie_rx_p[6]}] ;# MGTHTXN1_224 GTHE3_CHANNEL_X0Y1 / GTHE3_COMMON_X0Y0
#set_property -dict {LOC AE3 } [get_ports {pcie_rx_n[6]}] ;# MGTHTXP1_224 GTHE3_CHANNEL_X0Y1 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AD6 } [get_ports {pcie_tx_p[6]}] ;# MGTHTXN1_224 GTHE3_CHANNEL_X0Y1 / GTHE3_COMMON_X0Y0
#set_property -dict {LOC AD5 } [get_ports {pcie_tx_n[6]}] ;# MGTHTXP1_224 GTHE3_CHANNEL_X0Y1 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AD2 } [get_ports {pcie_rx_p[5]}] ;# MGTHTXN2_224 GTHE3_CHANNEL_X0Y2 / GTHE3_COMMON_X0Y0
#set_property -dict {LOC AD1 } [get_ports {pcie_rx_n[5]}] ;# MGTHTXP2_224 GTHE3_CHANNEL_X0Y2 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AC4 } [get_ports {pcie_tx_p[5]}] ;# MGTHTXN2_224 GTHE3_CHANNEL_X0Y2 / GTHE3_COMMON_X0Y0
#set_property -dict {LOC AC3 } [get_ports {pcie_tx_n[5]}] ;# MGTHTXP2_224 GTHE3_CHANNEL_X0Y2 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AB2 } [get_ports {pcie_rx_p[4]}] ;# MGTHTXN3_224 GTHE3_CHANNEL_X0Y3 / GTHE3_COMMON_X0Y0
#set_property -dict {LOC AB1 } [get_ports {pcie_rx_n[4]}] ;# MGTHTXP3_224 GTHE3_CHANNEL_X0Y3 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AB6 } [get_ports {pcie_tx_p[4]}] ;# MGTHTXN3_224 GTHE3_CHANNEL_X0Y3 / GTHE3_COMMON_X0Y0
#set_property -dict {LOC AB5 } [get_ports {pcie_tx_n[4]}] ;# MGTHTXP3_224 GTHE3_CHANNEL_X0Y3 / GTHE3_COMMON_X0Y0
set_property -dict {LOC Y2 } [get_ports {pcie_rx_p[3]}] ;# MGTHTXN0_225 GTHE3_CHANNEL_X0Y4 / GTHE3_COMMON_X0Y1
#set_property -dict {LOC Y1 } [get_ports {pcie_rx_n[3]}] ;# MGTHTXP0_225 GTHE3_CHANNEL_X0Y4 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AA4 } [get_ports {pcie_tx_p[3]}] ;# MGTHTXN0_225 GTHE3_CHANNEL_X0Y4 / GTHE3_COMMON_X0Y1
#set_property -dict {LOC AA3 } [get_ports {pcie_tx_n[3]}] ;# MGTHTXP0_225 GTHE3_CHANNEL_X0Y4 / GTHE3_COMMON_X0Y1
set_property -dict {LOC V2 } [get_ports {pcie_rx_p[2]}] ;# MGTHTXN1_225 GTHE3_CHANNEL_X0Y5 / GTHE3_COMMON_X0Y1
#set_property -dict {LOC V1 } [get_ports {pcie_rx_n[2]}] ;# MGTHTXP1_225 GTHE3_CHANNEL_X0Y5 / GTHE3_COMMON_X0Y1
set_property -dict {LOC W4 } [get_ports {pcie_tx_p[2]}] ;# MGTHTXN1_225 GTHE3_CHANNEL_X0Y5 / GTHE3_COMMON_X0Y1
#set_property -dict {LOC W3 } [get_ports {pcie_tx_n[2]}] ;# MGTHTXP1_225 GTHE3_CHANNEL_X0Y5 / GTHE3_COMMON_X0Y1
set_property -dict {LOC T2 } [get_ports {pcie_rx_p[1]}] ;# MGTHTXN2_225 GTHE3_CHANNEL_X0Y6 / GTHE3_COMMON_X0Y1
#set_property -dict {LOC T1 } [get_ports {pcie_rx_n[1]}] ;# MGTHTXP2_225 GTHE3_CHANNEL_X0Y6 / GTHE3_COMMON_X0Y1
set_property -dict {LOC U4 } [get_ports {pcie_tx_p[1]}] ;# MGTHTXN2_225 GTHE3_CHANNEL_X0Y6 / GTHE3_COMMON_X0Y1
#set_property -dict {LOC U3 } [get_ports {pcie_tx_n[1]}] ;# MGTHTXP2_225 GTHE3_CHANNEL_X0Y6 / GTHE3_COMMON_X0Y1
set_property -dict {LOC P2 } [get_ports {pcie_rx_p[0]}] ;# MGTHTXN3_225 GTHE3_CHANNEL_X0Y7 / GTHE3_COMMON_X0Y1
#set_property -dict {LOC P1 } [get_ports {pcie_rx_n[0]}] ;# MGTHTXP3_225 GTHE3_CHANNEL_X0Y7 / GTHE3_COMMON_X0Y1
set_property -dict {LOC R4 } [get_ports {pcie_tx_p[0]}] ;# MGTHTXN3_225 GTHE3_CHANNEL_X0Y7 / GTHE3_COMMON_X0Y1
#set_property -dict {LOC R3 } [get_ports {pcie_tx_n[0]}] ;# MGTHTXP3_225 GTHE3_CHANNEL_X0Y7 / GTHE3_COMMON_X0Y1
set_property -dict {LOC T6 } [get_ports pcie_mgt_refclk_p] ;# MGTREFCLK0P_225
#set_property -dict {LOC T5 } [get_ports pcie_mgt_refclk_n] ;# MGTREFCLK0N_225
set_property -dict {LOC AC22 IOSTANDARD LVCMOS18 PULLUP true} [get_ports pcie_reset_n]
# 100 MHz MGT reference clock
create_clock -period 10 -name pcie_mgt_refclk [get_ports pcie_mgt_refclk_p]
# Flash
#set_property -dict {LOC AE10 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[0]}]
#set_property -dict {LOC AC8 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[1]}]
#set_property -dict {LOC AD10 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[2]}]
#set_property -dict {LOC AD9 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[3]}]
#set_property -dict {LOC AC11 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[4]}]
#set_property -dict {LOC AF10 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[5]}]
#set_property -dict {LOC AF14 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[6]}]
#set_property -dict {LOC AE12 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[7]}]
#set_property -dict {LOC AD14 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[8]}]
#set_property -dict {LOC AF13 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[9]}]
#set_property -dict {LOC AE13 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[10]}]
#set_property -dict {LOC AD8 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[11]}]
#set_property -dict {LOC AC13 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[12]}]
#set_property -dict {LOC AD13 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[13]}]
#set_property -dict {LOC AA14 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[14]}]
#set_property -dict {LOC AB15 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[15]}]
#set_property -dict {LOC AD11 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[0]}]
#set_property -dict {LOC AE11 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[1]}]
#set_property -dict {LOC AF12 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[2]}]
#set_property -dict {LOC AB11 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[3]}]
#set_property -dict {LOC AB9 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[4]}]
#set_property -dict {LOC AB14 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[5]}]
#set_property -dict {LOC AA10 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[6]}]
#set_property -dict {LOC AA9 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[7]}]
#set_property -dict {LOC W10 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[8]}]
#set_property -dict {LOC AA13 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[9]}]
#set_property -dict {LOC Y15 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[10]}]
#set_property -dict {LOC AC12 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[11]}]
#set_property -dict {LOC V12 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[12]}]
#set_property -dict {LOC V11 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[13]}]
#set_property -dict {LOC Y12 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[14]}]
#set_property -dict {LOC W9 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[15]}]
#set_property -dict {LOC Y8 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[16]}]
#set_property -dict {LOC W8 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[17]}]
#set_property -dict {LOC W15 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[18]}]
#set_property -dict {LOC AA15 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[19]}]
#set_property -dict {LOC AE16 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[20]}]
#set_property -dict {LOC AF15 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[21]}]
#set_property -dict {LOC AE15 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[22]}]
#set_property -dict {LOC AD15 IOSTANDARD LVCMOS18 PULLUP true} [get_ports {flash_region}]
#set_property -dict {LOC AC9 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_ce_n}]
#set_property -dict {LOC AC14 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_oe_n}]
#set_property -dict {LOC AB10 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_we_n}]
#set_property -dict {LOC Y10 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_adv_n}]

View File

@ -0,0 +1,87 @@
# FPGA settings
FPGA_PART = xcku035-fbva676-2-e
FPGA_TOP = fpga
FPGA_ARCH = kintexu
# Files for synthesis
SYN_FILES = rtl/fpga.v
SYN_FILES += rtl/fpga_core.v
SYN_FILES += rtl/debounce_switch.v
SYN_FILES += rtl/sync_reset.v
SYN_FILES += rtl/sync_signal.v
SYN_FILES += rtl/axi_ram.v
SYN_FILES += rtl/axis_register.v
SYN_FILES += lib/pcie/rtl/axis_arb_mux.v
SYN_FILES += lib/pcie/rtl/pcie_us_axil_master.v
SYN_FILES += lib/pcie/rtl/pcie_us_axi_dma.v
SYN_FILES += lib/pcie/rtl/pcie_us_axi_dma_rd.v
SYN_FILES += lib/pcie/rtl/pcie_us_axi_dma_wr.v
SYN_FILES += lib/pcie/rtl/pcie_tag_manager.v
SYN_FILES += lib/pcie/rtl/pcie_us_axi_master.v
SYN_FILES += lib/pcie/rtl/pcie_us_axi_master_rd.v
SYN_FILES += lib/pcie/rtl/pcie_us_axi_master_wr.v
SYN_FILES += lib/pcie/rtl/pcie_us_axis_cq_demux.v
SYN_FILES += lib/pcie/rtl/pcie_us_cfg.v
SYN_FILES += lib/pcie/rtl/pcie_us_msi.v
SYN_FILES += lib/pcie/rtl/arbiter.v
SYN_FILES += lib/pcie/rtl/priority_encoder.v
SYN_FILES += lib/pcie/rtl/pulse_merge.v
# XDC files
XDC_FILES = fpga.xdc
# IP
XCI_FILES = ip/pcie3_ultrascale_0.xci
include ../common/vivado.mk
program: $(FPGA_TOP).bit
echo "open_hw" > program.tcl
echo "connect_hw_server" >> program.tcl
echo "open_hw_target" >> program.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl
echo "set_property PROGRAM.FILE {$(FPGA_TOP).bit} [current_hw_device]" >> program.tcl
echo "program_hw_devices [current_hw_device]" >> program.tcl
echo "exit" >> program.tcl
vivado -nojournal -nolog -mode batch -source program.tcl
%.mcs %.prm: %.bit
echo "write_cfgmem -force -format mcs -size 32 -interface BPIx16 -loadbit {up 0x0000000 $*.bit} -checksum -file $*.mcs" > generate_mcs.tcl
echo "exit" >> generate_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*$$x rev/$*_rev$$COUNT$$x; \
echo "Output: rev/$*_rev$$COUNT$$x"; done;
flash: $(FPGA_TOP).mcs $(FPGA_TOP).prm
echo "open_hw" > flash.tcl
echo "connect_hw_server" >> flash.tcl
echo "open_hw_target" >> flash.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> flash.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> flash.tcl
echo "create_hw_cfgmem -hw_device [current_hw_device] [lindex [get_cfgmem_parts {28f256p30t-bpi-x16}] 0]" >> flash.tcl
echo "current_hw_cfgmem -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM [current_hw_device]]" >> flash.tcl
echo "set_property PROGRAM.FILES [list \"$(FPGA_TOP).mcs\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP).prm\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ERASE 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.VERIFY 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CHECKSUM 0 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ADDRESS_RANGE {use_file} [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.BPI_RS_PINS {none} [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [current_hw_cfgmem]" >> flash.tcl
echo "create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]]" >> flash.tcl
echo "program_hw_devices [current_hw_device]" >> flash.tcl
echo "refresh_hw_device [current_hw_device]" >> flash.tcl
echo "program_hw_cfgmem -hw_cfgmem [current_hw_cfgmem]" >> flash.tcl
echo "boot_hw_device [current_hw_device]" >> flash.tcl
echo "exit" >> flash.tcl
vivado -nojournal -nolog -mode batch -source flash.tcl

View File

@ -0,0 +1,899 @@
<?xml version="1.0" encoding="UTF-8"?>
<spirit:design xmlns:xilinx="http://www.xilinx.com" xmlns:spirit="http://www.spiritconsortium.org/XMLSchema/SPIRIT/1685-2009" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<spirit:vendor>xilinx.com</spirit:vendor>
<spirit:library>xci</spirit:library>
<spirit:name>unknown</spirit:name>
<spirit:version>1.0</spirit:version>
<spirit:componentInstances>
<spirit:componentInstance>
<spirit:instanceName>pcie3_ultrascale_0</spirit:instanceName>
<spirit:componentRef spirit:vendor="xilinx.com" spirit:library="ip" spirit:name="pcie3_ultrascale" spirit:version="4.4"/>
<spirit:configurableElementValues>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLK.SYS_CLK.ASSOCIATED_BUSIF"/>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLK.SYS_CLK.ASSOCIATED_RESET"/>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLK.SYS_CLK.CLK_DOMAIN"/>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLK.SYS_CLK.FREQ_HZ">100000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLK.SYS_CLK.INSERT_VIP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLK.SYS_CLK.PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLK.SYS_CLK_GT.ASSOCIATED_BUSIF"/>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLK.SYS_CLK_GT.ASSOCIATED_RESET"/>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLK.SYS_CLK_GT.CLK_DOMAIN"/>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLK.SYS_CLK_GT.FREQ_HZ">100000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLK.SYS_CLK_GT.INSERT_VIP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLK.SYS_CLK_GT.PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLK.USER_CLK.CLK_DOMAIN"/>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLK.USER_CLK.INSERT_VIP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLK.USER_CLK.PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.CLK_DOMAIN"/>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.FREQ_HZ">100000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.HAS_TKEEP">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.HAS_TLAST">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.HAS_TREADY">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.HAS_TSTRB">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.INSERT_VIP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.LAYERED_METADATA">undef</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.TDATA_NUM_BYTES">32</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.TDEST_WIDTH">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.TID_WIDTH">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.TUSER_WIDTH">85</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.CLK_DOMAIN"/>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.FREQ_HZ">100000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.HAS_TKEEP">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.HAS_TLAST">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.HAS_TREADY">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.HAS_TSTRB">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.INSERT_VIP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.LAYERED_METADATA">undef</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.TDATA_NUM_BYTES">32</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.TDEST_WIDTH">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.TID_WIDTH">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.TUSER_WIDTH">75</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.RST.SYS_RST.INSERT_VIP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.RST.SYS_RST.POLARITY">ACTIVE_LOW</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.RST.USER_RESET.INSERT_VIP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.CLK_DOMAIN"/>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.FREQ_HZ">100000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.HAS_TKEEP">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.HAS_TLAST">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.HAS_TREADY">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.HAS_TSTRB">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.INSERT_VIP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.LAYERED_METADATA">undef</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.TDATA_NUM_BYTES">32</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.TDEST_WIDTH">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.TID_WIDTH">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.TUSER_WIDTH">33</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.CLK_DOMAIN"/>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.FREQ_HZ">100000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.HAS_TKEEP">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.HAS_TLAST">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.HAS_TREADY">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.HAS_TSTRB">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.INSERT_VIP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.LAYERED_METADATA">undef</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.TDATA_NUM_BYTES">32</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.TDEST_WIDTH">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.TID_WIDTH">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.TUSER_WIDTH">60</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.ACS_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.ACS_EXT_CAP_ENABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.ARI_CAP_ENABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.AXISTEN_IF_CC_ALIGNMENT_MODE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.AXISTEN_IF_CC_PARITY_CHK">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.AXISTEN_IF_CQ_ALIGNMENT_MODE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.AXISTEN_IF_ENABLE_CLIENT_TAG">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.AXISTEN_IF_ENABLE_MSG_ROUTE">0x00000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.AXISTEN_IF_ENABLE_RX_MSG_INTFC">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.AXISTEN_IF_RC_ALIGNMENT_MODE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.AXISTEN_IF_RC_STRADDLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.AXISTEN_IF_RQ_ALIGNMENT_MODE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.AXISTEN_IF_RQ_PARITY_CHK">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.BMD_PIO_MODE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.CFG_CTL_IF">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.CFG_EXT_IF">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.CFG_FC_IF">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.CFG_MGMT_IF">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.CFG_STATUS_IF">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.CFG_TX_MSG_IF">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.COMPLETION_SPACE">16KB</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.CORE_CLK_FREQ">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DATA_WIDTH">256</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.DBG_DESCRAMBLE_EN">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.DEDICATE_PERST">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.DEV_PORT_TYPE">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.DIS_GT_WIZARD">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.ENABLE_AUTO_RXEQ">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.ENABLE_GT_V1_5">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.ENABLE_IBERT">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.ENABLE_JTAG_DBG">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.EN_GT_SELECTION">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.EXT_CH_GT_DRP">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.EXT_STARTUP_PRIMITIVE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.EXT_XVC_VSEC_ENABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.FREE_RUN_FREQ">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.GTWIZ_IN_CORE">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.GT_DRP_CLK_SRC">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.INS_LOSS_PROFILE">Add-in_Card</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.MCAP_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.MCAP_ENABLEMENT">NONE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.MCAP_FPGA_BITSTREAM_VERSION">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.MSIX_EN">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.MSI_EN">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.MULT_PF_DES">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PCIE3_DRP">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PCIE_CONFIGURATION">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PCIE_FAST_CONFIG">NONE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PCIE_LINK_SPEED">3</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PCIE_USE_MODE">2.0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PER_FUNC_STATUS_IF">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_AER_CAP_ECRC_CHECK_CAPABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_AER_CAP_ECRC_GEN_CAPABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_AER_CAP_NEXTPTR">0x300</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_ARI_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_ARI_CAP_NEXT_FUNC">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_BAR0_APERTURE_SIZE">0x11</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_BAR0_CONTROL">0x4</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_BAR1_APERTURE_SIZE">0x11</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_BAR1_CONTROL">0x4</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_BAR2_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_BAR2_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_BAR3_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_BAR3_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_BAR4_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_BAR4_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_BAR5_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_BAR5_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_CAPABILITY_POINTER">0x80</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_CLASS_CODE">0x020000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DEVICE_ID">0x0001</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DEV_CAP2_128B_CAS_ATOMIC_COMPLETER_SUPPORT">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DEV_CAP2_32B_ATOMIC_COMPLETER_SUPPORT">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DEV_CAP2_64B_ATOMIC_COMPLETER_SUPPORT">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DEV_CAP2_LTR_SUPPORT">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DEV_CAP2_OBFF_SUPPORT">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DEV_CAP2_TPH_COMPLETER_SUPPORT">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DEV_CAP_EXT_TAG_SUPPORTED">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DEV_CAP_FUNCTION_LEVEL_RESET_CAPABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DEV_CAP_MAX_PAYLOAD_SIZE">0x2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DPA_CAP_NEXTPTR">0x300</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION0">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION1">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION2">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION3">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION4">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION5">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION6">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION7">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_DSN_CAP_NEXTPTR">0x300</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_EXPANSION_ROM_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_EXPANSION_ROM_ENABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_INTERRUPT_PIN">0x1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_LINK_CAP_ASPM_SUPPORT">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_LINK_STATUS_SLOT_CLOCK_CONFIG">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_LTR_CAP_NEXTPTR">0x300</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_MSIX_CAP_NEXTPTR">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_MSIX_CAP_PBA_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_MSIX_CAP_PBA_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_MSIX_CAP_TABLE_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_MSIX_CAP_TABLE_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_MSIX_CAP_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_MSI_CAP_MULTIMSGCAP">5</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_MSI_CAP_NEXTPTR">0xC0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_PB_CAP_NEXTPTR">0x274</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_PM_CAP_NEXTPTR">0x90</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_PM_CAP_PMESUPPORT_D0">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_PM_CAP_PMESUPPORT_D1">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_PM_CAP_PMESUPPORT_D3HOT">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_PM_CAP_SUPP_D1_STATE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_RBAR_CAP_ENABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_RBAR_CAP_NEXTPTR">0x300</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_RBAR_CAP_SIZE0">0x00000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_RBAR_CAP_SIZE1">0x00000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_RBAR_CAP_SIZE2">0x00000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_REVISION_ID">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SECONDARY_PCIE_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_BAR0_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_BAR0_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_BAR1_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_BAR1_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_BAR2_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_BAR2_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_BAR3_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_BAR3_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_BAR4_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_BAR4_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_BAR5_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_BAR5_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_CAP_INITIAL_VF">0x0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_CAP_NEXTPTR">0x300</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_CAP_TOTAL_VF">0x0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_CAP_VER">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_FIRST_VF_OFFSET">0x0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_FUNC_DEP_LINK">0x0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_SUPPORTED_PAGE_SIZE">0x00000553</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SRIOV_VF_DEVICE_ID">0x0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SUBSYSTEM_ID">0x0001</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_SUBSYSTEM_VENDOR_ID">0x1234</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_TPHR_CAP_DEV_SPECIFIC_MODE">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_TPHR_CAP_ENABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_TPHR_CAP_INT_VEC_MODE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_TPHR_CAP_NEXTPTR">0x300</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_TPHR_CAP_ST_MODE_SEL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_TPHR_CAP_ST_TABLE_LOC">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_TPHR_CAP_ST_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_TPHR_CAP_VER">0x1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_VC_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF0_VENDOR_ID">0x1234</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_AER_CAP_ECRC_CHECK_CAPABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_AER_CAP_ECRC_GEN_CAPABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_AER_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_ARI_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_BAR0_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_BAR0_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_BAR1_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_BAR1_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_BAR2_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_BAR2_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_BAR3_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_BAR3_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_BAR4_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_BAR4_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_BAR5_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_BAR5_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_CAPABILITY_POINTER">0x80</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_CLASS_CODE">0x058000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_DEVICE_ID">0x8011</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_DEV_CAP_MAX_PAYLOAD_SIZE">0x2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_DPA_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION0">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION1">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION2">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION3">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION4">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION5">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION6">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION7">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_DSN_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_EXPANSION_ROM_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_EXPANSION_ROM_ENABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_INTERRUPT_PIN">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_MSIX_CAP_NEXTPTR">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_MSIX_CAP_PBA_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_MSIX_CAP_PBA_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_MSIX_CAP_TABLE_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_MSIX_CAP_TABLE_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_MSIX_CAP_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_MSI_CAP_MULTIMSGCAP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_MSI_CAP_NEXTPTR">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_PB_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_PM_CAP_NEXTPTR">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_RBAR_CAP_ENABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_RBAR_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_RBAR_CAP_SIZE0">0x00000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_RBAR_CAP_SIZE1">0x00000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_RBAR_CAP_SIZE2">0x00000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_REVISION_ID">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_BAR0_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_BAR0_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_BAR1_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_BAR1_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_BAR2_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_BAR2_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_BAR3_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_BAR3_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_BAR4_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_BAR4_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_BAR5_APERTURE_SIZE">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_BAR5_CONTROL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_CAP_INITIAL_VF">0x0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_CAP_TOTAL_VF">0x0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_CAP_VER">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_FIRST_VF_OFFSET">0x0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_FUNC_DEP_LINK">0x0001</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_SUPPORTED_PAGE_SIZE">0x00000553</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SRIOV_VF_DEVICE_ID">0x0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_SUBSYSTEM_ID">0x0007</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_TPHR_CAP_DEV_SPECIFIC_MODE">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_TPHR_CAP_ENABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_TPHR_CAP_INT_VEC_MODE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_TPHR_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_TPHR_CAP_ST_MODE_SEL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_TPHR_CAP_ST_TABLE_LOC">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_TPHR_CAP_ST_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PF1_TPHR_CAP_VER">0x1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PHY_LP_TXPRESET">4</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PIPE_SIM">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PLL_TYPE">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PL_INTERFACE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PL_LINK_CAP_MAX_LINK_SPEED">4</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PL_LINK_CAP_MAX_LINK_WIDTH">8</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PL_UPSTREAM_FACING">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.PM_ENABLE_L23_ENTRY">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.RCV_MSG_IF">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.REF_CLK_FREQ">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.RX_DETECT">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.SELECT_QUAD">GTH_Quad_225</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.SHARED_LOGIC">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.SPARE_WORD1">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.SRIOV_CAP_ENABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.SYS_RESET_POLARITY">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.TL_CREDITS_CD">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.TL_CREDITS_CH">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.TL_CREDITS_NPD">0x028</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.TL_CREDITS_NPH">0x20</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.TL_CREDITS_PD">0x198</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.TL_CREDITS_PH">0x20</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.TL_EXTENDED_CFG_EXTEND_INTERFACE_ENABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.TL_LEGACY_MODE_ENABLE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.TL_PF_ENABLE_REG">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.TRANSCEIVER_CTRL_STATUS_PORTS">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.TX_FC_IF">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.USER_CLK_FREQ">3</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_ARI_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_CAPABILITY_POINTER">0x80</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_MSIX_CAP_PBA_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_MSIX_CAP_PBA_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_MSIX_CAP_TABLE_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_MSIX_CAP_TABLE_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_MSIX_CAP_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_MSI_CAP_MULTIMSGCAP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_PM_CAP_NEXTPTR">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_TPHR_CAP_DEV_SPECIFIC_MODE">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_TPHR_CAP_INT_VEC_MODE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_TPHR_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_TPHR_CAP_ST_MODE_SEL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_TPHR_CAP_ST_TABLE_LOC">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_TPHR_CAP_ST_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF0_TPHR_CAP_VER">0x1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF1_ARI_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF1_MSIX_CAP_PBA_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF1_MSIX_CAP_PBA_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF1_MSIX_CAP_TABLE_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF1_MSIX_CAP_TABLE_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF1_MSIX_CAP_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF1_MSI_CAP_MULTIMSGCAP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF1_PM_CAP_NEXTPTR">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF1_TPHR_CAP_DEV_SPECIFIC_MODE">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF1_TPHR_CAP_INT_VEC_MODE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF1_TPHR_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF1_TPHR_CAP_ST_MODE_SEL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF1_TPHR_CAP_ST_TABLE_LOC">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF1_TPHR_CAP_ST_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF1_TPHR_CAP_VER">0x1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF2_ARI_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF2_MSIX_CAP_PBA_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF2_MSIX_CAP_PBA_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF2_MSIX_CAP_TABLE_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF2_MSIX_CAP_TABLE_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF2_MSIX_CAP_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF2_MSI_CAP_MULTIMSGCAP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF2_PM_CAP_NEXTPTR">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF2_TPHR_CAP_DEV_SPECIFIC_MODE">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF2_TPHR_CAP_INT_VEC_MODE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF2_TPHR_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF2_TPHR_CAP_ST_MODE_SEL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF2_TPHR_CAP_ST_TABLE_LOC">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF2_TPHR_CAP_ST_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF2_TPHR_CAP_VER">0x1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF3_ARI_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF3_MSIX_CAP_PBA_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF3_MSIX_CAP_PBA_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF3_MSIX_CAP_TABLE_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF3_MSIX_CAP_TABLE_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF3_MSIX_CAP_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF3_MSI_CAP_MULTIMSGCAP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF3_PM_CAP_NEXTPTR">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF3_TPHR_CAP_DEV_SPECIFIC_MODE">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF3_TPHR_CAP_INT_VEC_MODE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF3_TPHR_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF3_TPHR_CAP_ST_MODE_SEL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF3_TPHR_CAP_ST_TABLE_LOC">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF3_TPHR_CAP_ST_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF3_TPHR_CAP_VER">0x1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF4_ARI_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF4_MSIX_CAP_PBA_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF4_MSIX_CAP_PBA_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF4_MSIX_CAP_TABLE_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF4_MSIX_CAP_TABLE_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF4_MSIX_CAP_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF4_MSI_CAP_MULTIMSGCAP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF4_PM_CAP_NEXTPTR">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF4_TPHR_CAP_DEV_SPECIFIC_MODE">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF4_TPHR_CAP_INT_VEC_MODE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF4_TPHR_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF4_TPHR_CAP_ST_MODE_SEL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF4_TPHR_CAP_ST_TABLE_LOC">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF4_TPHR_CAP_ST_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF4_TPHR_CAP_VER">0x1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF5_ARI_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF5_MSIX_CAP_PBA_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF5_MSIX_CAP_PBA_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF5_MSIX_CAP_TABLE_BIR">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF5_MSIX_CAP_TABLE_OFFSET">0x00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF5_MSIX_CAP_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF5_MSI_CAP_MULTIMSGCAP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF5_PM_CAP_NEXTPTR">0x00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF5_TPHR_CAP_DEV_SPECIFIC_MODE">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF5_TPHR_CAP_INT_VEC_MODE">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF5_TPHR_CAP_NEXTPTR">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF5_TPHR_CAP_ST_MODE_SEL">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF5_TPHR_CAP_ST_TABLE_LOC">0x0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF5_TPHR_CAP_ST_TABLE_SIZE">0x000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.VF5_TPHR_CAP_VER">0x1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.en_msi_per_vec_masking">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.gen_x0y0_xdc">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.gen_x0y1_xdc">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.gen_x0y2_xdc">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.gen_x0y3_xdc">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.gen_x0y4_xdc">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.gen_x0y5_xdc">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.pcie_blk_locn">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.silicon_revision">Production</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.xlnx_ref_board">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_ENABLEMENT.xlnx_ref_board">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.AXISTEN_IF_RC_STRADDLE">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.Component_Name">pcie3_ultrascale_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.INS_LOSS_NYQ">15</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_AER_CAP_ECRC_CHECK_CAPABLE">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_AER_CAP_ECRC_GEN_CAPABLE">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_CLASS_CODE">020000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_DEVICE_ID">0001</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_DEV_CAP2_128B_CAS_ATOMIC_COMPLETER_SUPPORT">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_DEV_CAP2_32B_ATOMIC_COMPLETER_SUPPORT">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_DEV_CAP2_64B_ATOMIC_COMPLETER_SUPPORT">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_DEV_CAP2_OBFF_SUPPORT">00_Not_Supported</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_DEV_CAP2_TPH_COMPLETER_SUPPORT">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_DEV_CAP_FUNCTION_LEVEL_RESET_CAPABLE">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_INTERRUPT_PIN">INTA</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_LINK_STATUS_SLOT_CLOCK_CONFIG">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_MSIX_CAP_PBA_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_MSIX_CAP_PBA_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_MSIX_CAP_TABLE_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_MSIX_CAP_TABLE_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_MSIX_CAP_TABLE_SIZE">000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_MSI_CAP_MULTIMSGCAP">32_vectors</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_PM_CAP_PMESUPPORT_D0">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_PM_CAP_PMESUPPORT_D1">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_PM_CAP_PMESUPPORT_D3HOT">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_PM_CAP_SUPP_D1_STATE">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_REVISION_ID">00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_SRIOV_CAP_INITIAL_VF">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_SRIOV_FIRST_VF_OFFSET">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_SRIOV_FUNC_DEP_LINK">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_SRIOV_SUPPORTED_PAGE_SIZE">00000553</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_SRIOV_VF_DEVICE_ID">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_SUBSYSTEM_ID">0001</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_SUBSYSTEM_VENDOR_ID">1234</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF0_Use_Class_Code_Lookup_Assistant">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_AER_CAP_ECRC_CHECK_CAPABLE">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_AER_CAP_ECRC_GEN_CAPABLE">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_CLASS_CODE">058000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_DEVICE_ID">8011</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_INTERRUPT_PIN">NONE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_MSIX_CAP_PBA_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_MSIX_CAP_PBA_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_MSIX_CAP_TABLE_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_MSIX_CAP_TABLE_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_MSIX_CAP_TABLE_SIZE">000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_MSI_CAP_MULTIMSGCAP">1_vector</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_REVISION_ID">00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_SRIOV_CAP_INITIAL_VF">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_SRIOV_CAP_VER">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_SRIOV_FIRST_VF_OFFSET">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_SRIOV_FUNC_DEP_LINK">0001</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_SRIOV_SUPPORTED_PAGE_SIZE">00000553</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_SRIOV_VF_DEVICE_ID">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_SUBSYSTEM_ID">0007</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PF1_Use_Class_Code_Lookup_Assistant">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PHY_LP_TXPRESET">4</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PL_LINK_CAP_MAX_LINK_SPEED">8.0_GT/s</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PL_LINK_CAP_MAX_LINK_WIDTH">X8</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.REF_CLK_FREQ">100_MHz</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.RX_DETECT">Default</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.RX_PPM_OFFSET">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.RX_SSC_PPM">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.SRIOV_CAP_ENABLE">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.SRIOV_CAP_ENABLE_EXT">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.Shared_Logic">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.TL_PF_ENABLE_REG">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF0_MSIX_CAP_PBA_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF0_MSIX_CAP_PBA_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF0_MSIX_CAP_TABLE_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF0_MSIX_CAP_TABLE_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF0_MSIX_CAP_TABLE_SIZE">000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF0_MSI_CAP_MULTIMSGCAP">1_vector</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF1_MSIX_CAP_PBA_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF1_MSIX_CAP_PBA_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF1_MSIX_CAP_TABLE_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF1_MSIX_CAP_TABLE_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF1_MSIX_CAP_TABLE_SIZE">000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF1_MSI_CAP_MULTIMSGCAP">1_vector</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF2_MSIX_CAP_PBA_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF2_MSIX_CAP_PBA_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF2_MSIX_CAP_TABLE_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF2_MSIX_CAP_TABLE_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF2_MSIX_CAP_TABLE_SIZE">000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF2_MSI_CAP_MULTIMSGCAP">1_vector</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF3_MSIX_CAP_PBA_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF3_MSIX_CAP_PBA_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF3_MSIX_CAP_TABLE_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF3_MSIX_CAP_TABLE_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF3_MSIX_CAP_TABLE_SIZE">000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF3_MSI_CAP_MULTIMSGCAP">1_vector</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF4_MSIX_CAP_PBA_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF4_MSIX_CAP_PBA_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF4_MSIX_CAP_TABLE_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF4_MSIX_CAP_TABLE_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF4_MSIX_CAP_TABLE_SIZE">000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF4_MSI_CAP_MULTIMSGCAP">1_vector</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF5_MSIX_CAP_PBA_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF5_MSIX_CAP_PBA_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF5_MSIX_CAP_TABLE_BIR">BAR_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF5_MSIX_CAP_TABLE_OFFSET">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF5_MSIX_CAP_TABLE_SIZE">000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.VF5_MSI_CAP_MULTIMSGCAP">1_vector</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.acs_ext_cap_enable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.alignment_mode">DWORD_Aligned</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.aspm_support">No_ASPM</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.axisten_freq">250</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.axisten_if_enable_client_tag">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.axisten_if_enable_msg_route">2FFFF</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.axisten_if_enable_msg_route_override">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.axisten_if_enable_rx_msg_intfc">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.axisten_if_width">256_bit</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.bmd_pio_mode">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.cc_cq_alignment">None</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.cfg_ctl_if">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.cfg_ext_if">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.cfg_fc_if">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.cfg_mgmt_if">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.cfg_status_if">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.cfg_tx_msg_if">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.coreclk_freq">500</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.dedicate_perst">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.device_port_type">PCI_Express_Endpoint_device</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.dis_gt_wizard">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.disable_gt_loc">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.en_dbg_descramble">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.en_ext_ch_gt_drp">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.en_ext_clk">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.en_gt_selection">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.en_l23_entry">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.en_msi_per_vec_masking">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.en_parity">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.en_pcie_conf">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.en_pcie_drp">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.en_pl_ifc">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.en_transceiver_status_ports">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.enable_auto_rxeq">False</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.enable_gt_v1_5">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.enable_ibert">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.enable_jtag_dbg">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.ext_pcie_cfg_space_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.ext_startup_primitive">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.ext_xvc_vsec_enable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.extended_tag_field">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.free_run_freq">100_MHz</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.gen_x0y0">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.gen_x0y1">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.gen_x0y2">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.gen_x0y3">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.gen_x0y4">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.gen_x0y5">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.gt_drp_clk_src">Internal</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.gtwiz_in_core">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.ins_loss_profile">Add-in_Card</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.mcap_enablement">None</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.mcap_fpga_bitstream_version">00000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.mode_selection">Basic</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.mult_pf_des">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pcie_blk_locn">X0Y0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.per_func_status_if">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.perf_level">Extreme</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.performance">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_aer_enabled">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_ari_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar0_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar0_enabled">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar0_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar0_scale">Megabytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar0_size">16</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar0_type">Memory</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar1_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar1_enabled">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar1_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar1_scale">Megabytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar1_size">16</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar1_type">Memory</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar2_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar2_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar2_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar2_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar2_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar2_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar3_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar3_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar3_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar3_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar3_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar3_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar4_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar4_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar4_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar4_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar4_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar4_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar5_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar5_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar5_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar5_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_bar5_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_base_class_menu">Network_controller</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_class_code_base">02</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_class_code_interface">00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_class_code_sub">00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_dev_cap_max_payload">512_bytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_dpa_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_dsn_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_expansion_rom_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_expansion_rom_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_expansion_rom_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_ltr_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_msi_enabled">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_msix_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_pb_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_rbar_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar0_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar0_enabled">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar0_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar0_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar0_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar0_type">Memory</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar1_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar1_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar1_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar1_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar1_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar1_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar2_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar2_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar2_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar2_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar2_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar2_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar3_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar3_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar3_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar3_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar3_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar3_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar4_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar4_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar4_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar4_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar4_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar4_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar5_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar5_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar5_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar5_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_bar5_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sriov_cap_ver">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_sub_class_interface_menu">Ethernet_controller</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_tphr_enable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf0_vc_cap_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_aer_enabled">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_ari_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar0_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar0_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar0_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar0_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar0_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar0_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar1_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar1_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar1_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar1_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar1_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar1_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar2_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar2_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar2_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar2_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar2_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar2_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar3_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar3_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar3_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar3_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar3_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar3_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar4_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar4_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar4_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar4_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar4_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar4_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar5_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar5_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar5_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar5_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_bar5_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_base_class_menu">Memory_controller</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_class_code_base">05</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_class_code_interface">00</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_class_code_sub">80</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_dev_cap_max_payload">512_bytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_dpa_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_dsn_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_expansion_rom_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_expansion_rom_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_expansion_rom_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_msi_enabled">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_msix_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_pb_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_rbar_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar0_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar0_enabled">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar0_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar0_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar0_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar0_type">Memory</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar1_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar1_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar1_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar1_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar1_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar1_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar2_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar2_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar2_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar2_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar2_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar2_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar3_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar3_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar3_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar3_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar3_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar3_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar4_64bit">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar4_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar4_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar4_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar4_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar4_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar5_enabled">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar5_prefetchable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar5_scale">Kilobytes</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar5_size">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sriov_bar5_type">N/A</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_sub_class_interface_menu">Other_memory_controller</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pf1_tphr_enable">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.pipe_sim">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.plltype">QPLL1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.rc_rq_alignment">None</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.rcv_msg_if">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.select_quad">GTH_Quad_225</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.special_gui">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.sys_reset_polarity">ACTIVE_LOW</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.tandem_mode">None</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.tl_pf0_enable_reg">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.tx_fc_if">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.vendor_id">1234</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.xlnx_ref_board">None</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PROJECT_PARAM.ARCHITECTURE">kintexu</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PROJECT_PARAM.BASE_BOARD_PART"/>
<spirit:configurableElementValue spirit:referenceId="PROJECT_PARAM.BOARD_CONNECTIONS"/>
<spirit:configurableElementValue spirit:referenceId="PROJECT_PARAM.DEVICE">xcku035</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PROJECT_PARAM.PACKAGE">fbva676</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PROJECT_PARAM.PREFHDL">VERILOG</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PROJECT_PARAM.SILICON_REVISION"/>
<spirit:configurableElementValue spirit:referenceId="PROJECT_PARAM.SIMULATOR_LANGUAGE">MIXED</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PROJECT_PARAM.SPEEDGRADE">-2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PROJECT_PARAM.STATIC_POWER"/>
<spirit:configurableElementValue spirit:referenceId="PROJECT_PARAM.TEMPERATURE_GRADE">E</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PROJECT_PARAM.USE_RDI_CUSTOMIZATION">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PROJECT_PARAM.USE_RDI_GENERATION">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.IPCONTEXT">IP_Flow</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.IPREVISION">5</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.MANAGED">TRUE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.OUTPUTDIR">.</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SELECTEDSIMMODEL"/>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SHAREDDIR">.</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SWVERSION">2019.1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="RUNTIME_PARAM.SYNTHESISFLOW">OUT_OF_CONTEXT</spirit:configurableElementValue>
</spirit:configurableElementValues>
<spirit:vendorExtensions>
<xilinx:componentInstanceExtensions>
<xilinx:configElementInfos>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.HAS_TKEEP" xilinx:valueSource="auto"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.HAS_TLAST" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.HAS_TREADY" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.HAS_TSTRB" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.TDATA_NUM_BYTES" xilinx:valueSource="auto"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.TDEST_WIDTH" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.TID_WIDTH" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_CQ.TUSER_WIDTH" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.HAS_TKEEP" xilinx:valueSource="auto"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.HAS_TLAST" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.HAS_TREADY" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.HAS_TSTRB" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.TDATA_NUM_BYTES" xilinx:valueSource="auto"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.TDEST_WIDTH" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.TID_WIDTH" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.M_AXIS_RC.TUSER_WIDTH" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.HAS_TKEEP" xilinx:valueSource="auto"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.HAS_TLAST" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.HAS_TREADY" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.HAS_TSTRB" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.TDATA_NUM_BYTES" xilinx:valueSource="auto"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.TDEST_WIDTH" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.TID_WIDTH" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_CC.TUSER_WIDTH" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.HAS_TKEEP" xilinx:valueSource="auto"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.HAS_TLAST" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.HAS_TREADY" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.HAS_TSTRB" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.TDATA_NUM_BYTES" xilinx:valueSource="auto"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.TDEST_WIDTH" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.TID_WIDTH" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="BUSIFPARAM_VALUE.S_AXIS_RQ.TUSER_WIDTH" xilinx:valueSource="constant"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.AXISTEN_IF_RC_STRADDLE" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PF0_CLASS_CODE" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PF0_DEVICE_ID" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PF0_MSIX_CAP_PBA_BIR" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PF0_MSIX_CAP_TABLE_BIR" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PF0_MSI_CAP_MULTIMSGCAP" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PF0_SRIOV_CAP_INITIAL_VF" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PF0_SUBSYSTEM_ID" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PF0_SUBSYSTEM_VENDOR_ID" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PF0_Use_Class_Code_Lookup_Assistant" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PF1_DEVICE_ID" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PF1_MSIX_CAP_PBA_BIR" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PF1_MSIX_CAP_TABLE_BIR" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PF1_SRIOV_CAP_INITIAL_VF" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PL_LINK_CAP_MAX_LINK_SPEED" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PL_LINK_CAP_MAX_LINK_WIDTH" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.TL_PF_ENABLE_REG" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.aspm_support" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.axisten_freq" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.axisten_if_width" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.coreclk_freq" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.dedicate_perst" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.extended_tag_field" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.gen_x0y0" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.gen_x0y1" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.mcap_enablement" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.mult_pf_des" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pcie_blk_locn" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pf0_bar0_64bit" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pf0_bar0_scale" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pf0_bar0_size" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pf0_bar1_enabled" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pf0_bar1_scale" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pf0_bar1_size" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pf0_bar1_type" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pf0_base_class_menu" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pf0_class_code_base" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pf0_class_code_interface" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pf0_class_code_sub" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pf0_sub_class_interface_menu" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pf1_bar0_enabled" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pf1_bar0_size" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pf1_bar0_type" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.pipe_sim" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.plltype" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.select_quad" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.vendor_id" xilinx:valueSource="user"/>
</xilinx:configElementInfos>
</xilinx:componentInstanceExtensions>
</spirit:vendorExtensions>
</spirit:componentInstance>
</spirit:componentInstances>
</spirit:design>

View File

@ -0,0 +1 @@
../../../../

View File

@ -0,0 +1,365 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* AXI4 RAM
*/
module axi_ram #
(
parameter DATA_WIDTH = 32, // width of data bus in bits
parameter ADDR_WIDTH = 16, // width of address bus in bits
parameter STRB_WIDTH = (DATA_WIDTH/8),
parameter ID_WIDTH = 8,
parameter PIPELINE_OUTPUT = 0
)
(
input wire clk,
input wire rst,
input wire [ID_WIDTH-1:0] s_axi_awid,
input wire [ADDR_WIDTH-1:0] s_axi_awaddr,
input wire [7:0] s_axi_awlen,
input wire [2:0] s_axi_awsize,
input wire [1:0] s_axi_awburst,
input wire s_axi_awlock,
input wire [3:0] s_axi_awcache,
input wire [2:0] s_axi_awprot,
input wire s_axi_awvalid,
output wire s_axi_awready,
input wire [DATA_WIDTH-1:0] s_axi_wdata,
input wire [STRB_WIDTH-1:0] s_axi_wstrb,
input wire s_axi_wlast,
input wire s_axi_wvalid,
output wire s_axi_wready,
output wire [ID_WIDTH-1:0] s_axi_bid,
output wire [1:0] s_axi_bresp,
output wire s_axi_bvalid,
input wire s_axi_bready,
input wire [ID_WIDTH-1:0] s_axi_arid,
input wire [ADDR_WIDTH-1:0] s_axi_araddr,
input wire [7:0] s_axi_arlen,
input wire [2:0] s_axi_arsize,
input wire [1:0] s_axi_arburst,
input wire s_axi_arlock,
input wire [3:0] s_axi_arcache,
input wire [2:0] s_axi_arprot,
input wire s_axi_arvalid,
output wire s_axi_arready,
output wire [ID_WIDTH-1:0] s_axi_rid,
output wire [DATA_WIDTH-1:0] s_axi_rdata,
output wire [1:0] s_axi_rresp,
output wire s_axi_rlast,
output wire s_axi_rvalid,
input wire s_axi_rready
);
parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(STRB_WIDTH);
parameter WORD_WIDTH = STRB_WIDTH;
parameter WORD_SIZE = DATA_WIDTH/WORD_WIDTH;
// bus width assertions
initial begin
if (WORD_SIZE * STRB_WIDTH != DATA_WIDTH) begin
$error("Error: AXI data width not evenly divisble");
$finish;
end
if (2**$clog2(WORD_WIDTH) != WORD_WIDTH) begin
$error("Error: AXI word width must be even power of two");
$finish;
end
end
localparam [0:0]
READ_STATE_IDLE = 1'd0,
READ_STATE_BURST = 1'd1;
reg [0:0] read_state_reg = READ_STATE_IDLE, read_state_next;
localparam [1:0]
WRITE_STATE_IDLE = 2'd0,
WRITE_STATE_BURST = 2'd1,
WRITE_STATE_RESP = 2'd2;
reg [1:0] write_state_reg = WRITE_STATE_IDLE, write_state_next;
reg mem_wr_en;
reg mem_rd_en;
reg [ID_WIDTH-1:0] read_id_reg = {ID_WIDTH{1'b0}}, read_id_next;
reg [ADDR_WIDTH-1:0] read_addr_reg = {ADDR_WIDTH{1'b0}}, read_addr_next;
reg [7:0] read_count_reg = 8'd0, read_count_next;
reg [2:0] read_size_reg = 3'd0, read_size_next;
reg [1:0] read_burst_reg = 2'd0, read_burst_next;
reg [ID_WIDTH-1:0] write_id_reg = {ID_WIDTH{1'b0}}, write_id_next;
reg [ADDR_WIDTH-1:0] write_addr_reg = {ADDR_WIDTH{1'b0}}, write_addr_next;
reg [7:0] write_count_reg = 8'd0, write_count_next;
reg [2:0] write_size_reg = 3'd0, write_size_next;
reg [1:0] write_burst_reg = 2'd0, write_burst_next;
reg s_axi_awready_reg = 1'b0, s_axi_awready_next;
reg s_axi_wready_reg = 1'b0, s_axi_wready_next;
reg [ID_WIDTH-1:0] s_axi_bid_reg = {ID_WIDTH{1'b0}}, s_axi_bid_next;
reg s_axi_bvalid_reg = 1'b0, s_axi_bvalid_next;
reg s_axi_arready_reg = 1'b0, s_axi_arready_next;
reg [ID_WIDTH-1:0] s_axi_rid_reg = {ID_WIDTH{1'b0}}, s_axi_rid_next;
reg [DATA_WIDTH-1:0] s_axi_rdata_reg = {DATA_WIDTH{1'b0}}, s_axi_rdata_next;
reg s_axi_rlast_reg = 1'b0, s_axi_rlast_next;
reg s_axi_rvalid_reg = 1'b0, s_axi_rvalid_next;
reg [ID_WIDTH-1:0] s_axi_rid_pipe_reg = {ID_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] s_axi_rdata_pipe_reg = {DATA_WIDTH{1'b0}};
reg s_axi_rlast_pipe_reg = 1'b0;
reg s_axi_rvalid_pipe_reg = 1'b0;
// (* RAM_STYLE="BLOCK" *)
reg [DATA_WIDTH-1:0] mem[(2**VALID_ADDR_WIDTH)-1:0];
wire [VALID_ADDR_WIDTH-1:0] s_axi_awaddr_valid = s_axi_awaddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
wire [VALID_ADDR_WIDTH-1:0] s_axi_araddr_valid = s_axi_araddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
wire [VALID_ADDR_WIDTH-1:0] read_addr_valid = read_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
wire [VALID_ADDR_WIDTH-1:0] write_addr_valid = write_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
assign s_axi_awready = s_axi_awready_reg;
assign s_axi_wready = s_axi_wready_reg;
assign s_axi_bid = s_axi_bid_reg;
assign s_axi_bresp = 2'b00;
assign s_axi_bvalid = s_axi_bvalid_reg;
assign s_axi_arready = s_axi_arready_reg;
assign s_axi_rid = PIPELINE_OUTPUT ? s_axi_rid_pipe_reg : s_axi_rid_reg;
assign s_axi_rdata = PIPELINE_OUTPUT ? s_axi_rdata_pipe_reg : s_axi_rdata_reg;
assign s_axi_rresp = 2'b00;
assign s_axi_rlast = PIPELINE_OUTPUT ? s_axi_rlast_pipe_reg : s_axi_rlast_reg;
assign s_axi_rvalid = PIPELINE_OUTPUT ? s_axi_rvalid_pipe_reg : s_axi_rvalid_reg;
integer i, j;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (i = 0; i < 2**ADDR_WIDTH; i = i + 2**(ADDR_WIDTH/2)) begin
for (j = i; j < i + 2**(ADDR_WIDTH/2); j = j + 1) begin
mem[j] = 0;
end
end
end
always @* begin
write_state_next = WRITE_STATE_IDLE;
mem_wr_en = 1'b0;
write_id_next = write_id_reg;
write_addr_next = write_addr_reg;
write_count_next = write_count_reg;
write_size_next = write_size_reg;
write_burst_next = write_burst_reg;
s_axi_awready_next = 1'b0;
s_axi_wready_next = 1'b0;
s_axi_bid_next = s_axi_bid_reg;
s_axi_bvalid_next = s_axi_bvalid_reg && !s_axi_bready;
case (write_state_reg)
WRITE_STATE_IDLE: begin
s_axi_awready_next = 1'b1;
if (s_axi_awready && s_axi_awvalid) begin
write_id_next = s_axi_awid;
write_addr_next = s_axi_awaddr;
write_count_next = s_axi_awlen;
write_size_next = s_axi_awsize < $clog2(STRB_WIDTH) ? s_axi_awsize : $clog2(STRB_WIDTH);
write_burst_next = s_axi_awburst;
s_axi_awready_next = 1'b0;
s_axi_wready_next = 1'b1;
write_state_next = WRITE_STATE_BURST;
end else begin
write_state_next = WRITE_STATE_IDLE;
end
end
WRITE_STATE_BURST: begin
s_axi_wready_next = 1'b1;
if (s_axi_wready && s_axi_wvalid) begin
mem_wr_en = 1'b1;
if (write_burst_reg != 2'b00) begin
write_addr_next = write_addr_reg + (1 << write_size_reg);
end
write_count_next = write_count_reg - 1;
if (write_count_reg > 0) begin
write_state_next = WRITE_STATE_BURST;
end else begin
s_axi_wready_next = 1'b0;
if (s_axi_bready || !s_axi_bvalid) begin
s_axi_bid_next = write_id_reg;
s_axi_bvalid_next = 1'b1;
s_axi_awready_next = 1'b1;
write_state_next = WRITE_STATE_IDLE;
end else begin
write_state_next = WRITE_STATE_RESP;
end
end
end else begin
write_state_next = WRITE_STATE_BURST;
end
end
WRITE_STATE_RESP: begin
if (s_axi_bready || !s_axi_bvalid) begin
s_axi_bid_next = write_id_reg;
s_axi_bvalid_next = 1'b1;
s_axi_awready_next = 1'b1;
write_state_next = WRITE_STATE_IDLE;
end else begin
write_state_next = WRITE_STATE_RESP;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
write_state_reg <= WRITE_STATE_IDLE;
s_axi_awready_reg <= 1'b0;
s_axi_wready_reg <= 1'b0;
s_axi_bvalid_reg <= 1'b0;
end else begin
write_state_reg <= write_state_next;
s_axi_awready_reg <= s_axi_awready_next;
s_axi_wready_reg <= s_axi_wready_next;
s_axi_bvalid_reg <= s_axi_bvalid_next;
end
write_id_reg <= write_id_next;
write_addr_reg <= write_addr_next;
write_count_reg <= write_count_next;
write_size_reg <= write_size_next;
write_burst_reg <= write_burst_next;
s_axi_bid_reg <= s_axi_bid_next;
for (i = 0; i < WORD_WIDTH; i = i + 1) begin
if (mem_wr_en & s_axi_wstrb[i]) begin
mem[write_addr_valid][WORD_SIZE*i +: WORD_SIZE] <= s_axi_wdata[WORD_SIZE*i +: WORD_SIZE];
end
end
end
always @* begin
read_state_next = READ_STATE_IDLE;
mem_rd_en = 1'b0;
s_axi_rid_next = s_axi_rid_reg;
s_axi_rlast_next = s_axi_rlast_reg;
s_axi_rvalid_next = s_axi_rvalid_reg && !(s_axi_rready || (PIPELINE_OUTPUT && !s_axi_rvalid_pipe_reg));
read_id_next = read_id_reg;
read_addr_next = read_addr_reg;
read_count_next = read_count_reg;
read_size_next = read_size_reg;
read_burst_next = read_burst_reg;
s_axi_arready_next = 1'b0;
case (read_state_reg)
READ_STATE_IDLE: begin
s_axi_arready_next = 1'b1;
if (s_axi_arready && s_axi_arvalid) begin
read_id_next = s_axi_arid;
read_addr_next = s_axi_araddr;
read_count_next = s_axi_arlen;
read_size_next = s_axi_arsize < $clog2(STRB_WIDTH) ? s_axi_arsize : $clog2(STRB_WIDTH);
read_burst_next = s_axi_arburst;
s_axi_arready_next = 1'b0;
read_state_next = READ_STATE_BURST;
end else begin
read_state_next = READ_STATE_IDLE;
end
end
READ_STATE_BURST: begin
if (s_axi_rready || (PIPELINE_OUTPUT && !s_axi_rvalid_pipe_reg) || !s_axi_rvalid_reg) begin
mem_rd_en = 1'b1;
s_axi_rvalid_next = 1'b1;
s_axi_rid_next = read_id_reg;
s_axi_rlast_next = read_count_reg == 0;
if (read_burst_reg != 2'b00) begin
read_addr_next = read_addr_reg + (1 << read_size_reg);
end
read_count_next = read_count_reg - 1;
if (read_count_reg > 0) begin
read_state_next = READ_STATE_BURST;
end else begin
s_axi_arready_next = 1'b1;
read_state_next = READ_STATE_IDLE;
end
end else begin
read_state_next = READ_STATE_BURST;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
read_state_reg <= READ_STATE_IDLE;
s_axi_arready_reg <= 1'b0;
s_axi_rvalid_reg <= 1'b0;
s_axi_rvalid_pipe_reg <= 1'b0;
end else begin
read_state_reg <= read_state_next;
s_axi_arready_reg <= s_axi_arready_next;
s_axi_rvalid_reg <= s_axi_rvalid_next;
if (!s_axi_rvalid_pipe_reg || s_axi_rready) begin
s_axi_rvalid_pipe_reg <= s_axi_rvalid_reg;
end
end
read_id_reg <= read_id_next;
read_addr_reg <= read_addr_next;
read_count_reg <= read_count_next;
read_size_reg <= read_size_next;
read_burst_reg <= read_burst_next;
s_axi_rid_reg <= s_axi_rid_next;
s_axi_rlast_reg <= s_axi_rlast_next;
if (mem_rd_en) begin
s_axi_rdata_reg <= mem[read_addr_valid];
end
if (!s_axi_rvalid_pipe_reg || s_axi_rready) begin
s_axi_rid_pipe_reg <= s_axi_rid_reg;
s_axi_rdata_pipe_reg <= s_axi_rdata_reg;
s_axi_rlast_pipe_reg <= s_axi_rlast_reg;
end
end
endmodule

View File

@ -0,0 +1,264 @@
/*
Copyright (c) 2014-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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* AXI4-Stream register
*/
module axis_register #
(
parameter DATA_WIDTH = 8,
parameter KEEP_ENABLE = (DATA_WIDTH>8),
parameter KEEP_WIDTH = (DATA_WIDTH/8),
parameter LAST_ENABLE = 1,
parameter ID_ENABLE = 0,
parameter ID_WIDTH = 8,
parameter DEST_ENABLE = 0,
parameter DEST_WIDTH = 8,
parameter USER_ENABLE = 1,
parameter USER_WIDTH = 1,
parameter REG_TYPE = 2
)
(
input wire clk,
input wire rst,
/*
* AXI Stream input
*/
input wire [DATA_WIDTH-1:0] s_axis_tdata,
input wire [KEEP_WIDTH-1:0] s_axis_tkeep,
input wire s_axis_tvalid,
output wire s_axis_tready,
input wire s_axis_tlast,
input wire [ID_WIDTH-1:0] s_axis_tid,
input wire [DEST_WIDTH-1:0] s_axis_tdest,
input wire [USER_WIDTH-1:0] s_axis_tuser,
/*
* AXI Stream output
*/
output wire [DATA_WIDTH-1:0] m_axis_tdata,
output wire [KEEP_WIDTH-1:0] m_axis_tkeep,
output wire m_axis_tvalid,
input wire m_axis_tready,
output wire m_axis_tlast,
output wire [ID_WIDTH-1:0] m_axis_tid,
output wire [DEST_WIDTH-1:0] m_axis_tdest,
output wire [USER_WIDTH-1:0] m_axis_tuser
);
generate
if (REG_TYPE > 1) begin
// skid buffer, no bubble cycles
// datapath registers
reg s_axis_tready_reg = 1'b0;
reg [DATA_WIDTH-1:0] m_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg m_axis_tvalid_reg = 1'b0, m_axis_tvalid_next;
reg m_axis_tlast_reg = 1'b0;
reg [ID_WIDTH-1:0] m_axis_tid_reg = {ID_WIDTH{1'b0}};
reg [DEST_WIDTH-1:0] m_axis_tdest_reg = {DEST_WIDTH{1'b0}};
reg [USER_WIDTH-1:0] m_axis_tuser_reg = {USER_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] temp_m_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_m_axis_tvalid_reg = 1'b0, temp_m_axis_tvalid_next;
reg temp_m_axis_tlast_reg = 1'b0;
reg [ID_WIDTH-1:0] temp_m_axis_tid_reg = {ID_WIDTH{1'b0}};
reg [DEST_WIDTH-1:0] temp_m_axis_tdest_reg = {DEST_WIDTH{1'b0}};
reg [USER_WIDTH-1:0] temp_m_axis_tuser_reg = {USER_WIDTH{1'b0}};
// datapath control
reg store_axis_input_to_output;
reg store_axis_input_to_temp;
reg store_axis_temp_to_output;
assign s_axis_tready = s_axis_tready_reg;
assign m_axis_tdata = m_axis_tdata_reg;
assign m_axis_tkeep = KEEP_ENABLE ? m_axis_tkeep_reg : {KEEP_WIDTH{1'b1}};
assign m_axis_tvalid = m_axis_tvalid_reg;
assign m_axis_tlast = LAST_ENABLE ? m_axis_tlast_reg : 1'b1;
assign m_axis_tid = ID_ENABLE ? m_axis_tid_reg : {ID_WIDTH{1'b0}};
assign m_axis_tdest = DEST_ENABLE ? m_axis_tdest_reg : {DEST_WIDTH{1'b0}};
assign m_axis_tuser = USER_ENABLE ? m_axis_tuser_reg : {USER_WIDTH{1'b0}};
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
wire s_axis_tready_early = m_axis_tready || (!temp_m_axis_tvalid_reg && (!m_axis_tvalid_reg || !s_axis_tvalid));
always @* begin
// transfer sink ready state to source
m_axis_tvalid_next = m_axis_tvalid_reg;
temp_m_axis_tvalid_next = temp_m_axis_tvalid_reg;
store_axis_input_to_output = 1'b0;
store_axis_input_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (s_axis_tready_reg) begin
// input is ready
if (m_axis_tready || !m_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axis_tvalid_next = s_axis_tvalid;
store_axis_input_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axis_tvalid_next = s_axis_tvalid;
store_axis_input_to_temp = 1'b1;
end
end else if (m_axis_tready) begin
// input is not ready, but output is ready
m_axis_tvalid_next = temp_m_axis_tvalid_reg;
temp_m_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
s_axis_tready_reg <= 1'b0;
m_axis_tvalid_reg <= 1'b0;
temp_m_axis_tvalid_reg <= 1'b0;
end else begin
s_axis_tready_reg <= s_axis_tready_early;
m_axis_tvalid_reg <= m_axis_tvalid_next;
temp_m_axis_tvalid_reg <= temp_m_axis_tvalid_next;
end
// datapath
if (store_axis_input_to_output) begin
m_axis_tdata_reg <= s_axis_tdata;
m_axis_tkeep_reg <= s_axis_tkeep;
m_axis_tlast_reg <= s_axis_tlast;
m_axis_tid_reg <= s_axis_tid;
m_axis_tdest_reg <= s_axis_tdest;
m_axis_tuser_reg <= s_axis_tuser;
end else if (store_axis_temp_to_output) begin
m_axis_tdata_reg <= temp_m_axis_tdata_reg;
m_axis_tkeep_reg <= temp_m_axis_tkeep_reg;
m_axis_tlast_reg <= temp_m_axis_tlast_reg;
m_axis_tid_reg <= temp_m_axis_tid_reg;
m_axis_tdest_reg <= temp_m_axis_tdest_reg;
m_axis_tuser_reg <= temp_m_axis_tuser_reg;
end
if (store_axis_input_to_temp) begin
temp_m_axis_tdata_reg <= s_axis_tdata;
temp_m_axis_tkeep_reg <= s_axis_tkeep;
temp_m_axis_tlast_reg <= s_axis_tlast;
temp_m_axis_tid_reg <= s_axis_tid;
temp_m_axis_tdest_reg <= s_axis_tdest;
temp_m_axis_tuser_reg <= s_axis_tuser;
end
end
end else if (REG_TYPE == 1) begin
// simple register, inserts bubble cycles
// datapath registers
reg s_axis_tready_reg = 1'b0;
reg [DATA_WIDTH-1:0] m_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg m_axis_tvalid_reg = 1'b0, m_axis_tvalid_next;
reg m_axis_tlast_reg = 1'b0;
reg [ID_WIDTH-1:0] m_axis_tid_reg = {ID_WIDTH{1'b0}};
reg [DEST_WIDTH-1:0] m_axis_tdest_reg = {DEST_WIDTH{1'b0}};
reg [USER_WIDTH-1:0] m_axis_tuser_reg = {USER_WIDTH{1'b0}};
// datapath control
reg store_axis_input_to_output;
assign s_axis_tready = s_axis_tready_reg;
assign m_axis_tdata = m_axis_tdata_reg;
assign m_axis_tkeep = KEEP_ENABLE ? m_axis_tkeep_reg : {KEEP_WIDTH{1'b1}};
assign m_axis_tvalid = m_axis_tvalid_reg;
assign m_axis_tlast = LAST_ENABLE ? m_axis_tlast_reg : 1'b1;
assign m_axis_tid = ID_ENABLE ? m_axis_tid_reg : {ID_WIDTH{1'b0}};
assign m_axis_tdest = DEST_ENABLE ? m_axis_tdest_reg : {DEST_WIDTH{1'b0}};
assign m_axis_tuser = USER_ENABLE ? m_axis_tuser_reg : {USER_WIDTH{1'b0}};
// enable ready input next cycle if output buffer will be empty
wire s_axis_tready_early = !m_axis_tvalid_next;
always @* begin
// transfer sink ready state to source
m_axis_tvalid_next = m_axis_tvalid_reg;
store_axis_input_to_output = 1'b0;
if (s_axis_tready_reg) begin
m_axis_tvalid_next = s_axis_tvalid;
store_axis_input_to_output = 1'b1;
end else if (m_axis_tready) begin
m_axis_tvalid_next = 1'b0;
end
end
always @(posedge clk) begin
if (rst) begin
s_axis_tready_reg <= 1'b0;
m_axis_tvalid_reg <= 1'b0;
end else begin
s_axis_tready_reg <= s_axis_tready_early;
m_axis_tvalid_reg <= m_axis_tvalid_next;
end
// datapath
if (store_axis_input_to_output) begin
m_axis_tdata_reg <= s_axis_tdata;
m_axis_tkeep_reg <= s_axis_tkeep;
m_axis_tlast_reg <= s_axis_tlast;
m_axis_tid_reg <= s_axis_tid;
m_axis_tdest_reg <= s_axis_tdest;
m_axis_tuser_reg <= s_axis_tuser;
end
end
end else begin
// bypass
assign m_axis_tdata = s_axis_tdata;
assign m_axis_tkeep = KEEP_ENABLE ? s_axis_tkeep : {KEEP_WIDTH{1'b1}};
assign m_axis_tvalid = s_axis_tvalid;
assign m_axis_tlast = LAST_ENABLE ? s_axis_tlast : 1'b1;
assign m_axis_tid = ID_ENABLE ? s_axis_tid : {ID_WIDTH{1'b0}};
assign m_axis_tdest = DEST_ENABLE ? s_axis_tdest : {DEST_WIDTH{1'b0}};
assign m_axis_tuser = USER_ENABLE ? s_axis_tuser : {USER_WIDTH{1'b0}};
assign s_axis_tready = m_axis_tready;
end
endgenerate
endmodule

View File

@ -0,0 +1,89 @@
/*
Copyright (c) 2014-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.
*/
// Language: Verilog-2001
`timescale 1 ns / 1 ps
/*
* Synchronizes switch and button inputs with a slow sampled shift register
*/
module debounce_switch #(
parameter WIDTH=1, // width of the input and output signals
parameter N=3, // length of shift register
parameter RATE=125000 // clock division factor
)(
input wire clk,
input wire rst,
input wire [WIDTH-1:0] in,
output wire [WIDTH-1:0] out
);
reg [23:0] cnt_reg = 24'd0;
reg [N-1:0] debounce_reg[WIDTH-1:0];
reg [WIDTH-1:0] state;
/*
* The synchronized output is the state register
*/
assign out = state;
integer k;
always @(posedge clk or posedge rst) begin
if (rst) begin
cnt_reg <= 0;
state <= 0;
for (k = 0; k < WIDTH; k = k + 1) begin
debounce_reg[k] <= 0;
end
end else begin
if (cnt_reg < RATE) begin
cnt_reg <= cnt_reg + 24'd1;
end else begin
cnt_reg <= 24'd0;
end
if (cnt_reg == 24'd0) begin
for (k = 0; k < WIDTH; k = k + 1) begin
debounce_reg[k] <= {debounce_reg[k][N-2:0], in[k]};
end
end
for (k = 0; k < WIDTH; k = k + 1) begin
if (|debounce_reg[k] == 0) begin
state[k] <= 0;
end else if (&debounce_reg[k] == 1) begin
state[k] <= 1;
end else begin
state[k] <= state[k];
end
end
end
end
endmodule

View File

@ -0,0 +1,402 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* FPGA top-level module
*/
module fpga (
/*
* GPIO
*/
output wire [1:0] sfp_1_led,
output wire [1:0] sfp_2_led,
output wire [1:0] sma_led,
/*
* PCI express
*/
input wire [7:0] pcie_rx_p,
input wire [7:0] pcie_rx_n,
output wire [7:0] pcie_tx_p,
output wire [7:0] pcie_tx_n,
input wire pcie_mgt_refclk_p,
input wire pcie_mgt_refclk_n,
input wire pcie_reset_n
);
parameter AXIS_PCIE_DATA_WIDTH = 256;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
// PCIe
wire pcie_user_clk;
wire pcie_user_reset;
wire pcie_sys_clk;
wire pcie_sys_clk_gt;
IBUFDS_GTE3 #(
.REFCLK_HROW_CK_SEL(2'b00)
)
ibufds_gte3_pcie_mgt_refclk_inst (
.I (pcie_mgt_refclk_p),
.IB (pcie_mgt_refclk_n),
.CEB (1'b0),
.O (pcie_sys_clk_gt),
.ODIV2 (pcie_sys_clk)
);
wire [AXIS_PCIE_DATA_WIDTH-1:0] axis_rq_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] axis_rq_tkeep;
wire axis_rq_tlast;
wire axis_rq_tready;
wire [59:0] axis_rq_tuser;
wire axis_rq_tvalid;
wire [AXIS_PCIE_DATA_WIDTH-1:0] axis_rc_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] axis_rc_tkeep;
wire axis_rc_tlast;
wire axis_rc_tready;
wire [74:0] axis_rc_tuser;
wire axis_rc_tvalid;
wire [AXIS_PCIE_DATA_WIDTH-1:0] axis_cq_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] axis_cq_tkeep;
wire axis_cq_tlast;
wire axis_cq_tready;
wire [84:0] axis_cq_tuser;
wire axis_cq_tvalid;
wire [AXIS_PCIE_DATA_WIDTH-1:0] axis_cc_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] axis_cc_tkeep;
wire axis_cc_tlast;
wire axis_cc_tready;
wire [32:0] axis_cc_tuser;
wire axis_cc_tvalid;
// ila_0 rq_ila (
// .clk(pcie_user_clk),
// .probe0(axis_rq_tdata),
// .probe1(axis_rq_tkeep),
// .probe2(axis_rq_tlast),
// .probe3(axis_rq_tready),
// .probe4(axis_rq_tuser),
// .probe5(axis_rq_tvalid)
// );
// ila_0 rc_ila (
// .clk(pcie_user_clk),
// .probe0(axis_rc_tdata),
// .probe1(axis_rc_tkeep),
// .probe2(axis_rc_tlast),
// .probe3(axis_rc_tready),
// .probe4(axis_rc_tuser),
// .probe5(axis_rc_tvalid)
// );
wire [2:0] cfg_max_payload;
wire [2:0] cfg_max_read_req;
wire [18:0] cfg_mgmt_addr;
wire cfg_mgmt_write;
wire [31:0] cfg_mgmt_write_data;
wire [3:0] cfg_mgmt_byte_enable;
wire cfg_mgmt_read;
wire [31:0] cfg_mgmt_read_data;
wire cfg_mgmt_read_write_done;
wire [3:0] cfg_interrupt_msi_enable;
wire [7:0] cfg_interrupt_msi_vf_enable;
wire [11:0] cfg_interrupt_msi_mmenable;
wire cfg_interrupt_msi_mask_update;
wire [31:0] cfg_interrupt_msi_data;
wire [3:0] cfg_interrupt_msi_select;
wire [31:0] cfg_interrupt_msi_int;
wire [31:0] cfg_interrupt_msi_pending_status;
wire cfg_interrupt_msi_pending_status_data_enable;
wire [3:0] cfg_interrupt_msi_pending_status_function_num;
wire cfg_interrupt_msi_sent;
wire cfg_interrupt_msi_fail;
wire [2:0] cfg_interrupt_msi_attr;
wire cfg_interrupt_msi_tph_present;
wire [1:0] cfg_interrupt_msi_tph_type;
wire [8:0] cfg_interrupt_msi_tph_st_tag;
wire [3:0] cfg_interrupt_msi_function_number;
wire status_error_cor;
wire status_error_uncor;
pcie3_ultrascale_0
pcie3_ultrascale_inst (
.pci_exp_txn(pcie_tx_n),
.pci_exp_txp(pcie_tx_p),
.pci_exp_rxn(pcie_rx_n),
.pci_exp_rxp(pcie_rx_p),
.user_clk(pcie_user_clk),
.user_reset(pcie_user_reset),
.user_lnk_up(),
.s_axis_rq_tdata(axis_rq_tdata),
.s_axis_rq_tkeep(axis_rq_tkeep),
.s_axis_rq_tlast(axis_rq_tlast),
.s_axis_rq_tready(axis_rq_tready),
.s_axis_rq_tuser(axis_rq_tuser),
.s_axis_rq_tvalid(axis_rq_tvalid),
.m_axis_rc_tdata(axis_rc_tdata),
.m_axis_rc_tkeep(axis_rc_tkeep),
.m_axis_rc_tlast(axis_rc_tlast),
.m_axis_rc_tready(axis_rc_tready),
.m_axis_rc_tuser(axis_rc_tuser),
.m_axis_rc_tvalid(axis_rc_tvalid),
.m_axis_cq_tdata(axis_cq_tdata),
.m_axis_cq_tkeep(axis_cq_tkeep),
.m_axis_cq_tlast(axis_cq_tlast),
.m_axis_cq_tready(axis_cq_tready),
.m_axis_cq_tuser(axis_cq_tuser),
.m_axis_cq_tvalid(axis_cq_tvalid),
.s_axis_cc_tdata(axis_cc_tdata),
.s_axis_cc_tkeep(axis_cc_tkeep),
.s_axis_cc_tlast(axis_cc_tlast),
.s_axis_cc_tready(axis_cc_tready),
.s_axis_cc_tuser(axis_cc_tuser),
.s_axis_cc_tvalid(axis_cc_tvalid),
.pcie_rq_seq_num(),
.pcie_rq_seq_num_vld(),
.pcie_rq_tag(),
.pcie_rq_tag_av(),
.pcie_rq_tag_vld(),
.pcie_tfc_nph_av(),
.pcie_tfc_npd_av(),
.pcie_cq_np_req(1'b1),
.pcie_cq_np_req_count(),
.cfg_phy_link_down(),
.cfg_phy_link_status(),
.cfg_negotiated_width(),
.cfg_current_speed(),
.cfg_max_payload(cfg_max_payload),
.cfg_max_read_req(cfg_max_read_req),
.cfg_function_status(),
.cfg_function_power_state(),
.cfg_vf_status(),
.cfg_vf_power_state(),
.cfg_link_power_state(),
.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(1'b0),
.cfg_err_cor_out(),
.cfg_err_nonfatal_out(),
.cfg_err_fatal_out(),
.cfg_local_error(),
.cfg_ltr_enable(),
.cfg_ltssm_state(),
.cfg_rcb_status(),
.cfg_dpa_substate_change(),
.cfg_obff_enable(),
.cfg_pl_status_change(),
.cfg_tph_requester_enable(),
.cfg_tph_st_mode(),
.cfg_vf_tph_requester_enable(),
.cfg_vf_tph_st_mode(),
.cfg_msg_received(),
.cfg_msg_received_data(),
.cfg_msg_received_type(),
.cfg_msg_transmit(1'b0),
.cfg_msg_transmit_type(3'd0),
.cfg_msg_transmit_data(32'd0),
.cfg_msg_transmit_done(),
.cfg_fc_ph(),
.cfg_fc_pd(),
.cfg_fc_nph(),
.cfg_fc_npd(),
.cfg_fc_cplh(),
.cfg_fc_cpld(),
.cfg_fc_sel(3'd0),
.cfg_per_func_status_control(3'd0),
.cfg_per_func_status_data(),
.cfg_per_function_number(4'd0),
.cfg_per_function_output_request(1'b0),
.cfg_per_function_update_done(),
.cfg_dsn(64'd0),
.cfg_power_state_change_ack(1'b1),
.cfg_power_state_change_interrupt(),
.cfg_err_cor_in(status_error_cor),
.cfg_err_uncor_in(status_error_uncor),
.cfg_flr_in_process(),
.cfg_flr_done(4'd0),
.cfg_vf_flr_in_process(),
.cfg_vf_flr_done(8'd0),
.cfg_link_training_enable(1'b1),
.cfg_interrupt_int(4'd0),
.cfg_interrupt_pending(4'd0),
.cfg_interrupt_sent(),
.cfg_interrupt_msi_enable(cfg_interrupt_msi_enable),
.cfg_interrupt_msi_vf_enable(cfg_interrupt_msi_vf_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_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),
.cfg_hot_reset_out(),
.cfg_config_space_enable(1'b1),
.cfg_req_pm_transition_l23_ready(1'b0),
.cfg_hot_reset_in(1'b0),
.cfg_ds_port_number(8'd0),
.cfg_ds_bus_number(8'd0),
.cfg_ds_device_number(5'd0),
.cfg_ds_function_number(3'd0),
.cfg_subsys_vend_id(16'h1234),
.sys_clk(pcie_sys_clk),
.sys_clk_gt(pcie_sys_clk_gt),
.sys_reset(pcie_reset_n),
.pcie_perstn1_in(1'b0),
.pcie_perstn0_out(),
.pcie_perstn1_out(),
.int_qpll1lock_out(),
.int_qpll1outrefclk_out(),
.int_qpll1outclk_out(),
.phy_rdy_out()
);
fpga_core #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH)
)
core_inst (
/*
* Clock: 250 MHz
* Synchronous reset
*/
.clk(pcie_user_clk),
.rst(pcie_user_reset),
/*
* GPIO
*/
.sfp_1_led(sfp_1_led),
.sfp_2_led(sfp_2_led),
.sma_led(sma_led),
/*
* PCIe
*/
.m_axis_rq_tdata(axis_rq_tdata),
.m_axis_rq_tkeep(axis_rq_tkeep),
.m_axis_rq_tlast(axis_rq_tlast),
.m_axis_rq_tready(axis_rq_tready),
.m_axis_rq_tuser(axis_rq_tuser),
.m_axis_rq_tvalid(axis_rq_tvalid),
.s_axis_rc_tdata(axis_rc_tdata),
.s_axis_rc_tkeep(axis_rc_tkeep),
.s_axis_rc_tlast(axis_rc_tlast),
.s_axis_rc_tready(axis_rc_tready),
.s_axis_rc_tuser(axis_rc_tuser),
.s_axis_rc_tvalid(axis_rc_tvalid),
.s_axis_cq_tdata(axis_cq_tdata),
.s_axis_cq_tkeep(axis_cq_tkeep),
.s_axis_cq_tlast(axis_cq_tlast),
.s_axis_cq_tready(axis_cq_tready),
.s_axis_cq_tuser(axis_cq_tuser),
.s_axis_cq_tvalid(axis_cq_tvalid),
.m_axis_cc_tdata(axis_cc_tdata),
.m_axis_cc_tkeep(axis_cc_tkeep),
.m_axis_cc_tlast(axis_cc_tlast),
.m_axis_cc_tready(axis_cc_tready),
.m_axis_cc_tuser(axis_cc_tuser),
.m_axis_cc_tvalid(axis_cc_tvalid),
.cfg_max_payload(cfg_max_payload),
.cfg_max_read_req(cfg_max_read_req),
.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_interrupt_msi_enable(cfg_interrupt_msi_enable),
.cfg_interrupt_msi_vf_enable(cfg_interrupt_msi_vf_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_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),
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
endmodule

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
/*
Copyright (c) 2014-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.
*/
// Language: Verilog-2001
`timescale 1 ns / 1 ps
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
* using a pipeline of N registers.
*/
module sync_reset #(
parameter N=2 // depth of synchronizer
)(
input wire clk,
input wire rst,
output wire sync_reset_out
);
reg [N-1:0] sync_reg = {N{1'b1}};
assign sync_reset_out = sync_reg[N-1];
always @(posedge clk or posedge rst) begin
if (rst)
sync_reg <= {N{1'b1}};
else
sync_reg <= {sync_reg[N-2:0], 1'b0};
end
endmodule

View File

@ -0,0 +1,58 @@
/*
Copyright (c) 2014-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.
*/
// Language: Verilog-2001
`timescale 1 ns / 1 ps
/*
* Synchronizes an asyncronous signal to a given clock by using a pipeline of
* two registers.
*/
module sync_signal #(
parameter WIDTH=1, // width of the input and output signals
parameter N=2 // depth of synchronizer
)(
input wire clk,
input wire [WIDTH-1:0] in,
output wire [WIDTH-1:0] out
);
reg [WIDTH-1:0] sync_reg[N-1:0];
/*
* The synchronized output is the last register in the pipeline.
*/
assign out = sync_reg[N-1];
integer k;
always @(posedge clk) begin
sync_reg[0] <= in;
for (k = 1; k < N; k = k + 1) begin
sync_reg[k] <= sync_reg[k-1];
end
end
endmodule

View File

@ -0,0 +1 @@
../lib/pcie/tb/axis_ep.py

View File

@ -0,0 +1 @@
../lib/pcie/tb/pcie.py

View File

@ -0,0 +1 @@
../lib/pcie/tb/pcie_us.py

View File

@ -0,0 +1,507 @@
#!/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 os
import struct
import pcie
import pcie_us
module = 'fpga_core'
testbench = 'test_%s' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("../rtl/axi_ram.v")
srcs.append("../rtl/axis_register.v")
srcs.append("../lib/pcie/rtl/axis_arb_mux.v")
srcs.append("../lib/pcie/rtl/pcie_us_axil_master.v")
srcs.append("../lib/pcie/rtl/pcie_us_axi_dma.v")
srcs.append("../lib/pcie/rtl/pcie_us_axi_dma_rd.v")
srcs.append("../lib/pcie/rtl/pcie_us_axi_dma_wr.v")
srcs.append("../lib/pcie/rtl/pcie_tag_manager.v")
srcs.append("../lib/pcie/rtl/pcie_us_axi_master.v")
srcs.append("../lib/pcie/rtl/pcie_us_axi_master_rd.v")
srcs.append("../lib/pcie/rtl/pcie_us_axi_master_wr.v")
srcs.append("../lib/pcie/rtl/pcie_us_axis_cq_demux.v")
srcs.append("../lib/pcie/rtl/pcie_us_cfg.v")
srcs.append("../lib/pcie/rtl/pcie_us_msi.v")
srcs.append("../lib/pcie/rtl/arbiter.v")
srcs.append("../lib/pcie/rtl/priority_encoder.v")
srcs.append("../lib/pcie/rtl/pulse_merge.v")
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
m_axis_rq_tready = Signal(bool(0))
s_axis_rc_tdata = Signal(intbv(0)[256:])
s_axis_rc_tkeep = Signal(intbv(0)[8:])
s_axis_rc_tlast = Signal(bool(0))
s_axis_rc_tuser = Signal(intbv(0)[75:])
s_axis_rc_tvalid = Signal(bool(0))
s_axis_cq_tdata = Signal(intbv(0)[256:])
s_axis_cq_tkeep = Signal(intbv(0)[8:])
s_axis_cq_tlast = Signal(bool(0))
s_axis_cq_tuser = Signal(intbv(0)[85:])
s_axis_cq_tvalid = Signal(bool(0))
m_axis_cc_tready = Signal(bool(0))
cfg_max_payload = Signal(intbv(0)[3:])
cfg_max_read_req = Signal(intbv(0)[3:])
cfg_mgmt_read_data = Signal(intbv(0)[32:])
cfg_mgmt_read_write_done = Signal(bool(0))
cfg_interrupt_msi_enable = Signal(intbv(0)[4:])
cfg_interrupt_msi_vf_enable = Signal(intbv(0)[8:])
cfg_interrupt_msi_mmenable = Signal(intbv(0)[12:])
cfg_interrupt_msi_mask_update = Signal(bool(0))
cfg_interrupt_msi_data = Signal(intbv(0)[32:])
cfg_interrupt_msi_sent = Signal(bool(0))
cfg_interrupt_msi_fail = Signal(bool(0))
# Outputs
sfp_1_led = Signal(intbv(0)[2:])
sfp_2_led = Signal(intbv(0)[2:])
sma_led = Signal(intbv(0)[2:])
m_axis_rq_tdata = Signal(intbv(0)[256:])
m_axis_rq_tkeep = Signal(intbv(0)[8:])
m_axis_rq_tlast = Signal(bool(0))
m_axis_rq_tuser = Signal(intbv(0)[60:])
m_axis_rq_tvalid = Signal(bool(0))
s_axis_rc_tready = Signal(bool(0))
s_axis_cq_tready = Signal(bool(0))
m_axis_cc_tdata = Signal(intbv(0)[256:])
m_axis_cc_tkeep = Signal(intbv(0)[8:])
m_axis_cc_tlast = Signal(bool(0))
m_axis_cc_tuser = Signal(intbv(0)[33:])
m_axis_cc_tvalid = Signal(bool(0))
status_error_cor = Signal(bool(0))
status_error_uncor = Signal(bool(0))
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_interrupt_msi_int = Signal(intbv(0)[32:])
cfg_interrupt_msi_pending_status = Signal(intbv(0)[32:])
cfg_interrupt_msi_select = Signal(intbv(0)[4:])
cfg_interrupt_msi_pending_status_function_num = Signal(intbv(0)[4:])
cfg_interrupt_msi_pending_status_data_enable = 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)[4:])
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# PCIe devices
rc = pcie.RootComplex()
mem_base, mem_data = rc.alloc_region(16*1024*1024)
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 8
dev.user_clock_frequency = 256e6
dev.functions[0].msi_multiple_message_capable = 5
dev.functions[0].configure_bar(0, 4*1024*1024)
dev.functions[0].configure_bar(1, 4*1024*1024)
rc.make_port().connect(dev)
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=s_axis_cq_tdata,
m_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cq_tlast=s_axis_cq_tlast,
m_axis_cq_tkeep=s_axis_cq_tkeep,
m_axis_cq_tvalid=s_axis_cq_tvalid,
m_axis_cq_tready=s_axis_cq_tready,
#pcie_cq_np_req=pcie_cq_np_req,
pcie_cq_np_req=Signal(bool(1)),
#pcie_cq_np_req_count=pcie_cq_np_req_count,
# Completer Completion Interface
s_axis_cc_tdata=m_axis_cc_tdata,
s_axis_cc_tuser=m_axis_cc_tuser,
s_axis_cc_tlast=m_axis_cc_tlast,
s_axis_cc_tkeep=m_axis_cc_tkeep,
s_axis_cc_tvalid=m_axis_cc_tvalid,
s_axis_cc_tready=m_axis_cc_tready,
# Requester reQuest Interface
s_axis_rq_tdata=m_axis_rq_tdata,
s_axis_rq_tuser=m_axis_rq_tuser,
s_axis_rq_tlast=m_axis_rq_tlast,
s_axis_rq_tkeep=m_axis_rq_tkeep,
s_axis_rq_tvalid=m_axis_rq_tvalid,
s_axis_rq_tready=m_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_vld=pcie_rq_tag_vld,
# Requester Completion Interface
m_axis_rc_tdata=s_axis_rc_tdata,
m_axis_rc_tuser=s_axis_rc_tuser,
m_axis_rc_tlast=s_axis_rc_tlast,
m_axis_rc_tkeep=s_axis_rc_tkeep,
m_axis_rc_tvalid=s_axis_rc_tvalid,
m_axis_rc_tready=s_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=status_error_cor,
cfg_err_uncor_in=status_error_uncor,
#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_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_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,
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
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
sfp_1_led=sfp_1_led,
sfp_2_led=sfp_2_led,
sma_led=sma_led,
m_axis_rq_tdata=m_axis_rq_tdata,
m_axis_rq_tkeep=m_axis_rq_tkeep,
m_axis_rq_tlast=m_axis_rq_tlast,
m_axis_rq_tready=m_axis_rq_tready,
m_axis_rq_tuser=m_axis_rq_tuser,
m_axis_rq_tvalid=m_axis_rq_tvalid,
s_axis_rc_tdata=s_axis_rc_tdata,
s_axis_rc_tkeep=s_axis_rc_tkeep,
s_axis_rc_tlast=s_axis_rc_tlast,
s_axis_rc_tready=s_axis_rc_tready,
s_axis_rc_tuser=s_axis_rc_tuser,
s_axis_rc_tvalid=s_axis_rc_tvalid,
s_axis_cq_tdata=s_axis_cq_tdata,
s_axis_cq_tkeep=s_axis_cq_tkeep,
s_axis_cq_tlast=s_axis_cq_tlast,
s_axis_cq_tready=s_axis_cq_tready,
s_axis_cq_tuser=s_axis_cq_tuser,
s_axis_cq_tvalid=s_axis_cq_tvalid,
m_axis_cc_tdata=m_axis_cc_tdata,
m_axis_cc_tkeep=m_axis_cc_tkeep,
m_axis_cc_tlast=m_axis_cc_tlast,
m_axis_cc_tready=m_axis_cc_tready,
m_axis_cc_tuser=m_axis_cc_tuser,
m_axis_cc_tvalid=m_axis_cc_tvalid,
cfg_max_payload=cfg_max_payload,
cfg_max_read_req=cfg_max_read_req,
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_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_msi_pending_status_function_num=cfg_interrupt_msi_pending_status_function_num,
cfg_interrupt_msi_pending_status_data_enable=cfg_interrupt_msi_pending_status_data_enable,
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,
status_error_cor=status_error_cor,
status_error_uncor=status_error_uncor
)
@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 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
# testbench stimulus
current_tag = 1
yield clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate(enable_bus_mastering=True, configure_msi=True)
dev_pf0_bar0 = dev.functions[0].bar[0] & 0xfffffffc
dev_pf0_bar1 = dev.functions[0].bar[1] & 0xfffffffc
yield delay(100)
yield clk.posedge
print("test 2: memory write to bar 1")
current_test.next = 2
yield rc.mem_write(dev_pf0_bar1, b'\x11\x22\x33\x44')
yield delay(100)
yield clk.posedge
print("test 3: memory read from bar 1")
current_test.next = 3
val = yield from rc.mem_read(dev_pf0_bar1, 4, 1000)
print(val)
assert val == b'\x11\x22\x33\x44'
yield delay(100)
yield clk.posedge
print("test 4: test DMA")
current_test.next = 4
# write packet data
mem_data[0:1024] = bytearray([x%256 for x in range(1024)])
# enable DMA
yield rc.mem_write(dev_pf0_bar0+0x100000, struct.pack('<L', 1))
# write pcie read descriptor
yield rc.mem_write(dev_pf0_bar0+0x100100, struct.pack('<L', (mem_base+0x0000) & 0xffffffff))
yield rc.mem_write(dev_pf0_bar0+0x100104, struct.pack('<L', (mem_base+0x0000 >> 32) & 0xffffffff))
yield rc.mem_write(dev_pf0_bar0+0x100108, struct.pack('<L', (0x100) & 0xffffffff))
yield rc.mem_write(dev_pf0_bar0+0x10010C, struct.pack('<L', (0x100 >> 32) & 0xffffffff))
yield rc.mem_write(dev_pf0_bar0+0x100110, struct.pack('<L', 0x400))
yield rc.mem_write(dev_pf0_bar0+0x100114, struct.pack('<L', 0xAA))
yield delay(2000)
# read status
val = yield from rc.mem_read(dev_pf0_bar0+0x100118, 4)
print(val)
# write pcie write descriptor
yield rc.mem_write(dev_pf0_bar0+0x100200, struct.pack('<L', (mem_base+0x1000) & 0xffffffff))
yield rc.mem_write(dev_pf0_bar0+0x100204, struct.pack('<L', (mem_base+0x1000 >> 32) & 0xffffffff))
yield rc.mem_write(dev_pf0_bar0+0x100208, struct.pack('<L', (0x100) & 0xffffffff))
yield rc.mem_write(dev_pf0_bar0+0x10020C, struct.pack('<L', (0x100 >> 32) & 0xffffffff))
yield rc.mem_write(dev_pf0_bar0+0x100210, struct.pack('<L', 0x400))
yield rc.mem_write(dev_pf0_bar0+0x100214, struct.pack('<L', 0x55))
yield delay(2000)
# read status
val = yield from rc.mem_read(dev_pf0_bar0+0x100218, 4)
print(val)
data = mem_data[0x1000:(0x1000)+64]
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert mem_data[0:1024] == mem_data[0x1000:0x1000+1024]
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,230 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for fpga_core
*/
module test_fpga_core;
// Parameters
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg m_axis_rq_tready = 0;
reg [255:0] s_axis_rc_tdata = 0;
reg [7:0] s_axis_rc_tkeep = 0;
reg s_axis_rc_tlast = 0;
reg [74:0] s_axis_rc_tuser = 0;
reg s_axis_rc_tvalid = 0;
reg [255:0] s_axis_cq_tdata = 0;
reg [7:0] s_axis_cq_tkeep = 0;
reg s_axis_cq_tlast = 0;
reg [84:0] s_axis_cq_tuser = 0;
reg s_axis_cq_tvalid = 0;
reg m_axis_cc_tready = 0;
reg [2:0] cfg_max_payload = 0;
reg [2:0] cfg_max_read_req = 0;
reg [31:0] cfg_mgmt_read_data = 0;
reg cfg_mgmt_read_write_done = 0;
reg [3:0] cfg_interrupt_msi_enable = 0;
reg [7:0] cfg_interrupt_msi_vf_enable = 0;
reg [11:0] cfg_interrupt_msi_mmenable = 0;
reg cfg_interrupt_msi_mask_update = 0;
reg [31:0] cfg_interrupt_msi_data = 0;
reg cfg_interrupt_msi_sent = 0;
reg cfg_interrupt_msi_fail = 0;
// Outputs
wire [1:0] sfp_1_led;
wire [1:0] sfp_2_led;
wire [1:0] sma_led;
wire [255:0] m_axis_rq_tdata;
wire [7:0] m_axis_rq_tkeep;
wire m_axis_rq_tlast;
wire [59:0] m_axis_rq_tuser;
wire m_axis_rq_tvalid;
wire s_axis_rc_tready;
wire s_axis_cq_tready;
wire [255:0] m_axis_cc_tdata;
wire [7:0] m_axis_cc_tkeep;
wire m_axis_cc_tlast;
wire [32:0] m_axis_cc_tuser;
wire m_axis_cc_tvalid;
wire [18:0] cfg_mgmt_addr;
wire cfg_mgmt_write;
wire [31:0] cfg_mgmt_write_data;
wire [3:0] cfg_mgmt_byte_enable;
wire cfg_mgmt_read;
wire [3:0] cfg_interrupt_msi_select;
wire [31:0] cfg_interrupt_msi_int;
wire [31:0] cfg_interrupt_msi_pending_status;
wire cfg_interrupt_msi_pending_status_data_enable;
wire [3:0] cfg_interrupt_msi_pending_status_function_num;
wire [2:0] cfg_interrupt_msi_attr;
wire cfg_interrupt_msi_tph_present;
wire [1:0] cfg_interrupt_msi_tph_type;
wire [8:0] cfg_interrupt_msi_tph_st_tag;
wire [3:0] cfg_interrupt_msi_function_number;
wire status_error_cor;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
m_axis_rq_tready,
s_axis_rc_tdata,
s_axis_rc_tkeep,
s_axis_rc_tlast,
s_axis_rc_tuser,
s_axis_rc_tvalid,
s_axis_cq_tdata,
s_axis_cq_tkeep,
s_axis_cq_tlast,
s_axis_cq_tuser,
s_axis_cq_tvalid,
m_axis_cc_tready,
cfg_max_payload,
cfg_max_read_req,
cfg_mgmt_read_data,
cfg_mgmt_read_write_done,
cfg_interrupt_msi_enable,
cfg_interrupt_msi_vf_enable,
cfg_interrupt_msi_mmenable,
cfg_interrupt_msi_mask_update,
cfg_interrupt_msi_data,
cfg_interrupt_msi_sent,
cfg_interrupt_msi_fail
);
$to_myhdl(
sfp_1_led,
sfp_2_led,
sma_led,
m_axis_rq_tdata,
m_axis_rq_tkeep,
m_axis_rq_tlast,
m_axis_rq_tuser,
m_axis_rq_tvalid,
s_axis_rc_tready,
s_axis_cq_tready,
m_axis_cc_tdata,
m_axis_cc_tkeep,
m_axis_cc_tlast,
m_axis_cc_tuser,
m_axis_cc_tvalid,
cfg_mgmt_addr,
cfg_mgmt_write,
cfg_mgmt_write_data,
cfg_mgmt_byte_enable,
cfg_mgmt_read,
cfg_interrupt_msi_select,
cfg_interrupt_msi_int,
cfg_interrupt_msi_pending_status,
cfg_interrupt_msi_pending_status_data_enable,
cfg_interrupt_msi_pending_status_function_num,
cfg_interrupt_msi_attr,
cfg_interrupt_msi_tph_present,
cfg_interrupt_msi_tph_type,
cfg_interrupt_msi_tph_st_tag,
cfg_interrupt_msi_function_number,
status_error_cor,
status_error_uncor
);
// dump file
$dumpfile("test_fpga_core.lxt");
$dumpvars(0, test_fpga_core);
end
fpga_core
UUT (
.clk(clk),
.rst(rst),
.sfp_1_led(sfp_1_led),
.sfp_2_led(sfp_2_led),
.sma_led(sma_led),
.m_axis_rq_tdata(m_axis_rq_tdata),
.m_axis_rq_tkeep(m_axis_rq_tkeep),
.m_axis_rq_tlast(m_axis_rq_tlast),
.m_axis_rq_tready(m_axis_rq_tready),
.m_axis_rq_tuser(m_axis_rq_tuser),
.m_axis_rq_tvalid(m_axis_rq_tvalid),
.s_axis_rc_tdata(s_axis_rc_tdata),
.s_axis_rc_tkeep(s_axis_rc_tkeep),
.s_axis_rc_tlast(s_axis_rc_tlast),
.s_axis_rc_tready(s_axis_rc_tready),
.s_axis_rc_tuser(s_axis_rc_tuser),
.s_axis_rc_tvalid(s_axis_rc_tvalid),
.s_axis_cq_tdata(s_axis_cq_tdata),
.s_axis_cq_tkeep(s_axis_cq_tkeep),
.s_axis_cq_tlast(s_axis_cq_tlast),
.s_axis_cq_tready(s_axis_cq_tready),
.s_axis_cq_tuser(s_axis_cq_tuser),
.s_axis_cq_tvalid(s_axis_cq_tvalid),
.m_axis_cc_tdata(m_axis_cc_tdata),
.m_axis_cc_tkeep(m_axis_cc_tkeep),
.m_axis_cc_tlast(m_axis_cc_tlast),
.m_axis_cc_tready(m_axis_cc_tready),
.m_axis_cc_tuser(m_axis_cc_tuser),
.m_axis_cc_tvalid(m_axis_cc_tvalid),
.cfg_max_payload(cfg_max_payload),
.cfg_max_read_req(cfg_max_read_req),
.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_interrupt_msi_enable(cfg_interrupt_msi_enable),
.cfg_interrupt_msi_vf_enable(cfg_interrupt_msi_vf_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_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),
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
endmodule

153
fpga/lib/pcie/rtl/arbiter.v Normal file
View File

@ -0,0 +1,153 @@
/*
Copyright (c) 2014-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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Arbiter module
*/
module arbiter #
(
parameter PORTS = 4,
// arbitration type: "PRIORITY" or "ROUND_ROBIN"
parameter TYPE = "PRIORITY",
// block type: "NONE", "REQUEST", "ACKNOWLEDGE"
parameter BLOCK = "NONE",
// LSB priority: "LOW", "HIGH"
parameter LSB_PRIORITY = "LOW"
)
(
input wire clk,
input wire rst,
input wire [PORTS-1:0] request,
input wire [PORTS-1:0] acknowledge,
output wire [PORTS-1:0] grant,
output wire grant_valid,
output wire [$clog2(PORTS)-1:0] grant_encoded
);
reg [PORTS-1:0] grant_reg = 0, grant_next;
reg grant_valid_reg = 0, grant_valid_next;
reg [$clog2(PORTS)-1:0] grant_encoded_reg = 0, grant_encoded_next;
assign grant_valid = grant_valid_reg;
assign grant = grant_reg;
assign grant_encoded = grant_encoded_reg;
wire request_valid;
wire [$clog2(PORTS)-1:0] request_index;
wire [PORTS-1:0] request_mask;
priority_encoder #(
.WIDTH(PORTS),
.LSB_PRIORITY(LSB_PRIORITY)
)
priority_encoder_inst (
.input_unencoded(request),
.output_valid(request_valid),
.output_encoded(request_index),
.output_unencoded(request_mask)
);
reg [PORTS-1:0] mask_reg = 0, mask_next;
wire masked_request_valid;
wire [$clog2(PORTS)-1:0] masked_request_index;
wire [PORTS-1:0] masked_request_mask;
priority_encoder #(
.WIDTH(PORTS),
.LSB_PRIORITY(LSB_PRIORITY)
)
priority_encoder_masked (
.input_unencoded(request & mask_reg),
.output_valid(masked_request_valid),
.output_encoded(masked_request_index),
.output_unencoded(masked_request_mask)
);
always @* begin
grant_next = 0;
grant_valid_next = 0;
grant_encoded_next = 0;
mask_next = mask_reg;
if (BLOCK == "REQUEST" && grant_reg & request) begin
// granted request still asserted; hold it
grant_valid_next = grant_valid_reg;
grant_next = grant_reg;
grant_encoded_next = grant_encoded_reg;
end else if (BLOCK == "ACKNOWLEDGE" && grant_valid && !(grant_reg & acknowledge)) begin
// granted request not yet acknowledged; hold it
grant_valid_next = grant_valid_reg;
grant_next = grant_reg;
grant_encoded_next = grant_encoded_reg;
end else if (request_valid) begin
if (TYPE == "PRIORITY") begin
grant_valid_next = 1;
grant_next = request_mask;
grant_encoded_next = request_index;
end else if (TYPE == "ROUND_ROBIN") begin
if (masked_request_valid) begin
grant_valid_next = 1;
grant_next = masked_request_mask;
grant_encoded_next = masked_request_index;
if (LSB_PRIORITY == "LOW") begin
mask_next = {PORTS{1'b1}} >> (PORTS - masked_request_index);
end else begin
mask_next = {PORTS{1'b1}} << (masked_request_index + 1);
end
end else begin
grant_valid_next = 1;
grant_next = request_mask;
grant_encoded_next = request_index;
if (LSB_PRIORITY == "LOW") begin
mask_next = {PORTS{1'b1}} >> (PORTS - request_index);
end else begin
mask_next = {PORTS{1'b1}} << (request_index + 1);
end
end
end
end
end
always @(posedge clk) begin
if (rst) begin
grant_reg <= 0;
grant_valid_reg <= 0;
grant_encoded_reg <= 0;
mask_reg <= 0;
end else begin
grant_reg <= grant_next;
grant_valid_reg <= grant_valid_next;
grant_encoded_reg <= grant_encoded_next;
mask_reg <= mask_next;
end
end
endmodule

View File

@ -0,0 +1,245 @@
/*
Copyright (c) 2014-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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* AXI4-Stream arbitrated multiplexer
*/
module axis_arb_mux #
(
parameter S_COUNT = 4,
parameter DATA_WIDTH = 8,
parameter KEEP_ENABLE = (DATA_WIDTH>8),
parameter KEEP_WIDTH = (DATA_WIDTH/8),
parameter ID_ENABLE = 0,
parameter ID_WIDTH = 8,
parameter DEST_ENABLE = 0,
parameter DEST_WIDTH = 8,
parameter USER_ENABLE = 1,
parameter USER_WIDTH = 1,
// arbitration type: "PRIORITY" or "ROUND_ROBIN"
parameter ARB_TYPE = "PRIORITY",
// LSB priority: "LOW", "HIGH"
parameter LSB_PRIORITY = "HIGH"
)
(
input wire clk,
input wire rst,
/*
* AXI Stream inputs
*/
input wire [S_COUNT*DATA_WIDTH-1:0] s_axis_tdata,
input wire [S_COUNT*KEEP_WIDTH-1:0] s_axis_tkeep,
input wire [S_COUNT-1:0] s_axis_tvalid,
output wire [S_COUNT-1:0] s_axis_tready,
input wire [S_COUNT-1:0] s_axis_tlast,
input wire [S_COUNT*ID_WIDTH-1:0] s_axis_tid,
input wire [S_COUNT*DEST_WIDTH-1:0] s_axis_tdest,
input wire [S_COUNT*USER_WIDTH-1:0] s_axis_tuser,
/*
* AXI Stream output
*/
output wire [DATA_WIDTH-1:0] m_axis_tdata,
output wire [KEEP_WIDTH-1:0] m_axis_tkeep,
output wire m_axis_tvalid,
input wire m_axis_tready,
output wire m_axis_tlast,
output wire [ID_WIDTH-1:0] m_axis_tid,
output wire [DEST_WIDTH-1:0] m_axis_tdest,
output wire [USER_WIDTH-1:0] m_axis_tuser
);
parameter CL_S_COUNT = $clog2(S_COUNT);
wire [S_COUNT-1:0] request;
wire [S_COUNT-1:0] acknowledge;
wire [S_COUNT-1:0] grant;
wire grant_valid;
wire [CL_S_COUNT-1:0] grant_encoded;
// internal datapath
reg [DATA_WIDTH-1:0] m_axis_tdata_int;
reg [KEEP_WIDTH-1:0] m_axis_tkeep_int;
reg m_axis_tvalid_int;
reg m_axis_tready_int_reg = 1'b0;
reg m_axis_tlast_int;
reg [ID_WIDTH-1:0] m_axis_tid_int;
reg [DEST_WIDTH-1:0] m_axis_tdest_int;
reg [USER_WIDTH-1:0] m_axis_tuser_int;
wire m_axis_tready_int_early;
assign s_axis_tready = (m_axis_tready_int_reg && grant_valid) << grant_encoded;
// mux for incoming packet
wire [DATA_WIDTH-1:0] current_s_tdata = s_axis_tdata[grant_encoded*DATA_WIDTH +: DATA_WIDTH];
wire [KEEP_WIDTH-1:0] current_s_tkeep = s_axis_tkeep[grant_encoded*KEEP_WIDTH +: KEEP_WIDTH];
wire current_s_tvalid = s_axis_tvalid[grant_encoded];
wire current_s_tready = s_axis_tready[grant_encoded];
wire current_s_tlast = s_axis_tlast[grant_encoded];
wire [ID_WIDTH-1:0] current_s_tid = s_axis_tid[grant_encoded*ID_WIDTH +: ID_WIDTH];
wire [DEST_WIDTH-1:0] current_s_tdest = s_axis_tdest[grant_encoded*DEST_WIDTH +: DEST_WIDTH];
wire [USER_WIDTH-1:0] current_s_tuser = s_axis_tuser[grant_encoded*USER_WIDTH +: USER_WIDTH];
// arbiter instance
arbiter #(
.PORTS(S_COUNT),
.TYPE(ARB_TYPE),
.BLOCK("ACKNOWLEDGE"),
.LSB_PRIORITY(LSB_PRIORITY)
)
arb_inst (
.clk(clk),
.rst(rst),
.request(request),
.acknowledge(acknowledge),
.grant(grant),
.grant_valid(grant_valid),
.grant_encoded(grant_encoded)
);
generate
genvar n;
for (n = 0; n < S_COUNT; n = n + 1) begin
assign request[n] = s_axis_tvalid[n] && !grant[n];
assign acknowledge[n] = grant[n] && s_axis_tvalid[n] && s_axis_tready[n] && s_axis_tlast[n];
end
endgenerate
always @* begin
// pass through selected packet data
m_axis_tdata_int = current_s_tdata;
m_axis_tkeep_int = current_s_tkeep;
m_axis_tvalid_int = current_s_tvalid && m_axis_tready_int_reg && grant_valid;
m_axis_tlast_int = current_s_tlast;
m_axis_tid_int = current_s_tid;
m_axis_tdest_int = current_s_tdest;
m_axis_tuser_int = current_s_tuser;
end
// output datapath logic
reg [DATA_WIDTH-1:0] m_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg m_axis_tvalid_reg = 1'b0, m_axis_tvalid_next;
reg m_axis_tlast_reg = 1'b0;
reg [ID_WIDTH-1:0] m_axis_tid_reg = {ID_WIDTH{1'b0}};
reg [DEST_WIDTH-1:0] m_axis_tdest_reg = {DEST_WIDTH{1'b0}};
reg [USER_WIDTH-1:0] m_axis_tuser_reg = {USER_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] temp_m_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_m_axis_tvalid_reg = 1'b0, temp_m_axis_tvalid_next;
reg temp_m_axis_tlast_reg = 1'b0;
reg [ID_WIDTH-1:0] temp_m_axis_tid_reg = {ID_WIDTH{1'b0}};
reg [DEST_WIDTH-1:0] temp_m_axis_tdest_reg = {DEST_WIDTH{1'b0}};
reg [USER_WIDTH-1:0] temp_m_axis_tuser_reg = {USER_WIDTH{1'b0}};
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_axis_temp_to_output;
assign m_axis_tdata = m_axis_tdata_reg;
assign m_axis_tkeep = KEEP_ENABLE ? m_axis_tkeep_reg : {KEEP_WIDTH{1'b1}};
assign m_axis_tvalid = m_axis_tvalid_reg;
assign m_axis_tlast = m_axis_tlast_reg;
assign m_axis_tid = ID_ENABLE ? m_axis_tid_reg : {ID_WIDTH{1'b0}};
assign m_axis_tdest = DEST_ENABLE ? m_axis_tdest_reg : {DEST_WIDTH{1'b0}};
assign m_axis_tuser = USER_ENABLE ? m_axis_tuser_reg : {USER_WIDTH{1'b0}};
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_axis_tready_int_early = m_axis_tready || (!temp_m_axis_tvalid_reg && (!m_axis_tvalid_reg || !m_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
m_axis_tvalid_next = m_axis_tvalid_reg;
temp_m_axis_tvalid_next = temp_m_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (m_axis_tready_int_reg) begin
// input is ready
if (m_axis_tready || !m_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axis_tvalid_next = m_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axis_tvalid_next = m_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (m_axis_tready) begin
// input is not ready, but output is ready
m_axis_tvalid_next = temp_m_axis_tvalid_reg;
temp_m_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_axis_tvalid_reg <= 1'b0;
m_axis_tready_int_reg <= 1'b0;
temp_m_axis_tvalid_reg <= 1'b0;
end else begin
m_axis_tvalid_reg <= m_axis_tvalid_next;
m_axis_tready_int_reg <= m_axis_tready_int_early;
temp_m_axis_tvalid_reg <= temp_m_axis_tvalid_next;
end
// datapath
if (store_axis_int_to_output) begin
m_axis_tdata_reg <= m_axis_tdata_int;
m_axis_tkeep_reg <= m_axis_tkeep_int;
m_axis_tlast_reg <= m_axis_tlast_int;
m_axis_tid_reg <= m_axis_tid_int;
m_axis_tdest_reg <= m_axis_tdest_int;
m_axis_tuser_reg <= m_axis_tuser_int;
end else if (store_axis_temp_to_output) begin
m_axis_tdata_reg <= temp_m_axis_tdata_reg;
m_axis_tkeep_reg <= temp_m_axis_tkeep_reg;
m_axis_tlast_reg <= temp_m_axis_tlast_reg;
m_axis_tid_reg <= temp_m_axis_tid_reg;
m_axis_tdest_reg <= temp_m_axis_tdest_reg;
m_axis_tuser_reg <= temp_m_axis_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_m_axis_tdata_reg <= m_axis_tdata_int;
temp_m_axis_tkeep_reg <= m_axis_tkeep_int;
temp_m_axis_tlast_reg <= m_axis_tlast_int;
temp_m_axis_tid_reg <= m_axis_tid_int;
temp_m_axis_tdest_reg <= m_axis_tdest_int;
temp_m_axis_tuser_reg <= m_axis_tuser_int;
end
end
endmodule

View File

@ -0,0 +1,256 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* PCIe AXI DMA descriptor mux
*/
module pcie_axi_dma_desc_mux #
(
parameter PORTS = 2,
parameter PCIE_ADDR_WIDTH = 64,
parameter AXI_ADDR_WIDTH = 16,
parameter LEN_WIDTH = 20,
parameter S_TAG_WIDTH = 8,
parameter M_TAG_WIDTH = S_TAG_WIDTH+$clog2(PORTS),
// arbitration type: "PRIORITY" or "ROUND_ROBIN"
parameter ARB_TYPE = "PRIORITY",
// LSB priority: "LOW", "HIGH"
parameter LSB_PRIORITY = "HIGH"
)
(
input wire clk,
input wire rst,
/*
* Descriptor output (to PCIe DMA core)
*/
output wire [PCIE_ADDR_WIDTH-1:0] m_axis_desc_pcie_addr,
output wire [AXI_ADDR_WIDTH-1:0] m_axis_desc_axi_addr,
output wire [LEN_WIDTH-1:0] m_axis_desc_len,
output wire [M_TAG_WIDTH-1:0] m_axis_desc_tag,
output wire m_axis_desc_valid,
input wire m_axis_desc_ready,
/*
* Descriptor status input (from PCIe DMA core)
*/
input wire [M_TAG_WIDTH-1:0] s_axis_desc_status_tag,
input wire s_axis_desc_status_valid,
/*
* Descriptor input
*/
input wire [PORTS*PCIE_ADDR_WIDTH-1:0] s_axis_desc_pcie_addr,
input wire [PORTS*AXI_ADDR_WIDTH-1:0] s_axis_desc_axi_addr,
input wire [PORTS*LEN_WIDTH-1:0] s_axis_desc_len,
input wire [PORTS*S_TAG_WIDTH-1:0] s_axis_desc_tag,
input wire [PORTS-1:0] s_axis_desc_valid,
output wire [PORTS-1:0] s_axis_desc_ready,
/*
* Descriptor status output
*/
output wire [PORTS*S_TAG_WIDTH-1:0] m_axis_desc_status_tag,
output wire [PORTS-1:0] m_axis_desc_status_valid
);
parameter CL_PORTS = $clog2(PORTS);
// check configuration
initial begin
if (M_TAG_WIDTH < S_TAG_WIDTH+$clog2(PORTS)) begin
$error("Error: M_TAG_WIDTH must be at least $clog2(PORTS) larger than S_TAG_WIDTH");
$finish;
end
end
// descriptor mux
wire [PORTS-1:0] request;
wire [PORTS-1:0] acknowledge;
wire [PORTS-1:0] grant;
wire grant_valid;
wire [CL_PORTS-1:0] grant_encoded;
// internal datapath
reg [PCIE_ADDR_WIDTH-1:0] m_axis_desc_pcie_addr_int;
reg [AXI_ADDR_WIDTH-1:0] m_axis_desc_axi_addr_int;
reg [LEN_WIDTH-1:0] m_axis_desc_len_int;
reg [M_TAG_WIDTH-1:0] m_axis_desc_tag_int;
reg m_axis_desc_valid_int;
reg m_axis_desc_ready_int_reg = 1'b0;
wire m_axis_desc_ready_int_early;
assign s_axis_desc_ready = (m_axis_desc_ready_int_reg && grant_valid) << grant_encoded;
// mux for incoming packet
wire [PCIE_ADDR_WIDTH-1:0] current_s_desc_pcie_addr = s_axis_desc_pcie_addr[grant_encoded*PCIE_ADDR_WIDTH +: PCIE_ADDR_WIDTH];
wire [AXI_ADDR_WIDTH-1:0] current_s_desc_axi_addr = s_axis_desc_axi_addr[grant_encoded*AXI_ADDR_WIDTH +: AXI_ADDR_WIDTH];
wire [LEN_WIDTH-1:0] current_s_desc_len = s_axis_desc_len[grant_encoded*LEN_WIDTH +: LEN_WIDTH];
wire [S_TAG_WIDTH-1:0] current_s_desc_tag = s_axis_desc_tag[grant_encoded*S_TAG_WIDTH +: S_TAG_WIDTH];
wire current_s_desc_valid = s_axis_desc_valid[grant_encoded];
wire current_s_desc_ready = s_axis_desc_ready[grant_encoded];
// arbiter instance
arbiter #(
.PORTS(PORTS),
.TYPE(ARB_TYPE),
.BLOCK("ACKNOWLEDGE"),
.LSB_PRIORITY(LSB_PRIORITY)
)
arb_inst (
.clk(clk),
.rst(rst),
.request(request),
.acknowledge(acknowledge),
.grant(grant),
.grant_valid(grant_valid),
.grant_encoded(grant_encoded)
);
assign request = s_axis_desc_valid & ~grant;
assign acknowledge = grant & s_axis_desc_valid & s_axis_desc_ready;
always @* begin
// pass through selected packet data
m_axis_desc_pcie_addr_int = current_s_desc_pcie_addr;
m_axis_desc_axi_addr_int = current_s_desc_axi_addr;
m_axis_desc_len_int = current_s_desc_len;
m_axis_desc_tag_int = {grant_encoded, current_s_desc_tag};
m_axis_desc_valid_int = current_s_desc_valid && m_axis_desc_ready_int_reg && grant_valid;
end
// output datapath logic
reg [PCIE_ADDR_WIDTH-1:0] m_axis_desc_pcie_addr_reg = {PCIE_ADDR_WIDTH{1'b0}};
reg [AXI_ADDR_WIDTH-1:0] m_axis_desc_axi_addr_reg = {AXI_ADDR_WIDTH{1'b0}};
reg [LEN_WIDTH-1:0] m_axis_desc_len_reg = {LEN_WIDTH{1'b0}};
reg [M_TAG_WIDTH-1:0] m_axis_desc_tag_reg = {M_TAG_WIDTH{1'b0}};
reg m_axis_desc_valid_reg = 1'b0, m_axis_desc_valid_next;
reg [PCIE_ADDR_WIDTH-1:0] temp_m_axis_desc_pcie_addr_reg = {PCIE_ADDR_WIDTH{1'b0}};
reg [AXI_ADDR_WIDTH-1:0] temp_m_axis_desc_axi_addr_reg = {AXI_ADDR_WIDTH{1'b0}};
reg [LEN_WIDTH-1:0] temp_m_axis_desc_len_reg = {LEN_WIDTH{1'b0}};
reg [M_TAG_WIDTH-1:0] temp_m_axis_desc_tag_reg = {M_TAG_WIDTH{1'b0}};
reg temp_m_axis_desc_valid_reg = 1'b0, temp_m_axis_desc_valid_next;
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_axis_temp_to_output;
assign m_axis_desc_pcie_addr = m_axis_desc_pcie_addr_reg;
assign m_axis_desc_axi_addr = m_axis_desc_axi_addr_reg;
assign m_axis_desc_len = m_axis_desc_len_reg;
assign m_axis_desc_tag = m_axis_desc_tag_reg;
assign m_axis_desc_valid = m_axis_desc_valid_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_axis_desc_ready_int_early = m_axis_desc_ready || (!temp_m_axis_desc_valid_reg && (!m_axis_desc_valid_reg || !m_axis_desc_valid_int));
always @* begin
// transfer sink ready state to source
m_axis_desc_valid_next = m_axis_desc_valid_reg;
temp_m_axis_desc_valid_next = temp_m_axis_desc_valid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (m_axis_desc_ready_int_reg) begin
// input is ready
if (m_axis_desc_ready || !m_axis_desc_valid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axis_desc_valid_next = m_axis_desc_valid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axis_desc_valid_next = m_axis_desc_valid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (m_axis_desc_ready) begin
// input is not ready, but output is ready
m_axis_desc_valid_next = temp_m_axis_desc_valid_reg;
temp_m_axis_desc_valid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_axis_desc_valid_reg <= 1'b0;
m_axis_desc_ready_int_reg <= 1'b0;
temp_m_axis_desc_valid_reg <= 1'b0;
end else begin
m_axis_desc_valid_reg <= m_axis_desc_valid_next;
m_axis_desc_ready_int_reg <= m_axis_desc_ready_int_early;
temp_m_axis_desc_valid_reg <= temp_m_axis_desc_valid_next;
end
// datapath
if (store_axis_int_to_output) begin
m_axis_desc_pcie_addr_reg <= m_axis_desc_pcie_addr_int;
m_axis_desc_axi_addr_reg <= m_axis_desc_axi_addr_int;
m_axis_desc_len_reg <= m_axis_desc_len_int;
m_axis_desc_tag_reg <= m_axis_desc_tag_int;
end else if (store_axis_temp_to_output) begin
m_axis_desc_pcie_addr_reg <= temp_m_axis_desc_pcie_addr_reg;
m_axis_desc_axi_addr_reg <= temp_m_axis_desc_axi_addr_reg;
m_axis_desc_len_reg <= temp_m_axis_desc_len_reg;
m_axis_desc_tag_reg <= temp_m_axis_desc_tag_reg;
end
if (store_axis_int_to_temp) begin
temp_m_axis_desc_pcie_addr_reg <= m_axis_desc_pcie_addr_int;
temp_m_axis_desc_axi_addr_reg <= m_axis_desc_axi_addr_int;
temp_m_axis_desc_len_reg <= m_axis_desc_len_int;
temp_m_axis_desc_tag_reg <= m_axis_desc_tag_int;
end
end
// descriptor status demux
reg [S_TAG_WIDTH-1:0] m_axis_desc_status_tag_reg = {S_TAG_WIDTH{1'b0}}, m_axis_desc_status_tag_next;
reg [PORTS-1:0] m_axis_desc_status_valid_reg = {PORTS{1'b0}}, m_axis_desc_status_valid_next;
assign m_axis_desc_status_tag = {PORTS{m_axis_desc_status_tag_reg}};
assign m_axis_desc_status_valid = m_axis_desc_status_valid_reg;
always @* begin
m_axis_desc_status_tag_next = s_axis_desc_status_tag;
m_axis_desc_status_valid_next = s_axis_desc_status_valid << (PORTS > 1 ? s_axis_desc_status_tag[S_TAG_WIDTH+CL_PORTS-1:S_TAG_WIDTH] : 0);
end
always @(posedge clk) begin
if (rst) begin
m_axis_desc_status_valid_reg <= {PORTS{1'b0}};
end else begin
m_axis_desc_status_valid_reg <= m_axis_desc_status_valid_next;
end
m_axis_desc_status_tag_reg <= m_axis_desc_status_tag_next;
end
endmodule

View File

@ -0,0 +1,168 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* PCIe tag manager
*/
module pcie_tag_manager #
(
parameter PCIE_TAG_COUNT = 256,
parameter PCIE_TAG_WIDTH = $clog2(PCIE_TAG_COUNT),
parameter PCIE_EXT_TAG_ENABLE = 1
)
(
input wire clk,
input wire rst,
/*
* AXIS tag output
*/
output wire [PCIE_TAG_WIDTH-1:0] m_axis_tag,
output wire m_axis_tag_valid,
input wire m_axis_tag_ready,
/*
* AXIS tag output
*/
input wire [PCIE_TAG_WIDTH-1:0] s_axis_tag,
input wire s_axis_tag_valid,
/*
* Configuration
*/
input wire ext_tag_enable,
/*
* Status
*/
output wire [PCIE_TAG_COUNT-1:0] active_tags
);
// parameter assertions
initial begin
if (PCIE_TAG_WIDTH < $clog2(PCIE_TAG_COUNT)) begin
$error("Error: PCIe tag width insufficient for requested tag count");
$finish;
end
if (PCIE_TAG_COUNT < 1 || PCIE_TAG_COUNT > 256) begin
$error("Error: PCIe tag count must be between 1 and 256");
$finish;
end
if (PCIE_TAG_COUNT > 32 && !PCIE_EXT_TAG_ENABLE) begin
$warning("Warning: PCIe tag count set larger than 32, but extended tag support is disabled");
end
if (PCIE_TAG_COUNT <= 32 && PCIE_EXT_TAG_ENABLE) begin
$warning("Warning: PCIe tag count set to 32 or less, but extended tag support is enabled");
end
end
reg [PCIE_TAG_COUNT-1:0] tag_active_reg = {PCIE_TAG_COUNT{1'b0}}, tag_active_next;
reg [PCIE_TAG_COUNT-1:0] tag_mask_reg = {PCIE_TAG_COUNT{1'b0}}, tag_mask_next;
reg [PCIE_TAG_WIDTH-1:0] m_axis_tag_reg = {PCIE_TAG_WIDTH{1'b0}}, m_axis_tag_next;
reg m_axis_tag_valid_reg = 1'b0, m_axis_tag_valid_next;
assign m_axis_tag = m_axis_tag_reg;
assign m_axis_tag_valid = m_axis_tag_valid_reg;
assign active_tags = tag_active_reg;
wire tag_valid;
wire [PCIE_TAG_WIDTH-1:0] tag_index;
priority_encoder #(
.WIDTH(PCIE_TAG_COUNT),
.LSB_PRIORITY("HIGH")
)
priority_encoder_inst (
.input_unencoded(~tag_active_reg & (ext_tag_enable && PCIE_EXT_TAG_ENABLE ? {256{1'b1}} : {32{1'b1}})),
.output_valid(tag_valid),
.output_encoded(tag_index),
.output_unencoded()
);
wire masked_tag_valid;
wire [PCIE_TAG_WIDTH-1:0] masked_tag_index;
priority_encoder #(
.WIDTH(PCIE_TAG_COUNT),
.LSB_PRIORITY("HIGH")
)
priority_encoder_masked (
.input_unencoded(~tag_active_reg & tag_mask_reg & (ext_tag_enable && PCIE_EXT_TAG_ENABLE ? {256{1'b1}} : {32{1'b1}})),
.output_valid(masked_tag_valid),
.output_encoded(masked_tag_index),
.output_unencoded()
);
always @* begin
tag_active_next = tag_active_reg;
tag_mask_next = tag_mask_reg;
m_axis_tag_next = m_axis_tag_reg;
m_axis_tag_valid_next = m_axis_tag_valid_reg && !m_axis_tag_ready;
if (s_axis_tag_valid) begin
tag_active_next[s_axis_tag] = 1'b0;
end
if (!m_axis_tag_valid || m_axis_tag_ready) begin
if (tag_valid) begin
if (masked_tag_valid) begin
m_axis_tag_next = masked_tag_index;
m_axis_tag_valid_next = 1'b1;
tag_active_next[masked_tag_index] = 1'b1;
tag_mask_next = {PCIE_TAG_COUNT{1'b1}} << (masked_tag_index + 1);
end else begin
m_axis_tag_next = tag_index;
m_axis_tag_valid_next = 1'b1;
tag_active_next[tag_index] = 1'b1;
tag_mask_next = {PCIE_TAG_COUNT{1'b1}} << (tag_index + 1);
end
end
end
end
always @(posedge clk) begin
if (rst) begin
tag_active_reg <= {PCIE_TAG_COUNT{1'b0}};
tag_mask_reg <= {PCIE_TAG_COUNT{1'b0}};
m_axis_tag_valid_reg <= 1'b0;
end else begin
tag_active_reg <= tag_active_next;
tag_mask_reg <= tag_mask_next;
m_axis_tag_valid_reg <= m_axis_tag_valid_next;
end
m_axis_tag_reg <= m_axis_tag_next;
end
endmodule

View File

@ -0,0 +1,387 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Ultrascale PCIe AXI DMA
*/
module pcie_us_axi_dma #
(
parameter AXIS_PCIE_DATA_WIDTH = 256,
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32),
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH,
parameter AXI_ADDR_WIDTH = 64,
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8),
parameter AXI_ID_WIDTH = 8,
parameter AXI_MAX_BURST_LEN = 256,
parameter PCIE_ADDR_WIDTH = 64,
parameter PCIE_CLIENT_TAG = 1,
parameter PCIE_TAG_COUNT = 32,
parameter PCIE_TAG_WIDTH = $clog2(PCIE_TAG_COUNT),
parameter PCIE_EXT_TAG_ENABLE = (PCIE_TAG_COUNT>32),
parameter LEN_WIDTH = 20,
parameter TAG_WIDTH = 8
)
(
input wire clk,
input wire rst,
/*
* AXI input (RC)
*/
input wire [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_rc_tdata,
input wire [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_rc_tkeep,
input wire s_axis_rc_tvalid,
output wire s_axis_rc_tready,
input wire s_axis_rc_tlast,
input wire [74:0] s_axis_rc_tuser,
/*
* AXI output (RQ)
*/
output wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rq_tdata,
output wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rq_tkeep,
output wire m_axis_rq_tvalid,
input wire m_axis_rq_tready,
output wire m_axis_rq_tlast,
output wire [59:0] m_axis_rq_tuser,
/*
* Tag input
*/
input wire [PCIE_TAG_WIDTH-1:0] s_axis_pcie_rq_tag,
input wire s_axis_pcie_rq_tag_valid,
/*
* AXI read descriptor input
*/
input wire [PCIE_ADDR_WIDTH-1:0] s_axis_read_desc_pcie_addr,
input wire [AXI_ADDR_WIDTH-1:0] s_axis_read_desc_axi_addr,
input wire [LEN_WIDTH-1:0] s_axis_read_desc_len,
input wire [TAG_WIDTH-1:0] s_axis_read_desc_tag,
input wire s_axis_read_desc_valid,
output wire s_axis_read_desc_ready,
/*
* AXI read descriptor status output
*/
output wire [TAG_WIDTH-1:0] m_axis_read_desc_status_tag,
output wire m_axis_read_desc_status_valid,
/*
* AXI write descriptor input
*/
input wire [PCIE_ADDR_WIDTH-1:0] s_axis_write_desc_pcie_addr,
input wire [AXI_ADDR_WIDTH-1:0] s_axis_write_desc_axi_addr,
input wire [LEN_WIDTH-1:0] s_axis_write_desc_len,
input wire [TAG_WIDTH-1:0] s_axis_write_desc_tag,
input wire s_axis_write_desc_valid,
output wire s_axis_write_desc_ready,
/*
* AXI write descriptor status output
*/
output wire [TAG_WIDTH-1:0] m_axis_write_desc_status_tag,
output wire m_axis_write_desc_status_valid,
/*
* AXI master interface
*/
output wire [AXI_ID_WIDTH-1:0] m_axi_awid,
output wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr,
output wire [7:0] m_axi_awlen,
output wire [2:0] m_axi_awsize,
output wire [1:0] m_axi_awburst,
output wire m_axi_awlock,
output wire [3:0] m_axi_awcache,
output wire [2:0] m_axi_awprot,
output wire m_axi_awvalid,
input wire m_axi_awready,
output wire [AXI_DATA_WIDTH-1:0] m_axi_wdata,
output wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb,
output wire m_axi_wlast,
output wire m_axi_wvalid,
input wire m_axi_wready,
input wire [AXI_ID_WIDTH-1:0] m_axi_bid,
input wire [1:0] m_axi_bresp,
input wire m_axi_bvalid,
output wire m_axi_bready,
output wire [AXI_ID_WIDTH-1:0] m_axi_arid,
output wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr,
output wire [7:0] m_axi_arlen,
output wire [2:0] m_axi_arsize,
output wire [1:0] m_axi_arburst,
output wire m_axi_arlock,
output wire [3:0] m_axi_arcache,
output wire [2:0] m_axi_arprot,
output wire m_axi_arvalid,
input wire m_axi_arready,
input wire [AXI_ID_WIDTH-1:0] m_axi_rid,
input wire [AXI_DATA_WIDTH-1:0] m_axi_rdata,
input wire [1:0] m_axi_rresp,
input wire m_axi_rlast,
input wire m_axi_rvalid,
output wire m_axi_rready,
/*
* Configuration
*/
input wire read_enable,
input wire write_enable,
input wire ext_tag_enable,
input wire [15:0] requester_id,
input wire requester_id_enable,
input wire [2:0] max_read_request_size,
input wire [2:0] max_payload_size,
/*
* Status
*/
output wire status_error_cor,
output wire status_error_uncor
);
wire [AXIS_PCIE_DATA_WIDTH-1:0] axis_rq_tdata_read;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] axis_rq_tkeep_read;
wire axis_rq_tvalid_read;
wire axis_rq_tready_read;
wire axis_rq_tlast_read;
wire [59:0] axis_rq_tuser_read;
wire [AXIS_PCIE_DATA_WIDTH-1:0] axis_rq_tdata_write;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] axis_rq_tkeep_write;
wire axis_rq_tvalid_write;
wire axis_rq_tready_write;
wire axis_rq_tlast_write;
wire [59:0] axis_rq_tuser_write;
pcie_us_axi_dma_rd #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
.PCIE_ADDR_WIDTH(PCIE_ADDR_WIDTH),
.PCIE_CLIENT_TAG(PCIE_CLIENT_TAG),
.PCIE_TAG_COUNT(PCIE_TAG_COUNT),
.PCIE_TAG_WIDTH(PCIE_TAG_WIDTH),
.PCIE_EXT_TAG_ENABLE(PCIE_EXT_TAG_ENABLE),
.LEN_WIDTH(LEN_WIDTH),
.TAG_WIDTH(TAG_WIDTH)
)
pcie_us_axi_dma_rd_inst (
.clk(clk),
.rst(rst),
/*
* AXI input (RC)
*/
.s_axis_rc_tdata(s_axis_rc_tdata),
.s_axis_rc_tkeep(s_axis_rc_tkeep),
.s_axis_rc_tvalid(s_axis_rc_tvalid),
.s_axis_rc_tready(s_axis_rc_tready),
.s_axis_rc_tlast(s_axis_rc_tlast),
.s_axis_rc_tuser(s_axis_rc_tuser),
/*
* AXI output (RQ)
*/
.m_axis_rq_tdata(axis_rq_tdata_read),
.m_axis_rq_tkeep(axis_rq_tkeep_read),
.m_axis_rq_tvalid(axis_rq_tvalid_read),
.m_axis_rq_tready(axis_rq_tready_read),
.m_axis_rq_tlast(axis_rq_tlast_read),
.m_axis_rq_tuser(axis_rq_tuser_read),
/*
* Tag input
*/
.s_axis_pcie_rq_tag(s_axis_pcie_rq_tag),
.s_axis_pcie_rq_tag_valid(s_axis_pcie_rq_tag_valid),
/*
* AXI read descriptor input
*/
.s_axis_read_desc_pcie_addr(s_axis_read_desc_pcie_addr),
.s_axis_read_desc_axi_addr(s_axis_read_desc_axi_addr),
.s_axis_read_desc_len(s_axis_read_desc_len),
.s_axis_read_desc_tag(s_axis_read_desc_tag),
.s_axis_read_desc_valid(s_axis_read_desc_valid),
.s_axis_read_desc_ready(s_axis_read_desc_ready),
/*
* AXI read descriptor status output
*/
.m_axis_read_desc_status_tag(m_axis_read_desc_status_tag),
.m_axis_read_desc_status_valid(m_axis_read_desc_status_valid),
/*
* AXI master interface
*/
.m_axi_awid(m_axi_awid),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awlen(m_axi_awlen),
.m_axi_awsize(m_axi_awsize),
.m_axi_awburst(m_axi_awburst),
.m_axi_awlock(m_axi_awlock),
.m_axi_awcache(m_axi_awcache),
.m_axi_awprot(m_axi_awprot),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wstrb(m_axi_wstrb),
.m_axi_wlast(m_axi_wlast),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
/*
* Configuration
*/
.enable(read_enable),
.ext_tag_enable(ext_tag_enable),
.requester_id(requester_id),
.requester_id_enable(requester_id_enable),
.max_read_request_size(max_read_request_size),
/*
* Status
*/
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
pcie_us_axi_dma_wr #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
.PCIE_ADDR_WIDTH(PCIE_ADDR_WIDTH),
.LEN_WIDTH(LEN_WIDTH),
.TAG_WIDTH(TAG_WIDTH)
)
pcie_us_axi_dma_wr_inst (
.clk(clk),
.rst(rst),
/*
* AXI output (RQ)
*/
.m_axis_rq_tdata(axis_rq_tdata_write),
.m_axis_rq_tkeep(axis_rq_tkeep_write),
.m_axis_rq_tvalid(axis_rq_tvalid_write),
.m_axis_rq_tready(axis_rq_tready_write),
.m_axis_rq_tlast(axis_rq_tlast_write),
.m_axis_rq_tuser(axis_rq_tuser_write),
/*
* AXI write descriptor input
*/
.s_axis_write_desc_pcie_addr(s_axis_write_desc_pcie_addr),
.s_axis_write_desc_axi_addr(s_axis_write_desc_axi_addr),
.s_axis_write_desc_len(s_axis_write_desc_len),
.s_axis_write_desc_tag(s_axis_write_desc_tag),
.s_axis_write_desc_valid(s_axis_write_desc_valid),
.s_axis_write_desc_ready(s_axis_write_desc_ready),
/*
* AXI write descriptor status output
*/
.m_axis_write_desc_status_tag(m_axis_write_desc_status_tag),
.m_axis_write_desc_status_valid(m_axis_write_desc_status_valid),
/*
* AXI master interface
*/
.m_axi_arid(m_axi_arid),
.m_axi_araddr(m_axi_araddr),
.m_axi_arlen(m_axi_arlen),
.m_axi_arsize(m_axi_arsize),
.m_axi_arburst(m_axi_arburst),
.m_axi_arlock(m_axi_arlock),
.m_axi_arcache(m_axi_arcache),
.m_axi_arprot(m_axi_arprot),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rid(m_axi_rid),
.m_axi_rdata(m_axi_rdata),
.m_axi_rresp(m_axi_rresp),
.m_axi_rlast(m_axi_rlast),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready),
/*
* Configuration
*/
.enable(write_enable),
.requester_id(requester_id),
.requester_id_enable(requester_id_enable),
.max_payload_size(max_payload_size)
);
axis_arb_mux #(
.S_COUNT(2),
.DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.KEEP_ENABLE(1),
.KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.ID_ENABLE(0),
.DEST_ENABLE(0),
.USER_ENABLE(1),
.USER_WIDTH(60),
.ARB_TYPE("PRIORITY"),
.LSB_PRIORITY("HIGH")
)
request_mux_inst (
.clk(clk),
.rst(rst),
.s_axis_tdata({axis_rq_tdata_write, axis_rq_tdata_read}),
.s_axis_tkeep({axis_rq_tkeep_write, axis_rq_tkeep_read}),
.s_axis_tvalid({axis_rq_tvalid_write, axis_rq_tvalid_read}),
.s_axis_tready({axis_rq_tready_write, axis_rq_tready_read}),
.s_axis_tlast({axis_rq_tlast_write, axis_rq_tlast_read}),
.s_axis_tid(0),
.s_axis_tdest(0),
.s_axis_tuser({axis_rq_tuser_write, axis_rq_tuser_read}),
.m_axis_tdata(m_axis_rq_tdata),
.m_axis_tkeep(m_axis_rq_tkeep),
.m_axis_tvalid(m_axis_rq_tvalid),
.m_axis_tready(m_axis_rq_tready),
.m_axis_tlast(m_axis_rq_tlast),
.m_axis_tid(),
.m_axis_tdest(),
.m_axis_tuser(m_axis_rq_tuser)
);
endmodule

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,858 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Ultrascale PCIe AXI DMA Write
*/
module pcie_us_axi_dma_wr #
(
parameter AXIS_PCIE_DATA_WIDTH = 256,
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32),
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH,
parameter AXI_ADDR_WIDTH = 64,
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8),
parameter AXI_ID_WIDTH = 8,
parameter AXI_MAX_BURST_LEN = 256,
parameter PCIE_ADDR_WIDTH = 64,
parameter LEN_WIDTH = 20,
parameter TAG_WIDTH = 8
)
(
input wire clk,
input wire rst,
/*
* AXI output (RQ)
*/
output wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rq_tdata,
output wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rq_tkeep,
output wire m_axis_rq_tvalid,
input wire m_axis_rq_tready,
output wire m_axis_rq_tlast,
output wire [59:0] m_axis_rq_tuser,
/*
* AXI write descriptor input
*/
input wire [PCIE_ADDR_WIDTH-1:0] s_axis_write_desc_pcie_addr,
input wire [AXI_ADDR_WIDTH-1:0] s_axis_write_desc_axi_addr,
input wire [LEN_WIDTH-1:0] s_axis_write_desc_len,
input wire [TAG_WIDTH-1:0] s_axis_write_desc_tag,
input wire s_axis_write_desc_valid,
output wire s_axis_write_desc_ready,
/*
* AXI write descriptor status output
*/
output wire [TAG_WIDTH-1:0] m_axis_write_desc_status_tag,
output wire m_axis_write_desc_status_valid,
/*
* AXI master interface
*/
output wire [AXI_ID_WIDTH-1:0] m_axi_arid,
output wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr,
output wire [7:0] m_axi_arlen,
output wire [2:0] m_axi_arsize,
output wire [1:0] m_axi_arburst,
output wire m_axi_arlock,
output wire [3:0] m_axi_arcache,
output wire [2:0] m_axi_arprot,
output wire m_axi_arvalid,
input wire m_axi_arready,
input wire [AXI_ID_WIDTH-1:0] m_axi_rid,
input wire [AXI_DATA_WIDTH-1:0] m_axi_rdata,
input wire [1:0] m_axi_rresp,
input wire m_axi_rlast,
input wire m_axi_rvalid,
output wire m_axi_rready,
/*
* Configuration
*/
input wire enable,
input wire [15:0] requester_id,
input wire requester_id_enable,
input wire [2:0] max_payload_size
);
parameter AXI_WORD_WIDTH = AXI_STRB_WIDTH;
parameter AXI_WORD_SIZE = AXI_DATA_WIDTH/AXI_WORD_WIDTH;
parameter AXI_BURST_SIZE = $clog2(AXI_STRB_WIDTH);
parameter AXI_MAX_BURST_SIZE = AXI_MAX_BURST_LEN*AXI_WORD_WIDTH;
parameter AXIS_PCIE_WORD_WIDTH = AXIS_PCIE_KEEP_WIDTH;
parameter AXIS_PCIE_WORD_SIZE = AXIS_PCIE_DATA_WIDTH/AXIS_PCIE_WORD_WIDTH;
parameter OFFSET_WIDTH = $clog2(AXI_DATA_WIDTH/8);
parameter WORD_LEN_WIDTH = LEN_WIDTH - $clog2(AXIS_PCIE_KEEP_WIDTH);
parameter CYCLE_COUNT_WIDTH = 13-AXI_BURST_SIZE;
// bus width assertions
initial begin
if (AXIS_PCIE_DATA_WIDTH != 64 && AXIS_PCIE_DATA_WIDTH != 128 && AXIS_PCIE_DATA_WIDTH != 256) begin
$error("Error: PCIe interface width must be 64, 128, or 256");
$finish;
end
if (AXIS_PCIE_KEEP_WIDTH * 32 != AXIS_PCIE_DATA_WIDTH) begin
$error("Error: PCIe interface requires dword (32-bit) granularity");
$finish;
end
if (AXI_DATA_WIDTH != AXIS_PCIE_DATA_WIDTH) begin
$error("Error: AXI interface width must match PCIe interface width");
$finish;
end
if (AXI_STRB_WIDTH * 8 != AXI_DATA_WIDTH) begin
$error("Error: AXI interface requires byte (8-bit) granularity");
$finish;
end
if (AXI_MAX_BURST_LEN < 1 || AXI_MAX_BURST_LEN > 256) begin
$error("Error: AXI_MAX_BURST_LEN must be between 1 and 256");
$finish;
end
end
localparam [3:0]
REQ_MEM_READ = 4'b0000,
REQ_MEM_WRITE = 4'b0001,
REQ_IO_READ = 4'b0010,
REQ_IO_WRITE = 4'b0011,
REQ_MEM_FETCH_ADD = 4'b0100,
REQ_MEM_SWAP = 4'b0101,
REQ_MEM_CAS = 4'b0110,
REQ_MEM_READ_LOCKED = 4'b0111,
REQ_CFG_READ_0 = 4'b1000,
REQ_CFG_READ_1 = 4'b1001,
REQ_CFG_WRITE_0 = 4'b1010,
REQ_CFG_WRITE_1 = 4'b1011,
REQ_MSG = 4'b1100,
REQ_MSG_VENDOR = 4'b1101,
REQ_MSG_ATS = 4'b1110;
localparam [2:0]
CPL_STATUS_SC = 3'b000, // successful completion
CPL_STATUS_UR = 3'b001, // unsupported request
CPL_STATUS_CRS = 3'b010, // configuration request retry status
CPL_STATUS_CA = 3'b100; // completer abort
localparam [1:0]
AXI_STATE_IDLE = 2'd0,
AXI_STATE_START = 2'd1,
AXI_STATE_REQ = 2'd2;
reg [1:0] axi_state_reg = AXI_STATE_IDLE, axi_state_next;
localparam [1:0]
TLP_STATE_IDLE = 2'd0,
TLP_STATE_HEADER_1 = 2'd1,
TLP_STATE_HEADER_2 = 2'd2,
TLP_STATE_TRANSFER = 2'd3;
reg [1:0] tlp_state_reg = TLP_STATE_IDLE, tlp_state_next;
// datapath control signals
reg transfer_in_save;
reg tlp_cmd_ready;
reg [PCIE_ADDR_WIDTH-1:0] pcie_addr_reg = {PCIE_ADDR_WIDTH{1'b0}}, pcie_addr_next;
reg [AXI_ADDR_WIDTH-1:0] axi_addr_reg = {AXI_ADDR_WIDTH{1'b0}}, axi_addr_next;
reg [LEN_WIDTH-1:0] op_count_reg = {LEN_WIDTH{1'b0}}, op_count_next;
reg [LEN_WIDTH-1:0] tr_count_reg = {LEN_WIDTH{1'b0}}, tr_count_next;
reg [LEN_WIDTH-1:0] tlp_count_reg = {LEN_WIDTH{1'b0}}, tlp_count_next;
reg [PCIE_ADDR_WIDTH-1:0] tlp_addr_reg = {PCIE_ADDR_WIDTH{1'b0}}, tlp_addr_next;
reg [11:0] tlp_len_reg = 12'd0, tlp_len_next;
reg [OFFSET_WIDTH-1:0] offset_reg = {OFFSET_WIDTH{1'b0}}, offset_next;
reg [9:0] dword_count_reg = 10'd0, dword_count_next;
reg [CYCLE_COUNT_WIDTH-1:0] input_cycle_count_reg = {CYCLE_COUNT_WIDTH{1'b0}}, input_cycle_count_next;
reg [CYCLE_COUNT_WIDTH-1:0] output_cycle_count_reg = {CYCLE_COUNT_WIDTH{1'b0}}, output_cycle_count_next;
reg input_active_reg = 1'b0, input_active_next;
reg bubble_cycle_reg = 1'b0, bubble_cycle_next;
reg last_cycle_reg = 1'b0, last_cycle_next;
reg last_tlp_reg = 1'b0, last_tlp_next;
reg [TAG_WIDTH-1:0] tag_reg = {TAG_WIDTH{1'b0}}, tag_next;
reg [PCIE_ADDR_WIDTH-1:0] tlp_cmd_addr_reg = {PCIE_ADDR_WIDTH{1'b0}}, tlp_cmd_addr_next;
reg [11:0] tlp_cmd_len_reg = 12'd0, tlp_cmd_len_next;
reg [9:0] tlp_cmd_dword_len_reg = 10'd0, tlp_cmd_dword_len_next;
reg [CYCLE_COUNT_WIDTH-1:0] tlp_cmd_input_cycle_len_reg = {CYCLE_COUNT_WIDTH{1'b0}}, tlp_cmd_input_cycle_len_next;
reg [CYCLE_COUNT_WIDTH-1:0] tlp_cmd_output_cycle_len_reg = {CYCLE_COUNT_WIDTH{1'b0}}, tlp_cmd_output_cycle_len_next;
reg [OFFSET_WIDTH-1:0] tlp_cmd_offset_reg = {OFFSET_WIDTH{1'b0}}, tlp_cmd_offset_next;
reg [TAG_WIDTH-1:0] tlp_cmd_tag_reg = {TAG_WIDTH{1'b0}}, tlp_cmd_tag_next;
reg tlp_cmd_bubble_cycle_reg = 1'b0, tlp_cmd_bubble_cycle_next;
reg tlp_cmd_last_reg = 1'b0, tlp_cmd_last_next;
reg tlp_cmd_valid_reg = 1'b0, tlp_cmd_valid_next;
reg [10:0] max_payload_size_dw_reg = 11'd0;
reg s_axis_write_desc_ready_reg = 1'b0, s_axis_write_desc_ready_next;
reg [TAG_WIDTH-1:0] m_axis_write_desc_status_tag_reg = {TAG_WIDTH{1'b0}}, m_axis_write_desc_status_tag_next;
reg m_axis_write_desc_status_valid_reg = 1'b0, m_axis_write_desc_status_valid_next;
reg [AXI_ADDR_WIDTH-1:0] m_axi_araddr_reg = {AXI_ADDR_WIDTH{1'b0}}, m_axi_araddr_next;
reg [7:0] m_axi_arlen_reg = 8'd0, m_axi_arlen_next;
reg m_axi_arvalid_reg = 1'b0, m_axi_arvalid_next;
reg m_axi_rready_reg = 1'b0, m_axi_rready_next;
reg [AXI_DATA_WIDTH-1:0] save_axi_rdata_reg = {AXI_DATA_WIDTH{1'b0}};
wire [AXI_DATA_WIDTH-1:0] shift_axi_rdata = {m_axi_rdata, save_axi_rdata_reg} >> ((AXI_STRB_WIDTH-offset_reg)*AXI_WORD_SIZE);
// internal datapath
reg [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rq_tdata_int;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rq_tkeep_int;
reg m_axis_rq_tvalid_int;
reg m_axis_rq_tready_int_reg = 1'b0;
reg m_axis_rq_tlast_int;
reg [59:0] m_axis_rq_tuser_int;
wire m_axis_rq_tready_int_early;
assign s_axis_write_desc_ready = s_axis_write_desc_ready_reg;
assign m_axis_write_desc_status_tag = m_axis_write_desc_status_tag_reg;
assign m_axis_write_desc_status_valid = m_axis_write_desc_status_valid_reg;
assign m_axi_arid = {AXI_ID_WIDTH{1'b0}};
assign m_axi_araddr = m_axi_araddr_reg;
assign m_axi_arlen = m_axi_arlen_reg;
assign m_axi_arsize = AXI_BURST_SIZE;
assign m_axi_arburst = 2'b01;
assign m_axi_arlock = 1'b0;
assign m_axi_arcache = 4'b0011;
assign m_axi_arprot = 3'b010;
assign m_axi_arvalid = m_axi_arvalid_reg;
assign m_axi_rready = m_axi_rready_reg;
wire [PCIE_ADDR_WIDTH-1:0] pcie_addr_plus_max_payload = pcie_addr_reg + {max_payload_size_dw_reg, 2'b00};
wire [PCIE_ADDR_WIDTH-1:0] pcie_addr_plus_op_count = pcie_addr_reg + op_count_reg;
wire [PCIE_ADDR_WIDTH-1:0] pcie_addr_plus_tlp_count = pcie_addr_reg + tlp_count_reg;
wire [AXI_ADDR_WIDTH-1:0] axi_addr_plus_max_burst = axi_addr_reg + AXI_MAX_BURST_SIZE;
wire [AXI_ADDR_WIDTH-1:0] axi_addr_plus_op_count = axi_addr_reg + op_count_reg;
wire [AXI_ADDR_WIDTH-1:0] axi_addr_plus_tlp_count = axi_addr_reg + tlp_count_reg;
always @* begin
axi_state_next = AXI_STATE_IDLE;
s_axis_write_desc_ready_next = 1'b0;
m_axi_araddr_next = m_axi_araddr_reg;
m_axi_arlen_next = m_axi_arlen_reg;
m_axi_arvalid_next = m_axi_arvalid_reg && !m_axi_arready;
pcie_addr_next = pcie_addr_reg;
axi_addr_next = axi_addr_reg;
op_count_next = op_count_reg;
tr_count_next = tr_count_reg;
tlp_count_next = tlp_count_reg;
tlp_cmd_addr_next = tlp_cmd_addr_reg;
tlp_cmd_len_next = tlp_cmd_len_reg;
tlp_cmd_dword_len_next = tlp_cmd_dword_len_reg;
tlp_cmd_input_cycle_len_next = tlp_cmd_input_cycle_len_reg;
tlp_cmd_output_cycle_len_next = tlp_cmd_output_cycle_len_reg;
tlp_cmd_offset_next = tlp_cmd_offset_reg;
tlp_cmd_tag_next = tlp_cmd_tag_reg;
tlp_cmd_bubble_cycle_next = tlp_cmd_bubble_cycle_reg;
tlp_cmd_last_next = tlp_cmd_last_reg;
tlp_cmd_valid_next = tlp_cmd_valid_reg && !tlp_cmd_ready;
// TLP segmentation and AXI read request generation
case (axi_state_reg)
AXI_STATE_IDLE: begin
// idle state, wait for incoming descriptor
s_axis_write_desc_ready_next = !tlp_cmd_valid_reg && enable;
if (s_axis_write_desc_ready & s_axis_write_desc_valid) begin
s_axis_write_desc_ready_next = 1'b0;
pcie_addr_next = s_axis_write_desc_pcie_addr;
axi_addr_next = s_axis_write_desc_axi_addr;
op_count_next = s_axis_write_desc_len;
tlp_cmd_tag_next = s_axis_write_desc_tag;
axi_state_next = AXI_STATE_START;
end else begin
axi_state_next = AXI_STATE_IDLE;
end
end
AXI_STATE_START: begin
// start state, compute TLP length
if (!tlp_cmd_valid_reg) begin
if (op_count_reg <= {max_payload_size_dw_reg, 2'b00}-pcie_addr_reg[1:0]) begin
// packet smaller than max payload size
if (pcie_addr_reg[12] != pcie_addr_plus_op_count[12]) begin
// crosses 4k boundary
tlp_count_next = 13'h1000 - pcie_addr_reg[11:0];
end else begin
// does not cross 4k boundary, send one TLP
tlp_count_next = op_count_reg;
end
end else begin
// packet larger than max payload size
if (pcie_addr_reg[12] != pcie_addr_plus_max_payload[12]) begin
// crosses 4k boundary
tlp_count_next = 13'h1000 - pcie_addr_reg[11:0];
end else begin
// does not cross 4k boundary, send one TLP
tlp_count_next = {max_payload_size_dw_reg, 2'b00}-pcie_addr_reg[1:0];
end
end
tlp_cmd_input_cycle_len_next = (tlp_count_next + axi_addr_reg[OFFSET_WIDTH-1:0] - 1) >> AXI_BURST_SIZE;
if (AXIS_PCIE_DATA_WIDTH == 256) begin
tlp_cmd_output_cycle_len_next = (tlp_count_next + 16+pcie_addr_reg[1:0] - 1) >> AXI_BURST_SIZE;
end else begin
tlp_cmd_output_cycle_len_next = (tlp_count_next + pcie_addr_reg[1:0] - 1) >> AXI_BURST_SIZE;
end
pcie_addr_next = pcie_addr_reg + tlp_count_next;
op_count_next = op_count_reg - tlp_count_next;
tlp_cmd_addr_next = pcie_addr_reg;
tlp_cmd_len_next = tlp_count_next;
tlp_cmd_dword_len_next = (tlp_count_next + pcie_addr_reg[1:0] + 3) >> 2;
if (AXIS_PCIE_DATA_WIDTH == 256) begin
tlp_cmd_offset_next = 16+pcie_addr_reg[1:0]-axi_addr_reg[OFFSET_WIDTH-1:0];
tlp_cmd_bubble_cycle_next = axi_addr_reg[OFFSET_WIDTH-1:0] > 16+pcie_addr_reg[1:0];
end else begin
tlp_cmd_offset_next = pcie_addr_reg[1:0]-axi_addr_reg[OFFSET_WIDTH-1:0];
tlp_cmd_bubble_cycle_next = axi_addr_reg[OFFSET_WIDTH-1:0] > pcie_addr_reg[1:0];
end
tlp_cmd_last_next = op_count_next == 0;
tlp_cmd_valid_next = 1'b1;
axi_state_next = AXI_STATE_REQ;
end else begin
axi_state_next = AXI_STATE_START;
end
end
AXI_STATE_REQ: begin
// request state, generate AXI read requests
if (!m_axi_arvalid) begin
if (tlp_count_reg <= AXI_MAX_BURST_SIZE-axi_addr_reg[1:0]) begin
// packet smaller than max burst size
if (axi_addr_reg[12] != axi_addr_plus_tlp_count[12]) begin
// crosses 4k boundary
tr_count_next = 13'h1000 - axi_addr_reg[11:0];
end else begin
// does not cross 4k boundary, send one request
tr_count_next = tlp_count_reg;
end
end else begin
// packet larger than max burst size
if (axi_addr_reg[12] != axi_addr_plus_max_burst[12]) begin
// crosses 4k boundary
tr_count_next = 13'h1000 - axi_addr_reg[11:0];
end else begin
// does not cross 4k boundary, send one request
tr_count_next = AXI_MAX_BURST_SIZE - axi_addr_reg[OFFSET_WIDTH-1:0];
end
end
m_axi_araddr_next = axi_addr_reg;
m_axi_arlen_next = (tr_count_next + axi_addr_reg[OFFSET_WIDTH-1:0] - 1) >> AXI_BURST_SIZE;
m_axi_arvalid_next = 1;
axi_addr_next = axi_addr_reg + tr_count_next;
tlp_count_next = tlp_count_reg - tr_count_next;
if (tlp_count_next != 0) begin
axi_state_next = AXI_STATE_REQ;
end else if (op_count_next != 0) begin
axi_state_next = AXI_STATE_START;
end else begin
s_axis_write_desc_ready_next = !tlp_cmd_valid_reg && enable;
axi_state_next = AXI_STATE_IDLE;
end
end else begin
axi_state_next = AXI_STATE_REQ;
end
end
endcase
end
wire [3:0] first_be = 4'b1111 << tlp_addr_reg[1:0];
wire [3:0] last_be = 4'b1111 >> (3 - ((tlp_addr_reg[1:0] + tlp_len_reg[1:0] - 1) & 3));
always @* begin
tlp_state_next = TLP_STATE_IDLE;
transfer_in_save = 1'b0;
tlp_cmd_ready = 1'b0;
m_axis_write_desc_status_tag_next = m_axis_write_desc_status_tag_reg;
m_axis_write_desc_status_valid_next = 1'b0;
m_axi_rready_next = 1'b0;
tlp_addr_next = tlp_addr_reg;
tlp_len_next = tlp_len_reg;
dword_count_next = dword_count_reg;
offset_next = offset_reg;
input_cycle_count_next = input_cycle_count_reg;
output_cycle_count_next = output_cycle_count_reg;
input_active_next = input_active_reg;
bubble_cycle_next = bubble_cycle_reg;
last_cycle_next = last_cycle_reg;
last_tlp_next = last_tlp_reg;
tag_next = tag_reg;
m_axis_rq_tdata_int = {AXIS_PCIE_DATA_WIDTH{1'b0}};
m_axis_rq_tkeep_int = {AXIS_PCIE_KEEP_WIDTH{1'b0}};
m_axis_rq_tvalid_int = 1'b0;
m_axis_rq_tlast_int = 1'b0;
m_axis_rq_tuser_int = 60'd0;
m_axis_rq_tdata_int[1:0] = 2'b0; // address type
m_axis_rq_tdata_int[63:2] = tlp_addr_reg[PCIE_ADDR_WIDTH-1:2]; // address
if (AXIS_PCIE_DATA_WIDTH > 64) begin
m_axis_rq_tdata_int[74:64] = dword_count_reg; // DWORD count
m_axis_rq_tdata_int[78:75] = REQ_MEM_WRITE; // request type - memory write
m_axis_rq_tdata_int[79] = 1'b0; // poisoned request
m_axis_rq_tdata_int[95:80] = requester_id;
m_axis_rq_tdata_int[103:96] = 8'd0; // tag
m_axis_rq_tdata_int[119:104] = 16'd0; // completer ID
m_axis_rq_tdata_int[120] = requester_id_enable; // requester ID enable
m_axis_rq_tdata_int[123:121] = 3'b000; // traffic class
m_axis_rq_tdata_int[126:124] = 3'b000; // attr
m_axis_rq_tdata_int[127] = 1'b0; // force ECRC
end
if (AXIS_PCIE_DATA_WIDTH == 256) begin
m_axis_rq_tkeep_int = 8'b00001111;
end else if (AXIS_PCIE_DATA_WIDTH == 128) begin
m_axis_rq_tkeep_int = 4'b1111;
end else if (AXIS_PCIE_DATA_WIDTH == 64) begin
m_axis_rq_tkeep_int = 2'b11;
end
m_axis_rq_tuser_int[3:0] = dword_count_reg == 1 ? first_be & last_be : first_be; // first BE
m_axis_rq_tuser_int[7:4] = dword_count_reg == 1 ? 4'b0000 : last_be; // last BE
m_axis_rq_tuser_int[10:8] = 3'd0; // addr_offset
m_axis_rq_tuser_int[11] = 1'b0; // discontinue
m_axis_rq_tuser_int[12] = 1'b0; // tph_present
m_axis_rq_tuser_int[14:13] = 2'b00; // tph_type
m_axis_rq_tuser_int[15] = 1'b0; // tph_indirect_tag_en
m_axis_rq_tuser_int[23:16] = 8'd0; // tph_st_tag
m_axis_rq_tuser_int[27:24] = 4'd0; // seq_num
m_axis_rq_tuser_int[59:28] = 32'd0; // parity
// AXI read response processing and TLP generation
case (tlp_state_reg)
TLP_STATE_IDLE: begin
// idle state, wait for command
m_axi_rready_next = 1'b0;
tlp_addr_next = tlp_cmd_addr_reg;
tlp_len_next = tlp_cmd_len_reg;
dword_count_next = tlp_cmd_dword_len_reg;
offset_next = tlp_cmd_offset_reg;
input_cycle_count_next = tlp_cmd_input_cycle_len_reg;
output_cycle_count_next = tlp_cmd_output_cycle_len_reg;
input_active_next = 1'b1;
bubble_cycle_next = tlp_cmd_bubble_cycle_reg;
last_cycle_next = tlp_cmd_output_cycle_len_reg == 0;
last_tlp_next = tlp_cmd_last_reg;
tag_next = tlp_cmd_tag_reg;
if (tlp_cmd_valid_reg) begin
tlp_cmd_ready = 1'b1;
if (AXIS_PCIE_DATA_WIDTH == 256) begin
m_axi_rready_next = m_axis_rq_tready_int_early;
end else if (AXIS_PCIE_DATA_WIDTH == 128) begin
m_axi_rready_next = m_axis_rq_tready_int_early && bubble_cycle_next;
end else begin
m_axi_rready_next = 1'b0;
end
tlp_state_next = TLP_STATE_HEADER_1;
end else begin
tlp_state_next = TLP_STATE_IDLE;
end
end
TLP_STATE_HEADER_1: begin
// header 1 state, send TLP header
if (AXIS_PCIE_DATA_WIDTH == 256) begin
m_axi_rready_next = m_axis_rq_tready_int_early && input_active_reg;
if (m_axis_rq_tready_int_reg && ((m_axi_rready && m_axi_rvalid) || !input_active_reg)) begin
transfer_in_save = m_axi_rready && m_axi_rvalid;
if (bubble_cycle_reg) begin
if (input_active_reg) begin
input_cycle_count_next = input_cycle_count_reg - 1;
input_active_next = input_cycle_count_reg != 0;
end
bubble_cycle_next = 1'b0;
m_axi_rready_next = m_axis_rq_tready_int_early && input_active_next;
tlp_state_next = TLP_STATE_HEADER_1;
end else begin
dword_count_next = dword_count_reg - 4;
if (input_active_reg) begin
input_cycle_count_next = input_cycle_count_reg - 1;
input_active_next = input_cycle_count_reg != 0;
end
output_cycle_count_next = output_cycle_count_reg - 1;
last_cycle_next = output_cycle_count_next == 0;
m_axis_rq_tdata_int[255:128] = shift_axi_rdata[255:128];
m_axis_rq_tvalid_int = 1'b1;
if (dword_count_reg >= 4) begin
m_axis_rq_tkeep_int = 8'b11111111;
end else begin
m_axis_rq_tkeep_int = 8'b11111111 >> (4 - dword_count_reg);
end
if (last_cycle_reg) begin
m_axis_rq_tlast_int = 1'b1;
if (last_tlp_reg) begin
m_axis_write_desc_status_tag_next = tag_reg;
m_axis_write_desc_status_valid_next = 1'b1;
end
// skip idle state if possible
tlp_addr_next = tlp_cmd_addr_reg;
tlp_len_next = tlp_cmd_len_reg;
dword_count_next = tlp_cmd_dword_len_reg;
offset_next = tlp_cmd_offset_reg;
input_cycle_count_next = tlp_cmd_input_cycle_len_reg;
output_cycle_count_next = tlp_cmd_output_cycle_len_reg;
input_active_next = 1'b1;
bubble_cycle_next = tlp_cmd_bubble_cycle_reg;
last_cycle_next = tlp_cmd_output_cycle_len_reg == 0;
last_tlp_next = tlp_cmd_last_reg;
tag_next = tlp_cmd_tag_reg;
if (tlp_cmd_valid_reg) begin
tlp_cmd_ready = 1'b1;
if (AXIS_PCIE_DATA_WIDTH == 256) begin
m_axi_rready_next = m_axis_rq_tready_int_early;
end else if (AXIS_PCIE_DATA_WIDTH == 128) begin
m_axi_rready_next = m_axis_rq_tready_int_early && bubble_cycle_next;
end else begin
m_axi_rready_next = 1'b0;
end
tlp_state_next = TLP_STATE_HEADER_1;
end else begin
m_axi_rready_next = 0;
tlp_state_next = TLP_STATE_IDLE;
end
end else begin
m_axi_rready_next = m_axis_rq_tready_int_early && input_active_next;
tlp_state_next = TLP_STATE_TRANSFER;
end
end
end else begin
tlp_state_next = TLP_STATE_HEADER_1;
end
end else begin
if (m_axis_rq_tready_int_reg) begin
m_axis_rq_tvalid_int = 1'b1;
if (AXIS_PCIE_DATA_WIDTH == 128) begin
m_axi_rready_next = m_axis_rq_tready_int_early;
if ((m_axi_rready && m_axi_rvalid) && bubble_cycle_reg) begin
transfer_in_save = 1'b1;
if (input_active_reg) begin
input_cycle_count_next = input_cycle_count_reg - 1;
input_active_next = input_cycle_count_reg != 0;
end
bubble_cycle_next = 1'b0;
m_axi_rready_next = m_axis_rq_tready_int_early && input_active_next;
end
tlp_state_next = TLP_STATE_TRANSFER;
end else begin
m_axi_rready_next = m_axis_rq_tready_int_early && bubble_cycle_reg;
tlp_state_next = TLP_STATE_HEADER_2;
end
end else begin
tlp_state_next = TLP_STATE_HEADER_1;
end
end
end
TLP_STATE_HEADER_2: begin
// header 2 state, send rest of TLP header (64 bit interface only)
if (m_axis_rq_tready_int_reg) begin
m_axis_rq_tdata_int[10:0] = dword_count_reg; // DWORD count
m_axis_rq_tdata_int[14:11] = 4'b0001; // request type - memory write
m_axis_rq_tdata_int[15] = 1'b0; // poisoned request
m_axis_rq_tdata_int[31:16] = requester_id;
m_axis_rq_tdata_int[39:32] = 8'd0; // tag
m_axis_rq_tdata_int[55:40] = 16'd0; // completer ID
m_axis_rq_tdata_int[56] = requester_id_enable; // requester ID enable
m_axis_rq_tdata_int[59:57] = 3'b000; // traffic class
m_axis_rq_tdata_int[62:60] = 3'b000; // attr
m_axis_rq_tdata_int[63] = 1'b0; // force ECRC
m_axis_rq_tvalid_int = 1'b1;
m_axis_rq_tkeep_int = 2'b11;
m_axi_rready_next = m_axis_rq_tready_int_early;
if ((m_axi_rready && m_axi_rvalid) && bubble_cycle_reg) begin
transfer_in_save = 1'b1;
if (input_active_reg) begin
input_cycle_count_next = input_cycle_count_reg - 1;
input_active_next = input_cycle_count_reg != 0;
end
bubble_cycle_next = 1'b0;
m_axi_rready_next = m_axis_rq_tready_int_early && input_active_next;
end
tlp_state_next = TLP_STATE_TRANSFER;
end else begin
tlp_state_next = TLP_STATE_HEADER_2;
end
end
TLP_STATE_TRANSFER: begin
// transfer state, transfer data
m_axi_rready_next = m_axis_rq_tready_int_early && input_active_reg;
if (m_axis_rq_tready_int_reg && ((m_axi_rready && m_axi_rvalid) || !input_active_reg)) begin
transfer_in_save = 1'b1;
if (bubble_cycle_reg) begin
if (input_active_reg) begin
input_cycle_count_next = input_cycle_count_reg - 1;
input_active_next = input_cycle_count_reg != 0;
end
bubble_cycle_next = 1'b0;
m_axi_rready_next = m_axis_rq_tready_int_early && input_active_next;
tlp_state_next = TLP_STATE_TRANSFER;
end else begin
dword_count_next = dword_count_reg - AXI_STRB_WIDTH/4;
if (input_active_reg) begin
input_cycle_count_next = input_cycle_count_reg - 1;
input_active_next = input_cycle_count_reg != 0;
end
output_cycle_count_next = output_cycle_count_reg - 1;
last_cycle_next = output_cycle_count_next == 0;
m_axis_rq_tdata_int = shift_axi_rdata;
m_axis_rq_tvalid_int = 1'b1;
if (dword_count_reg >= AXI_STRB_WIDTH/4) begin
m_axis_rq_tkeep_int = {AXI_STRB_WIDTH{1'b1}};
end else begin
m_axis_rq_tkeep_int = {AXI_STRB_WIDTH{1'b1}} >> (AXI_STRB_WIDTH - dword_count_reg);
end
if (last_cycle_reg) begin
m_axis_rq_tlast_int = 1'b1;
if (last_tlp_reg) begin
m_axis_write_desc_status_tag_next = tag_reg;
m_axis_write_desc_status_valid_next = 1'b1;
end
// skip idle state if possible
tlp_addr_next = tlp_cmd_addr_reg;
tlp_len_next = tlp_cmd_len_reg;
dword_count_next = tlp_cmd_dword_len_reg;
offset_next = tlp_cmd_offset_reg;
input_cycle_count_next = tlp_cmd_input_cycle_len_reg;
output_cycle_count_next = tlp_cmd_output_cycle_len_reg;
input_active_next = 1'b1;
bubble_cycle_next = tlp_cmd_bubble_cycle_reg;
last_cycle_next = tlp_cmd_output_cycle_len_reg == 0;
last_tlp_next = tlp_cmd_last_reg;
tag_next = tlp_cmd_tag_reg;
if (tlp_cmd_valid_reg) begin
tlp_cmd_ready = 1'b1;
if (AXIS_PCIE_DATA_WIDTH == 256) begin
m_axi_rready_next = m_axis_rq_tready_int_early;
end else if (AXIS_PCIE_DATA_WIDTH == 128) begin
m_axi_rready_next = m_axis_rq_tready_int_early && bubble_cycle_next;
end else begin
m_axi_rready_next = 1'b0;
end
tlp_state_next = TLP_STATE_HEADER_1;
end else begin
m_axi_rready_next = 0;
tlp_state_next = TLP_STATE_IDLE;
end
end else begin
m_axi_rready_next = m_axis_rq_tready_int_early && input_active_next;
tlp_state_next = TLP_STATE_TRANSFER;
end
end
end else begin
tlp_state_next = TLP_STATE_TRANSFER;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
axi_state_reg <= AXI_STATE_IDLE;
tlp_state_reg <= TLP_STATE_IDLE;
tlp_cmd_valid_reg <= 1'b0;
s_axis_write_desc_ready_reg <= 1'b0;
m_axis_write_desc_status_valid_reg <= 1'b0;
m_axi_arvalid_reg <= 1'b0;
m_axi_rready_reg <= 1'b0;
end else begin
axi_state_reg <= axi_state_next;
tlp_state_reg <= tlp_state_next;
tlp_cmd_valid_reg <= tlp_cmd_valid_next;
s_axis_write_desc_ready_reg <= s_axis_write_desc_ready_next;
m_axis_write_desc_status_valid_reg <= m_axis_write_desc_status_valid_next;
m_axi_arvalid_reg <= m_axi_arvalid_next;
m_axi_rready_reg <= m_axi_rready_next;
end
pcie_addr_reg <= pcie_addr_next;
axi_addr_reg <= axi_addr_next;
op_count_reg <= op_count_next;
tr_count_reg <= tr_count_next;
tlp_count_reg <= tlp_count_next;
tlp_addr_reg <= tlp_addr_next;
tlp_len_reg <= tlp_len_next;
dword_count_reg <= dword_count_next;
offset_reg <= offset_next;
input_cycle_count_reg <= input_cycle_count_next;
output_cycle_count_reg <= output_cycle_count_next;
input_active_reg <= input_active_next;
bubble_cycle_reg <= bubble_cycle_next;
last_cycle_reg <= last_cycle_next;
last_tlp_reg <= last_tlp_next;
tag_reg <= tag_next;
tlp_cmd_addr_reg <= tlp_cmd_addr_next;
tlp_cmd_len_reg <= tlp_cmd_len_next;
tlp_cmd_dword_len_reg <= tlp_cmd_dword_len_next;
tlp_cmd_input_cycle_len_reg <= tlp_cmd_input_cycle_len_next;
tlp_cmd_output_cycle_len_reg <= tlp_cmd_output_cycle_len_next;
tlp_cmd_offset_reg <= tlp_cmd_offset_next;
tlp_cmd_bubble_cycle_reg <= tlp_cmd_bubble_cycle_next;
tlp_cmd_tag_reg <= tlp_cmd_tag_next;
tlp_cmd_last_reg <= tlp_cmd_last_next;
m_axis_write_desc_status_tag_reg <= m_axis_write_desc_status_tag_next;
m_axi_araddr_reg <= m_axi_araddr_next;
m_axi_arlen_reg <= m_axi_arlen_next;
max_payload_size_dw_reg <= 11'd32 << (max_payload_size > 5 ? 5 : max_payload_size);
if (transfer_in_save) begin
save_axi_rdata_reg <= m_axi_rdata;
end
end
// output datapath logic (PCIe TLP)
reg [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rq_tdata_reg = {AXIS_PCIE_DATA_WIDTH{1'b0}};
reg [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rq_tkeep_reg = {AXIS_PCIE_KEEP_WIDTH{1'b0}};
reg m_axis_rq_tvalid_reg = 1'b0, m_axis_rq_tvalid_next;
reg m_axis_rq_tlast_reg = 1'b0;
reg [59:0] m_axis_rq_tuser_reg = 60'd0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] temp_m_axis_rq_tdata_reg = {AXIS_PCIE_DATA_WIDTH{1'b0}};
reg [AXIS_PCIE_KEEP_WIDTH-1:0] temp_m_axis_rq_tkeep_reg = {AXIS_PCIE_KEEP_WIDTH{1'b0}};
reg temp_m_axis_rq_tvalid_reg = 1'b0, temp_m_axis_rq_tvalid_next;
reg temp_m_axis_rq_tlast_reg = 1'b0;
reg [59:0] temp_m_axis_rq_tuser_reg = 60'd0;
// datapath control
reg store_axis_rq_int_to_output;
reg store_axis_rq_int_to_temp;
reg store_axis_rq_temp_to_output;
assign m_axis_rq_tdata = m_axis_rq_tdata_reg;
assign m_axis_rq_tkeep = m_axis_rq_tkeep_reg;
assign m_axis_rq_tvalid = m_axis_rq_tvalid_reg;
assign m_axis_rq_tlast = m_axis_rq_tlast_reg;
assign m_axis_rq_tuser = m_axis_rq_tuser_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_axis_rq_tready_int_early = m_axis_rq_tready || (!temp_m_axis_rq_tvalid_reg && (!m_axis_rq_tvalid_reg || !m_axis_rq_tvalid_int));
always @* begin
// transfer sink ready state to source
m_axis_rq_tvalid_next = m_axis_rq_tvalid_reg;
temp_m_axis_rq_tvalid_next = temp_m_axis_rq_tvalid_reg;
store_axis_rq_int_to_output = 1'b0;
store_axis_rq_int_to_temp = 1'b0;
store_axis_rq_temp_to_output = 1'b0;
if (m_axis_rq_tready_int_reg) begin
// input is ready
if (m_axis_rq_tready || !m_axis_rq_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axis_rq_tvalid_next = m_axis_rq_tvalid_int;
store_axis_rq_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axis_rq_tvalid_next = m_axis_rq_tvalid_int;
store_axis_rq_int_to_temp = 1'b1;
end
end else if (m_axis_rq_tready) begin
// input is not ready, but output is ready
m_axis_rq_tvalid_next = temp_m_axis_rq_tvalid_reg;
temp_m_axis_rq_tvalid_next = 1'b0;
store_axis_rq_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_axis_rq_tvalid_reg <= 1'b0;
m_axis_rq_tready_int_reg <= 1'b0;
temp_m_axis_rq_tvalid_reg <= 1'b0;
end else begin
m_axis_rq_tvalid_reg <= m_axis_rq_tvalid_next;
m_axis_rq_tready_int_reg <= m_axis_rq_tready_int_early;
temp_m_axis_rq_tvalid_reg <= temp_m_axis_rq_tvalid_next;
end
// datapath
if (store_axis_rq_int_to_output) begin
m_axis_rq_tdata_reg <= m_axis_rq_tdata_int;
m_axis_rq_tkeep_reg <= m_axis_rq_tkeep_int;
m_axis_rq_tlast_reg <= m_axis_rq_tlast_int;
m_axis_rq_tuser_reg <= m_axis_rq_tuser_int;
end else if (store_axis_rq_temp_to_output) begin
m_axis_rq_tdata_reg <= temp_m_axis_rq_tdata_reg;
m_axis_rq_tkeep_reg <= temp_m_axis_rq_tkeep_reg;
m_axis_rq_tlast_reg <= temp_m_axis_rq_tlast_reg;
m_axis_rq_tuser_reg <= temp_m_axis_rq_tuser_reg;
end
if (store_axis_rq_int_to_temp) begin
temp_m_axis_rq_tdata_reg <= m_axis_rq_tdata_int;
temp_m_axis_rq_tkeep_reg <= m_axis_rq_tkeep_int;
temp_m_axis_rq_tlast_reg <= m_axis_rq_tlast_int;
temp_m_axis_rq_tuser_reg <= m_axis_rq_tuser_int;
end
end
endmodule

View File

@ -0,0 +1,307 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Ultrascale PCIe AXI Master
*/
module pcie_us_axi_master #
(
parameter AXIS_PCIE_DATA_WIDTH = 256,
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32),
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH,
parameter AXI_ADDR_WIDTH = 64,
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8),
parameter AXI_ID_WIDTH = 8,
parameter AXI_MAX_BURST_LEN = 256
)
(
input wire clk,
input wire rst,
/*
* AXI input (CQ)
*/
input wire [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata,
input wire [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep,
input wire s_axis_cq_tvalid,
output wire s_axis_cq_tready,
input wire s_axis_cq_tlast,
input wire [84:0] s_axis_cq_tuser,
/*
* AXI output (CC)
*/
output wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata,
output wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep,
output wire m_axis_cc_tvalid,
input wire m_axis_cc_tready,
output wire m_axis_cc_tlast,
output wire [32:0] m_axis_cc_tuser,
/*
* AXI Master output
*/
output wire [AXI_ID_WIDTH-1:0] m_axi_awid,
output wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr,
output wire [7:0] m_axi_awlen,
output wire [2:0] m_axi_awsize,
output wire [1:0] m_axi_awburst,
output wire m_axi_awlock,
output wire [3:0] m_axi_awcache,
output wire [2:0] m_axi_awprot,
output wire m_axi_awvalid,
input wire m_axi_awready,
output wire [AXI_DATA_WIDTH-1:0] m_axi_wdata,
output wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb,
output wire m_axi_wlast,
output wire m_axi_wvalid,
input wire m_axi_wready,
input wire [AXI_ID_WIDTH-1:0] m_axi_bid,
input wire [1:0] m_axi_bresp,
input wire m_axi_bvalid,
output wire m_axi_bready,
output wire [AXI_ID_WIDTH-1:0] m_axi_arid,
output wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr,
output wire [7:0] m_axi_arlen,
output wire [2:0] m_axi_arsize,
output wire [1:0] m_axi_arburst,
output wire m_axi_arlock,
output wire [3:0] m_axi_arcache,
output wire [2:0] m_axi_arprot,
output wire m_axi_arvalid,
input wire m_axi_arready,
input wire [AXI_ID_WIDTH-1:0] m_axi_rid,
input wire [AXI_DATA_WIDTH-1:0] m_axi_rdata,
input wire [1:0] m_axi_rresp,
input wire m_axi_rlast,
input wire m_axi_rvalid,
output wire m_axi_rready,
/*
* Configuration
*/
input wire [15:0] completer_id,
input wire completer_id_enable,
input wire [2:0] max_payload_size,
/*
* Status
*/
output wire status_error_cor,
output wire status_error_uncor
);
wire [AXIS_PCIE_DATA_WIDTH-1:0] axis_cq_tdata_read;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] axis_cq_tkeep_read;
wire axis_cq_tvalid_read;
wire axis_cq_tready_read;
wire axis_cq_tlast_read;
wire [84:0] axis_cq_tuser_read;
wire [AXIS_PCIE_DATA_WIDTH-1:0] axis_cq_tdata_write;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] axis_cq_tkeep_write;
wire axis_cq_tvalid_write;
wire axis_cq_tready_write;
wire axis_cq_tlast_write;
wire [84:0] axis_cq_tuser_write;
wire [3:0] req_type;
wire [1:0] select;
wire [1:0] status_error_uncor_int;
pcie_us_axis_cq_demux #(
.M_COUNT(2),
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH)
)
cq_demux_inst (
.clk(clk),
.rst(rst),
.s_axis_cq_tdata(s_axis_cq_tdata),
.s_axis_cq_tkeep(s_axis_cq_tkeep),
.s_axis_cq_tvalid(s_axis_cq_tvalid),
.s_axis_cq_tready(s_axis_cq_tready),
.s_axis_cq_tlast(s_axis_cq_tlast),
.s_axis_cq_tuser(s_axis_cq_tuser),
.m_axis_cq_tdata({axis_cq_tdata_write, axis_cq_tdata_read}),
.m_axis_cq_tkeep({axis_cq_tkeep_write, axis_cq_tkeep_read}),
.m_axis_cq_tvalid({axis_cq_tvalid_write, axis_cq_tvalid_read}),
.m_axis_cq_tready({axis_cq_tready_write, axis_cq_tready_read}),
.m_axis_cq_tlast({axis_cq_tlast_write, axis_cq_tlast_read}),
.m_axis_cq_tuser({axis_cq_tuser_write, axis_cq_tuser_read}),
.req_type(req_type),
.target_function(),
.bar_id(),
.msg_code(),
.msg_routing(),
.enable(1'b1),
.drop(1'b0),
.select(select)
);
assign select[1] = req_type == 4'b0001;
assign select[0] = ~select[1];
pcie_us_axi_master_rd #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN)
)
pcie_us_axi_master_rd_inst (
.clk(clk),
.rst(rst),
/*
* AXI input (CQ)
*/
.s_axis_cq_tdata(axis_cq_tdata_read),
.s_axis_cq_tkeep(axis_cq_tkeep_read),
.s_axis_cq_tvalid(axis_cq_tvalid_read),
.s_axis_cq_tready(axis_cq_tready_read),
.s_axis_cq_tlast(axis_cq_tlast_read),
.s_axis_cq_tuser(axis_cq_tuser_read),
/*
* AXI output (CC)
*/
.m_axis_cc_tdata(m_axis_cc_tdata),
.m_axis_cc_tkeep(m_axis_cc_tkeep),
.m_axis_cc_tvalid(m_axis_cc_tvalid),
.m_axis_cc_tready(m_axis_cc_tready),
.m_axis_cc_tlast(m_axis_cc_tlast),
.m_axis_cc_tuser(m_axis_cc_tuser),
/*
* AXI master interface
*/
.m_axi_arid(m_axi_arid),
.m_axi_araddr(m_axi_araddr),
.m_axi_arlen(m_axi_arlen),
.m_axi_arsize(m_axi_arsize),
.m_axi_arburst(m_axi_arburst),
.m_axi_arlock(m_axi_arlock),
.m_axi_arcache(m_axi_arcache),
.m_axi_arprot(m_axi_arprot),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rid(m_axi_rid),
.m_axi_rdata(m_axi_rdata),
.m_axi_rresp(m_axi_rresp),
.m_axi_rlast(m_axi_rlast),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready),
/*
* Configuration
*/
.completer_id(completer_id),
.completer_id_enable(completer_id_enable),
.max_payload_size(max_payload_size),
/*
* Status
*/
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor_int[0])
);
pcie_us_axi_master_wr #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN)
)
pcie_us_axi_master_wr_inst (
.clk(clk),
.rst(rst),
/*
* AXI input (CQ)
*/
.s_axis_cq_tdata(axis_cq_tdata_write),
.s_axis_cq_tkeep(axis_cq_tkeep_write),
.s_axis_cq_tvalid(axis_cq_tvalid_write),
.s_axis_cq_tready(axis_cq_tready_write),
.s_axis_cq_tlast(axis_cq_tlast_write),
.s_axis_cq_tuser(axis_cq_tuser_write),
/*
* AXI master interface
*/
.m_axi_awid(m_axi_awid),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awlen(m_axi_awlen),
.m_axi_awsize(m_axi_awsize),
.m_axi_awburst(m_axi_awburst),
.m_axi_awlock(m_axi_awlock),
.m_axi_awcache(m_axi_awcache),
.m_axi_awprot(m_axi_awprot),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wstrb(m_axi_wstrb),
.m_axi_wlast(m_axi_wlast),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
/*
* Status
*/
.status_error_uncor(status_error_uncor_int[1])
);
pulse_merge #(
.INPUT_WIDTH(2),
.COUNT_WIDTH(4)
)
status_error_uncor_pm_inst (
.clk(clk),
.rst(rst),
.pulse_in(status_error_uncor_int),
.count_out(),
.pulse_out(status_error_uncor)
);
endmodule

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,650 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Ultrascale PCIe AXI Master (write)
*/
module pcie_us_axi_master_wr #
(
parameter AXIS_PCIE_DATA_WIDTH = 256,
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32),
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH,
parameter AXI_ADDR_WIDTH = 64,
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8),
parameter AXI_ID_WIDTH = 8,
parameter AXI_MAX_BURST_LEN = 256
)
(
input wire clk,
input wire rst,
/*
* AXI input (CQ)
*/
input wire [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata,
input wire [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep,
input wire s_axis_cq_tvalid,
output wire s_axis_cq_tready,
input wire s_axis_cq_tlast,
input wire [84:0] s_axis_cq_tuser,
/*
* AXI Master output
*/
output wire [AXI_ID_WIDTH-1:0] m_axi_awid,
output wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr,
output wire [7:0] m_axi_awlen,
output wire [2:0] m_axi_awsize,
output wire [1:0] m_axi_awburst,
output wire m_axi_awlock,
output wire [3:0] m_axi_awcache,
output wire [2:0] m_axi_awprot,
output wire m_axi_awvalid,
input wire m_axi_awready,
output wire [AXI_DATA_WIDTH-1:0] m_axi_wdata,
output wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb,
output wire m_axi_wlast,
output wire m_axi_wvalid,
input wire m_axi_wready,
input wire [AXI_ID_WIDTH-1:0] m_axi_bid,
input wire [1:0] m_axi_bresp,
input wire m_axi_bvalid,
output wire m_axi_bready,
/*
* Status
*/
output wire status_error_uncor
);
parameter AXI_WORD_WIDTH = AXI_STRB_WIDTH;
parameter AXI_WORD_SIZE = AXI_DATA_WIDTH/AXI_WORD_WIDTH;
parameter AXI_BURST_SIZE = $clog2(AXI_STRB_WIDTH);
parameter AXI_MAX_BURST_SIZE = AXI_MAX_BURST_LEN*AXI_WORD_WIDTH;
parameter AXIS_PCIE_WORD_WIDTH = AXIS_PCIE_KEEP_WIDTH;
parameter AXIS_PCIE_WORD_SIZE = AXIS_PCIE_DATA_WIDTH/AXIS_PCIE_WORD_WIDTH;
parameter OFFSET_WIDTH = $clog2(AXIS_PCIE_DATA_WIDTH/32);
// bus width assertions
initial begin
if (AXIS_PCIE_DATA_WIDTH != 64 && AXIS_PCIE_DATA_WIDTH != 128 && AXIS_PCIE_DATA_WIDTH != 256) begin
$error("Error: PCIe interface width must be 64, 128, or 256");
$finish;
end
if (AXIS_PCIE_KEEP_WIDTH * 32 != AXIS_PCIE_DATA_WIDTH) begin
$error("Error: PCIe interface requires dword (32-bit) granularity");
$finish;
end
if (AXI_DATA_WIDTH != AXIS_PCIE_DATA_WIDTH) begin
$error("Error: AXI interface width must match PCIe interface width");
$finish;
end
if (AXI_STRB_WIDTH * 8 != AXI_DATA_WIDTH) begin
$error("Error: AXI interface requires byte (8-bit) granularity");
$finish;
end
if (AXI_MAX_BURST_LEN < 1 || AXI_MAX_BURST_LEN > 256) begin
$error("Error: AXI_MAX_BURST_LEN must be between 1 and 256");
$finish;
end
end
localparam [3:0]
REQ_MEM_READ = 4'b0000,
REQ_MEM_WRITE = 4'b0001,
REQ_IO_READ = 4'b0010,
REQ_IO_WRITE = 4'b0011,
REQ_MEM_FETCH_ADD = 4'b0100,
REQ_MEM_SWAP = 4'b0101,
REQ_MEM_CAS = 4'b0110,
REQ_MEM_READ_LOCKED = 4'b0111,
REQ_CFG_READ_0 = 4'b1000,
REQ_CFG_READ_1 = 4'b1001,
REQ_CFG_WRITE_0 = 4'b1010,
REQ_CFG_WRITE_1 = 4'b1011,
REQ_MSG = 4'b1100,
REQ_MSG_VENDOR = 4'b1101,
REQ_MSG_ATS = 4'b1110;
localparam [2:0]
CPL_STATUS_SC = 3'b000, // successful completion
CPL_STATUS_UR = 3'b001, // unsupported request
CPL_STATUS_CRS = 3'b010, // configuration request retry status
CPL_STATUS_CA = 3'b100; // completer abort
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_HEADER = 3'd1,
STATE_TRANSFER = 2'd2,
STATE_WAIT_END = 2'd3;
reg [1:0] state_reg = STATE_IDLE, state_next;
// datapath control signals
reg transfer_in_save;
reg flush_save;
reg [AXI_ADDR_WIDTH-1:0] axi_addr_reg = {AXI_ADDR_WIDTH{1'b0}}, axi_addr_next;
reg [9:0] op_dword_count_reg = 10'd0, op_dword_count_next;
reg [9:0] tr_dword_count_reg = 10'd0, tr_dword_count_next;
reg [11:0] input_cycle_count_reg = 12'd0, input_cycle_count_next;
reg [11:0] output_cycle_count_reg = 12'd0, output_cycle_count_next;
reg input_active_reg = 1'b0, input_active_next;
reg bubble_cycle_reg = 1'b0, bubble_cycle_next;
reg first_cycle_reg = 1'b0, first_cycle_next;
reg last_cycle_reg = 1'b0, last_cycle_next;
reg [3:0] type_reg = 4'd0, type_next;
reg [3:0] first_be_reg = 4'd0, first_be_next;
reg [3:0] last_be_reg = 4'd0, last_be_next;
reg [OFFSET_WIDTH-1:0] offset_reg = {OFFSET_WIDTH{1'b0}}, offset_next;
reg [OFFSET_WIDTH-1:0] first_cycle_offset_reg = {OFFSET_WIDTH{1'b0}}, first_cycle_offset_next;
reg [OFFSET_WIDTH-1:0] last_cycle_offset_reg = {OFFSET_WIDTH{1'b0}}, last_cycle_offset_next;
reg s_axis_cq_tready_reg = 1'b0, s_axis_cq_tready_next;
reg [AXI_ADDR_WIDTH-1:0] m_axi_awaddr_reg = {AXI_ADDR_WIDTH{1'b0}}, m_axi_awaddr_next;
reg [7:0] m_axi_awlen_reg = 8'd0, m_axi_awlen_next;
reg m_axi_awvalid_reg = 1'b0, m_axi_awvalid_next;
reg [AXI_DATA_WIDTH-1:0] save_axis_tdata_reg = {AXI_DATA_WIDTH{1'b0}};
wire [AXI_DATA_WIDTH-1:0] shift_axis_tdata = {s_axis_cq_tdata, save_axis_tdata_reg} >> ((AXI_STRB_WIDTH/4-offset_reg)*32);
reg status_error_uncor_reg = 1'b0, status_error_uncor_next;
// internal datapath
reg [AXI_DATA_WIDTH-1:0] m_axi_wdata_int;
reg [AXI_STRB_WIDTH-1:0] m_axi_wstrb_int;
reg m_axi_wvalid_int;
reg m_axi_wready_int_reg = 1'b0;
reg m_axi_wlast_int;
wire m_axi_wready_int_early;
assign s_axis_cq_tready = s_axis_cq_tready_reg;
assign m_axi_awid = {AXI_ID_WIDTH{1'b0}};
assign m_axi_awaddr = m_axi_awaddr_reg;
assign m_axi_awlen = m_axi_awlen_reg;
assign m_axi_awsize = $clog2(AXI_STRB_WIDTH);
assign m_axi_awburst = 2'b01;
assign m_axi_awlock = 1'b0;
assign m_axi_awcache = 4'b0011;
assign m_axi_awprot = 3'b010;
assign m_axi_awvalid = m_axi_awvalid_reg;
assign m_axi_bready = 1'b1;
assign status_error_uncor = status_error_uncor_reg;
always @* begin
state_next = STATE_IDLE;
transfer_in_save = 1'b0;
s_axis_cq_tready_next = 1'b0;
type_next = type_reg;
axi_addr_next = axi_addr_reg;
op_dword_count_next = op_dword_count_reg;
tr_dword_count_next = tr_dword_count_reg;
input_cycle_count_next = input_cycle_count_reg;
output_cycle_count_next = output_cycle_count_reg;
input_active_next = input_active_reg;
bubble_cycle_next = bubble_cycle_reg;
first_cycle_next = first_cycle_reg;
last_cycle_next = last_cycle_reg;
first_be_next = first_be_reg;
last_be_next = last_be_reg;
offset_next = offset_reg;
first_cycle_offset_next = first_cycle_offset_reg;
last_cycle_offset_next = last_cycle_offset_reg;
m_axi_awaddr_next = m_axi_awaddr_reg;
m_axi_awlen_next = m_axi_awlen_reg;
m_axi_awvalid_next = m_axi_awvalid_reg && !m_axi_awready;
m_axi_wdata_int = shift_axis_tdata;
m_axi_wstrb_int = {AXI_STRB_WIDTH{1'b1}};
m_axi_wvalid_int = 1'b0;
m_axi_wlast_int = 1'b0;
status_error_uncor_next = 1'b0;
case (state_reg)
STATE_IDLE: begin
// idle state, wait for completion request
if (AXIS_PCIE_DATA_WIDTH > 64) begin
s_axis_cq_tready_next = m_axi_wready_int_early && (!m_axi_awvalid || m_axi_awready);
if (s_axis_cq_tready && s_axis_cq_tvalid) begin
transfer_in_save = 1'b1;
// header fields
axi_addr_next = {s_axis_cq_tdata[63:2], 2'b00};
op_dword_count_next = s_axis_cq_tdata[74:64];
type_next = s_axis_cq_tdata[78:75];
// tuser fields
first_be_next = s_axis_cq_tuser[3:0];
last_be_next = s_axis_cq_tuser[7:4];
if (op_dword_count_next == 1) begin
// use first_be for both byte enables for single DWORD transfers
last_be_next = first_be_next;
end
if (op_dword_count_next <= AXI_MAX_BURST_SIZE/4) begin
// packet smaller than max burst size
// assumed to not cross 4k boundary, send one request
tr_dword_count_next = op_dword_count_next;
m_axi_awlen_next = (tr_dword_count_next + axi_addr_next[OFFSET_WIDTH+2-1:2] - 1) >> (AXI_BURST_SIZE-2);
end else begin
// packet larger than max burst size
// assumed to not cross 4k boundary, send one request
tr_dword_count_next = AXI_MAX_BURST_SIZE/4 - axi_addr_next[OFFSET_WIDTH+2-1:2];
m_axi_awlen_next = (tr_dword_count_next - 1) >> (AXI_BURST_SIZE-2);
end
m_axi_awaddr_next = axi_addr_next;
// required DWORD shift to place first DWORD from the TLP payload into proper position on AXI interface
// bubble cycle required if first TLP payload transfer does not fill first AXI transfer
if (AXIS_PCIE_DATA_WIDTH == 256) begin
offset_next = axi_addr_next[OFFSET_WIDTH+2-1:2] - 4;
bubble_cycle_next = axi_addr_next[OFFSET_WIDTH+2-1:2] < 4;
end else begin
offset_next = axi_addr_next[OFFSET_WIDTH+2-1:2];
bubble_cycle_next = 1'b0;
end
first_cycle_offset_next = axi_addr_next[OFFSET_WIDTH+2-1:2];
first_cycle_next = 1'b1;
// number of bus transfers in TLP, DOWRD count plus payload start DWORD offset, divided by bus width in DWORDS
if (AXIS_PCIE_DATA_WIDTH == 256) begin
input_cycle_count_next = (tr_dword_count_next + 4 - 1) >> (AXI_BURST_SIZE-2);
end else begin
input_cycle_count_next = (tr_dword_count_next - 1) >> (AXI_BURST_SIZE-2);
end
// number of bus transfers to AXI, DWORD count plus DWORD offset, divided by bus width in DWORDS
output_cycle_count_next = (tr_dword_count_next + axi_addr_next[OFFSET_WIDTH+2-1:2] - 1) >> (AXI_BURST_SIZE-2);
last_cycle_offset_next = axi_addr_next[OFFSET_WIDTH+2-1:2] + tr_dword_count_next;
last_cycle_next = output_cycle_count_next == 0;
input_active_next = 1'b1;
axi_addr_next = axi_addr_next + (tr_dword_count_next << 2);
op_dword_count_next = op_dword_count_next - tr_dword_count_next;
if (type_next == REQ_MEM_WRITE) begin
// write request
m_axi_awvalid_next = 1'b1;
if (AXIS_PCIE_DATA_WIDTH == 256) begin
// some data is transferred with header
input_active_next = input_cycle_count_next > 0;
input_cycle_count_next = input_cycle_count_next - 1;
s_axis_cq_tready_next = 1'b0;
state_next = STATE_TRANSFER;
end else begin
s_axis_cq_tready_next = m_axi_wready_int_early;
state_next = STATE_TRANSFER;
end
end else begin
// invalid request
status_error_uncor_next = 1'b1;
if (s_axis_cq_tlast) begin
state_next = STATE_IDLE;
end else begin
s_axis_cq_tready_next = 1'b1;
state_next = STATE_WAIT_END;
end
end
end else begin
state_next = STATE_IDLE;
end
end else begin
s_axis_cq_tready_next = !m_axi_awvalid || m_axi_awready;
if (s_axis_cq_tready & s_axis_cq_tvalid) begin
// header fields
axi_addr_next = {s_axis_cq_tdata[63:2], 2'b00};
// tuser fields
first_be_next = s_axis_cq_tuser[3:0];
last_be_next = s_axis_cq_tuser[7:4];
state_next = STATE_HEADER;
end else begin
state_next = STATE_IDLE;
end
end
end
STATE_HEADER: begin
// header state, store rest of header (64 bit interface only)
s_axis_cq_tready_next = m_axi_wready_int_early;
if (s_axis_cq_tready && s_axis_cq_tvalid) begin
transfer_in_save = 1'b1;
// header fields
op_dword_count_next = s_axis_cq_tdata[10:0];
type_next = s_axis_cq_tdata[14:11];
if (op_dword_count_next == 1) begin
// use first_be for both byte enables for single DWORD transfers
last_be_next = first_be_reg;
end
if (op_dword_count_next <= AXI_MAX_BURST_SIZE/4) begin
// packet smaller than max burst size (only for 64 bits)
// assumed to not cross 4k boundary, send one request
tr_dword_count_next = op_dword_count_next;
end else begin
// packet larger than max burst size
// assumed to not cross 4k boundary, send one request
tr_dword_count_next = AXI_MAX_BURST_SIZE/4 - axi_addr_reg[OFFSET_WIDTH+2-1:2];
end
// required DWORD shift to place first DWORD from the TLP payload into proper position on AXI interface
// bubble cycle required if first TLP payload transfer does not fill first AXI transfer
offset_next = axi_addr_reg[OFFSET_WIDTH+2-1:2];
bubble_cycle_next = 1'b0;
first_cycle_offset_next = axi_addr_reg[OFFSET_WIDTH+2-1:2];
first_cycle_next = 1'b1;
// number of bus transfers in TLP, DOWRD count plus payload start DWORD offset, divided by bus width in DWORDS
input_cycle_count_next = (tr_dword_count_next - 1) >> (AXI_BURST_SIZE-2);
// number of bus transfers to AXI, DWORD count plus DWORD offset, divided by bus width in DWORDS
output_cycle_count_next = (tr_dword_count_next + axi_addr_reg[OFFSET_WIDTH+2-1:2] - 1) >> (AXI_BURST_SIZE-2);
last_cycle_offset_next = axi_addr_reg[OFFSET_WIDTH+2-1:2] + tr_dword_count_next;
last_cycle_next = output_cycle_count_next == 0;
input_active_next = 1'b1;
m_axi_awaddr_next = axi_addr_reg;
m_axi_awlen_next = output_cycle_count_next;
axi_addr_next = axi_addr_reg + (tr_dword_count_next << 2);
op_dword_count_next = op_dword_count_next - tr_dword_count_next;
if (type_next == REQ_MEM_WRITE) begin
// write request
m_axi_awvalid_next = 1'b1;
s_axis_cq_tready_next = m_axi_wready_int_early;
state_next = STATE_TRANSFER;
end else begin
// invalid request
status_error_uncor_next = 1'b1;
if (s_axis_cq_tlast) begin
state_next = STATE_IDLE;
end else begin
s_axis_cq_tready_next = 1'b1;
state_next = STATE_WAIT_END;
end
end
end else begin
state_next = STATE_HEADER;
end
end
STATE_TRANSFER: begin
// transfer state, transfer data
s_axis_cq_tready_next = m_axi_wready_int_early && input_active_reg && !(AXIS_PCIE_DATA_WIDTH == 256 && first_cycle_reg && !bubble_cycle_reg);
if (m_axi_wready_int_reg && ((s_axis_cq_tready && s_axis_cq_tvalid) || !input_active_reg || (AXIS_PCIE_DATA_WIDTH == 256 && first_cycle_reg && !bubble_cycle_reg))) begin
transfer_in_save = s_axis_cq_tready && s_axis_cq_tvalid;
// transfer data
if (AXIS_PCIE_DATA_WIDTH == 256 && first_cycle_reg && !bubble_cycle_reg) begin
m_axi_wdata_int = {save_axis_tdata_reg, {AXIS_PCIE_DATA_WIDTH{1'b0}}} >> ((AXI_STRB_WIDTH/4-offset_reg)*32);
s_axis_cq_tready_next = m_axi_wready_int_early && input_active_reg;
end else begin
m_axi_wdata_int = shift_axis_tdata;
end
// generate strb signal
if (first_cycle_reg) begin
m_axi_wstrb_int = {{AXI_STRB_WIDTH-4{1'b1}}, first_be_reg} << (first_cycle_offset_reg*4);
end else begin
m_axi_wstrb_int = {AXI_STRB_WIDTH{1'b1}};
end
// update cycle counters
if (input_active_reg && !(AXIS_PCIE_DATA_WIDTH == 256 && first_cycle_reg && !bubble_cycle_reg)) begin
input_cycle_count_next = input_cycle_count_reg - 1;
input_active_next = input_cycle_count_reg > 0;
end
output_cycle_count_next = output_cycle_count_reg - 1;
last_cycle_next = output_cycle_count_next == 0;
// modify strb signal at end of transfer
if (last_cycle_reg) begin
if (op_dword_count_reg == 0) begin
if (last_cycle_offset_reg > 0) begin
m_axi_wstrb_int = m_axi_wstrb_int & {last_be_reg, {AXI_STRB_WIDTH-4{1'b1}}} >> (AXI_STRB_WIDTH-last_cycle_offset_reg*4);
end else begin
m_axi_wstrb_int = m_axi_wstrb_int & {last_be_reg, {AXI_STRB_WIDTH-4{1'b1}}};
end
end
m_axi_wlast_int = 1'b1;
end
m_axi_wvalid_int = 1'b1;
first_cycle_next = 1'b0;
if (!last_cycle_reg) begin
s_axis_cq_tready_next = m_axi_wready_int_early && input_active_next;
state_next = STATE_TRANSFER;
end else if (op_dword_count_reg > 0) begin
// current transfer done, but operation not finished yet
if (op_dword_count_reg <= AXI_MAX_BURST_SIZE/4) begin
// packet smaller than max burst size
// assumed to not cross 4k boundary, send one request
tr_dword_count_next = op_dword_count_reg;
m_axi_awlen_next = (tr_dword_count_next + axi_addr_reg[OFFSET_WIDTH+2-1:2] - 1) >> (AXI_BURST_SIZE-2);
end else begin
// packet larger than max burst size
// assumed to not cross 4k boundary, send one request
tr_dword_count_next = AXI_MAX_BURST_SIZE/4 - axi_addr_reg[OFFSET_WIDTH+2-1:2];
m_axi_awlen_next = (tr_dword_count_next - 1) >> (AXI_BURST_SIZE-2);
end
m_axi_awaddr_next = axi_addr_reg;
// keep offset, no bubble cycles, not first cycle
bubble_cycle_next = 1'b0;
first_cycle_next = 1'b0;
// number of bus transfers in TLP, DOWRD count minus payload start DWORD offset, divided by bus width in DWORDS
input_cycle_count_next = (tr_dword_count_next - offset_reg - 1) >> (AXI_BURST_SIZE-2);
// number of bus transfers to AXI, DWORD count plus DWORD offset, divided by bus width in DWORDS
output_cycle_count_next = (tr_dword_count_next + axi_addr_reg[OFFSET_WIDTH+2-1:2] - 1) >> (AXI_BURST_SIZE-2);
last_cycle_offset_next = axi_addr_reg[OFFSET_WIDTH+2-1:2] + tr_dword_count_next;
last_cycle_next = output_cycle_count_next == 0;
input_active_next = tr_dword_count_next > offset_reg;
axi_addr_next = axi_addr_reg + (tr_dword_count_next << 2);
op_dword_count_next = op_dword_count_reg - tr_dword_count_next;
m_axi_awvalid_next = 1'b1;
s_axis_cq_tready_next = m_axi_wready_int_early && input_active_next;
state_next = STATE_TRANSFER;
end else begin
s_axis_cq_tready_next = m_axi_wready_int_early && (!m_axi_awvalid || m_axi_awready);
state_next = STATE_IDLE;
end
end else begin
state_next = STATE_TRANSFER;
end
end
STATE_WAIT_END: begin
// wait end state, wait for end of TLP
s_axis_cq_tready_next = 1'b1;
if (s_axis_cq_tready & s_axis_cq_tvalid) begin
if (s_axis_cq_tlast) begin
if (AXIS_PCIE_DATA_WIDTH > 64) begin
s_axis_cq_tready_next = m_axi_wready_int_early && (!m_axi_awvalid || m_axi_awready);
end else begin
s_axis_cq_tready_next = 1'b1;
end
state_next = STATE_IDLE;
end else begin
state_next = STATE_WAIT_END;
end
end else begin
state_next = STATE_WAIT_END;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
s_axis_cq_tready_reg <= 1'b0;
m_axi_awvalid_reg <= 1'b0;
status_error_uncor_reg <= 1'b0;
end else begin
state_reg <= state_next;
s_axis_cq_tready_reg <= s_axis_cq_tready_next;
m_axi_awvalid_reg <= m_axi_awvalid_next;
status_error_uncor_reg <= status_error_uncor_next;
end
axi_addr_reg <= axi_addr_next;
op_dword_count_reg <= op_dword_count_next;
tr_dword_count_reg <= tr_dword_count_next;
input_cycle_count_reg <= input_cycle_count_next;
output_cycle_count_reg <= output_cycle_count_next;
input_active_reg <= input_active_next;
bubble_cycle_reg <= bubble_cycle_next;
first_cycle_reg <= first_cycle_next;
last_cycle_reg <= last_cycle_next;
type_reg <= type_next;
first_be_reg <= first_be_next;
last_be_reg <= last_be_next;
offset_reg <= offset_next;
first_cycle_offset_reg <= first_cycle_offset_next;
last_cycle_offset_reg <= last_cycle_offset_next;
m_axi_awaddr_reg <= m_axi_awaddr_next;
m_axi_awlen_reg <= m_axi_awlen_next;
if (transfer_in_save) begin
save_axis_tdata_reg <= s_axis_cq_tdata;
end
end
// output datapath logic (AXI write data)
reg [AXI_DATA_WIDTH-1:0] m_axi_wdata_reg = {AXI_DATA_WIDTH{1'b0}};
reg [AXI_STRB_WIDTH-1:0] m_axi_wstrb_reg = {AXI_STRB_WIDTH{1'b0}};
reg m_axi_wvalid_reg = 1'b0, m_axi_wvalid_next;
reg m_axi_wlast_reg = 1'b0;
reg [AXI_DATA_WIDTH-1:0] temp_m_axi_wdata_reg = {AXI_DATA_WIDTH{1'b0}};
reg [AXI_STRB_WIDTH-1:0] temp_m_axi_wstrb_reg = {AXI_STRB_WIDTH{1'b0}};
reg temp_m_axi_wvalid_reg = 1'b0, temp_m_axi_wvalid_next;
reg temp_m_axi_wlast_reg = 1'b0;
// datapath control
reg store_axi_w_int_to_output;
reg store_axi_w_int_to_temp;
reg store_axi_w_temp_to_output;
assign m_axi_wdata = m_axi_wdata_reg;
assign m_axi_wstrb = m_axi_wstrb_reg;
assign m_axi_wvalid = m_axi_wvalid_reg;
assign m_axi_wlast = m_axi_wlast_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_axi_wready_int_early = m_axi_wready || (!temp_m_axi_wvalid_reg && (!m_axi_wvalid_reg || !m_axi_wvalid_int));
always @* begin
// transfer sink ready state to source
m_axi_wvalid_next = m_axi_wvalid_reg;
temp_m_axi_wvalid_next = temp_m_axi_wvalid_reg;
store_axi_w_int_to_output = 1'b0;
store_axi_w_int_to_temp = 1'b0;
store_axi_w_temp_to_output = 1'b0;
if (m_axi_wready_int_reg) begin
// input is ready
if (m_axi_wready || !m_axi_wvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axi_wvalid_next = m_axi_wvalid_int;
store_axi_w_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axi_wvalid_next = m_axi_wvalid_int;
store_axi_w_int_to_temp = 1'b1;
end
end else if (m_axi_wready) begin
// input is not ready, but output is ready
m_axi_wvalid_next = temp_m_axi_wvalid_reg;
temp_m_axi_wvalid_next = 1'b0;
store_axi_w_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_axi_wvalid_reg <= 1'b0;
m_axi_wready_int_reg <= 1'b0;
temp_m_axi_wvalid_reg <= 1'b0;
end else begin
m_axi_wvalid_reg <= m_axi_wvalid_next;
m_axi_wready_int_reg <= m_axi_wready_int_early;
temp_m_axi_wvalid_reg <= temp_m_axi_wvalid_next;
end
// datapath
if (store_axi_w_int_to_output) begin
m_axi_wdata_reg <= m_axi_wdata_int;
m_axi_wstrb_reg <= m_axi_wstrb_int;
m_axi_wlast_reg <= m_axi_wlast_int;
end else if (store_axi_w_temp_to_output) begin
m_axi_wdata_reg <= temp_m_axi_wdata_reg;
m_axi_wstrb_reg <= temp_m_axi_wstrb_reg;
m_axi_wlast_reg <= temp_m_axi_wlast_reg;
end
if (store_axi_w_int_to_temp) begin
temp_m_axi_wdata_reg <= m_axi_wdata_int;
temp_m_axi_wstrb_reg <= m_axi_wstrb_int;
temp_m_axi_wlast_reg <= m_axi_wlast_int;
end
end
endmodule

View File

@ -0,0 +1,846 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Ultrascale PCIe AXI Lite Master
*/
module pcie_us_axil_master #
(
parameter AXIS_PCIE_DATA_WIDTH = 256,
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32),
parameter AXI_DATA_WIDTH = 32,
parameter AXI_ADDR_WIDTH = 64,
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8),
parameter ENABLE_PARITY = 0
)
(
input wire clk,
input wire rst,
/*
* AXI input (CQ)
*/
input wire [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata,
input wire [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep,
input wire s_axis_cq_tvalid,
output wire s_axis_cq_tready,
input wire s_axis_cq_tlast,
input wire [84:0] s_axis_cq_tuser,
/*
* AXI output (CC)
*/
output wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata,
output wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep,
output wire m_axis_cc_tvalid,
input wire m_axis_cc_tready,
output wire m_axis_cc_tlast,
output wire [32:0] m_axis_cc_tuser,
/*
* AXI Lite Master output
*/
output wire [AXI_ADDR_WIDTH-1:0] m_axil_awaddr,
output wire [2:0] m_axil_awprot,
output wire m_axil_awvalid,
input wire m_axil_awready,
output wire [AXI_DATA_WIDTH-1:0] m_axil_wdata,
output wire [AXI_STRB_WIDTH-1:0] m_axil_wstrb,
output wire m_axil_wvalid,
input wire m_axil_wready,
input wire [1:0] m_axil_bresp,
input wire m_axil_bvalid,
output wire m_axil_bready,
output wire [AXI_ADDR_WIDTH-1:0] m_axil_araddr,
output wire [2:0] m_axil_arprot,
output wire m_axil_arvalid,
input wire m_axil_arready,
input wire [AXI_DATA_WIDTH-1:0] m_axil_rdata,
input wire [1:0] m_axil_rresp,
input wire m_axil_rvalid,
output wire m_axil_rready,
/*
* Configuration
*/
input wire [15:0] completer_id,
input wire completer_id_enable,
/*
* Status
*/
output wire status_error_cor,
output wire status_error_uncor
);
// bus width assertions
initial begin
if (AXIS_PCIE_DATA_WIDTH != 64 && AXIS_PCIE_DATA_WIDTH != 128 && AXIS_PCIE_DATA_WIDTH != 256) begin
$error("Error: PCIe interface width must be 64, 128, or 256");
$finish;
end
if (AXIS_PCIE_KEEP_WIDTH * 32 != AXIS_PCIE_DATA_WIDTH) begin
$error("Error: PCIe interface requires dword (32-bit) granularity");
$finish;
end
if (AXI_DATA_WIDTH != 32) begin
$error("Error: AXI interface width must be 32");
$finish;
end
if (AXI_STRB_WIDTH * 8 != AXI_DATA_WIDTH) begin
$error("Error: AXI interface requires byte (8-bit) granularity");
$finish;
end
end
localparam [3:0]
REQ_MEM_READ = 4'b0000,
REQ_MEM_WRITE = 4'b0001,
REQ_IO_READ = 4'b0010,
REQ_IO_WRITE = 4'b0011,
REQ_MEM_FETCH_ADD = 4'b0100,
REQ_MEM_SWAP = 4'b0101,
REQ_MEM_CAS = 4'b0110,
REQ_MEM_READ_LOCKED = 4'b0111,
REQ_CFG_READ_0 = 4'b1000,
REQ_CFG_READ_1 = 4'b1001,
REQ_CFG_WRITE_0 = 4'b1010,
REQ_CFG_WRITE_1 = 4'b1011,
REQ_MSG = 4'b1100,
REQ_MSG_VENDOR = 4'b1101,
REQ_MSG_ATS = 4'b1110;
localparam [2:0]
CPL_STATUS_SC = 3'b000, // successful completion
CPL_STATUS_UR = 3'b001, // unsupported request
CPL_STATUS_CRS = 3'b010, // configuration request retry status
CPL_STATUS_CA = 3'b100; // completer abort
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_HEADER = 3'd1,
STATE_READ = 3'd2,
STATE_WRITE_1 = 3'd3,
STATE_WRITE_2 = 3'd4,
STATE_WAIT_END = 3'd5,
STATE_CPL_1 = 3'd6,
STATE_CPL_2 = 3'd7;
reg [2:0] state_reg = STATE_IDLE, state_next;
reg [1:0] at_reg = 2'd0, at_next;
reg [10:0] dword_count_reg = 11'd0, dword_count_next;
reg [3:0] type_reg = 4'd0, type_next;
reg [2:0] status_reg = 3'b000, status_next;
reg [15:0] requester_id_reg = 16'd0, requester_id_next;
reg [7:0] tag_reg = 7'd0, tag_next;
reg [2:0] tc_reg = 3'd0, tc_next;
reg [2:0] attr_reg = 3'd0, attr_next;
reg [3:0] first_be_reg = 4'd0, first_be_next;
reg [3:0] last_be_reg = 4'd0, last_be_next;
reg cpl_data_reg = 1'b0, cpl_data_next;
reg s_axis_cq_tready_reg = 1'b0, s_axis_cq_tready_next;
reg [AXI_ADDR_WIDTH-1:0] m_axil_addr_reg = {AXI_ADDR_WIDTH{1'b0}}, m_axil_addr_next;
reg m_axil_awvalid_reg = 1'b0, m_axil_awvalid_next;
reg [AXI_DATA_WIDTH-1:0] m_axil_wdata_reg = {AXI_DATA_WIDTH{1'b0}}, m_axil_wdata_next;
reg [AXI_STRB_WIDTH-1:0] m_axil_wstrb_reg = {AXI_STRB_WIDTH{1'b0}}, m_axil_wstrb_next;
reg m_axil_wvalid_reg = 1'b0, m_axil_wvalid_next;
reg m_axil_bready_reg = 1'b0, m_axil_bready_next;
reg m_axil_arvalid_reg = 1'b0, m_axil_arvalid_next;
reg m_axil_rready_reg = 1'b0, m_axil_rready_next;
reg status_error_cor_reg = 1'b0, status_error_cor_next;
reg status_error_uncor_reg = 1'b0, status_error_uncor_next;
// internal datapath
reg [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata_int;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep_int;
reg m_axis_cc_tvalid_int;
reg m_axis_cc_tready_int_reg = 1'b0;
reg m_axis_cc_tlast_int;
reg [32:0] m_axis_cc_tuser_int;
wire m_axis_cc_tready_int_early;
assign s_axis_cq_tready = s_axis_cq_tready_reg;
assign m_axil_awaddr = m_axil_addr_reg;
assign m_axil_awprot = 3'b010;
assign m_axil_awvalid = m_axil_awvalid_reg;
assign m_axil_wdata = m_axil_wdata_reg;
assign m_axil_wstrb = m_axil_wstrb_reg;
assign m_axil_wvalid = m_axil_wvalid_reg;
assign m_axil_bready = m_axil_bready_reg;
assign m_axil_araddr = m_axil_addr_reg;
assign m_axil_arprot = 3'b010;
assign m_axil_arvalid = m_axil_arvalid_reg;
assign m_axil_rready = m_axil_rready_reg;
assign status_error_cor = status_error_cor_reg;
assign status_error_uncor = status_error_uncor_reg;
always @* begin
state_next = STATE_IDLE;
s_axis_cq_tready_next = 1'b0;
at_next = at_reg;
dword_count_next = dword_count_reg;
type_next = type_reg;
status_next = status_reg;
requester_id_next = requester_id_reg;
tag_next = tag_reg;
tc_next = tc_reg;
attr_next = attr_reg;
first_be_next = first_be_reg;
last_be_next = last_be_reg;
cpl_data_next = cpl_data_reg;
m_axis_cc_tdata_int = {AXIS_PCIE_DATA_WIDTH{1'b0}};
m_axis_cc_tkeep_int = {AXIS_PCIE_KEEP_WIDTH{1'b0}};
m_axis_cc_tvalid_int = 1'b0;
m_axis_cc_tlast_int = 1'b0;
m_axis_cc_tuser_int = 33'd0;
casez (first_be_reg)
4'b0000: m_axis_cc_tdata_int[6:0] = {m_axil_addr_reg[6:2], 2'b00}; // lower address
4'bzzz1: m_axis_cc_tdata_int[6:0] = {m_axil_addr_reg[6:2], 2'b00}; // lower address
4'bzz10: m_axis_cc_tdata_int[6:0] = {m_axil_addr_reg[6:2], 2'b01}; // lower address
4'bz100: m_axis_cc_tdata_int[6:0] = {m_axil_addr_reg[6:2], 2'b10}; // lower address
4'b1000: m_axis_cc_tdata_int[6:0] = {m_axil_addr_reg[6:2], 2'b11}; // lower address
endcase
m_axis_cc_tdata_int[9:8] = at_reg;
casez (first_be_reg)
4'b0000: m_axis_cc_tdata_int[28:16] = 13'd0; // Byte count
4'b0001: m_axis_cc_tdata_int[28:16] = 13'd1; // Byte count
4'b0010: m_axis_cc_tdata_int[28:16] = 13'd1; // Byte count
4'b0100: m_axis_cc_tdata_int[28:16] = 13'd1; // Byte count
4'b1000: m_axis_cc_tdata_int[28:16] = 13'd1; // Byte count
4'b0011: m_axis_cc_tdata_int[28:16] = 13'd2; // Byte count
4'b0110: m_axis_cc_tdata_int[28:16] = 13'd2; // Byte count
4'b1100: m_axis_cc_tdata_int[28:16] = 13'd2; // Byte count
4'b01z1: m_axis_cc_tdata_int[28:16] = 13'd3; // Byte count
4'b1z10: m_axis_cc_tdata_int[28:16] = 13'd3; // Byte count
4'b1zz1: m_axis_cc_tdata_int[28:16] = 13'd4; // Byte count
endcase
m_axis_cc_tdata_int[42:32] = 11'd1; // DWORD count
m_axis_cc_tdata_int[45:43] = status_reg;
m_axis_cc_tdata_int[63:48] = requester_id_reg;
if (AXIS_PCIE_DATA_WIDTH > 64) begin
m_axis_cc_tdata_int[71:64] = tag_reg;
m_axis_cc_tdata_int[87:72] = completer_id;
m_axis_cc_tdata_int[88] = completer_id_enable;
m_axis_cc_tdata_int[91:89] = tc_reg;
m_axis_cc_tdata_int[94:92] = attr_reg;
m_axis_cc_tdata_int[95] = 1'b0; // force ECRC
m_axis_cc_tdata_int[127:96] = m_axil_rdata;
end
m_axis_cc_tuser_int[0] = 1'b0; // discontinue
m_axis_cc_tuser_int[32:1] = 32'd0; // parity
if (AXIS_PCIE_DATA_WIDTH == 256) begin
m_axis_cc_tkeep_int = 8'b00001111;
end else if (AXIS_PCIE_DATA_WIDTH == 128) begin
m_axis_cc_tkeep_int = 4'b1111;
end else if (AXIS_PCIE_DATA_WIDTH == 64) begin
m_axis_cc_tkeep_int = 2'b11;
end
m_axil_addr_next = m_axil_addr_reg;
m_axil_awvalid_next = m_axil_awvalid_reg && !m_axil_awready;
m_axil_wdata_next = m_axil_wdata_reg;
m_axil_wstrb_next = m_axil_wstrb_reg;
m_axil_wvalid_next = m_axil_wvalid_reg && !m_axil_wready;
m_axil_bready_next = 1'b0;
m_axil_arvalid_next = m_axil_arvalid_reg && !m_axil_arready;
m_axil_rready_next = 1'b0;
status_error_cor_next = 1'b0;
status_error_uncor_next = 1'b0;
case (state_reg)
STATE_IDLE: begin
// idle state, wait for completion request
s_axis_cq_tready_next = m_axis_cc_tready_int_early;
if (s_axis_cq_tready && s_axis_cq_tvalid) begin
// header fields
at_next = s_axis_cq_tdata[1:0];
m_axil_addr_next = {s_axis_cq_tdata[63:2], 2'b00};
if (AXIS_PCIE_DATA_WIDTH > 64) begin
dword_count_next = s_axis_cq_tdata[74:64];
type_next = s_axis_cq_tdata[78:75];
requester_id_next = s_axis_cq_tdata[95:80];
tag_next = s_axis_cq_tdata[103:96];
tc_next = s_axis_cq_tdata[123:121];
attr_next = s_axis_cq_tdata[126:124];
// data
if (AXIS_PCIE_DATA_WIDTH == 256) begin
m_axil_wdata_next = s_axis_cq_tdata[159:128];
end
end
// tuser fields
first_be_next = s_axis_cq_tuser[3:0];
last_be_next = s_axis_cq_tuser[7:4];
m_axil_wstrb_next = first_be_next;
status_next = CPL_STATUS_SC; // successful completion
if (AXIS_PCIE_DATA_WIDTH == 64) begin
if (s_axis_cq_tlast) begin
// truncated packet
// report uncorrectable error
status_error_uncor_next = 1'b1;
state_next = STATE_IDLE;
end else begin
state_next = STATE_HEADER;
end
end else begin
if (type_next == REQ_MEM_READ || type_next == REQ_IO_READ) begin
// read request
if (s_axis_cq_tlast && dword_count_next == 11'd1) begin
m_axil_arvalid_next = 1'b1;
m_axil_rready_next = m_axis_cc_tready_int_early;
s_axis_cq_tready_next = 1'b0;
state_next = STATE_READ;
end else begin
// bad length
status_next = CPL_STATUS_CA; // completer abort
// report correctable error
status_error_cor_next = 1'b1;
if (s_axis_cq_tlast) begin
s_axis_cq_tready_next = 1'b0;
state_next = STATE_CPL_1;
end else begin
s_axis_cq_tready_next = 1'b1;
state_next = STATE_WAIT_END;
end
end
end else if (type_next == REQ_MEM_WRITE || type_next == REQ_IO_WRITE) begin
// write request
if (AXIS_PCIE_DATA_WIDTH == 256 && s_axis_cq_tlast && dword_count_next == 11'd1) begin
m_axil_awvalid_next = 1'b1;
m_axil_wvalid_next = 1'b1;
m_axil_bready_next = 1'b1;
s_axis_cq_tready_next = 1'b0;
state_next = STATE_WRITE_2;
end else if (AXIS_PCIE_DATA_WIDTH < 256 && dword_count_next == 11'd1) begin
s_axis_cq_tready_next = 1'b1;
state_next = STATE_WRITE_1;
end else begin
// bad length
status_next = CPL_STATUS_CA; // completer abort
if (type_next == REQ_MEM_WRITE) begin
// memory write - posted, no completion
// report uncorrectable error
status_error_uncor_next = 1'b1;
if (s_axis_cq_tlast) begin
s_axis_cq_tready_next = m_axis_cc_tready_int_early;
state_next = STATE_IDLE;
end else begin
s_axis_cq_tready_next = 1'b1;
state_next = STATE_WAIT_END;
end
end else begin
// IO write - non-posted, send completion
// report correctable error
status_error_cor_next = 1'b1;
if (s_axis_cq_tlast) begin
s_axis_cq_tready_next = 1'b0;
state_next = STATE_CPL_1;
end else begin
s_axis_cq_tready_next = 1'b1;
state_next = STATE_WAIT_END;
end
end
end
end else begin
// other request
status_next = CPL_STATUS_UR; // unsupported request
if (type_next == REQ_MEM_WRITE || (type_next & 4'b1100) == 4'b1100) begin
// memory write or message - posted, no completion
// report uncorrectable error
status_error_uncor_next = 1'b1;
if (s_axis_cq_tlast) begin
s_axis_cq_tready_next = m_axis_cc_tready_int_early;
state_next = STATE_IDLE;
end else begin
s_axis_cq_tready_next = 1'b1;
state_next = STATE_WAIT_END;
end
end else begin
// other non-posted request, send UR completion
// report correctable error
status_error_cor_next = 1'b1;
if (s_axis_cq_tlast) begin
s_axis_cq_tready_next = 1'b0;
state_next = STATE_CPL_1;
end else begin
s_axis_cq_tready_next = 1'b1;
state_next = STATE_WAIT_END;
end
end
end
end
end else begin
state_next = STATE_IDLE;
end
end
STATE_HEADER: begin
// header state, handle header (64 bit interface only)
s_axis_cq_tready_next = m_axis_cc_tready_int_early;
// header fields
dword_count_next = s_axis_cq_tdata[10:0];
type_next = s_axis_cq_tdata[14:11];
requester_id_next = s_axis_cq_tdata[31:16];
tag_next = s_axis_cq_tdata[39:32];
tc_next = s_axis_cq_tdata[59:57];
attr_next = s_axis_cq_tdata[62:60];
// data
m_axil_wstrb_next = first_be_reg;
if (s_axis_cq_tready && s_axis_cq_tvalid) begin
if (type_next == REQ_MEM_READ || type_next == REQ_IO_READ) begin
// read request
if (s_axis_cq_tlast && dword_count_next == 11'd1) begin
m_axil_arvalid_next = 1'b1;
m_axil_rready_next = m_axis_cc_tready_int_early;
s_axis_cq_tready_next = 1'b0;
state_next = STATE_READ;
end else begin
// bad length
status_next = CPL_STATUS_CA; // completer abort
// report correctable error
status_error_cor_next = 1'b1;
if (s_axis_cq_tlast) begin
s_axis_cq_tready_next = 1'b0;
state_next = STATE_CPL_1;
end else begin
s_axis_cq_tready_next = 1'b1;
state_next = STATE_WAIT_END;
end
end
end else if (type_next == REQ_MEM_WRITE || type_next == REQ_IO_WRITE) begin
// write request
if (dword_count_next == 11'd1) begin
s_axis_cq_tready_next = 1'b1;
state_next = STATE_WRITE_1;
end else begin
// bad length
status_next = CPL_STATUS_CA; // completer abort
if (type_next == REQ_MEM_WRITE) begin
// memory write - posted, no completion
// report uncorrectable error
status_error_uncor_next = 1'b1;
if (s_axis_cq_tlast) begin
s_axis_cq_tready_next = m_axis_cc_tready_int_early;
state_next = STATE_IDLE;
end else begin
s_axis_cq_tready_next = 1'b1;
state_next = STATE_WAIT_END;
end
end else begin
// other non-posted request, send UR completion
// report correctable error
status_error_cor_next = 1'b1;
if (s_axis_cq_tlast) begin
s_axis_cq_tready_next = 1'b0;
state_next = STATE_CPL_1;
end else begin
s_axis_cq_tready_next = 1'b1;
state_next = STATE_WAIT_END;
end
end
end
end else begin
// other request
status_next = CPL_STATUS_UR; // unsupported request
if (type_next == REQ_MEM_WRITE || (type_next & 4'b1100) == 4'b1100) begin
// memory write or message - posted, no completion
// report uncorrectable error
status_error_uncor_next = 1'b1;
if (s_axis_cq_tlast) begin
s_axis_cq_tready_next = m_axis_cc_tready_int_early;
state_next = STATE_IDLE;
end else begin
s_axis_cq_tready_next = 1'b1;
state_next = STATE_WAIT_END;
end
end else begin
// other non-posted request, send UR completion
// report correctable error
status_error_cor_next = 1'b1;
if (s_axis_cq_tlast) begin
s_axis_cq_tready_next = 1'b0;
state_next = STATE_CPL_1;
end else begin
s_axis_cq_tready_next = 1'b1;
state_next = STATE_WAIT_END;
end
end
end
end else begin
state_next = STATE_HEADER;
end
end
STATE_READ: begin
// read state, wait for read response
m_axil_rready_next = m_axis_cc_tready_int_early;
m_axis_cc_tdata_int[42:32] = 11'd1; // DWORD count
m_axis_cc_tdata_int[45:43] = CPL_STATUS_SC; // status: successful completion
m_axis_cc_tdata_int[127:96] = m_axil_rdata;
if (AXIS_PCIE_DATA_WIDTH == 256) begin
m_axis_cc_tkeep_int = 8'b00001111;
m_axis_cc_tlast_int = 1'b1;
end else if (AXIS_PCIE_DATA_WIDTH == 128) begin
m_axis_cc_tkeep_int = 4'b1111;
m_axis_cc_tlast_int = 1'b1;
end else if (AXIS_PCIE_DATA_WIDTH == 64) begin
m_axis_cc_tkeep_int = 2'b11;
m_axis_cc_tlast_int = 1'b0;
end
if (m_axil_rready && m_axil_rvalid) begin
// send completion
m_axis_cc_tvalid_int = 1'b1;
m_axil_rready_next = 1'b0;
if (AXIS_PCIE_DATA_WIDTH == 64) begin
cpl_data_next = 1'b1;
state_next = STATE_CPL_2;
end else begin
s_axis_cq_tready_next = m_axis_cc_tready_int_early;
state_next = STATE_IDLE;
end
end else begin
state_next = STATE_READ;
end
end
STATE_WRITE_1: begin
// write 1 state, store write data and initiate write
s_axis_cq_tready_next = 1'b1;
// data
m_axil_wdata_next = s_axis_cq_tdata[31:0];
if (s_axis_cq_tready && s_axis_cq_tvalid) begin
if (s_axis_cq_tlast) begin
m_axil_awvalid_next = 1'b1;
m_axil_wvalid_next = 1'b1;
m_axil_bready_next = m_axis_cc_tready_int_early;
s_axis_cq_tready_next = 1'b0;
state_next = STATE_WRITE_2;
end else begin
s_axis_cq_tready_next = 1'b1;
state_next = STATE_WAIT_END;
end
end else begin
state_next = STATE_WRITE_1;
end
end
STATE_WRITE_2: begin
// write 2 state, handle write response
m_axil_bready_next = m_axis_cc_tready_int_early;
if (m_axil_bready && m_axil_bvalid) begin
m_axil_bready_next = 1'b0;
if (type_reg == REQ_MEM_WRITE) begin
// memory write - posted, no completion
s_axis_cq_tready_next = m_axis_cc_tready_int_early;
state_next = STATE_IDLE;
end else begin
// IO write - non-posted, send completion
m_axis_cc_tvalid_int = 1'b1;
m_axis_cc_tdata_int[42:32] = 11'd0; // DWORD count
m_axis_cc_tdata_int[45:43] = CPL_STATUS_SC; // status: successful completion
if (AXIS_PCIE_DATA_WIDTH == 256) begin
m_axis_cc_tkeep_int = 8'b00000111;
m_axis_cc_tlast_int = 1'b1;
end else if (AXIS_PCIE_DATA_WIDTH == 128) begin
m_axis_cc_tkeep_int = 4'b0111;
m_axis_cc_tlast_int = 1'b1;
end else if (AXIS_PCIE_DATA_WIDTH == 64) begin
m_axis_cc_tkeep_int = 2'b11;
m_axis_cc_tlast_int = 1'b0;
end
if (AXIS_PCIE_DATA_WIDTH == 64) begin
cpl_data_next = 1'b0;
state_next = STATE_CPL_2;
end else begin
s_axis_cq_tready_next = m_axis_cc_tready_int_early;
state_next = STATE_IDLE;
end
end
end else begin
state_next = STATE_WRITE_2;
end
end
STATE_WAIT_END: begin
// wait end state, wait for end of completion request
s_axis_cq_tready_next = 1'b1;
if (s_axis_cq_tready && s_axis_cq_tvalid) begin
if (s_axis_cq_tlast) begin
// completion
if (type_reg == REQ_MEM_WRITE || (type_reg & 4'b1100) == 4'b1100) begin
// memory write or message - posted, no completion
s_axis_cq_tready_next = m_axis_cc_tready_int_early;
state_next = STATE_IDLE;
end else begin
// IO write - non-posted, send completion
m_axis_cc_tvalid_int = 1'b1;
m_axis_cc_tdata_int[42:32] = 11'd0; // DWORD count
if (AXIS_PCIE_DATA_WIDTH == 256) begin
m_axis_cc_tkeep_int = 8'b00000111;
m_axis_cc_tlast_int = 1'b1;
end else if (AXIS_PCIE_DATA_WIDTH == 128) begin
m_axis_cc_tkeep_int = 4'b0111;
m_axis_cc_tlast_int = 1'b1;
end else if (AXIS_PCIE_DATA_WIDTH == 64) begin
m_axis_cc_tkeep_int = 2'b11;
m_axis_cc_tlast_int = 1'b0;
end
if (m_axis_cc_tready_int_reg) begin
if (AXIS_PCIE_DATA_WIDTH == 64) begin
cpl_data_next = 1'b0;
state_next = STATE_CPL_2;
end else begin
s_axis_cq_tready_next = m_axis_cc_tready_int_early;
state_next = STATE_IDLE;
end
end else begin
state_next = STATE_CPL_1;
end
end
end else begin
state_next = STATE_WAIT_END;
end
end else begin
state_next = STATE_WAIT_END;
end
end
STATE_CPL_1: begin
// send completion
m_axis_cc_tvalid_int = 1'b1;
m_axis_cc_tdata_int[28:16] = 13'd0; // byte count
m_axis_cc_tdata_int[42:32] = 11'd0; // DWORD count
m_axis_cc_tdata_int[45:43] = status_reg;
if (AXIS_PCIE_DATA_WIDTH == 256) begin
m_axis_cc_tkeep_int = 8'b00000111;
m_axis_cc_tlast_int = 1'b1;
end else if (AXIS_PCIE_DATA_WIDTH == 128) begin
m_axis_cc_tkeep_int = 4'b0111;
m_axis_cc_tlast_int = 1'b1;
end else if (AXIS_PCIE_DATA_WIDTH == 64) begin
m_axis_cc_tkeep_int = 2'b11;
m_axis_cc_tlast_int = 1'b0;
end
if (m_axis_cc_tready_int_reg) begin
if (AXIS_PCIE_DATA_WIDTH == 64) begin
cpl_data_next = 1'b0;
state_next = STATE_CPL_2;
end else begin
s_axis_cq_tready_next = m_axis_cc_tready_int_early;
state_next = STATE_IDLE;
end
end else begin
state_next = STATE_CPL_1;
end
end
STATE_CPL_2: begin
// send rest of completion
m_axis_cc_tvalid_int = 1'b1;
m_axis_cc_tdata_int[7:0] = tag_reg;
m_axis_cc_tdata_int[23:8] = completer_id;
m_axis_cc_tdata_int[24] = completer_id_enable;
m_axis_cc_tdata_int[27:25] = tc_reg;
m_axis_cc_tdata_int[30:28] = attr_reg;
m_axis_cc_tdata_int[31] = 1'b0; // force ECRC
m_axis_cc_tdata_int[63:32] = m_axil_rdata;
m_axis_cc_tkeep_int = {cpl_data_reg, 1'b1};
m_axis_cc_tlast_int = 1'b1;
if (m_axis_cc_tready_int_reg) begin
s_axis_cq_tready_next = m_axis_cc_tready_int_early;
state_next = STATE_IDLE;
end else begin
state_next = STATE_CPL_2;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
s_axis_cq_tready_reg <= 1'b0;
m_axil_awvalid_reg <= 1'b0;
m_axil_wvalid_reg <= 1'b0;
m_axil_bready_reg <= 1'b0;
m_axil_arvalid_reg <= 1'b0;
m_axil_rready_reg <= 1'b0;
status_error_cor_reg <= 1'b0;
status_error_uncor_reg <= 1'b0;
end else begin
state_reg <= state_next;
s_axis_cq_tready_reg <= s_axis_cq_tready_next;
m_axil_awvalid_reg <= m_axil_awvalid_next;
m_axil_wvalid_reg <= m_axil_wvalid_next;
m_axil_bready_reg <= m_axil_bready_next;
m_axil_arvalid_reg <= m_axil_arvalid_next;
m_axil_rready_reg <= m_axil_rready_next;
status_error_cor_reg <= status_error_cor_next;
status_error_uncor_reg <= status_error_uncor_next;
end
at_reg <= at_next;
dword_count_reg <= dword_count_next;
type_reg <= type_next;
tag_reg <= tag_next;
status_reg <= status_next;
requester_id_reg <= requester_id_next;
tc_reg <= tc_next;
attr_reg <= attr_next;
first_be_reg <= first_be_next;
last_be_reg <= last_be_next;
cpl_data_reg <= cpl_data_next;
m_axil_addr_reg <= m_axil_addr_next;
m_axil_wdata_reg <= m_axil_wdata_next;
m_axil_wstrb_reg <= m_axil_wstrb_next;
end
// output datapath logic
reg [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata_reg = {AXIS_PCIE_DATA_WIDTH{1'b0}};
reg [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep_reg = {AXIS_PCIE_KEEP_WIDTH{1'b0}};
reg m_axis_cc_tvalid_reg = 1'b0, m_axis_cc_tvalid_next;
reg m_axis_cc_tlast_reg = 1'b0;
reg [32:0] m_axis_cc_tuser_reg = 33'd0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] temp_m_axis_cc_tdata_reg = {AXIS_PCIE_DATA_WIDTH{1'b0}};
reg [AXIS_PCIE_KEEP_WIDTH-1:0] temp_m_axis_cc_tkeep_reg = {AXIS_PCIE_KEEP_WIDTH{1'b0}};
reg temp_m_axis_cc_tvalid_reg = 1'b0, temp_m_axis_cc_tvalid_next;
reg temp_m_axis_cc_tlast_reg = 1'b0;
reg [32:0] temp_m_axis_cc_tuser_reg = 33'd0;
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_axis_temp_to_output;
assign m_axis_cc_tdata = m_axis_cc_tdata_reg;
assign m_axis_cc_tkeep = m_axis_cc_tkeep_reg;
assign m_axis_cc_tvalid = m_axis_cc_tvalid_reg;
assign m_axis_cc_tlast = m_axis_cc_tlast_reg;
assign m_axis_cc_tuser = m_axis_cc_tuser_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_axis_cc_tready_int_early = m_axis_cc_tready || (!temp_m_axis_cc_tvalid_reg && (!m_axis_cc_tvalid_reg || !m_axis_cc_tvalid_int));
always @* begin
// transfer sink ready state to source
m_axis_cc_tvalid_next = m_axis_cc_tvalid_reg;
temp_m_axis_cc_tvalid_next = temp_m_axis_cc_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (m_axis_cc_tready_int_reg) begin
// input is ready
if (m_axis_cc_tready || !m_axis_cc_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axis_cc_tvalid_next = m_axis_cc_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axis_cc_tvalid_next = m_axis_cc_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (m_axis_cc_tready) begin
// input is not ready, but output is ready
m_axis_cc_tvalid_next = temp_m_axis_cc_tvalid_reg;
temp_m_axis_cc_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_axis_cc_tvalid_reg <= 1'b0;
m_axis_cc_tready_int_reg <= 1'b0;
temp_m_axis_cc_tvalid_reg <= 1'b0;
end else begin
m_axis_cc_tvalid_reg <= m_axis_cc_tvalid_next;
m_axis_cc_tready_int_reg <= m_axis_cc_tready_int_early;
temp_m_axis_cc_tvalid_reg <= temp_m_axis_cc_tvalid_next;
end
// datapath
if (store_axis_int_to_output) begin
m_axis_cc_tdata_reg <= m_axis_cc_tdata_int;
m_axis_cc_tkeep_reg <= m_axis_cc_tkeep_int;
m_axis_cc_tlast_reg <= m_axis_cc_tlast_int;
m_axis_cc_tuser_reg <= m_axis_cc_tuser_int;
end else if (store_axis_temp_to_output) begin
m_axis_cc_tdata_reg <= temp_m_axis_cc_tdata_reg;
m_axis_cc_tkeep_reg <= temp_m_axis_cc_tkeep_reg;
m_axis_cc_tlast_reg <= temp_m_axis_cc_tlast_reg;
m_axis_cc_tuser_reg <= temp_m_axis_cc_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_m_axis_cc_tdata_reg <= m_axis_cc_tdata_int;
temp_m_axis_cc_tkeep_reg <= m_axis_cc_tkeep_int;
temp_m_axis_cc_tlast_reg <= m_axis_cc_tlast_int;
temp_m_axis_cc_tuser_reg <= m_axis_cc_tuser_int;
end
end
endmodule

View File

@ -0,0 +1,306 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Ultrascale PCIe CQ demultiplexer
*/
module pcie_us_axis_cq_demux #
(
parameter M_COUNT = 2,
parameter AXIS_PCIE_DATA_WIDTH = 256,
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
)
(
input wire clk,
input wire rst,
/*
* AXI input (CQ)
*/
input wire [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata,
input wire [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep,
input wire s_axis_cq_tvalid,
output wire s_axis_cq_tready,
input wire s_axis_cq_tlast,
input wire [84:0] s_axis_cq_tuser,
/*
* AXI output (CQ)
*/
output wire [M_COUNT*AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cq_tdata,
output wire [M_COUNT*AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cq_tkeep,
output wire [M_COUNT-1:0] m_axis_cq_tvalid,
input wire [M_COUNT-1:0] m_axis_cq_tready,
output wire [M_COUNT-1:0] m_axis_cq_tlast,
output wire [M_COUNT*85-1:0] m_axis_cq_tuser,
/*
* Fields
*/
output wire [3:0] req_type,
output wire [7:0] target_function,
output wire [2:0] bar_id,
output wire [7:0] msg_code,
output wire [2:0] msg_routing,
/*
* Control
*/
input wire enable,
input wire drop,
input wire [M_COUNT-1:0] select
);
parameter CL_M_COUNT = $clog2(M_COUNT);
// bus width assertions
initial begin
if (AXIS_PCIE_DATA_WIDTH != 64 && AXIS_PCIE_DATA_WIDTH != 128 && AXIS_PCIE_DATA_WIDTH != 256) begin
$error("Error: PCIe interface width must be 64, 128, or 256");
$finish;
end
if (AXIS_PCIE_KEEP_WIDTH * 32 != AXIS_PCIE_DATA_WIDTH) begin
$error("Error: PCIe interface requires dword (32-bit) granularity");
$finish;
end
end
reg [CL_M_COUNT-1:0] select_reg = {CL_M_COUNT{1'b0}}, select_ctl, select_next;
reg drop_reg = 1'b0, drop_ctl, drop_next;
reg frame_reg = 1'b0, frame_ctl, frame_next;
reg s_axis_cq_tready_reg = 1'b0, s_axis_cq_tready_next;
reg [AXIS_PCIE_DATA_WIDTH-1:0] temp_s_axis_cq_tdata = {AXIS_PCIE_DATA_WIDTH{1'b0}};
reg [AXIS_PCIE_KEEP_WIDTH-1:0] temp_s_axis_cq_tkeep = {AXIS_PCIE_KEEP_WIDTH{1'b0}};
reg temp_s_axis_cq_tvalid = 1'b0;
reg temp_s_axis_cq_tlast = 1'b0;
reg [84:0] temp_s_axis_cq_tuser = 85'b0;
// internal datapath
reg [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cq_tdata_int;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cq_tkeep_int;
reg [M_COUNT-1:0] m_axis_cq_tvalid_int;
reg m_axis_cq_tready_int_reg = 1'b0;
reg m_axis_cq_tlast_int;
reg [84:0] m_axis_cq_tuser_int;
wire m_axis_cq_tready_int_early;
assign s_axis_cq_tready = (s_axis_cq_tready_reg || (AXIS_PCIE_DATA_WIDTH == 64 && !temp_s_axis_cq_tvalid)) && enable;
assign req_type = AXIS_PCIE_DATA_WIDTH > 64 ? s_axis_cq_tdata[78:75] : s_axis_cq_tdata[14:11];
assign target_function = AXIS_PCIE_DATA_WIDTH > 64 ? s_axis_cq_tdata[111:104] : s_axis_cq_tdata[47:40];
assign bar_id = AXIS_PCIE_DATA_WIDTH > 64 ? s_axis_cq_tdata[114:112] : s_axis_cq_tdata[50:48];
assign msg_code = AXIS_PCIE_DATA_WIDTH > 64 ? s_axis_cq_tdata[111:104] : s_axis_cq_tdata[47:40];
assign msg_routing = AXIS_PCIE_DATA_WIDTH > 64 ? s_axis_cq_tdata[114:112] : s_axis_cq_tdata[50:48];
integer i;
always @* begin
select_next = select_reg;
select_ctl = select_reg;
drop_next = drop_reg;
drop_ctl = drop_reg;
frame_next = frame_reg;
frame_ctl = frame_reg;
s_axis_cq_tready_next = 1'b0;
if (AXIS_PCIE_DATA_WIDTH == 64) begin
if (temp_s_axis_cq_tvalid && s_axis_cq_tready) begin
// end of frame detection
if (temp_s_axis_cq_tlast) begin
frame_next = 1'b0;
drop_next = 1'b0;
end
end
end else begin
if (s_axis_cq_tvalid && s_axis_cq_tready) begin
// end of frame detection
if (s_axis_cq_tlast) begin
frame_next = 1'b0;
drop_next = 1'b0;
end
end
end
if (!frame_reg && (AXIS_PCIE_DATA_WIDTH == 64 ? temp_s_axis_cq_tvalid : s_axis_cq_tvalid) && s_axis_cq_tready) begin
// start of frame, grab select value
select_ctl = 0;
drop_ctl = 1'b1;
frame_ctl = 1'b1;
for (i = M_COUNT-1; i >= 0; i = i - 1) begin
if (select[i]) begin
select_ctl = i;
drop_ctl = 1'b0;
end
end
drop_ctl = drop_ctl || drop;
if (AXIS_PCIE_DATA_WIDTH == 64) begin
if (!(s_axis_cq_tready && temp_s_axis_cq_tvalid && temp_s_axis_cq_tlast)) begin
select_next = select_ctl;
drop_next = drop_ctl;
frame_next = 1'b1;
end
end else begin
if (!(s_axis_cq_tready && s_axis_cq_tvalid && s_axis_cq_tlast)) begin
select_next = select_ctl;
drop_next = drop_ctl;
frame_next = 1'b1;
end
end
end
s_axis_cq_tready_next = m_axis_cq_tready_int_early || drop_ctl;
if (AXIS_PCIE_DATA_WIDTH == 64) begin
m_axis_cq_tdata_int = temp_s_axis_cq_tdata;
m_axis_cq_tkeep_int = temp_s_axis_cq_tkeep;
m_axis_cq_tvalid_int = (temp_s_axis_cq_tvalid && s_axis_cq_tready && !drop_ctl) << select_ctl;
m_axis_cq_tlast_int = temp_s_axis_cq_tlast;
m_axis_cq_tuser_int = temp_s_axis_cq_tuser;
end else begin
m_axis_cq_tdata_int = s_axis_cq_tdata;
m_axis_cq_tkeep_int = s_axis_cq_tkeep;
m_axis_cq_tvalid_int = (s_axis_cq_tvalid && s_axis_cq_tready && !drop_ctl) << select_ctl;
m_axis_cq_tlast_int = s_axis_cq_tlast;
m_axis_cq_tuser_int = s_axis_cq_tuser;
end
end
always @(posedge clk) begin
if (rst) begin
select_reg <= 2'd0;
drop_reg <= 1'b0;
frame_reg <= 1'b0;
s_axis_cq_tready_reg <= 1'b0;
end else begin
select_reg <= select_next;
drop_reg <= drop_next;
frame_reg <= frame_next;
s_axis_cq_tready_reg <= s_axis_cq_tready_next;
end
if (s_axis_cq_tready && AXIS_PCIE_DATA_WIDTH == 64) begin
temp_s_axis_cq_tdata <= s_axis_cq_tdata;
temp_s_axis_cq_tkeep <= s_axis_cq_tkeep;
temp_s_axis_cq_tvalid <= s_axis_cq_tvalid;
temp_s_axis_cq_tlast <= s_axis_cq_tlast;
temp_s_axis_cq_tuser <= s_axis_cq_tuser;
end
end
// output datapath logic
reg [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cq_tdata_reg = {AXIS_PCIE_DATA_WIDTH{1'b0}};
reg [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cq_tkeep_reg = {AXIS_PCIE_KEEP_WIDTH{1'b0}};
reg [M_COUNT-1:0] m_axis_cq_tvalid_reg = {M_COUNT{1'b0}}, m_axis_cq_tvalid_next;
reg m_axis_cq_tlast_reg = 1'b0;
reg [84:0] m_axis_cq_tuser_reg = 85'd0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] temp_m_axis_cq_tdata_reg = {AXIS_PCIE_DATA_WIDTH{1'b0}};
reg [AXIS_PCIE_KEEP_WIDTH-1:0] temp_m_axis_cq_tkeep_reg = {AXIS_PCIE_KEEP_WIDTH{1'b0}};
reg [M_COUNT-1:0] temp_m_axis_cq_tvalid_reg = {M_COUNT{1'b0}}, temp_m_axis_cq_tvalid_next;
reg temp_m_axis_cq_tlast_reg = 1'b0;
reg [84:0] temp_m_axis_cq_tuser_reg = 85'd0;
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_axis_cq_temp_to_output;
assign m_axis_cq_tdata = {M_COUNT{m_axis_cq_tdata_reg}};
assign m_axis_cq_tkeep = {M_COUNT{m_axis_cq_tkeep_reg}};
assign m_axis_cq_tvalid = m_axis_cq_tvalid_reg;
assign m_axis_cq_tlast = {M_COUNT{m_axis_cq_tlast_reg}};
assign m_axis_cq_tuser = {M_COUNT{m_axis_cq_tuser_reg}};
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_axis_cq_tready_int_early = (m_axis_cq_tready & m_axis_cq_tvalid) || (!temp_m_axis_cq_tvalid_reg && (!m_axis_cq_tvalid || !m_axis_cq_tvalid_int));
always @* begin
// transfer sink ready state to source
m_axis_cq_tvalid_next = m_axis_cq_tvalid_reg;
temp_m_axis_cq_tvalid_next = temp_m_axis_cq_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_cq_temp_to_output = 1'b0;
if (m_axis_cq_tready_int_reg) begin
// input is ready
if ((m_axis_cq_tready & m_axis_cq_tvalid) || !m_axis_cq_tvalid) begin
// output is ready or currently not valid, transfer data to output
m_axis_cq_tvalid_next = m_axis_cq_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axis_cq_tvalid_next = m_axis_cq_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (m_axis_cq_tready & m_axis_cq_tvalid) begin
// input is not ready, but output is ready
m_axis_cq_tvalid_next = temp_m_axis_cq_tvalid_reg;
temp_m_axis_cq_tvalid_next = 1'b0;
store_axis_cq_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_axis_cq_tvalid_reg <= {M_COUNT{1'b0}};
m_axis_cq_tready_int_reg <= 1'b0;
temp_m_axis_cq_tvalid_reg <= 1'b0;
end else begin
m_axis_cq_tvalid_reg <= m_axis_cq_tvalid_next;
m_axis_cq_tready_int_reg <= m_axis_cq_tready_int_early;
temp_m_axis_cq_tvalid_reg <= temp_m_axis_cq_tvalid_next;
end
// datapath
if (store_axis_int_to_output) begin
m_axis_cq_tdata_reg <= m_axis_cq_tdata_int;
m_axis_cq_tkeep_reg <= m_axis_cq_tkeep_int;
m_axis_cq_tlast_reg <= m_axis_cq_tlast_int;
m_axis_cq_tuser_reg <= m_axis_cq_tuser_int;
end else if (store_axis_cq_temp_to_output) begin
m_axis_cq_tdata_reg <= temp_m_axis_cq_tdata_reg;
m_axis_cq_tkeep_reg <= temp_m_axis_cq_tkeep_reg;
m_axis_cq_tlast_reg <= temp_m_axis_cq_tlast_reg;
m_axis_cq_tuser_reg <= temp_m_axis_cq_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_m_axis_cq_tdata_reg <= m_axis_cq_tdata_int;
temp_m_axis_cq_tkeep_reg <= m_axis_cq_tkeep_int;
temp_m_axis_cq_tlast_reg <= m_axis_cq_tlast_int;
temp_m_axis_cq_tuser_reg <= m_axis_cq_tuser_int;
end
end
endmodule

View File

@ -0,0 +1,258 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Ultrascale PCIe RC demultiplexer
*/
module pcie_us_axis_rc_demux #
(
parameter M_COUNT = 2,
parameter AXIS_PCIE_DATA_WIDTH = 256,
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
)
(
input wire clk,
input wire rst,
/*
* AXI input (RC)
*/
input wire [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_rc_tdata,
input wire [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_rc_tkeep,
input wire s_axis_rc_tvalid,
output wire s_axis_rc_tready,
input wire s_axis_rc_tlast,
input wire [74:0] s_axis_rc_tuser,
/*
* AXI output (RC)
*/
output wire [M_COUNT*AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rc_tdata,
output wire [M_COUNT*AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rc_tkeep,
output wire [M_COUNT-1:0] m_axis_rc_tvalid,
input wire [M_COUNT-1:0] m_axis_rc_tready,
output wire [M_COUNT-1:0] m_axis_rc_tlast,
output wire [M_COUNT*75-1:0] m_axis_rc_tuser,
/*
* Fields
*/
output wire [15:0] requester_id,
/*
* Control
*/
input wire enable,
input wire drop,
input wire [M_COUNT-1:0] select
);
parameter CL_M_COUNT = $clog2(M_COUNT);
// bus width assertions
initial begin
if (AXIS_PCIE_DATA_WIDTH != 64 && AXIS_PCIE_DATA_WIDTH != 128 && AXIS_PCIE_DATA_WIDTH != 256) begin
$error("Error: PCIe interface width must be 64, 128, or 256");
$finish;
end
if (AXIS_PCIE_KEEP_WIDTH * 32 != AXIS_PCIE_DATA_WIDTH) begin
$error("Error: PCIe interface requires dword (32-bit) granularity");
$finish;
end
end
reg [CL_M_COUNT-1:0] select_reg = {CL_M_COUNT{1'b0}}, select_ctl, select_next;
reg drop_reg = 1'b0, drop_ctl, drop_next;
reg frame_reg = 1'b0, frame_ctl, frame_next;
reg s_axis_rc_tready_reg = 1'b0, s_axis_rc_tready_next;
// internal datapath
reg [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rc_tdata_int;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rc_tkeep_int;
reg [M_COUNT-1:0] m_axis_rc_tvalid_int;
reg m_axis_rc_tready_int_reg = 1'b0;
reg m_axis_rc_tlast_int;
reg [74:0] m_axis_rc_tuser_int;
wire m_axis_rc_tready_int_early;
assign s_axis_rc_tready = s_axis_rc_tready_reg && enable;
assign requester_id = s_axis_rc_tdata[63:48];
integer i;
always @* begin
select_next = select_reg;
select_ctl = select_reg;
drop_next = drop_reg;
drop_ctl = drop_reg;
frame_next = frame_reg;
frame_ctl = frame_reg;
s_axis_rc_tready_next = 1'b0;
if (s_axis_rc_tvalid && s_axis_rc_tready) begin
// end of frame detection
if (s_axis_rc_tlast) begin
frame_next = 1'b0;
drop_next = 1'b0;
end
end
if (!frame_reg && s_axis_rc_tvalid && s_axis_rc_tready) begin
// start of frame, grab select value
select_ctl = 0;
drop_ctl = 1'b1;
frame_ctl = 1'b1;
for (i = M_COUNT-1; i >= 0; i = i - 1) begin
if (select[i]) begin
select_ctl = i;
drop_ctl = 1'b0;
end
end
drop_ctl = drop_ctl || drop;
if (!(s_axis_rc_tready && s_axis_rc_tvalid && s_axis_rc_tlast)) begin
select_next = select_ctl;
drop_next = drop_ctl;
frame_next = 1'b1;
end
end
s_axis_rc_tready_next = m_axis_rc_tready_int_early || drop_ctl;
m_axis_rc_tdata_int = s_axis_rc_tdata;
m_axis_rc_tkeep_int = s_axis_rc_tkeep;
m_axis_rc_tvalid_int = (s_axis_rc_tvalid && s_axis_rc_tready && !drop_ctl) << select_ctl;
m_axis_rc_tlast_int = s_axis_rc_tlast;
m_axis_rc_tuser_int = s_axis_rc_tuser;
end
always @(posedge clk) begin
if (rst) begin
select_reg <= 2'd0;
drop_reg <= 1'b0;
frame_reg <= 1'b0;
s_axis_rc_tready_reg <= 1'b0;
end else begin
select_reg <= select_next;
drop_reg <= drop_next;
frame_reg <= frame_next;
s_axis_rc_tready_reg <= s_axis_rc_tready_next;
end
end
// output datapath logic
reg [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rc_tdata_reg = {AXIS_PCIE_DATA_WIDTH{1'b0}};
reg [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rc_tkeep_reg = {AXIS_PCIE_KEEP_WIDTH{1'b0}};
reg [M_COUNT-1:0] m_axis_rc_tvalid_reg = {M_COUNT{1'b0}}, m_axis_rc_tvalid_next;
reg m_axis_rc_tlast_reg = 1'b0;
reg [74:0] m_axis_rc_tuser_reg = 75'd0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] temp_m_axis_rc_tdata_reg = {AXIS_PCIE_DATA_WIDTH{1'b0}};
reg [AXIS_PCIE_KEEP_WIDTH-1:0] temp_m_axis_rc_tkeep_reg = {AXIS_PCIE_KEEP_WIDTH{1'b0}};
reg [M_COUNT-1:0] temp_m_axis_rc_tvalid_reg = {M_COUNT{1'b0}}, temp_m_axis_rc_tvalid_next;
reg temp_m_axis_rc_tlast_reg = 1'b0;
reg [74:0] temp_m_axis_rc_tuser_reg = 75'd0;
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_axis_rc_temp_to_output;
assign m_axis_rc_tdata = {M_COUNT{m_axis_rc_tdata_reg}};
assign m_axis_rc_tkeep = {M_COUNT{m_axis_rc_tkeep_reg}};
assign m_axis_rc_tvalid = m_axis_rc_tvalid_reg;
assign m_axis_rc_tlast = {M_COUNT{m_axis_rc_tlast_reg}};
assign m_axis_rc_tuser = {M_COUNT{m_axis_rc_tuser_reg}};
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_axis_rc_tready_int_early = (m_axis_rc_tready & m_axis_rc_tvalid) || (!temp_m_axis_rc_tvalid_reg && (!m_axis_rc_tvalid || !m_axis_rc_tvalid_int));
always @* begin
// transfer sink ready state to source
m_axis_rc_tvalid_next = m_axis_rc_tvalid_reg;
temp_m_axis_rc_tvalid_next = temp_m_axis_rc_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_rc_temp_to_output = 1'b0;
if (m_axis_rc_tready_int_reg) begin
// input is ready
if ((m_axis_rc_tready & m_axis_rc_tvalid) || !m_axis_rc_tvalid) begin
// output is ready or currently not valid, transfer data to output
m_axis_rc_tvalid_next = m_axis_rc_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axis_rc_tvalid_next = m_axis_rc_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (m_axis_rc_tready & m_axis_rc_tvalid) begin
// input is not ready, but output is ready
m_axis_rc_tvalid_next = temp_m_axis_rc_tvalid_reg;
temp_m_axis_rc_tvalid_next = 1'b0;
store_axis_rc_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_axis_rc_tvalid_reg <= {M_COUNT{1'b0}};
m_axis_rc_tready_int_reg <= 1'b0;
temp_m_axis_rc_tvalid_reg <= 1'b0;
end else begin
m_axis_rc_tvalid_reg <= m_axis_rc_tvalid_next;
m_axis_rc_tready_int_reg <= m_axis_rc_tready_int_early;
temp_m_axis_rc_tvalid_reg <= temp_m_axis_rc_tvalid_next;
end
// datapath
if (store_axis_int_to_output) begin
m_axis_rc_tdata_reg <= m_axis_rc_tdata_int;
m_axis_rc_tkeep_reg <= m_axis_rc_tkeep_int;
m_axis_rc_tlast_reg <= m_axis_rc_tlast_int;
m_axis_rc_tuser_reg <= m_axis_rc_tuser_int;
end else if (store_axis_rc_temp_to_output) begin
m_axis_rc_tdata_reg <= temp_m_axis_rc_tdata_reg;
m_axis_rc_tkeep_reg <= temp_m_axis_rc_tkeep_reg;
m_axis_rc_tlast_reg <= temp_m_axis_rc_tlast_reg;
m_axis_rc_tuser_reg <= temp_m_axis_rc_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_m_axis_rc_tdata_reg <= m_axis_rc_tdata_int;
temp_m_axis_rc_tkeep_reg <= m_axis_rc_tkeep_int;
temp_m_axis_rc_tlast_reg <= m_axis_rc_tlast_int;
temp_m_axis_rc_tuser_reg <= m_axis_rc_tuser_int;
end
end
endmodule

View File

@ -0,0 +1,171 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Ultrascale PCIe configuration shim
*/
module pcie_us_cfg #
(
parameter PF_COUNT = 1,
parameter VF_COUNT = 0,
parameter VF_OFFSET = 64,
parameter F_COUNT = PF_COUNT+VF_COUNT,
parameter READ_EXT_TAG_ENABLE = 1,
parameter READ_MAX_READ_REQ_SIZE = 1,
parameter READ_MAX_PAYLOAD_SIZE = 1,
parameter PCIE_CAP_OFFSET = 12'h0C0
)
(
input wire clk,
input wire rst,
/*
* Configuration outputs
*/
output wire [F_COUNT-1:0] ext_tag_enable,
output wire [F_COUNT*3-1:0] max_read_request_size,
output wire [F_COUNT*3-1:0] max_payload_size,
/*
* Interface to Ultrascale PCIe IP core
*/
output wire [9:0] cfg_mgmt_addr,
output wire [7:0] cfg_mgmt_function_number,
output wire cfg_mgmt_write,
output wire [31:0] cfg_mgmt_write_data,
output wire [3:0] cfg_mgmt_byte_enable,
output wire cfg_mgmt_read,
input wire [31:0] cfg_mgmt_read_data,
input wire cfg_mgmt_read_write_done
);
localparam READ_REV_CTRL = READ_EXT_TAG_ENABLE || READ_MAX_READ_REQ_SIZE || READ_MAX_PAYLOAD_SIZE;
localparam DEV_CTRL_OFFSET = PCIE_CAP_OFFSET + 12'h008;
reg [F_COUNT-1:0] ext_tag_enable_reg = {F_COUNT{1'b0}}, ext_tag_enable_next;
reg [F_COUNT*3-1:0] max_read_request_size_reg = {F_COUNT{3'd0}}, max_read_request_size_next;
reg [F_COUNT*3-1:0] max_payload_size_reg = {F_COUNT{3'd0}}, max_payload_size_next;
reg [9:0] cfg_mgmt_addr_reg = 10'd0, cfg_mgmt_addr_next;
reg [7:0] cfg_mgmt_function_number_reg = 8'd0, cfg_mgmt_function_number_next;
reg cfg_mgmt_write_reg = 1'b0, cfg_mgmt_write_next;
reg [31:0] cfg_mgmt_write_data_reg = 32'd0, cfg_mgmt_write_data_next;
reg [3:0] cfg_mgmt_byte_enable_reg = 4'd0, cfg_mgmt_byte_enable_next;
reg cfg_mgmt_read_reg = 1'b0, cfg_mgmt_read_next;
reg [7:0] delay_reg = 8'hff, delay_next;
reg [7:0] func_cnt_reg = 8'd0, func_cnt_next;
assign ext_tag_enable = ext_tag_enable_reg;
assign max_read_request_size = max_read_request_size_reg;
assign max_payload_size = max_payload_size_reg;
assign cfg_mgmt_addr = cfg_mgmt_addr_reg;
assign cfg_mgmt_function_number = cfg_mgmt_function_number_reg;
assign cfg_mgmt_write = cfg_mgmt_write_reg;
assign cfg_mgmt_write_data = cfg_mgmt_write_data_reg;
assign cfg_mgmt_byte_enable = cfg_mgmt_byte_enable_reg;
assign cfg_mgmt_read = cfg_mgmt_read_reg;
always @* begin
ext_tag_enable_next = ext_tag_enable_reg;
max_read_request_size_next = max_read_request_size_reg;
max_payload_size_next = max_payload_size_reg;
cfg_mgmt_addr_next = cfg_mgmt_addr_reg;
cfg_mgmt_function_number_next = cfg_mgmt_function_number_reg;
cfg_mgmt_write_next = cfg_mgmt_write_reg && !cfg_mgmt_read_write_done;
cfg_mgmt_write_data_next = cfg_mgmt_write_data_reg;
cfg_mgmt_byte_enable_next = cfg_mgmt_byte_enable_reg;
cfg_mgmt_read_next = cfg_mgmt_read_reg && !cfg_mgmt_read_write_done;
delay_next = delay_reg;
func_cnt_next = func_cnt_reg;
if (delay_reg > 0) begin
delay_next = delay_reg - 1;
end else begin
cfg_mgmt_addr_next = DEV_CTRL_OFFSET >> 2;
cfg_mgmt_read_next = 1'b1;
if (cfg_mgmt_read_write_done) begin
cfg_mgmt_read_next = 1'b0;
ext_tag_enable_next[func_cnt_reg] = cfg_mgmt_read_data[8];
max_read_request_size_next[func_cnt_reg*3 +: 3] = cfg_mgmt_read_data[14:12];
max_payload_size_next[func_cnt_reg*3 +: 3] = cfg_mgmt_read_data[7:5];
if (func_cnt_reg == F_COUNT-1) begin
func_cnt_next = 0;
cfg_mgmt_function_number_next = 0;
end else if (func_cnt_reg == PF_COUNT-1) begin
func_cnt_next = func_cnt_reg + 1;
cfg_mgmt_function_number_next = VF_OFFSET;
end else begin
func_cnt_next = func_cnt_reg + 1;
cfg_mgmt_function_number_next = cfg_mgmt_function_number_reg + 1;
end
delay_next = 8'hff;
end
end
end
always @(posedge clk) begin
if (rst) begin
ext_tag_enable_reg <= {F_COUNT{1'b0}};
max_read_request_size_reg <= {F_COUNT{3'd0}};
max_payload_size_reg <= {F_COUNT{3'd0}};
cfg_mgmt_addr_reg <= 10'd0;
cfg_mgmt_function_number_reg <= 8'd0;
cfg_mgmt_write_reg <= 1'b0;
cfg_mgmt_read_reg <= 1'b0;
delay_reg <= 8'hff;
func_cnt_reg <= 8'd0;
end else begin
ext_tag_enable_reg <= ext_tag_enable_next;
max_read_request_size_reg <= max_read_request_size_next;
max_payload_size_reg <= max_payload_size_next;
cfg_mgmt_addr_reg <= cfg_mgmt_addr_next;
cfg_mgmt_function_number_reg <= cfg_mgmt_function_number_next;
cfg_mgmt_write_reg <= cfg_mgmt_write_next;
cfg_mgmt_read_reg <= cfg_mgmt_read_next;
delay_reg <= delay_next;
func_cnt_reg <= func_cnt_next;
end
cfg_mgmt_write_data_reg <= cfg_mgmt_write_data_next;
cfg_mgmt_byte_enable_reg <= cfg_mgmt_byte_enable_next;
end
endmodule

View File

@ -0,0 +1,156 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Ultrascale PCIe MSI shim
*/
module pcie_us_msi #
(
parameter MSI_COUNT = 32
)
(
input wire clk,
input wire rst,
/*
* Interrupt request inputs
*/
input wire [MSI_COUNT-1:0] msi_irq,
/*
* Interface to Ultrascale PCIe IP core
*/
input wire [3:0] cfg_interrupt_msi_enable,
input wire [7:0] cfg_interrupt_msi_vf_enable,
input wire [11:0] cfg_interrupt_msi_mmenable,
input wire cfg_interrupt_msi_mask_update,
input wire [31:0] cfg_interrupt_msi_data,
output wire [3:0] cfg_interrupt_msi_select,
output wire [31:0] cfg_interrupt_msi_int,
output wire [31:0] cfg_interrupt_msi_pending_status,
output wire cfg_interrupt_msi_pending_status_data_enable,
output wire [3:0] cfg_interrupt_msi_pending_status_function_num,
input wire cfg_interrupt_msi_sent,
input wire cfg_interrupt_msi_fail,
output wire [2:0] cfg_interrupt_msi_attr,
output wire cfg_interrupt_msi_tph_present,
output wire [1:0] cfg_interrupt_msi_tph_type,
output wire [8:0] cfg_interrupt_msi_tph_st_tag,
output wire [3:0] cfg_interrupt_msi_function_number
);
reg active_reg = 1'b0, active_next;
reg [MSI_COUNT-1:0] msi_irq_reg = {MSI_COUNT{1'b0}};
reg [MSI_COUNT-1:0] msi_irq_last_reg = {MSI_COUNT{1'b0}};
reg [MSI_COUNT-1:0] msi_irq_active_reg = {MSI_COUNT{1'b0}}, msi_irq_active_next;
reg [MSI_COUNT-1:0] msi_irq_mask_reg = {MSI_COUNT{1'b0}}, msi_irq_mask_next;
reg [MSI_COUNT-1:0] msi_int_reg = {MSI_COUNT{1'b0}}, msi_int_next;
assign cfg_interrupt_msi_select = 4'd0; // request PF0 mask on cfg_interrupt_msi_data
assign cfg_interrupt_msi_int = msi_int_reg;
assign cfg_interrupt_msi_pending_status = msi_irq_reg;
assign cfg_interrupt_msi_pending_status_data_enable = 1'b1; // set PF0 pending status
assign cfg_interrupt_msi_pending_status_function_num = 4'd0; // set PF0 pending status
assign cfg_interrupt_msi_attr = 3'd0;
assign cfg_interrupt_msi_tph_present = 1'b0; // no TPH
assign cfg_interrupt_msi_tph_type = 2'd0;
assign cfg_interrupt_msi_tph_st_tag = 9'd0;
assign cfg_interrupt_msi_function_number = 4'd0; // send MSI for PF0
wire [MSI_COUNT-1:0] message_enable_mask = cfg_interrupt_msi_mmenable[2:0] > 3'd4 ? {32{1'b1}} : {32{1'b1}} >> (32 - (1 << cfg_interrupt_msi_mmenable[2:0]));
reg [MSI_COUNT-1:0] acknowledge;
wire [MSI_COUNT-1:0] grant;
wire grant_valid;
// arbiter instance
arbiter #(
.PORTS(MSI_COUNT),
.TYPE("ROUND_ROBIN"),
.BLOCK("ACKNOWLEDGE"),
.LSB_PRIORITY("HIGH")
)
arb_inst (
.clk(clk),
.rst(rst),
.request(msi_irq_active_reg & msi_irq_mask_reg & ~grant),
.acknowledge(acknowledge),
.grant(grant),
.grant_valid(grant_valid),
.grant_encoded()
);
always @* begin
active_next = active_reg;
msi_irq_active_next = (msi_irq_active_reg | (msi_irq_reg & ~msi_irq_last_reg));
msi_irq_mask_next = ~cfg_interrupt_msi_data & message_enable_mask & {32{cfg_interrupt_msi_enable[0]}};
msi_int_next = {MSI_COUNT{1'b0}};
acknowledge = {MSI_COUNT{1'b0}};
if (!active_reg) begin
if (cfg_interrupt_msi_enable && grant_valid) begin
msi_int_next = grant;
active_next = 1'b1;
end
end else begin
if (cfg_interrupt_msi_sent || cfg_interrupt_msi_fail) begin
if (cfg_interrupt_msi_sent) begin
msi_irq_active_next = msi_irq_active_next & ~grant;
end
acknowledge = grant;
active_next = 1'b0;
end
end
end
always @(posedge clk) begin
if (rst) begin
active_reg <= 1'b0;
msi_irq_reg <= {MSI_COUNT{1'b0}};
msi_irq_last_reg <= {MSI_COUNT{1'b0}};
msi_irq_active_reg <= {MSI_COUNT{1'b0}};
msi_irq_mask_reg <= {MSI_COUNT{1'b0}};
msi_int_reg <= {MSI_COUNT{1'b0}};
end else begin
active_reg <= active_next;
msi_irq_reg <= msi_irq;
msi_irq_last_reg <= msi_irq_reg;
msi_irq_active_reg <= msi_irq_active_next;
msi_irq_mask_reg <= msi_irq_mask_next;
msi_int_reg <= msi_int_next;
end
end
endmodule

View File

@ -0,0 +1,94 @@
/*
Copyright (c) 2014-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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Priority encoder module
*/
module priority_encoder #
(
parameter WIDTH = 4,
// LSB priority: "LOW", "HIGH"
parameter LSB_PRIORITY = "LOW"
)
(
input wire [WIDTH-1:0] input_unencoded,
output wire output_valid,
output wire [$clog2(WIDTH)-1:0] output_encoded,
output wire [WIDTH-1:0] output_unencoded
);
// power-of-two width
parameter W1 = 2**$clog2(WIDTH);
parameter W2 = W1/2;
generate
if (WIDTH == 2) begin
// two inputs - just an OR gate
assign output_valid = |input_unencoded;
if (LSB_PRIORITY == "LOW") begin
assign output_encoded = input_unencoded[1];
end else begin
assign output_encoded = ~input_unencoded[0];
end
end else begin
// more than two inputs - split into two parts and recurse
// also pad input to correct power-of-two width
wire [$clog2(W2)-1:0] out1, out2;
wire valid1, valid2;
priority_encoder #(
.WIDTH(W2),
.LSB_PRIORITY(LSB_PRIORITY)
)
priority_encoder_inst1 (
.input_unencoded(input_unencoded[W2-1:0]),
.output_valid(valid1),
.output_encoded(out1)
);
priority_encoder #(
.WIDTH(W2),
.LSB_PRIORITY(LSB_PRIORITY)
)
priority_encoder_inst2 (
.input_unencoded({{W1-WIDTH{1'b0}}, input_unencoded[WIDTH-1:W2]}),
.output_valid(valid2),
.output_encoded(out2)
);
// multiplexer to select part
assign output_valid = valid1 | valid2;
if (LSB_PRIORITY == "LOW") begin
assign output_encoded = valid2 ? {1'b1, out2} : {1'b0, out1};
end else begin
assign output_encoded = valid1 ? {1'b0, out1} : {1'b1, out2};
end
end
endgenerate
// unencoded output
assign output_unencoded = 1 << output_encoded;
endmodule

View File

@ -0,0 +1,77 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Pulse merge module
*/
module pulse_merge #
(
parameter INPUT_WIDTH = 2,
parameter COUNT_WIDTH = 4
)
(
input wire clk,
input wire rst,
input wire [INPUT_WIDTH-1:0] pulse_in,
output wire [COUNT_WIDTH-1:0] count_out,
output wire pulse_out
);
reg [COUNT_WIDTH-1:0] count_reg = {COUNT_WIDTH{1'b0}}, count_next;
reg pulse_reg = 1'b0, pulse_next;
assign count_out = count_reg;
assign pulse_out = pulse_reg;
integer i;
always @* begin
count_next = count_reg;
pulse_next = count_reg > 0;
if (count_reg > 0) begin
count_next = count_reg - 1;
end
for (i = 0; i < INPUT_WIDTH; i = i + 1) begin
count_next = count_next + pulse_in[i];
end
end
always @(posedge clk) begin
if (rst) begin
count_reg <= {COUNT_WIDTH{1'b0}};
pulse_reg <= 1'b0;
end else begin
count_reg <= count_next;
pulse_reg <= pulse_next;
end
end
endmodule

View File

@ -0,0 +1,41 @@
#!/bin/bash
dev=$1
if [ -z "$dev" ]; then
echo "Error: no device specified"
exit 1
fi
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
dev="0000:$dev"
fi
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
echo "Error: device $dev not found"
exit 1
fi
port=$(basename $(dirname $(readlink "/sys/bus/pci/devices/$dev")))
if [ ! -e "/sys/bus/pci/devices/$port" ]; then
echo "Error: device $port not found"
exit 1
fi
echo "Disabling fatal error reporting on port $port..."
cmd=$(setpci -s $port COMMAND)
echo "Command:" $cmd
# clear SERR bit in command register
setpci -s $port COMMAND=$(printf "%04x" $(("0x$cmd" & ~0x0100)))
ctrl=$(setpci -s $port CAP_EXP+8.w)
echo "Device control:" $ctrl
# clear fatal error reporting enable bit in device control register
setpci -s $port CAP_EXP+8.w=$(printf "%04x" $(("0x$ctrl" & ~0x0004)))

View File

@ -0,0 +1,44 @@
#!/bin/bash
dev=$1
en=$2
if [ -z "$dev" ]; then
echo "Error: no device specified"
exit 1
fi
if [ -z "$en" ]; then
echo "Error: must specify operation"
exit 1
fi
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
dev="0000:$dev"
fi
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
echo "Error: device $dev not found"
exit 1
fi
ctrl=$(setpci -s $dev CAP_EXP+8.w)
if (($en > 0)); then
echo "Enabling ext tag on $dev..."
echo "Device control:" $ctrl
setpci -s $dev CAP_EXP+8.w=$(printf "%04x" $(("0x$ctrl" | 0x0100)))
else
echo "Disabling ext tag on $dev..."
echo "Device control:" $ctrl
setpci -s $dev CAP_EXP+8.w=$(printf "%04x" $(("0x$ctrl" & ~0x0100)))
fi

View File

@ -0,0 +1,23 @@
#!/bin/bash
dev=$1
if [ -z "$dev" ]; then
echo "Error: no device specified"
exit 1
fi
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
dev="0000:$dev"
fi
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
echo "Error: device $dev not found"
exit 1
fi
echo "Resetting function $dev..."
echo 1 > "/sys/bus/pci/devices/$dev/reset"

View File

@ -0,0 +1,49 @@
#!/bin/bash
dev=$1
if [ -z "$dev" ]; then
echo "Error: no device specified"
exit 1
fi
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
dev="0000:$dev"
fi
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
echo "Error: device $dev not found"
exit 1
fi
port=$(basename $(dirname $(readlink "/sys/bus/pci/devices/$dev")))
if [[ $port != pci* ]]; then
echo "Note: it may be necessary to run this on the corresponding upstream port"
echo "Device $dev is connected to upstream port $port"
fi
echo "Configuring $dev..."
lc2=$(setpci -s $dev CAP_EXP+30.L)
echo "Original link control 2:" $lc2
echo "Original link target speed:" $(("0x$lc2" & 0xF))
lc2n=$(printf "%08x" $((("0x$lc2" & 0xFFFFFFF0) | 0x2)))
echo "New link control 2:" $lc2n
setpci -s $dev CAP_EXP+30.L=$lc2n
echo "Triggering link retraining..."
lc=$(setpci -s $dev CAP_EXP+10.L)
echo "Original link control:" $lc
lcn=$(printf "%08x" $(("0x$lc" | 0x20)))
echo "New link control:" $lcn
setpci -s $dev CAP_EXP+10.L=$lcn

View File

@ -0,0 +1,45 @@
#!/bin/bash
dev=$1
if [ -z "$dev" ]; then
echo "Error: no device specified"
exit 1
fi
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
dev="0000:$dev"
fi
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
echo "Error: device $dev not found"
exit 1
fi
port=$(basename $(dirname $(readlink "/sys/bus/pci/devices/$dev")))
if [ ! -e "/sys/bus/pci/devices/$port" ]; then
echo "Error: device $port not found"
exit 1
fi
echo "Removing $dev..."
echo 1 > "/sys/bus/pci/devices/$dev/remove"
echo "Performing hot reset of port $port..."
bc=$(setpci -s $port BRIDGE_CONTROL)
echo "Bridge control:" $bc
setpci -s $port BRIDGE_CONTROL=$(printf "%04x" $(("0x$bc" | 0x40)))
sleep 0.01
setpci -s $port BRIDGE_CONTROL=$bc
sleep 0.5
echo "Rescanning bus..."
echo 1 > "/sys/bus/pci/devices/$port/rescan"

View File

@ -0,0 +1,5 @@
#!/bin/bash
echo 1 > /sys/bus/pci/rescan

View File

@ -0,0 +1,27 @@
#!/bin/bash
dev=$1
if [ -z "$dev" ]; then
echo "Error: no device specified"
exit 1
fi
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
dev="0000:$dev"
fi
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
echo "Error: device $dev not found"
exit 1
fi
echo "Removing $dev..."
echo 1 > "/sys/bus/pci/devices/$dev/remove"
echo "Rescanning bus..."
echo 1 > "/sys/bus/pci/rescan"

788
fpga/lib/pcie/tb/axi.py Normal file
View File

@ -0,0 +1,788 @@
"""
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 math
import mmap
BURST_FIXED = 0b00
BURST_INCR = 0b01
BURST_WRAP = 0b10
BURST_SIZE_1 = 0b000
BURST_SIZE_2 = 0b001
BURST_SIZE_4 = 0b010
BURST_SIZE_8 = 0b011
BURST_SIZE_16 = 0b100
BURST_SIZE_32 = 0b101
BURST_SIZE_64 = 0b110
BURST_SIZE_128 = 0b111
LOCK_NORMAL = 0b0
LOCK_EXCLUSIVE = 0b1
CACHE_B = 0b0001
CACHE_M = 0b0010
CACHE_RA = 0b0100
CACHE_WA = 0b1000
ARCACHE_DEVICE_NON_BUFFERABLE = 0b0000
ARCACHE_DEVICE_BUFFERABLE = 0b0001
ARCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 0b0010
ARCACHE_NORMAL_NON_CACHEABLE_BUFFERABLE = 0b0011
ARCACHE_WRITE_THROUGH_NO_ALLOC = 0b1010
ARCACHE_WRITE_THROUGH_READ_ALLOC = 0b1110
ARCACHE_WRITE_THROUGH_WRITE_ALLOC = 0b1010
ARCACHE_WRITE_THROUGH_READ_AND_WRITE_ALLOC = 0b1110
ARCACHE_WRITE_BACK_NO_ALLOC = 0b1011
ARCACHE_WRITE_BACK_READ_ALLOC = 0b1111
ARCACHE_WRITE_BACK_WRITE_ALLOC = 0b1011
ARCACHE_WRITE_BACK_READ_AND_WRIE_ALLOC = 0b1111
AWCACHE_DEVICE_NON_BUFFERABLE = 0b0000
AWCACHE_DEVICE_BUFFERABLE = 0b0001
AWCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 0b0010
AWCACHE_NORMAL_NON_CACHEABLE_BUFFERABLE = 0b0011
AWCACHE_WRITE_THROUGH_NO_ALLOC = 0b0110
AWCACHE_WRITE_THROUGH_READ_ALLOC = 0b0110
AWCACHE_WRITE_THROUGH_WRITE_ALLOC = 0b1110
AWCACHE_WRITE_THROUGH_READ_AND_WRITE_ALLOC = 0b1110
AWCACHE_WRITE_BACK_NO_ALLOC = 0b0111
AWCACHE_WRITE_BACK_READ_ALLOC = 0b0111
AWCACHE_WRITE_BACK_WRITE_ALLOC = 0b1111
AWCACHE_WRITE_BACK_READ_AND_WRIE_ALLOC = 0b1111
class AXIMaster(object):
def __init__(self):
self.write_command_queue = []
self.write_command_sync = Signal(False)
self.write_resp_queue = []
self.write_resp_sync = Signal(False)
self.read_command_queue = []
self.read_command_sync = Signal(False)
self.read_data_queue = []
self.read_data_sync = Signal(False)
self.cur_write_id = 0
self.cur_read_id = 0
self.int_write_addr_queue = []
self.int_write_addr_sync = Signal(False)
self.int_write_data_queue = []
self.int_write_data_sync = Signal(False)
self.int_write_resp_command_queue = []
self.int_write_resp_command_sync = Signal(False)
self.int_write_resp_queue = []
self.int_write_resp_sync = Signal(False)
self.int_read_addr_queue = []
self.int_read_addr_sync = Signal(False)
self.int_read_resp_command_queue = []
self.int_read_resp_command_sync = Signal(False)
self.int_read_resp_queue = []
self.int_read_resp_sync = Signal(False)
self.in_flight_operations = 0
self.has_logic = False
self.clk = None
def init_read(self, address, length, burst=0b01, size=None, lock=0b0, cache=0b0000, prot=0b010, qos=0b0000, region=0b0000, user=None):
self.read_command_queue.append((address, length, burst, size, lock, cache, prot, qos, region, user))
self.read_command_sync.next = not self.read_command_sync
def init_write(self, address, data, burst=0b01, size=None, lock=0b0, cache=0b0000, prot=0b010, qos=0b0000, region=0b0000, user=None):
self.write_command_queue.append((address, data, burst, size, lock, cache, prot, qos, region, user))
self.write_command_sync.next = not self.write_command_sync
def idle(self):
return not self.write_command_queue and not self.read_command_queue and not self.in_flight_operations
def wait(self):
while not self.idle():
yield self.clk.posedge
def read_data_ready(self):
return bool(self.read_data_queue)
def get_read_data(self):
if self.read_data_queue:
return self.read_data_queue.pop(0)
return None
def create_logic(self,
clk,
rst,
m_axi_awid=None,
m_axi_awaddr=None,
m_axi_awlen=Signal(intbv(0)[8:]),
m_axi_awsize=Signal(intbv(0)[3:]),
m_axi_awburst=Signal(intbv(0)[2:]),
m_axi_awlock=Signal(intbv(0)[1:]),
m_axi_awcache=Signal(intbv(0)[4:]),
m_axi_awprot=Signal(intbv(0)[3:]),
m_axi_awqos=Signal(intbv(0)[4:]),
m_axi_awregion=Signal(intbv(0)[4:]),
m_axi_awuser=None,
m_axi_awvalid=Signal(bool(False)),
m_axi_awready=Signal(bool(True)),
m_axi_wdata=None,
m_axi_wstrb=Signal(intbv(1)[1:]),
m_axi_wlast=Signal(bool(True)),
m_axi_wuser=None,
m_axi_wvalid=Signal(bool(False)),
m_axi_wready=Signal(bool(True)),
m_axi_bid=None,
m_axi_bresp=Signal(intbv(0)[2:]),
m_axi_buser=None,
m_axi_bvalid=Signal(bool(False)),
m_axi_bready=Signal(bool(False)),
m_axi_arid=None,
m_axi_araddr=None,
m_axi_arlen=Signal(intbv(0)[8:]),
m_axi_arsize=Signal(intbv(0)[3:]),
m_axi_arburst=Signal(intbv(0)[2:]),
m_axi_arlock=Signal(intbv(0)[1:]),
m_axi_arcache=Signal(intbv(0)[4:]),
m_axi_arprot=Signal(intbv(0)[3:]),
m_axi_arqos=Signal(intbv(0)[4:]),
m_axi_arregion=Signal(intbv(0)[4:]),
m_axi_aruser=None,
m_axi_arvalid=Signal(bool(False)),
m_axi_arready=Signal(bool(True)),
m_axi_rid=None,
m_axi_rdata=None,
m_axi_rresp=Signal(intbv(0)[2:]),
m_axi_rlast=Signal(bool(True)),
m_axi_ruser=None,
m_axi_rvalid=Signal(bool(False)),
m_axi_rready=Signal(bool(False)),
name=None
):
if self.has_logic:
raise Exception("Logic already instantiated!")
if m_axi_wdata is not None:
assert m_axi_awid is not None
assert m_axi_bid is not None
assert len(m_axi_awid) == len(m_axi_bid)
assert m_axi_awaddr is not None
assert len(m_axi_wdata) % 8 == 0
assert len(m_axi_wdata) / 8 == len(m_axi_wstrb)
w = len(m_axi_wdata)
if m_axi_rdata is not None:
assert m_axi_arid is not None
assert m_axi_rid is not None
assert len(m_axi_arid) == len(m_axi_rid)
assert m_axi_araddr is not None
assert len(m_axi_rdata) % 8 == 0
w = len(m_axi_rdata)
if m_axi_wdata is not None:
assert len(m_axi_wdata) == len(m_axi_rdata)
assert len(m_axi_awid) == len(m_axi_arid)
assert len(m_axi_awaddr) == len(m_axi_araddr)
bw = int(w/8)
assert bw in (1, 2, 4, 8, 16, 32, 64, 128)
self.has_logic = True
self.clk = clk
@instance
def write_logic():
while True:
if not self.write_command_queue:
yield self.write_command_sync
addr, data, burst, size, lock, cache, prot, qos, region, user = self.write_command_queue.pop(0)
self.in_flight_operations += 1
num_bytes = bw
if size is None:
size = int(math.log(bw, 2))
else:
num_bytes = 2**size
assert 0 < num_bytes <= bw
aligned_addr = int(addr/num_bytes)*num_bytes
word_addr = int(addr/bw)*bw
start_offset = addr % bw
end_offset = ((addr + len(data) - 1) % bw) + 1
cycles = int((len(data) + num_bytes-1 + (addr % num_bytes)) / num_bytes)
cur_addr = aligned_addr
offset = 0
cycle_offset = aligned_addr-word_addr
n = 0
transfer_count = 0
burst_length = 0
if name is not None:
print("[%s] Write data addr: 0x%08x prot: 0x%x data: %s" % (name, addr, prot, " ".join(("{:02x}".format(c) for c in bytearray(data)))))
for k in range(cycles):
start = cycle_offset
stop = cycle_offset+num_bytes
if k == 0:
start = start_offset
if k == cycles-1:
stop = end_offset
strb = ((2**bw-1) << start) & (2**bw-1) & (2**bw-1) >> (bw - stop)
val = 0
for j in range(start, stop):
val |= bytearray(data)[offset] << j*8
offset += 1
if n >= burst_length:
transfer_count += 1
n = 0
burst_length = min(cycles-k, 256) # max len
burst_length = min(burst_length, 0x1000-(cur_addr&0xfff)) # 4k align
awid = self.cur_write_id
self.cur_write_id = (self.cur_write_id + 1) % 2**len(m_axi_awid)
self.int_write_addr_queue.append((cur_addr, awid, burst_length-1, size, burst, lock, cache, prot, qos, region, user))
self.int_write_addr_sync.next = not self.int_write_addr_sync
n += 1
self.int_write_data_queue.append((val, strb, n >= burst_length))
self.int_write_data_sync.next = not self.int_write_data_sync
cur_addr += num_bytes
cycle_offset = (cycle_offset + num_bytes) % bw
self.int_write_resp_command_queue.append((addr, len(data), transfer_count, prot))
self.int_write_resp_command_sync.next = not self.int_write_resp_command_sync
@instance
def write_resp_logic():
while True:
if not self.int_write_resp_command_queue:
yield self.int_write_resp_command_sync
addr, length, transfer_count, prot = self.int_write_resp_command_queue.pop(0)
resp = 0
for k in range(transfer_count):
while not self.int_write_resp_queue:
yield clk.posedge
cycle_resp = self.int_write_resp_queue.pop(0)
if cycle_resp != 0:
resp = cycle_resp
self.write_resp_queue.append((addr, length, prot, resp))
self.write_resp_sync.next = not self.write_resp_sync
self.in_flight_operations -= 1
@instance
def write_addr_interface_logic():
while True:
while not self.int_write_addr_queue:
yield clk.posedge
addr, awid, length, size, burst, lock, cache, prot, qos, region, user = self.int_write_addr_queue.pop(0)
m_axi_awaddr.next = addr
m_axi_awid.next = awid
m_axi_awlen.next = length
m_axi_awsize.next = size
m_axi_awburst.next = burst
m_axi_awlock.next = lock
m_axi_awcache.next = cache
m_axi_awprot.next = prot
m_axi_awqos.next = qos
m_axi_awregion.next = region
if m_axi_awuser is not None:
m_axi_awuser.next = user
m_axi_awvalid.next = True
yield clk.posedge
while m_axi_awvalid and not m_axi_awready:
yield clk.posedge
m_axi_awvalid.next = False
@instance
def write_data_interface_logic():
while True:
while not self.int_write_data_queue:
yield clk.posedge
m_axi_wdata.next, m_axi_wstrb.next, m_axi_wlast.next = self.int_write_data_queue.pop(0)
m_axi_wvalid.next = True
yield clk.posedge
while m_axi_wvalid and not m_axi_wready:
yield clk.posedge
m_axi_wvalid.next = False
@instance
def write_resp_interface_logic():
while True:
m_axi_bready.next = True
yield clk.posedge
if m_axi_bready & m_axi_bvalid:
self.int_write_resp_queue.append(int(m_axi_bresp))
self.int_write_resp_sync.next = not self.int_write_resp_sync
@instance
def read_logic():
while True:
if not self.read_command_queue:
yield self.read_command_sync
addr, length, burst, size, lock, cache, prot, qos, region, user = self.read_command_queue.pop(0)
self.in_flight_operations += 1
num_bytes = bw
if size is None:
size = int(math.log(bw, 2))
else:
num_bytes = 2**size
assert 0 < num_bytes <= bw
aligned_addr = int(addr/num_bytes)*num_bytes
word_addr = int(addr/bw)*bw
cycles = int((length + num_bytes-1 + (addr % num_bytes)) / num_bytes)
self.int_read_resp_command_queue.append((addr, length, size, cycles, prot))
self.int_read_resp_command_sync.next = not self.int_read_resp_command_sync
cur_addr = aligned_addr
n = 0
burst_length = 0
for k in range(cycles):
n += 1
if n >= burst_length:
n = 0
burst_length = min(cycles-k, 256) # max len
burst_length = min(burst_length, 0x1000-((aligned_addr+k*num_bytes)&0xfff))# 4k align
arid = self.cur_read_id
self.cur_read_id = (self.cur_read_id + 1) % 2**len(m_axi_arid)
self.int_read_addr_queue.append((cur_addr, arid, burst_length-1, size, burst, lock, cache, prot, qos, region, user))
self.int_read_addr_sync.next = not self.int_read_addr_sync
cur_addr += num_bytes
@instance
def read_resp_logic():
while True:
if not self.int_read_resp_command_queue:
yield self.int_read_resp_command_sync
addr, length, size, cycles, prot = self.int_read_resp_command_queue.pop(0)
num_bytes = 2**size
assert 0 <= size <= int(math.log(bw, 2))
aligned_addr = int(addr/num_bytes)*num_bytes
word_addr = int(addr/bw)*bw
start_offset = addr % bw
end_offset = ((addr + length - 1) % bw) + 1
cycle_offset = aligned_addr-word_addr
data = b''
resp = 0
for k in range(cycles):
if not self.int_read_resp_queue:
yield self.int_read_resp_sync
cycle_data, cycle_resp, cycle_last = self.int_read_resp_queue.pop(0)
if cycle_resp != 0:
resp = cycle_resp
start = cycle_offset
stop = cycle_offset+num_bytes
if k == 0:
start = start_offset
if k == cycles-1:
stop = end_offset
assert cycle_last == (k == cycles - 1)
for j in range(start, stop):
data += bytearray([(cycle_data >> j*8) & 0xff])
cycle_offset = (cycle_offset + num_bytes) % bw
if name is not None:
print("[%s] Read data addr: 0x%08x prot: 0x%x data: %s" % (name, addr, prot, " ".join(("{:02x}".format(c) for c in bytearray(data)))))
self.read_data_queue.append((addr, data, prot, resp))
self.read_data_sync.next = not self.read_data_sync
self.in_flight_operations -= 1
@instance
def read_addr_interface_logic():
while True:
while not self.int_read_addr_queue:
yield clk.posedge
addr, arid, length, size, burst, lock, cache, prot, qos, region, user = self.int_read_addr_queue.pop(0)
m_axi_araddr.next = addr
m_axi_arid.next = arid
m_axi_arlen.next = length
m_axi_arsize.next = size
m_axi_arburst.next = burst
m_axi_arlock.next = lock
m_axi_arcache.next = cache
m_axi_arprot.next = prot
m_axi_arqos.next = qos
m_axi_arregion.next = region
if m_axi_aruser is not None:
m_axi_aruser.next = user
m_axi_arvalid.next = True
yield clk.posedge
while m_axi_arvalid and not m_axi_arready:
yield clk.posedge
m_axi_arvalid.next = False
@instance
def read_resp_interface_logic():
while True:
m_axi_rready.next = True
yield clk.posedge
if m_axi_rready & m_axi_rvalid:
self.int_read_resp_queue.append((int(m_axi_rdata), int(m_axi_rresp), int(m_axi_rlast)))
self.int_read_resp_sync.next = not self.int_read_resp_sync
return instances()
class AXIRam(object):
def __init__(self, size = 1024):
self.size = size
self.mem = mmap.mmap(-1, size)
self.int_write_addr_queue = []
self.int_write_addr_sync = Signal(False)
self.int_write_data_queue = []
self.int_write_data_sync = Signal(False)
self.int_write_resp_queue = []
self.int_write_resp_sync = Signal(False)
self.int_read_addr_queue = []
self.int_read_addr_sync = Signal(False)
self.int_read_resp_queue = []
self.int_read_resp_sync = Signal(False)
def read_mem(self, address, length):
self.mem.seek(address % self.size)
return self.mem.read(length)
def write_mem(self, address, data):
self.mem.seek(address % self.size)
self.mem.write(data)
def create_port(self,
clk,
s_axi_awid=None,
s_axi_awaddr=None,
s_axi_awlen=Signal(intbv(0)[8:]),
s_axi_awsize=Signal(intbv(0)[3:]),
s_axi_awburst=Signal(intbv(0)[2:]),
s_axi_awlock=Signal(intbv(0)[1:]),
s_axi_awcache=Signal(intbv(0)[4:]),
s_axi_awprot=Signal(intbv(0)[3:]),
s_axi_awvalid=Signal(bool(False)),
s_axi_awready=Signal(bool(True)),
s_axi_wdata=None,
s_axi_wstrb=Signal(intbv(1)[1:]),
s_axi_wlast=Signal(bool(True)),
s_axi_wvalid=Signal(bool(False)),
s_axi_wready=Signal(bool(True)),
s_axi_bid=None,
s_axi_bresp=Signal(intbv(0)[2:]),
s_axi_bvalid=Signal(bool(False)),
s_axi_bready=Signal(bool(False)),
s_axi_arid=None,
s_axi_araddr=None,
s_axi_arlen=Signal(intbv(0)[8:]),
s_axi_arsize=Signal(intbv(0)[3:]),
s_axi_arburst=Signal(intbv(0)[2:]),
s_axi_arlock=Signal(intbv(0)[1:]),
s_axi_arcache=Signal(intbv(0)[4:]),
s_axi_arprot=Signal(intbv(0)[3:]),
s_axi_arvalid=Signal(bool(False)),
s_axi_arready=Signal(bool(True)),
s_axi_rid=None,
s_axi_rdata=None,
s_axi_rresp=Signal(intbv(0)[2:]),
s_axi_rlast=Signal(bool(True)),
s_axi_rvalid=Signal(bool(False)),
s_axi_rready=Signal(bool(False)),
name=None
):
if s_axi_wdata is not None:
assert s_axi_awid is not None
assert s_axi_bid is not None
assert len(s_axi_awid) == len(s_axi_bid)
assert s_axi_awaddr is not None
assert len(s_axi_wdata) % 8 == 0
assert len(s_axi_wdata) / 8 == len(s_axi_wstrb)
w = len(s_axi_wdata)
if s_axi_rdata is not None:
assert s_axi_arid is not None
assert s_axi_rid is not None
assert len(s_axi_arid) == len(s_axi_rid)
assert s_axi_araddr is not None
assert len(s_axi_rdata) % 8 == 0
w = len(s_axi_rdata)
if s_axi_wdata is not None:
assert len(s_axi_wdata) == len(s_axi_rdata)
assert len(s_axi_awid) == len(s_axi_arid)
assert len(s_axi_awaddr) == len(s_axi_araddr)
bw = int(w/8)
assert bw in (1, 2, 4, 8, 16, 32, 64, 128)
@instance
def write_logic():
while True:
if not self.int_write_addr_queue:
yield self.int_write_addr_sync
addr, awid, length, size, burst, lock, cache, prot = self.int_write_addr_queue.pop(0)
num_bytes = 2**size
assert 0 < num_bytes <= bw
aligned_addr = int(addr/num_bytes)*num_bytes
length = length+1
transfer_size = num_bytes*length
if burst == BURST_WRAP:
lower_wrap_boundary = int(addr/transfer_size)*transfer_size
upper_wrap_boundary = lower_wrap_boundary+transfer_size
if burst == BURST_INCR:
# check for 4k boundary crossing
assert 0x1000-(aligned_addr&0xfff) >= transfer_size
cur_addr = aligned_addr
for n in range(length):
cur_word_addr = int(cur_addr/bw)*bw
self.mem.seek(cur_word_addr % self.size)
if not self.int_write_data_queue:
yield self.int_write_data_sync
wdata, strb, last = self.int_write_data_queue.pop(0)
data = bytearray()
for i in range(bw):
data.extend(bytearray([wdata & 0xff]))
wdata >>= 8
for i in range(bw):
if strb & (1 << i):
self.mem.write(data[i:i+1])
else:
self.mem.seek(1, 1)
if n == length-1:
self.int_write_resp_queue.append((awid, 0b00))
self.int_write_resp_sync.next = not self.int_write_resp_sync
assert last == (n == length-1)
if name is not None:
print("[%s] Write word id: %d addr: 0x%08x prot: 0x%x wstrb: 0x%02x data: %s" % (name, awid, cur_addr, prot, s_axi_wstrb, " ".join(("{:02x}".format(c) for c in bytearray(data)))))
if burst != BURST_FIXED:
cur_addr += num_bytes
if burst == BURST_WRAP:
if cur_addr == upper_wrap_boundary:
cur_addr = lower_wrap_boundary
@instance
def write_addr_interface_logic():
while True:
s_axi_awready.next = True
yield clk.posedge
if s_axi_awready & s_axi_awvalid:
addr = int(s_axi_awaddr)
awid = int(s_axi_awid)
length = int(s_axi_awlen)
size = int(s_axi_awsize)
burst = int(s_axi_awburst)
lock = int(s_axi_awlock)
cache = int(s_axi_awcache)
prot = int(s_axi_awprot)
self.int_write_addr_queue.append((addr, awid, length, size, burst, lock, cache, prot))
self.int_write_addr_sync.next = not self.int_write_addr_sync
@instance
def write_data_interface_logic():
while True:
s_axi_wready.next = True
yield clk.posedge
if s_axi_wready & s_axi_wvalid:
data = int(s_axi_wdata)
strb = int(s_axi_wstrb)
last = bool(s_axi_wlast)
self.int_write_data_queue.append((data, strb, last))
self.int_write_data_sync.next = not self.int_write_data_sync
@instance
def write_resp_interface_logic():
while True:
while not self.int_write_resp_queue:
yield clk.posedge
s_axi_bid.next, s_axi_bresp.next = self.int_write_resp_queue.pop(0)
s_axi_bvalid.next = True
yield clk.posedge
while s_axi_bvalid and not s_axi_bready:
yield clk.posedge
s_axi_bvalid.next = False
@instance
def read_logic():
while True:
if not self.int_read_addr_queue:
yield self.int_read_addr_sync
addr, arid, length, size, burst, lock, cache, prot = self.int_read_addr_queue.pop(0)
num_bytes = 2**size
assert 0 < num_bytes <= bw
aligned_addr = int(addr/num_bytes)*num_bytes
length = length+1
transfer_size = num_bytes*length
if burst == BURST_WRAP:
lower_wrap_boundary = int(addr/transfer_size)*transfer_size
upper_wrap_boundary = lower_wrap_boundary+transfer_size
if burst == BURST_INCR:
# check for 4k boundary crossing
assert 0x1000-(aligned_addr&0xfff) >= transfer_size
cur_addr = aligned_addr
for n in range(length):
cur_word_addr = int(cur_addr/bw)*bw
self.mem.seek(cur_word_addr % self.size)
data = bytearray(self.mem.read(bw))
val = 0
for i in range(bw-1,-1,-1):
val <<= 8
val += data[i]
self.int_read_resp_queue.append((arid, val, 0x00, n == length-1))
self.int_read_resp_sync.next = not self.int_read_resp_sync
if name is not None:
print("[%s] Read word id: %d addr: 0x%08x prot: 0x%x data: %s" % (name, arid, cur_addr, prot, " ".join(("{:02x}".format(c) for c in bytearray(data)))))
if burst != BURST_FIXED:
cur_addr += num_bytes
if burst == BURST_WRAP:
if cur_addr == upper_wrap_boundary:
cur_addr = lower_wrap_boundary
@instance
def read_addr_interface_logic():
while True:
s_axi_arready.next = True
yield clk.posedge
if s_axi_arready & s_axi_arvalid:
addr = int(s_axi_araddr)
arid = int(s_axi_arid)
length = int(s_axi_arlen)
size = int(s_axi_arsize)
burst = int(s_axi_arburst)
lock = int(s_axi_arlock)
cache = int(s_axi_arcache)
prot = int(s_axi_arprot)
self.int_read_addr_queue.append((addr, arid, length, size, burst, lock, cache, prot))
self.int_read_addr_sync.next = not self.int_read_addr_sync
@instance
def read_resp_interface_logic():
while True:
while not self.int_read_resp_queue:
yield clk.posedge
s_axi_rid.next, s_axi_rdata.next, s_axi_rresp.next, s_axi_rlast.next = self.int_read_resp_queue.pop(0)
s_axi_rvalid.next = True
yield clk.posedge
while s_axi_rvalid and not s_axi_rready:
yield clk.posedge
s_axi_rvalid.next = False
return instances()

470
fpga/lib/pcie/tb/axil.py Normal file
View File

@ -0,0 +1,470 @@
"""
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 mmap
class AXILiteMaster(object):
def __init__(self):
self.write_command_queue = []
self.write_resp_queue = []
self.read_command_queue = []
self.read_data_queue = []
self.int_write_addr_queue = []
self.int_write_data_queue = []
self.int_write_resp_command_queue = []
self.int_write_resp_queue = []
self.int_read_addr_queue = []
self.int_read_resp_command_queue = []
self.int_read_resp_queue = []
self.in_flight_operations = 0
self.has_logic = False
self.clk = None
def init_read(self, address, length, prot=0b010):
self.read_command_queue.append((address, length, prot))
def init_write(self, address, data, prot=0b010):
self.write_command_queue.append((address, data, prot))
def idle(self):
return not self.write_command_queue and not self.read_command_queue and not self.in_flight_operations
def wait(self):
while not self.idle():
yield self.clk.posedge
def read_data_ready(self):
return bool(self.read_data_queue)
def get_read_data(self):
if self.read_data_queue:
return self.read_data_queue.pop(0)
return None
def create_logic(self,
clk,
rst,
m_axil_awaddr=None,
m_axil_awprot=Signal(intbv(0)[3:]),
m_axil_awvalid=Signal(bool(False)),
m_axil_awready=Signal(bool(True)),
m_axil_wdata=None,
m_axil_wstrb=Signal(intbv(1)[1:]),
m_axil_wvalid=Signal(bool(False)),
m_axil_wready=Signal(bool(True)),
m_axil_bresp=Signal(intbv(0)[2:]),
m_axil_bvalid=Signal(bool(False)),
m_axil_bready=Signal(bool(False)),
m_axil_araddr=None,
m_axil_arprot=Signal(intbv(0)[3:]),
m_axil_arvalid=Signal(bool(False)),
m_axil_arready=Signal(bool(True)),
m_axil_rdata=None,
m_axil_rresp=Signal(intbv(0)[2:]),
m_axil_rvalid=Signal(bool(False)),
m_axil_rready=Signal(bool(False)),
name=None
):
if self.has_logic:
raise Exception("Logic already instantiated!")
if m_axil_wdata is not None:
assert m_axil_awaddr is not None
assert len(m_axil_wdata) % 8 == 0
assert len(m_axil_wdata) / 8 == len(m_axil_wstrb)
w = len(m_axil_wdata)
if m_axil_rdata is not None:
assert m_axil_araddr is not None
assert len(m_axil_rdata) % 8 == 0
w = len(m_axil_rdata)
if m_axil_wdata is not None:
assert len(m_axil_wdata) == len(m_axil_rdata)
assert len(m_axil_awaddr) == len(m_axil_araddr)
bw = int(w/8)
assert bw in (1, 2, 4, 8, 16, 32, 64, 128)
self.has_logic = True
self.clk = clk
@instance
def write_logic():
while True:
while not self.write_command_queue:
yield clk.posedge
addr, data, prot = self.write_command_queue.pop(0)
self.in_flight_operations += 1
word_addr = int(addr/bw)*bw
start_offset = addr % bw
end_offset = ((addr + len(data) - 1) % bw) + 1
strb_start = ((2**bw-1) << start_offset) & (2**bw-1)
strb_end = (2**bw-1) >> (bw - end_offset)
cycles = int((len(data) + bw-1 + (addr % bw)) / bw)
self.int_write_resp_command_queue.append((addr, len(data), cycles, prot))
offset = 0
if name is not None:
print("[%s] Write data addr: 0x%08x prot: 0x%x data: %s" % (name, addr, prot, " ".join(("{:02x}".format(c) for c in bytearray(data)))))
for k in range(cycles):
start = 0
stop = bw
strb = 2**bw-1
if k == 0:
start = start_offset
strb &= strb_start
if k == cycles-1:
stop = end_offset
strb &= strb_end
val = 0
for j in range(start, stop):
val |= bytearray(data)[offset] << j*8
offset += 1
self.int_write_addr_queue.append((word_addr + start + k*bw, prot))
self.int_write_data_queue.append((val, strb))
@instance
def write_resp_logic():
while True:
while not self.int_write_resp_command_queue:
yield clk.posedge
addr, length, cycles, prot = self.int_write_resp_command_queue.pop(0)
resp = 0
for k in range(cycles):
while not self.int_write_resp_queue:
yield clk.posedge
cycle_resp = self.int_write_resp_queue.pop(0)
if cycle_resp != 0:
resp = cycle_resp
self.write_resp_queue.append((addr, length, prot, resp))
self.in_flight_operations -= 1
@instance
def write_addr_interface_logic():
while True:
while not self.int_write_addr_queue:
yield clk.posedge
m_axil_awaddr.next, m_axil_awprot.next = self.int_write_addr_queue.pop(0)
m_axil_awvalid.next = True
yield clk.posedge
while m_axil_awvalid and not m_axil_awready:
yield clk.posedge
m_axil_awvalid.next = False
@instance
def write_data_interface_logic():
while True:
while not self.int_write_data_queue:
yield clk.posedge
m_axil_wdata.next, m_axil_wstrb.next = self.int_write_data_queue.pop(0)
m_axil_wvalid.next = True
yield clk.posedge
while m_axil_wvalid and not m_axil_wready:
yield clk.posedge
m_axil_wvalid.next = False
@instance
def write_resp_interface_logic():
while True:
m_axil_bready.next = True
yield clk.posedge
if m_axil_bready & m_axil_bvalid:
self.int_write_resp_queue.append(int(m_axil_bresp))
@instance
def read_logic():
while True:
while not self.read_command_queue:
yield clk.posedge
addr, length, prot = self.read_command_queue.pop(0)
self.in_flight_operations += 1
word_addr = int(addr/bw)*bw
start_offset = addr % bw
cycles = int((length + bw-1 + (addr % bw)) / bw)
self.int_read_resp_command_queue.append((addr, length, cycles, prot))
# first cycle
self.int_read_addr_queue.append((word_addr+start_offset, prot))
for k in range(1, cycles):
# middle and last cycles
self.int_read_addr_queue.append((word_addr + k*bw, prot))
@instance
def read_resp_logic():
while True:
while not self.int_read_resp_command_queue:
yield clk.posedge
addr, length, cycles, prot = self.int_read_resp_command_queue.pop(0)
word_addr = int(addr/bw)*bw
start_offset = addr % bw
end_offset = ((addr + length - 1) % bw) + 1
data = b''
resp = 0
for k in range(cycles):
while not self.int_read_resp_queue:
yield clk.posedge
cycle_data, cycle_resp = self.int_read_resp_queue.pop(0)
if cycle_resp != 0:
resp = cycle_resp
start = 0
stop = bw
if k == 0:
start = start_offset
if k == cycles-1:
stop = end_offset
for j in range(start, stop):
data += bytearray([(cycle_data >> j*8) & 0xff])
if name is not None:
print("[%s] Read data addr: 0x%08x prot: 0x%x data: %s" % (name, addr, prot, " ".join(("{:02x}".format(c) for c in bytearray(data)))))
self.read_data_queue.append((addr, data, prot, resp))
self.in_flight_operations -= 1
@instance
def read_addr_interface_logic():
while True:
while not self.int_read_addr_queue:
yield clk.posedge
m_axil_araddr.next, m_axil_arprot.next = self.int_read_addr_queue.pop(0)
m_axil_arvalid.next = True
yield clk.posedge
while m_axil_arvalid and not m_axil_arready:
yield clk.posedge
m_axil_arvalid.next = False
@instance
def read_resp_interface_logic():
while True:
m_axil_rready.next = True
yield clk.posedge
if m_axil_rready & m_axil_rvalid:
self.int_read_resp_queue.append((int(m_axil_rdata), int(m_axil_rresp)))
return instances()
class AXILiteRam(object):
def __init__(self, size = 1024):
self.size = size
self.mem = mmap.mmap(-1, size)
def read_mem(self, address, length):
self.mem.seek(address)
return self.mem.read(length)
def write_mem(self, address, data):
self.mem.seek(address)
self.mem.write(bytes(data))
def create_port(self,
clk,
s_axil_awaddr=None,
s_axil_awprot=Signal(intbv(0)[3:]),
s_axil_awvalid=Signal(bool(False)),
s_axil_awready=Signal(bool(True)),
s_axil_wdata=None,
s_axil_wstrb=Signal(intbv(1)[1:]),
s_axil_wvalid=Signal(bool(False)),
s_axil_wready=Signal(bool(True)),
s_axil_bresp=Signal(intbv(0)[2:]),
s_axil_bvalid=Signal(bool(False)),
s_axil_bready=Signal(bool(False)),
s_axil_araddr=None,
s_axil_arprot=Signal(intbv(0)[3:]),
s_axil_arvalid=Signal(bool(False)),
s_axil_arready=Signal(bool(True)),
s_axil_rdata=None,
s_axil_rresp=Signal(intbv(0)[2:]),
s_axil_rvalid=Signal(bool(False)),
s_axil_rready=Signal(bool(False)),
latency=1,
name=None
):
if s_axil_wdata is not None:
assert s_axil_awaddr is not None
assert len(s_axil_wdata) % 8 == 0
assert len(s_axil_wdata) / 8 == len(s_axil_wstrb)
w = len(s_axil_wdata)
if s_axil_rdata is not None:
assert s_axil_araddr is not None
assert len(s_axil_rdata) % 8 == 0
w = len(s_axil_rdata)
if s_axil_wdata is not None:
assert len(s_axil_wdata) == len(s_axil_rdata)
assert len(s_axil_awaddr) == len(s_axil_araddr)
bw = int(w/8)
assert bw in (1, 2, 4, 8, 16, 32, 64, 128)
@instance
def write_logic():
while True:
s_axil_awready.next = True
yield clk.posedge
addr = int(int(s_axil_awaddr)/bw)*bw
prot = int(s_axil_awprot)
if s_axil_awready & s_axil_awvalid:
s_axil_awready.next = False
for i in range(latency):
yield clk.posedge
self.mem.seek(addr % self.size)
s_axil_wready.next = True
yield clk.posedge
while not s_axil_wvalid:
yield clk.posedge
s_axil_wready.next = False
data = bytearray()
val = int(s_axil_wdata)
for i in range(bw):
data.extend(bytearray([val & 0xff]))
val >>= 8
for i in range(bw):
if s_axil_wstrb & (1 << i):
self.mem.write(bytes(data[i:i+1]))
else:
self.mem.seek(1, 1)
s_axil_bresp.next = 0b00
s_axil_bvalid.next = True
if name is not None:
print("[%s] Write word addr: 0x%08x prot: 0x%x wstrb: 0x%02x data: %s" % (name, addr, prot, s_axil_wstrb, " ".join(("{:02x}".format(c) for c in bytearray(data)))))
yield clk.posedge
while not s_axil_bready:
yield clk.posedge
s_axil_bvalid.next = False
@instance
def read_logic():
while True:
s_axil_arready.next = True
yield clk.posedge
addr = int(int(s_axil_araddr)/bw)*bw
prot = int(s_axil_arprot)
if s_axil_arready & s_axil_arvalid:
s_axil_arready.next = False
for i in range(latency):
yield clk.posedge
self.mem.seek(addr % self.size)
data = bytearray(self.mem.read(bw))
val = 0
for i in range(bw-1,-1,-1):
val <<= 8
val += data[i]
s_axil_rdata.next = val
s_axil_rresp.next = 0b00
s_axil_rvalid.next = True
if name is not None:
print("[%s] Read word addr: 0x%08x prot: 0x%x data: %s" % (name, addr, prot, " ".join(("{:02x}".format(c) for c in bytearray(data)))))
yield clk.posedge
while not s_axil_rready:
yield clk.posedge
s_axil_rvalid.next = False
return instances()

522
fpga/lib/pcie/tb/axis_ep.py Normal file
View File

@ -0,0 +1,522 @@
"""
Copyright (c) 2014-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 *
skip_asserts = False
class AXIStreamFrame(object):
def __init__(self, data=b'', keep=None, id=None, dest=None, user=None, last_cycle_user=None):
self.B = 0
self.N = 8
self.M = 1
self.WL = 8
self.data = b''
self.keep = None
self.id = 0
self.dest = 0
self.user = None
self.last_cycle_user = None
if type(data) in (bytes, bytearray):
self.data = bytearray(data)
self.keep = keep
self.id = id
self.dest = dest
self.user = user
self.last_cycle_user = last_cycle_user
elif type(data) is AXIStreamFrame:
self.N = data.N
self.WL = data.WL
if type(data.data) is bytearray:
self.data = bytearray(data.data)
else:
self.data = list(data.data)
if data.keep is not None:
self.keep = list(data.keep)
if data.id is not None:
if type(data.id) in (int, bool):
self.id = data.id
else:
self.id = list(data.id)
if data.dest is not None:
if type(data.dest) in (int, bool):
self.dest = data.dest
else:
self.dest = list(data.dest)
if data.user is not None:
if type(data.user) in (int, bool):
self.user = data.user
else:
self.user = list(data.user)
self.last_cycle_user = data.last_cycle_user
else:
self.data = list(data)
self.keep = keep
self.id = id
self.dest = dest
self.user = user
self.last_cycle_user = last_cycle_user
def build(self):
if self.data is None:
return
f = list(self.data)
tdata = []
tkeep = []
tid = []
tdest = []
tuser = []
i = 0
while len(f) > 0:
if self.B == 0:
data = 0
keep = 0
for j in range(self.M):
data = data | (f.pop(0) << (j*self.WL))
keep = keep | (1 << j)
if len(f) == 0: break
tdata.append(data)
if self.keep is None:
tkeep.append(keep)
else:
tkeep.append(self.keep[i])
else:
# multiple tdata signals
data = 0
tdata.append(f.pop(0))
tkeep.append(0)
if self.id is None:
tid.append(0)
elif type(self.id) is int:
tid.append(self.id)
else:
tid.append(self.id[i])
if self.dest is None:
tdest.append(0)
elif type(self.dest) is int:
tdest.append(self.dest)
else:
tdest.append(self.dest[i])
if self.user is None:
tuser.append(0)
elif type(self.user) is int:
tuser.append(self.user)
else:
tuser.append(self.user[i])
i += 1
if self.last_cycle_user:
tuser[-1] = self.last_cycle_user
return tdata, tkeep, tid, tdest, tuser
def parse(self, tdata, tkeep, tid, tdest, tuser):
if tdata is None or tkeep is None or tuser is None:
return
if len(tdata) != len(tkeep) or len(tdata) != len(tid) or len(tdata) != len(tdest) or len(tdata) != len(tuser):
raise Exception("Invalid data")
self.data = []
self.keep = []
self.id = []
self.dest = []
self.user = []
if self.B == 0:
mask = 2**self.WL-1
for i in range(len(tdata)):
for j in range(self.M):
if tkeep[i] & (1 << j):
self.data.append((tdata[i] >> (j*self.WL)) & mask)
self.keep.append(tkeep[i])
self.id.append(tid[i])
self.dest.append(tdest[i])
self.user.append(tuser[i])
else:
for i in range(len(tdata)):
self.data.append(tdata[i])
self.keep.append(tkeep[i])
self.id.append(tid[i])
self.dest.append(tdest[i])
self.user.append(tuser[i])
if self.WL == 8:
self.data = bytearray(self.data)
self.last_cycle_user = self.user[-1]
def __eq__(self, other):
if not isinstance(other, AXIStreamFrame):
return False
if self.data != other.data:
return False
if self.keep is not None and other.keep is not None:
if self.keep != other.keep:
return False
if self.id is not None and other.id is not None:
if type(self.id) in (int, bool) and type(other.id) is list:
for k in other.id:
if self.id != k:
return False
elif type(other.id) in (int, bool) and type(self.id) is list:
for k in self.id:
if other.id != k:
return False
elif self.id != other.id:
return False
if self.dest is not None and other.dest is not None:
if type(self.dest) in (int, bool) and type(other.dest) is list:
for k in other.dest:
if self.dest != k:
return False
elif type(other.dest) in (int, bool) and type(self.dest) is list:
for k in self.dest:
if other.dest != k:
return False
elif self.dest != other.dest:
return False
if self.last_cycle_user is not None and other.last_cycle_user is not None:
if self.last_cycle_user != other.last_cycle_user:
return False
if self.user is not None and other.user is not None:
if type(self.user) in (int, bool) and type(other.user) is list:
for k in other.user[:-1]:
if self.user != k:
return False
elif type(other.user) in (int, bool) and type(self.user) is list:
for k in self.user[:-1]:
if other.user != k:
return False
elif self.user != other.user:
return False
else:
if self.user is not None and other.user is not None:
if type(self.user) in (int, bool) and type(other.user) is list:
for k in other.user:
if self.user != k:
return False
elif type(other.user) in (int, bool) and type(self.user) is list:
for k in self.user:
if other.user != k:
return False
elif self.user != other.user:
return False
return True
def __repr__(self):
return (
('AXIStreamFrame(data=%s, ' % repr(self.data)) +
('keep=%s, ' % repr(self.keep)) +
('id=%s, ' % repr(self.id)) +
('dest=%s, ' % repr(self.dest)) +
('user=%s, ' % repr(self.user)) +
('last_cycle_user=%s)' % repr(self.last_cycle_user))
)
def __iter__(self):
return self.data.__iter__()
class AXIStreamSource(object):
def __init__(self):
self.has_logic = False
self.queue = []
def send(self, frame):
self.queue.append(AXIStreamFrame(frame))
def write(self, data):
self.send(data)
def count(self):
return len(self.queue)
def empty(self):
return not self.queue
def create_logic(self,
clk,
rst,
tdata=None,
tkeep=Signal(bool(True)),
tvalid=Signal(bool(False)),
tready=Signal(bool(True)),
tlast=Signal(bool(False)),
tid=Signal(intbv(0)),
tdest=Signal(intbv(0)),
tuser=Signal(intbv(0)),
pause=0,
name=None
):
assert not self.has_logic
self.has_logic = True
tready_int = Signal(bool(False))
tvalid_int = Signal(bool(False))
@always_comb
def pause_logic():
tready_int.next = tready and not pause
tvalid.next = tvalid_int and not pause
@instance
def logic():
frame = AXIStreamFrame()
data = []
keep = []
id = []
dest = []
user = []
B = 0
N = len(tdata)
M = len(tkeep)
WL = int((len(tdata)+M-1)/M)
if type(tdata) is list or type(tdata) is tuple:
# multiple tdata signals
B = len(tdata)
N = [len(b) for b in tdata]
M = 1
WL = [1]*B
while True:
yield clk.posedge, rst.posedge
if rst:
if B > 0:
for s in tdata:
s.next = 0
else:
tdata.next = 0
tkeep.next = 0
tid.next = 0
tdest.next = 0
tuser.next = False
tvalid_int.next = False
tlast.next = False
else:
if tready_int and tvalid:
if len(data) > 0:
if B > 0:
l = data.pop(0)
for i in range(B):
tdata[i].next = l[i]
else:
tdata.next = data.pop(0)
tkeep.next = keep.pop(0)
tid.next = id.pop(0)
tdest.next = dest.pop(0)
tuser.next = user.pop(0)
tvalid_int.next = True
tlast.next = len(data) == 0
else:
tvalid_int.next = False
tlast.next = False
if (tlast and tready_int and tvalid) or not tvalid_int:
if self.queue:
frame = self.queue.pop(0)
frame.B = B
frame.N = N
frame.M = M
frame.WL = WL
data, keep, id, dest, user = frame.build()
if name is not None:
print("[%s] Sending frame %s" % (name, repr(frame)))
if B > 0:
l = data.pop(0)
for i in range(B):
tdata[i].next = l[i]
else:
tdata.next = data.pop(0)
tkeep.next = keep.pop(0)
tid.next = id.pop(0)
tdest.next = dest.pop(0)
tuser.next = user.pop(0)
tvalid_int.next = True
tlast.next = len(data) == 0
return instances()
class AXIStreamSink(object):
def __init__(self):
self.has_logic = False
self.queue = []
self.read_queue = []
self.sync = Signal(intbv(0))
def recv(self):
if self.queue:
return self.queue.pop(0)
return None
def read(self, count=-1):
while self.queue:
self.read_queue.extend(self.queue.pop(0).data)
if count < 0:
count = len(self.read_queue)
data = self.read_queue[:count]
del self.read_queue[:count]
return data
def count(self):
return len(self.queue)
def empty(self):
return not self.queue
def wait(self, timeout=0):
if self.queue:
return
if timeout:
yield self.sync, delay(timeout)
else:
yield self.sync
def create_logic(self,
clk,
rst,
tdata=None,
tkeep=Signal(bool(True)),
tvalid=Signal(bool(False)),
tready=Signal(bool(True)),
tlast=Signal(bool(True)),
tid=Signal(intbv(0)),
tdest=Signal(intbv(0)),
tuser=Signal(intbv(0)),
pause=0,
name=None
):
assert not self.has_logic
self.has_logic = True
tready_int = Signal(bool(False))
tvalid_int = Signal(bool(False))
@always_comb
def pause_logic():
tready.next = tready_int and not pause
tvalid_int.next = tvalid and not pause
@instance
def logic():
frame = AXIStreamFrame()
data = []
keep = []
id = []
dest = []
user = []
B = 0
N = len(tdata)
M = len(tkeep)
WL = int((len(tdata)+M-1)/M)
first = True
if type(tdata) is list or type(tdata) is tuple:
# multiple tdata signals
B = len(tdata)
N = [len(b) for b in tdata]
M = 1
WL = [1]*B
while True:
yield clk.posedge, rst.posedge
if rst:
tready_int.next = False
frame = AXIStreamFrame()
data = []
keep = []
id = []
dest = []
user = []
first = True
else:
tready_int.next = True
if tvalid_int:
if not skip_asserts:
# zero tkeep not allowed
assert int(tkeep) != 0
# tkeep must be contiguous
# i.e. 0b00011110 allowed, but 0b00011010 not allowed
b = int(tkeep)
while b & 1 == 0:
b = b >> 1
while b & 1 == 1:
b = b >> 1
assert b == 0
# tkeep must not have gaps across cycles
if not first:
# not first cycle; lowest bit must be set
assert int(tkeep) & 1
if not tlast:
# not last cycle; highest bit must be set
assert int(tkeep) & (1 << len(tkeep)-1)
if B > 0:
l = []
for i in range(B):
l.append(int(tdata[i]))
data.append(l)
else:
data.append(int(tdata))
keep.append(int(tkeep))
id.append(int(tid))
dest.append(int(tdest))
user.append(int(tuser))
first = False
if tlast:
frame.B = B
frame.N = N
frame.M = M
frame.WL = WL
frame.parse(data, keep, id, dest, user)
self.queue.append(frame)
self.sync.next = not self.sync
if name is not None:
print("[%s] Got frame %s" % (name, repr(frame)))
frame = AXIStreamFrame()
data = []
keep = []
id = []
dest = []
user = []
first = True
return instances()

4489
fpga/lib/pcie/tb/pcie.py Normal file

File diff suppressed because it is too large Load Diff

1629
fpga/lib/pcie/tb/pcie_us.py Normal file

File diff suppressed because it is too large Load Diff

260
fpga/lib/pcie/tb/test_pcie.py Executable file
View File

@ -0,0 +1,260 @@
#!/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, pcie.MSICapability):
def __init__(self, *args, **kwargs):
super(TestEP, self).__init__(*args, **kwargs)
self.vendor_id = 0x1234
self.device_id = 0x5678
self.msi_multiple_message_capable = 5
self.msi_64bit_address_capable = 1
self.msi_per_vector_mask_capable = 1
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 from rc.enumerate(enable_bus_mastering=True, configure_msi=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 from 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 from 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 from 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 from 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 from rc.mem_write(0x8000000000000000, bytearray(range(256))*32, 100)
# yield delay(1000)
# 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 from 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 from 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 from 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 from 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 from 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 from 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 from 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)
yield clk.posedge
print("test 7: MSI")
current_test.next = 7
yield from ep.issue_msi_interrupt(4)
yield rc.msi_get_signal(ep.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()

View File

@ -0,0 +1,209 @@
#!/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 os
import axis_ep
module = 'pcie_tag_manager'
testbench = 'test_%s' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("../rtl/priority_encoder.v")
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
PCIE_TAG_COUNT = 256
PCIE_TAG_WIDTH = (PCIE_TAG_COUNT-1).bit_length()
PCIE_EXT_TAG_ENABLE = 1
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
m_axis_tag_ready = Signal(bool(0))
s_axis_tag = Signal(intbv(0)[PCIE_TAG_WIDTH:])
s_axis_tag_valid = Signal(bool(0))
ext_tag_enable = Signal(bool(0))
# Outputs
m_axis_tag = Signal(intbv(0)[PCIE_TAG_WIDTH:])
m_axis_tag_valid = Signal(bool(0))
active_tags = Signal(intbv(0)[PCIE_TAG_COUNT:])
# sources and sinks
tag_sink_pause = Signal(bool(1))
tag_source = axis_ep.AXIStreamSource()
tag_source_logic = tag_source.create_logic(
clk,
rst,
tdata=s_axis_tag,
tvalid=s_axis_tag_valid,
name='tag_source'
)
tag_sink = axis_ep.AXIStreamSink()
tag_sink_logic = tag_sink.create_logic(
clk,
rst,
tdata=m_axis_tag,
tvalid=m_axis_tag_valid,
tready=m_axis_tag_ready,
pause=tag_sink_pause,
name='tag_sink'
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=clk,
rst=rst,
current_test=current_test,
m_axis_tag=m_axis_tag,
m_axis_tag_valid=m_axis_tag_valid,
m_axis_tag_ready=m_axis_tag_ready,
s_axis_tag=s_axis_tag,
s_axis_tag_valid=s_axis_tag_valid,
ext_tag_enable=ext_tag_enable,
active_tags=active_tags
)
@always(delay(4))
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
# testbench stimulus
ext_tag_enable.next = 0
yield clk.posedge
print("test 1: activate all tags")
current_test.next = 1
tag_sink_pause.next = 0
yield delay(300)
tag_sink_pause.next = 1
for k in range(32):
assert tag_sink.recv().data[0] == k
yield delay(100)
yield clk.posedge
print("test 2: return and reissue some tags")
current_test.next = 2
for k in [2, 4, 6, 8]:
tag_source.send([k])
tag_sink_pause.next = 0
yield delay(100)
tag_sink_pause.next = 1
for k in [2, 4, 6, 8]:
assert tag_sink.recv().data[0] == k
yield delay(100)
yield clk.posedge
print("test 3: activate all extended tags")
current_test.next = 3
rst.next = 1
ext_tag_enable.next = 1
yield clk.posedge
rst.next = 0
tag_sink_pause.next = 0
yield delay(2100)
tag_sink_pause.next = 1
for k in range(256):
assert tag_sink.recv().data[0] == k
yield delay(100)
yield clk.posedge
print("test 4: return and reissue some tags")
current_test.next = 4
for k in [10, 20, 30, 40, 50, 60]:
tag_source.send([k])
tag_sink_pause.next = 0
yield delay(100)
tag_sink_pause.next = 1
for k in [10, 20, 30, 40, 50, 60]:
assert tag_sink.recv().data[0] == k
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,93 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_tag_manager
*/
module test_pcie_tag_manager;
// Parameters
parameter PCIE_TAG_COUNT = 256;
parameter PCIE_TAG_WIDTH = $clog2(PCIE_TAG_COUNT);
parameter PCIE_EXT_TAG_ENABLE = 1;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg m_axis_tag_ready = 0;
reg [PCIE_TAG_WIDTH-1:0] s_axis_tag = 0;
reg s_axis_tag_valid = 0;
reg ext_tag_enable = 0;
// Outputs
wire [PCIE_TAG_WIDTH-1:0] m_axis_tag;
wire m_axis_tag_valid;
wire [PCIE_TAG_COUNT-1:0] active_tags;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
m_axis_tag_ready,
s_axis_tag,
s_axis_tag_valid,
ext_tag_enable
);
$to_myhdl(
m_axis_tag,
m_axis_tag_valid,
active_tags
);
// dump file
$dumpfile("test_pcie_tag_manager.lxt");
$dumpvars(0, test_pcie_tag_manager);
end
pcie_tag_manager #(
.PCIE_TAG_COUNT(PCIE_TAG_COUNT),
.PCIE_TAG_WIDTH(PCIE_TAG_WIDTH),
.PCIE_EXT_TAG_ENABLE(PCIE_EXT_TAG_ENABLE)
)
UUT (
.clk(clk),
.rst(rst),
.m_axis_tag(m_axis_tag),
.m_axis_tag_valid(m_axis_tag_valid),
.m_axis_tag_ready(m_axis_tag_ready),
.s_axis_tag(s_axis_tag),
.s_axis_tag_valid(s_axis_tag_valid),
.ext_tag_enable(ext_tag_enable),
.active_tags(active_tags)
);
endmodule

929
fpga/lib/pcie/tb/test_pcie_us.py Executable file
View File

@ -0,0 +1,929 @@
#!/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)[4:])
cfg_interrupt_msi_vf_enable=Signal(intbv(0)[8:])
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)[4:])
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)[4:])
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)[8:])
cfg_interrupt_msix_vf_mask=Signal(intbv(0)[8:])
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)[4:])
# 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].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_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_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_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_type == pcie.TLP_IO_READ):
print("IO read")
cpl = pcie_us.TLP_us()
cpl.set_completion(tlp, pcie_us.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_us.TLP_us()
cpl.set_completion(tlp, pcie_us.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_us.TLP_us()
cpl.set_completion(tlp, pcie_us.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_us.TLP_us()
tlp.fmt_type = pcie.TLP_IO_WRITE
tlp.requester_id = pcie_us.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_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_type = pcie.TLP_IO_READ
tlp.requester_id = pcie_us.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_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_type = pcie.TLP_MEM_WRITE_64
else:
tlp.fmt_type = pcie.TLP_MEM_WRITE
tlp.requester_id = pcie_us.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_us.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_us.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_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)
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()

View File

@ -0,0 +1,532 @@
#!/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 os
import pcie
import pcie_us
import axi
import axis_ep
module = 'pcie_us_axi_dma'
testbench = 'test_%s_256' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("../rtl/pcie_us_axi_dma_rd.v")
srcs.append("../rtl/pcie_us_axi_dma_wr.v")
srcs.append("../rtl/pcie_tag_manager.v")
srcs.append("../rtl/axis_arb_mux.v")
srcs.append("../rtl/arbiter.v")
srcs.append("../rtl/priority_encoder.v")
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 256
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
PCIE_ADDR_WIDTH = 64
PCIE_CLIENT_TAG = 1
PCIE_TAG_WIDTH = 8
PCIE_TAG_COUNT = 256
PCIE_EXT_TAG_ENABLE = 1
LEN_WIDTH = 20
TAG_WIDTH = 8
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_rc_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_rc_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_rc_tvalid = Signal(bool(0))
s_axis_rc_tlast = Signal(bool(0))
s_axis_rc_tuser = Signal(intbv(0)[75:])
m_axis_rq_tready = Signal(bool(0))
s_axis_pcie_rq_tag = Signal(intbv(0)[PCIE_TAG_WIDTH:])
s_axis_pcie_rq_tag_valid = Signal(bool(0))
s_axis_read_desc_pcie_addr = Signal(intbv(0)[PCIE_ADDR_WIDTH:])
s_axis_read_desc_axi_addr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
s_axis_read_desc_len = Signal(intbv(0)[LEN_WIDTH:])
s_axis_read_desc_tag = Signal(intbv(0)[TAG_WIDTH:])
s_axis_read_desc_valid = Signal(bool(0))
s_axis_write_desc_pcie_addr = Signal(intbv(0)[PCIE_ADDR_WIDTH:])
s_axis_write_desc_axi_addr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
s_axis_write_desc_len = Signal(intbv(0)[LEN_WIDTH:])
s_axis_write_desc_tag = Signal(intbv(0)[TAG_WIDTH:])
s_axis_write_desc_valid = Signal(bool(0))
m_axi_awready = Signal(bool(0))
m_axi_wready = Signal(bool(0))
m_axi_bid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_bresp = Signal(intbv(0)[2:])
m_axi_bvalid = Signal(bool(0))
m_axi_arready = Signal(bool(0))
m_axi_rid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_rdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_rresp = Signal(intbv(0)[2:])
m_axi_rlast = Signal(bool(0))
m_axi_rvalid = Signal(bool(0))
read_enable = Signal(bool(0))
write_enable = Signal(bool(0))
ext_tag_enable = Signal(bool(0))
requester_id = Signal(intbv(0)[16:])
requester_id_enable = Signal(bool(0))
max_read_request_size = Signal(intbv(0)[3:])
max_payload_size = Signal(intbv(0)[3:])
# Outputs
s_axis_rc_tready = Signal(bool(0))
m_axis_rq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_rq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_rq_tvalid = Signal(bool(0))
m_axis_rq_tlast = Signal(bool(0))
m_axis_rq_tuser = Signal(intbv(0)[60:])
s_axis_read_desc_ready = Signal(bool(0))
m_axis_read_desc_status_tag = Signal(intbv(0)[TAG_WIDTH:])
m_axis_read_desc_status_valid = Signal(bool(0))
s_axis_write_desc_ready = Signal(bool(0))
m_axis_write_desc_status_tag = Signal(intbv(0)[TAG_WIDTH:])
m_axis_write_desc_status_valid = Signal(bool(0))
m_axi_awid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_awaddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_awlen = Signal(intbv(0)[8:])
m_axi_awsize = Signal(intbv(5)[3:])
m_axi_awburst = Signal(intbv(1)[2:])
m_axi_awlock = Signal(bool(0))
m_axi_awcache = Signal(intbv(3)[4:])
m_axi_awprot = Signal(intbv(2)[3:])
m_axi_awvalid = Signal(bool(0))
m_axi_wdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_wstrb = Signal(intbv(0)[AXI_STRB_WIDTH:])
m_axi_wlast = Signal(bool(0))
m_axi_wvalid = Signal(bool(0))
m_axi_bready = Signal(bool(0))
m_axi_arid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_araddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_arlen = Signal(intbv(0)[8:])
m_axi_arsize = Signal(intbv(5)[3:])
m_axi_arburst = Signal(intbv(1)[2:])
m_axi_arlock = Signal(bool(0))
m_axi_arcache = Signal(intbv(3)[4:])
m_axi_arprot = Signal(intbv(2)[3:])
m_axi_arvalid = Signal(bool(0))
m_axi_rready = Signal(bool(0))
status_error_cor = Signal(bool(0))
status_error_uncor = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_awid=m_axi_awid,
s_axi_awaddr=m_axi_awaddr,
s_axi_awlen=m_axi_awlen,
s_axi_awsize=m_axi_awsize,
s_axi_awburst=m_axi_awburst,
s_axi_awlock=m_axi_awlock,
s_axi_awcache=m_axi_awcache,
s_axi_awprot=m_axi_awprot,
s_axi_awvalid=m_axi_awvalid,
s_axi_awready=m_axi_awready,
s_axi_wdata=m_axi_wdata,
s_axi_wstrb=m_axi_wstrb,
s_axi_wlast=m_axi_wlast,
s_axi_wvalid=m_axi_wvalid,
s_axi_wready=m_axi_wready,
s_axi_bid=m_axi_bid,
s_axi_bresp=m_axi_bresp,
s_axi_bvalid=m_axi_bvalid,
s_axi_bready=m_axi_bready,
s_axi_arid=m_axi_arid,
s_axi_araddr=m_axi_araddr,
s_axi_arlen=m_axi_arlen,
s_axi_arsize=m_axi_arsize,
s_axi_arburst=m_axi_arburst,
s_axi_arlock=m_axi_arlock,
s_axi_arcache=m_axi_arcache,
s_axi_arprot=m_axi_arprot,
s_axi_arvalid=m_axi_arvalid,
s_axi_arready=m_axi_arready,
s_axi_rid=m_axi_rid,
s_axi_rdata=m_axi_rdata,
s_axi_rresp=m_axi_rresp,
s_axi_rlast=m_axi_rlast,
s_axi_rvalid=m_axi_rvalid,
s_axi_rready=m_axi_rready,
name='port0'
)
# sources and sinks
read_desc_source = axis_ep.AXIStreamSource()
read_desc_source_logic = read_desc_source.create_logic(
user_clk,
user_reset,
tdata=(s_axis_read_desc_pcie_addr, s_axis_read_desc_axi_addr, s_axis_read_desc_len, s_axis_read_desc_tag),
tvalid=s_axis_read_desc_valid,
tready=s_axis_read_desc_ready,
name='read_desc_source'
)
read_desc_status_sink = axis_ep.AXIStreamSink()
read_desc_status_sink_logic = read_desc_status_sink.create_logic(
user_clk,
user_reset,
tdata=(m_axis_read_desc_status_tag,),
tvalid=m_axis_read_desc_status_valid,
name='read_desc_status_sink'
)
write_desc_source = axis_ep.AXIStreamSource()
write_desc_source_logic = write_desc_source.create_logic(
user_clk,
user_reset,
tdata=(s_axis_write_desc_pcie_addr, s_axis_write_desc_axi_addr, s_axis_write_desc_len, s_axis_write_desc_tag),
tvalid=s_axis_write_desc_valid,
tready=s_axis_write_desc_ready,
name='write_desc_source'
)
write_desc_status_sink = axis_ep.AXIStreamSink()
write_desc_status_sink_logic = write_desc_status_sink.create_logic(
user_clk,
user_reset,
tdata=(m_axis_write_desc_status_tag,),
tvalid=m_axis_write_desc_status_valid,
name='write_desc_status_sink'
)
# PCIe devices
rc = pcie.RootComplex()
mem_base, mem_data = rc.alloc_region(16*1024*1024)
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 8
dev.user_clock_frequency = 256e6
rc.make_port().connect(dev)
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_cq_tuser=Signal(intbv(0)[85:]),
m_axis_cq_tlast=Signal(bool(0)),
m_axis_cq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_cq_tvalid=Signal(bool(0)),
m_axis_cq_tready=Signal(bool(1)),
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)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_cc_tuser=Signal(intbv(0)[33:]),
s_axis_cc_tlast=Signal(bool(0)),
s_axis_cc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_cc_tvalid=Signal(bool(0)),
s_axis_cc_tready=Signal(bool(0)),
# Requester reQuest Interface
s_axis_rq_tdata=m_axis_rq_tdata,
s_axis_rq_tuser=m_axis_rq_tuser,
s_axis_rq_tlast=m_axis_rq_tlast,
s_axis_rq_tkeep=m_axis_rq_tkeep,
s_axis_rq_tvalid=m_axis_rq_tvalid,
s_axis_rq_tready=m_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=s_axis_rc_tdata,
m_axis_rc_tuser=s_axis_rc_tuser,
m_axis_rc_tlast=s_axis_rc_tlast,
m_axis_rc_tkeep=s_axis_rc_tkeep,
m_axis_rc_tvalid=s_axis_rc_tvalid,
m_axis_rc_tready=s_axis_rc_tready,
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
s_axis_rc_tdata=s_axis_rc_tdata,
s_axis_rc_tkeep=s_axis_rc_tkeep,
s_axis_rc_tvalid=s_axis_rc_tvalid,
s_axis_rc_tready=s_axis_rc_tready,
s_axis_rc_tlast=s_axis_rc_tlast,
s_axis_rc_tuser=s_axis_rc_tuser,
m_axis_rq_tdata=m_axis_rq_tdata,
m_axis_rq_tkeep=m_axis_rq_tkeep,
m_axis_rq_tvalid=m_axis_rq_tvalid,
m_axis_rq_tready=m_axis_rq_tready,
m_axis_rq_tlast=m_axis_rq_tlast,
m_axis_rq_tuser=m_axis_rq_tuser,
s_axis_pcie_rq_tag=s_axis_pcie_rq_tag,
s_axis_pcie_rq_tag_valid=s_axis_pcie_rq_tag_valid,
s_axis_read_desc_pcie_addr=s_axis_read_desc_pcie_addr,
s_axis_read_desc_axi_addr=s_axis_read_desc_axi_addr,
s_axis_read_desc_len=s_axis_read_desc_len,
s_axis_read_desc_tag=s_axis_read_desc_tag,
s_axis_read_desc_valid=s_axis_read_desc_valid,
s_axis_read_desc_ready=s_axis_read_desc_ready,
m_axis_read_desc_status_tag=m_axis_read_desc_status_tag,
m_axis_read_desc_status_valid=m_axis_read_desc_status_valid,
s_axis_write_desc_pcie_addr=s_axis_write_desc_pcie_addr,
s_axis_write_desc_axi_addr=s_axis_write_desc_axi_addr,
s_axis_write_desc_len=s_axis_write_desc_len,
s_axis_write_desc_tag=s_axis_write_desc_tag,
s_axis_write_desc_valid=s_axis_write_desc_valid,
s_axis_write_desc_ready=s_axis_write_desc_ready,
m_axis_write_desc_status_tag=m_axis_write_desc_status_tag,
m_axis_write_desc_status_valid=m_axis_write_desc_status_valid,
m_axi_awid=m_axi_awid,
m_axi_awaddr=m_axi_awaddr,
m_axi_awlen=m_axi_awlen,
m_axi_awsize=m_axi_awsize,
m_axi_awburst=m_axi_awburst,
m_axi_awlock=m_axi_awlock,
m_axi_awcache=m_axi_awcache,
m_axi_awprot=m_axi_awprot,
m_axi_awvalid=m_axi_awvalid,
m_axi_awready=m_axi_awready,
m_axi_wdata=m_axi_wdata,
m_axi_wstrb=m_axi_wstrb,
m_axi_wlast=m_axi_wlast,
m_axi_wvalid=m_axi_wvalid,
m_axi_wready=m_axi_wready,
m_axi_bid=m_axi_bid,
m_axi_bresp=m_axi_bresp,
m_axi_bvalid=m_axi_bvalid,
m_axi_bready=m_axi_bready,
m_axi_arid=m_axi_arid,
m_axi_araddr=m_axi_araddr,
m_axi_arlen=m_axi_arlen,
m_axi_arsize=m_axi_arsize,
m_axi_arburst=m_axi_arburst,
m_axi_arlock=m_axi_arlock,
m_axi_arcache=m_axi_arcache,
m_axi_arprot=m_axi_arprot,
m_axi_arvalid=m_axi_arvalid,
m_axi_arready=m_axi_arready,
m_axi_rid=m_axi_rid,
m_axi_rdata=m_axi_rdata,
m_axi_rresp=m_axi_rresp,
m_axi_rlast=m_axi_rlast,
m_axi_rvalid=m_axi_rvalid,
m_axi_rready=m_axi_rready,
read_enable=read_enable,
write_enable=write_enable,
ext_tag_enable=ext_tag_enable,
requester_id=requester_id,
requester_id_enable=requester_id_enable,
max_read_request_size=max_read_request_size,
max_payload_size=max_payload_size,
status_error_cor=status_error_cor,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
@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
# testbench stimulus
cur_tag = 1
max_payload_size.next = 0
max_read_request_size.next = 2
read_enable.next = 1
write_enable.next = 1
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate(enable_bus_mastering=True)
yield delay(100)
yield user_clk.posedge
print("test 2: PCIe write")
current_test.next = 2
pcie_addr = 0x00000000
axi_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
axi_ram_inst.write_mem(axi_addr, test_data)
data = axi_ram_inst.read_mem(axi_addr, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
write_desc_source.send([(mem_base+pcie_addr, axi_addr, len(test_data), cur_tag)])
yield write_desc_status_sink.wait(1000)
yield delay(50)
status = write_desc_status_sink.recv()
print(status)
assert status.data[0][0] == cur_tag
data = mem_data[pcie_addr:pcie_addr+32]
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert mem_data[pcie_addr:pcie_addr+len(test_data)] == test_data
cur_tag = (cur_tag + 1) % 256
yield delay(100)
yield user_clk.posedge
print("test 3: PCIe read")
current_test.next = 3
pcie_addr = 0x00000000
axi_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
mem_data[pcie_addr:pcie_addr+len(test_data)] = test_data
data = mem_data[pcie_addr:pcie_addr+32]
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
read_desc_source.send([(pcie_addr, axi_addr, len(test_data), cur_tag)])
yield read_desc_status_sink.wait(2000)
status = read_desc_status_sink.recv()
print(status)
data = axi_ram_inst.read_mem(axi_addr, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(axi_addr, len(test_data)) == test_data
cur_tag = (cur_tag + 1) % 256
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,316 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_dma
*/
module test_pcie_us_axi_dma_256;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 256;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
parameter PCIE_ADDR_WIDTH = 64;
parameter PCIE_CLIENT_TAG = 1;
parameter PCIE_TAG_WIDTH = 8;
parameter PCIE_TAG_COUNT = 256;
parameter PCIE_EXT_TAG_ENABLE = 1;
parameter LEN_WIDTH = 20;
parameter TAG_WIDTH = 8;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_rc_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_rc_tkeep = 0;
reg s_axis_rc_tvalid = 0;
reg s_axis_rc_tlast = 0;
reg [74:0] s_axis_rc_tuser = 0;
reg m_axis_rq_tready = 0;
reg [PCIE_TAG_WIDTH-1:0] s_axis_pcie_rq_tag = 0;
reg s_axis_pcie_rq_tag_valid = 0;
reg [PCIE_ADDR_WIDTH-1:0] s_axis_read_desc_pcie_addr = 0;
reg [AXI_ADDR_WIDTH-1:0] s_axis_read_desc_axi_addr = 0;
reg [LEN_WIDTH-1:0] s_axis_read_desc_len = 0;
reg [TAG_WIDTH-1:0] s_axis_read_desc_tag = 0;
reg s_axis_read_desc_valid = 0;
reg [PCIE_ADDR_WIDTH-1:0] s_axis_write_desc_pcie_addr = 0;
reg [AXI_ADDR_WIDTH-1:0] s_axis_write_desc_axi_addr = 0;
reg [LEN_WIDTH-1:0] s_axis_write_desc_len = 0;
reg [TAG_WIDTH-1:0] s_axis_write_desc_tag = 0;
reg s_axis_write_desc_valid = 0;
reg m_axi_awready = 0;
reg m_axi_wready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_bid = 0;
reg [1:0] m_axi_bresp = 0;
reg m_axi_bvalid = 0;
reg m_axi_arready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_rid = 0;
reg [AXI_DATA_WIDTH-1:0] m_axi_rdata = 0;
reg [1:0] m_axi_rresp = 0;
reg m_axi_rlast = 0;
reg m_axi_rvalid = 0;
reg read_enable = 0;
reg write_enable = 0;
reg ext_tag_enable = 0;
reg [15:0] requester_id = 0;
reg requester_id_enable = 0;
reg [2:0] max_read_request_size = 0;
reg [2:0] max_payload_size = 0;
// Outputs
wire s_axis_rc_tready;
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rq_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rq_tkeep;
wire m_axis_rq_tvalid;
wire m_axis_rq_tlast;
wire [59:0] m_axis_rq_tuser;
wire s_axis_read_desc_ready;
wire [TAG_WIDTH-1:0] m_axis_read_desc_status_tag;
wire m_axis_read_desc_status_valid;
wire s_axis_write_desc_ready;
wire [TAG_WIDTH-1:0] m_axis_write_desc_status_tag;
wire m_axis_write_desc_status_valid;
wire [AXI_ID_WIDTH-1:0] m_axi_awid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr;
wire [7:0] m_axi_awlen;
wire [2:0] m_axi_awsize;
wire [1:0] m_axi_awburst;
wire m_axi_awlock;
wire [3:0] m_axi_awcache;
wire [2:0] m_axi_awprot;
wire m_axi_awvalid;
wire [AXI_DATA_WIDTH-1:0] m_axi_wdata;
wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb;
wire m_axi_wlast;
wire m_axi_wvalid;
wire m_axi_bready;
wire [AXI_ID_WIDTH-1:0] m_axi_arid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr;
wire [7:0] m_axi_arlen;
wire [2:0] m_axi_arsize;
wire [1:0] m_axi_arburst;
wire m_axi_arlock;
wire [3:0] m_axi_arcache;
wire [2:0] m_axi_arprot;
wire m_axi_arvalid;
wire m_axi_rready;
wire status_error_cor;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_rc_tdata,
s_axis_rc_tkeep,
s_axis_rc_tvalid,
s_axis_rc_tlast,
s_axis_rc_tuser,
m_axis_rq_tready,
s_axis_pcie_rq_tag,
s_axis_pcie_rq_tag_valid,
s_axis_read_desc_pcie_addr,
s_axis_read_desc_axi_addr,
s_axis_read_desc_len,
s_axis_read_desc_tag,
s_axis_read_desc_valid,
s_axis_write_desc_pcie_addr,
s_axis_write_desc_axi_addr,
s_axis_write_desc_len,
s_axis_write_desc_tag,
s_axis_write_desc_valid,
m_axi_awready,
m_axi_wready,
m_axi_bid,
m_axi_bresp,
m_axi_bvalid,
m_axi_arready,
m_axi_rid,
m_axi_rdata,
m_axi_rresp,
m_axi_rlast,
m_axi_rvalid,
read_enable,
write_enable,
ext_tag_enable,
requester_id,
requester_id_enable,
max_read_request_size,
max_payload_size
);
$to_myhdl(
s_axis_rc_tready,
m_axis_rq_tdata,
m_axis_rq_tkeep,
m_axis_rq_tvalid,
m_axis_rq_tlast,
m_axis_rq_tuser,
s_axis_read_desc_ready,
m_axis_read_desc_status_tag,
m_axis_read_desc_status_valid,
s_axis_write_desc_ready,
m_axis_write_desc_status_tag,
m_axis_write_desc_status_valid,
m_axi_awid,
m_axi_awaddr,
m_axi_awlen,
m_axi_awsize,
m_axi_awburst,
m_axi_awlock,
m_axi_awcache,
m_axi_awprot,
m_axi_awvalid,
m_axi_wdata,
m_axi_wstrb,
m_axi_wlast,
m_axi_wvalid,
m_axi_bready,
m_axi_arid,
m_axi_araddr,
m_axi_arlen,
m_axi_arsize,
m_axi_arburst,
m_axi_arlock,
m_axi_arcache,
m_axi_arprot,
m_axi_arvalid,
m_axi_rready,
status_error_cor,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axi_dma_256.lxt");
$dumpvars(0, test_pcie_us_axi_dma_256);
end
pcie_us_axi_dma #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
.PCIE_ADDR_WIDTH(PCIE_ADDR_WIDTH),
.PCIE_CLIENT_TAG(PCIE_CLIENT_TAG),
.PCIE_TAG_WIDTH(PCIE_TAG_WIDTH),
.PCIE_TAG_COUNT(PCIE_TAG_COUNT),
.PCIE_EXT_TAG_ENABLE(PCIE_EXT_TAG_ENABLE),
.LEN_WIDTH(LEN_WIDTH),
.TAG_WIDTH(TAG_WIDTH)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_rc_tdata(s_axis_rc_tdata),
.s_axis_rc_tkeep(s_axis_rc_tkeep),
.s_axis_rc_tvalid(s_axis_rc_tvalid),
.s_axis_rc_tready(s_axis_rc_tready),
.s_axis_rc_tlast(s_axis_rc_tlast),
.s_axis_rc_tuser(s_axis_rc_tuser),
.m_axis_rq_tdata(m_axis_rq_tdata),
.m_axis_rq_tkeep(m_axis_rq_tkeep),
.m_axis_rq_tvalid(m_axis_rq_tvalid),
.m_axis_rq_tready(m_axis_rq_tready),
.m_axis_rq_tlast(m_axis_rq_tlast),
.m_axis_rq_tuser(m_axis_rq_tuser),
.s_axis_pcie_rq_tag(s_axis_pcie_rq_tag),
.s_axis_pcie_rq_tag_valid(s_axis_pcie_rq_tag_valid),
.s_axis_read_desc_pcie_addr(s_axis_read_desc_pcie_addr),
.s_axis_read_desc_axi_addr(s_axis_read_desc_axi_addr),
.s_axis_read_desc_len(s_axis_read_desc_len),
.s_axis_read_desc_tag(s_axis_read_desc_tag),
.s_axis_read_desc_valid(s_axis_read_desc_valid),
.s_axis_read_desc_ready(s_axis_read_desc_ready),
.m_axis_read_desc_status_tag(m_axis_read_desc_status_tag),
.m_axis_read_desc_status_valid(m_axis_read_desc_status_valid),
.s_axis_write_desc_pcie_addr(s_axis_write_desc_pcie_addr),
.s_axis_write_desc_axi_addr(s_axis_write_desc_axi_addr),
.s_axis_write_desc_len(s_axis_write_desc_len),
.s_axis_write_desc_tag(s_axis_write_desc_tag),
.s_axis_write_desc_valid(s_axis_write_desc_valid),
.s_axis_write_desc_ready(s_axis_write_desc_ready),
.m_axis_write_desc_status_tag(m_axis_write_desc_status_tag),
.m_axis_write_desc_status_valid(m_axis_write_desc_status_valid),
.m_axi_awid(m_axi_awid),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awlen(m_axi_awlen),
.m_axi_awsize(m_axi_awsize),
.m_axi_awburst(m_axi_awburst),
.m_axi_awlock(m_axi_awlock),
.m_axi_awcache(m_axi_awcache),
.m_axi_awprot(m_axi_awprot),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wstrb(m_axi_wstrb),
.m_axi_wlast(m_axi_wlast),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
.m_axi_arid(m_axi_arid),
.m_axi_araddr(m_axi_araddr),
.m_axi_arlen(m_axi_arlen),
.m_axi_arsize(m_axi_arsize),
.m_axi_arburst(m_axi_arburst),
.m_axi_arlock(m_axi_arlock),
.m_axi_arcache(m_axi_arcache),
.m_axi_arprot(m_axi_arprot),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rid(m_axi_rid),
.m_axi_rdata(m_axi_rdata),
.m_axi_rresp(m_axi_rresp),
.m_axi_rlast(m_axi_rlast),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready),
.read_enable(read_enable),
.write_enable(write_enable),
.ext_tag_enable(ext_tag_enable),
.requester_id(requester_id),
.requester_id_enable(requester_id_enable),
.max_read_request_size(max_read_request_size),
.max_payload_size(max_payload_size),
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
endmodule

View File

@ -0,0 +1,496 @@
#!/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 os
import struct
import pcie
import pcie_us
import axi
import axis_ep
module = 'pcie_us_axi_dma_rd'
testbench = 'test_%s_128' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("../rtl/pcie_tag_manager.v")
srcs.append("../rtl/priority_encoder.v")
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 128
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
PCIE_ADDR_WIDTH = 64
PCIE_CLIENT_TAG = 1
PCIE_TAG_WIDTH = 8
PCIE_TAG_COUNT = 256
PCIE_EXT_TAG_ENABLE = 1
LEN_WIDTH = 20
TAG_WIDTH = 8
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_rc_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_rc_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_rc_tvalid = Signal(bool(0))
s_axis_rc_tlast = Signal(bool(0))
s_axis_rc_tuser = Signal(intbv(0)[75:])
m_axis_rq_tready = Signal(bool(0))
s_axis_pcie_rq_tag = Signal(intbv(0)[PCIE_TAG_WIDTH:])
s_axis_pcie_rq_tag_valid = Signal(bool(0))
s_axis_read_desc_pcie_addr = Signal(intbv(0)[PCIE_ADDR_WIDTH:])
s_axis_read_desc_axi_addr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
s_axis_read_desc_len = Signal(intbv(0)[LEN_WIDTH:])
s_axis_read_desc_tag = Signal(intbv(0)[TAG_WIDTH:])
s_axis_read_desc_valid = Signal(bool(0))
m_axi_awready = Signal(bool(0))
m_axi_wready = Signal(bool(0))
m_axi_bid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_bresp = Signal(intbv(0)[2:])
m_axi_bvalid = Signal(bool(0))
enable = Signal(bool(0))
ext_tag_enable = Signal(bool(0))
requester_id = Signal(intbv(0)[16:])
requester_id_enable = Signal(bool(0))
max_read_request_size = Signal(intbv(0)[3:])
# Outputs
s_axis_rc_tready = Signal(bool(0))
m_axis_rq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_rq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_rq_tvalid = Signal(bool(0))
m_axis_rq_tlast = Signal(bool(0))
m_axis_rq_tuser = Signal(intbv(0)[60:])
s_axis_read_desc_ready = Signal(bool(0))
m_axis_read_desc_status_tag = Signal(intbv(0)[TAG_WIDTH:])
m_axis_read_desc_status_valid = Signal(bool(0))
m_axi_awid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_awaddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_awlen = Signal(intbv(0)[8:])
m_axi_awsize = Signal(intbv(4)[3:])
m_axi_awburst = Signal(intbv(1)[2:])
m_axi_awlock = Signal(bool(0))
m_axi_awcache = Signal(intbv(3)[4:])
m_axi_awprot = Signal(intbv(2)[3:])
m_axi_awvalid = Signal(bool(0))
m_axi_wdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_wstrb = Signal(intbv(0)[AXI_STRB_WIDTH:])
m_axi_wlast = Signal(bool(0))
m_axi_wvalid = Signal(bool(0))
m_axi_bready = Signal(bool(0))
status_error_cor = Signal(bool(0))
status_error_uncor = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_awid=m_axi_awid,
s_axi_awaddr=m_axi_awaddr,
s_axi_awlen=m_axi_awlen,
s_axi_awsize=m_axi_awsize,
s_axi_awburst=m_axi_awburst,
s_axi_awlock=m_axi_awlock,
s_axi_awcache=m_axi_awcache,
s_axi_awprot=m_axi_awprot,
s_axi_awvalid=m_axi_awvalid,
s_axi_awready=m_axi_awready,
s_axi_wdata=m_axi_wdata,
s_axi_wstrb=m_axi_wstrb,
s_axi_wlast=m_axi_wlast,
s_axi_wvalid=m_axi_wvalid,
s_axi_wready=m_axi_wready,
s_axi_bid=m_axi_bid,
s_axi_bresp=m_axi_bresp,
s_axi_bvalid=m_axi_bvalid,
s_axi_bready=m_axi_bready,
name='port0'
)
# sources and sinks
read_desc_source = axis_ep.AXIStreamSource()
read_desc_source_logic = read_desc_source.create_logic(
user_clk,
user_reset,
tdata=(s_axis_read_desc_pcie_addr, s_axis_read_desc_axi_addr, s_axis_read_desc_len, s_axis_read_desc_tag),
tvalid=s_axis_read_desc_valid,
tready=s_axis_read_desc_ready,
name='read_desc_source'
)
read_desc_status_sink = axis_ep.AXIStreamSink()
read_desc_status_sink_logic = read_desc_status_sink.create_logic(
user_clk,
user_reset,
tdata=(m_axis_read_desc_status_tag,),
tvalid=m_axis_read_desc_status_valid,
name='read_desc_status_sink'
)
# PCIe devices
rc = pcie.RootComplex()
mem_base, mem_data = rc.alloc_region(16*1024*1024)
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 4
dev.user_clock_frequency = 256e6
rc.make_port().connect(dev)
cq_pause = Signal(bool(0))
cc_pause = Signal(bool(0))
rq_pause = Signal(bool(0))
rc_pause = Signal(bool(0))
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_cq_tuser=Signal(intbv(0)[85:]),
m_axis_cq_tlast=Signal(bool(0)),
m_axis_cq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_cq_tvalid=Signal(bool(0)),
m_axis_cq_tready=Signal(bool(1)),
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)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_cc_tuser=Signal(intbv(0)[33:]),
s_axis_cc_tlast=Signal(bool(0)),
s_axis_cc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_cc_tvalid=Signal(bool(0)),
s_axis_cc_tready=Signal(bool(0)),
# Requester reQuest Interface
s_axis_rq_tdata=m_axis_rq_tdata,
s_axis_rq_tuser=m_axis_rq_tuser,
s_axis_rq_tlast=m_axis_rq_tlast,
s_axis_rq_tkeep=m_axis_rq_tkeep,
s_axis_rq_tvalid=m_axis_rq_tvalid,
s_axis_rq_tready=m_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=s_axis_rc_tdata,
m_axis_rc_tuser=s_axis_rc_tuser,
m_axis_rc_tlast=s_axis_rc_tlast,
m_axis_rc_tkeep=s_axis_rc_tkeep,
m_axis_rc_tvalid=s_axis_rc_tvalid,
m_axis_rc_tready=s_axis_rc_tready,
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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,
cq_pause=cq_pause,
cc_pause=cc_pause,
rq_pause=rq_pause,
rc_pause=rc_pause
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
s_axis_rc_tdata=s_axis_rc_tdata,
s_axis_rc_tkeep=s_axis_rc_tkeep,
s_axis_rc_tvalid=s_axis_rc_tvalid,
s_axis_rc_tready=s_axis_rc_tready,
s_axis_rc_tlast=s_axis_rc_tlast,
s_axis_rc_tuser=s_axis_rc_tuser,
m_axis_rq_tdata=m_axis_rq_tdata,
m_axis_rq_tkeep=m_axis_rq_tkeep,
m_axis_rq_tvalid=m_axis_rq_tvalid,
m_axis_rq_tready=m_axis_rq_tready,
m_axis_rq_tlast=m_axis_rq_tlast,
m_axis_rq_tuser=m_axis_rq_tuser,
s_axis_pcie_rq_tag=s_axis_pcie_rq_tag,
s_axis_pcie_rq_tag_valid=s_axis_pcie_rq_tag_valid,
s_axis_read_desc_pcie_addr=s_axis_read_desc_pcie_addr,
s_axis_read_desc_axi_addr=s_axis_read_desc_axi_addr,
s_axis_read_desc_len=s_axis_read_desc_len,
s_axis_read_desc_tag=s_axis_read_desc_tag,
s_axis_read_desc_valid=s_axis_read_desc_valid,
s_axis_read_desc_ready=s_axis_read_desc_ready,
m_axis_read_desc_status_tag=m_axis_read_desc_status_tag,
m_axis_read_desc_status_valid=m_axis_read_desc_status_valid,
m_axi_awid=m_axi_awid,
m_axi_awaddr=m_axi_awaddr,
m_axi_awlen=m_axi_awlen,
m_axi_awsize=m_axi_awsize,
m_axi_awburst=m_axi_awburst,
m_axi_awlock=m_axi_awlock,
m_axi_awcache=m_axi_awcache,
m_axi_awprot=m_axi_awprot,
m_axi_awvalid=m_axi_awvalid,
m_axi_awready=m_axi_awready,
m_axi_wdata=m_axi_wdata,
m_axi_wstrb=m_axi_wstrb,
m_axi_wlast=m_axi_wlast,
m_axi_wvalid=m_axi_wvalid,
m_axi_wready=m_axi_wready,
m_axi_bid=m_axi_bid,
m_axi_bresp=m_axi_bresp,
m_axi_bvalid=m_axi_bvalid,
m_axi_bready=m_axi_bready,
enable=enable,
ext_tag_enable=ext_tag_enable,
requester_id=requester_id,
requester_id_enable=requester_id_enable,
max_read_request_size=max_read_request_size,
status_error_cor=status_error_cor,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
status_error_cor_asserted = Signal(bool(0))
status_error_uncor_asserted = Signal(bool(0))
@always(clk.posedge)
def monitor():
if (status_error_cor):
status_error_cor_asserted.next = 1
if (status_error_uncor):
status_error_uncor_asserted.next = 1
cq_pause_toggle = Signal(bool(0))
cc_pause_toggle = Signal(bool(0))
rq_pause_toggle = Signal(bool(0))
rc_pause_toggle = Signal(bool(0))
@instance
def pause_toggle():
while True:
if (cq_pause_toggle or cc_pause_toggle or rq_pause_toggle or rc_pause_toggle):
cq_pause.next = cq_pause_toggle
cc_pause.next = cc_pause_toggle
rq_pause.next = rq_pause_toggle
rc_pause.next = rc_pause_toggle
yield user_clk.posedge
yield user_clk.posedge
yield user_clk.posedge
cq_pause.next = 0
cc_pause.next = 0
rq_pause.next = 0
rc_pause.next = 0
yield user_clk.posedge
@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
# testbench stimulus
cur_tag = 1
max_read_request_size.next = 2
enable.next = 1
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate(enable_bus_mastering=True)
yield delay(100)
yield user_clk.posedge
print("test 2: PCIe read")
current_test.next = 2
pcie_addr = 0x00000000
axi_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
mem_data[pcie_addr:pcie_addr+len(test_data)] = test_data
data = mem_data[pcie_addr:pcie_addr+32]
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
read_desc_source.send([(pcie_addr, axi_addr, len(test_data), cur_tag)])
yield read_desc_status_sink.wait(2000)
yield delay(50)
status = read_desc_status_sink.recv()
print(status)
data = axi_ram_inst.read_mem(axi_addr, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(axi_addr, len(test_data)) == test_data
cur_tag = (cur_tag + 1) % 256
yield delay(100)
yield user_clk.posedge
print("test 3: various reads")
current_test.next = 3
for length in list(range(1,19))+list(range(128-4,128+4))+[1024]:
for pcie_offset in list(range(8,13))+list(range(4096-4,4096+4)):
for axi_offset in list(range(8,25))+list(range(4096-16,4096)):
for pause in [False, True]:
print("length %d, pcie_offset %d, axi_offset %d"% (length, pcie_offset, axi_offset))
#pcie_addr = length * 0x100000000 + pcie_offset * 0x10000 + offset
pcie_addr = pcie_offset
axi_addr = axi_offset
test_data = bytearray([x%256 for x in range(length)])
mem_data[pcie_addr:pcie_addr+len(test_data)] = test_data
data = mem_data[pcie_addr&0xffff80:(pcie_addr&0xffff80)+64]
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
axi_ram_inst.write_mem(axi_addr & 0xffff80, b'\xaa'*(len(test_data)+256))
rq_pause_toggle.next = pause
rc_pause_toggle.next = pause
read_desc_source.send([(pcie_addr, axi_addr, len(test_data), cur_tag)])
yield read_desc_status_sink.wait(2000)
rq_pause_toggle.next = 0
rc_pause_toggle.next = 0
status = read_desc_status_sink.recv()
print(status)
data = axi_ram_inst.read_mem(axi_addr&0xfffff0, 64)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(axi_addr-8, len(test_data)+16) == b'\xaa'*8+test_data+b'\xaa'*8
cur_tag = (cur_tag + 1) % 256
yield delay(50)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,238 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_dma_rd
*/
module test_pcie_us_axi_dma_rd_128;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 128;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
parameter PCIE_ADDR_WIDTH = 64;
parameter PCIE_CLIENT_TAG = 1;
parameter PCIE_TAG_WIDTH = 8;
parameter PCIE_TAG_COUNT = 256;
parameter PCIE_EXT_TAG_ENABLE = 1;
parameter LEN_WIDTH = 20;
parameter TAG_WIDTH = 8;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_rc_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_rc_tkeep = 0;
reg s_axis_rc_tvalid = 0;
reg s_axis_rc_tlast = 0;
reg [74:0] s_axis_rc_tuser = 0;
reg m_axis_rq_tready = 0;
reg [PCIE_TAG_WIDTH-1:0] s_axis_pcie_rq_tag = 0;
reg s_axis_pcie_rq_tag_valid = 0;
reg [PCIE_ADDR_WIDTH-1:0] s_axis_read_desc_pcie_addr = 0;
reg [AXI_ADDR_WIDTH-1:0] s_axis_read_desc_axi_addr = 0;
reg [LEN_WIDTH-1:0] s_axis_read_desc_len = 0;
reg [TAG_WIDTH-1:0] s_axis_read_desc_tag = 0;
reg s_axis_read_desc_valid = 0;
reg m_axi_awready = 0;
reg m_axi_wready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_bid = 0;
reg [1:0] m_axi_bresp = 0;
reg m_axi_bvalid = 0;
reg enable = 0;
reg ext_tag_enable = 0;
reg [15:0] requester_id = 0;
reg requester_id_enable = 0;
reg [2:0] max_read_request_size = 0;
// Outputs
wire s_axis_rc_tready;
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rq_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rq_tkeep;
wire m_axis_rq_tvalid;
wire m_axis_rq_tlast;
wire [59:0] m_axis_rq_tuser;
wire s_axis_read_desc_ready;
wire [TAG_WIDTH-1:0] m_axis_read_desc_status_tag;
wire m_axis_read_desc_status_valid;
wire [AXI_ID_WIDTH-1:0] m_axi_awid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr;
wire [7:0] m_axi_awlen;
wire [2:0] m_axi_awsize;
wire [1:0] m_axi_awburst;
wire m_axi_awlock;
wire [3:0] m_axi_awcache;
wire [2:0] m_axi_awprot;
wire m_axi_awvalid;
wire [AXI_DATA_WIDTH-1:0] m_axi_wdata;
wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb;
wire m_axi_wlast;
wire m_axi_wvalid;
wire m_axi_bready;
wire status_error_cor;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_rc_tdata,
s_axis_rc_tkeep,
s_axis_rc_tvalid,
s_axis_rc_tlast,
s_axis_rc_tuser,
m_axis_rq_tready,
s_axis_pcie_rq_tag,
s_axis_pcie_rq_tag_valid,
s_axis_read_desc_pcie_addr,
s_axis_read_desc_axi_addr,
s_axis_read_desc_len,
s_axis_read_desc_tag,
s_axis_read_desc_valid,
m_axi_awready,
m_axi_wready,
m_axi_bid,
m_axi_bresp,
m_axi_bvalid,
enable,
ext_tag_enable,
requester_id,
requester_id_enable,
max_read_request_size
);
$to_myhdl(
s_axis_rc_tready,
m_axis_rq_tdata,
m_axis_rq_tkeep,
m_axis_rq_tvalid,
m_axis_rq_tlast,
m_axis_rq_tuser,
s_axis_read_desc_ready,
m_axis_read_desc_status_tag,
m_axis_read_desc_status_valid,
m_axi_awid,
m_axi_awaddr,
m_axi_awlen,
m_axi_awsize,
m_axi_awburst,
m_axi_awlock,
m_axi_awcache,
m_axi_awprot,
m_axi_awvalid,
m_axi_wdata,
m_axi_wstrb,
m_axi_wlast,
m_axi_wvalid,
m_axi_bready,
status_error_cor,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axi_dma_rd_128.lxt");
$dumpvars(0, test_pcie_us_axi_dma_rd_128);
end
pcie_us_axi_dma_rd #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
.PCIE_ADDR_WIDTH(PCIE_ADDR_WIDTH),
.PCIE_CLIENT_TAG(PCIE_CLIENT_TAG),
.PCIE_TAG_WIDTH(PCIE_TAG_WIDTH),
.PCIE_TAG_COUNT(PCIE_TAG_COUNT),
.PCIE_EXT_TAG_ENABLE(PCIE_EXT_TAG_ENABLE),
.LEN_WIDTH(LEN_WIDTH),
.TAG_WIDTH(TAG_WIDTH)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_rc_tdata(s_axis_rc_tdata),
.s_axis_rc_tkeep(s_axis_rc_tkeep),
.s_axis_rc_tvalid(s_axis_rc_tvalid),
.s_axis_rc_tready(s_axis_rc_tready),
.s_axis_rc_tlast(s_axis_rc_tlast),
.s_axis_rc_tuser(s_axis_rc_tuser),
.m_axis_rq_tdata(m_axis_rq_tdata),
.m_axis_rq_tkeep(m_axis_rq_tkeep),
.m_axis_rq_tvalid(m_axis_rq_tvalid),
.m_axis_rq_tready(m_axis_rq_tready),
.m_axis_rq_tlast(m_axis_rq_tlast),
.m_axis_rq_tuser(m_axis_rq_tuser),
.s_axis_pcie_rq_tag(s_axis_pcie_rq_tag),
.s_axis_pcie_rq_tag_valid(s_axis_pcie_rq_tag_valid),
.s_axis_read_desc_pcie_addr(s_axis_read_desc_pcie_addr),
.s_axis_read_desc_axi_addr(s_axis_read_desc_axi_addr),
.s_axis_read_desc_len(s_axis_read_desc_len),
.s_axis_read_desc_tag(s_axis_read_desc_tag),
.s_axis_read_desc_valid(s_axis_read_desc_valid),
.s_axis_read_desc_ready(s_axis_read_desc_ready),
.m_axis_read_desc_status_tag(m_axis_read_desc_status_tag),
.m_axis_read_desc_status_valid(m_axis_read_desc_status_valid),
.m_axi_awid(m_axi_awid),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awlen(m_axi_awlen),
.m_axi_awsize(m_axi_awsize),
.m_axi_awburst(m_axi_awburst),
.m_axi_awlock(m_axi_awlock),
.m_axi_awcache(m_axi_awcache),
.m_axi_awprot(m_axi_awprot),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wstrb(m_axi_wstrb),
.m_axi_wlast(m_axi_wlast),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
.enable(enable),
.ext_tag_enable(ext_tag_enable),
.requester_id(requester_id),
.requester_id_enable(requester_id_enable),
.max_read_request_size(max_read_request_size),
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
endmodule

View File

@ -0,0 +1,496 @@
#!/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 os
import struct
import pcie
import pcie_us
import axi
import axis_ep
module = 'pcie_us_axi_dma_rd'
testbench = 'test_%s_256' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("../rtl/pcie_tag_manager.v")
srcs.append("../rtl/priority_encoder.v")
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 256
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
PCIE_ADDR_WIDTH = 64
PCIE_CLIENT_TAG = 1
PCIE_TAG_WIDTH = 8
PCIE_TAG_COUNT = 256
PCIE_EXT_TAG_ENABLE = 1
LEN_WIDTH = 20
TAG_WIDTH = 8
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_rc_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_rc_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_rc_tvalid = Signal(bool(0))
s_axis_rc_tlast = Signal(bool(0))
s_axis_rc_tuser = Signal(intbv(0)[75:])
m_axis_rq_tready = Signal(bool(0))
s_axis_pcie_rq_tag = Signal(intbv(0)[PCIE_TAG_WIDTH:])
s_axis_pcie_rq_tag_valid = Signal(bool(0))
s_axis_read_desc_pcie_addr = Signal(intbv(0)[PCIE_ADDR_WIDTH:])
s_axis_read_desc_axi_addr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
s_axis_read_desc_len = Signal(intbv(0)[LEN_WIDTH:])
s_axis_read_desc_tag = Signal(intbv(0)[TAG_WIDTH:])
s_axis_read_desc_valid = Signal(bool(0))
m_axi_awready = Signal(bool(0))
m_axi_wready = Signal(bool(0))
m_axi_bid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_bresp = Signal(intbv(0)[2:])
m_axi_bvalid = Signal(bool(0))
enable = Signal(bool(0))
ext_tag_enable = Signal(bool(0))
requester_id = Signal(intbv(0)[16:])
requester_id_enable = Signal(bool(0))
max_read_request_size = Signal(intbv(0)[3:])
# Outputs
s_axis_rc_tready = Signal(bool(0))
m_axis_rq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_rq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_rq_tvalid = Signal(bool(0))
m_axis_rq_tlast = Signal(bool(0))
m_axis_rq_tuser = Signal(intbv(0)[60:])
s_axis_read_desc_ready = Signal(bool(0))
m_axis_read_desc_status_tag = Signal(intbv(0)[TAG_WIDTH:])
m_axis_read_desc_status_valid = Signal(bool(0))
m_axi_awid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_awaddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_awlen = Signal(intbv(0)[8:])
m_axi_awsize = Signal(intbv(5)[3:])
m_axi_awburst = Signal(intbv(1)[2:])
m_axi_awlock = Signal(bool(0))
m_axi_awcache = Signal(intbv(3)[4:])
m_axi_awprot = Signal(intbv(2)[3:])
m_axi_awvalid = Signal(bool(0))
m_axi_wdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_wstrb = Signal(intbv(0)[AXI_STRB_WIDTH:])
m_axi_wlast = Signal(bool(0))
m_axi_wvalid = Signal(bool(0))
m_axi_bready = Signal(bool(0))
status_error_cor = Signal(bool(0))
status_error_uncor = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_awid=m_axi_awid,
s_axi_awaddr=m_axi_awaddr,
s_axi_awlen=m_axi_awlen,
s_axi_awsize=m_axi_awsize,
s_axi_awburst=m_axi_awburst,
s_axi_awlock=m_axi_awlock,
s_axi_awcache=m_axi_awcache,
s_axi_awprot=m_axi_awprot,
s_axi_awvalid=m_axi_awvalid,
s_axi_awready=m_axi_awready,
s_axi_wdata=m_axi_wdata,
s_axi_wstrb=m_axi_wstrb,
s_axi_wlast=m_axi_wlast,
s_axi_wvalid=m_axi_wvalid,
s_axi_wready=m_axi_wready,
s_axi_bid=m_axi_bid,
s_axi_bresp=m_axi_bresp,
s_axi_bvalid=m_axi_bvalid,
s_axi_bready=m_axi_bready,
name='port0'
)
# sources and sinks
read_desc_source = axis_ep.AXIStreamSource()
read_desc_source_logic = read_desc_source.create_logic(
user_clk,
user_reset,
tdata=(s_axis_read_desc_pcie_addr, s_axis_read_desc_axi_addr, s_axis_read_desc_len, s_axis_read_desc_tag),
tvalid=s_axis_read_desc_valid,
tready=s_axis_read_desc_ready,
name='read_desc_source'
)
read_desc_status_sink = axis_ep.AXIStreamSink()
read_desc_status_sink_logic = read_desc_status_sink.create_logic(
user_clk,
user_reset,
tdata=(m_axis_read_desc_status_tag,),
tvalid=m_axis_read_desc_status_valid,
name='read_desc_status_sink'
)
# PCIe devices
rc = pcie.RootComplex()
mem_base, mem_data = rc.alloc_region(16*1024*1024)
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 8
dev.user_clock_frequency = 256e6
rc.make_port().connect(dev)
cq_pause = Signal(bool(0))
cc_pause = Signal(bool(0))
rq_pause = Signal(bool(0))
rc_pause = Signal(bool(0))
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_cq_tuser=Signal(intbv(0)[85:]),
m_axis_cq_tlast=Signal(bool(0)),
m_axis_cq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_cq_tvalid=Signal(bool(0)),
m_axis_cq_tready=Signal(bool(1)),
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)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_cc_tuser=Signal(intbv(0)[33:]),
s_axis_cc_tlast=Signal(bool(0)),
s_axis_cc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_cc_tvalid=Signal(bool(0)),
s_axis_cc_tready=Signal(bool(0)),
# Requester reQuest Interface
s_axis_rq_tdata=m_axis_rq_tdata,
s_axis_rq_tuser=m_axis_rq_tuser,
s_axis_rq_tlast=m_axis_rq_tlast,
s_axis_rq_tkeep=m_axis_rq_tkeep,
s_axis_rq_tvalid=m_axis_rq_tvalid,
s_axis_rq_tready=m_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=s_axis_rc_tdata,
m_axis_rc_tuser=s_axis_rc_tuser,
m_axis_rc_tlast=s_axis_rc_tlast,
m_axis_rc_tkeep=s_axis_rc_tkeep,
m_axis_rc_tvalid=s_axis_rc_tvalid,
m_axis_rc_tready=s_axis_rc_tready,
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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,
cq_pause=cq_pause,
cc_pause=cc_pause,
rq_pause=rq_pause,
rc_pause=rc_pause
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
s_axis_rc_tdata=s_axis_rc_tdata,
s_axis_rc_tkeep=s_axis_rc_tkeep,
s_axis_rc_tvalid=s_axis_rc_tvalid,
s_axis_rc_tready=s_axis_rc_tready,
s_axis_rc_tlast=s_axis_rc_tlast,
s_axis_rc_tuser=s_axis_rc_tuser,
m_axis_rq_tdata=m_axis_rq_tdata,
m_axis_rq_tkeep=m_axis_rq_tkeep,
m_axis_rq_tvalid=m_axis_rq_tvalid,
m_axis_rq_tready=m_axis_rq_tready,
m_axis_rq_tlast=m_axis_rq_tlast,
m_axis_rq_tuser=m_axis_rq_tuser,
s_axis_pcie_rq_tag=s_axis_pcie_rq_tag,
s_axis_pcie_rq_tag_valid=s_axis_pcie_rq_tag_valid,
s_axis_read_desc_pcie_addr=s_axis_read_desc_pcie_addr,
s_axis_read_desc_axi_addr=s_axis_read_desc_axi_addr,
s_axis_read_desc_len=s_axis_read_desc_len,
s_axis_read_desc_tag=s_axis_read_desc_tag,
s_axis_read_desc_valid=s_axis_read_desc_valid,
s_axis_read_desc_ready=s_axis_read_desc_ready,
m_axis_read_desc_status_tag=m_axis_read_desc_status_tag,
m_axis_read_desc_status_valid=m_axis_read_desc_status_valid,
m_axi_awid=m_axi_awid,
m_axi_awaddr=m_axi_awaddr,
m_axi_awlen=m_axi_awlen,
m_axi_awsize=m_axi_awsize,
m_axi_awburst=m_axi_awburst,
m_axi_awlock=m_axi_awlock,
m_axi_awcache=m_axi_awcache,
m_axi_awprot=m_axi_awprot,
m_axi_awvalid=m_axi_awvalid,
m_axi_awready=m_axi_awready,
m_axi_wdata=m_axi_wdata,
m_axi_wstrb=m_axi_wstrb,
m_axi_wlast=m_axi_wlast,
m_axi_wvalid=m_axi_wvalid,
m_axi_wready=m_axi_wready,
m_axi_bid=m_axi_bid,
m_axi_bresp=m_axi_bresp,
m_axi_bvalid=m_axi_bvalid,
m_axi_bready=m_axi_bready,
enable=enable,
ext_tag_enable=ext_tag_enable,
requester_id=requester_id,
requester_id_enable=requester_id_enable,
max_read_request_size=max_read_request_size,
status_error_cor=status_error_cor,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
status_error_cor_asserted = Signal(bool(0))
status_error_uncor_asserted = Signal(bool(0))
@always(clk.posedge)
def monitor():
if (status_error_cor):
status_error_cor_asserted.next = 1
if (status_error_uncor):
status_error_uncor_asserted.next = 1
cq_pause_toggle = Signal(bool(0))
cc_pause_toggle = Signal(bool(0))
rq_pause_toggle = Signal(bool(0))
rc_pause_toggle = Signal(bool(0))
@instance
def pause_toggle():
while True:
if (cq_pause_toggle or cc_pause_toggle or rq_pause_toggle or rc_pause_toggle):
cq_pause.next = cq_pause_toggle
cc_pause.next = cc_pause_toggle
rq_pause.next = rq_pause_toggle
rc_pause.next = rc_pause_toggle
yield user_clk.posedge
yield user_clk.posedge
yield user_clk.posedge
cq_pause.next = 0
cc_pause.next = 0
rq_pause.next = 0
rc_pause.next = 0
yield user_clk.posedge
@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
# testbench stimulus
cur_tag = 1
max_read_request_size.next = 2
enable.next = 1
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate(enable_bus_mastering=True)
yield delay(100)
yield user_clk.posedge
print("test 2: PCIe read")
current_test.next = 2
pcie_addr = 0x00000000
axi_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
mem_data[pcie_addr:pcie_addr+len(test_data)] = test_data
data = mem_data[pcie_addr:pcie_addr+32]
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
read_desc_source.send([(pcie_addr, axi_addr, len(test_data), cur_tag)])
yield read_desc_status_sink.wait(2000)
yield delay(50)
status = read_desc_status_sink.recv()
print(status)
data = axi_ram_inst.read_mem(axi_addr, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(axi_addr, len(test_data)) == test_data
cur_tag = (cur_tag + 1) % 256
yield delay(100)
yield user_clk.posedge
print("test 3: various reads")
current_test.next = 3
for length in list(range(1,35))+list(range(128-4,128+4))+[1024]:
for pcie_offset in list(range(8,13))+list(range(4096-4,4096+4)):
for axi_offset in list(range(8,41))+list(range(4096-32,4096)):
for pause in [False, True]:
print("length %d, pcie_offset %d, axi_offset %d"% (length, pcie_offset, axi_offset))
#pcie_addr = length * 0x100000000 + pcie_offset * 0x10000 + offset
pcie_addr = pcie_offset
axi_addr = axi_offset
test_data = bytearray([x%256 for x in range(length)])
mem_data[pcie_addr:pcie_addr+len(test_data)] = test_data
data = mem_data[pcie_addr&0xffff80:(pcie_addr&0xffff80)+64]
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
axi_ram_inst.write_mem(axi_addr & 0xffff80, b'\xaa'*(len(test_data)+256))
rq_pause_toggle.next = pause
rc_pause_toggle.next = pause
read_desc_source.send([(pcie_addr, axi_addr, len(test_data), cur_tag)])
yield read_desc_status_sink.wait(2000)
rq_pause_toggle.next = 0
rc_pause_toggle.next = 0
status = read_desc_status_sink.recv()
print(status)
data = axi_ram_inst.read_mem(axi_addr&0xfffff0, 64)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(axi_addr-8, len(test_data)+16) == b'\xaa'*8+test_data+b'\xaa'*8
cur_tag = (cur_tag + 1) % 256
yield delay(50)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,238 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_dma_rd
*/
module test_pcie_us_axi_dma_rd_256;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 256;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
parameter PCIE_ADDR_WIDTH = 64;
parameter PCIE_CLIENT_TAG = 1;
parameter PCIE_TAG_WIDTH = 8;
parameter PCIE_TAG_COUNT = 256;
parameter PCIE_EXT_TAG_ENABLE = 1;
parameter LEN_WIDTH = 20;
parameter TAG_WIDTH = 8;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_rc_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_rc_tkeep = 0;
reg s_axis_rc_tvalid = 0;
reg s_axis_rc_tlast = 0;
reg [74:0] s_axis_rc_tuser = 0;
reg m_axis_rq_tready = 0;
reg [PCIE_TAG_WIDTH-1:0] s_axis_pcie_rq_tag = 0;
reg s_axis_pcie_rq_tag_valid = 0;
reg [PCIE_ADDR_WIDTH-1:0] s_axis_read_desc_pcie_addr = 0;
reg [AXI_ADDR_WIDTH-1:0] s_axis_read_desc_axi_addr = 0;
reg [LEN_WIDTH-1:0] s_axis_read_desc_len = 0;
reg [TAG_WIDTH-1:0] s_axis_read_desc_tag = 0;
reg s_axis_read_desc_valid = 0;
reg m_axi_awready = 0;
reg m_axi_wready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_bid = 0;
reg [1:0] m_axi_bresp = 0;
reg m_axi_bvalid = 0;
reg enable = 0;
reg ext_tag_enable = 0;
reg [15:0] requester_id = 0;
reg requester_id_enable = 0;
reg [2:0] max_read_request_size = 0;
// Outputs
wire s_axis_rc_tready;
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rq_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rq_tkeep;
wire m_axis_rq_tvalid;
wire m_axis_rq_tlast;
wire [59:0] m_axis_rq_tuser;
wire s_axis_read_desc_ready;
wire [TAG_WIDTH-1:0] m_axis_read_desc_status_tag;
wire m_axis_read_desc_status_valid;
wire [AXI_ID_WIDTH-1:0] m_axi_awid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr;
wire [7:0] m_axi_awlen;
wire [2:0] m_axi_awsize;
wire [1:0] m_axi_awburst;
wire m_axi_awlock;
wire [3:0] m_axi_awcache;
wire [2:0] m_axi_awprot;
wire m_axi_awvalid;
wire [AXI_DATA_WIDTH-1:0] m_axi_wdata;
wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb;
wire m_axi_wlast;
wire m_axi_wvalid;
wire m_axi_bready;
wire status_error_cor;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_rc_tdata,
s_axis_rc_tkeep,
s_axis_rc_tvalid,
s_axis_rc_tlast,
s_axis_rc_tuser,
m_axis_rq_tready,
s_axis_pcie_rq_tag,
s_axis_pcie_rq_tag_valid,
s_axis_read_desc_pcie_addr,
s_axis_read_desc_axi_addr,
s_axis_read_desc_len,
s_axis_read_desc_tag,
s_axis_read_desc_valid,
m_axi_awready,
m_axi_wready,
m_axi_bid,
m_axi_bresp,
m_axi_bvalid,
enable,
ext_tag_enable,
requester_id,
requester_id_enable,
max_read_request_size
);
$to_myhdl(
s_axis_rc_tready,
m_axis_rq_tdata,
m_axis_rq_tkeep,
m_axis_rq_tvalid,
m_axis_rq_tlast,
m_axis_rq_tuser,
s_axis_read_desc_ready,
m_axis_read_desc_status_tag,
m_axis_read_desc_status_valid,
m_axi_awid,
m_axi_awaddr,
m_axi_awlen,
m_axi_awsize,
m_axi_awburst,
m_axi_awlock,
m_axi_awcache,
m_axi_awprot,
m_axi_awvalid,
m_axi_wdata,
m_axi_wstrb,
m_axi_wlast,
m_axi_wvalid,
m_axi_bready,
status_error_cor,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axi_dma_rd_256.lxt");
$dumpvars(0, test_pcie_us_axi_dma_rd_256);
end
pcie_us_axi_dma_rd #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
.PCIE_ADDR_WIDTH(PCIE_ADDR_WIDTH),
.PCIE_CLIENT_TAG(PCIE_CLIENT_TAG),
.PCIE_TAG_WIDTH(PCIE_TAG_WIDTH),
.PCIE_TAG_COUNT(PCIE_TAG_COUNT),
.PCIE_EXT_TAG_ENABLE(PCIE_EXT_TAG_ENABLE),
.LEN_WIDTH(LEN_WIDTH),
.TAG_WIDTH(TAG_WIDTH)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_rc_tdata(s_axis_rc_tdata),
.s_axis_rc_tkeep(s_axis_rc_tkeep),
.s_axis_rc_tvalid(s_axis_rc_tvalid),
.s_axis_rc_tready(s_axis_rc_tready),
.s_axis_rc_tlast(s_axis_rc_tlast),
.s_axis_rc_tuser(s_axis_rc_tuser),
.m_axis_rq_tdata(m_axis_rq_tdata),
.m_axis_rq_tkeep(m_axis_rq_tkeep),
.m_axis_rq_tvalid(m_axis_rq_tvalid),
.m_axis_rq_tready(m_axis_rq_tready),
.m_axis_rq_tlast(m_axis_rq_tlast),
.m_axis_rq_tuser(m_axis_rq_tuser),
.s_axis_pcie_rq_tag(s_axis_pcie_rq_tag),
.s_axis_pcie_rq_tag_valid(s_axis_pcie_rq_tag_valid),
.s_axis_read_desc_pcie_addr(s_axis_read_desc_pcie_addr),
.s_axis_read_desc_axi_addr(s_axis_read_desc_axi_addr),
.s_axis_read_desc_len(s_axis_read_desc_len),
.s_axis_read_desc_tag(s_axis_read_desc_tag),
.s_axis_read_desc_valid(s_axis_read_desc_valid),
.s_axis_read_desc_ready(s_axis_read_desc_ready),
.m_axis_read_desc_status_tag(m_axis_read_desc_status_tag),
.m_axis_read_desc_status_valid(m_axis_read_desc_status_valid),
.m_axi_awid(m_axi_awid),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awlen(m_axi_awlen),
.m_axi_awsize(m_axi_awsize),
.m_axi_awburst(m_axi_awburst),
.m_axi_awlock(m_axi_awlock),
.m_axi_awcache(m_axi_awcache),
.m_axi_awprot(m_axi_awprot),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wstrb(m_axi_wstrb),
.m_axi_wlast(m_axi_wlast),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
.enable(enable),
.ext_tag_enable(ext_tag_enable),
.requester_id(requester_id),
.requester_id_enable(requester_id_enable),
.max_read_request_size(max_read_request_size),
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
endmodule

View File

@ -0,0 +1,496 @@
#!/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 os
import struct
import pcie
import pcie_us
import axi
import axis_ep
module = 'pcie_us_axi_dma_rd'
testbench = 'test_%s_64' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("../rtl/pcie_tag_manager.v")
srcs.append("../rtl/priority_encoder.v")
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 64
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
PCIE_ADDR_WIDTH = 64
PCIE_CLIENT_TAG = 1
PCIE_TAG_WIDTH = 8
PCIE_TAG_COUNT = 256
PCIE_EXT_TAG_ENABLE = 1
LEN_WIDTH = 20
TAG_WIDTH = 8
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_rc_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_rc_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_rc_tvalid = Signal(bool(0))
s_axis_rc_tlast = Signal(bool(0))
s_axis_rc_tuser = Signal(intbv(0)[75:])
m_axis_rq_tready = Signal(bool(0))
s_axis_pcie_rq_tag = Signal(intbv(0)[PCIE_TAG_WIDTH:])
s_axis_pcie_rq_tag_valid = Signal(bool(0))
s_axis_read_desc_pcie_addr = Signal(intbv(0)[PCIE_ADDR_WIDTH:])
s_axis_read_desc_axi_addr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
s_axis_read_desc_len = Signal(intbv(0)[LEN_WIDTH:])
s_axis_read_desc_tag = Signal(intbv(0)[TAG_WIDTH:])
s_axis_read_desc_valid = Signal(bool(0))
m_axi_awready = Signal(bool(0))
m_axi_wready = Signal(bool(0))
m_axi_bid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_bresp = Signal(intbv(0)[2:])
m_axi_bvalid = Signal(bool(0))
enable = Signal(bool(0))
ext_tag_enable = Signal(bool(0))
requester_id = Signal(intbv(0)[16:])
requester_id_enable = Signal(bool(0))
max_read_request_size = Signal(intbv(0)[3:])
# Outputs
s_axis_rc_tready = Signal(bool(0))
m_axis_rq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_rq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_rq_tvalid = Signal(bool(0))
m_axis_rq_tlast = Signal(bool(0))
m_axis_rq_tuser = Signal(intbv(0)[60:])
s_axis_read_desc_ready = Signal(bool(0))
m_axis_read_desc_status_tag = Signal(intbv(0)[TAG_WIDTH:])
m_axis_read_desc_status_valid = Signal(bool(0))
m_axi_awid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_awaddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_awlen = Signal(intbv(0)[8:])
m_axi_awsize = Signal(intbv(3)[3:])
m_axi_awburst = Signal(intbv(1)[2:])
m_axi_awlock = Signal(bool(0))
m_axi_awcache = Signal(intbv(3)[4:])
m_axi_awprot = Signal(intbv(2)[3:])
m_axi_awvalid = Signal(bool(0))
m_axi_wdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_wstrb = Signal(intbv(0)[AXI_STRB_WIDTH:])
m_axi_wlast = Signal(bool(0))
m_axi_wvalid = Signal(bool(0))
m_axi_bready = Signal(bool(0))
status_error_cor = Signal(bool(0))
status_error_uncor = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_awid=m_axi_awid,
s_axi_awaddr=m_axi_awaddr,
s_axi_awlen=m_axi_awlen,
s_axi_awsize=m_axi_awsize,
s_axi_awburst=m_axi_awburst,
s_axi_awlock=m_axi_awlock,
s_axi_awcache=m_axi_awcache,
s_axi_awprot=m_axi_awprot,
s_axi_awvalid=m_axi_awvalid,
s_axi_awready=m_axi_awready,
s_axi_wdata=m_axi_wdata,
s_axi_wstrb=m_axi_wstrb,
s_axi_wlast=m_axi_wlast,
s_axi_wvalid=m_axi_wvalid,
s_axi_wready=m_axi_wready,
s_axi_bid=m_axi_bid,
s_axi_bresp=m_axi_bresp,
s_axi_bvalid=m_axi_bvalid,
s_axi_bready=m_axi_bready,
name='port0'
)
# sources and sinks
read_desc_source = axis_ep.AXIStreamSource()
read_desc_source_logic = read_desc_source.create_logic(
user_clk,
user_reset,
tdata=(s_axis_read_desc_pcie_addr, s_axis_read_desc_axi_addr, s_axis_read_desc_len, s_axis_read_desc_tag),
tvalid=s_axis_read_desc_valid,
tready=s_axis_read_desc_ready,
name='read_desc_source'
)
read_desc_status_sink = axis_ep.AXIStreamSink()
read_desc_status_sink_logic = read_desc_status_sink.create_logic(
user_clk,
user_reset,
tdata=(m_axis_read_desc_status_tag,),
tvalid=m_axis_read_desc_status_valid,
name='read_desc_status_sink'
)
# PCIe devices
rc = pcie.RootComplex()
mem_base, mem_data = rc.alloc_region(16*1024*1024)
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 2
dev.user_clock_frequency = 256e6
rc.make_port().connect(dev)
cq_pause = Signal(bool(0))
cc_pause = Signal(bool(0))
rq_pause = Signal(bool(0))
rc_pause = Signal(bool(0))
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_cq_tuser=Signal(intbv(0)[85:]),
m_axis_cq_tlast=Signal(bool(0)),
m_axis_cq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_cq_tvalid=Signal(bool(0)),
m_axis_cq_tready=Signal(bool(1)),
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)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_cc_tuser=Signal(intbv(0)[33:]),
s_axis_cc_tlast=Signal(bool(0)),
s_axis_cc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_cc_tvalid=Signal(bool(0)),
s_axis_cc_tready=Signal(bool(0)),
# Requester reQuest Interface
s_axis_rq_tdata=m_axis_rq_tdata,
s_axis_rq_tuser=m_axis_rq_tuser,
s_axis_rq_tlast=m_axis_rq_tlast,
s_axis_rq_tkeep=m_axis_rq_tkeep,
s_axis_rq_tvalid=m_axis_rq_tvalid,
s_axis_rq_tready=m_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=s_axis_rc_tdata,
m_axis_rc_tuser=s_axis_rc_tuser,
m_axis_rc_tlast=s_axis_rc_tlast,
m_axis_rc_tkeep=s_axis_rc_tkeep,
m_axis_rc_tvalid=s_axis_rc_tvalid,
m_axis_rc_tready=s_axis_rc_tready,
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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,
cq_pause=cq_pause,
cc_pause=cc_pause,
rq_pause=rq_pause,
rc_pause=rc_pause
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
s_axis_rc_tdata=s_axis_rc_tdata,
s_axis_rc_tkeep=s_axis_rc_tkeep,
s_axis_rc_tvalid=s_axis_rc_tvalid,
s_axis_rc_tready=s_axis_rc_tready,
s_axis_rc_tlast=s_axis_rc_tlast,
s_axis_rc_tuser=s_axis_rc_tuser,
m_axis_rq_tdata=m_axis_rq_tdata,
m_axis_rq_tkeep=m_axis_rq_tkeep,
m_axis_rq_tvalid=m_axis_rq_tvalid,
m_axis_rq_tready=m_axis_rq_tready,
m_axis_rq_tlast=m_axis_rq_tlast,
m_axis_rq_tuser=m_axis_rq_tuser,
s_axis_pcie_rq_tag=s_axis_pcie_rq_tag,
s_axis_pcie_rq_tag_valid=s_axis_pcie_rq_tag_valid,
s_axis_read_desc_pcie_addr=s_axis_read_desc_pcie_addr,
s_axis_read_desc_axi_addr=s_axis_read_desc_axi_addr,
s_axis_read_desc_len=s_axis_read_desc_len,
s_axis_read_desc_tag=s_axis_read_desc_tag,
s_axis_read_desc_valid=s_axis_read_desc_valid,
s_axis_read_desc_ready=s_axis_read_desc_ready,
m_axis_read_desc_status_tag=m_axis_read_desc_status_tag,
m_axis_read_desc_status_valid=m_axis_read_desc_status_valid,
m_axi_awid=m_axi_awid,
m_axi_awaddr=m_axi_awaddr,
m_axi_awlen=m_axi_awlen,
m_axi_awsize=m_axi_awsize,
m_axi_awburst=m_axi_awburst,
m_axi_awlock=m_axi_awlock,
m_axi_awcache=m_axi_awcache,
m_axi_awprot=m_axi_awprot,
m_axi_awvalid=m_axi_awvalid,
m_axi_awready=m_axi_awready,
m_axi_wdata=m_axi_wdata,
m_axi_wstrb=m_axi_wstrb,
m_axi_wlast=m_axi_wlast,
m_axi_wvalid=m_axi_wvalid,
m_axi_wready=m_axi_wready,
m_axi_bid=m_axi_bid,
m_axi_bresp=m_axi_bresp,
m_axi_bvalid=m_axi_bvalid,
m_axi_bready=m_axi_bready,
enable=enable,
ext_tag_enable=ext_tag_enable,
requester_id=requester_id,
requester_id_enable=requester_id_enable,
max_read_request_size=max_read_request_size,
status_error_cor=status_error_cor,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
status_error_cor_asserted = Signal(bool(0))
status_error_uncor_asserted = Signal(bool(0))
@always(clk.posedge)
def monitor():
if (status_error_cor):
status_error_cor_asserted.next = 1
if (status_error_uncor):
status_error_uncor_asserted.next = 1
cq_pause_toggle = Signal(bool(0))
cc_pause_toggle = Signal(bool(0))
rq_pause_toggle = Signal(bool(0))
rc_pause_toggle = Signal(bool(0))
@instance
def pause_toggle():
while True:
if (cq_pause_toggle or cc_pause_toggle or rq_pause_toggle or rc_pause_toggle):
cq_pause.next = cq_pause_toggle
cc_pause.next = cc_pause_toggle
rq_pause.next = rq_pause_toggle
rc_pause.next = rc_pause_toggle
yield user_clk.posedge
yield user_clk.posedge
yield user_clk.posedge
cq_pause.next = 0
cc_pause.next = 0
rq_pause.next = 0
rc_pause.next = 0
yield user_clk.posedge
@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
# testbench stimulus
cur_tag = 1
max_read_request_size.next = 2
enable.next = 1
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate(enable_bus_mastering=True)
yield delay(100)
yield user_clk.posedge
print("test 2: PCIe read")
current_test.next = 2
pcie_addr = 0x00000000
axi_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
mem_data[pcie_addr:pcie_addr+len(test_data)] = test_data
data = mem_data[pcie_addr:pcie_addr+32]
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
read_desc_source.send([(pcie_addr, axi_addr, len(test_data), cur_tag)])
yield read_desc_status_sink.wait(2000)
yield delay(50)
status = read_desc_status_sink.recv()
print(status)
data = axi_ram_inst.read_mem(axi_addr, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(axi_addr, len(test_data)) == test_data
cur_tag = (cur_tag + 1) % 256
yield delay(100)
yield user_clk.posedge
print("test 3: various reads")
current_test.next = 3
for length in list(range(1,11))+list(range(128-4,128+4))+[1024]:
for pcie_offset in list(range(8,13))+list(range(4096-4,4096+4)):
for axi_offset in list(range(8,17))+list(range(4096-8,4096)):
for pause in [False, True]:
print("length %d, pcie_offset %d, axi_offset %d"% (length, pcie_offset, axi_offset))
#pcie_addr = length * 0x100000000 + pcie_offset * 0x10000 + offset
pcie_addr = pcie_offset
axi_addr = axi_offset
test_data = bytearray([x%256 for x in range(length)])
mem_data[pcie_addr:pcie_addr+len(test_data)] = test_data
data = mem_data[pcie_addr&0xffff80:(pcie_addr&0xffff80)+64]
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
axi_ram_inst.write_mem(axi_addr & 0xffff80, b'\xaa'*(len(test_data)+256))
rq_pause_toggle.next = pause
rc_pause_toggle.next = pause
read_desc_source.send([(pcie_addr, axi_addr, len(test_data), cur_tag)])
yield read_desc_status_sink.wait(4000)
rq_pause_toggle.next = 0
rc_pause_toggle.next = 0
status = read_desc_status_sink.recv()
print(status)
data = axi_ram_inst.read_mem(axi_addr&0xfffff0, 64)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(axi_addr-8, len(test_data)+16) == b'\xaa'*8+test_data+b'\xaa'*8
cur_tag = (cur_tag + 1) % 256
yield delay(50)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,238 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_dma_rd
*/
module test_pcie_us_axi_dma_rd_64;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 64;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
parameter PCIE_ADDR_WIDTH = 64;
parameter PCIE_CLIENT_TAG = 1;
parameter PCIE_TAG_WIDTH = 8;
parameter PCIE_TAG_COUNT = 256;
parameter PCIE_EXT_TAG_ENABLE = 1;
parameter LEN_WIDTH = 20;
parameter TAG_WIDTH = 8;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_rc_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_rc_tkeep = 0;
reg s_axis_rc_tvalid = 0;
reg s_axis_rc_tlast = 0;
reg [74:0] s_axis_rc_tuser = 0;
reg m_axis_rq_tready = 0;
reg [PCIE_TAG_WIDTH-1:0] s_axis_pcie_rq_tag = 0;
reg s_axis_pcie_rq_tag_valid = 0;
reg [PCIE_ADDR_WIDTH-1:0] s_axis_read_desc_pcie_addr = 0;
reg [AXI_ADDR_WIDTH-1:0] s_axis_read_desc_axi_addr = 0;
reg [LEN_WIDTH-1:0] s_axis_read_desc_len = 0;
reg [TAG_WIDTH-1:0] s_axis_read_desc_tag = 0;
reg s_axis_read_desc_valid = 0;
reg m_axi_awready = 0;
reg m_axi_wready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_bid = 0;
reg [1:0] m_axi_bresp = 0;
reg m_axi_bvalid = 0;
reg enable = 0;
reg ext_tag_enable = 0;
reg [15:0] requester_id = 0;
reg requester_id_enable = 0;
reg [2:0] max_read_request_size = 0;
// Outputs
wire s_axis_rc_tready;
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rq_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rq_tkeep;
wire m_axis_rq_tvalid;
wire m_axis_rq_tlast;
wire [59:0] m_axis_rq_tuser;
wire s_axis_read_desc_ready;
wire [TAG_WIDTH-1:0] m_axis_read_desc_status_tag;
wire m_axis_read_desc_status_valid;
wire [AXI_ID_WIDTH-1:0] m_axi_awid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr;
wire [7:0] m_axi_awlen;
wire [2:0] m_axi_awsize;
wire [1:0] m_axi_awburst;
wire m_axi_awlock;
wire [3:0] m_axi_awcache;
wire [2:0] m_axi_awprot;
wire m_axi_awvalid;
wire [AXI_DATA_WIDTH-1:0] m_axi_wdata;
wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb;
wire m_axi_wlast;
wire m_axi_wvalid;
wire m_axi_bready;
wire status_error_cor;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_rc_tdata,
s_axis_rc_tkeep,
s_axis_rc_tvalid,
s_axis_rc_tlast,
s_axis_rc_tuser,
m_axis_rq_tready,
s_axis_pcie_rq_tag,
s_axis_pcie_rq_tag_valid,
s_axis_read_desc_pcie_addr,
s_axis_read_desc_axi_addr,
s_axis_read_desc_len,
s_axis_read_desc_tag,
s_axis_read_desc_valid,
m_axi_awready,
m_axi_wready,
m_axi_bid,
m_axi_bresp,
m_axi_bvalid,
enable,
ext_tag_enable,
requester_id,
requester_id_enable,
max_read_request_size
);
$to_myhdl(
s_axis_rc_tready,
m_axis_rq_tdata,
m_axis_rq_tkeep,
m_axis_rq_tvalid,
m_axis_rq_tlast,
m_axis_rq_tuser,
s_axis_read_desc_ready,
m_axis_read_desc_status_tag,
m_axis_read_desc_status_valid,
m_axi_awid,
m_axi_awaddr,
m_axi_awlen,
m_axi_awsize,
m_axi_awburst,
m_axi_awlock,
m_axi_awcache,
m_axi_awprot,
m_axi_awvalid,
m_axi_wdata,
m_axi_wstrb,
m_axi_wlast,
m_axi_wvalid,
m_axi_bready,
status_error_cor,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axi_dma_rd_64.lxt");
$dumpvars(0, test_pcie_us_axi_dma_rd_64);
end
pcie_us_axi_dma_rd #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
.PCIE_ADDR_WIDTH(PCIE_ADDR_WIDTH),
.PCIE_CLIENT_TAG(PCIE_CLIENT_TAG),
.PCIE_TAG_WIDTH(PCIE_TAG_WIDTH),
.PCIE_TAG_COUNT(PCIE_TAG_COUNT),
.PCIE_EXT_TAG_ENABLE(PCIE_EXT_TAG_ENABLE),
.LEN_WIDTH(LEN_WIDTH),
.TAG_WIDTH(TAG_WIDTH)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_rc_tdata(s_axis_rc_tdata),
.s_axis_rc_tkeep(s_axis_rc_tkeep),
.s_axis_rc_tvalid(s_axis_rc_tvalid),
.s_axis_rc_tready(s_axis_rc_tready),
.s_axis_rc_tlast(s_axis_rc_tlast),
.s_axis_rc_tuser(s_axis_rc_tuser),
.m_axis_rq_tdata(m_axis_rq_tdata),
.m_axis_rq_tkeep(m_axis_rq_tkeep),
.m_axis_rq_tvalid(m_axis_rq_tvalid),
.m_axis_rq_tready(m_axis_rq_tready),
.m_axis_rq_tlast(m_axis_rq_tlast),
.m_axis_rq_tuser(m_axis_rq_tuser),
.s_axis_pcie_rq_tag(s_axis_pcie_rq_tag),
.s_axis_pcie_rq_tag_valid(s_axis_pcie_rq_tag_valid),
.s_axis_read_desc_pcie_addr(s_axis_read_desc_pcie_addr),
.s_axis_read_desc_axi_addr(s_axis_read_desc_axi_addr),
.s_axis_read_desc_len(s_axis_read_desc_len),
.s_axis_read_desc_tag(s_axis_read_desc_tag),
.s_axis_read_desc_valid(s_axis_read_desc_valid),
.s_axis_read_desc_ready(s_axis_read_desc_ready),
.m_axis_read_desc_status_tag(m_axis_read_desc_status_tag),
.m_axis_read_desc_status_valid(m_axis_read_desc_status_valid),
.m_axi_awid(m_axi_awid),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awlen(m_axi_awlen),
.m_axi_awsize(m_axi_awsize),
.m_axi_awburst(m_axi_awburst),
.m_axi_awlock(m_axi_awlock),
.m_axi_awcache(m_axi_awcache),
.m_axi_awprot(m_axi_awprot),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wstrb(m_axi_wstrb),
.m_axi_wlast(m_axi_wlast),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
.enable(enable),
.ext_tag_enable(ext_tag_enable),
.requester_id(requester_id),
.requester_id_enable(requester_id_enable),
.max_read_request_size(max_read_request_size),
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
endmodule

View File

@ -0,0 +1,449 @@
#!/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 os
import pcie
import pcie_us
import axi
import axis_ep
module = 'pcie_us_axi_dma_wr'
testbench = 'test_%s_128' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 128
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
PCIE_ADDR_WIDTH = 64
LEN_WIDTH = 20
TAG_WIDTH = 8
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
m_axis_rq_tready = Signal(bool(0))
s_axis_write_desc_pcie_addr = Signal(intbv(0)[PCIE_ADDR_WIDTH:])
s_axis_write_desc_axi_addr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
s_axis_write_desc_len = Signal(intbv(0)[LEN_WIDTH:])
s_axis_write_desc_tag = Signal(intbv(0)[TAG_WIDTH:])
s_axis_write_desc_valid = Signal(bool(0))
m_axi_arready = Signal(bool(0))
m_axi_rid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_rdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_rresp = Signal(intbv(0)[2:])
m_axi_rlast = Signal(bool(0))
m_axi_rvalid = Signal(bool(0))
enable = Signal(bool(0))
requester_id = Signal(intbv(0)[16:])
requester_id_enable = Signal(bool(0))
max_payload_size = Signal(intbv(0)[3:])
# Outputs
m_axis_rq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_rq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_rq_tvalid = Signal(bool(0))
m_axis_rq_tlast = Signal(bool(0))
m_axis_rq_tuser = Signal(intbv(0)[60:])
s_axis_write_desc_ready = Signal(bool(0))
m_axis_write_desc_status_tag = Signal(intbv(0)[TAG_WIDTH:])
m_axis_write_desc_status_valid = Signal(bool(0))
m_axi_arid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_araddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_arlen = Signal(intbv(0)[8:])
m_axi_arsize = Signal(intbv(4)[3:])
m_axi_arburst = Signal(intbv(1)[2:])
m_axi_arlock = Signal(bool(0))
m_axi_arcache = Signal(intbv(3)[4:])
m_axi_arprot = Signal(intbv(2)[3:])
m_axi_arvalid = Signal(bool(0))
m_axi_rready = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_arid=m_axi_arid,
s_axi_araddr=m_axi_araddr,
s_axi_arlen=m_axi_arlen,
s_axi_arsize=m_axi_arsize,
s_axi_arburst=m_axi_arburst,
s_axi_arlock=m_axi_arlock,
s_axi_arcache=m_axi_arcache,
s_axi_arprot=m_axi_arprot,
s_axi_arvalid=m_axi_arvalid,
s_axi_arready=m_axi_arready,
s_axi_rid=m_axi_rid,
s_axi_rdata=m_axi_rdata,
s_axi_rresp=m_axi_rresp,
s_axi_rlast=m_axi_rlast,
s_axi_rvalid=m_axi_rvalid,
s_axi_rready=m_axi_rready,
name='port0'
)
write_desc_source = axis_ep.AXIStreamSource()
write_desc_source_logic = write_desc_source.create_logic(
user_clk,
user_reset,
tdata=(s_axis_write_desc_pcie_addr, s_axis_write_desc_axi_addr, s_axis_write_desc_len, s_axis_write_desc_tag),
tvalid=s_axis_write_desc_valid,
tready=s_axis_write_desc_ready,
name='write_desc_source'
)
write_desc_status_sink = axis_ep.AXIStreamSink()
write_desc_status_sink_logic = write_desc_status_sink.create_logic(
user_clk,
user_reset,
tdata=(m_axis_write_desc_status_tag,),
tvalid=m_axis_write_desc_status_valid,
name='write_desc_status_sink'
)
# PCIe devices
rc = pcie.RootComplex()
mem_base, mem_data = rc.alloc_region(16*1024*1024)
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 4
dev.user_clock_frequency = 250e6
rc.make_port().connect(dev)
cq_pause = Signal(bool(0))
cc_pause = Signal(bool(0))
rq_pause = Signal(bool(0))
rc_pause = Signal(bool(0))
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_cq_tuser=Signal(intbv(0)[85:]),
m_axis_cq_tlast=Signal(bool(0)),
m_axis_cq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_cq_tvalid=Signal(bool(0)),
m_axis_cq_tready=Signal(bool(1)),
#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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_cc_tuser=Signal(intbv(0)[33:]),
s_axis_cc_tlast=Signal(bool(0)),
s_axis_cc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_cc_tvalid=Signal(bool(0)),
s_axis_cc_tready=Signal(bool(0)),
# Requester reQuest Interface
s_axis_rq_tdata=m_axis_rq_tdata,
s_axis_rq_tuser=m_axis_rq_tuser,
s_axis_rq_tlast=m_axis_rq_tlast,
s_axis_rq_tkeep=m_axis_rq_tkeep,
s_axis_rq_tvalid=m_axis_rq_tvalid,
s_axis_rq_tready=m_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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_rc_tuser=Signal(intbv(0)[75:]),
m_axis_rc_tlast=Signal(bool(0)),
m_axis_rc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_rc_tvalid=Signal(bool(0)),
m_axis_rc_tready=Signal(bool(0)),
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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,
cq_pause=cq_pause,
cc_pause=cc_pause,
rq_pause=rq_pause,
rc_pause=rc_pause
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
m_axis_rq_tdata=m_axis_rq_tdata,
m_axis_rq_tkeep=m_axis_rq_tkeep,
m_axis_rq_tvalid=m_axis_rq_tvalid,
m_axis_rq_tready=m_axis_rq_tready,
m_axis_rq_tlast=m_axis_rq_tlast,
m_axis_rq_tuser=m_axis_rq_tuser,
s_axis_write_desc_pcie_addr=s_axis_write_desc_pcie_addr,
s_axis_write_desc_axi_addr=s_axis_write_desc_axi_addr,
s_axis_write_desc_len=s_axis_write_desc_len,
s_axis_write_desc_tag=s_axis_write_desc_tag,
s_axis_write_desc_valid=s_axis_write_desc_valid,
s_axis_write_desc_ready=s_axis_write_desc_ready,
m_axis_write_desc_status_tag=m_axis_write_desc_status_tag,
m_axis_write_desc_status_valid=m_axis_write_desc_status_valid,
m_axi_arid=m_axi_arid,
m_axi_araddr=m_axi_araddr,
m_axi_arlen=m_axi_arlen,
m_axi_arsize=m_axi_arsize,
m_axi_arburst=m_axi_arburst,
m_axi_arlock=m_axi_arlock,
m_axi_arcache=m_axi_arcache,
m_axi_arprot=m_axi_arprot,
m_axi_arvalid=m_axi_arvalid,
m_axi_arready=m_axi_arready,
m_axi_rid=m_axi_rid,
m_axi_rdata=m_axi_rdata,
m_axi_rresp=m_axi_rresp,
m_axi_rlast=m_axi_rlast,
m_axi_rvalid=m_axi_rvalid,
m_axi_rready=m_axi_rready,
enable=enable,
requester_id=requester_id,
requester_id_enable=requester_id_enable,
max_payload_size=max_payload_size
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
cq_pause_toggle = Signal(bool(0))
cc_pause_toggle = Signal(bool(0))
rq_pause_toggle = Signal(bool(0))
rc_pause_toggle = Signal(bool(0))
@instance
def pause_toggle():
while True:
if (cq_pause_toggle or cc_pause_toggle or rq_pause_toggle or rc_pause_toggle):
cq_pause.next = cq_pause_toggle
cc_pause.next = cc_pause_toggle
rq_pause.next = rq_pause_toggle
rc_pause.next = rc_pause_toggle
yield user_clk.posedge
yield user_clk.posedge
yield user_clk.posedge
cq_pause.next = 0
cc_pause.next = 0
rq_pause.next = 0
rc_pause.next = 0
yield user_clk.posedge
@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
# testbench stimulus
cur_tag = 1
max_payload_size.next = 0
enable.next = 1
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate(enable_bus_mastering=True)
yield delay(100)
yield user_clk.posedge
print("test 2: PCIe write")
current_test.next = 2
pcie_addr = 0x00000000
axi_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
axi_ram_inst.write_mem(axi_addr, test_data)
data = axi_ram_inst.read_mem(axi_addr, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
write_desc_source.send([(mem_base+pcie_addr, axi_addr, len(test_data), cur_tag)])
yield write_desc_status_sink.wait(1000)
yield delay(50)
status = write_desc_status_sink.recv()
print(status)
assert status.data[0][0] == cur_tag
data = mem_data[pcie_addr:pcie_addr+32]
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert mem_data[pcie_addr:pcie_addr+len(test_data)] == test_data
cur_tag = (cur_tag + 1) % 256
yield delay(100)
yield user_clk.posedge
print("test 3: various writes")
current_test.next = 3
for length in list(range(1,19))+list(range(128-4,128+4))+[1024]:
for pcie_offset in list(range(8,13))+list(range(4096-4,4096+4)):
for axi_offset in list(range(8,25))+list(range(4096-16,4096)):
for pause in [False, True]:
print("length %d, pcie_offset %d, axi_offset %d"% (length, pcie_offset, axi_offset))
#pcie_addr = length * 0x100000000 + pcie_offset * 0x10000 + offset
pcie_addr = pcie_offset
axi_addr = axi_offset
test_data = bytearray([x%256 for x in range(length)])
axi_ram_inst.write_mem(axi_addr & 0xffff80, b'\x55'*(len(test_data)+256))
mem_data[(pcie_addr-1) & 0xffff80:((pcie_addr-1) & 0xffff80)+len(test_data)+256] = b'\xaa'*(len(test_data)+256)
axi_ram_inst.write_mem(axi_addr, test_data)
data = axi_ram_inst.read_mem(axi_addr&0xfffff0, 64)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
rq_pause_toggle.next = pause
write_desc_source.send([(mem_base+pcie_addr, axi_addr, len(test_data), cur_tag)])
yield write_desc_status_sink.wait(4000)
yield delay(50)
rq_pause_toggle.next = 0
status = write_desc_status_sink.recv()
print(status)
assert status.data[0][0] == cur_tag
data = mem_data[pcie_addr&0xfffff0:(pcie_addr&0xfffff0)+64]
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert mem_data[pcie_addr-1:pcie_addr+len(test_data)+1] == b'\xaa'+test_data+b'\xaa'
cur_tag = (cur_tag + 1) % 256
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,188 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_dma_wr
*/
module test_pcie_us_axi_dma_wr_128;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 128;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
parameter PCIE_ADDR_WIDTH = 64;
parameter LEN_WIDTH = 20;
parameter TAG_WIDTH = 8;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg m_axis_rq_tready = 0;
reg [PCIE_ADDR_WIDTH-1:0] s_axis_write_desc_pcie_addr = 0;
reg [AXI_ADDR_WIDTH-1:0] s_axis_write_desc_axi_addr = 0;
reg [LEN_WIDTH-1:0] s_axis_write_desc_len = 0;
reg [TAG_WIDTH-1:0] s_axis_write_desc_tag = 0;
reg s_axis_write_desc_valid = 0;
reg m_axi_arready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_rid = 0;
reg [AXI_DATA_WIDTH-1:0] m_axi_rdata = 0;
reg [1:0] m_axi_rresp = 0;
reg m_axi_rlast = 0;
reg m_axi_rvalid = 0;
reg enable = 0;
reg [15:0] requester_id = 0;
reg requester_id_enable = 0;
reg [2:0] max_payload_size = 0;
// Outputs
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rq_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rq_tkeep;
wire m_axis_rq_tvalid;
wire m_axis_rq_tlast;
wire [59:0] m_axis_rq_tuser;
wire s_axis_write_desc_ready;
wire [TAG_WIDTH-1:0] m_axis_write_desc_status_tag;
wire m_axis_write_desc_status_valid;
wire [AXI_ID_WIDTH-1:0] m_axi_arid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr;
wire [7:0] m_axi_arlen;
wire [2:0] m_axi_arsize;
wire [1:0] m_axi_arburst;
wire m_axi_arlock;
wire [3:0] m_axi_arcache;
wire [2:0] m_axi_arprot;
wire m_axi_arvalid;
wire m_axi_rready;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
m_axis_rq_tready,
s_axis_write_desc_pcie_addr,
s_axis_write_desc_axi_addr,
s_axis_write_desc_len,
s_axis_write_desc_tag,
s_axis_write_desc_valid,
m_axi_arready,
m_axi_rid,
m_axi_rdata,
m_axi_rresp,
m_axi_rlast,
m_axi_rvalid,
enable,
requester_id,
requester_id_enable,
max_payload_size
);
$to_myhdl(
m_axis_rq_tdata,
m_axis_rq_tkeep,
m_axis_rq_tvalid,
m_axis_rq_tlast,
m_axis_rq_tuser,
s_axis_write_desc_ready,
m_axis_write_desc_status_tag,
m_axis_write_desc_status_valid,
m_axi_arid,
m_axi_araddr,
m_axi_arlen,
m_axi_arsize,
m_axi_arburst,
m_axi_arlock,
m_axi_arcache,
m_axi_arprot,
m_axi_arvalid,
m_axi_rready
);
// dump file
$dumpfile("test_pcie_us_axi_dma_wr_128.lxt");
$dumpvars(0, test_pcie_us_axi_dma_wr_128);
end
pcie_us_axi_dma_wr #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
.PCIE_ADDR_WIDTH(PCIE_ADDR_WIDTH),
.LEN_WIDTH(LEN_WIDTH),
.TAG_WIDTH(TAG_WIDTH)
)
UUT (
.clk(clk),
.rst(rst),
.m_axis_rq_tdata(m_axis_rq_tdata),
.m_axis_rq_tkeep(m_axis_rq_tkeep),
.m_axis_rq_tvalid(m_axis_rq_tvalid),
.m_axis_rq_tready(m_axis_rq_tready),
.m_axis_rq_tlast(m_axis_rq_tlast),
.m_axis_rq_tuser(m_axis_rq_tuser),
.s_axis_write_desc_pcie_addr(s_axis_write_desc_pcie_addr),
.s_axis_write_desc_axi_addr(s_axis_write_desc_axi_addr),
.s_axis_write_desc_len(s_axis_write_desc_len),
.s_axis_write_desc_tag(s_axis_write_desc_tag),
.s_axis_write_desc_valid(s_axis_write_desc_valid),
.s_axis_write_desc_ready(s_axis_write_desc_ready),
.m_axis_write_desc_status_tag(m_axis_write_desc_status_tag),
.m_axis_write_desc_status_valid(m_axis_write_desc_status_valid),
.m_axi_arid(m_axi_arid),
.m_axi_araddr(m_axi_araddr),
.m_axi_arlen(m_axi_arlen),
.m_axi_arsize(m_axi_arsize),
.m_axi_arburst(m_axi_arburst),
.m_axi_arlock(m_axi_arlock),
.m_axi_arcache(m_axi_arcache),
.m_axi_arprot(m_axi_arprot),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rid(m_axi_rid),
.m_axi_rdata(m_axi_rdata),
.m_axi_rresp(m_axi_rresp),
.m_axi_rlast(m_axi_rlast),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready),
.enable(enable),
.requester_id(requester_id),
.requester_id_enable(requester_id_enable),
.max_payload_size(max_payload_size)
);
endmodule

View File

@ -0,0 +1,449 @@
#!/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 os
import pcie
import pcie_us
import axi
import axis_ep
module = 'pcie_us_axi_dma_wr'
testbench = 'test_%s_256' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 256
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
PCIE_ADDR_WIDTH = 64
LEN_WIDTH = 20
TAG_WIDTH = 8
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
m_axis_rq_tready = Signal(bool(0))
s_axis_write_desc_pcie_addr = Signal(intbv(0)[PCIE_ADDR_WIDTH:])
s_axis_write_desc_axi_addr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
s_axis_write_desc_len = Signal(intbv(0)[LEN_WIDTH:])
s_axis_write_desc_tag = Signal(intbv(0)[TAG_WIDTH:])
s_axis_write_desc_valid = Signal(bool(0))
m_axi_arready = Signal(bool(0))
m_axi_rid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_rdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_rresp = Signal(intbv(0)[2:])
m_axi_rlast = Signal(bool(0))
m_axi_rvalid = Signal(bool(0))
enable = Signal(bool(0))
requester_id = Signal(intbv(0)[16:])
requester_id_enable = Signal(bool(0))
max_payload_size = Signal(intbv(0)[3:])
# Outputs
m_axis_rq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_rq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_rq_tvalid = Signal(bool(0))
m_axis_rq_tlast = Signal(bool(0))
m_axis_rq_tuser = Signal(intbv(0)[60:])
s_axis_write_desc_ready = Signal(bool(0))
m_axis_write_desc_status_tag = Signal(intbv(0)[TAG_WIDTH:])
m_axis_write_desc_status_valid = Signal(bool(0))
m_axi_arid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_araddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_arlen = Signal(intbv(0)[8:])
m_axi_arsize = Signal(intbv(5)[3:])
m_axi_arburst = Signal(intbv(1)[2:])
m_axi_arlock = Signal(bool(0))
m_axi_arcache = Signal(intbv(3)[4:])
m_axi_arprot = Signal(intbv(2)[3:])
m_axi_arvalid = Signal(bool(0))
m_axi_rready = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_arid=m_axi_arid,
s_axi_araddr=m_axi_araddr,
s_axi_arlen=m_axi_arlen,
s_axi_arsize=m_axi_arsize,
s_axi_arburst=m_axi_arburst,
s_axi_arlock=m_axi_arlock,
s_axi_arcache=m_axi_arcache,
s_axi_arprot=m_axi_arprot,
s_axi_arvalid=m_axi_arvalid,
s_axi_arready=m_axi_arready,
s_axi_rid=m_axi_rid,
s_axi_rdata=m_axi_rdata,
s_axi_rresp=m_axi_rresp,
s_axi_rlast=m_axi_rlast,
s_axi_rvalid=m_axi_rvalid,
s_axi_rready=m_axi_rready,
name='port0'
)
write_desc_source = axis_ep.AXIStreamSource()
write_desc_source_logic = write_desc_source.create_logic(
user_clk,
user_reset,
tdata=(s_axis_write_desc_pcie_addr, s_axis_write_desc_axi_addr, s_axis_write_desc_len, s_axis_write_desc_tag),
tvalid=s_axis_write_desc_valid,
tready=s_axis_write_desc_ready,
name='write_desc_source'
)
write_desc_status_sink = axis_ep.AXIStreamSink()
write_desc_status_sink_logic = write_desc_status_sink.create_logic(
user_clk,
user_reset,
tdata=(m_axis_write_desc_status_tag,),
tvalid=m_axis_write_desc_status_valid,
name='write_desc_status_sink'
)
# PCIe devices
rc = pcie.RootComplex()
mem_base, mem_data = rc.alloc_region(16*1024*1024)
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 8
dev.user_clock_frequency = 250e6
rc.make_port().connect(dev)
cq_pause = Signal(bool(0))
cc_pause = Signal(bool(0))
rq_pause = Signal(bool(0))
rc_pause = Signal(bool(0))
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_cq_tuser=Signal(intbv(0)[85:]),
m_axis_cq_tlast=Signal(bool(0)),
m_axis_cq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_cq_tvalid=Signal(bool(0)),
m_axis_cq_tready=Signal(bool(1)),
#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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_cc_tuser=Signal(intbv(0)[33:]),
s_axis_cc_tlast=Signal(bool(0)),
s_axis_cc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_cc_tvalid=Signal(bool(0)),
s_axis_cc_tready=Signal(bool(0)),
# Requester reQuest Interface
s_axis_rq_tdata=m_axis_rq_tdata,
s_axis_rq_tuser=m_axis_rq_tuser,
s_axis_rq_tlast=m_axis_rq_tlast,
s_axis_rq_tkeep=m_axis_rq_tkeep,
s_axis_rq_tvalid=m_axis_rq_tvalid,
s_axis_rq_tready=m_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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_rc_tuser=Signal(intbv(0)[75:]),
m_axis_rc_tlast=Signal(bool(0)),
m_axis_rc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_rc_tvalid=Signal(bool(0)),
m_axis_rc_tready=Signal(bool(0)),
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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,
cq_pause=cq_pause,
cc_pause=cc_pause,
rq_pause=rq_pause,
rc_pause=rc_pause
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
m_axis_rq_tdata=m_axis_rq_tdata,
m_axis_rq_tkeep=m_axis_rq_tkeep,
m_axis_rq_tvalid=m_axis_rq_tvalid,
m_axis_rq_tready=m_axis_rq_tready,
m_axis_rq_tlast=m_axis_rq_tlast,
m_axis_rq_tuser=m_axis_rq_tuser,
s_axis_write_desc_pcie_addr=s_axis_write_desc_pcie_addr,
s_axis_write_desc_axi_addr=s_axis_write_desc_axi_addr,
s_axis_write_desc_len=s_axis_write_desc_len,
s_axis_write_desc_tag=s_axis_write_desc_tag,
s_axis_write_desc_valid=s_axis_write_desc_valid,
s_axis_write_desc_ready=s_axis_write_desc_ready,
m_axis_write_desc_status_tag=m_axis_write_desc_status_tag,
m_axis_write_desc_status_valid=m_axis_write_desc_status_valid,
m_axi_arid=m_axi_arid,
m_axi_araddr=m_axi_araddr,
m_axi_arlen=m_axi_arlen,
m_axi_arsize=m_axi_arsize,
m_axi_arburst=m_axi_arburst,
m_axi_arlock=m_axi_arlock,
m_axi_arcache=m_axi_arcache,
m_axi_arprot=m_axi_arprot,
m_axi_arvalid=m_axi_arvalid,
m_axi_arready=m_axi_arready,
m_axi_rid=m_axi_rid,
m_axi_rdata=m_axi_rdata,
m_axi_rresp=m_axi_rresp,
m_axi_rlast=m_axi_rlast,
m_axi_rvalid=m_axi_rvalid,
m_axi_rready=m_axi_rready,
enable=enable,
requester_id=requester_id,
requester_id_enable=requester_id_enable,
max_payload_size=max_payload_size
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
cq_pause_toggle = Signal(bool(0))
cc_pause_toggle = Signal(bool(0))
rq_pause_toggle = Signal(bool(0))
rc_pause_toggle = Signal(bool(0))
@instance
def pause_toggle():
while True:
if (cq_pause_toggle or cc_pause_toggle or rq_pause_toggle or rc_pause_toggle):
cq_pause.next = cq_pause_toggle
cc_pause.next = cc_pause_toggle
rq_pause.next = rq_pause_toggle
rc_pause.next = rc_pause_toggle
yield user_clk.posedge
yield user_clk.posedge
yield user_clk.posedge
cq_pause.next = 0
cc_pause.next = 0
rq_pause.next = 0
rc_pause.next = 0
yield user_clk.posedge
@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
# testbench stimulus
cur_tag = 1
max_payload_size.next = 0
enable.next = 1
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate(enable_bus_mastering=True)
yield delay(100)
yield user_clk.posedge
print("test 2: PCIe write")
current_test.next = 2
pcie_addr = 0x00000000
axi_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
axi_ram_inst.write_mem(axi_addr, test_data)
data = axi_ram_inst.read_mem(axi_addr, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
write_desc_source.send([(mem_base+pcie_addr, axi_addr, len(test_data), cur_tag)])
yield write_desc_status_sink.wait(1000)
yield delay(50)
status = write_desc_status_sink.recv()
print(status)
assert status.data[0][0] == cur_tag
data = mem_data[pcie_addr:pcie_addr+32]
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert mem_data[pcie_addr:pcie_addr+len(test_data)] == test_data
cur_tag = (cur_tag + 1) % 256
yield delay(100)
yield user_clk.posedge
print("test 3: various writes")
current_test.next = 3
for length in list(range(1,35))+list(range(128-4,128+4))+[1024]:
for pcie_offset in list(range(8,13))+list(range(4096-4,4096+4)):
for axi_offset in list(range(8,41))+list(range(4096-32,4096)):
for pause in [False, True]:
print("length %d, pcie_offset %d, axi_offset %d"% (length, pcie_offset, axi_offset))
#pcie_addr = length * 0x100000000 + pcie_offset * 0x10000 + offset
pcie_addr = pcie_offset
axi_addr = axi_offset
test_data = bytearray([x%256 for x in range(length)])
axi_ram_inst.write_mem(axi_addr & 0xffff80, b'\x55'*(len(test_data)+256))
mem_data[(pcie_addr-1) & 0xffff80:((pcie_addr-1) & 0xffff80)+len(test_data)+256] = b'\xaa'*(len(test_data)+256)
axi_ram_inst.write_mem(axi_addr, test_data)
data = axi_ram_inst.read_mem(axi_addr&0xfffff0, 64)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
rq_pause_toggle.next = pause
write_desc_source.send([(mem_base+pcie_addr, axi_addr, len(test_data), cur_tag)])
yield write_desc_status_sink.wait(4000)
yield delay(50)
rq_pause_toggle.next = 0
status = write_desc_status_sink.recv()
print(status)
assert status.data[0][0] == cur_tag
data = mem_data[pcie_addr&0xfffff0:(pcie_addr&0xfffff0)+64]
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert mem_data[pcie_addr-1:pcie_addr+len(test_data)+1] == b'\xaa'+test_data+b'\xaa'
cur_tag = (cur_tag + 1) % 256
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,188 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_dma_wr
*/
module test_pcie_us_axi_dma_wr_256;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 256;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
parameter PCIE_ADDR_WIDTH = 64;
parameter LEN_WIDTH = 20;
parameter TAG_WIDTH = 8;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg m_axis_rq_tready = 0;
reg [PCIE_ADDR_WIDTH-1:0] s_axis_write_desc_pcie_addr = 0;
reg [AXI_ADDR_WIDTH-1:0] s_axis_write_desc_axi_addr = 0;
reg [LEN_WIDTH-1:0] s_axis_write_desc_len = 0;
reg [TAG_WIDTH-1:0] s_axis_write_desc_tag = 0;
reg s_axis_write_desc_valid = 0;
reg m_axi_arready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_rid = 0;
reg [AXI_DATA_WIDTH-1:0] m_axi_rdata = 0;
reg [1:0] m_axi_rresp = 0;
reg m_axi_rlast = 0;
reg m_axi_rvalid = 0;
reg enable = 0;
reg [15:0] requester_id = 0;
reg requester_id_enable = 0;
reg [2:0] max_payload_size = 0;
// Outputs
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rq_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rq_tkeep;
wire m_axis_rq_tvalid;
wire m_axis_rq_tlast;
wire [59:0] m_axis_rq_tuser;
wire s_axis_write_desc_ready;
wire [TAG_WIDTH-1:0] m_axis_write_desc_status_tag;
wire m_axis_write_desc_status_valid;
wire [AXI_ID_WIDTH-1:0] m_axi_arid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr;
wire [7:0] m_axi_arlen;
wire [2:0] m_axi_arsize;
wire [1:0] m_axi_arburst;
wire m_axi_arlock;
wire [3:0] m_axi_arcache;
wire [2:0] m_axi_arprot;
wire m_axi_arvalid;
wire m_axi_rready;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
m_axis_rq_tready,
s_axis_write_desc_pcie_addr,
s_axis_write_desc_axi_addr,
s_axis_write_desc_len,
s_axis_write_desc_tag,
s_axis_write_desc_valid,
m_axi_arready,
m_axi_rid,
m_axi_rdata,
m_axi_rresp,
m_axi_rlast,
m_axi_rvalid,
enable,
requester_id,
requester_id_enable,
max_payload_size
);
$to_myhdl(
m_axis_rq_tdata,
m_axis_rq_tkeep,
m_axis_rq_tvalid,
m_axis_rq_tlast,
m_axis_rq_tuser,
s_axis_write_desc_ready,
m_axis_write_desc_status_tag,
m_axis_write_desc_status_valid,
m_axi_arid,
m_axi_araddr,
m_axi_arlen,
m_axi_arsize,
m_axi_arburst,
m_axi_arlock,
m_axi_arcache,
m_axi_arprot,
m_axi_arvalid,
m_axi_rready
);
// dump file
$dumpfile("test_pcie_us_axi_dma_wr_256.lxt");
$dumpvars(0, test_pcie_us_axi_dma_wr_256);
end
pcie_us_axi_dma_wr #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
.PCIE_ADDR_WIDTH(PCIE_ADDR_WIDTH),
.LEN_WIDTH(LEN_WIDTH),
.TAG_WIDTH(TAG_WIDTH)
)
UUT (
.clk(clk),
.rst(rst),
.m_axis_rq_tdata(m_axis_rq_tdata),
.m_axis_rq_tkeep(m_axis_rq_tkeep),
.m_axis_rq_tvalid(m_axis_rq_tvalid),
.m_axis_rq_tready(m_axis_rq_tready),
.m_axis_rq_tlast(m_axis_rq_tlast),
.m_axis_rq_tuser(m_axis_rq_tuser),
.s_axis_write_desc_pcie_addr(s_axis_write_desc_pcie_addr),
.s_axis_write_desc_axi_addr(s_axis_write_desc_axi_addr),
.s_axis_write_desc_len(s_axis_write_desc_len),
.s_axis_write_desc_tag(s_axis_write_desc_tag),
.s_axis_write_desc_valid(s_axis_write_desc_valid),
.s_axis_write_desc_ready(s_axis_write_desc_ready),
.m_axis_write_desc_status_tag(m_axis_write_desc_status_tag),
.m_axis_write_desc_status_valid(m_axis_write_desc_status_valid),
.m_axi_arid(m_axi_arid),
.m_axi_araddr(m_axi_araddr),
.m_axi_arlen(m_axi_arlen),
.m_axi_arsize(m_axi_arsize),
.m_axi_arburst(m_axi_arburst),
.m_axi_arlock(m_axi_arlock),
.m_axi_arcache(m_axi_arcache),
.m_axi_arprot(m_axi_arprot),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rid(m_axi_rid),
.m_axi_rdata(m_axi_rdata),
.m_axi_rresp(m_axi_rresp),
.m_axi_rlast(m_axi_rlast),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready),
.enable(enable),
.requester_id(requester_id),
.requester_id_enable(requester_id_enable),
.max_payload_size(max_payload_size)
);
endmodule

View File

@ -0,0 +1,450 @@
#!/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 os
import pcie
import pcie_us
import axi
import axis_ep
module = 'pcie_us_axi_dma_wr'
testbench = 'test_%s_64' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 64
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
PCIE_ADDR_WIDTH = 64
LEN_WIDTH = 20
TAG_WIDTH = 8
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
m_axis_rq_tready = Signal(bool(0))
s_axis_write_desc_pcie_addr = Signal(intbv(0)[PCIE_ADDR_WIDTH:])
s_axis_write_desc_axi_addr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
s_axis_write_desc_len = Signal(intbv(0)[LEN_WIDTH:])
s_axis_write_desc_tag = Signal(intbv(0)[TAG_WIDTH:])
s_axis_write_desc_valid = Signal(bool(0))
m_axi_arready = Signal(bool(0))
m_axi_rid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_rdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_rresp = Signal(intbv(0)[2:])
m_axi_rlast = Signal(bool(0))
m_axi_rvalid = Signal(bool(0))
enable = Signal(bool(0))
requester_id = Signal(intbv(0)[16:])
requester_id_enable = Signal(bool(0))
max_payload_size = Signal(intbv(0)[3:])
# Outputs
m_axis_rq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_rq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_rq_tvalid = Signal(bool(0))
m_axis_rq_tlast = Signal(bool(0))
m_axis_rq_tuser = Signal(intbv(0)[60:])
s_axis_write_desc_ready = Signal(bool(0))
m_axis_write_desc_status_tag = Signal(intbv(0)[TAG_WIDTH:])
m_axis_write_desc_status_valid = Signal(bool(0))
m_axi_arid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_araddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_arlen = Signal(intbv(0)[8:])
m_axi_arsize = Signal(intbv(3)[3:])
m_axi_arburst = Signal(intbv(1)[2:])
m_axi_arlock = Signal(bool(0))
m_axi_arcache = Signal(intbv(3)[4:])
m_axi_arprot = Signal(intbv(2)[3:])
m_axi_arvalid = Signal(bool(0))
m_axi_rready = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_arid=m_axi_arid,
s_axi_araddr=m_axi_araddr,
s_axi_arlen=m_axi_arlen,
s_axi_arsize=m_axi_arsize,
s_axi_arburst=m_axi_arburst,
s_axi_arlock=m_axi_arlock,
s_axi_arcache=m_axi_arcache,
s_axi_arprot=m_axi_arprot,
s_axi_arvalid=m_axi_arvalid,
s_axi_arready=m_axi_arready,
s_axi_rid=m_axi_rid,
s_axi_rdata=m_axi_rdata,
s_axi_rresp=m_axi_rresp,
s_axi_rlast=m_axi_rlast,
s_axi_rvalid=m_axi_rvalid,
s_axi_rready=m_axi_rready,
name='port0'
)
write_desc_source = axis_ep.AXIStreamSource()
write_desc_source_logic = write_desc_source.create_logic(
user_clk,
user_reset,
tdata=(s_axis_write_desc_pcie_addr, s_axis_write_desc_axi_addr, s_axis_write_desc_len, s_axis_write_desc_tag),
tvalid=s_axis_write_desc_valid,
tready=s_axis_write_desc_ready,
name='write_desc_source'
)
write_desc_status_sink = axis_ep.AXIStreamSink()
write_desc_status_sink_logic = write_desc_status_sink.create_logic(
user_clk,
user_reset,
tdata=(m_axis_write_desc_status_tag,),
tvalid=m_axis_write_desc_status_valid,
name='write_desc_status_sink'
)
# PCIe devices
rc = pcie.RootComplex()
mem_base, mem_data = rc.alloc_region(16*1024*1024)
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 2
dev.user_clock_frequency = 250e6
rc.make_port().connect(dev)
cq_pause = Signal(bool(0))
cc_pause = Signal(bool(0))
rq_pause = Signal(bool(0))
rc_pause = Signal(bool(0))
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_cq_tuser=Signal(intbv(0)[85:]),
m_axis_cq_tlast=Signal(bool(0)),
m_axis_cq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_cq_tvalid=Signal(bool(0)),
m_axis_cq_tready=Signal(bool(1)),
#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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_cc_tuser=Signal(intbv(0)[33:]),
s_axis_cc_tlast=Signal(bool(0)),
s_axis_cc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_cc_tvalid=Signal(bool(0)),
s_axis_cc_tready=Signal(bool(0)),
# Requester reQuest Interface
s_axis_rq_tdata=m_axis_rq_tdata,
s_axis_rq_tuser=m_axis_rq_tuser,
s_axis_rq_tlast=m_axis_rq_tlast,
s_axis_rq_tkeep=m_axis_rq_tkeep,
s_axis_rq_tvalid=m_axis_rq_tvalid,
s_axis_rq_tready=m_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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_rc_tuser=Signal(intbv(0)[75:]),
m_axis_rc_tlast=Signal(bool(0)),
m_axis_rc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_rc_tvalid=Signal(bool(0)),
m_axis_rc_tready=Signal(bool(0)),
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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,
cq_pause=cq_pause,
cc_pause=cc_pause,
rq_pause=rq_pause,
rc_pause=rc_pause
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
m_axis_rq_tdata=m_axis_rq_tdata,
m_axis_rq_tkeep=m_axis_rq_tkeep,
m_axis_rq_tvalid=m_axis_rq_tvalid,
m_axis_rq_tready=m_axis_rq_tready,
m_axis_rq_tlast=m_axis_rq_tlast,
m_axis_rq_tuser=m_axis_rq_tuser,
s_axis_write_desc_pcie_addr=s_axis_write_desc_pcie_addr,
s_axis_write_desc_axi_addr=s_axis_write_desc_axi_addr,
s_axis_write_desc_len=s_axis_write_desc_len,
s_axis_write_desc_tag=s_axis_write_desc_tag,
s_axis_write_desc_valid=s_axis_write_desc_valid,
s_axis_write_desc_ready=s_axis_write_desc_ready,
m_axis_write_desc_status_tag=m_axis_write_desc_status_tag,
m_axis_write_desc_status_valid=m_axis_write_desc_status_valid,
m_axi_arid=m_axi_arid,
m_axi_araddr=m_axi_araddr,
m_axi_arlen=m_axi_arlen,
m_axi_arsize=m_axi_arsize,
m_axi_arburst=m_axi_arburst,
m_axi_arlock=m_axi_arlock,
m_axi_arcache=m_axi_arcache,
m_axi_arprot=m_axi_arprot,
m_axi_arvalid=m_axi_arvalid,
m_axi_arready=m_axi_arready,
m_axi_rid=m_axi_rid,
m_axi_rdata=m_axi_rdata,
m_axi_rresp=m_axi_rresp,
m_axi_rlast=m_axi_rlast,
m_axi_rvalid=m_axi_rvalid,
m_axi_rready=m_axi_rready,
enable=enable,
requester_id=requester_id,
requester_id_enable=requester_id_enable,
max_payload_size=max_payload_size
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
cq_pause_toggle = Signal(bool(0))
cc_pause_toggle = Signal(bool(0))
rq_pause_toggle = Signal(bool(0))
rc_pause_toggle = Signal(bool(0))
@instance
def pause_toggle():
while True:
if (cq_pause_toggle or cc_pause_toggle or rq_pause_toggle or rc_pause_toggle):
cq_pause.next = cq_pause_toggle
cc_pause.next = cc_pause_toggle
rq_pause.next = rq_pause_toggle
rc_pause.next = rc_pause_toggle
yield user_clk.posedge
yield user_clk.posedge
yield user_clk.posedge
cq_pause.next = 0
cc_pause.next = 0
rq_pause.next = 0
rc_pause.next = 0
yield user_clk.posedge
@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
# testbench stimulus
cur_tag = 1
max_payload_size.next = 0
enable.next = 1
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate(enable_bus_mastering=True)
yield delay(100)
yield user_clk.posedge
print("test 2: PCIe write")
current_test.next = 2
pcie_addr = 0x00000000
axi_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
axi_ram_inst.write_mem(axi_addr, test_data)
data = axi_ram_inst.read_mem(axi_addr, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
write_desc_source.send([(mem_base+pcie_addr, axi_addr, len(test_data), cur_tag)])
yield write_desc_status_sink.wait(1000)
yield delay(50)
status = write_desc_status_sink.recv()
print(status)
assert status.data[0][0] == cur_tag
data = mem_data[pcie_addr:pcie_addr+32]
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert mem_data[pcie_addr:pcie_addr+len(test_data)] == test_data
cur_tag = (cur_tag + 1) % 256
yield delay(100)
yield user_clk.posedge
print("test 3: various writes")
current_test.next = 3
for length in list(range(1,11))+list(range(128-4,128+4))+[1024]:
for pcie_offset in list(range(8,13))+list(range(4096-4,4096+4)):
for axi_offset in list(range(8,17))+list(range(4096-8,4096)):
for pause in [False, True]:
print("length %d, pcie_offset %d, axi_offset %d"% (length, pcie_offset, axi_offset))
#pcie_addr = length * 0x100000000 + pcie_offset * 0x10000 + offset
pcie_addr = pcie_offset
axi_addr = axi_offset
test_data = bytearray([x%256 for x in range(length)])
axi_ram_inst.write_mem(axi_addr & 0xffff80, b'\x55'*(len(test_data)+256))
mem_data[(pcie_addr-1) & 0xffff80:((pcie_addr-1) & 0xffff80)+len(test_data)+256] = b'\xaa'*(len(test_data)+256)
axi_ram_inst.write_mem(axi_addr, test_data)
data = axi_ram_inst.read_mem(axi_addr&0xfffff0, 64)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
rq_pause_toggle.next = pause
write_desc_source.send([(mem_base+pcie_addr, axi_addr, len(test_data), cur_tag)])
yield write_desc_status_sink.wait(4000)
yield delay(50)
rq_pause_toggle.next = 0
status = write_desc_status_sink.recv()
print(status)
assert status.data[0][0] == cur_tag
data = mem_data[pcie_addr&0xfffff0:(pcie_addr&0xfffff0)+64]
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
print(mem_data[pcie_addr-1:pcie_addr+len(test_data)+1])
assert mem_data[pcie_addr-1:pcie_addr+len(test_data)+1] == b'\xaa'+test_data+b'\xaa'
cur_tag = (cur_tag + 1) % 256
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,188 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_dma_wr
*/
module test_pcie_us_axi_dma_wr_64;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 64;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
parameter PCIE_ADDR_WIDTH = 64;
parameter LEN_WIDTH = 20;
parameter TAG_WIDTH = 8;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg m_axis_rq_tready = 0;
reg [PCIE_ADDR_WIDTH-1:0] s_axis_write_desc_pcie_addr = 0;
reg [AXI_ADDR_WIDTH-1:0] s_axis_write_desc_axi_addr = 0;
reg [LEN_WIDTH-1:0] s_axis_write_desc_len = 0;
reg [TAG_WIDTH-1:0] s_axis_write_desc_tag = 0;
reg s_axis_write_desc_valid = 0;
reg m_axi_arready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_rid = 0;
reg [AXI_DATA_WIDTH-1:0] m_axi_rdata = 0;
reg [1:0] m_axi_rresp = 0;
reg m_axi_rlast = 0;
reg m_axi_rvalid = 0;
reg enable = 0;
reg [15:0] requester_id = 0;
reg requester_id_enable = 0;
reg [2:0] max_payload_size = 0;
// Outputs
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rq_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rq_tkeep;
wire m_axis_rq_tvalid;
wire m_axis_rq_tlast;
wire [59:0] m_axis_rq_tuser;
wire s_axis_write_desc_ready;
wire [TAG_WIDTH-1:0] m_axis_write_desc_status_tag;
wire m_axis_write_desc_status_valid;
wire [AXI_ID_WIDTH-1:0] m_axi_arid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr;
wire [7:0] m_axi_arlen;
wire [2:0] m_axi_arsize;
wire [1:0] m_axi_arburst;
wire m_axi_arlock;
wire [3:0] m_axi_arcache;
wire [2:0] m_axi_arprot;
wire m_axi_arvalid;
wire m_axi_rready;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
m_axis_rq_tready,
s_axis_write_desc_pcie_addr,
s_axis_write_desc_axi_addr,
s_axis_write_desc_len,
s_axis_write_desc_tag,
s_axis_write_desc_valid,
m_axi_arready,
m_axi_rid,
m_axi_rdata,
m_axi_rresp,
m_axi_rlast,
m_axi_rvalid,
enable,
requester_id,
requester_id_enable,
max_payload_size
);
$to_myhdl(
m_axis_rq_tdata,
m_axis_rq_tkeep,
m_axis_rq_tvalid,
m_axis_rq_tlast,
m_axis_rq_tuser,
s_axis_write_desc_ready,
m_axis_write_desc_status_tag,
m_axis_write_desc_status_valid,
m_axi_arid,
m_axi_araddr,
m_axi_arlen,
m_axi_arsize,
m_axi_arburst,
m_axi_arlock,
m_axi_arcache,
m_axi_arprot,
m_axi_arvalid,
m_axi_rready
);
// dump file
$dumpfile("test_pcie_us_axi_dma_wr_64.lxt");
$dumpvars(0, test_pcie_us_axi_dma_wr_64);
end
pcie_us_axi_dma_wr #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
.PCIE_ADDR_WIDTH(PCIE_ADDR_WIDTH),
.LEN_WIDTH(LEN_WIDTH),
.TAG_WIDTH(TAG_WIDTH)
)
UUT (
.clk(clk),
.rst(rst),
.m_axis_rq_tdata(m_axis_rq_tdata),
.m_axis_rq_tkeep(m_axis_rq_tkeep),
.m_axis_rq_tvalid(m_axis_rq_tvalid),
.m_axis_rq_tready(m_axis_rq_tready),
.m_axis_rq_tlast(m_axis_rq_tlast),
.m_axis_rq_tuser(m_axis_rq_tuser),
.s_axis_write_desc_pcie_addr(s_axis_write_desc_pcie_addr),
.s_axis_write_desc_axi_addr(s_axis_write_desc_axi_addr),
.s_axis_write_desc_len(s_axis_write_desc_len),
.s_axis_write_desc_tag(s_axis_write_desc_tag),
.s_axis_write_desc_valid(s_axis_write_desc_valid),
.s_axis_write_desc_ready(s_axis_write_desc_ready),
.m_axis_write_desc_status_tag(m_axis_write_desc_status_tag),
.m_axis_write_desc_status_valid(m_axis_write_desc_status_valid),
.m_axi_arid(m_axi_arid),
.m_axi_araddr(m_axi_araddr),
.m_axi_arlen(m_axi_arlen),
.m_axi_arsize(m_axi_arsize),
.m_axi_arburst(m_axi_arburst),
.m_axi_arlock(m_axi_arlock),
.m_axi_arcache(m_axi_arcache),
.m_axi_arprot(m_axi_arprot),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rid(m_axi_rid),
.m_axi_rdata(m_axi_rdata),
.m_axi_rresp(m_axi_rresp),
.m_axi_rlast(m_axi_rlast),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready),
.enable(enable),
.requester_id(requester_id),
.requester_id_enable(requester_id_enable),
.max_payload_size(max_payload_size)
);
endmodule

View File

@ -0,0 +1,420 @@
#!/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 os
import pcie
import pcie_us
import axi
module = 'pcie_us_axi_master'
testbench = 'test_%s_128' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("../rtl/pcie_us_axi_master_wr.v")
srcs.append("../rtl/pcie_us_axi_master_rd.v")
srcs.append("../rtl/pcie_us_axis_cq_demux.v")
srcs.append("../rtl/pulse_merge.v")
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 128
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_cq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_cq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_cq_tvalid = Signal(bool(0))
s_axis_cq_tlast = Signal(bool(0))
s_axis_cq_tuser = Signal(intbv(0)[85:])
m_axis_cc_tready = Signal(bool(0))
m_axi_awready = Signal(bool(0))
m_axi_wready = Signal(bool(0))
m_axi_bid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_bresp = Signal(intbv(0)[2:])
m_axi_bvalid = Signal(bool(0))
m_axi_arready = Signal(bool(0))
m_axi_rid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_rdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_rresp = Signal(intbv(0)[2:])
m_axi_rlast = Signal(bool(0))
m_axi_rvalid = Signal(bool(0))
completer_id = Signal(intbv(0)[16:])
completer_id_enable = Signal(bool(0))
max_payload_size = Signal(intbv(0)[3:])
# Outputs
s_axis_cq_tready = Signal(bool(0))
m_axis_cc_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_cc_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_cc_tvalid = Signal(bool(0))
m_axis_cc_tlast = Signal(bool(0))
m_axis_cc_tuser = Signal(intbv(0)[33:])
m_axi_awid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_awaddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_awlen = Signal(intbv(0)[8:])
m_axi_awsize = Signal(intbv(4)[3:])
m_axi_awburst = Signal(intbv(1)[2:])
m_axi_awlock = Signal(bool(0))
m_axi_awcache = Signal(intbv(3)[4:])
m_axi_awprot = Signal(intbv(2)[3:])
m_axi_awvalid = Signal(bool(0))
m_axi_wdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_wstrb = Signal(intbv(0)[AXI_STRB_WIDTH:])
m_axi_wlast = Signal(bool(0))
m_axi_wvalid = Signal(bool(0))
m_axi_bready = Signal(bool(0))
m_axi_arid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_araddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_arlen = Signal(intbv(0)[8:])
m_axi_arsize = Signal(intbv(4)[3:])
m_axi_arburst = Signal(intbv(1)[2:])
m_axi_arlock = Signal(bool(0))
m_axi_arcache = Signal(intbv(3)[4:])
m_axi_arprot = Signal(intbv(2)[3:])
m_axi_arvalid = Signal(bool(0))
m_axi_rready = Signal(bool(0))
status_error_cor = Signal(bool(0))
status_error_uncor = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_awid=m_axi_awid,
s_axi_awaddr=m_axi_awaddr,
s_axi_awlen=m_axi_awlen,
s_axi_awsize=m_axi_awsize,
s_axi_awburst=m_axi_awburst,
s_axi_awlock=m_axi_awlock,
s_axi_awcache=m_axi_awcache,
s_axi_awprot=m_axi_awprot,
s_axi_awvalid=m_axi_awvalid,
s_axi_awready=m_axi_awready,
s_axi_wdata=m_axi_wdata,
s_axi_wstrb=m_axi_wstrb,
s_axi_wlast=m_axi_wlast,
s_axi_wvalid=m_axi_wvalid,
s_axi_wready=m_axi_wready,
s_axi_bid=m_axi_bid,
s_axi_bresp=m_axi_bresp,
s_axi_bvalid=m_axi_bvalid,
s_axi_bready=m_axi_bready,
s_axi_arid=m_axi_arid,
s_axi_araddr=m_axi_araddr,
s_axi_arlen=m_axi_arlen,
s_axi_arsize=m_axi_arsize,
s_axi_arburst=m_axi_arburst,
s_axi_arlock=m_axi_arlock,
s_axi_arcache=m_axi_arcache,
s_axi_arprot=m_axi_arprot,
s_axi_arvalid=m_axi_arvalid,
s_axi_arready=m_axi_arready,
s_axi_rid=m_axi_rid,
s_axi_rdata=m_axi_rdata,
s_axi_rresp=m_axi_rresp,
s_axi_rlast=m_axi_rlast,
s_axi_rvalid=m_axi_rvalid,
s_axi_rready=m_axi_rready,
name='port0'
)
# PCIe devices
rc = pcie.RootComplex()
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 4
dev.user_clock_frequency = 250e6
dev.functions[0].configure_bar(0, 16*1024*1024)
rc.make_port().connect(dev)
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=s_axis_cq_tdata,
m_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cq_tlast=s_axis_cq_tlast,
m_axis_cq_tkeep=s_axis_cq_tkeep,
m_axis_cq_tvalid=s_axis_cq_tvalid,
m_axis_cq_tready=s_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=m_axis_cc_tdata,
s_axis_cc_tuser=m_axis_cc_tuser,
s_axis_cc_tlast=m_axis_cc_tlast,
s_axis_cc_tkeep=m_axis_cc_tkeep,
s_axis_cc_tvalid=m_axis_cc_tvalid,
s_axis_cc_tready=m_axis_cc_tready,
# Requester reQuest Interface
s_axis_rq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_rq_tuser=Signal(intbv(0)[60:]),
s_axis_rq_tlast=Signal(bool(0)),
s_axis_rq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_rq_tvalid=Signal(bool(0)),
s_axis_rq_tready=Signal(bool(1)),
# 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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_rc_tuser=Signal(intbv(0)[75:]),
m_axis_rc_tlast=Signal(bool(0)),
m_axis_rc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_rc_tvalid=Signal(bool(0)),
m_axis_rc_tready=Signal(bool(0)),
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
s_axis_cq_tdata=s_axis_cq_tdata,
s_axis_cq_tkeep=s_axis_cq_tkeep,
s_axis_cq_tvalid=s_axis_cq_tvalid,
s_axis_cq_tready=s_axis_cq_tready,
s_axis_cq_tlast=s_axis_cq_tlast,
s_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cc_tdata=m_axis_cc_tdata,
m_axis_cc_tkeep=m_axis_cc_tkeep,
m_axis_cc_tvalid=m_axis_cc_tvalid,
m_axis_cc_tready=m_axis_cc_tready,
m_axis_cc_tlast=m_axis_cc_tlast,
m_axis_cc_tuser=m_axis_cc_tuser,
m_axi_awid=m_axi_awid,
m_axi_awaddr=m_axi_awaddr,
m_axi_awlen=m_axi_awlen,
m_axi_awsize=m_axi_awsize,
m_axi_awburst=m_axi_awburst,
m_axi_awlock=m_axi_awlock,
m_axi_awcache=m_axi_awcache,
m_axi_awprot=m_axi_awprot,
m_axi_awvalid=m_axi_awvalid,
m_axi_awready=m_axi_awready,
m_axi_wdata=m_axi_wdata,
m_axi_wstrb=m_axi_wstrb,
m_axi_wlast=m_axi_wlast,
m_axi_wvalid=m_axi_wvalid,
m_axi_wready=m_axi_wready,
m_axi_bid=m_axi_bid,
m_axi_bresp=m_axi_bresp,
m_axi_bvalid=m_axi_bvalid,
m_axi_bready=m_axi_bready,
m_axi_arid=m_axi_arid,
m_axi_araddr=m_axi_araddr,
m_axi_arlen=m_axi_arlen,
m_axi_arsize=m_axi_arsize,
m_axi_arburst=m_axi_arburst,
m_axi_arlock=m_axi_arlock,
m_axi_arcache=m_axi_arcache,
m_axi_arprot=m_axi_arprot,
m_axi_arvalid=m_axi_arvalid,
m_axi_arready=m_axi_arready,
m_axi_rid=m_axi_rid,
m_axi_rdata=m_axi_rdata,
m_axi_rresp=m_axi_rresp,
m_axi_rlast=m_axi_rlast,
m_axi_rvalid=m_axi_rvalid,
m_axi_rready=m_axi_rready,
completer_id=completer_id,
completer_id_enable=completer_id_enable,
max_payload_size=max_payload_size,
status_error_cor=status_error_cor,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
status_error_cor_asserted = Signal(bool(0))
status_error_uncor_asserted = Signal(bool(0))
@always(user_clk.posedge)
def monitor():
if (status_error_cor):
status_error_cor_asserted.next = 1
if (status_error_uncor):
status_error_uncor_asserted.next = 1
@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
# testbench stimulus
max_payload_size.next = 0
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate()
dev_bar0 = rc.tree[0][0].bar[0]
yield delay(100)
yield clk.posedge
print("test 2: memory write")
current_test.next = 2
pcie_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
yield rc.mem_write(dev_bar0+pcie_addr, test_data)
yield delay(300)
data = axi_ram_inst.read_mem(pcie_addr, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(pcie_addr, len(test_data)) == test_data
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
yield delay(100)
yield clk.posedge
print("test 3: memory read")
current_test.next = 3
pcie_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
axi_ram_inst.write_mem(pcie_addr, test_data)
data = axi_ram_inst.read_mem(0, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
val = yield from rc.mem_read(dev_bar0+pcie_addr, len(test_data), 1000)
print(val)
assert val == test_data
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,236 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_master
*/
module test_pcie_us_axi_master_128;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 128;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep = 0;
reg s_axis_cq_tvalid = 0;
reg s_axis_cq_tlast = 0;
reg [84:0] s_axis_cq_tuser = 0;
reg m_axis_cc_tready = 0;
reg m_axi_awready = 0;
reg m_axi_wready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_bid = 0;
reg [1:0] m_axi_bresp = 0;
reg m_axi_bvalid = 0;
reg m_axi_arready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_rid = 0;
reg [AXI_DATA_WIDTH-1:0] m_axi_rdata = 0;
reg [1:0] m_axi_rresp = 0;
reg m_axi_rlast = 0;
reg m_axi_rvalid = 0;
reg [15:0] completer_id = 0;
reg completer_id_enable = 0;
reg [2:0] max_payload_size = 0;
// Outputs
wire s_axis_cq_tready;
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep;
wire m_axis_cc_tvalid;
wire m_axis_cc_tlast;
wire [32:0] m_axis_cc_tuser;
wire [AXI_ID_WIDTH-1:0] m_axi_awid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr;
wire [7:0] m_axi_awlen;
wire [2:0] m_axi_awsize;
wire [1:0] m_axi_awburst;
wire m_axi_awlock;
wire [3:0] m_axi_awcache;
wire [2:0] m_axi_awprot;
wire m_axi_awvalid;
wire [AXI_DATA_WIDTH-1:0] m_axi_wdata;
wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb;
wire m_axi_wlast;
wire m_axi_wvalid;
wire m_axi_bready;
wire [AXI_ID_WIDTH-1:0] m_axi_arid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr;
wire [7:0] m_axi_arlen;
wire [2:0] m_axi_arsize;
wire [1:0] m_axi_arburst;
wire m_axi_arlock;
wire [3:0] m_axi_arcache;
wire [2:0] m_axi_arprot;
wire m_axi_arvalid;
wire m_axi_rready;
wire status_error_cor;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_cq_tdata,
s_axis_cq_tkeep,
s_axis_cq_tvalid,
s_axis_cq_tlast,
s_axis_cq_tuser,
m_axis_cc_tready,
m_axi_awready,
m_axi_wready,
m_axi_bid,
m_axi_bresp,
m_axi_bvalid,
m_axi_arready,
m_axi_rid,
m_axi_rdata,
m_axi_rresp,
m_axi_rlast,
m_axi_rvalid,
completer_id,
completer_id_enable,
max_payload_size
);
$to_myhdl(
s_axis_cq_tready,
m_axis_cc_tdata,
m_axis_cc_tkeep,
m_axis_cc_tvalid,
m_axis_cc_tlast,
m_axis_cc_tuser,
m_axi_awid,
m_axi_awaddr,
m_axi_awlen,
m_axi_awsize,
m_axi_awburst,
m_axi_awlock,
m_axi_awcache,
m_axi_awprot,
m_axi_awvalid,
m_axi_wdata,
m_axi_wstrb,
m_axi_wlast,
m_axi_wvalid,
m_axi_bready,
m_axi_arid,
m_axi_araddr,
m_axi_arlen,
m_axi_arsize,
m_axi_arburst,
m_axi_arlock,
m_axi_arcache,
m_axi_arprot,
m_axi_arvalid,
m_axi_rready,
status_error_cor,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axi_master_128.lxt");
$dumpvars(0, test_pcie_us_axi_master_128);
end
pcie_us_axi_master #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_cq_tdata(s_axis_cq_tdata),
.s_axis_cq_tkeep(s_axis_cq_tkeep),
.s_axis_cq_tvalid(s_axis_cq_tvalid),
.s_axis_cq_tready(s_axis_cq_tready),
.s_axis_cq_tlast(s_axis_cq_tlast),
.s_axis_cq_tuser(s_axis_cq_tuser),
.m_axis_cc_tdata(m_axis_cc_tdata),
.m_axis_cc_tkeep(m_axis_cc_tkeep),
.m_axis_cc_tvalid(m_axis_cc_tvalid),
.m_axis_cc_tready(m_axis_cc_tready),
.m_axis_cc_tlast(m_axis_cc_tlast),
.m_axis_cc_tuser(m_axis_cc_tuser),
.m_axi_awid(m_axi_awid),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awlen(m_axi_awlen),
.m_axi_awsize(m_axi_awsize),
.m_axi_awburst(m_axi_awburst),
.m_axi_awlock(m_axi_awlock),
.m_axi_awcache(m_axi_awcache),
.m_axi_awprot(m_axi_awprot),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wstrb(m_axi_wstrb),
.m_axi_wlast(m_axi_wlast),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
.m_axi_arid(m_axi_arid),
.m_axi_araddr(m_axi_araddr),
.m_axi_arlen(m_axi_arlen),
.m_axi_arsize(m_axi_arsize),
.m_axi_arburst(m_axi_arburst),
.m_axi_arlock(m_axi_arlock),
.m_axi_arcache(m_axi_arcache),
.m_axi_arprot(m_axi_arprot),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rid(m_axi_rid),
.m_axi_rdata(m_axi_rdata),
.m_axi_rresp(m_axi_rresp),
.m_axi_rlast(m_axi_rlast),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready),
.completer_id(completer_id),
.completer_id_enable(completer_id_enable),
.max_payload_size(max_payload_size),
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
endmodule

View File

@ -0,0 +1,420 @@
#!/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 os
import pcie
import pcie_us
import axi
module = 'pcie_us_axi_master'
testbench = 'test_%s_256' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("../rtl/pcie_us_axi_master_wr.v")
srcs.append("../rtl/pcie_us_axi_master_rd.v")
srcs.append("../rtl/pcie_us_axis_cq_demux.v")
srcs.append("../rtl/pulse_merge.v")
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 256
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_cq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_cq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_cq_tvalid = Signal(bool(0))
s_axis_cq_tlast = Signal(bool(0))
s_axis_cq_tuser = Signal(intbv(0)[85:])
m_axis_cc_tready = Signal(bool(0))
m_axi_awready = Signal(bool(0))
m_axi_wready = Signal(bool(0))
m_axi_bid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_bresp = Signal(intbv(0)[2:])
m_axi_bvalid = Signal(bool(0))
m_axi_arready = Signal(bool(0))
m_axi_rid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_rdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_rresp = Signal(intbv(0)[2:])
m_axi_rlast = Signal(bool(0))
m_axi_rvalid = Signal(bool(0))
completer_id = Signal(intbv(0)[16:])
completer_id_enable = Signal(bool(0))
max_payload_size = Signal(intbv(0)[3:])
# Outputs
s_axis_cq_tready = Signal(bool(0))
m_axis_cc_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_cc_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_cc_tvalid = Signal(bool(0))
m_axis_cc_tlast = Signal(bool(0))
m_axis_cc_tuser = Signal(intbv(0)[33:])
m_axi_awid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_awaddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_awlen = Signal(intbv(0)[8:])
m_axi_awsize = Signal(intbv(5)[3:])
m_axi_awburst = Signal(intbv(1)[2:])
m_axi_awlock = Signal(bool(0))
m_axi_awcache = Signal(intbv(3)[4:])
m_axi_awprot = Signal(intbv(2)[3:])
m_axi_awvalid = Signal(bool(0))
m_axi_wdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_wstrb = Signal(intbv(0)[AXI_STRB_WIDTH:])
m_axi_wlast = Signal(bool(0))
m_axi_wvalid = Signal(bool(0))
m_axi_bready = Signal(bool(0))
m_axi_arid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_araddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_arlen = Signal(intbv(0)[8:])
m_axi_arsize = Signal(intbv(5)[3:])
m_axi_arburst = Signal(intbv(1)[2:])
m_axi_arlock = Signal(bool(0))
m_axi_arcache = Signal(intbv(3)[4:])
m_axi_arprot = Signal(intbv(2)[3:])
m_axi_arvalid = Signal(bool(0))
m_axi_rready = Signal(bool(0))
status_error_cor = Signal(bool(0))
status_error_uncor = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_awid=m_axi_awid,
s_axi_awaddr=m_axi_awaddr,
s_axi_awlen=m_axi_awlen,
s_axi_awsize=m_axi_awsize,
s_axi_awburst=m_axi_awburst,
s_axi_awlock=m_axi_awlock,
s_axi_awcache=m_axi_awcache,
s_axi_awprot=m_axi_awprot,
s_axi_awvalid=m_axi_awvalid,
s_axi_awready=m_axi_awready,
s_axi_wdata=m_axi_wdata,
s_axi_wstrb=m_axi_wstrb,
s_axi_wlast=m_axi_wlast,
s_axi_wvalid=m_axi_wvalid,
s_axi_wready=m_axi_wready,
s_axi_bid=m_axi_bid,
s_axi_bresp=m_axi_bresp,
s_axi_bvalid=m_axi_bvalid,
s_axi_bready=m_axi_bready,
s_axi_arid=m_axi_arid,
s_axi_araddr=m_axi_araddr,
s_axi_arlen=m_axi_arlen,
s_axi_arsize=m_axi_arsize,
s_axi_arburst=m_axi_arburst,
s_axi_arlock=m_axi_arlock,
s_axi_arcache=m_axi_arcache,
s_axi_arprot=m_axi_arprot,
s_axi_arvalid=m_axi_arvalid,
s_axi_arready=m_axi_arready,
s_axi_rid=m_axi_rid,
s_axi_rdata=m_axi_rdata,
s_axi_rresp=m_axi_rresp,
s_axi_rlast=m_axi_rlast,
s_axi_rvalid=m_axi_rvalid,
s_axi_rready=m_axi_rready,
name='port0'
)
# PCIe devices
rc = pcie.RootComplex()
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 8
dev.user_clock_frequency = 250e6
dev.functions[0].configure_bar(0, 16*1024*1024)
rc.make_port().connect(dev)
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=s_axis_cq_tdata,
m_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cq_tlast=s_axis_cq_tlast,
m_axis_cq_tkeep=s_axis_cq_tkeep,
m_axis_cq_tvalid=s_axis_cq_tvalid,
m_axis_cq_tready=s_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=m_axis_cc_tdata,
s_axis_cc_tuser=m_axis_cc_tuser,
s_axis_cc_tlast=m_axis_cc_tlast,
s_axis_cc_tkeep=m_axis_cc_tkeep,
s_axis_cc_tvalid=m_axis_cc_tvalid,
s_axis_cc_tready=m_axis_cc_tready,
# Requester reQuest Interface
s_axis_rq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_rq_tuser=Signal(intbv(0)[60:]),
s_axis_rq_tlast=Signal(bool(0)),
s_axis_rq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_rq_tvalid=Signal(bool(0)),
s_axis_rq_tready=Signal(bool(1)),
# 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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_rc_tuser=Signal(intbv(0)[75:]),
m_axis_rc_tlast=Signal(bool(0)),
m_axis_rc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_rc_tvalid=Signal(bool(0)),
m_axis_rc_tready=Signal(bool(0)),
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
s_axis_cq_tdata=s_axis_cq_tdata,
s_axis_cq_tkeep=s_axis_cq_tkeep,
s_axis_cq_tvalid=s_axis_cq_tvalid,
s_axis_cq_tready=s_axis_cq_tready,
s_axis_cq_tlast=s_axis_cq_tlast,
s_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cc_tdata=m_axis_cc_tdata,
m_axis_cc_tkeep=m_axis_cc_tkeep,
m_axis_cc_tvalid=m_axis_cc_tvalid,
m_axis_cc_tready=m_axis_cc_tready,
m_axis_cc_tlast=m_axis_cc_tlast,
m_axis_cc_tuser=m_axis_cc_tuser,
m_axi_awid=m_axi_awid,
m_axi_awaddr=m_axi_awaddr,
m_axi_awlen=m_axi_awlen,
m_axi_awsize=m_axi_awsize,
m_axi_awburst=m_axi_awburst,
m_axi_awlock=m_axi_awlock,
m_axi_awcache=m_axi_awcache,
m_axi_awprot=m_axi_awprot,
m_axi_awvalid=m_axi_awvalid,
m_axi_awready=m_axi_awready,
m_axi_wdata=m_axi_wdata,
m_axi_wstrb=m_axi_wstrb,
m_axi_wlast=m_axi_wlast,
m_axi_wvalid=m_axi_wvalid,
m_axi_wready=m_axi_wready,
m_axi_bid=m_axi_bid,
m_axi_bresp=m_axi_bresp,
m_axi_bvalid=m_axi_bvalid,
m_axi_bready=m_axi_bready,
m_axi_arid=m_axi_arid,
m_axi_araddr=m_axi_araddr,
m_axi_arlen=m_axi_arlen,
m_axi_arsize=m_axi_arsize,
m_axi_arburst=m_axi_arburst,
m_axi_arlock=m_axi_arlock,
m_axi_arcache=m_axi_arcache,
m_axi_arprot=m_axi_arprot,
m_axi_arvalid=m_axi_arvalid,
m_axi_arready=m_axi_arready,
m_axi_rid=m_axi_rid,
m_axi_rdata=m_axi_rdata,
m_axi_rresp=m_axi_rresp,
m_axi_rlast=m_axi_rlast,
m_axi_rvalid=m_axi_rvalid,
m_axi_rready=m_axi_rready,
completer_id=completer_id,
completer_id_enable=completer_id_enable,
max_payload_size=max_payload_size,
status_error_cor=status_error_cor,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
status_error_cor_asserted = Signal(bool(0))
status_error_uncor_asserted = Signal(bool(0))
@always(user_clk.posedge)
def monitor():
if (status_error_cor):
status_error_cor_asserted.next = 1
if (status_error_uncor):
status_error_uncor_asserted.next = 1
@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
# testbench stimulus
max_payload_size.next = 0
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate()
dev_bar0 = rc.tree[0][0].bar[0]
yield delay(100)
yield clk.posedge
print("test 2: memory write")
current_test.next = 2
pcie_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
yield rc.mem_write(dev_bar0+pcie_addr, test_data)
yield delay(300)
data = axi_ram_inst.read_mem(pcie_addr, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(pcie_addr, len(test_data)) == test_data
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
yield delay(100)
yield clk.posedge
print("test 3: memory read")
current_test.next = 3
pcie_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
axi_ram_inst.write_mem(pcie_addr, test_data)
data = axi_ram_inst.read_mem(0, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
val = yield from rc.mem_read(dev_bar0+pcie_addr, len(test_data), 1000)
print(val)
assert val == test_data
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,236 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_master
*/
module test_pcie_us_axi_master_256;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 256;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep = 0;
reg s_axis_cq_tvalid = 0;
reg s_axis_cq_tlast = 0;
reg [84:0] s_axis_cq_tuser = 0;
reg m_axis_cc_tready = 0;
reg m_axi_awready = 0;
reg m_axi_wready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_bid = 0;
reg [1:0] m_axi_bresp = 0;
reg m_axi_bvalid = 0;
reg m_axi_arready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_rid = 0;
reg [AXI_DATA_WIDTH-1:0] m_axi_rdata = 0;
reg [1:0] m_axi_rresp = 0;
reg m_axi_rlast = 0;
reg m_axi_rvalid = 0;
reg [15:0] completer_id = 0;
reg completer_id_enable = 0;
reg [2:0] max_payload_size = 0;
// Outputs
wire s_axis_cq_tready;
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep;
wire m_axis_cc_tvalid;
wire m_axis_cc_tlast;
wire [32:0] m_axis_cc_tuser;
wire [AXI_ID_WIDTH-1:0] m_axi_awid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr;
wire [7:0] m_axi_awlen;
wire [2:0] m_axi_awsize;
wire [1:0] m_axi_awburst;
wire m_axi_awlock;
wire [3:0] m_axi_awcache;
wire [2:0] m_axi_awprot;
wire m_axi_awvalid;
wire [AXI_DATA_WIDTH-1:0] m_axi_wdata;
wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb;
wire m_axi_wlast;
wire m_axi_wvalid;
wire m_axi_bready;
wire [AXI_ID_WIDTH-1:0] m_axi_arid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr;
wire [7:0] m_axi_arlen;
wire [2:0] m_axi_arsize;
wire [1:0] m_axi_arburst;
wire m_axi_arlock;
wire [3:0] m_axi_arcache;
wire [2:0] m_axi_arprot;
wire m_axi_arvalid;
wire m_axi_rready;
wire status_error_cor;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_cq_tdata,
s_axis_cq_tkeep,
s_axis_cq_tvalid,
s_axis_cq_tlast,
s_axis_cq_tuser,
m_axis_cc_tready,
m_axi_awready,
m_axi_wready,
m_axi_bid,
m_axi_bresp,
m_axi_bvalid,
m_axi_arready,
m_axi_rid,
m_axi_rdata,
m_axi_rresp,
m_axi_rlast,
m_axi_rvalid,
completer_id,
completer_id_enable,
max_payload_size
);
$to_myhdl(
s_axis_cq_tready,
m_axis_cc_tdata,
m_axis_cc_tkeep,
m_axis_cc_tvalid,
m_axis_cc_tlast,
m_axis_cc_tuser,
m_axi_awid,
m_axi_awaddr,
m_axi_awlen,
m_axi_awsize,
m_axi_awburst,
m_axi_awlock,
m_axi_awcache,
m_axi_awprot,
m_axi_awvalid,
m_axi_wdata,
m_axi_wstrb,
m_axi_wlast,
m_axi_wvalid,
m_axi_bready,
m_axi_arid,
m_axi_araddr,
m_axi_arlen,
m_axi_arsize,
m_axi_arburst,
m_axi_arlock,
m_axi_arcache,
m_axi_arprot,
m_axi_arvalid,
m_axi_rready,
status_error_cor,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axi_master_256.lxt");
$dumpvars(0, test_pcie_us_axi_master_256);
end
pcie_us_axi_master #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_cq_tdata(s_axis_cq_tdata),
.s_axis_cq_tkeep(s_axis_cq_tkeep),
.s_axis_cq_tvalid(s_axis_cq_tvalid),
.s_axis_cq_tready(s_axis_cq_tready),
.s_axis_cq_tlast(s_axis_cq_tlast),
.s_axis_cq_tuser(s_axis_cq_tuser),
.m_axis_cc_tdata(m_axis_cc_tdata),
.m_axis_cc_tkeep(m_axis_cc_tkeep),
.m_axis_cc_tvalid(m_axis_cc_tvalid),
.m_axis_cc_tready(m_axis_cc_tready),
.m_axis_cc_tlast(m_axis_cc_tlast),
.m_axis_cc_tuser(m_axis_cc_tuser),
.m_axi_awid(m_axi_awid),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awlen(m_axi_awlen),
.m_axi_awsize(m_axi_awsize),
.m_axi_awburst(m_axi_awburst),
.m_axi_awlock(m_axi_awlock),
.m_axi_awcache(m_axi_awcache),
.m_axi_awprot(m_axi_awprot),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wstrb(m_axi_wstrb),
.m_axi_wlast(m_axi_wlast),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
.m_axi_arid(m_axi_arid),
.m_axi_araddr(m_axi_araddr),
.m_axi_arlen(m_axi_arlen),
.m_axi_arsize(m_axi_arsize),
.m_axi_arburst(m_axi_arburst),
.m_axi_arlock(m_axi_arlock),
.m_axi_arcache(m_axi_arcache),
.m_axi_arprot(m_axi_arprot),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rid(m_axi_rid),
.m_axi_rdata(m_axi_rdata),
.m_axi_rresp(m_axi_rresp),
.m_axi_rlast(m_axi_rlast),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready),
.completer_id(completer_id),
.completer_id_enable(completer_id_enable),
.max_payload_size(max_payload_size),
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
endmodule

View File

@ -0,0 +1,420 @@
#!/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 os
import pcie
import pcie_us
import axi
module = 'pcie_us_axi_master'
testbench = 'test_%s_64' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("../rtl/pcie_us_axi_master_wr.v")
srcs.append("../rtl/pcie_us_axi_master_rd.v")
srcs.append("../rtl/pcie_us_axis_cq_demux.v")
srcs.append("../rtl/pulse_merge.v")
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 64
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_cq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_cq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_cq_tvalid = Signal(bool(0))
s_axis_cq_tlast = Signal(bool(0))
s_axis_cq_tuser = Signal(intbv(0)[85:])
m_axis_cc_tready = Signal(bool(0))
m_axi_awready = Signal(bool(0))
m_axi_wready = Signal(bool(0))
m_axi_bid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_bresp = Signal(intbv(0)[2:])
m_axi_bvalid = Signal(bool(0))
m_axi_arready = Signal(bool(0))
m_axi_rid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_rdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_rresp = Signal(intbv(0)[2:])
m_axi_rlast = Signal(bool(0))
m_axi_rvalid = Signal(bool(0))
completer_id = Signal(intbv(0)[16:])
completer_id_enable = Signal(bool(0))
max_payload_size = Signal(intbv(0)[3:])
# Outputs
s_axis_cq_tready = Signal(bool(0))
m_axis_cc_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_cc_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_cc_tvalid = Signal(bool(0))
m_axis_cc_tlast = Signal(bool(0))
m_axis_cc_tuser = Signal(intbv(0)[33:])
m_axi_awid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_awaddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_awlen = Signal(intbv(0)[8:])
m_axi_awsize = Signal(intbv(3)[3:])
m_axi_awburst = Signal(intbv(1)[2:])
m_axi_awlock = Signal(bool(0))
m_axi_awcache = Signal(intbv(3)[4:])
m_axi_awprot = Signal(intbv(2)[3:])
m_axi_awvalid = Signal(bool(0))
m_axi_wdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_wstrb = Signal(intbv(0)[AXI_STRB_WIDTH:])
m_axi_wlast = Signal(bool(0))
m_axi_wvalid = Signal(bool(0))
m_axi_bready = Signal(bool(0))
m_axi_arid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_araddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_arlen = Signal(intbv(0)[8:])
m_axi_arsize = Signal(intbv(3)[3:])
m_axi_arburst = Signal(intbv(1)[2:])
m_axi_arlock = Signal(bool(0))
m_axi_arcache = Signal(intbv(3)[4:])
m_axi_arprot = Signal(intbv(2)[3:])
m_axi_arvalid = Signal(bool(0))
m_axi_rready = Signal(bool(0))
status_error_cor = Signal(bool(0))
status_error_uncor = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_awid=m_axi_awid,
s_axi_awaddr=m_axi_awaddr,
s_axi_awlen=m_axi_awlen,
s_axi_awsize=m_axi_awsize,
s_axi_awburst=m_axi_awburst,
s_axi_awlock=m_axi_awlock,
s_axi_awcache=m_axi_awcache,
s_axi_awprot=m_axi_awprot,
s_axi_awvalid=m_axi_awvalid,
s_axi_awready=m_axi_awready,
s_axi_wdata=m_axi_wdata,
s_axi_wstrb=m_axi_wstrb,
s_axi_wlast=m_axi_wlast,
s_axi_wvalid=m_axi_wvalid,
s_axi_wready=m_axi_wready,
s_axi_bid=m_axi_bid,
s_axi_bresp=m_axi_bresp,
s_axi_bvalid=m_axi_bvalid,
s_axi_bready=m_axi_bready,
s_axi_arid=m_axi_arid,
s_axi_araddr=m_axi_araddr,
s_axi_arlen=m_axi_arlen,
s_axi_arsize=m_axi_arsize,
s_axi_arburst=m_axi_arburst,
s_axi_arlock=m_axi_arlock,
s_axi_arcache=m_axi_arcache,
s_axi_arprot=m_axi_arprot,
s_axi_arvalid=m_axi_arvalid,
s_axi_arready=m_axi_arready,
s_axi_rid=m_axi_rid,
s_axi_rdata=m_axi_rdata,
s_axi_rresp=m_axi_rresp,
s_axi_rlast=m_axi_rlast,
s_axi_rvalid=m_axi_rvalid,
s_axi_rready=m_axi_rready,
name='port0'
)
# PCIe devices
rc = pcie.RootComplex()
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 2
dev.user_clock_frequency = 250e6
dev.functions[0].configure_bar(0, 16*1024*1024)
rc.make_port().connect(dev)
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=s_axis_cq_tdata,
m_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cq_tlast=s_axis_cq_tlast,
m_axis_cq_tkeep=s_axis_cq_tkeep,
m_axis_cq_tvalid=s_axis_cq_tvalid,
m_axis_cq_tready=s_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=m_axis_cc_tdata,
s_axis_cc_tuser=m_axis_cc_tuser,
s_axis_cc_tlast=m_axis_cc_tlast,
s_axis_cc_tkeep=m_axis_cc_tkeep,
s_axis_cc_tvalid=m_axis_cc_tvalid,
s_axis_cc_tready=m_axis_cc_tready,
# Requester reQuest Interface
s_axis_rq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_rq_tuser=Signal(intbv(0)[60:]),
s_axis_rq_tlast=Signal(bool(0)),
s_axis_rq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_rq_tvalid=Signal(bool(0)),
s_axis_rq_tready=Signal(bool(1)),
# 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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_rc_tuser=Signal(intbv(0)[75:]),
m_axis_rc_tlast=Signal(bool(0)),
m_axis_rc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_rc_tvalid=Signal(bool(0)),
m_axis_rc_tready=Signal(bool(0)),
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
s_axis_cq_tdata=s_axis_cq_tdata,
s_axis_cq_tkeep=s_axis_cq_tkeep,
s_axis_cq_tvalid=s_axis_cq_tvalid,
s_axis_cq_tready=s_axis_cq_tready,
s_axis_cq_tlast=s_axis_cq_tlast,
s_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cc_tdata=m_axis_cc_tdata,
m_axis_cc_tkeep=m_axis_cc_tkeep,
m_axis_cc_tvalid=m_axis_cc_tvalid,
m_axis_cc_tready=m_axis_cc_tready,
m_axis_cc_tlast=m_axis_cc_tlast,
m_axis_cc_tuser=m_axis_cc_tuser,
m_axi_awid=m_axi_awid,
m_axi_awaddr=m_axi_awaddr,
m_axi_awlen=m_axi_awlen,
m_axi_awsize=m_axi_awsize,
m_axi_awburst=m_axi_awburst,
m_axi_awlock=m_axi_awlock,
m_axi_awcache=m_axi_awcache,
m_axi_awprot=m_axi_awprot,
m_axi_awvalid=m_axi_awvalid,
m_axi_awready=m_axi_awready,
m_axi_wdata=m_axi_wdata,
m_axi_wstrb=m_axi_wstrb,
m_axi_wlast=m_axi_wlast,
m_axi_wvalid=m_axi_wvalid,
m_axi_wready=m_axi_wready,
m_axi_bid=m_axi_bid,
m_axi_bresp=m_axi_bresp,
m_axi_bvalid=m_axi_bvalid,
m_axi_bready=m_axi_bready,
m_axi_arid=m_axi_arid,
m_axi_araddr=m_axi_araddr,
m_axi_arlen=m_axi_arlen,
m_axi_arsize=m_axi_arsize,
m_axi_arburst=m_axi_arburst,
m_axi_arlock=m_axi_arlock,
m_axi_arcache=m_axi_arcache,
m_axi_arprot=m_axi_arprot,
m_axi_arvalid=m_axi_arvalid,
m_axi_arready=m_axi_arready,
m_axi_rid=m_axi_rid,
m_axi_rdata=m_axi_rdata,
m_axi_rresp=m_axi_rresp,
m_axi_rlast=m_axi_rlast,
m_axi_rvalid=m_axi_rvalid,
m_axi_rready=m_axi_rready,
completer_id=completer_id,
completer_id_enable=completer_id_enable,
max_payload_size=max_payload_size,
status_error_cor=status_error_cor,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
status_error_cor_asserted = Signal(bool(0))
status_error_uncor_asserted = Signal(bool(0))
@always(user_clk.posedge)
def monitor():
if (status_error_cor):
status_error_cor_asserted.next = 1
if (status_error_uncor):
status_error_uncor_asserted.next = 1
@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
# testbench stimulus
max_payload_size.next = 0
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate()
dev_bar0 = rc.tree[0][0].bar[0]
yield delay(100)
yield clk.posedge
print("test 2: memory write")
current_test.next = 2
pcie_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
yield rc.mem_write(dev_bar0+pcie_addr, test_data)
yield delay(300)
data = axi_ram_inst.read_mem(pcie_addr, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(pcie_addr, len(test_data)) == test_data
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
yield delay(100)
yield clk.posedge
print("test 3: memory read")
current_test.next = 3
pcie_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
axi_ram_inst.write_mem(pcie_addr, test_data)
data = axi_ram_inst.read_mem(0, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
val = yield from rc.mem_read(dev_bar0+pcie_addr, len(test_data), 1000)
print(val)
assert val == test_data
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,236 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_master
*/
module test_pcie_us_axi_master_64;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 64;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep = 0;
reg s_axis_cq_tvalid = 0;
reg s_axis_cq_tlast = 0;
reg [84:0] s_axis_cq_tuser = 0;
reg m_axis_cc_tready = 0;
reg m_axi_awready = 0;
reg m_axi_wready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_bid = 0;
reg [1:0] m_axi_bresp = 0;
reg m_axi_bvalid = 0;
reg m_axi_arready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_rid = 0;
reg [AXI_DATA_WIDTH-1:0] m_axi_rdata = 0;
reg [1:0] m_axi_rresp = 0;
reg m_axi_rlast = 0;
reg m_axi_rvalid = 0;
reg [15:0] completer_id = 0;
reg completer_id_enable = 0;
reg [2:0] max_payload_size = 0;
// Outputs
wire s_axis_cq_tready;
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep;
wire m_axis_cc_tvalid;
wire m_axis_cc_tlast;
wire [32:0] m_axis_cc_tuser;
wire [AXI_ID_WIDTH-1:0] m_axi_awid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr;
wire [7:0] m_axi_awlen;
wire [2:0] m_axi_awsize;
wire [1:0] m_axi_awburst;
wire m_axi_awlock;
wire [3:0] m_axi_awcache;
wire [2:0] m_axi_awprot;
wire m_axi_awvalid;
wire [AXI_DATA_WIDTH-1:0] m_axi_wdata;
wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb;
wire m_axi_wlast;
wire m_axi_wvalid;
wire m_axi_bready;
wire [AXI_ID_WIDTH-1:0] m_axi_arid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr;
wire [7:0] m_axi_arlen;
wire [2:0] m_axi_arsize;
wire [1:0] m_axi_arburst;
wire m_axi_arlock;
wire [3:0] m_axi_arcache;
wire [2:0] m_axi_arprot;
wire m_axi_arvalid;
wire m_axi_rready;
wire status_error_cor;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_cq_tdata,
s_axis_cq_tkeep,
s_axis_cq_tvalid,
s_axis_cq_tlast,
s_axis_cq_tuser,
m_axis_cc_tready,
m_axi_awready,
m_axi_wready,
m_axi_bid,
m_axi_bresp,
m_axi_bvalid,
m_axi_arready,
m_axi_rid,
m_axi_rdata,
m_axi_rresp,
m_axi_rlast,
m_axi_rvalid,
completer_id,
completer_id_enable,
max_payload_size
);
$to_myhdl(
s_axis_cq_tready,
m_axis_cc_tdata,
m_axis_cc_tkeep,
m_axis_cc_tvalid,
m_axis_cc_tlast,
m_axis_cc_tuser,
m_axi_awid,
m_axi_awaddr,
m_axi_awlen,
m_axi_awsize,
m_axi_awburst,
m_axi_awlock,
m_axi_awcache,
m_axi_awprot,
m_axi_awvalid,
m_axi_wdata,
m_axi_wstrb,
m_axi_wlast,
m_axi_wvalid,
m_axi_bready,
m_axi_arid,
m_axi_araddr,
m_axi_arlen,
m_axi_arsize,
m_axi_arburst,
m_axi_arlock,
m_axi_arcache,
m_axi_arprot,
m_axi_arvalid,
m_axi_rready,
status_error_cor,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axi_master_64.lxt");
$dumpvars(0, test_pcie_us_axi_master_64);
end
pcie_us_axi_master #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_cq_tdata(s_axis_cq_tdata),
.s_axis_cq_tkeep(s_axis_cq_tkeep),
.s_axis_cq_tvalid(s_axis_cq_tvalid),
.s_axis_cq_tready(s_axis_cq_tready),
.s_axis_cq_tlast(s_axis_cq_tlast),
.s_axis_cq_tuser(s_axis_cq_tuser),
.m_axis_cc_tdata(m_axis_cc_tdata),
.m_axis_cc_tkeep(m_axis_cc_tkeep),
.m_axis_cc_tvalid(m_axis_cc_tvalid),
.m_axis_cc_tready(m_axis_cc_tready),
.m_axis_cc_tlast(m_axis_cc_tlast),
.m_axis_cc_tuser(m_axis_cc_tuser),
.m_axi_awid(m_axi_awid),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awlen(m_axi_awlen),
.m_axi_awsize(m_axi_awsize),
.m_axi_awburst(m_axi_awburst),
.m_axi_awlock(m_axi_awlock),
.m_axi_awcache(m_axi_awcache),
.m_axi_awprot(m_axi_awprot),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wstrb(m_axi_wstrb),
.m_axi_wlast(m_axi_wlast),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
.m_axi_arid(m_axi_arid),
.m_axi_araddr(m_axi_araddr),
.m_axi_arlen(m_axi_arlen),
.m_axi_arsize(m_axi_arsize),
.m_axi_arburst(m_axi_arburst),
.m_axi_arlock(m_axi_arlock),
.m_axi_arcache(m_axi_arcache),
.m_axi_arprot(m_axi_arprot),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rid(m_axi_rid),
.m_axi_rdata(m_axi_rdata),
.m_axi_rresp(m_axi_rresp),
.m_axi_rlast(m_axi_rlast),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready),
.completer_id(completer_id),
.completer_id_enable(completer_id_enable),
.max_payload_size(max_payload_size),
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
endmodule

View File

@ -0,0 +1,440 @@
#!/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 os
import pcie
import pcie_us
import axi
module = 'pcie_us_axi_master_rd'
testbench = 'test_%s_128' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 128
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_cq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_cq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_cq_tvalid = Signal(bool(0))
s_axis_cq_tlast = Signal(bool(0))
s_axis_cq_tuser = Signal(intbv(0)[85:])
m_axis_cc_tready = Signal(bool(0))
m_axi_arready = Signal(bool(0))
m_axi_rid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_rdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_rresp = Signal(intbv(0)[2:])
m_axi_rlast = Signal(bool(0))
m_axi_rvalid = Signal(bool(0))
completer_id = Signal(intbv(0)[16:])
completer_id_enable = Signal(bool(0))
max_payload_size = Signal(intbv(0)[3:])
# Outputs
s_axis_cq_tready = Signal(bool(0))
m_axis_cc_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_cc_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_cc_tvalid = Signal(bool(0))
m_axis_cc_tlast = Signal(bool(0))
m_axis_cc_tuser = Signal(intbv(0)[33:])
m_axi_arid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_araddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_arlen = Signal(intbv(0)[8:])
m_axi_arsize = Signal(intbv(4)[3:])
m_axi_arburst = Signal(intbv(1)[2:])
m_axi_arlock = Signal(bool(0))
m_axi_arcache = Signal(intbv(3)[4:])
m_axi_arprot = Signal(intbv(2)[3:])
m_axi_arvalid = Signal(bool(0))
m_axi_rready = Signal(bool(0))
status_error_cor = Signal(bool(0))
status_error_uncor = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_arid=m_axi_arid,
s_axi_araddr=m_axi_araddr,
s_axi_arlen=m_axi_arlen,
s_axi_arsize=m_axi_arsize,
s_axi_arburst=m_axi_arburst,
s_axi_arlock=m_axi_arlock,
s_axi_arcache=m_axi_arcache,
s_axi_arprot=m_axi_arprot,
s_axi_arvalid=m_axi_arvalid,
s_axi_arready=m_axi_arready,
s_axi_rid=m_axi_rid,
s_axi_rdata=m_axi_rdata,
s_axi_rresp=m_axi_rresp,
s_axi_rlast=m_axi_rlast,
s_axi_rvalid=m_axi_rvalid,
s_axi_rready=m_axi_rready,
name='port0'
)
# PCIe devices
rc = pcie.RootComplex()
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 4
dev.user_clock_frequency = 250e6
dev.functions[0].configure_bar(0, 16*1024*1024)
dev.functions[0].configure_bar(1, 32, io=True)
rc.make_port().connect(dev)
cq_pause = Signal(bool(0))
cc_pause = Signal(bool(0))
rq_pause = Signal(bool(0))
rc_pause = Signal(bool(0))
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=s_axis_cq_tdata,
m_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cq_tlast=s_axis_cq_tlast,
m_axis_cq_tkeep=s_axis_cq_tkeep,
m_axis_cq_tvalid=s_axis_cq_tvalid,
m_axis_cq_tready=s_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=m_axis_cc_tdata,
s_axis_cc_tuser=m_axis_cc_tuser,
s_axis_cc_tlast=m_axis_cc_tlast,
s_axis_cc_tkeep=m_axis_cc_tkeep,
s_axis_cc_tvalid=m_axis_cc_tvalid,
s_axis_cc_tready=m_axis_cc_tready,
# Requester reQuest Interface
s_axis_rq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_rq_tuser=Signal(intbv(0)[60:]),
s_axis_rq_tlast=Signal(bool(0)),
s_axis_rq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_rq_tvalid=Signal(bool(0)),
s_axis_rq_tready=Signal(bool(1)),
# 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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_rc_tuser=Signal(intbv(0)[75:]),
m_axis_rc_tlast=Signal(bool(0)),
m_axis_rc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_rc_tvalid=Signal(bool(0)),
m_axis_rc_tready=Signal(bool(0)),
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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,
cq_pause=cq_pause,
cc_pause=cc_pause,
rq_pause=rq_pause,
rc_pause=rc_pause
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
s_axis_cq_tdata=s_axis_cq_tdata,
s_axis_cq_tkeep=s_axis_cq_tkeep,
s_axis_cq_tvalid=s_axis_cq_tvalid,
s_axis_cq_tready=s_axis_cq_tready,
s_axis_cq_tlast=s_axis_cq_tlast,
s_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cc_tdata=m_axis_cc_tdata,
m_axis_cc_tkeep=m_axis_cc_tkeep,
m_axis_cc_tvalid=m_axis_cc_tvalid,
m_axis_cc_tready=m_axis_cc_tready,
m_axis_cc_tlast=m_axis_cc_tlast,
m_axis_cc_tuser=m_axis_cc_tuser,
m_axi_arid=m_axi_arid,
m_axi_araddr=m_axi_araddr,
m_axi_arlen=m_axi_arlen,
m_axi_arsize=m_axi_arsize,
m_axi_arburst=m_axi_arburst,
m_axi_arlock=m_axi_arlock,
m_axi_arcache=m_axi_arcache,
m_axi_arprot=m_axi_arprot,
m_axi_arvalid=m_axi_arvalid,
m_axi_arready=m_axi_arready,
m_axi_rid=m_axi_rid,
m_axi_rdata=m_axi_rdata,
m_axi_rresp=m_axi_rresp,
m_axi_rlast=m_axi_rlast,
m_axi_rvalid=m_axi_rvalid,
m_axi_rready=m_axi_rready,
completer_id=completer_id,
completer_id_enable=completer_id_enable,
max_payload_size=max_payload_size,
status_error_cor=status_error_cor,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
status_error_cor_asserted = Signal(bool(0))
status_error_uncor_asserted = Signal(bool(0))
@always(user_clk.posedge)
def monitor():
if (status_error_cor):
status_error_cor_asserted.next = 1
if (status_error_uncor):
status_error_uncor_asserted.next = 1
cq_pause_toggle = Signal(bool(0))
cc_pause_toggle = Signal(bool(0))
rq_pause_toggle = Signal(bool(0))
rc_pause_toggle = Signal(bool(0))
@instance
def pause_toggle():
while True:
if (cq_pause_toggle or cc_pause_toggle or rq_pause_toggle or rc_pause_toggle):
cq_pause.next = cq_pause_toggle
cc_pause.next = cc_pause_toggle
rq_pause.next = rq_pause_toggle
rc_pause.next = rc_pause_toggle
yield user_clk.posedge
yield user_clk.posedge
yield user_clk.posedge
cq_pause.next = 0
cc_pause.next = 0
rq_pause.next = 0
rc_pause.next = 0
yield user_clk.posedge
@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
# testbench stimulus
max_payload_size.next = 0
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate()
dev_bar0 = rc.tree[0][0].bar[0]
dev_bar1 = rc.tree[0][0].bar[1]
yield delay(100)
yield clk.posedge
print("test 2: memory read")
current_test.next = 2
pcie_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
axi_ram_inst.write_mem(pcie_addr, test_data)
data = axi_ram_inst.read_mem(0, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
val = yield from rc.mem_read(dev_bar0+pcie_addr, len(test_data), 1000)
print(val)
assert val == test_data
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
yield delay(100)
yield user_clk.posedge
print("test 3: various reads")
current_test.next = 3
for length in list(range(1,34))+[1024]:
for pcie_offset in list(range(8,25))+list(range(4096-16,4096)):
for pause in [False, True]:
print("length %d, pcie_offset %d"% (length, pcie_offset))
#pcie_addr = length * 0x100000000 + pcie_offset * 0x10000 + offset
pcie_addr = pcie_offset
test_data = bytearray([x%256 for x in range(length)])
axi_ram_inst.write_mem(pcie_addr & 0xffff80, b'\x55'*(len(test_data)+256))
axi_ram_inst.write_mem(pcie_addr, test_data)
data = axi_ram_inst.read_mem(pcie_addr&0xfffff0, 64)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
cq_pause_toggle.next = pause
cc_pause_toggle.next = pause
val = yield from rc.mem_read(dev_bar0+pcie_addr, len(test_data), 1000)
cq_pause_toggle.next = 0
cc_pause_toggle.next = 0
print(val)
assert val == test_data
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
yield delay(100)
yield clk.posedge
print("test 4: bad requests")
current_test.next = 4
yield from rc.mem_write(dev_bar0, b'\x11\x22\x33\x44')
yield delay(100)
assert not status_error_cor_asserted
assert status_error_uncor_asserted
status_error_cor_asserted.next = False
status_error_uncor_asserted.next = False
try:
yield from rc.io_write(dev_bar1, b'\x11\x22\x33\x44')
except:
print("Caught unsuccessful completion exception")
pass
else:
assert False
assert status_error_cor_asserted
assert not status_error_uncor_asserted
status_error_cor_asserted.next = False
status_error_uncor_asserted.next = False
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,179 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_master_rd
*/
module test_pcie_us_axi_master_rd_128;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 128;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep = 0;
reg s_axis_cq_tvalid = 0;
reg s_axis_cq_tlast = 0;
reg [84:0] s_axis_cq_tuser = 0;
reg m_axis_cc_tready = 0;
reg m_axi_arready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_rid = 0;
reg [AXI_DATA_WIDTH-1:0] m_axi_rdata = 0;
reg [1:0] m_axi_rresp = 0;
reg m_axi_rlast = 0;
reg m_axi_rvalid = 0;
reg [15:0] completer_id = 0;
reg completer_id_enable = 0;
reg [2:0] max_payload_size = 0;
// Outputs
wire s_axis_cq_tready;
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep;
wire m_axis_cc_tvalid;
wire m_axis_cc_tlast;
wire [32:0] m_axis_cc_tuser;
wire [AXI_ID_WIDTH-1:0] m_axi_arid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr;
wire [7:0] m_axi_arlen;
wire [2:0] m_axi_arsize;
wire [1:0] m_axi_arburst;
wire m_axi_arlock;
wire [3:0] m_axi_arcache;
wire [2:0] m_axi_arprot;
wire m_axi_arvalid;
wire m_axi_rready;
wire status_error_cor;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_cq_tdata,
s_axis_cq_tkeep,
s_axis_cq_tvalid,
s_axis_cq_tlast,
s_axis_cq_tuser,
m_axis_cc_tready,
m_axi_arready,
m_axi_rid,
m_axi_rdata,
m_axi_rresp,
m_axi_rlast,
m_axi_rvalid,
completer_id,
completer_id_enable,
max_payload_size
);
$to_myhdl(
s_axis_cq_tready,
m_axis_cc_tdata,
m_axis_cc_tkeep,
m_axis_cc_tvalid,
m_axis_cc_tlast,
m_axis_cc_tuser,
m_axi_arid,
m_axi_araddr,
m_axi_arlen,
m_axi_arsize,
m_axi_arburst,
m_axi_arlock,
m_axi_arcache,
m_axi_arprot,
m_axi_arvalid,
m_axi_rready,
status_error_cor,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axi_master_rd_128.lxt");
$dumpvars(0, test_pcie_us_axi_master_rd_128);
end
pcie_us_axi_master_rd #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_cq_tdata(s_axis_cq_tdata),
.s_axis_cq_tkeep(s_axis_cq_tkeep),
.s_axis_cq_tvalid(s_axis_cq_tvalid),
.s_axis_cq_tready(s_axis_cq_tready),
.s_axis_cq_tlast(s_axis_cq_tlast),
.s_axis_cq_tuser(s_axis_cq_tuser),
.m_axis_cc_tdata(m_axis_cc_tdata),
.m_axis_cc_tkeep(m_axis_cc_tkeep),
.m_axis_cc_tvalid(m_axis_cc_tvalid),
.m_axis_cc_tready(m_axis_cc_tready),
.m_axis_cc_tlast(m_axis_cc_tlast),
.m_axis_cc_tuser(m_axis_cc_tuser),
.m_axi_arid(m_axi_arid),
.m_axi_araddr(m_axi_araddr),
.m_axi_arlen(m_axi_arlen),
.m_axi_arsize(m_axi_arsize),
.m_axi_arburst(m_axi_arburst),
.m_axi_arlock(m_axi_arlock),
.m_axi_arcache(m_axi_arcache),
.m_axi_arprot(m_axi_arprot),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rid(m_axi_rid),
.m_axi_rdata(m_axi_rdata),
.m_axi_rresp(m_axi_rresp),
.m_axi_rlast(m_axi_rlast),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready),
.completer_id(completer_id),
.completer_id_enable(completer_id_enable),
.max_payload_size(max_payload_size),
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
endmodule

View File

@ -0,0 +1,440 @@
#!/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 os
import pcie
import pcie_us
import axi
module = 'pcie_us_axi_master_rd'
testbench = 'test_%s_256' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 256
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_cq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_cq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_cq_tvalid = Signal(bool(0))
s_axis_cq_tlast = Signal(bool(0))
s_axis_cq_tuser = Signal(intbv(0)[85:])
m_axis_cc_tready = Signal(bool(0))
m_axi_arready = Signal(bool(0))
m_axi_rid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_rdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_rresp = Signal(intbv(0)[2:])
m_axi_rlast = Signal(bool(0))
m_axi_rvalid = Signal(bool(0))
completer_id = Signal(intbv(0)[16:])
completer_id_enable = Signal(bool(0))
max_payload_size = Signal(intbv(0)[3:])
# Outputs
s_axis_cq_tready = Signal(bool(0))
m_axis_cc_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_cc_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_cc_tvalid = Signal(bool(0))
m_axis_cc_tlast = Signal(bool(0))
m_axis_cc_tuser = Signal(intbv(0)[33:])
m_axi_arid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_araddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_arlen = Signal(intbv(0)[8:])
m_axi_arsize = Signal(intbv(5)[3:])
m_axi_arburst = Signal(intbv(1)[2:])
m_axi_arlock = Signal(bool(0))
m_axi_arcache = Signal(intbv(3)[4:])
m_axi_arprot = Signal(intbv(2)[3:])
m_axi_arvalid = Signal(bool(0))
m_axi_rready = Signal(bool(0))
status_error_cor = Signal(bool(0))
status_error_uncor = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_arid=m_axi_arid,
s_axi_araddr=m_axi_araddr,
s_axi_arlen=m_axi_arlen,
s_axi_arsize=m_axi_arsize,
s_axi_arburst=m_axi_arburst,
s_axi_arlock=m_axi_arlock,
s_axi_arcache=m_axi_arcache,
s_axi_arprot=m_axi_arprot,
s_axi_arvalid=m_axi_arvalid,
s_axi_arready=m_axi_arready,
s_axi_rid=m_axi_rid,
s_axi_rdata=m_axi_rdata,
s_axi_rresp=m_axi_rresp,
s_axi_rlast=m_axi_rlast,
s_axi_rvalid=m_axi_rvalid,
s_axi_rready=m_axi_rready,
name='port0'
)
# PCIe devices
rc = pcie.RootComplex()
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 8
dev.user_clock_frequency = 250e6
dev.functions[0].configure_bar(0, 16*1024*1024)
dev.functions[0].configure_bar(1, 32, io=True)
rc.make_port().connect(dev)
cq_pause = Signal(bool(0))
cc_pause = Signal(bool(0))
rq_pause = Signal(bool(0))
rc_pause = Signal(bool(0))
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=s_axis_cq_tdata,
m_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cq_tlast=s_axis_cq_tlast,
m_axis_cq_tkeep=s_axis_cq_tkeep,
m_axis_cq_tvalid=s_axis_cq_tvalid,
m_axis_cq_tready=s_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=m_axis_cc_tdata,
s_axis_cc_tuser=m_axis_cc_tuser,
s_axis_cc_tlast=m_axis_cc_tlast,
s_axis_cc_tkeep=m_axis_cc_tkeep,
s_axis_cc_tvalid=m_axis_cc_tvalid,
s_axis_cc_tready=m_axis_cc_tready,
# Requester reQuest Interface
s_axis_rq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_rq_tuser=Signal(intbv(0)[60:]),
s_axis_rq_tlast=Signal(bool(0)),
s_axis_rq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_rq_tvalid=Signal(bool(0)),
s_axis_rq_tready=Signal(bool(1)),
# 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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_rc_tuser=Signal(intbv(0)[75:]),
m_axis_rc_tlast=Signal(bool(0)),
m_axis_rc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_rc_tvalid=Signal(bool(0)),
m_axis_rc_tready=Signal(bool(0)),
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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,
cq_pause=cq_pause,
cc_pause=cc_pause,
rq_pause=rq_pause,
rc_pause=rc_pause
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
s_axis_cq_tdata=s_axis_cq_tdata,
s_axis_cq_tkeep=s_axis_cq_tkeep,
s_axis_cq_tvalid=s_axis_cq_tvalid,
s_axis_cq_tready=s_axis_cq_tready,
s_axis_cq_tlast=s_axis_cq_tlast,
s_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cc_tdata=m_axis_cc_tdata,
m_axis_cc_tkeep=m_axis_cc_tkeep,
m_axis_cc_tvalid=m_axis_cc_tvalid,
m_axis_cc_tready=m_axis_cc_tready,
m_axis_cc_tlast=m_axis_cc_tlast,
m_axis_cc_tuser=m_axis_cc_tuser,
m_axi_arid=m_axi_arid,
m_axi_araddr=m_axi_araddr,
m_axi_arlen=m_axi_arlen,
m_axi_arsize=m_axi_arsize,
m_axi_arburst=m_axi_arburst,
m_axi_arlock=m_axi_arlock,
m_axi_arcache=m_axi_arcache,
m_axi_arprot=m_axi_arprot,
m_axi_arvalid=m_axi_arvalid,
m_axi_arready=m_axi_arready,
m_axi_rid=m_axi_rid,
m_axi_rdata=m_axi_rdata,
m_axi_rresp=m_axi_rresp,
m_axi_rlast=m_axi_rlast,
m_axi_rvalid=m_axi_rvalid,
m_axi_rready=m_axi_rready,
completer_id=completer_id,
completer_id_enable=completer_id_enable,
max_payload_size=max_payload_size,
status_error_cor=status_error_cor,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
status_error_cor_asserted = Signal(bool(0))
status_error_uncor_asserted = Signal(bool(0))
@always(user_clk.posedge)
def monitor():
if (status_error_cor):
status_error_cor_asserted.next = 1
if (status_error_uncor):
status_error_uncor_asserted.next = 1
cq_pause_toggle = Signal(bool(0))
cc_pause_toggle = Signal(bool(0))
rq_pause_toggle = Signal(bool(0))
rc_pause_toggle = Signal(bool(0))
@instance
def pause_toggle():
while True:
if (cq_pause_toggle or cc_pause_toggle or rq_pause_toggle or rc_pause_toggle):
cq_pause.next = cq_pause_toggle
cc_pause.next = cc_pause_toggle
rq_pause.next = rq_pause_toggle
rc_pause.next = rc_pause_toggle
yield user_clk.posedge
yield user_clk.posedge
yield user_clk.posedge
cq_pause.next = 0
cc_pause.next = 0
rq_pause.next = 0
rc_pause.next = 0
yield user_clk.posedge
@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
# testbench stimulus
max_payload_size.next = 0
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate()
dev_bar0 = rc.tree[0][0].bar[0]
dev_bar1 = rc.tree[0][0].bar[1]
yield delay(100)
yield clk.posedge
print("test 2: memory read")
current_test.next = 2
pcie_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
axi_ram_inst.write_mem(pcie_addr, test_data)
data = axi_ram_inst.read_mem(0, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
val = yield from rc.mem_read(dev_bar0+pcie_addr, len(test_data), 1000)
print(val)
assert val == test_data
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
yield delay(100)
yield user_clk.posedge
print("test 3: various reads")
current_test.next = 3
for length in list(range(1,34))+[1024]:
for pcie_offset in list(range(8,41))+list(range(4096-32,4096)):
for pause in [False, True]:
print("length %d, pcie_offset %d"% (length, pcie_offset))
#pcie_addr = length * 0x100000000 + pcie_offset * 0x10000 + offset
pcie_addr = pcie_offset
test_data = bytearray([x%256 for x in range(length)])
axi_ram_inst.write_mem(pcie_addr & 0xffff80, b'\x55'*(len(test_data)+256))
axi_ram_inst.write_mem(pcie_addr, test_data)
data = axi_ram_inst.read_mem(pcie_addr&0xfffff0, 64)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
cq_pause_toggle.next = pause
cc_pause_toggle.next = pause
val = yield from rc.mem_read(dev_bar0+pcie_addr, len(test_data), 1000)
cq_pause_toggle.next = 0
cc_pause_toggle.next = 0
print(val)
assert val == test_data
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
yield delay(100)
yield clk.posedge
print("test 4: bad requests")
current_test.next = 4
yield from rc.mem_write(dev_bar0, b'\x11\x22\x33\x44')
yield delay(100)
assert not status_error_cor_asserted
assert status_error_uncor_asserted
status_error_cor_asserted.next = False
status_error_uncor_asserted.next = False
try:
yield from rc.io_write(dev_bar1, b'\x11\x22\x33\x44')
except:
print("Caught unsuccessful completion exception")
pass
else:
assert False
assert status_error_cor_asserted
assert not status_error_uncor_asserted
status_error_cor_asserted.next = False
status_error_uncor_asserted.next = False
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,179 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_master_rd
*/
module test_pcie_us_axi_master_rd_256;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 256;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep = 0;
reg s_axis_cq_tvalid = 0;
reg s_axis_cq_tlast = 0;
reg [84:0] s_axis_cq_tuser = 0;
reg m_axis_cc_tready = 0;
reg m_axi_arready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_rid = 0;
reg [AXI_DATA_WIDTH-1:0] m_axi_rdata = 0;
reg [1:0] m_axi_rresp = 0;
reg m_axi_rlast = 0;
reg m_axi_rvalid = 0;
reg [15:0] completer_id = 0;
reg completer_id_enable = 0;
reg [2:0] max_payload_size = 0;
// Outputs
wire s_axis_cq_tready;
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep;
wire m_axis_cc_tvalid;
wire m_axis_cc_tlast;
wire [32:0] m_axis_cc_tuser;
wire [AXI_ID_WIDTH-1:0] m_axi_arid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr;
wire [7:0] m_axi_arlen;
wire [2:0] m_axi_arsize;
wire [1:0] m_axi_arburst;
wire m_axi_arlock;
wire [3:0] m_axi_arcache;
wire [2:0] m_axi_arprot;
wire m_axi_arvalid;
wire m_axi_rready;
wire status_error_cor;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_cq_tdata,
s_axis_cq_tkeep,
s_axis_cq_tvalid,
s_axis_cq_tlast,
s_axis_cq_tuser,
m_axis_cc_tready,
m_axi_arready,
m_axi_rid,
m_axi_rdata,
m_axi_rresp,
m_axi_rlast,
m_axi_rvalid,
completer_id,
completer_id_enable,
max_payload_size
);
$to_myhdl(
s_axis_cq_tready,
m_axis_cc_tdata,
m_axis_cc_tkeep,
m_axis_cc_tvalid,
m_axis_cc_tlast,
m_axis_cc_tuser,
m_axi_arid,
m_axi_araddr,
m_axi_arlen,
m_axi_arsize,
m_axi_arburst,
m_axi_arlock,
m_axi_arcache,
m_axi_arprot,
m_axi_arvalid,
m_axi_rready,
status_error_cor,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axi_master_rd_256.lxt");
$dumpvars(0, test_pcie_us_axi_master_rd_256);
end
pcie_us_axi_master_rd #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_cq_tdata(s_axis_cq_tdata),
.s_axis_cq_tkeep(s_axis_cq_tkeep),
.s_axis_cq_tvalid(s_axis_cq_tvalid),
.s_axis_cq_tready(s_axis_cq_tready),
.s_axis_cq_tlast(s_axis_cq_tlast),
.s_axis_cq_tuser(s_axis_cq_tuser),
.m_axis_cc_tdata(m_axis_cc_tdata),
.m_axis_cc_tkeep(m_axis_cc_tkeep),
.m_axis_cc_tvalid(m_axis_cc_tvalid),
.m_axis_cc_tready(m_axis_cc_tready),
.m_axis_cc_tlast(m_axis_cc_tlast),
.m_axis_cc_tuser(m_axis_cc_tuser),
.m_axi_arid(m_axi_arid),
.m_axi_araddr(m_axi_araddr),
.m_axi_arlen(m_axi_arlen),
.m_axi_arsize(m_axi_arsize),
.m_axi_arburst(m_axi_arburst),
.m_axi_arlock(m_axi_arlock),
.m_axi_arcache(m_axi_arcache),
.m_axi_arprot(m_axi_arprot),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rid(m_axi_rid),
.m_axi_rdata(m_axi_rdata),
.m_axi_rresp(m_axi_rresp),
.m_axi_rlast(m_axi_rlast),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready),
.completer_id(completer_id),
.completer_id_enable(completer_id_enable),
.max_payload_size(max_payload_size),
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
endmodule

View File

@ -0,0 +1,440 @@
#!/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 os
import pcie
import pcie_us
import axi
module = 'pcie_us_axi_master_rd'
testbench = 'test_%s_64' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 64
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_cq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_cq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_cq_tvalid = Signal(bool(0))
s_axis_cq_tlast = Signal(bool(0))
s_axis_cq_tuser = Signal(intbv(0)[85:])
m_axis_cc_tready = Signal(bool(0))
m_axi_arready = Signal(bool(0))
m_axi_rid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_rdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_rresp = Signal(intbv(0)[2:])
m_axi_rlast = Signal(bool(0))
m_axi_rvalid = Signal(bool(0))
completer_id = Signal(intbv(0)[16:])
completer_id_enable = Signal(bool(0))
max_payload_size = Signal(intbv(0)[3:])
# Outputs
s_axis_cq_tready = Signal(bool(0))
m_axis_cc_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_cc_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_cc_tvalid = Signal(bool(0))
m_axis_cc_tlast = Signal(bool(0))
m_axis_cc_tuser = Signal(intbv(0)[33:])
m_axi_arid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_araddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_arlen = Signal(intbv(0)[8:])
m_axi_arsize = Signal(intbv(3)[3:])
m_axi_arburst = Signal(intbv(1)[2:])
m_axi_arlock = Signal(bool(0))
m_axi_arcache = Signal(intbv(3)[4:])
m_axi_arprot = Signal(intbv(2)[3:])
m_axi_arvalid = Signal(bool(0))
m_axi_rready = Signal(bool(0))
status_error_cor = Signal(bool(0))
status_error_uncor = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_arid=m_axi_arid,
s_axi_araddr=m_axi_araddr,
s_axi_arlen=m_axi_arlen,
s_axi_arsize=m_axi_arsize,
s_axi_arburst=m_axi_arburst,
s_axi_arlock=m_axi_arlock,
s_axi_arcache=m_axi_arcache,
s_axi_arprot=m_axi_arprot,
s_axi_arvalid=m_axi_arvalid,
s_axi_arready=m_axi_arready,
s_axi_rid=m_axi_rid,
s_axi_rdata=m_axi_rdata,
s_axi_rresp=m_axi_rresp,
s_axi_rlast=m_axi_rlast,
s_axi_rvalid=m_axi_rvalid,
s_axi_rready=m_axi_rready,
name='port0'
)
# PCIe devices
rc = pcie.RootComplex()
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 2
dev.user_clock_frequency = 250e6
dev.functions[0].configure_bar(0, 16*1024*1024)
dev.functions[0].configure_bar(1, 32, io=True)
rc.make_port().connect(dev)
cq_pause = Signal(bool(0))
cc_pause = Signal(bool(0))
rq_pause = Signal(bool(0))
rc_pause = Signal(bool(0))
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=s_axis_cq_tdata,
m_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cq_tlast=s_axis_cq_tlast,
m_axis_cq_tkeep=s_axis_cq_tkeep,
m_axis_cq_tvalid=s_axis_cq_tvalid,
m_axis_cq_tready=s_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=m_axis_cc_tdata,
s_axis_cc_tuser=m_axis_cc_tuser,
s_axis_cc_tlast=m_axis_cc_tlast,
s_axis_cc_tkeep=m_axis_cc_tkeep,
s_axis_cc_tvalid=m_axis_cc_tvalid,
s_axis_cc_tready=m_axis_cc_tready,
# Requester reQuest Interface
s_axis_rq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_rq_tuser=Signal(intbv(0)[60:]),
s_axis_rq_tlast=Signal(bool(0)),
s_axis_rq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_rq_tvalid=Signal(bool(0)),
s_axis_rq_tready=Signal(bool(1)),
# 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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_rc_tuser=Signal(intbv(0)[75:]),
m_axis_rc_tlast=Signal(bool(0)),
m_axis_rc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_rc_tvalid=Signal(bool(0)),
m_axis_rc_tready=Signal(bool(0)),
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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,
cq_pause=cq_pause,
cc_pause=cc_pause,
rq_pause=rq_pause,
rc_pause=rc_pause
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
s_axis_cq_tdata=s_axis_cq_tdata,
s_axis_cq_tkeep=s_axis_cq_tkeep,
s_axis_cq_tvalid=s_axis_cq_tvalid,
s_axis_cq_tready=s_axis_cq_tready,
s_axis_cq_tlast=s_axis_cq_tlast,
s_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cc_tdata=m_axis_cc_tdata,
m_axis_cc_tkeep=m_axis_cc_tkeep,
m_axis_cc_tvalid=m_axis_cc_tvalid,
m_axis_cc_tready=m_axis_cc_tready,
m_axis_cc_tlast=m_axis_cc_tlast,
m_axis_cc_tuser=m_axis_cc_tuser,
m_axi_arid=m_axi_arid,
m_axi_araddr=m_axi_araddr,
m_axi_arlen=m_axi_arlen,
m_axi_arsize=m_axi_arsize,
m_axi_arburst=m_axi_arburst,
m_axi_arlock=m_axi_arlock,
m_axi_arcache=m_axi_arcache,
m_axi_arprot=m_axi_arprot,
m_axi_arvalid=m_axi_arvalid,
m_axi_arready=m_axi_arready,
m_axi_rid=m_axi_rid,
m_axi_rdata=m_axi_rdata,
m_axi_rresp=m_axi_rresp,
m_axi_rlast=m_axi_rlast,
m_axi_rvalid=m_axi_rvalid,
m_axi_rready=m_axi_rready,
completer_id=completer_id,
completer_id_enable=completer_id_enable,
max_payload_size=max_payload_size,
status_error_cor=status_error_cor,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
status_error_cor_asserted = Signal(bool(0))
status_error_uncor_asserted = Signal(bool(0))
@always(user_clk.posedge)
def monitor():
if (status_error_cor):
status_error_cor_asserted.next = 1
if (status_error_uncor):
status_error_uncor_asserted.next = 1
cq_pause_toggle = Signal(bool(0))
cc_pause_toggle = Signal(bool(0))
rq_pause_toggle = Signal(bool(0))
rc_pause_toggle = Signal(bool(0))
@instance
def pause_toggle():
while True:
if (cq_pause_toggle or cc_pause_toggle or rq_pause_toggle or rc_pause_toggle):
cq_pause.next = cq_pause_toggle
cc_pause.next = cc_pause_toggle
rq_pause.next = rq_pause_toggle
rc_pause.next = rc_pause_toggle
yield user_clk.posedge
yield user_clk.posedge
yield user_clk.posedge
cq_pause.next = 0
cc_pause.next = 0
rq_pause.next = 0
rc_pause.next = 0
yield user_clk.posedge
@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
# testbench stimulus
max_payload_size.next = 0
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate()
dev_bar0 = rc.tree[0][0].bar[0]
dev_bar1 = rc.tree[0][0].bar[1]
yield delay(100)
yield clk.posedge
print("test 2: memory read")
current_test.next = 2
pcie_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
axi_ram_inst.write_mem(pcie_addr, test_data)
data = axi_ram_inst.read_mem(0, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
val = yield from rc.mem_read(dev_bar0+pcie_addr, len(test_data), 1000)
print(val)
assert val == test_data
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
yield delay(100)
yield user_clk.posedge
print("test 3: various reads")
current_test.next = 3
for length in list(range(1,34))+[1024]:
for pcie_offset in list(range(8,17))+list(range(4096-8,4096)):
for pause in [False, True]:
print("length %d, pcie_offset %d"% (length, pcie_offset))
#pcie_addr = length * 0x100000000 + pcie_offset * 0x10000 + offset
pcie_addr = pcie_offset
test_data = bytearray([x%256 for x in range(length)])
axi_ram_inst.write_mem(pcie_addr & 0xffff80, b'\x55'*(len(test_data)+256))
axi_ram_inst.write_mem(pcie_addr, test_data)
data = axi_ram_inst.read_mem(pcie_addr&0xfffff0, 64)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
cq_pause_toggle.next = pause
cc_pause_toggle.next = pause
val = yield from rc.mem_read(dev_bar0+pcie_addr, len(test_data), 1000)
cq_pause_toggle.next = 0
cc_pause_toggle.next = 0
print(val)
assert val == test_data
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
yield delay(100)
yield clk.posedge
print("test 4: bad requests")
current_test.next = 4
yield from rc.mem_write(dev_bar0, b'\x11\x22\x33\x44')
yield delay(100)
assert not status_error_cor_asserted
assert status_error_uncor_asserted
status_error_cor_asserted.next = False
status_error_uncor_asserted.next = False
try:
yield from rc.io_write(dev_bar1, b'\x11\x22\x33\x44')
except:
print("Caught unsuccessful completion exception")
pass
else:
assert False
assert status_error_cor_asserted
assert not status_error_uncor_asserted
status_error_cor_asserted.next = False
status_error_uncor_asserted.next = False
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,179 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_master_rd
*/
module test_pcie_us_axi_master_rd_64;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 64;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep = 0;
reg s_axis_cq_tvalid = 0;
reg s_axis_cq_tlast = 0;
reg [84:0] s_axis_cq_tuser = 0;
reg m_axis_cc_tready = 0;
reg m_axi_arready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_rid = 0;
reg [AXI_DATA_WIDTH-1:0] m_axi_rdata = 0;
reg [1:0] m_axi_rresp = 0;
reg m_axi_rlast = 0;
reg m_axi_rvalid = 0;
reg [15:0] completer_id = 0;
reg completer_id_enable = 0;
reg [2:0] max_payload_size = 0;
// Outputs
wire s_axis_cq_tready;
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep;
wire m_axis_cc_tvalid;
wire m_axis_cc_tlast;
wire [32:0] m_axis_cc_tuser;
wire [AXI_ID_WIDTH-1:0] m_axi_arid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr;
wire [7:0] m_axi_arlen;
wire [2:0] m_axi_arsize;
wire [1:0] m_axi_arburst;
wire m_axi_arlock;
wire [3:0] m_axi_arcache;
wire [2:0] m_axi_arprot;
wire m_axi_arvalid;
wire m_axi_rready;
wire status_error_cor;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_cq_tdata,
s_axis_cq_tkeep,
s_axis_cq_tvalid,
s_axis_cq_tlast,
s_axis_cq_tuser,
m_axis_cc_tready,
m_axi_arready,
m_axi_rid,
m_axi_rdata,
m_axi_rresp,
m_axi_rlast,
m_axi_rvalid,
completer_id,
completer_id_enable,
max_payload_size
);
$to_myhdl(
s_axis_cq_tready,
m_axis_cc_tdata,
m_axis_cc_tkeep,
m_axis_cc_tvalid,
m_axis_cc_tlast,
m_axis_cc_tuser,
m_axi_arid,
m_axi_araddr,
m_axi_arlen,
m_axi_arsize,
m_axi_arburst,
m_axi_arlock,
m_axi_arcache,
m_axi_arprot,
m_axi_arvalid,
m_axi_rready,
status_error_cor,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axi_master_rd_64.lxt");
$dumpvars(0, test_pcie_us_axi_master_rd_64);
end
pcie_us_axi_master_rd #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_cq_tdata(s_axis_cq_tdata),
.s_axis_cq_tkeep(s_axis_cq_tkeep),
.s_axis_cq_tvalid(s_axis_cq_tvalid),
.s_axis_cq_tready(s_axis_cq_tready),
.s_axis_cq_tlast(s_axis_cq_tlast),
.s_axis_cq_tuser(s_axis_cq_tuser),
.m_axis_cc_tdata(m_axis_cc_tdata),
.m_axis_cc_tkeep(m_axis_cc_tkeep),
.m_axis_cc_tvalid(m_axis_cc_tvalid),
.m_axis_cc_tready(m_axis_cc_tready),
.m_axis_cc_tlast(m_axis_cc_tlast),
.m_axis_cc_tuser(m_axis_cc_tuser),
.m_axi_arid(m_axi_arid),
.m_axi_araddr(m_axi_araddr),
.m_axi_arlen(m_axi_arlen),
.m_axi_arsize(m_axi_arsize),
.m_axi_arburst(m_axi_arburst),
.m_axi_arlock(m_axi_arlock),
.m_axi_arcache(m_axi_arcache),
.m_axi_arprot(m_axi_arprot),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rid(m_axi_rid),
.m_axi_rdata(m_axi_rdata),
.m_axi_rresp(m_axi_rresp),
.m_axi_rlast(m_axi_rlast),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready),
.completer_id(completer_id),
.completer_id_enable(completer_id_enable),
.max_payload_size(max_payload_size),
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
endmodule

View File

@ -0,0 +1,403 @@
#!/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 os
import pcie
import pcie_us
import axi
module = 'pcie_us_axi_master_wr'
testbench = 'test_%s_128' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 128
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_cq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_cq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_cq_tvalid = Signal(bool(0))
s_axis_cq_tlast = Signal(bool(0))
s_axis_cq_tuser = Signal(intbv(0)[85:])
m_axi_awready = Signal(bool(0))
m_axi_wready = Signal(bool(0))
m_axi_bid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_bresp = Signal(intbv(0)[2:])
m_axi_bvalid = Signal(bool(0))
# Outputs
s_axis_cq_tready = Signal(bool(0))
m_axi_awid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_awaddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_awlen = Signal(intbv(0)[8:])
m_axi_awsize = Signal(intbv(4)[3:])
m_axi_awburst = Signal(intbv(1)[2:])
m_axi_awlock = Signal(bool(0))
m_axi_awcache = Signal(intbv(3)[4:])
m_axi_awprot = Signal(intbv(2)[3:])
m_axi_awvalid = Signal(bool(0))
m_axi_wdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_wstrb = Signal(intbv(0)[AXI_STRB_WIDTH:])
m_axi_wlast = Signal(bool(0))
m_axi_wvalid = Signal(bool(0))
m_axi_bready = Signal(bool(1))
status_error_uncor = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_awid=m_axi_awid,
s_axi_awaddr=m_axi_awaddr,
s_axi_awlen=m_axi_awlen,
s_axi_awsize=m_axi_awsize,
s_axi_awburst=m_axi_awburst,
s_axi_awlock=m_axi_awlock,
s_axi_awcache=m_axi_awcache,
s_axi_awprot=m_axi_awprot,
s_axi_awvalid=m_axi_awvalid,
s_axi_awready=m_axi_awready,
s_axi_wdata=m_axi_wdata,
s_axi_wstrb=m_axi_wstrb,
s_axi_wlast=m_axi_wlast,
s_axi_wvalid=m_axi_wvalid,
s_axi_wready=m_axi_wready,
s_axi_bid=m_axi_bid,
s_axi_bresp=m_axi_bresp,
s_axi_bvalid=m_axi_bvalid,
s_axi_bready=m_axi_bready,
name='port0'
)
# PCIe devices
rc = pcie.RootComplex()
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 4
dev.user_clock_frequency = 250e6
dev.functions[0].configure_bar(0, 16*1024*1024)
rc.make_port().connect(dev)
cq_pause = Signal(bool(0))
cc_pause = Signal(bool(0))
rq_pause = Signal(bool(0))
rc_pause = Signal(bool(0))
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=s_axis_cq_tdata,
m_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cq_tlast=s_axis_cq_tlast,
m_axis_cq_tkeep=s_axis_cq_tkeep,
m_axis_cq_tvalid=s_axis_cq_tvalid,
m_axis_cq_tready=s_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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_cc_tuser=Signal(intbv(0)[33:]),
s_axis_cc_tlast=Signal(bool(0)),
s_axis_cc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_cc_tvalid=Signal(bool(0)),
s_axis_cc_tready=Signal(bool(0)),
# Requester reQuest Interface
s_axis_rq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_rq_tuser=Signal(intbv(0)[60:]),
s_axis_rq_tlast=Signal(bool(0)),
s_axis_rq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_rq_tvalid=Signal(bool(0)),
s_axis_rq_tready=Signal(bool(1)),
# 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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_rc_tuser=Signal(intbv(0)[75:]),
m_axis_rc_tlast=Signal(bool(0)),
m_axis_rc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_rc_tvalid=Signal(bool(0)),
m_axis_rc_tready=Signal(bool(0)),
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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,
cq_pause=cq_pause,
cc_pause=cc_pause,
rq_pause=rq_pause,
rc_pause=rc_pause
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
s_axis_cq_tdata=s_axis_cq_tdata,
s_axis_cq_tkeep=s_axis_cq_tkeep,
s_axis_cq_tvalid=s_axis_cq_tvalid,
s_axis_cq_tready=s_axis_cq_tready,
s_axis_cq_tlast=s_axis_cq_tlast,
s_axis_cq_tuser=s_axis_cq_tuser,
m_axi_awid=m_axi_awid,
m_axi_awaddr=m_axi_awaddr,
m_axi_awlen=m_axi_awlen,
m_axi_awsize=m_axi_awsize,
m_axi_awburst=m_axi_awburst,
m_axi_awlock=m_axi_awlock,
m_axi_awcache=m_axi_awcache,
m_axi_awprot=m_axi_awprot,
m_axi_awvalid=m_axi_awvalid,
m_axi_awready=m_axi_awready,
m_axi_wdata=m_axi_wdata,
m_axi_wstrb=m_axi_wstrb,
m_axi_wlast=m_axi_wlast,
m_axi_wvalid=m_axi_wvalid,
m_axi_wready=m_axi_wready,
m_axi_bid=m_axi_bid,
m_axi_bresp=m_axi_bresp,
m_axi_bvalid=m_axi_bvalid,
m_axi_bready=m_axi_bready,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
status_error_uncor_asserted = Signal(bool(0))
@always(user_clk.posedge)
def monitor():
if (status_error_uncor):
status_error_uncor_asserted.next = 1
cq_pause_toggle = Signal(bool(0))
cc_pause_toggle = Signal(bool(0))
rq_pause_toggle = Signal(bool(0))
rc_pause_toggle = Signal(bool(0))
@instance
def pause_toggle():
while True:
if (cq_pause_toggle or cc_pause_toggle or rq_pause_toggle or rc_pause_toggle):
cq_pause.next = cq_pause_toggle
cc_pause.next = cc_pause_toggle
rq_pause.next = rq_pause_toggle
rc_pause.next = rc_pause_toggle
yield user_clk.posedge
yield user_clk.posedge
yield user_clk.posedge
cq_pause.next = 0
cc_pause.next = 0
rq_pause.next = 0
rc_pause.next = 0
yield user_clk.posedge
@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
# testbench stimulus
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate()
dev_bar0 = rc.tree[0][0].bar[0]
yield delay(100)
yield clk.posedge
print("test 2: memory write")
current_test.next = 2
pcie_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
yield rc.mem_write(dev_bar0+pcie_addr, test_data)
yield delay(300)
data = axi_ram_inst.read_mem(pcie_addr, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(pcie_addr, len(test_data)) == test_data
assert not status_error_uncor_asserted
yield delay(100)
yield user_clk.posedge
print("test 3: various writes")
current_test.next = 3
for length in list(range(1,34))+[1024]:
for pcie_offset in list(range(8,41))+list(range(4096-32,4096)):
for pause in [False, True]:
print("length %d, pcie_offset %d"% (length, pcie_offset))
#pcie_addr = length * 0x100000000 + pcie_offset * 0x10000 + offset
pcie_addr = pcie_offset
test_data = bytearray([x%256 for x in range(length)])
axi_ram_inst.write_mem(pcie_addr & 0xffff80, b'\x55'*(len(test_data)+256))
cq_pause_toggle.next = pause
yield from rc.mem_write(dev_bar0+pcie_addr, test_data)
yield delay(int(length*4+120))
cq_pause_toggle.next = 0
data = axi_ram_inst.read_mem(pcie_addr&0xfffff0, 64)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(pcie_addr-1, len(test_data)+2) == b'\x55'+test_data+b'\x55'
assert not status_error_uncor_asserted
yield delay(100)
yield clk.posedge
print("test 4: bad request")
current_test.next = 4
try:
yield from rc.mem_read(dev_bar0, 4, 100)
except:
print("Caught timeout exception")
pass
else:
assert False
assert status_error_uncor_asserted
status_error_uncor_asserted.next = False
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,158 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_master_wr
*/
module test_pcie_us_axi_master_wr_128;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 128;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep = 0;
reg s_axis_cq_tvalid = 0;
reg s_axis_cq_tlast = 0;
reg [84:0] s_axis_cq_tuser = 0;
reg m_axi_awready = 0;
reg m_axi_wready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_bid = 0;
reg [1:0] m_axi_bresp = 0;
reg m_axi_bvalid = 0;
// Outputs
wire s_axis_cq_tready;
wire [AXI_ID_WIDTH-1:0] m_axi_awid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr;
wire [7:0] m_axi_awlen;
wire [2:0] m_axi_awsize;
wire [1:0] m_axi_awburst;
wire m_axi_awlock;
wire [3:0] m_axi_awcache;
wire [2:0] m_axi_awprot;
wire m_axi_awvalid;
wire [AXI_DATA_WIDTH-1:0] m_axi_wdata;
wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb;
wire m_axi_wlast;
wire m_axi_wvalid;
wire m_axi_bready;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_cq_tdata,
s_axis_cq_tkeep,
s_axis_cq_tvalid,
s_axis_cq_tlast,
s_axis_cq_tuser,
m_axi_awready,
m_axi_wready,
m_axi_bid,
m_axi_bresp,
m_axi_bvalid
);
$to_myhdl(
s_axis_cq_tready,
m_axi_awid,
m_axi_awaddr,
m_axi_awlen,
m_axi_awsize,
m_axi_awburst,
m_axi_awlock,
m_axi_awcache,
m_axi_awprot,
m_axi_awvalid,
m_axi_wdata,
m_axi_wstrb,
m_axi_wlast,
m_axi_wvalid,
m_axi_bready,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axi_master_wr_128.lxt");
$dumpvars(0, test_pcie_us_axi_master_wr_128);
end
pcie_us_axi_master_wr #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_cq_tdata(s_axis_cq_tdata),
.s_axis_cq_tkeep(s_axis_cq_tkeep),
.s_axis_cq_tvalid(s_axis_cq_tvalid),
.s_axis_cq_tready(s_axis_cq_tready),
.s_axis_cq_tlast(s_axis_cq_tlast),
.s_axis_cq_tuser(s_axis_cq_tuser),
.m_axi_awid(m_axi_awid),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awlen(m_axi_awlen),
.m_axi_awsize(m_axi_awsize),
.m_axi_awburst(m_axi_awburst),
.m_axi_awlock(m_axi_awlock),
.m_axi_awcache(m_axi_awcache),
.m_axi_awprot(m_axi_awprot),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wstrb(m_axi_wstrb),
.m_axi_wlast(m_axi_wlast),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
.status_error_uncor(status_error_uncor)
);
endmodule

View File

@ -0,0 +1,403 @@
#!/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 os
import pcie
import pcie_us
import axi
module = 'pcie_us_axi_master_wr'
testbench = 'test_%s_256' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 256
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_cq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_cq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_cq_tvalid = Signal(bool(0))
s_axis_cq_tlast = Signal(bool(0))
s_axis_cq_tuser = Signal(intbv(0)[85:])
m_axi_awready = Signal(bool(0))
m_axi_wready = Signal(bool(0))
m_axi_bid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_bresp = Signal(intbv(0)[2:])
m_axi_bvalid = Signal(bool(0))
# Outputs
s_axis_cq_tready = Signal(bool(0))
m_axi_awid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_awaddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_awlen = Signal(intbv(0)[8:])
m_axi_awsize = Signal(intbv(5)[3:])
m_axi_awburst = Signal(intbv(1)[2:])
m_axi_awlock = Signal(bool(0))
m_axi_awcache = Signal(intbv(3)[4:])
m_axi_awprot = Signal(intbv(2)[3:])
m_axi_awvalid = Signal(bool(0))
m_axi_wdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_wstrb = Signal(intbv(0)[AXI_STRB_WIDTH:])
m_axi_wlast = Signal(bool(0))
m_axi_wvalid = Signal(bool(0))
m_axi_bready = Signal(bool(1))
status_error_uncor = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_awid=m_axi_awid,
s_axi_awaddr=m_axi_awaddr,
s_axi_awlen=m_axi_awlen,
s_axi_awsize=m_axi_awsize,
s_axi_awburst=m_axi_awburst,
s_axi_awlock=m_axi_awlock,
s_axi_awcache=m_axi_awcache,
s_axi_awprot=m_axi_awprot,
s_axi_awvalid=m_axi_awvalid,
s_axi_awready=m_axi_awready,
s_axi_wdata=m_axi_wdata,
s_axi_wstrb=m_axi_wstrb,
s_axi_wlast=m_axi_wlast,
s_axi_wvalid=m_axi_wvalid,
s_axi_wready=m_axi_wready,
s_axi_bid=m_axi_bid,
s_axi_bresp=m_axi_bresp,
s_axi_bvalid=m_axi_bvalid,
s_axi_bready=m_axi_bready,
name='port0'
)
# PCIe devices
rc = pcie.RootComplex()
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 8
dev.user_clock_frequency = 250e6
dev.functions[0].configure_bar(0, 16*1024*1024)
rc.make_port().connect(dev)
cq_pause = Signal(bool(0))
cc_pause = Signal(bool(0))
rq_pause = Signal(bool(0))
rc_pause = Signal(bool(0))
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=s_axis_cq_tdata,
m_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cq_tlast=s_axis_cq_tlast,
m_axis_cq_tkeep=s_axis_cq_tkeep,
m_axis_cq_tvalid=s_axis_cq_tvalid,
m_axis_cq_tready=s_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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_cc_tuser=Signal(intbv(0)[33:]),
s_axis_cc_tlast=Signal(bool(0)),
s_axis_cc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_cc_tvalid=Signal(bool(0)),
s_axis_cc_tready=Signal(bool(0)),
# Requester reQuest Interface
s_axis_rq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_rq_tuser=Signal(intbv(0)[60:]),
s_axis_rq_tlast=Signal(bool(0)),
s_axis_rq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_rq_tvalid=Signal(bool(0)),
s_axis_rq_tready=Signal(bool(1)),
# 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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_rc_tuser=Signal(intbv(0)[75:]),
m_axis_rc_tlast=Signal(bool(0)),
m_axis_rc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_rc_tvalid=Signal(bool(0)),
m_axis_rc_tready=Signal(bool(0)),
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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,
cq_pause=cq_pause,
cc_pause=cc_pause,
rq_pause=rq_pause,
rc_pause=rc_pause
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
s_axis_cq_tdata=s_axis_cq_tdata,
s_axis_cq_tkeep=s_axis_cq_tkeep,
s_axis_cq_tvalid=s_axis_cq_tvalid,
s_axis_cq_tready=s_axis_cq_tready,
s_axis_cq_tlast=s_axis_cq_tlast,
s_axis_cq_tuser=s_axis_cq_tuser,
m_axi_awid=m_axi_awid,
m_axi_awaddr=m_axi_awaddr,
m_axi_awlen=m_axi_awlen,
m_axi_awsize=m_axi_awsize,
m_axi_awburst=m_axi_awburst,
m_axi_awlock=m_axi_awlock,
m_axi_awcache=m_axi_awcache,
m_axi_awprot=m_axi_awprot,
m_axi_awvalid=m_axi_awvalid,
m_axi_awready=m_axi_awready,
m_axi_wdata=m_axi_wdata,
m_axi_wstrb=m_axi_wstrb,
m_axi_wlast=m_axi_wlast,
m_axi_wvalid=m_axi_wvalid,
m_axi_wready=m_axi_wready,
m_axi_bid=m_axi_bid,
m_axi_bresp=m_axi_bresp,
m_axi_bvalid=m_axi_bvalid,
m_axi_bready=m_axi_bready,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
status_error_uncor_asserted = Signal(bool(0))
@always(user_clk.posedge)
def monitor():
if (status_error_uncor):
status_error_uncor_asserted.next = 1
cq_pause_toggle = Signal(bool(0))
cc_pause_toggle = Signal(bool(0))
rq_pause_toggle = Signal(bool(0))
rc_pause_toggle = Signal(bool(0))
@instance
def pause_toggle():
while True:
if (cq_pause_toggle or cc_pause_toggle or rq_pause_toggle or rc_pause_toggle):
cq_pause.next = cq_pause_toggle
cc_pause.next = cc_pause_toggle
rq_pause.next = rq_pause_toggle
rc_pause.next = rc_pause_toggle
yield user_clk.posedge
yield user_clk.posedge
yield user_clk.posedge
cq_pause.next = 0
cc_pause.next = 0
rq_pause.next = 0
rc_pause.next = 0
yield user_clk.posedge
@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
# testbench stimulus
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate()
dev_bar0 = rc.tree[0][0].bar[0]
yield delay(100)
yield clk.posedge
print("test 2: memory write")
current_test.next = 2
pcie_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
yield rc.mem_write(dev_bar0+pcie_addr, test_data)
yield delay(300)
data = axi_ram_inst.read_mem(pcie_addr, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(pcie_addr, len(test_data)) == test_data
assert not status_error_uncor_asserted
yield delay(100)
yield user_clk.posedge
print("test 3: various writes")
current_test.next = 3
for length in list(range(1,34))+[1024]:
for pcie_offset in list(range(8,41))+list(range(4096-32,4096)):
for pause in [False, True]:
print("length %d, pcie_offset %d"% (length, pcie_offset))
#pcie_addr = length * 0x100000000 + pcie_offset * 0x10000 + offset
pcie_addr = pcie_offset
test_data = bytearray([x%256 for x in range(length)])
axi_ram_inst.write_mem(pcie_addr & 0xffff80, b'\x55'*(len(test_data)+256))
cq_pause_toggle.next = pause
yield from rc.mem_write(dev_bar0+pcie_addr, test_data)
yield delay(int(length*4+60))
cq_pause_toggle.next = 0
data = axi_ram_inst.read_mem(pcie_addr&0xfffff0, 64)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(pcie_addr-1, len(test_data)+2) == b'\x55'+test_data+b'\x55'
assert not status_error_uncor_asserted
yield delay(100)
yield clk.posedge
print("test 4: bad request")
current_test.next = 4
try:
yield from rc.mem_read(dev_bar0, 4, 100)
except:
print("Caught timeout exception")
pass
else:
assert False
assert status_error_uncor_asserted
status_error_uncor_asserted.next = False
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,158 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_master_wr
*/
module test_pcie_us_axi_master_wr_256;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 256;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep = 0;
reg s_axis_cq_tvalid = 0;
reg s_axis_cq_tlast = 0;
reg [84:0] s_axis_cq_tuser = 0;
reg m_axi_awready = 0;
reg m_axi_wready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_bid = 0;
reg [1:0] m_axi_bresp = 0;
reg m_axi_bvalid = 0;
// Outputs
wire s_axis_cq_tready;
wire [AXI_ID_WIDTH-1:0] m_axi_awid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr;
wire [7:0] m_axi_awlen;
wire [2:0] m_axi_awsize;
wire [1:0] m_axi_awburst;
wire m_axi_awlock;
wire [3:0] m_axi_awcache;
wire [2:0] m_axi_awprot;
wire m_axi_awvalid;
wire [AXI_DATA_WIDTH-1:0] m_axi_wdata;
wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb;
wire m_axi_wlast;
wire m_axi_wvalid;
wire m_axi_bready;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_cq_tdata,
s_axis_cq_tkeep,
s_axis_cq_tvalid,
s_axis_cq_tlast,
s_axis_cq_tuser,
m_axi_awready,
m_axi_wready,
m_axi_bid,
m_axi_bresp,
m_axi_bvalid
);
$to_myhdl(
s_axis_cq_tready,
m_axi_awid,
m_axi_awaddr,
m_axi_awlen,
m_axi_awsize,
m_axi_awburst,
m_axi_awlock,
m_axi_awcache,
m_axi_awprot,
m_axi_awvalid,
m_axi_wdata,
m_axi_wstrb,
m_axi_wlast,
m_axi_wvalid,
m_axi_bready,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axi_master_wr_256.lxt");
$dumpvars(0, test_pcie_us_axi_master_wr_256);
end
pcie_us_axi_master_wr #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_cq_tdata(s_axis_cq_tdata),
.s_axis_cq_tkeep(s_axis_cq_tkeep),
.s_axis_cq_tvalid(s_axis_cq_tvalid),
.s_axis_cq_tready(s_axis_cq_tready),
.s_axis_cq_tlast(s_axis_cq_tlast),
.s_axis_cq_tuser(s_axis_cq_tuser),
.m_axi_awid(m_axi_awid),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awlen(m_axi_awlen),
.m_axi_awsize(m_axi_awsize),
.m_axi_awburst(m_axi_awburst),
.m_axi_awlock(m_axi_awlock),
.m_axi_awcache(m_axi_awcache),
.m_axi_awprot(m_axi_awprot),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wstrb(m_axi_wstrb),
.m_axi_wlast(m_axi_wlast),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
.status_error_uncor(status_error_uncor)
);
endmodule

View File

@ -0,0 +1,403 @@
#!/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 os
import pcie
import pcie_us
import axi
module = 'pcie_us_axi_master_wr'
testbench = 'test_%s_64' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 64
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
AXI_ID_WIDTH = 8
AXI_MAX_BURST_LEN = 256
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_cq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_cq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_cq_tvalid = Signal(bool(0))
s_axis_cq_tlast = Signal(bool(0))
s_axis_cq_tuser = Signal(intbv(0)[85:])
m_axi_awready = Signal(bool(0))
m_axi_wready = Signal(bool(0))
m_axi_bid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_bresp = Signal(intbv(0)[2:])
m_axi_bvalid = Signal(bool(0))
# Outputs
s_axis_cq_tready = Signal(bool(0))
m_axi_awid = Signal(intbv(0)[AXI_ID_WIDTH:])
m_axi_awaddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axi_awlen = Signal(intbv(0)[8:])
m_axi_awsize = Signal(intbv(3)[3:])
m_axi_awburst = Signal(intbv(1)[2:])
m_axi_awlock = Signal(bool(0))
m_axi_awcache = Signal(intbv(3)[4:])
m_axi_awprot = Signal(intbv(2)[3:])
m_axi_awvalid = Signal(bool(0))
m_axi_wdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axi_wstrb = Signal(intbv(0)[AXI_STRB_WIDTH:])
m_axi_wlast = Signal(bool(0))
m_axi_wvalid = Signal(bool(0))
m_axi_bready = Signal(bool(1))
status_error_uncor = Signal(bool(0))
# Clock and Reset Interface
user_clk=Signal(bool(0))
user_reset=Signal(bool(0))
sys_clk=Signal(bool(0))
sys_reset=Signal(bool(0))
# AXI4 RAM model
axi_ram_inst = axi.AXIRam(2**16)
axi_ram_port0 = axi_ram_inst.create_port(
user_clk,
s_axi_awid=m_axi_awid,
s_axi_awaddr=m_axi_awaddr,
s_axi_awlen=m_axi_awlen,
s_axi_awsize=m_axi_awsize,
s_axi_awburst=m_axi_awburst,
s_axi_awlock=m_axi_awlock,
s_axi_awcache=m_axi_awcache,
s_axi_awprot=m_axi_awprot,
s_axi_awvalid=m_axi_awvalid,
s_axi_awready=m_axi_awready,
s_axi_wdata=m_axi_wdata,
s_axi_wstrb=m_axi_wstrb,
s_axi_wlast=m_axi_wlast,
s_axi_wvalid=m_axi_wvalid,
s_axi_wready=m_axi_wready,
s_axi_bid=m_axi_bid,
s_axi_bresp=m_axi_bresp,
s_axi_bvalid=m_axi_bvalid,
s_axi_bready=m_axi_bready,
name='port0'
)
# PCIe devices
rc = pcie.RootComplex()
dev = pcie_us.UltrascalePCIe()
dev.pcie_generation = 3
dev.pcie_link_width = 2
dev.user_clock_frequency = 250e6
dev.functions[0].configure_bar(0, 16*1024*1024)
rc.make_port().connect(dev)
cq_pause = Signal(bool(0))
cc_pause = Signal(bool(0))
rq_pause = Signal(bool(0))
rc_pause = Signal(bool(0))
pcie_logic = dev.create_logic(
# Completer reQuest Interface
m_axis_cq_tdata=s_axis_cq_tdata,
m_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cq_tlast=s_axis_cq_tlast,
m_axis_cq_tkeep=s_axis_cq_tkeep,
m_axis_cq_tvalid=s_axis_cq_tvalid,
m_axis_cq_tready=s_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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_cc_tuser=Signal(intbv(0)[33:]),
s_axis_cc_tlast=Signal(bool(0)),
s_axis_cc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_cc_tvalid=Signal(bool(0)),
s_axis_cc_tready=Signal(bool(0)),
# Requester reQuest Interface
s_axis_rq_tdata=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
s_axis_rq_tuser=Signal(intbv(0)[60:]),
s_axis_rq_tlast=Signal(bool(0)),
s_axis_rq_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
s_axis_rq_tvalid=Signal(bool(0)),
s_axis_rq_tready=Signal(bool(1)),
# 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=Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:]),
m_axis_rc_tuser=Signal(intbv(0)[75:]),
m_axis_rc_tlast=Signal(bool(0)),
m_axis_rc_tkeep=Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:]),
m_axis_rc_tvalid=Signal(bool(0)),
m_axis_rc_tready=Signal(bool(0)),
# Transmit Flow Control Interface
# pcie_tfc_nph_av=pcie_tfc_nph_av,
# pcie_tfc_npd_av=pcie_tfc_npd_av,
# 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,
# 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,
cq_pause=cq_pause,
cc_pause=cc_pause,
rq_pause=rq_pause,
rc_pause=rc_pause
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=user_clk,
rst=user_reset,
current_test=current_test,
s_axis_cq_tdata=s_axis_cq_tdata,
s_axis_cq_tkeep=s_axis_cq_tkeep,
s_axis_cq_tvalid=s_axis_cq_tvalid,
s_axis_cq_tready=s_axis_cq_tready,
s_axis_cq_tlast=s_axis_cq_tlast,
s_axis_cq_tuser=s_axis_cq_tuser,
m_axi_awid=m_axi_awid,
m_axi_awaddr=m_axi_awaddr,
m_axi_awlen=m_axi_awlen,
m_axi_awsize=m_axi_awsize,
m_axi_awburst=m_axi_awburst,
m_axi_awlock=m_axi_awlock,
m_axi_awcache=m_axi_awcache,
m_axi_awprot=m_axi_awprot,
m_axi_awvalid=m_axi_awvalid,
m_axi_awready=m_axi_awready,
m_axi_wdata=m_axi_wdata,
m_axi_wstrb=m_axi_wstrb,
m_axi_wlast=m_axi_wlast,
m_axi_wvalid=m_axi_wvalid,
m_axi_wready=m_axi_wready,
m_axi_bid=m_axi_bid,
m_axi_bresp=m_axi_bresp,
m_axi_bvalid=m_axi_bvalid,
m_axi_bready=m_axi_bready,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
@always_comb
def clk_logic():
sys_clk.next = clk
sys_reset.next = not rst
status_error_uncor_asserted = Signal(bool(0))
@always(user_clk.posedge)
def monitor():
if (status_error_uncor):
status_error_uncor_asserted.next = 1
cq_pause_toggle = Signal(bool(0))
cc_pause_toggle = Signal(bool(0))
rq_pause_toggle = Signal(bool(0))
rc_pause_toggle = Signal(bool(0))
@instance
def pause_toggle():
while True:
if (cq_pause_toggle or cc_pause_toggle or rq_pause_toggle or rc_pause_toggle):
cq_pause.next = cq_pause_toggle
cc_pause.next = cc_pause_toggle
rq_pause.next = rq_pause_toggle
rc_pause.next = rc_pause_toggle
yield user_clk.posedge
yield user_clk.posedge
yield user_clk.posedge
cq_pause.next = 0
cc_pause.next = 0
rq_pause.next = 0
rc_pause.next = 0
yield user_clk.posedge
@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
# testbench stimulus
yield user_clk.posedge
print("test 1: enumeration")
current_test.next = 1
yield rc.enumerate()
dev_bar0 = rc.tree[0][0].bar[0]
yield delay(100)
yield clk.posedge
print("test 2: memory write")
current_test.next = 2
pcie_addr = 0x00000000
test_data = b'\x11\x22\x33\x44'
yield rc.mem_write(dev_bar0+pcie_addr, test_data)
yield delay(300)
data = axi_ram_inst.read_mem(pcie_addr, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(pcie_addr, len(test_data)) == test_data
assert not status_error_uncor_asserted
yield delay(100)
yield user_clk.posedge
print("test 3: various writes")
current_test.next = 3
for length in list(range(1,34))+[1024]:
for pcie_offset in list(range(8,41))+list(range(4096-32,4096)):
for pause in [False, True]:
print("length %d, pcie_offset %d"% (length, pcie_offset))
#pcie_addr = length * 0x100000000 + pcie_offset * 0x10000 + offset
pcie_addr = pcie_offset
test_data = bytearray([x%256 for x in range(length)])
axi_ram_inst.write_mem(pcie_addr & 0xffff80, b'\x55'*(len(test_data)+256))
cq_pause_toggle.next = pause
yield from rc.mem_write(dev_bar0+pcie_addr, test_data)
yield delay(length*4+120)
cq_pause_toggle.next = 0
data = axi_ram_inst.read_mem(pcie_addr&0xfffff0, 64)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axi_ram_inst.read_mem(pcie_addr-1, len(test_data)+2) == b'\x55'+test_data+b'\x55'
assert not status_error_uncor_asserted
yield delay(100)
yield clk.posedge
print("test 4: bad request")
current_test.next = 4
try:
yield from rc.mem_read(dev_bar0, 4, 100)
except:
print("Caught timeout exception")
pass
else:
assert False
assert status_error_uncor_asserted
status_error_uncor_asserted.next = False
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,158 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axi_master_wr
*/
module test_pcie_us_axi_master_wr_64;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 64;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = AXIS_PCIE_DATA_WIDTH;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter AXI_ID_WIDTH = 8;
parameter AXI_MAX_BURST_LEN = 256;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep = 0;
reg s_axis_cq_tvalid = 0;
reg s_axis_cq_tlast = 0;
reg [84:0] s_axis_cq_tuser = 0;
reg m_axi_awready = 0;
reg m_axi_wready = 0;
reg [AXI_ID_WIDTH-1:0] m_axi_bid = 0;
reg [1:0] m_axi_bresp = 0;
reg m_axi_bvalid = 0;
// Outputs
wire s_axis_cq_tready;
wire [AXI_ID_WIDTH-1:0] m_axi_awid;
wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr;
wire [7:0] m_axi_awlen;
wire [2:0] m_axi_awsize;
wire [1:0] m_axi_awburst;
wire m_axi_awlock;
wire [3:0] m_axi_awcache;
wire [2:0] m_axi_awprot;
wire m_axi_awvalid;
wire [AXI_DATA_WIDTH-1:0] m_axi_wdata;
wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb;
wire m_axi_wlast;
wire m_axi_wvalid;
wire m_axi_bready;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_cq_tdata,
s_axis_cq_tkeep,
s_axis_cq_tvalid,
s_axis_cq_tlast,
s_axis_cq_tuser,
m_axi_awready,
m_axi_wready,
m_axi_bid,
m_axi_bresp,
m_axi_bvalid
);
$to_myhdl(
s_axis_cq_tready,
m_axi_awid,
m_axi_awaddr,
m_axi_awlen,
m_axi_awsize,
m_axi_awburst,
m_axi_awlock,
m_axi_awcache,
m_axi_awprot,
m_axi_awvalid,
m_axi_wdata,
m_axi_wstrb,
m_axi_wlast,
m_axi_wvalid,
m_axi_bready,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axi_master_wr_64.lxt");
$dumpvars(0, test_pcie_us_axi_master_wr_64);
end
pcie_us_axi_master_wr #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_cq_tdata(s_axis_cq_tdata),
.s_axis_cq_tkeep(s_axis_cq_tkeep),
.s_axis_cq_tvalid(s_axis_cq_tvalid),
.s_axis_cq_tready(s_axis_cq_tready),
.s_axis_cq_tlast(s_axis_cq_tlast),
.s_axis_cq_tuser(s_axis_cq_tuser),
.m_axi_awid(m_axi_awid),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awlen(m_axi_awlen),
.m_axi_awsize(m_axi_awsize),
.m_axi_awburst(m_axi_awburst),
.m_axi_awlock(m_axi_awlock),
.m_axi_awcache(m_axi_awcache),
.m_axi_awprot(m_axi_awprot),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wstrb(m_axi_wstrb),
.m_axi_wlast(m_axi_wlast),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
.status_error_uncor(status_error_uncor)
);
endmodule

View File

@ -0,0 +1,532 @@
#!/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 os
import axis_ep
import axil
import pcie_us
module = 'pcie_us_axil_master'
testbench = 'test_%s_128' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 128
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = 32
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
ENABLE_PARITY = 0
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_cq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_cq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_cq_tvalid = Signal(bool(0))
s_axis_cq_tlast = Signal(bool(0))
s_axis_cq_tuser = Signal(intbv(0)[85:])
m_axis_cc_tready = Signal(bool(0))
m_axil_awready = Signal(bool(0))
m_axil_wready = Signal(bool(0))
m_axil_bresp = Signal(intbv(0)[2:])
m_axil_bvalid = Signal(bool(0))
m_axil_arready = Signal(bool(0))
m_axil_rdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axil_rresp = Signal(intbv(0)[2:])
m_axil_rvalid = Signal(bool(0))
completer_id = Signal(intbv(0)[16:])
completer_id_enable = Signal(bool(0))
# Outputs
s_axis_cq_tready = Signal(bool(0))
m_axis_cc_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_cc_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_cc_tvalid = Signal(bool(0))
m_axis_cc_tlast = Signal(bool(0))
m_axis_cc_tuser = Signal(intbv(0)[33:])
m_axil_awaddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axil_awprot = Signal(intbv(0)[3:])
m_axil_awvalid = Signal(bool(0))
m_axil_wdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axil_wstrb = Signal(intbv(0)[AXI_STRB_WIDTH:])
m_axil_wvalid = Signal(bool(0))
m_axil_bready = Signal(bool(0))
m_axil_araddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axil_arprot = Signal(intbv(2)[3:])
m_axil_arvalid = Signal(bool(0))
m_axil_rready = Signal(bool(0))
status_error_cor = Signal(bool(0))
status_error_uncor = Signal(bool(0))
# sources and sinks
cq_source = axis_ep.AXIStreamSource()
cq_source_logic = cq_source.create_logic(
clk,
rst,
tdata=s_axis_cq_tdata,
tkeep=s_axis_cq_tkeep,
tvalid=s_axis_cq_tvalid,
tready=s_axis_cq_tready,
tlast=s_axis_cq_tlast,
tuser=s_axis_cq_tuser,
name='cq_source'
)
cc_sink = axis_ep.AXIStreamSink()
cc_sink_logic = cc_sink.create_logic(
clk,
rst,
tdata=m_axis_cc_tdata,
tkeep=m_axis_cc_tkeep,
tvalid=m_axis_cc_tvalid,
tready=m_axis_cc_tready,
tlast=m_axis_cc_tlast,
tuser=m_axis_cc_tuser,
name='cc_sink'
)
# AXI4-Lite RAM model
axil_ram_inst = axil.AXILiteRam(2**16)
axil_ram_port0 = axil_ram_inst.create_port(
clk,
s_axil_awaddr=m_axil_awaddr,
s_axil_awprot=m_axil_awprot,
s_axil_awvalid=m_axil_awvalid,
s_axil_awready=m_axil_awready,
s_axil_wdata=m_axil_wdata,
s_axil_wstrb=m_axil_wstrb,
s_axil_wvalid=m_axil_wvalid,
s_axil_wready=m_axil_wready,
s_axil_bresp=m_axil_bresp,
s_axil_bvalid=m_axil_bvalid,
s_axil_bready=m_axil_bready,
s_axil_araddr=m_axil_araddr,
s_axil_arprot=m_axil_arprot,
s_axil_arvalid=m_axil_arvalid,
s_axil_arready=m_axil_arready,
s_axil_rdata=m_axil_rdata,
s_axil_rresp=m_axil_rresp,
s_axil_rvalid=m_axil_rvalid,
s_axil_rready=m_axil_rready,
latency=1,
name='ram'
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=clk,
rst=rst,
current_test=current_test,
s_axis_cq_tdata=s_axis_cq_tdata,
s_axis_cq_tkeep=s_axis_cq_tkeep,
s_axis_cq_tvalid=s_axis_cq_tvalid,
s_axis_cq_tready=s_axis_cq_tready,
s_axis_cq_tlast=s_axis_cq_tlast,
s_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cc_tdata=m_axis_cc_tdata,
m_axis_cc_tkeep=m_axis_cc_tkeep,
m_axis_cc_tvalid=m_axis_cc_tvalid,
m_axis_cc_tready=m_axis_cc_tready,
m_axis_cc_tlast=m_axis_cc_tlast,
m_axis_cc_tuser=m_axis_cc_tuser,
m_axil_awaddr=m_axil_awaddr,
m_axil_awprot=m_axil_awprot,
m_axil_awvalid=m_axil_awvalid,
m_axil_awready=m_axil_awready,
m_axil_wdata=m_axil_wdata,
m_axil_wstrb=m_axil_wstrb,
m_axil_wvalid=m_axil_wvalid,
m_axil_wready=m_axil_wready,
m_axil_bresp=m_axil_bresp,
m_axil_bvalid=m_axil_bvalid,
m_axil_bready=m_axil_bready,
m_axil_araddr=m_axil_araddr,
m_axil_arprot=m_axil_arprot,
m_axil_arvalid=m_axil_arvalid,
m_axil_arready=m_axil_arready,
m_axil_rdata=m_axil_rdata,
m_axil_rresp=m_axil_rresp,
m_axil_rvalid=m_axil_rvalid,
m_axil_rready=m_axil_rready,
completer_id=completer_id,
completer_id_enable=completer_id_enable,
status_error_cor=status_error_cor,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
status_error_cor_asserted = Signal(bool(0))
status_error_uncor_asserted = Signal(bool(0))
@always(clk.posedge)
def monitor():
if (status_error_cor):
status_error_cor_asserted.next = 1
if (status_error_uncor):
status_error_uncor_asserted.next = 1
@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
# testbench stimulus
cur_tag = 1
completer_id.next = int(pcie_us.PcieId(4, 5, 6))
yield clk.posedge
print("test 1: baseline")
current_test.next = 1
data = axil_ram_inst.read_mem(0, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
yield delay(100)
yield clk.posedge
print("test 2: memory write")
current_test.next = 2
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_WRITE
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.set_be_data(0x0000, b'\x11\x22\x33\x44')
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield delay(100)
data = axil_ram_inst.read_mem(0, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axil_ram_inst.read_mem(0, 4) == b'\x11\x22\x33\x44'
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 3: IO write")
current_test.next = 3
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_IO_WRITE
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.set_be_data(0x0000, b'\x11\x22\x33\x44')
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield cc_sink.wait(500)
pkt = cc_sink.recv()
rx_tlp = pcie_us.TLP_us().unpack_us_cc(pkt, AXIS_PCIE_DATA_WIDTH)
print(rx_tlp)
assert rx_tlp.status == pcie_us.CPL_STATUS_SC
assert rx_tlp.tag == cur_tag
assert rx_tlp.completer_id == pcie_us.PcieId(4, 5, 6)
data = axil_ram_inst.read_mem(0, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axil_ram_inst.read_mem(0, 4) == b'\x11\x22\x33\x44'
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 4: memory read")
current_test.next = 4
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_READ
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.length = 1
tlp.set_be(0x0000, 4)
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield cc_sink.wait(500)
pkt = cc_sink.recv()
rx_tlp = pcie_us.TLP_us().unpack_us_cc(pkt, AXIS_PCIE_DATA_WIDTH)
print(rx_tlp)
data = rx_tlp.get_data()
print(data)
assert data == b'\x11\x22\x33\x44'
assert rx_tlp.status == pcie_us.CPL_STATUS_SC
assert rx_tlp.tag == cur_tag
assert rx_tlp.completer_id == pcie_us.PcieId(4, 5, 6)
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 5: IO read")
current_test.next = 5
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_IO_READ
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.length = 1
tlp.set_be(0x0000, 4)
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield cc_sink.wait(500)
pkt = cc_sink.recv()
rx_tlp = pcie_us.TLP_us().unpack_us_cc(pkt, AXIS_PCIE_DATA_WIDTH)
print(rx_tlp)
data = rx_tlp.get_data()
print(data)
assert data == b'\x11\x22\x33\x44'
assert rx_tlp.status == pcie_us.CPL_STATUS_SC
assert rx_tlp.tag == cur_tag
assert rx_tlp.completer_id == pcie_us.PcieId(4, 5, 6)
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 6: various writes")
current_test.next = 6
for length in range(1,5):
for offset in range(4,8-length+1):
axil_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*32)
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_WRITE
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.set_be_data(256*(16*offset+length)+offset, b'\x11\x22\x33\x44'[0:length])
tlp.address = 256*(16*offset+length)+offset
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield delay(100)
data = axil_ram_inst.read_mem(256*(16*offset+length), 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axil_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44'[0:length]
assert axil_ram_inst.read_mem(256*(16*offset+length)+offset-1, 1) == b'\xAA'
assert axil_ram_inst.read_mem(256*(16*offset+length)+offset+length, 1) == b'\xAA'
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 7: various reads")
current_test.next = 7
for length in range(1,5):
for offset in range(4,8-length+1):
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_READ
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.length = 1
tlp.set_be(256*(16*offset+length)+offset, length)
tlp.address = 256*(16*offset+length)+offset
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield cc_sink.wait(500)
pkt = cc_sink.recv()
rx_tlp = pcie_us.TLP_us().unpack_us_cc(pkt, AXIS_PCIE_DATA_WIDTH)
print(rx_tlp)
data = rx_tlp.get_data()
print(data)
assert data == b'\xAA'*(offset-4)+b'\x11\x22\x33\x44'[0:length]+b'\xAA'*(8-offset-length)
assert rx_tlp.status == pcie_us.CPL_STATUS_SC
assert rx_tlp.tag == cur_tag
assert rx_tlp.completer_id == pcie_us.PcieId(4, 5, 6)
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 8: bad memory write")
current_test.next = 8
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_WRITE
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.set_be_data(0x0000, bytearray(range(64)))
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield delay(100)
assert not status_error_cor_asserted
assert status_error_uncor_asserted
status_error_uncor_asserted.next = 0
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 9: bad memory read")
current_test.next = 9
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_READ
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.set_be(0x0000, 64)
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield cc_sink.wait(500)
pkt = cc_sink.recv()
rx_tlp = pcie_us.TLP_us().unpack_us_cc(pkt, AXIS_PCIE_DATA_WIDTH)
print(rx_tlp)
assert rx_tlp.status == pcie_us.CPL_STATUS_CA
assert rx_tlp.tag == cur_tag
assert rx_tlp.completer_id == pcie_us.PcieId(4, 5, 6)
assert status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,183 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axil_master
*/
module test_pcie_us_axil_master_128;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 128;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = 32;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter ENABLE_PARITY = 0;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep = 0;
reg s_axis_cq_tvalid = 0;
reg s_axis_cq_tlast = 0;
reg [84:0] s_axis_cq_tuser = 0;
reg m_axis_cc_tready = 0;
reg m_axil_awready = 0;
reg m_axil_wready = 0;
reg [1:0] m_axil_bresp = 0;
reg m_axil_bvalid = 0;
reg m_axil_arready = 0;
reg [AXI_DATA_WIDTH-1:0] m_axil_rdata = 0;
reg [1:0] m_axil_rresp = 0;
reg m_axil_rvalid = 0;
reg [15:0] completer_id = 0;
reg completer_id_enable = 0;
// Outputs
wire s_axis_cq_tready;
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep;
wire m_axis_cc_tvalid;
wire m_axis_cc_tlast;
wire [32:0] m_axis_cc_tuser;
wire [AXI_ADDR_WIDTH-1:0] m_axil_awaddr;
wire [2:0] m_axil_awprot;
wire m_axil_awvalid;
wire [AXI_DATA_WIDTH-1:0] m_axil_wdata;
wire [AXI_STRB_WIDTH-1:0] m_axil_wstrb;
wire m_axil_wvalid;
wire m_axil_bready;
wire [AXI_ADDR_WIDTH-1:0] m_axil_araddr;
wire [2:0] m_axil_arprot;
wire m_axil_arvalid;
wire m_axil_rready;
wire status_error_cor;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_cq_tdata,
s_axis_cq_tkeep,
s_axis_cq_tvalid,
s_axis_cq_tlast,
s_axis_cq_tuser,
m_axis_cc_tready,
m_axil_awready,
m_axil_wready,
m_axil_bresp,
m_axil_bvalid,
m_axil_arready,
m_axil_rdata,
m_axil_rresp,
m_axil_rvalid,
completer_id,
completer_id_enable
);
$to_myhdl(
s_axis_cq_tready,
m_axis_cc_tdata,
m_axis_cc_tkeep,
m_axis_cc_tvalid,
m_axis_cc_tlast,
m_axis_cc_tuser,
m_axil_awaddr,
m_axil_awprot,
m_axil_awvalid,
m_axil_wdata,
m_axil_wstrb,
m_axil_wvalid,
m_axil_bready,
m_axil_araddr,
m_axil_arprot,
m_axil_arvalid,
m_axil_rready,
status_error_cor,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axil_master_128.lxt");
$dumpvars(0, test_pcie_us_axil_master_128);
end
pcie_us_axil_master #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.ENABLE_PARITY(ENABLE_PARITY)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_cq_tdata(s_axis_cq_tdata),
.s_axis_cq_tkeep(s_axis_cq_tkeep),
.s_axis_cq_tvalid(s_axis_cq_tvalid),
.s_axis_cq_tready(s_axis_cq_tready),
.s_axis_cq_tlast(s_axis_cq_tlast),
.s_axis_cq_tuser(s_axis_cq_tuser),
.m_axis_cc_tdata(m_axis_cc_tdata),
.m_axis_cc_tkeep(m_axis_cc_tkeep),
.m_axis_cc_tvalid(m_axis_cc_tvalid),
.m_axis_cc_tready(m_axis_cc_tready),
.m_axis_cc_tlast(m_axis_cc_tlast),
.m_axis_cc_tuser(m_axis_cc_tuser),
.m_axil_awaddr(m_axil_awaddr),
.m_axil_awprot(m_axil_awprot),
.m_axil_awvalid(m_axil_awvalid),
.m_axil_awready(m_axil_awready),
.m_axil_wdata(m_axil_wdata),
.m_axil_wstrb(m_axil_wstrb),
.m_axil_wvalid(m_axil_wvalid),
.m_axil_wready(m_axil_wready),
.m_axil_bresp(m_axil_bresp),
.m_axil_bvalid(m_axil_bvalid),
.m_axil_bready(m_axil_bready),
.m_axil_araddr(m_axil_araddr),
.m_axil_arprot(m_axil_arprot),
.m_axil_arvalid(m_axil_arvalid),
.m_axil_arready(m_axil_arready),
.m_axil_rdata(m_axil_rdata),
.m_axil_rresp(m_axil_rresp),
.m_axil_rvalid(m_axil_rvalid),
.m_axil_rready(m_axil_rready),
.completer_id(completer_id),
.completer_id_enable(completer_id_enable),
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
endmodule

View File

@ -0,0 +1,532 @@
#!/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 os
import axis_ep
import axil
import pcie_us
module = 'pcie_us_axil_master'
testbench = 'test_%s_256' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 256
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = 32
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
ENABLE_PARITY = 0
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_cq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_cq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_cq_tvalid = Signal(bool(0))
s_axis_cq_tlast = Signal(bool(0))
s_axis_cq_tuser = Signal(intbv(0)[85:])
m_axis_cc_tready = Signal(bool(0))
m_axil_awready = Signal(bool(0))
m_axil_wready = Signal(bool(0))
m_axil_bresp = Signal(intbv(0)[2:])
m_axil_bvalid = Signal(bool(0))
m_axil_arready = Signal(bool(0))
m_axil_rdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axil_rresp = Signal(intbv(0)[2:])
m_axil_rvalid = Signal(bool(0))
completer_id = Signal(intbv(0)[16:])
completer_id_enable = Signal(bool(0))
# Outputs
s_axis_cq_tready = Signal(bool(0))
m_axis_cc_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_cc_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_cc_tvalid = Signal(bool(0))
m_axis_cc_tlast = Signal(bool(0))
m_axis_cc_tuser = Signal(intbv(0)[33:])
m_axil_awaddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axil_awprot = Signal(intbv(0)[3:])
m_axil_awvalid = Signal(bool(0))
m_axil_wdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axil_wstrb = Signal(intbv(0)[AXI_STRB_WIDTH:])
m_axil_wvalid = Signal(bool(0))
m_axil_bready = Signal(bool(0))
m_axil_araddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axil_arprot = Signal(intbv(2)[3:])
m_axil_arvalid = Signal(bool(0))
m_axil_rready = Signal(bool(0))
status_error_cor = Signal(bool(0))
status_error_uncor = Signal(bool(0))
# sources and sinks
cq_source = axis_ep.AXIStreamSource()
cq_source_logic = cq_source.create_logic(
clk,
rst,
tdata=s_axis_cq_tdata,
tkeep=s_axis_cq_tkeep,
tvalid=s_axis_cq_tvalid,
tready=s_axis_cq_tready,
tlast=s_axis_cq_tlast,
tuser=s_axis_cq_tuser,
name='cq_source'
)
cc_sink = axis_ep.AXIStreamSink()
cc_sink_logic = cc_sink.create_logic(
clk,
rst,
tdata=m_axis_cc_tdata,
tkeep=m_axis_cc_tkeep,
tvalid=m_axis_cc_tvalid,
tready=m_axis_cc_tready,
tlast=m_axis_cc_tlast,
tuser=m_axis_cc_tuser,
name='cc_sink'
)
# AXI4-Lite RAM model
axil_ram_inst = axil.AXILiteRam(2**16)
axil_ram_port0 = axil_ram_inst.create_port(
clk,
s_axil_awaddr=m_axil_awaddr,
s_axil_awprot=m_axil_awprot,
s_axil_awvalid=m_axil_awvalid,
s_axil_awready=m_axil_awready,
s_axil_wdata=m_axil_wdata,
s_axil_wstrb=m_axil_wstrb,
s_axil_wvalid=m_axil_wvalid,
s_axil_wready=m_axil_wready,
s_axil_bresp=m_axil_bresp,
s_axil_bvalid=m_axil_bvalid,
s_axil_bready=m_axil_bready,
s_axil_araddr=m_axil_araddr,
s_axil_arprot=m_axil_arprot,
s_axil_arvalid=m_axil_arvalid,
s_axil_arready=m_axil_arready,
s_axil_rdata=m_axil_rdata,
s_axil_rresp=m_axil_rresp,
s_axil_rvalid=m_axil_rvalid,
s_axil_rready=m_axil_rready,
latency=1,
name='ram'
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=clk,
rst=rst,
current_test=current_test,
s_axis_cq_tdata=s_axis_cq_tdata,
s_axis_cq_tkeep=s_axis_cq_tkeep,
s_axis_cq_tvalid=s_axis_cq_tvalid,
s_axis_cq_tready=s_axis_cq_tready,
s_axis_cq_tlast=s_axis_cq_tlast,
s_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cc_tdata=m_axis_cc_tdata,
m_axis_cc_tkeep=m_axis_cc_tkeep,
m_axis_cc_tvalid=m_axis_cc_tvalid,
m_axis_cc_tready=m_axis_cc_tready,
m_axis_cc_tlast=m_axis_cc_tlast,
m_axis_cc_tuser=m_axis_cc_tuser,
m_axil_awaddr=m_axil_awaddr,
m_axil_awprot=m_axil_awprot,
m_axil_awvalid=m_axil_awvalid,
m_axil_awready=m_axil_awready,
m_axil_wdata=m_axil_wdata,
m_axil_wstrb=m_axil_wstrb,
m_axil_wvalid=m_axil_wvalid,
m_axil_wready=m_axil_wready,
m_axil_bresp=m_axil_bresp,
m_axil_bvalid=m_axil_bvalid,
m_axil_bready=m_axil_bready,
m_axil_araddr=m_axil_araddr,
m_axil_arprot=m_axil_arprot,
m_axil_arvalid=m_axil_arvalid,
m_axil_arready=m_axil_arready,
m_axil_rdata=m_axil_rdata,
m_axil_rresp=m_axil_rresp,
m_axil_rvalid=m_axil_rvalid,
m_axil_rready=m_axil_rready,
completer_id=completer_id,
completer_id_enable=completer_id_enable,
status_error_cor=status_error_cor,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
status_error_cor_asserted = Signal(bool(0))
status_error_uncor_asserted = Signal(bool(0))
@always(clk.posedge)
def monitor():
if (status_error_cor):
status_error_cor_asserted.next = 1
if (status_error_uncor):
status_error_uncor_asserted.next = 1
@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
# testbench stimulus
cur_tag = 1
completer_id.next = int(pcie_us.PcieId(4, 5, 6))
yield clk.posedge
print("test 1: baseline")
current_test.next = 1
data = axil_ram_inst.read_mem(0, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
yield delay(100)
yield clk.posedge
print("test 2: memory write")
current_test.next = 2
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_WRITE
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.set_be_data(0x0000, b'\x11\x22\x33\x44')
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield delay(100)
data = axil_ram_inst.read_mem(0, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axil_ram_inst.read_mem(0, 4) == b'\x11\x22\x33\x44'
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 3: IO write")
current_test.next = 3
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_IO_WRITE
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.set_be_data(0x0000, b'\x11\x22\x33\x44')
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield cc_sink.wait(500)
pkt = cc_sink.recv()
rx_tlp = pcie_us.TLP_us().unpack_us_cc(pkt, AXIS_PCIE_DATA_WIDTH)
print(rx_tlp)
assert rx_tlp.status == pcie_us.CPL_STATUS_SC
assert rx_tlp.tag == cur_tag
assert rx_tlp.completer_id == pcie_us.PcieId(4, 5, 6)
data = axil_ram_inst.read_mem(0, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axil_ram_inst.read_mem(0, 4) == b'\x11\x22\x33\x44'
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 4: memory read")
current_test.next = 4
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_READ
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.length = 1
tlp.set_be(0x0000, 4)
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield cc_sink.wait(500)
pkt = cc_sink.recv()
rx_tlp = pcie_us.TLP_us().unpack_us_cc(pkt, AXIS_PCIE_DATA_WIDTH)
print(rx_tlp)
data = rx_tlp.get_data()
print(data)
assert data == b'\x11\x22\x33\x44'
assert rx_tlp.status == pcie_us.CPL_STATUS_SC
assert rx_tlp.tag == cur_tag
assert rx_tlp.completer_id == pcie_us.PcieId(4, 5, 6)
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 5: IO read")
current_test.next = 5
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_IO_READ
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.length = 1
tlp.set_be(0x0000, 4)
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield cc_sink.wait(500)
pkt = cc_sink.recv()
rx_tlp = pcie_us.TLP_us().unpack_us_cc(pkt, AXIS_PCIE_DATA_WIDTH)
print(rx_tlp)
data = rx_tlp.get_data()
print(data)
assert data == b'\x11\x22\x33\x44'
assert rx_tlp.status == pcie_us.CPL_STATUS_SC
assert rx_tlp.tag == cur_tag
assert rx_tlp.completer_id == pcie_us.PcieId(4, 5, 6)
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 6: various writes")
current_test.next = 6
for length in range(1,5):
for offset in range(4,8-length+1):
axil_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*32)
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_WRITE
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.set_be_data(256*(16*offset+length)+offset, b'\x11\x22\x33\x44'[0:length])
tlp.address = 256*(16*offset+length)+offset
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield delay(100)
data = axil_ram_inst.read_mem(256*(16*offset+length), 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axil_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44'[0:length]
assert axil_ram_inst.read_mem(256*(16*offset+length)+offset-1, 1) == b'\xAA'
assert axil_ram_inst.read_mem(256*(16*offset+length)+offset+length, 1) == b'\xAA'
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 7: various reads")
current_test.next = 7
for length in range(1,5):
for offset in range(4,8-length+1):
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_READ
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.length = 1
tlp.set_be(256*(16*offset+length)+offset, length)
tlp.address = 256*(16*offset+length)+offset
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield cc_sink.wait(500)
pkt = cc_sink.recv()
rx_tlp = pcie_us.TLP_us().unpack_us_cc(pkt, AXIS_PCIE_DATA_WIDTH)
print(rx_tlp)
data = rx_tlp.get_data()
print(data)
assert data == b'\xAA'*(offset-4)+b'\x11\x22\x33\x44'[0:length]+b'\xAA'*(8-offset-length)
assert rx_tlp.status == pcie_us.CPL_STATUS_SC
assert rx_tlp.tag == cur_tag
assert rx_tlp.completer_id == pcie_us.PcieId(4, 5, 6)
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 8: bad memory write")
current_test.next = 8
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_WRITE
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.set_be_data(0x0000, bytearray(range(64)))
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield delay(100)
assert not status_error_cor_asserted
assert status_error_uncor_asserted
status_error_uncor_asserted.next = 0
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 9: bad memory read")
current_test.next = 9
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_READ
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.set_be(0x0000, 64)
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield cc_sink.wait(500)
pkt = cc_sink.recv()
rx_tlp = pcie_us.TLP_us().unpack_us_cc(pkt, AXIS_PCIE_DATA_WIDTH)
print(rx_tlp)
assert rx_tlp.status == pcie_us.CPL_STATUS_CA
assert rx_tlp.tag == cur_tag
assert rx_tlp.completer_id == pcie_us.PcieId(4, 5, 6)
assert status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,183 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axil_master
*/
module test_pcie_us_axil_master_256;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 256;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = 32;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter ENABLE_PARITY = 0;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep = 0;
reg s_axis_cq_tvalid = 0;
reg s_axis_cq_tlast = 0;
reg [84:0] s_axis_cq_tuser = 0;
reg m_axis_cc_tready = 0;
reg m_axil_awready = 0;
reg m_axil_wready = 0;
reg [1:0] m_axil_bresp = 0;
reg m_axil_bvalid = 0;
reg m_axil_arready = 0;
reg [AXI_DATA_WIDTH-1:0] m_axil_rdata = 0;
reg [1:0] m_axil_rresp = 0;
reg m_axil_rvalid = 0;
reg [15:0] completer_id = 0;
reg completer_id_enable = 0;
// Outputs
wire s_axis_cq_tready;
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep;
wire m_axis_cc_tvalid;
wire m_axis_cc_tlast;
wire [32:0] m_axis_cc_tuser;
wire [AXI_ADDR_WIDTH-1:0] m_axil_awaddr;
wire [2:0] m_axil_awprot;
wire m_axil_awvalid;
wire [AXI_DATA_WIDTH-1:0] m_axil_wdata;
wire [AXI_STRB_WIDTH-1:0] m_axil_wstrb;
wire m_axil_wvalid;
wire m_axil_bready;
wire [AXI_ADDR_WIDTH-1:0] m_axil_araddr;
wire [2:0] m_axil_arprot;
wire m_axil_arvalid;
wire m_axil_rready;
wire status_error_cor;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_cq_tdata,
s_axis_cq_tkeep,
s_axis_cq_tvalid,
s_axis_cq_tlast,
s_axis_cq_tuser,
m_axis_cc_tready,
m_axil_awready,
m_axil_wready,
m_axil_bresp,
m_axil_bvalid,
m_axil_arready,
m_axil_rdata,
m_axil_rresp,
m_axil_rvalid,
completer_id,
completer_id_enable
);
$to_myhdl(
s_axis_cq_tready,
m_axis_cc_tdata,
m_axis_cc_tkeep,
m_axis_cc_tvalid,
m_axis_cc_tlast,
m_axis_cc_tuser,
m_axil_awaddr,
m_axil_awprot,
m_axil_awvalid,
m_axil_wdata,
m_axil_wstrb,
m_axil_wvalid,
m_axil_bready,
m_axil_araddr,
m_axil_arprot,
m_axil_arvalid,
m_axil_rready,
status_error_cor,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axil_master_256.lxt");
$dumpvars(0, test_pcie_us_axil_master_256);
end
pcie_us_axil_master #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.ENABLE_PARITY(ENABLE_PARITY)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_cq_tdata(s_axis_cq_tdata),
.s_axis_cq_tkeep(s_axis_cq_tkeep),
.s_axis_cq_tvalid(s_axis_cq_tvalid),
.s_axis_cq_tready(s_axis_cq_tready),
.s_axis_cq_tlast(s_axis_cq_tlast),
.s_axis_cq_tuser(s_axis_cq_tuser),
.m_axis_cc_tdata(m_axis_cc_tdata),
.m_axis_cc_tkeep(m_axis_cc_tkeep),
.m_axis_cc_tvalid(m_axis_cc_tvalid),
.m_axis_cc_tready(m_axis_cc_tready),
.m_axis_cc_tlast(m_axis_cc_tlast),
.m_axis_cc_tuser(m_axis_cc_tuser),
.m_axil_awaddr(m_axil_awaddr),
.m_axil_awprot(m_axil_awprot),
.m_axil_awvalid(m_axil_awvalid),
.m_axil_awready(m_axil_awready),
.m_axil_wdata(m_axil_wdata),
.m_axil_wstrb(m_axil_wstrb),
.m_axil_wvalid(m_axil_wvalid),
.m_axil_wready(m_axil_wready),
.m_axil_bresp(m_axil_bresp),
.m_axil_bvalid(m_axil_bvalid),
.m_axil_bready(m_axil_bready),
.m_axil_araddr(m_axil_araddr),
.m_axil_arprot(m_axil_arprot),
.m_axil_arvalid(m_axil_arvalid),
.m_axil_arready(m_axil_arready),
.m_axil_rdata(m_axil_rdata),
.m_axil_rresp(m_axil_rresp),
.m_axil_rvalid(m_axil_rvalid),
.m_axil_rready(m_axil_rready),
.completer_id(completer_id),
.completer_id_enable(completer_id_enable),
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
endmodule

View File

@ -0,0 +1,532 @@
#!/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 os
import axis_ep
import axil
import pcie_us
module = 'pcie_us_axil_master'
testbench = 'test_%s_64' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
AXIS_PCIE_DATA_WIDTH = 64
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
AXI_DATA_WIDTH = 32
AXI_ADDR_WIDTH = 64
AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8)
ENABLE_PARITY = 0
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axis_cq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
s_axis_cq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
s_axis_cq_tvalid = Signal(bool(0))
s_axis_cq_tlast = Signal(bool(0))
s_axis_cq_tuser = Signal(intbv(0)[85:])
m_axis_cc_tready = Signal(bool(0))
m_axil_awready = Signal(bool(0))
m_axil_wready = Signal(bool(0))
m_axil_bresp = Signal(intbv(0)[2:])
m_axil_bvalid = Signal(bool(0))
m_axil_arready = Signal(bool(0))
m_axil_rdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axil_rresp = Signal(intbv(0)[2:])
m_axil_rvalid = Signal(bool(0))
completer_id = Signal(intbv(0)[16:])
completer_id_enable = Signal(bool(0))
# Outputs
s_axis_cq_tready = Signal(bool(0))
m_axis_cc_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
m_axis_cc_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
m_axis_cc_tvalid = Signal(bool(0))
m_axis_cc_tlast = Signal(bool(0))
m_axis_cc_tuser = Signal(intbv(0)[33:])
m_axil_awaddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axil_awprot = Signal(intbv(0)[3:])
m_axil_awvalid = Signal(bool(0))
m_axil_wdata = Signal(intbv(0)[AXI_DATA_WIDTH:])
m_axil_wstrb = Signal(intbv(0)[AXI_STRB_WIDTH:])
m_axil_wvalid = Signal(bool(0))
m_axil_bready = Signal(bool(0))
m_axil_araddr = Signal(intbv(0)[AXI_ADDR_WIDTH:])
m_axil_arprot = Signal(intbv(2)[3:])
m_axil_arvalid = Signal(bool(0))
m_axil_rready = Signal(bool(0))
status_error_cor = Signal(bool(0))
status_error_uncor = Signal(bool(0))
# sources and sinks
cq_source = axis_ep.AXIStreamSource()
cq_source_logic = cq_source.create_logic(
clk,
rst,
tdata=s_axis_cq_tdata,
tkeep=s_axis_cq_tkeep,
tvalid=s_axis_cq_tvalid,
tready=s_axis_cq_tready,
tlast=s_axis_cq_tlast,
tuser=s_axis_cq_tuser,
name='cq_source'
)
cc_sink = axis_ep.AXIStreamSink()
cc_sink_logic = cc_sink.create_logic(
clk,
rst,
tdata=m_axis_cc_tdata,
tkeep=m_axis_cc_tkeep,
tvalid=m_axis_cc_tvalid,
tready=m_axis_cc_tready,
tlast=m_axis_cc_tlast,
tuser=m_axis_cc_tuser,
name='cc_sink'
)
# AXI4-Lite RAM model
axil_ram_inst = axil.AXILiteRam(2**16)
axil_ram_port0 = axil_ram_inst.create_port(
clk,
s_axil_awaddr=m_axil_awaddr,
s_axil_awprot=m_axil_awprot,
s_axil_awvalid=m_axil_awvalid,
s_axil_awready=m_axil_awready,
s_axil_wdata=m_axil_wdata,
s_axil_wstrb=m_axil_wstrb,
s_axil_wvalid=m_axil_wvalid,
s_axil_wready=m_axil_wready,
s_axil_bresp=m_axil_bresp,
s_axil_bvalid=m_axil_bvalid,
s_axil_bready=m_axil_bready,
s_axil_araddr=m_axil_araddr,
s_axil_arprot=m_axil_arprot,
s_axil_arvalid=m_axil_arvalid,
s_axil_arready=m_axil_arready,
s_axil_rdata=m_axil_rdata,
s_axil_rresp=m_axil_rresp,
s_axil_rvalid=m_axil_rvalid,
s_axil_rready=m_axil_rready,
latency=1,
name='ram'
)
# DUT
if os.system(build_cmd):
raise Exception("Error running build command")
dut = Cosimulation(
"vvp -m myhdl %s.vvp -lxt2" % testbench,
clk=clk,
rst=rst,
current_test=current_test,
s_axis_cq_tdata=s_axis_cq_tdata,
s_axis_cq_tkeep=s_axis_cq_tkeep,
s_axis_cq_tvalid=s_axis_cq_tvalid,
s_axis_cq_tready=s_axis_cq_tready,
s_axis_cq_tlast=s_axis_cq_tlast,
s_axis_cq_tuser=s_axis_cq_tuser,
m_axis_cc_tdata=m_axis_cc_tdata,
m_axis_cc_tkeep=m_axis_cc_tkeep,
m_axis_cc_tvalid=m_axis_cc_tvalid,
m_axis_cc_tready=m_axis_cc_tready,
m_axis_cc_tlast=m_axis_cc_tlast,
m_axis_cc_tuser=m_axis_cc_tuser,
m_axil_awaddr=m_axil_awaddr,
m_axil_awprot=m_axil_awprot,
m_axil_awvalid=m_axil_awvalid,
m_axil_awready=m_axil_awready,
m_axil_wdata=m_axil_wdata,
m_axil_wstrb=m_axil_wstrb,
m_axil_wvalid=m_axil_wvalid,
m_axil_wready=m_axil_wready,
m_axil_bresp=m_axil_bresp,
m_axil_bvalid=m_axil_bvalid,
m_axil_bready=m_axil_bready,
m_axil_araddr=m_axil_araddr,
m_axil_arprot=m_axil_arprot,
m_axil_arvalid=m_axil_arvalid,
m_axil_arready=m_axil_arready,
m_axil_rdata=m_axil_rdata,
m_axil_rresp=m_axil_rresp,
m_axil_rvalid=m_axil_rvalid,
m_axil_rready=m_axil_rready,
completer_id=completer_id,
completer_id_enable=completer_id_enable,
status_error_cor=status_error_cor,
status_error_uncor=status_error_uncor
)
@always(delay(4))
def clkgen():
clk.next = not clk
status_error_cor_asserted = Signal(bool(0))
status_error_uncor_asserted = Signal(bool(0))
@always(clk.posedge)
def monitor():
if (status_error_cor):
status_error_cor_asserted.next = 1
if (status_error_uncor):
status_error_uncor_asserted.next = 1
@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
# testbench stimulus
cur_tag = 1
completer_id.next = int(pcie_us.PcieId(4, 5, 6))
yield clk.posedge
print("test 1: baseline")
current_test.next = 1
data = axil_ram_inst.read_mem(0, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
yield delay(100)
yield clk.posedge
print("test 2: memory write")
current_test.next = 2
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_WRITE
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.set_be_data(0x0000, b'\x11\x22\x33\x44')
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield delay(100)
data = axil_ram_inst.read_mem(0, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axil_ram_inst.read_mem(0, 4) == b'\x11\x22\x33\x44'
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 3: IO write")
current_test.next = 3
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_IO_WRITE
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.set_be_data(0x0000, b'\x11\x22\x33\x44')
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield cc_sink.wait(500)
pkt = cc_sink.recv()
rx_tlp = pcie_us.TLP_us().unpack_us_cc(pkt, AXIS_PCIE_DATA_WIDTH)
print(rx_tlp)
assert rx_tlp.status == pcie_us.CPL_STATUS_SC
assert rx_tlp.tag == cur_tag
assert rx_tlp.completer_id == pcie_us.PcieId(4, 5, 6)
data = axil_ram_inst.read_mem(0, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axil_ram_inst.read_mem(0, 4) == b'\x11\x22\x33\x44'
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 4: memory read")
current_test.next = 4
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_READ
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.length = 1
tlp.set_be(0x0000, 4)
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield cc_sink.wait(500)
pkt = cc_sink.recv()
rx_tlp = pcie_us.TLP_us().unpack_us_cc(pkt, AXIS_PCIE_DATA_WIDTH)
print(rx_tlp)
data = rx_tlp.get_data()
print(data)
assert data == b'\x11\x22\x33\x44'
assert rx_tlp.status == pcie_us.CPL_STATUS_SC
assert rx_tlp.tag == cur_tag
assert rx_tlp.completer_id == pcie_us.PcieId(4, 5, 6)
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 5: IO read")
current_test.next = 5
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_IO_READ
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.length = 1
tlp.set_be(0x0000, 4)
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield cc_sink.wait(500)
pkt = cc_sink.recv()
rx_tlp = pcie_us.TLP_us().unpack_us_cc(pkt, AXIS_PCIE_DATA_WIDTH)
print(rx_tlp)
data = rx_tlp.get_data()
print(data)
assert data == b'\x11\x22\x33\x44'
assert rx_tlp.status == pcie_us.CPL_STATUS_SC
assert rx_tlp.tag == cur_tag
assert rx_tlp.completer_id == pcie_us.PcieId(4, 5, 6)
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 6: various writes")
current_test.next = 6
for length in range(1,5):
for offset in range(4,8-length+1):
axil_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*32)
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_WRITE
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.set_be_data(256*(16*offset+length)+offset, b'\x11\x22\x33\x44'[0:length])
tlp.address = 256*(16*offset+length)+offset
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield delay(100)
data = axil_ram_inst.read_mem(256*(16*offset+length), 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
assert axil_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44'[0:length]
assert axil_ram_inst.read_mem(256*(16*offset+length)+offset-1, 1) == b'\xAA'
assert axil_ram_inst.read_mem(256*(16*offset+length)+offset+length, 1) == b'\xAA'
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 7: various reads")
current_test.next = 7
for length in range(1,5):
for offset in range(4,8-length+1):
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_READ
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.length = 1
tlp.set_be(256*(16*offset+length)+offset, length)
tlp.address = 256*(16*offset+length)+offset
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield cc_sink.wait(500)
pkt = cc_sink.recv()
rx_tlp = pcie_us.TLP_us().unpack_us_cc(pkt, AXIS_PCIE_DATA_WIDTH)
print(rx_tlp)
data = rx_tlp.get_data()
print(data)
assert data == b'\xAA'*(offset-4)+b'\x11\x22\x33\x44'[0:length]+b'\xAA'*(8-offset-length)
assert rx_tlp.status == pcie_us.CPL_STATUS_SC
assert rx_tlp.tag == cur_tag
assert rx_tlp.completer_id == pcie_us.PcieId(4, 5, 6)
assert not status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 8: bad memory write")
current_test.next = 8
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_WRITE
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.set_be_data(0x0000, bytearray(range(64)))
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield delay(100)
assert not status_error_cor_asserted
assert status_error_uncor_asserted
status_error_uncor_asserted.next = 0
cur_tag = (cur_tag + 1) % 32
yield delay(100)
yield clk.posedge
print("test 9: bad memory read")
current_test.next = 9
tlp = pcie_us.TLP_us()
tlp.fmt_type = pcie_us.TLP_MEM_READ
tlp.requester_id = pcie_us.PcieId(1, 2, 3)
tlp.tag = cur_tag
tlp.tc = 0
tlp.set_be(0x0000, 64)
tlp.address = 0x0000
cq_source.send(tlp.pack_us_cq(AXIS_PCIE_DATA_WIDTH))
yield cc_sink.wait(500)
pkt = cc_sink.recv()
rx_tlp = pcie_us.TLP_us().unpack_us_cc(pkt, AXIS_PCIE_DATA_WIDTH)
print(rx_tlp)
assert rx_tlp.status == pcie_us.CPL_STATUS_CA
assert rx_tlp.tag == cur_tag
assert rx_tlp.completer_id == pcie_us.PcieId(4, 5, 6)
assert status_error_cor_asserted
assert not status_error_uncor_asserted
cur_tag = (cur_tag + 1) % 32
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

View File

@ -0,0 +1,183 @@
/*
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.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Testbench for pcie_us_axil_master
*/
module test_pcie_us_axil_master_64;
// Parameters
parameter AXIS_PCIE_DATA_WIDTH = 64;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
parameter AXI_DATA_WIDTH = 32;
parameter AXI_ADDR_WIDTH = 64;
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8);
parameter ENABLE_PARITY = 0;
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata = 0;
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep = 0;
reg s_axis_cq_tvalid = 0;
reg s_axis_cq_tlast = 0;
reg [84:0] s_axis_cq_tuser = 0;
reg m_axis_cc_tready = 0;
reg m_axil_awready = 0;
reg m_axil_wready = 0;
reg [1:0] m_axil_bresp = 0;
reg m_axil_bvalid = 0;
reg m_axil_arready = 0;
reg [AXI_DATA_WIDTH-1:0] m_axil_rdata = 0;
reg [1:0] m_axil_rresp = 0;
reg m_axil_rvalid = 0;
reg [15:0] completer_id = 0;
reg completer_id_enable = 0;
// Outputs
wire s_axis_cq_tready;
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata;
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep;
wire m_axis_cc_tvalid;
wire m_axis_cc_tlast;
wire [32:0] m_axis_cc_tuser;
wire [AXI_ADDR_WIDTH-1:0] m_axil_awaddr;
wire [2:0] m_axil_awprot;
wire m_axil_awvalid;
wire [AXI_DATA_WIDTH-1:0] m_axil_wdata;
wire [AXI_STRB_WIDTH-1:0] m_axil_wstrb;
wire m_axil_wvalid;
wire m_axil_bready;
wire [AXI_ADDR_WIDTH-1:0] m_axil_araddr;
wire [2:0] m_axil_arprot;
wire m_axil_arvalid;
wire m_axil_rready;
wire status_error_cor;
wire status_error_uncor;
initial begin
// myhdl integration
$from_myhdl(
clk,
rst,
current_test,
s_axis_cq_tdata,
s_axis_cq_tkeep,
s_axis_cq_tvalid,
s_axis_cq_tlast,
s_axis_cq_tuser,
m_axis_cc_tready,
m_axil_awready,
m_axil_wready,
m_axil_bresp,
m_axil_bvalid,
m_axil_arready,
m_axil_rdata,
m_axil_rresp,
m_axil_rvalid,
completer_id,
completer_id_enable
);
$to_myhdl(
s_axis_cq_tready,
m_axis_cc_tdata,
m_axis_cc_tkeep,
m_axis_cc_tvalid,
m_axis_cc_tlast,
m_axis_cc_tuser,
m_axil_awaddr,
m_axil_awprot,
m_axil_awvalid,
m_axil_wdata,
m_axil_wstrb,
m_axil_wvalid,
m_axil_bready,
m_axil_araddr,
m_axil_arprot,
m_axil_arvalid,
m_axil_rready,
status_error_cor,
status_error_uncor
);
// dump file
$dumpfile("test_pcie_us_axil_master_64.lxt");
$dumpvars(0, test_pcie_us_axil_master_64);
end
pcie_us_axil_master #(
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.ENABLE_PARITY(ENABLE_PARITY)
)
UUT (
.clk(clk),
.rst(rst),
.s_axis_cq_tdata(s_axis_cq_tdata),
.s_axis_cq_tkeep(s_axis_cq_tkeep),
.s_axis_cq_tvalid(s_axis_cq_tvalid),
.s_axis_cq_tready(s_axis_cq_tready),
.s_axis_cq_tlast(s_axis_cq_tlast),
.s_axis_cq_tuser(s_axis_cq_tuser),
.m_axis_cc_tdata(m_axis_cc_tdata),
.m_axis_cc_tkeep(m_axis_cc_tkeep),
.m_axis_cc_tvalid(m_axis_cc_tvalid),
.m_axis_cc_tready(m_axis_cc_tready),
.m_axis_cc_tlast(m_axis_cc_tlast),
.m_axis_cc_tuser(m_axis_cc_tuser),
.m_axil_awaddr(m_axil_awaddr),
.m_axil_awprot(m_axil_awprot),
.m_axil_awvalid(m_axil_awvalid),
.m_axil_awready(m_axil_awready),
.m_axil_wdata(m_axil_wdata),
.m_axil_wstrb(m_axil_wstrb),
.m_axil_wvalid(m_axil_wvalid),
.m_axil_wready(m_axil_wready),
.m_axil_bresp(m_axil_bresp),
.m_axil_bvalid(m_axil_bvalid),
.m_axil_bready(m_axil_bready),
.m_axil_araddr(m_axil_araddr),
.m_axil_arprot(m_axil_arprot),
.m_axil_arvalid(m_axil_arvalid),
.m_axil_arready(m_axil_arready),
.m_axil_rdata(m_axil_rdata),
.m_axil_rresp(m_axil_rresp),
.m_axil_rvalid(m_axil_rvalid),
.m_axil_rready(m_axil_rready),
.completer_id(completer_id),
.completer_id_enable(completer_id_enable),
.status_error_cor(status_error_cor),
.status_error_uncor(status_error_uncor)
);
endmodule