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

merged changes in pcie

This commit is contained in:
Alex Forencich 2019-07-15 17:25:16 -07:00
commit 16262b2ead
48 changed files with 12478 additions and 0 deletions

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 PCIe ADM-PCIE-9V3 Example Design
## Introduction
This example design targets the Alpha Data ADM-PCIE-9V3 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: xcvu3p-ffvc1517-2-i
## 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 ADM-PCIE-9V3 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,180 @@
# XDC constraints for the ADM-PCIE-9V3
# part: xcvu3p-ffvc1517-2-i
# 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.EXTMASTERCCLK_EN {DIV-1} [current_design]
set_property BITSTREAM.CONFIG.SPI_32BIT_ADDR YES [current_design]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 8 [current_design]
set_property BITSTREAM.CONFIG.SPI_FALL_EDGE YES [current_design]
set_property BITSTREAM.CONFIG.UNUSEDPIN {Pullnone} [current_design]
set_property BITSTREAM.CONFIG.OVERTEMPSHUTDOWN Enable [current_design]
# 300 MHz system clock
#set_property -dict {LOC AP26 IOSTANDARD LVDS DIFF_TERM_ADV TERM_100} [get_ports clk_300mhz_p]
#set_property -dict {LOC AP27 IOSTANDARD LVDS DIFF_TERM_ADV TERM_100} [get_ports clk_300mhz_n]
#create_clock -period 3.333 -name clk_300mhz [get_ports clk_300mhz_p]
# LEDs
set_property -dict {LOC AT27 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {user_led_g[0]}]
set_property -dict {LOC AU27 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {user_led_g[1]}]
set_property -dict {LOC AU23 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {user_led_r}]
set_property -dict {LOC AH24 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {front_led[0]}]
set_property -dict {LOC AJ23 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {front_led[1]}]
# Switches
#set_property -dict {LOC AV27 IOSTANDARD LVCMOS18} [get_ports {user_sw[0]}]
#set_property -dict {LOC AW27 IOSTANDARD LVCMOS18} [get_ports {user_sw[1]}]
# GPIO
#set_property -dict {LOC G30 IOSTANDARD LVCMOS18} [get_ports gpio_p[0]]
#set_property -dict {LOC F30 IOSTANDARD LVCMOS18} [get_ports gpio_n[0]]
#set_property -dict {LOC J31 IOSTANDARD LVCMOS18} [get_ports gpio_p[1]]
#set_property -dict {LOC H31 IOSTANDARD LVCMOS18} [get_ports gpio_n[1]]
# QSFP28 Interfaces
#set_property -dict {LOC G38 } [get_ports qsfp_0_rx_0_p] ;# MGTYRXN0_128 GTYE3_CHANNEL_X0Y16 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC G39 } [get_ports qsfp_0_rx_0_n] ;# MGTYRXP0_128 GTYE3_CHANNEL_X0Y16 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC E38 } [get_ports qsfp_0_rx_1_p] ;# MGTYRXN1_128 GTYE3_CHANNEL_X0Y17 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC E39 } [get_ports qsfp_0_rx_1_n] ;# MGTYRXP1_128 GTYE3_CHANNEL_X0Y17 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC C38 } [get_ports qsfp_0_rx_2_p] ;# MGTYRXN2_128 GTYE3_CHANNEL_X0Y18 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC C39 } [get_ports qsfp_0_rx_2_n] ;# MGTYRXP2_128 GTYE3_CHANNEL_X0Y18 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC B36 } [get_ports qsfp_0_rx_3_p] ;# MGTYRXN3_128 GTYE3_CHANNEL_X0Y19 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC B37 } [get_ports qsfp_0_rx_3_n] ;# MGTYRXP3_128 GTYE3_CHANNEL_X0Y19 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC F35 } [get_ports qsfp_0_tx_0_p] ;# MGTYTXN0_128 GTYE3_CHANNEL_X0Y16 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC F36 } [get_ports qsfp_0_tx_0_n] ;# MGTYTXP0_128 GTYE3_CHANNEL_X0Y16 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC D35 } [get_ports qsfp_0_tx_1_p] ;# MGTYTXN1_128 GTYE3_CHANNEL_X0Y17 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC D36 } [get_ports qsfp_0_tx_1_n] ;# MGTYTXP1_128 GTYE3_CHANNEL_X0Y17 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC C33 } [get_ports qsfp_0_tx_2_p] ;# MGTYTXN2_128 GTYE3_CHANNEL_X0Y18 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC C34 } [get_ports qsfp_0_tx_2_n] ;# MGTYTXP2_128 GTYE3_CHANNEL_X0Y18 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC A33 } [get_ports qsfp_0_tx_3_p] ;# MGTYTXN3_128 GTYE3_CHANNEL_X0Y19 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC A34 } [get_ports qsfp_0_tx_3_n] ;# MGTYTXP3_128 GTYE3_CHANNEL_X0Y19 / GTYE3_COMMON_X0Y4
#set_property -dict {LOC N33 } [get_ports qsfp_0_mgt_refclk_p] ;# MGTREFCLK0P_128 from ?
#set_property -dict {LOC N34 } [get_ports qsfp_0_mgt_refclk_n] ;# MGTREFCLK0N_128 from ?
#set_property -dict {LOC F29 IOSTANDARD LVCMOS18 PULLUP true} [get_ports qsfp_0_modprs_l]
#set_property -dict {LOC D31 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports qsfp_0_sel_l]
# 161.1328125 MHz MGT reference clock
#create_clock -period 6.206 -name qsfp_0_mgt_refclk [get_ports qsfp_0_mgt_refclk_p]
#set_property -dict {LOC R38 } [get_ports qsfp_1_rx_0_p] ;# MGTYRXN0_127 GTYE3_CHANNEL_X0Y12 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC R39 } [get_ports qsfp_1_rx_0_n] ;# MGTYRXP0_127 GTYE3_CHANNEL_X0Y12 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC N38 } [get_ports qsfp_1_rx_1_p] ;# MGTYRXN1_127 GTYE3_CHANNEL_X0Y13 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC N39 } [get_ports qsfp_1_rx_1_n] ;# MGTYRXP1_127 GTYE3_CHANNEL_X0Y13 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC L38 } [get_ports qsfp_1_rx_2_p] ;# MGTYRXN2_127 GTYE3_CHANNEL_X0Y14 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC L39 } [get_ports qsfp_1_rx_2_n] ;# MGTYRXP2_127 GTYE3_CHANNEL_X0Y14 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC J38 } [get_ports qsfp_1_rx_3_p] ;# MGTYRXN3_127 GTYE3_CHANNEL_X0Y15 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC J39 } [get_ports qsfp_1_rx_3_n] ;# MGTYRXP3_127 GTYE3_CHANNEL_X0Y15 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC P35 } [get_ports qsfp_1_tx_0_p] ;# MGTYTXN0_127 GTYE3_CHANNEL_X0Y12 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC P36 } [get_ports qsfp_1_tx_0_n] ;# MGTYTXP0_127 GTYE3_CHANNEL_X0Y12 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC M35 } [get_ports qsfp_1_tx_1_p] ;# MGTYTXN1_127 GTYE3_CHANNEL_X0Y13 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC M36 } [get_ports qsfp_1_tx_1_n] ;# MGTYTXP1_127 GTYE3_CHANNEL_X0Y13 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC K35 } [get_ports qsfp_1_tx_2_p] ;# MGTYTXN2_127 GTYE3_CHANNEL_X0Y14 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC K36 } [get_ports qsfp_1_tx_2_n] ;# MGTYTXP2_127 GTYE3_CHANNEL_X0Y14 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC H35 } [get_ports qsfp_1_tx_3_p] ;# MGTYTXN3_127 GTYE3_CHANNEL_X0Y15 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC H36 } [get_ports qsfp_1_tx_3_n] ;# MGTYTXP3_127 GTYE3_CHANNEL_X0Y15 / GTYE3_COMMON_X0Y3
#set_property -dict {LOC U33 } [get_ports qsfp_1_mgt_refclk_p] ;# MGTREFCLK0P_127 from ?
#set_property -dict {LOC U34 } [get_ports qsfp_1_mgt_refclk_n] ;# MGTREFCLK0N_127 from ?
#set_property -dict {LOC F33 IOSTANDARD LVCMOS18 PULLUP true} [get_ports qsfp_1_modprs_l]
#set_property -dict {LOC D30 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports qsfp_1_sel_l]
# 161.1328125 MHz MGT reference clock
#create_clock -period 6.206 -name qsfp_1_mgt_refclk [get_ports qsfp_1_mgt_refclk_p]
#set_property -dict {LOC B29 IOSTANDARD LVCMOS18 PULLUP true} [get_ports qsfp_reset_l]
#set_property -dict {LOC C29 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports qsfp_int_l]
#set_property -dict {LOC A28 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports qsfp_i2c_scl]
#set_property -dict {LOC A29 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports qsfp_i2c_sda]
# 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 J2 } [get_ports {pcie_rx_p[0]}] ;# MGTYRXP3_227 GTYE3_CHANNEL_X0Y7 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC J1 } [get_ports {pcie_rx_n[0]}] ;# MGTYTXP3_227 GTYE3_CHANNEL_X0Y7 / GTYE3_COMMON_X0Y1
set_property -dict {LOC H5 } [get_ports {pcie_tx_p[0]}] ;# MGTYTXN3_227 GTYE3_CHANNEL_X0Y7 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC H4 } [get_ports {pcie_tx_n[0]}] ;# MGTYTXP3_227 GTYE3_CHANNEL_X0Y7 / GTYE3_COMMON_X0Y1
set_property -dict {LOC L2 } [get_ports {pcie_rx_p[1]}] ;# MGTYTXN2_227 GTYE3_CHANNEL_X0Y6 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC L1 } [get_ports {pcie_rx_n[1]}] ;# MGTYTXP2_227 GTYE3_CHANNEL_X0Y6 / GTYE3_COMMON_X0Y1
set_property -dict {LOC K5 } [get_ports {pcie_tx_p[1]}] ;# MGTYTXN2_227 GTYE3_CHANNEL_X0Y6 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC K4 } [get_ports {pcie_tx_n[1]}] ;# MGTYTXP2_227 GTYE3_CHANNEL_X0Y6 / GTYE3_COMMON_X0Y1
set_property -dict {LOC N2 } [get_ports {pcie_rx_p[2]}] ;# MGTYTXN1_227 GTYE3_CHANNEL_X0Y5 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC N1 } [get_ports {pcie_rx_n[2]}] ;# MGTYTXP1_227 GTYE3_CHANNEL_X0Y5 / GTYE3_COMMON_X0Y1
set_property -dict {LOC M5 } [get_ports {pcie_tx_p[2]}] ;# MGTYTXN1_227 GTYE3_CHANNEL_X0Y5 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC M4 } [get_ports {pcie_tx_n[2]}] ;# MGTYTXP1_227 GTYE3_CHANNEL_X0Y5 / GTYE3_COMMON_X0Y1
set_property -dict {LOC R2 } [get_ports {pcie_rx_p[3]}] ;# MGTYTXN0_227 GTYE3_CHANNEL_X0Y4 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC R1 } [get_ports {pcie_rx_n[3]}] ;# MGTYTXP0_227 GTYE3_CHANNEL_X0Y4 / GTYE3_COMMON_X0Y1
set_property -dict {LOC P5 } [get_ports {pcie_tx_p[3]}] ;# MGTYTXN0_227 GTYE3_CHANNEL_X0Y4 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC P4 } [get_ports {pcie_tx_n[3]}] ;# MGTYTXP0_227 GTYE3_CHANNEL_X0Y4 / GTYE3_COMMON_X0Y1
set_property -dict {LOC U2 } [get_ports {pcie_rx_p[4]}] ;# MGTYTXN3_226 GTYE3_CHANNEL_X0Y3 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC U1 } [get_ports {pcie_rx_n[4]}] ;# MGTYTXP3_226 GTYE3_CHANNEL_X0Y3 / GTYE3_COMMON_X0Y0
set_property -dict {LOC T5 } [get_ports {pcie_tx_p[4]}] ;# MGTYTXN3_226 GTYE3_CHANNEL_X0Y3 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC T4 } [get_ports {pcie_tx_n[4]}] ;# MGTYTXP3_226 GTYE3_CHANNEL_X0Y3 / GTYE3_COMMON_X0Y0
set_property -dict {LOC W2 } [get_ports {pcie_rx_p[5]}] ;# MGTYTXN2_226 GTYE3_CHANNEL_X0Y2 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC W1 } [get_ports {pcie_rx_n[5]}] ;# MGTYTXP2_226 GTYE3_CHANNEL_X0Y2 / GTYE3_COMMON_X0Y0
set_property -dict {LOC V5 } [get_ports {pcie_tx_p[5]}] ;# MGTYTXN2_226 GTYE3_CHANNEL_X0Y2 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC V4 } [get_ports {pcie_tx_n[5]}] ;# MGTYTXP2_226 GTYE3_CHANNEL_X0Y2 / GTYE3_COMMON_X0Y0
set_property -dict {LOC AA2 } [get_ports {pcie_rx_p[6]}] ;# MGTYTXN1_226 GTYE3_CHANNEL_X0Y1 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AA1 } [get_ports {pcie_rx_n[6]}] ;# MGTYTXP1_226 GTYE3_CHANNEL_X0Y1 / GTYE3_COMMON_X0Y0
set_property -dict {LOC AB5 } [get_ports {pcie_tx_p[6]}] ;# MGTYTXN1_226 GTYE3_CHANNEL_X0Y1 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AB4 } [get_ports {pcie_tx_n[6]}] ;# MGTYTXP1_226 GTYE3_CHANNEL_X0Y1 / GTYE3_COMMON_X0Y0
set_property -dict {LOC AC2 } [get_ports {pcie_rx_p[7]}] ;# MGTYTXN0_226 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AC1 } [get_ports {pcie_rx_n[7]}] ;# MGTYTXP0_226 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
set_property -dict {LOC AD5 } [get_ports {pcie_tx_p[7]}] ;# MGTYTXN0_226 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AD4 } [get_ports {pcie_tx_n[7]}] ;# MGTYTXP0_226 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AE2 } [get_ports {pcie_rx_p[8]}] ;# MGTYTXN3_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AE1 } [get_ports {pcie_rx_n[8]}] ;# MGTYTXP3_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AF5 } [get_ports {pcie_tx_p[8]}] ;# MGTYTXN3_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AF4 } [get_ports {pcie_tx_n[8]}] ;# MGTYTXP3_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AG2 } [get_ports {pcie_rx_p[9]}] ;# MGTYTXN2_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AG1 } [get_ports {pcie_rx_n[9]}] ;# MGTYTXP2_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AH5 } [get_ports {pcie_tx_p[9]}] ;# MGTYTXN2_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AH4 } [get_ports {pcie_tx_n[9]}] ;# MGTYTXP2_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AJ2 } [get_ports {pcie_rx_p[10]}] ;# MGTYTXN1_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AJ1 } [get_ports {pcie_rx_n[10]}] ;# MGTYTXP1_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AK5 } [get_ports {pcie_tx_p[10]}] ;# MGTYTXN1_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AK4 } [get_ports {pcie_tx_n[10]}] ;# MGTYTXP1_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AL2 } [get_ports {pcie_rx_p[11]}] ;# MGTYTXN0_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AL1 } [get_ports {pcie_rx_n[11]}] ;# MGTYTXP0_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AM5 } [get_ports {pcie_tx_p[11]}] ;# MGTYTXN0_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AM4 } [get_ports {pcie_tx_n[11]}] ;# MGTYTXP0_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AN2 } [get_ports {pcie_rx_p[12]}] ;# MGTYTXN3_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AN1 } [get_ports {pcie_rx_n[12]}] ;# MGTYTXP3_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AP5 } [get_ports {pcie_tx_p[12]}] ;# MGTYTXN3_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AP4 } [get_ports {pcie_tx_n[12]}] ;# MGTYTXP3_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AR2 } [get_ports {pcie_rx_p[13]}] ;# MGTYTXN2_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AR1 } [get_ports {pcie_rx_n[13]}] ;# MGTYTXP2_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AT5 } [get_ports {pcie_tx_p[13]}] ;# MGTYTXN2_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AT4 } [get_ports {pcie_tx_n[13]}] ;# MGTYTXP2_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AU2 } [get_ports {pcie_rx_p[14]}] ;# MGTYTXN1_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AU1 } [get_ports {pcie_rx_n[14]}] ;# MGTYTXP1_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AU7 } [get_ports {pcie_tx_p[14]}] ;# MGTYTXN1_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AU6 } [get_ports {pcie_tx_n[14]}] ;# MGTYTXP1_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AV4 } [get_ports {pcie_rx_p[15]}] ;# MGTYTXN0_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AV3 } [get_ports {pcie_rx_n[15]}] ;# MGTYTXP0_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AW7 } [get_ports {pcie_tx_p[15]}] ;# MGTYTXN0_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AW6 } [get_ports {pcie_tx_n[15]}] ;# MGTYTXP0_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
set_property -dict {LOC AA7 } [get_ports pcie_refclk_1_p] ;# MGTREFCLK0P_226
#set_property -dict {LOC AA6 } [get_ports pcie_refclk_1_n] ;# MGTREFCLK0N_226
#set_property -dict {LOC AJ7 } [get_ports pcie_refclk_2_p] ;# MGTREFCLK0P_224
#set_property -dict {LOC AJ6 } [get_ports pcie_refclk_2_n] ;# MGTREFCLK0N_224
set_property -dict {LOC AJ31 IOSTANDARD LVCMOS18 PULLUP true} [get_ports perst_0]
#set_property -dict {LOC AH29 IOSTANDARD LVCMOS18 PULLUP true} [get_ports perst_1]
# 100 MHz MGT reference clock
create_clock -period 10 -name pcie_mgt_refclk_1 [get_ports pcie_refclk_1_p]
#create_clock -period 10 -name pcie_mgt_refclk_2 [get_ports pcie_refclk_2_p]
# QSPI flash
#set_property -dict {LOC AB10 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {qspi_clk}]
#set_property -dict {LOC AB8 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {qspi0_dq[0]}]
#set_property -dict {LOC AD8 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {qspi0_dq[1]}]
#set_property -dict {LOC Y8 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {qspi0_dq[2]}]
#set_property -dict {LOC AC8 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {qspi0_dq[3]}]
#set_property -dict {LOC AF30 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {qspi1_dq[0]}]
#set_property -dict {LOC AG30 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {qspi1_dq[1]}]
#set_property -dict {LOC AF28 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {qspi1_dq[2]}]
#set_property -dict {LOC AG28 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {qspi1_dq[3]}]

View File

@ -0,0 +1,86 @@
# FPGA settings
FPGA_PART = xcvu3p-ffvc1517-2-i
FPGA_TOP = fpga
FPGA_ARCH = virtexuplus
# 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/pcie4_uscale_plus_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
%_primary.mcs %_secondary.mcs %_primary.prm %_secondary.prm: %.bit
echo "write_cfgmem -force -format mcs -size 64 -interface SPIx8 -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 _primary.mcs _secondary.mcs _primary.prm _secondary.prm; \
do cp $*$$x rev/$*_rev$$COUNT$$x; \
echo "Output: rev/$*_rev$$COUNT$$x"; done;
flash: $(FPGA_TOP)_primary.mcs $(FPGA_TOP)_secondary.mcs $(FPGA_TOP)_primary.prm $(FPGA_TOP)_secondary.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 {mt25qu256-spi-x1_x2_x4_x8}] 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)_primary.mcs\" \"$(FPGA_TOP)_secondary.mcs\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP)_primary.prm\" \"$(FPGA_TOP)_secondary.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.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

File diff suppressed because it is too large Load Diff

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,407 @@
/*
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] user_led_g,
output wire user_led_r,
output wire [1:0] front_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_refclk_1_p,
input wire pcie_refclk_1_n,
input wire perst_0
);
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_GTE4 #(
.REFCLK_HROW_CK_SEL(2'b00)
)
ibufds_gte4_pcie_mgt_refclk_inst (
.I (pcie_refclk_1_p),
.IB (pcie_refclk_1_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 [9:0] cfg_mgmt_addr;
wire [7:0] cfg_mgmt_function_number;
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 [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;
pcie4_uscale_plus_0
pcie4_uscale_plus_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), // width change
.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), // width change
.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_num0(),
.pcie_rq_seq_num_vld0(),
.pcie_rq_seq_num1(),
.pcie_rq_seq_num_vld1(),
.pcie_rq_tag0(),
.pcie_rq_tag1(),
.pcie_rq_tag_av(),
.pcie_rq_tag_vld0(),
.pcie_rq_tag_vld1(),
.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_function_number(cfg_mgmt_function_number),
.cfg_mgmt_write(cfg_mgmt_write),
.cfg_mgmt_write_data(cfg_mgmt_write_data),
.cfg_mgmt_byte_enable(cfg_mgmt_byte_enable),
.cfg_mgmt_read(cfg_mgmt_read),
.cfg_mgmt_read_data(cfg_mgmt_read_data),
.cfg_mgmt_read_write_done(cfg_mgmt_read_write_done),
.cfg_mgmt_debug_access(1'b0),
.cfg_err_cor_out(),
.cfg_err_nonfatal_out(),
.cfg_err_fatal_out(),
.cfg_local_error_valid(),
.cfg_local_error_out(),
.cfg_ltssm_state(),
.cfg_rx_pm_state(),
.cfg_tx_pm_state(),
.cfg_rcb_status(),
.cfg_obff_enable(),
.cfg_pl_status_change(),
.cfg_tph_requester_enable(),
.cfg_tph_st_mode(),
.cfg_vf_tph_requester_enable(),
.cfg_vf_tph_st_mode(),
.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_dsn(64'd0),
.cfg_bus_number(),
.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_func_num(8'd0),
.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_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_pm_aspm_l1_entry_reject(1'b0),
.cfg_pm_aspm_tx_l0s_entry_disable(1'b0),
.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(perst_0),
// .int_qpll0lock_out(),
// .int_qpll0outrefclk_out(),
// .int_qpll0outclk_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
*/
.user_led_g(user_led_g),
.user_led_r(user_led_r),
.front_led(front_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_function_number(cfg_mgmt_function_number),
.cfg_mgmt_write(cfg_mgmt_write),
.cfg_mgmt_write_data(cfg_mgmt_write_data),
.cfg_mgmt_byte_enable(cfg_mgmt_byte_enable),
.cfg_mgmt_read(cfg_mgmt_read),
.cfg_mgmt_read_data(cfg_mgmt_read_data),
.cfg_mgmt_read_write_done(cfg_mgmt_read_write_done),
.cfg_interrupt_msi_enable(cfg_interrupt_msi_enable),
.cfg_interrupt_msi_mmenable(cfg_interrupt_msi_mmenable),
.cfg_interrupt_msi_mask_update(cfg_interrupt_msi_mask_update),
.cfg_interrupt_msi_data(cfg_interrupt_msi_data),
.cfg_interrupt_msi_select(cfg_interrupt_msi_select),
.cfg_interrupt_msi_int(cfg_interrupt_msi_int),
.cfg_interrupt_msi_pending_status(cfg_interrupt_msi_pending_status),
.cfg_interrupt_msi_pending_status_data_enable(cfg_interrupt_msi_pending_status_data_enable),
.cfg_interrupt_msi_pending_status_function_num(cfg_interrupt_msi_pending_status_function_num),
.cfg_interrupt_msi_sent(cfg_interrupt_msi_sent),
.cfg_interrupt_msi_fail(cfg_interrupt_msi_fail),
.cfg_interrupt_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 @@
../lib/pcie/tb/pcie_usp.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_usp
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)[88:])
s_axis_cq_tvalid = Signal(bool(0))
m_axis_cc_tready = Signal(bool(0))
cfg_max_payload = Signal(intbv(0)[2:])
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_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
user_led_g = Signal(intbv(0)[2:])
user_led_r = Signal(bool(0))
front_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)[62:])
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)[10:])
cfg_mgmt_function_number = Signal(intbv(0)[8:])
cfg_mgmt_write = Signal(bool(0))
cfg_mgmt_write_data = Signal(intbv(0)[32:])
cfg_mgmt_byte_enable = Signal(intbv(0)[4:])
cfg_mgmt_read = Signal(bool(0))
cfg_interrupt_msi_int = Signal(intbv(0)[32:])
cfg_interrupt_msi_pending_status = Signal(intbv(0)[32:])
cfg_interrupt_msi_select = Signal(intbv(0)[2:])
cfg_interrupt_msi_pending_status_function_num = Signal(intbv(0)[2:])
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)[8:])
cfg_interrupt_msi_function_number = Signal(intbv(0)[8:])
# 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_usp.UltrascalePlusPCIe()
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(intbv(1)[2:]),
#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_num0=pcie_rq_seq_num0,
#pcie_rq_seq_num_vld0=pcie_rq_seq_num_vld0,
#pcie_rq_seq_num1=pcie_rq_seq_num1,
#pcie_rq_seq_num_vld1=pcie_rq_seq_num_vld1,
#pcie_rq_tag0=pcie_rq_tag0,
#pcie_rq_tag1=pcie_rq_tag1,
#pcie_rq_tag_av=pcie_rq_tag_av,
#pcie_rq_tag_vld0=pcie_rq_tag_vld0,
#pcie_rq_tag_vld1=pcie_rq_tag_vld1,
# Requester Completion Interface
m_axis_rc_tdata=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_function_number=cfg_mgmt_function_number,
cfg_mgmt_write=cfg_mgmt_write,
cfg_mgmt_write_data=cfg_mgmt_write_data,
cfg_mgmt_byte_enable=cfg_mgmt_byte_enable,
cfg_mgmt_read=cfg_mgmt_read,
cfg_mgmt_read_data=cfg_mgmt_read_data,
cfg_mgmt_read_write_done=cfg_mgmt_read_write_done,
#cfg_mgmt_debug_access=cfg_mgmt_debug_access,
# Configuration Status Interface
#cfg_phy_link_down=cfg_phy_link_down,
#cfg_phy_link_status=cfg_phy_link_status,
#cfg_negotiated_width=cfg_negotiated_width,
#cfg_current_speed=cfg_current_speed,
cfg_max_payload=cfg_max_payload,
cfg_max_read_req=cfg_max_read_req,
#cfg_function_status=cfg_function_status,
#cfg_vf_status=cfg_vf_status,
#cfg_function_power_state=cfg_function_power_state,
#cfg_vf_power_state=cfg_vf_power_state,
#cfg_link_power_state=cfg_link_power_state,
#cfg_err_cor_out=cfg_err_cor_out,
#cfg_err_nonfatal_out=cfg_err_nonfatal_out,
#cfg_err_fatal_out=cfg_err_fatal_out,
#cfg_local_err_out=cfg_local_err_out,
#cfg_local_err_valid=cfg_local_err_valid,
#cfg_rx_pm_state=cfg_rx_pm_state,
#cfg_tx_pm_state=cfg_tx_pm_state,
#cfg_ltssm_state=cfg_ltssm_state,
#cfg_rcb_status=cfg_rcb_status,
#cfg_obff_enable=cfg_obff_enable,
#cfg_pl_status_change=cfg_pl_status_change,
#cfg_tph_requester_enable=cfg_tph_requester_enable,
#cfg_tph_st_mode=cfg_tph_st_mode,
#cfg_vf_tph_requester_enable=cfg_vf_tph_requester_enable,
#cfg_vf_tph_st_mode=cfg_vf_tph_st_mode,
# Configuration Received Message Interface
#cfg_msg_received=cfg_msg_received,
#cfg_msg_received_data=cfg_msg_received_data,
#cfg_msg_received_type=cfg_msg_received_type,
# Configuration Transmit Message Interface
#cfg_msg_transmit=cfg_msg_transmit,
#cfg_msg_transmit_type=cfg_msg_transmit_type,
#cfg_msg_transmit_data=cfg_msg_transmit_data,
#cfg_msg_transmit_done=cfg_msg_transmit_done,
# Configuration Flow Control Interface
#cfg_fc_ph=cfg_fc_ph,
#cfg_fc_pd=cfg_fc_pd,
#cfg_fc_nph=cfg_fc_nph,
#cfg_fc_npd=cfg_fc_npd,
#cfg_fc_cplh=cfg_fc_cplh,
#cfg_fc_cpld=cfg_fc_cpld,
#cfg_fc_sel=cfg_fc_sel,
# Configuration Control Interface
#cfg_hot_reset_in=cfg_hot_reset_in,
#cfg_hot_reset_out=cfg_hot_reset_out,
#cfg_config_space_enable=cfg_config_space_enable,
#cfg_dsn=cfg_dsn,
#cfg_ds_port_number=cfg_ds_port_number,
#cfg_ds_bus_number=cfg_ds_bus_number,
#cfg_ds_device_number=cfg_ds_device_number,
#cfg_ds_function_number=cfg_ds_function_number,
#cfg_power_state_change_ack=cfg_power_state_change_ack,
#cfg_power_state_change_interrupt=cfg_power_state_change_interrupt,
cfg_err_cor_in=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_mmenable=cfg_interrupt_msi_mmenable,
cfg_interrupt_msi_mask_update=cfg_interrupt_msi_mask_update,
cfg_interrupt_msi_data=cfg_interrupt_msi_data,
cfg_interrupt_msi_select=cfg_interrupt_msi_select,
cfg_interrupt_msi_int=cfg_interrupt_msi_int,
cfg_interrupt_msi_pending_status=cfg_interrupt_msi_pending_status,
cfg_interrupt_msi_pending_status_data_enable=cfg_interrupt_msi_pending_status_data_enable,
cfg_interrupt_msi_pending_status_function_num=cfg_interrupt_msi_pending_status_function_num,
cfg_interrupt_msi_sent=cfg_interrupt_msi_sent,
cfg_interrupt_msi_fail=cfg_interrupt_msi_fail,
#cfg_interrupt_msix_enable=cfg_interrupt_msix_enable,
#cfg_interrupt_msix_mask=cfg_interrupt_msix_mask,
#cfg_interrupt_msix_vf_enable=cfg_interrupt_msix_vf_enable,
#cfg_interrupt_msix_vf_mask=cfg_interrupt_msix_vf_mask,
#cfg_interrupt_msix_address=cfg_interrupt_msix_address,
#cfg_interrupt_msix_data=cfg_interrupt_msix_data,
#cfg_interrupt_msix_int=cfg_interrupt_msix_int,
#cfg_interrupt_msix_vec_pending=cfg_interrupt_msix_vec_pending,
#cfg_interrupt_msix_vec_pending_status=cfg_interrupt_msix_vec_pending_status,
cfg_interrupt_msi_attr=cfg_interrupt_msi_attr,
cfg_interrupt_msi_tph_present=cfg_interrupt_msi_tph_present,
cfg_interrupt_msi_tph_type=cfg_interrupt_msi_tph_type,
cfg_interrupt_msi_tph_st_tag=cfg_interrupt_msi_tph_st_tag,
cfg_interrupt_msi_function_number=cfg_interrupt_msi_function_number,
# Configuration Extend Interface
#cfg_ext_read_received=cfg_ext_read_received,
#cfg_ext_write_received=cfg_ext_write_received,
#cfg_ext_register_number=cfg_ext_register_number,
#cfg_ext_function_number=cfg_ext_function_number,
#cfg_ext_write_data=cfg_ext_write_data,
#cfg_ext_write_byte_enable=cfg_ext_write_byte_enable,
#cfg_ext_read_data=cfg_ext_read_data,
#cfg_ext_read_data_valid=cfg_ext_read_data_valid,
# Clock and Reset Interface
user_clk=user_clk,
user_reset=user_reset,
#user_lnk_up=user_lnk_up,
sys_clk=sys_clk,
sys_clk_gt=sys_clk,
sys_reset=sys_reset,
#phy_rdy_out=phy_rdy_out
)
# 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,
user_led_g=user_led_g,
user_led_r=user_led_r,
front_led=front_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_function_number=cfg_mgmt_function_number,
cfg_mgmt_write=cfg_mgmt_write,
cfg_mgmt_write_data=cfg_mgmt_write_data,
cfg_mgmt_byte_enable=cfg_mgmt_byte_enable,
cfg_mgmt_read=cfg_mgmt_read,
cfg_mgmt_read_data=cfg_mgmt_read_data,
cfg_mgmt_read_write_done=cfg_mgmt_read_write_done,
cfg_interrupt_msi_enable=cfg_interrupt_msi_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 [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] user_led_g;
wire user_led_r;
wire [1:0] front_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 [9:0] cfg_mgmt_addr;
wire [7:0] cfg_mgmt_function_number;
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_mmenable,
cfg_interrupt_msi_mask_update,
cfg_interrupt_msi_data,
cfg_interrupt_msi_sent,
cfg_interrupt_msi_fail
);
$to_myhdl(
user_led_g,
user_led_r,
front_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_function_number,
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),
.user_led_g(user_led_g),
.user_led_r(user_led_r),
.front_led(front_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_function_number(cfg_mgmt_function_number),
.cfg_mgmt_write(cfg_mgmt_write),
.cfg_mgmt_write_data(cfg_mgmt_write_data),
.cfg_mgmt_byte_enable(cfg_mgmt_byte_enable),
.cfg_mgmt_read(cfg_mgmt_read),
.cfg_mgmt_read_data(cfg_mgmt_read_data),
.cfg_mgmt_read_write_done(cfg_mgmt_read_write_done),
.cfg_interrupt_msi_enable(cfg_interrupt_msi_enable),
.cfg_interrupt_msi_mmenable(cfg_interrupt_msi_mmenable),
.cfg_interrupt_msi_mask_update(cfg_interrupt_msi_mask_update),
.cfg_interrupt_msi_data(cfg_interrupt_msi_data),
.cfg_interrupt_msi_select(cfg_interrupt_msi_select),
.cfg_interrupt_msi_int(cfg_interrupt_msi_int),
.cfg_interrupt_msi_pending_status(cfg_interrupt_msi_pending_status),
.cfg_interrupt_msi_pending_status_data_enable(cfg_interrupt_msi_pending_status_data_enable),
.cfg_interrupt_msi_pending_status_function_num(cfg_interrupt_msi_pending_status_function_num),
.cfg_interrupt_msi_sent(cfg_interrupt_msi_sent),
.cfg_interrupt_msi_fail(cfg_interrupt_msi_fail),
.cfg_interrupt_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

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 PCIe VCU118 Example Design
## Introduction
This example design targets the Xilinx VCU118 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: xcvu9p-flga2104-2L-e
## 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 VCU118 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,226 @@
# XDC constraints for the Xilinx VCU118 board
# part: xcvu9p-flga2104-2L-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.EXTMASTERCCLK_EN {DIV-1} [current_design]
set_property BITSTREAM.CONFIG.SPI_32BIT_ADDR YES [current_design]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 8 [current_design]
set_property BITSTREAM.CONFIG.SPI_FALL_EDGE YES [current_design]
# System clocks
# 300 MHz
#set_property -dict {LOC G31 IOSTANDARD DIFF_SSTL12} [get_ports clk_300mhz_p]
#set_property -dict {LOC F31 IOSTANDARD DIFF_SSTL12} [get_ports clk_300mhz_n]
#create_clock -period 3.333 -name clk_300mhz [get_ports clk_300mhz_p]
# 250 MHz
#set_property -dict {LOC E12 IOSTANDARD DIFF_SSTL12} [get_ports clk_250mhz_1_p]
#set_property -dict {LOC D12 IOSTANDARD DIFF_SSTL12} [get_ports clk_250mhz_1_n]
#create_clock -period 4 -name clk_250mhz_1 [get_ports clk_250mhz_1_p]
#set_property -dict {LOC AW26 IOSTANDARD DIFF_SSTL12} [get_ports clk_250mhz_2_p]
#set_property -dict {LOC AW27 IOSTANDARD DIFF_SSTL12} [get_ports clk_250mhz_2_n]
#create_clock -period 4 -name clk_250mhz_2 [get_ports clk_250mhz_2_p]
# 125 MHz
#set_property -dict {LOC AY24 IOSTANDARD LVDS} [get_ports clk_125mhz_p]
#set_property -dict {LOC AY23 IOSTANDARD LVDS} [get_ports clk_125mhz_n]
#create_clock -period 8.000 -name clk_125mhz [get_ports clk_125mhz_p]
# 90 MHz
#set_property -dict {LOC AL20 IOSTANDARD LVCMOS18} [get_ports clk_90mhz]
#create_clock -period 11.111 -name clk_90mhz [get_ports clk_90mhz]
# LEDs
set_property -dict {LOC AT32 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {led[0]}]
set_property -dict {LOC AV34 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {led[1]}]
set_property -dict {LOC AY30 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {led[2]}]
set_property -dict {LOC BB32 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {led[3]}]
set_property -dict {LOC BF32 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {led[4]}]
set_property -dict {LOC AU37 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {led[5]}]
set_property -dict {LOC AV36 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {led[6]}]
set_property -dict {LOC BA37 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {led[7]}]
# Reset button
#set_property -dict {LOC L19 IOSTANDARD LVCMOS12} [get_ports reset]
# Push buttons
set_property -dict {LOC BB24 IOSTANDARD LVCMOS18} [get_ports btnu]
set_property -dict {LOC BF22 IOSTANDARD LVCMOS18} [get_ports btnl]
set_property -dict {LOC BE22 IOSTANDARD LVCMOS18} [get_ports btnd]
set_property -dict {LOC BE23 IOSTANDARD LVCMOS18} [get_ports btnr]
set_property -dict {LOC BD23 IOSTANDARD LVCMOS18} [get_ports btnc]
# DIP switches
set_property -dict {LOC B17 IOSTANDARD LVCMOS12} [get_ports {sw[0]}]
set_property -dict {LOC G16 IOSTANDARD LVCMOS12} [get_ports {sw[1]}]
set_property -dict {LOC J16 IOSTANDARD LVCMOS12} [get_ports {sw[2]}]
set_property -dict {LOC D21 IOSTANDARD LVCMOS12} [get_ports {sw[3]}]
# UART
#set_property -dict {LOC BB21 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports uart_txd]
#set_property -dict {LOC AW25 IOSTANDARD LVCMOS18} [get_ports uart_rxd]
#set_property -dict {LOC BB22 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports uart_rts]
#set_property -dict {LOC AY25 IOSTANDARD LVCMOS18} [get_ports uart_cts]
# Gigabit Ethernet SGMII PHY
#set_property -dict {LOC AU24 IOSTANDARD LVDS} [get_ports phy_sgmii_rx_p]
#set_property -dict {LOC AV24 IOSTANDARD LVDS} [get_ports phy_sgmii_rx_n]
#set_property -dict {LOC AU21 IOSTANDARD LVDS} [get_ports phy_sgmii_tx_p]
#set_property -dict {LOC AV21 IOSTANDARD LVDS} [get_ports phy_sgmii_tx_n]
#set_property -dict {LOC AT22 IOSTANDARD LVDS} [get_ports phy_sgmii_clk_p]
#set_property -dict {LOC AU22 IOSTANDARD LVDS} [get_ports phy_sgmii_clk_n]
#set_property -dict {LOC BA21 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports phy_reset_n]
#set_property -dict {LOC AR24 IOSTANDARD LVCMOS18} [get_ports phy_int_n]
#set_property -dict {LOC AR23 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports phy_mdio]
#set_property -dict {LOC AV23 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports phy_mdc]
# 625 MHz ref clock from SGMII PHY
#create_clock -period 1.600 -name phy_sgmii_clk [get_ports phy_sgmii_clk_p]
# QSFP28 Interfaces
#set_property -dict {LOC V7 } [get_ports qsfp1_tx1_p] ;# MGTYTXN0_231 GTYE3_CHANNEL_X1Y48 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC V6 } [get_ports qsfp1_tx1_n] ;# MGTYTXP0_231 GTYE3_CHANNEL_X1Y48 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC Y2 } [get_ports qsfp1_rx1_p] ;# MGTYTXN1_231 GTYE3_CHANNEL_X1Y48 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC Y1 } [get_ports qsfp1_rx1_n] ;# MGTYTXP1_231 GTYE3_CHANNEL_X1Y48 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC T7 } [get_ports qsfp1_tx2_p] ;# MGTYTXN2_231 GTYE3_CHANNEL_X1Y49 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC T6 } [get_ports qsfp1_tx2_n] ;# MGTYTXP2_231 GTYE3_CHANNEL_X1Y49 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC W4 } [get_ports qsfp1_rx2_p] ;# MGTYTXN3_231 GTYE3_CHANNEL_X1Y49 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC W3 } [get_ports qsfp1_rx2_n] ;# MGTYTXP3_231 GTYE3_CHANNEL_X1Y49 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC P7 } [get_ports qsfp1_tx3_p] ;# MGTYTXN0_231 GTYE3_CHANNEL_X1Y50 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC P6 } [get_ports qsfp1_tx3_n] ;# MGTYTXP0_231 GTYE3_CHANNEL_X1Y50 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC V2 } [get_ports qsfp1_rx3_p] ;# MGTYTXN1_231 GTYE3_CHANNEL_X1Y50 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC V1 } [get_ports qsfp1_rx3_n] ;# MGTYTXP1_231 GTYE3_CHANNEL_X1Y50 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC M7 } [get_ports qsfp1_tx4_p] ;# MGTYTXN2_231 GTYE3_CHANNEL_X1Y51 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC M6 } [get_ports qsfp1_tx4_n] ;# MGTYTXP2_231 GTYE3_CHANNEL_X1Y51 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC U4 } [get_ports qsfp1_rx4_p] ;# MGTYTXN3_231 GTYE3_CHANNEL_X1Y51 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC U3 } [get_ports qsfp1_rx4_n] ;# MGTYTXP3_231 GTYE3_CHANNEL_X1Y51 / GTYE3_COMMON_X1Y12
#set_property -dict {LOC W9 } [get_ports qsfp1_mgt_refclk_0_p] ;# MGTREFCLK0P_231 from U38.4
#set_property -dict {LOC W8 } [get_ports qsfp1_mgt_refclk_0_n] ;# MGTREFCLK0N_231 from U38.5
#set_property -dict {LOC U9 } [get_ports qsfp1_mgt_refclk_1_p] ;# MGTREFCLK1P_231 from U57.28
#set_property -dict {LOC U8 } [get_ports qsfp1_mgt_refclk_1_n] ;# MGTREFCLK1N_231 from U57.29
#set_property -dict {LOC AM23 IOSTANDARD LVDS} [get_ports qsfp1_recclk_p] ;# to U57.16
#set_property -dict {LOC AM22 IOSTANDARD LVDS} [get_ports qsfp1_recclk_n] ;# to U57.17
#set_property -dict {LOC AM21 IOSTANDARD LVCMOS18} [get_ports qsfp1_modsell]
#set_property -dict {LOC BA22 IOSTANDARD LVCMOS18} [get_ports qsfp1_resetl]
#set_property -dict {LOC AL21 IOSTANDARD LVCMOS18} [get_ports qsfp1_modprsl]
#set_property -dict {LOC AP21 IOSTANDARD LVCMOS18} [get_ports qsfp1_intl]
#set_property -dict {LOC AN21 IOSTANDARD LVCMOS18} [get_ports qsfp1_lpmode]
# 156.25 MHz MGT reference clock
#create_clock -period 6.400 -name qsfp1_mgt_refclk_0 [get_ports qsfp1_mgt_refclk_0_p]
#set_property -dict {LOC L5 } [get_ports qsfp2_tx1_p] ;# MGTYTXN0_232 GTYE3_CHANNEL_X1Y52 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC L4 } [get_ports qsfp2_tx1_n] ;# MGTYTXP0_232 GTYE3_CHANNEL_X1Y52 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC T2 } [get_ports qsfp2_rx1_p] ;# MGTYTXN1_232 GTYE3_CHANNEL_X1Y52 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC T1 } [get_ports qsfp2_rx1_n] ;# MGTYTXP1_232 GTYE3_CHANNEL_X1Y52 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC K7 } [get_ports qsfp2_tx2_p] ;# MGTYTXN2_232 GTYE3_CHANNEL_X1Y53 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC K6 } [get_ports qsfp2_tx2_n] ;# MGTYTXP2_232 GTYE3_CHANNEL_X1Y53 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC R4 } [get_ports qsfp2_rx2_p] ;# MGTYTXN3_232 GTYE3_CHANNEL_X1Y53 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC R3 } [get_ports qsfp2_rx2_n] ;# MGTYTXP3_232 GTYE3_CHANNEL_X1Y53 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC J5 } [get_ports qsfp2_tx3_p] ;# MGTYTXN0_232 GTYE3_CHANNEL_X1Y54 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC J4 } [get_ports qsfp2_tx3_n] ;# MGTYTXP0_232 GTYE3_CHANNEL_X1Y54 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC P2 } [get_ports qsfp2_rx3_p] ;# MGTYTXN1_232 GTYE3_CHANNEL_X1Y54 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC P1 } [get_ports qsfp2_rx3_n] ;# MGTYTXP1_232 GTYE3_CHANNEL_X1Y54 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC H7 } [get_ports qsfp2_tx4_p] ;# MGTYTXN2_232 GTYE3_CHANNEL_X1Y55 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC H6 } [get_ports qsfp2_tx4_n] ;# MGTYTXP2_232 GTYE3_CHANNEL_X1Y55 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC M2 } [get_ports qsfp2_rx4_p] ;# MGTYTXN3_232 GTYE3_CHANNEL_X1Y55 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC M1 } [get_ports qsfp2_rx4_n] ;# MGTYTXP3_232 GTYE3_CHANNEL_X1Y55 / GTYE3_COMMON_X1Y13
#set_property -dict {LOC R9 } [get_ports qsfp2_mgt_refclk_0_p] ;# MGTREFCLK0P_232 from U104.13
#set_property -dict {LOC R8 } [get_ports qsfp2_mgt_refclk_0_n] ;# MGTREFCLK0N_232 from U104.14
#set_property -dict {LOC N9 } [get_ports qsfp2_mgt_refclk_1_p] ;# MGTREFCLK1P_232 from U57.35
#set_property -dict {LOC N8 } [get_ports qsfp2_mgt_refclk_1_n] ;# MGTREFCLK1N_232 from U57.34
#set_property -dict {LOC AP23 IOSTANDARD LVDS} [get_ports qsfp2_recclk_p] ;# to U57.12
#set_property -dict {LOC AP22 IOSTANDARD LVDS} [get_ports qsfp2_recclk_n] ;# to U57.13
#set_property -dict {LOC AN23 IOSTANDARD LVCMOS18} [get_ports qsfp2_modsell]
#set_property -dict {LOC AY22 IOSTANDARD LVCMOS18} [get_ports qsfp2_resetl]
#set_property -dict {LOC AN24 IOSTANDARD LVCMOS18} [get_ports qsfp2_modprsl]
#set_property -dict {LOC AT21 IOSTANDARD LVCMOS18} [get_ports qsfp2_intl]
#set_property -dict {LOC AT24 IOSTANDARD LVCMOS18} [get_ports qsfp2_lpmode]
# 156.25 MHz MGT reference clock
#create_clock -period 6.400 -name qsfp2_mgt_refclk_0 [get_ports qsfp2_mgt_refclk_0_p]
# I2C interface
#set_property -dict {LOC AM24 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports i2c_scl]
#set_property -dict {LOC AL24 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports i2c_sda]
# PCIe Interface
set_property -dict {LOC AA4 } [get_ports {pcie_rx_p[0]}] ;# MGTYRXP3_227 GTYE3_CHANNEL_X0Y7 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC AA3 } [get_ports {pcie_rx_n[0]}] ;# MGTYTXP3_227 GTYE3_CHANNEL_X0Y7 / GTYE3_COMMON_X0Y1
set_property -dict {LOC Y7 } [get_ports {pcie_tx_p[0]}] ;# MGTYTXN3_227 GTYE3_CHANNEL_X0Y7 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC Y6 } [get_ports {pcie_tx_n[0]}] ;# MGTYTXP3_227 GTYE3_CHANNEL_X0Y7 / GTYE3_COMMON_X0Y1
set_property -dict {LOC AB2 } [get_ports {pcie_rx_p[1]}] ;# MGTYTXN2_227 GTYE3_CHANNEL_X0Y6 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC AB1 } [get_ports {pcie_rx_n[1]}] ;# MGTYTXP2_227 GTYE3_CHANNEL_X0Y6 / GTYE3_COMMON_X0Y1
set_property -dict {LOC AB7 } [get_ports {pcie_tx_p[1]}] ;# MGTYTXN2_227 GTYE3_CHANNEL_X0Y6 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC AB6 } [get_ports {pcie_tx_n[1]}] ;# MGTYTXP2_227 GTYE3_CHANNEL_X0Y6 / GTYE3_COMMON_X0Y1
set_property -dict {LOC AC4 } [get_ports {pcie_rx_p[2]}] ;# MGTYTXN1_227 GTYE3_CHANNEL_X0Y5 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC AC3 } [get_ports {pcie_rx_n[2]}] ;# MGTYTXP1_227 GTYE3_CHANNEL_X0Y5 / GTYE3_COMMON_X0Y1
set_property -dict {LOC AD7 } [get_ports {pcie_tx_p[2]}] ;# MGTYTXN1_227 GTYE3_CHANNEL_X0Y5 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC AD6 } [get_ports {pcie_tx_n[2]}] ;# MGTYTXP1_227 GTYE3_CHANNEL_X0Y5 / GTYE3_COMMON_X0Y1
set_property -dict {LOC AD2 } [get_ports {pcie_rx_p[3]}] ;# MGTYTXN0_227 GTYE3_CHANNEL_X0Y4 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC AD1 } [get_ports {pcie_rx_n[3]}] ;# MGTYTXP0_227 GTYE3_CHANNEL_X0Y4 / GTYE3_COMMON_X0Y1
set_property -dict {LOC AF7 } [get_ports {pcie_tx_p[3]}] ;# MGTYTXN0_227 GTYE3_CHANNEL_X0Y4 / GTYE3_COMMON_X0Y1
#set_property -dict {LOC AF6 } [get_ports {pcie_tx_n[3]}] ;# MGTYTXP0_227 GTYE3_CHANNEL_X0Y4 / GTYE3_COMMON_X0Y1
set_property -dict {LOC AE4 } [get_ports {pcie_rx_p[4]}] ;# MGTYTXN3_226 GTYE3_CHANNEL_X0Y3 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AE3 } [get_ports {pcie_rx_n[4]}] ;# MGTYTXP3_226 GTYE3_CHANNEL_X0Y3 / GTYE3_COMMON_X0Y0
set_property -dict {LOC AH7 } [get_ports {pcie_tx_p[4]}] ;# MGTYTXN3_226 GTYE3_CHANNEL_X0Y3 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AH6 } [get_ports {pcie_tx_n[4]}] ;# MGTYTXP3_226 GTYE3_CHANNEL_X0Y3 / GTYE3_COMMON_X0Y0
set_property -dict {LOC AF2 } [get_ports {pcie_rx_p[5]}] ;# MGTYTXN2_226 GTYE3_CHANNEL_X0Y2 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AF1 } [get_ports {pcie_rx_n[5]}] ;# MGTYTXP2_226 GTYE3_CHANNEL_X0Y2 / GTYE3_COMMON_X0Y0
set_property -dict {LOC AK7 } [get_ports {pcie_tx_p[5]}] ;# MGTYTXN2_226 GTYE3_CHANNEL_X0Y2 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AK6 } [get_ports {pcie_tx_n[5]}] ;# MGTYTXP2_226 GTYE3_CHANNEL_X0Y2 / GTYE3_COMMON_X0Y0
set_property -dict {LOC AG4 } [get_ports {pcie_rx_p[6]}] ;# MGTYTXN1_226 GTYE3_CHANNEL_X0Y1 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AG3 } [get_ports {pcie_rx_n[6]}] ;# MGTYTXP1_226 GTYE3_CHANNEL_X0Y1 / GTYE3_COMMON_X0Y0
set_property -dict {LOC AM7 } [get_ports {pcie_tx_p[6]}] ;# MGTYTXN1_226 GTYE3_CHANNEL_X0Y1 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AM6 } [get_ports {pcie_tx_n[6]}] ;# MGTYTXP1_226 GTYE3_CHANNEL_X0Y1 / GTYE3_COMMON_X0Y0
set_property -dict {LOC AH2 } [get_ports {pcie_rx_p[7]}] ;# MGTYTXN0_226 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AH1 } [get_ports {pcie_rx_n[7]}] ;# MGTYTXP0_226 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
set_property -dict {LOC AN5 } [get_ports {pcie_tx_p[7]}] ;# MGTYTXN0_226 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AN4 } [get_ports {pcie_tx_n[7]}] ;# MGTYTXP0_226 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AJ4 } [get_ports {pcie_rx_p[8]}] ;# MGTYTXN3_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AJ3 } [get_ports {pcie_rx_n[8]}] ;# MGTYTXP3_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AP7 } [get_ports {pcie_tx_p[8]}] ;# MGTYTXN3_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AP6 } [get_ports {pcie_tx_n[8]}] ;# MGTYTXP3_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AK2 } [get_ports {pcie_rx_p[9]}] ;# MGTYTXN2_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AK1 } [get_ports {pcie_rx_n[9]}] ;# MGTYTXP2_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AR5 } [get_ports {pcie_tx_p[9]}] ;# MGTYTXN2_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AR4 } [get_ports {pcie_tx_n[9]}] ;# MGTYTXP2_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AM2 } [get_ports {pcie_rx_p[10]}] ;# MGTYTXN1_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AM1 } [get_ports {pcie_rx_n[10]}] ;# MGTYTXP1_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AT7 } [get_ports {pcie_tx_p[10]}] ;# MGTYTXN1_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AT6 } [get_ports {pcie_tx_n[10]}] ;# MGTYTXP1_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AP2 } [get_ports {pcie_rx_p[11]}] ;# MGTYTXN0_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AP1 } [get_ports {pcie_rx_n[11]}] ;# MGTYTXP0_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AU5 } [get_ports {pcie_tx_p[11]}] ;# MGTYTXN0_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AU4 } [get_ports {pcie_tx_n[11]}] ;# MGTYTXP0_225 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AT2 } [get_ports {pcie_rx_p[12]}] ;# MGTYTXN3_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AT1 } [get_ports {pcie_rx_n[12]}] ;# MGTYTXP3_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AW5 } [get_ports {pcie_tx_p[12]}] ;# MGTYTXN3_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AW4 } [get_ports {pcie_tx_n[12]}] ;# MGTYTXP3_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AV2 } [get_ports {pcie_rx_p[13]}] ;# MGTYTXN2_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AV1 } [get_ports {pcie_rx_n[13]}] ;# MGTYTXP2_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC BA5 } [get_ports {pcie_tx_p[13]}] ;# MGTYTXN2_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC BA4 } [get_ports {pcie_tx_n[13]}] ;# MGTYTXP2_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AY2 } [get_ports {pcie_rx_p[14]}] ;# MGTYTXN1_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC AY1 } [get_ports {pcie_rx_n[14]}] ;# MGTYTXP1_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC BC5 } [get_ports {pcie_tx_p[14]}] ;# MGTYTXN1_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC BC4 } [get_ports {pcie_tx_n[14]}] ;# MGTYTXP1_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC BB2 } [get_ports {pcie_rx_p[15]}] ;# MGTYTXN0_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC BB1 } [get_ports {pcie_rx_n[15]}] ;# MGTYTXP0_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC BE5 } [get_ports {pcie_tx_p[15]}] ;# MGTYTXN0_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
#set_property -dict {LOC BE4 } [get_ports {pcie_tx_n[15]}] ;# MGTYTXP0_224 GTYE3_CHANNEL_X0Y0 / GTYE3_COMMON_X0Y0
set_property -dict {LOC AC9 } [get_ports pcie_refclk_1_p] ;# MGTREFCLK0P_227
#set_property -dict {LOC AC8 } [get_ports pcie_refclk_1_n] ;# MGTREFCLK0N_227
#set_property -dict {LOC AL9 } [get_ports pcie_refclk_2_p] ;# MGTREFCLK0P_225
#set_property -dict {LOC AL8 } [get_ports pcie_refclk_2_n] ;# MGTREFCLK0N_225
set_property -dict {LOC AM17 IOSTANDARD LVCMOS18 PULLUP true} [get_ports pcie_reset_n]
# 100 MHz MGT reference clock
create_clock -period 10 -name pcie_mgt_refclk_1 [get_ports pcie_refclk_1_p]
#create_clock -period 10 -name pcie_mgt_refclk_2 [get_ports pcie_refclk_2_p]

View File

@ -0,0 +1,86 @@
# FPGA settings
FPGA_PART = xcvu9p-flga2104-2L-e
FPGA_TOP = fpga
FPGA_ARCH = virtexuplus
# 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/pcie4_uscale_plus_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
%_primary.mcs %_secondary.mcs %_primary.prm %_secondary.prm: %.bit
echo "write_cfgmem -force -format mcs -size 256 -interface SPIx8 -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 _primary.mcs _secondary.mcs _primary.prm _secondary.prm; \
do cp $*$$x rev/$*_rev$$COUNT$$x; \
echo "Output: rev/$*_rev$$COUNT$$x"; done;
flash: $(FPGA_TOP)_primary.mcs $(FPGA_TOP)_secondary.mcs $(FPGA_TOP)_primary.prm $(FPGA_TOP)_secondary.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 {mt25qu01g-spi-x1_x2_x4_x8}] 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)_primary.mcs\" \"$(FPGA_TOP)_secondary.mcs\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP)_primary.prm\" \"$(FPGA_TOP)_secondary.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.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

File diff suppressed because it is too large Load Diff

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,446 @@
/*
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
*/
input wire btnu,
input wire btnl,
input wire btnd,
input wire btnr,
input wire btnc,
input wire [3:0] sw,
output wire [7:0] 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_refclk_1_p,
input wire pcie_refclk_1_n,
input wire pcie_reset_n
);
parameter AXIS_PCIE_DATA_WIDTH = 256;
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
// Clock and reset
wire pcie_user_clk;
wire pcie_user_reset;
// GPIO
wire btnu_int;
wire btnl_int;
wire btnd_int;
wire btnr_int;
wire btnc_int;
wire [3:0] sw_int;
debounce_switch #(
.WIDTH(9),
.N(4),
.RATE(250000)
)
debounce_switch_inst (
.clk(pcie_user_clk),
.rst(pcie_user_reset),
.in({btnu,
btnl,
btnd,
btnr,
btnc,
sw}),
.out({btnu_int,
btnl_int,
btnd_int,
btnr_int,
btnc_int,
sw_int})
);
// PCIe
wire pcie_sys_clk;
wire pcie_sys_clk_gt;
IBUFDS_GTE4 #(
.REFCLK_HROW_CK_SEL(2'b00)
)
ibufds_gte4_pcie_mgt_refclk_inst (
.I (pcie_refclk_1_p),
.IB (pcie_refclk_1_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 [9:0] cfg_mgmt_addr;
wire [7:0] cfg_mgmt_function_number;
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 [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;
pcie4_uscale_plus_0
pcie4_uscale_plus_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), // width change
.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), // width change
.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_num0(),
.pcie_rq_seq_num_vld0(),
.pcie_rq_seq_num1(),
.pcie_rq_seq_num_vld1(),
.pcie_rq_tag0(),
.pcie_rq_tag1(),
.pcie_rq_tag_av(),
.pcie_rq_tag_vld0(),
.pcie_rq_tag_vld1(),
.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_function_number(cfg_mgmt_function_number),
.cfg_mgmt_write(cfg_mgmt_write),
.cfg_mgmt_write_data(cfg_mgmt_write_data),
.cfg_mgmt_byte_enable(cfg_mgmt_byte_enable),
.cfg_mgmt_read(cfg_mgmt_read),
.cfg_mgmt_read_data(cfg_mgmt_read_data),
.cfg_mgmt_read_write_done(cfg_mgmt_read_write_done),
.cfg_mgmt_debug_access(1'b0),
.cfg_err_cor_out(),
.cfg_err_nonfatal_out(),
.cfg_err_fatal_out(),
.cfg_local_error_valid(),
.cfg_local_error_out(),
.cfg_ltssm_state(),
.cfg_rx_pm_state(),
.cfg_tx_pm_state(),
.cfg_rcb_status(),
.cfg_obff_enable(),
.cfg_pl_status_change(),
.cfg_tph_requester_enable(),
.cfg_tph_st_mode(),
.cfg_vf_tph_requester_enable(),
.cfg_vf_tph_st_mode(),
.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_dsn(64'd0),
.cfg_bus_number(),
.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_func_num(8'd0),
.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_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_pm_aspm_l1_entry_reject(1'b0),
.cfg_pm_aspm_tx_l0s_entry_disable(1'b0),
.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),
// .int_qpll0lock_out(),
// .int_qpll0outrefclk_out(),
// .int_qpll0outclk_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
*/
.btnu(btnu_int),
.btnl(btnl_int),
.btnd(btnd_int),
.btnr(btnr_int),
.btnc(btnc_int),
.sw(sw_int),
.led(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_function_number(cfg_mgmt_function_number),
.cfg_mgmt_write(cfg_mgmt_write),
.cfg_mgmt_write_data(cfg_mgmt_write_data),
.cfg_mgmt_byte_enable(cfg_mgmt_byte_enable),
.cfg_mgmt_read(cfg_mgmt_read),
.cfg_mgmt_read_data(cfg_mgmt_read_data),
.cfg_mgmt_read_write_done(cfg_mgmt_read_write_done),
.cfg_interrupt_msi_enable(cfg_interrupt_msi_enable),
.cfg_interrupt_msi_mmenable(cfg_interrupt_msi_mmenable),
.cfg_interrupt_msi_mask_update(cfg_interrupt_msi_mask_update),
.cfg_interrupt_msi_data(cfg_interrupt_msi_data),
.cfg_interrupt_msi_select(cfg_interrupt_msi_select),
.cfg_interrupt_msi_int(cfg_interrupt_msi_int),
.cfg_interrupt_msi_pending_status(cfg_interrupt_msi_pending_status),
.cfg_interrupt_msi_pending_status_data_enable(cfg_interrupt_msi_pending_status_data_enable),
.cfg_interrupt_msi_pending_status_function_num(cfg_interrupt_msi_pending_status_function_num),
.cfg_interrupt_msi_sent(cfg_interrupt_msi_sent),
.cfg_interrupt_msi_fail(cfg_interrupt_msi_fail),
.cfg_interrupt_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 @@
../lib/pcie/tb/pcie_usp.py

View File

@ -0,0 +1,515 @@
#!/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_usp
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:])
btnu = Signal(bool(0))
btnl = Signal(bool(0))
btnd = Signal(bool(0))
btnr = Signal(bool(0))
btnc = Signal(bool(0))
sw = Signal(intbv(0)[4:])
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)[88:])
s_axis_cq_tvalid = Signal(bool(0))
m_axis_cc_tready = Signal(bool(0))
cfg_max_payload = Signal(intbv(0)[2:])
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_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
led = Signal(intbv(0)[8:])
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)[62:])
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)[10:])
cfg_mgmt_function_number = Signal(intbv(0)[8:])
cfg_mgmt_write = Signal(bool(0))
cfg_mgmt_write_data = Signal(intbv(0)[32:])
cfg_mgmt_byte_enable = Signal(intbv(0)[4:])
cfg_mgmt_read = Signal(bool(0))
cfg_interrupt_msi_int = Signal(intbv(0)[32:])
cfg_interrupt_msi_pending_status = Signal(intbv(0)[32:])
cfg_interrupt_msi_select = Signal(intbv(0)[2:])
cfg_interrupt_msi_pending_status_function_num = Signal(intbv(0)[2:])
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)[8:])
cfg_interrupt_msi_function_number = Signal(intbv(0)[8:])
# 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_usp.UltrascalePlusPCIe()
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(intbv(1)[2:]),
#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_num0=pcie_rq_seq_num0,
#pcie_rq_seq_num_vld0=pcie_rq_seq_num_vld0,
#pcie_rq_seq_num1=pcie_rq_seq_num1,
#pcie_rq_seq_num_vld1=pcie_rq_seq_num_vld1,
#pcie_rq_tag0=pcie_rq_tag0,
#pcie_rq_tag1=pcie_rq_tag1,
#pcie_rq_tag_av=pcie_rq_tag_av,
#pcie_rq_tag_vld0=pcie_rq_tag_vld0,
#pcie_rq_tag_vld1=pcie_rq_tag_vld1,
# Requester Completion Interface
m_axis_rc_tdata=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_function_number=cfg_mgmt_function_number,
cfg_mgmt_write=cfg_mgmt_write,
cfg_mgmt_write_data=cfg_mgmt_write_data,
cfg_mgmt_byte_enable=cfg_mgmt_byte_enable,
cfg_mgmt_read=cfg_mgmt_read,
cfg_mgmt_read_data=cfg_mgmt_read_data,
cfg_mgmt_read_write_done=cfg_mgmt_read_write_done,
#cfg_mgmt_debug_access=cfg_mgmt_debug_access,
# Configuration Status Interface
#cfg_phy_link_down=cfg_phy_link_down,
#cfg_phy_link_status=cfg_phy_link_status,
#cfg_negotiated_width=cfg_negotiated_width,
#cfg_current_speed=cfg_current_speed,
cfg_max_payload=cfg_max_payload,
cfg_max_read_req=cfg_max_read_req,
#cfg_function_status=cfg_function_status,
#cfg_vf_status=cfg_vf_status,
#cfg_function_power_state=cfg_function_power_state,
#cfg_vf_power_state=cfg_vf_power_state,
#cfg_link_power_state=cfg_link_power_state,
#cfg_err_cor_out=cfg_err_cor_out,
#cfg_err_nonfatal_out=cfg_err_nonfatal_out,
#cfg_err_fatal_out=cfg_err_fatal_out,
#cfg_local_err_out=cfg_local_err_out,
#cfg_local_err_valid=cfg_local_err_valid,
#cfg_rx_pm_state=cfg_rx_pm_state,
#cfg_tx_pm_state=cfg_tx_pm_state,
#cfg_ltssm_state=cfg_ltssm_state,
#cfg_rcb_status=cfg_rcb_status,
#cfg_obff_enable=cfg_obff_enable,
#cfg_pl_status_change=cfg_pl_status_change,
#cfg_tph_requester_enable=cfg_tph_requester_enable,
#cfg_tph_st_mode=cfg_tph_st_mode,
#cfg_vf_tph_requester_enable=cfg_vf_tph_requester_enable,
#cfg_vf_tph_st_mode=cfg_vf_tph_st_mode,
# Configuration Received Message Interface
#cfg_msg_received=cfg_msg_received,
#cfg_msg_received_data=cfg_msg_received_data,
#cfg_msg_received_type=cfg_msg_received_type,
# Configuration Transmit Message Interface
#cfg_msg_transmit=cfg_msg_transmit,
#cfg_msg_transmit_type=cfg_msg_transmit_type,
#cfg_msg_transmit_data=cfg_msg_transmit_data,
#cfg_msg_transmit_done=cfg_msg_transmit_done,
# Configuration Flow Control Interface
#cfg_fc_ph=cfg_fc_ph,
#cfg_fc_pd=cfg_fc_pd,
#cfg_fc_nph=cfg_fc_nph,
#cfg_fc_npd=cfg_fc_npd,
#cfg_fc_cplh=cfg_fc_cplh,
#cfg_fc_cpld=cfg_fc_cpld,
#cfg_fc_sel=cfg_fc_sel,
# Configuration Control Interface
#cfg_hot_reset_in=cfg_hot_reset_in,
#cfg_hot_reset_out=cfg_hot_reset_out,
#cfg_config_space_enable=cfg_config_space_enable,
#cfg_dsn=cfg_dsn,
#cfg_ds_port_number=cfg_ds_port_number,
#cfg_ds_bus_number=cfg_ds_bus_number,
#cfg_ds_device_number=cfg_ds_device_number,
#cfg_ds_function_number=cfg_ds_function_number,
#cfg_power_state_change_ack=cfg_power_state_change_ack,
#cfg_power_state_change_interrupt=cfg_power_state_change_interrupt,
cfg_err_cor_in=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_mmenable=cfg_interrupt_msi_mmenable,
cfg_interrupt_msi_mask_update=cfg_interrupt_msi_mask_update,
cfg_interrupt_msi_data=cfg_interrupt_msi_data,
cfg_interrupt_msi_select=cfg_interrupt_msi_select,
cfg_interrupt_msi_int=cfg_interrupt_msi_int,
cfg_interrupt_msi_pending_status=cfg_interrupt_msi_pending_status,
cfg_interrupt_msi_pending_status_data_enable=cfg_interrupt_msi_pending_status_data_enable,
cfg_interrupt_msi_pending_status_function_num=cfg_interrupt_msi_pending_status_function_num,
cfg_interrupt_msi_sent=cfg_interrupt_msi_sent,
cfg_interrupt_msi_fail=cfg_interrupt_msi_fail,
#cfg_interrupt_msix_enable=cfg_interrupt_msix_enable,
#cfg_interrupt_msix_mask=cfg_interrupt_msix_mask,
#cfg_interrupt_msix_vf_enable=cfg_interrupt_msix_vf_enable,
#cfg_interrupt_msix_vf_mask=cfg_interrupt_msix_vf_mask,
#cfg_interrupt_msix_address=cfg_interrupt_msix_address,
#cfg_interrupt_msix_data=cfg_interrupt_msix_data,
#cfg_interrupt_msix_int=cfg_interrupt_msix_int,
#cfg_interrupt_msix_vec_pending=cfg_interrupt_msix_vec_pending,
#cfg_interrupt_msix_vec_pending_status=cfg_interrupt_msix_vec_pending_status,
cfg_interrupt_msi_attr=cfg_interrupt_msi_attr,
cfg_interrupt_msi_tph_present=cfg_interrupt_msi_tph_present,
cfg_interrupt_msi_tph_type=cfg_interrupt_msi_tph_type,
cfg_interrupt_msi_tph_st_tag=cfg_interrupt_msi_tph_st_tag,
cfg_interrupt_msi_function_number=cfg_interrupt_msi_function_number,
# Configuration Extend Interface
#cfg_ext_read_received=cfg_ext_read_received,
#cfg_ext_write_received=cfg_ext_write_received,
#cfg_ext_register_number=cfg_ext_register_number,
#cfg_ext_function_number=cfg_ext_function_number,
#cfg_ext_write_data=cfg_ext_write_data,
#cfg_ext_write_byte_enable=cfg_ext_write_byte_enable,
#cfg_ext_read_data=cfg_ext_read_data,
#cfg_ext_read_data_valid=cfg_ext_read_data_valid,
# Clock and Reset Interface
user_clk=user_clk,
user_reset=user_reset,
#user_lnk_up=user_lnk_up,
sys_clk=sys_clk,
sys_clk_gt=sys_clk,
sys_reset=sys_reset,
#phy_rdy_out=phy_rdy_out
)
# 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,
btnu=btnu,
btnl=btnl,
btnd=btnd,
btnr=btnr,
btnc=btnc,
sw=sw,
led=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_function_number=cfg_mgmt_function_number,
cfg_mgmt_write=cfg_mgmt_write,
cfg_mgmt_write_data=cfg_mgmt_write_data,
cfg_mgmt_byte_enable=cfg_mgmt_byte_enable,
cfg_mgmt_read=cfg_mgmt_read,
cfg_mgmt_read_data=cfg_mgmt_read_data,
cfg_mgmt_read_write_done=cfg_mgmt_read_write_done,
cfg_interrupt_msi_enable=cfg_interrupt_msi_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,245 @@
/*
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 btnu = 0;
reg btnl = 0;
reg btnd = 0;
reg btnr = 0;
reg btnc = 0;
reg [3:0] sw = 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 [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 [7:0] led;
wire [1:0] user_led_g;
wire user_led_r;
wire [1:0] front_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 [9:0] cfg_mgmt_addr;
wire [7:0] cfg_mgmt_function_number;
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,
btnu,
btnl,
btnd,
btnr,
btnc,
sw,
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_mmenable,
cfg_interrupt_msi_mask_update,
cfg_interrupt_msi_data,
cfg_interrupt_msi_sent,
cfg_interrupt_msi_fail
);
$to_myhdl(
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_function_number,
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),
.btnu(btnu),
.btnl(btnl),
.btnd(btnd),
.btnr(btnr),
.btnc(btnc),
.sw(sw),
.led(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_function_number(cfg_mgmt_function_number),
.cfg_mgmt_write(cfg_mgmt_write),
.cfg_mgmt_write_data(cfg_mgmt_write_data),
.cfg_mgmt_byte_enable(cfg_mgmt_byte_enable),
.cfg_mgmt_read(cfg_mgmt_read),
.cfg_mgmt_read_data(cfg_mgmt_read_data),
.cfg_mgmt_read_write_done(cfg_mgmt_read_write_done),
.cfg_interrupt_msi_enable(cfg_interrupt_msi_enable),
.cfg_interrupt_msi_mmenable(cfg_interrupt_msi_mmenable),
.cfg_interrupt_msi_mask_update(cfg_interrupt_msi_mask_update),
.cfg_interrupt_msi_data(cfg_interrupt_msi_data),
.cfg_interrupt_msi_select(cfg_interrupt_msi_select),
.cfg_interrupt_msi_int(cfg_interrupt_msi_int),
.cfg_interrupt_msi_pending_status(cfg_interrupt_msi_pending_status),
.cfg_interrupt_msi_pending_status_data_enable(cfg_interrupt_msi_pending_status_data_enable),
.cfg_interrupt_msi_pending_status_function_num(cfg_interrupt_msi_pending_status_function_num),
.cfg_interrupt_msi_sent(cfg_interrupt_msi_sent),
.cfg_interrupt_msi_fail(cfg_interrupt_msi_fail),
.cfg_interrupt_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

View File

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

925
fpga/lib/pcie/tb/test_pcie_usp.py Executable file
View File

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