├── test ├── __init__.py ├── model │ ├── __init__.py │ ├── host.py │ ├── tlp.py │ ├── chipset.py │ └── phy.py ├── common.py └── test_examples.py ├── examples ├── __init__.py ├── ac701.yml ├── acorn.yml └── kcu105.yml ├── litepcie ├── __init__.py ├── phy │ ├── __init__.py │ ├── xilinx_us │ │ ├── axis_iff.v │ │ ├── s_axis_cc_adapt_256b.v │ │ ├── m_axis_rc_adapt_128b.v │ │ ├── m_axis_rc_adapt_256b.v │ │ ├── s_axis_cc_adapt_128b.v │ │ ├── s_axis_rq_adapt_256b.v │ │ └── m_axis_cq_adapt_256b.v │ └── xilinx_usp │ │ ├── axis_iff.v │ │ ├── s_axis_cc_adapt_256b.v │ │ ├── m_axis_rc_adapt_128b.v │ │ ├── m_axis_rc_adapt_512b.v │ │ ├── m_axis_rc_adapt_256b.v │ │ ├── s_axis_cc_adapt_128b.v │ │ ├── s_axis_cc_adapt_512b.v │ │ ├── s_axis_rq_adapt_256b.v │ │ ├── m_axis_cq_adapt_512b.v │ │ └── m_axis_cq_adapt_256b.v ├── tlp │ └── __init__.py ├── frontend │ ├── __init__.py │ ├── ptm │ │ ├── __init__.py │ │ └── sniffer_tap.v │ ├── axi.py │ └── wishbone.py ├── core │ ├── __init__.py │ ├── common.py │ ├── endpoint.py │ ├── msi.py │ └── crossbar.py ├── software │ ├── kernel │ │ ├── README │ │ ├── Makefile │ │ ├── flags.h │ │ ├── init.sh │ │ ├── litex.h │ │ ├── litepcie.h │ │ └── config.h │ ├── user │ │ ├── liblitepcie │ │ │ ├── liblitepcie.h │ │ │ ├── litepcie_helpers.h │ │ │ ├── litepcie_flash.h │ │ │ ├── litepcie_helpers.c │ │ │ └── litepcie_dma.h │ │ └── Makefile │ └── __init__.py └── common.py ├── doc ├── architecture.png └── enjoy_digital.png ├── MANIFEST.in ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── CONTRIBUTORS ├── LICENSE ├── setup.py ├── README.md └── bench ├── kc705.py ├── test_ltssm_tracer.py ├── kcu105.py ├── fk33.py └── xcu1525.py /test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /litepcie/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/model/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /litepcie/phy/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /litepcie/tlp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /litepcie/frontend/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoy-digital/litepcie/HEAD/doc/architecture.png -------------------------------------------------------------------------------- /doc/enjoy_digital.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoy-digital/litepcie/HEAD/doc/enjoy_digital.png -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | graft litepcie 2 | 3 | include CONTRIBUTORS 4 | include LICENSE 5 | 6 | graft doc 7 | 8 | prune bench 9 | prune examples 10 | prune test 11 | -------------------------------------------------------------------------------- /litepcie/core/__init__.py: -------------------------------------------------------------------------------- 1 | from litepcie.core.endpoint import LitePCIeEndpoint 2 | from litepcie.core.msi import LitePCIeMSI, LitePCIeMSIMultiVector, LitePCIeMSIX 3 | -------------------------------------------------------------------------------- /litepcie/software/kernel/README: -------------------------------------------------------------------------------- 1 | - Use 'make' to build the driver 2 | 3 | - Install the driver and create the device with : 4 | 5 | ./init.sh 6 | 7 | - Remove driver with 8 | 9 | rmmod litepcie 10 | -------------------------------------------------------------------------------- /test/common.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2015-2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | 8 | def seed_to_data(seed, random=True): 9 | if random: 10 | return (seed * 0x31415979 + 1) & 0xffffffff 11 | else: 12 | return seed 13 | -------------------------------------------------------------------------------- /litepcie/frontend/ptm/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe-PTM. 3 | # 4 | # Copyright (c) 2023 NetTimeLogic 5 | # Copyright (c) 2023 Florent Kermarrec 6 | # SPDX-License-Identifier: BSD-2-Clause 7 | 8 | from litepcie.frontend.ptm.sniffer import PCIePTMSniffer 9 | from litepcie.frontend.ptm.core import PTMCapabilities, PTMRequester 10 | -------------------------------------------------------------------------------- /litepcie/software/user/liblitepcie/liblitepcie.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause 2 | * 3 | * LitePCIe library 4 | * 5 | * This file is part of LitePCIe. 6 | * 7 | * Copyright (C) 2018-2023 / EnjoyDigital / florent@enjoy-digital.fr 8 | * 9 | */ 10 | 11 | #ifndef LITEPCIE_LIB_H 12 | #define LITEPCIE_LIB_H 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #include "litepcie_dma.h" 19 | #include "litepcie_flash.h" 20 | #include "litepcie_helpers.h" 21 | #include "litepcie.h" 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | 27 | #endif /* LITEPCIE_LIB_H */ 28 | -------------------------------------------------------------------------------- /litepcie/frontend/ptm/sniffer_tap.v: -------------------------------------------------------------------------------- 1 | module sniffer_tap ( 2 | (* mark_debug = "true" *) 3 | input wire rst_n_in, 4 | (* mark_debug = "true" *) 5 | input wire clk_in, 6 | (* mark_debug = "true" *) 7 | input wire [15:0] rx_data_in, 8 | (* mark_debug = "true" *) 9 | input wire [1:0] rx_ctl_in, 10 | 11 | output wire rst_n_out, 12 | output wire clk_out, 13 | output wire [15:0] rx_data_out, 14 | output wire [1:0] rx_ctl_out 15 | ); 16 | 17 | assign rst_n_out = rst_n_in; 18 | assign clk_out = clk_in; 19 | assign rx_data_out = rx_data_in; 20 | assign rx_ctl_out = rx_ctl_in; 21 | 22 | endmodule -------------------------------------------------------------------------------- /litepcie/software/kernel/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for kernel module 2 | KERNEL_VERSION:=$(shell uname -r) 3 | KERNEL_PATH?=/lib/modules/$(KERNEL_VERSION)/build 4 | ARCH?=$(shell uname -m) 5 | 6 | obj-m = litepcie.o liteuart.o 7 | litepcie-objs = main.o 8 | #liteuart-objs = liteuart.o 9 | 10 | 11 | all: litepcie.ko liteuart.ko 12 | 13 | litepcie.ko: main.c 14 | make -C $(KERNEL_PATH) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(shell pwd) modules 15 | 16 | litepcie.ko: litepcie.h config.h flags.h csr.h soc.h 17 | 18 | liteuart.ko: liteuart.c 19 | make -C $(KERNEL_PATH) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(shell pwd) modules 20 | 21 | clean: 22 | make -C $(KERNEL_PATH) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(shell pwd) clean 23 | rm -f *~ 24 | -------------------------------------------------------------------------------- /litepcie/software/user/liblitepcie/litepcie_helpers.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause 2 | * 3 | * LitePCIe library 4 | * 5 | * This file is part of LitePCIe. 6 | * 7 | * Copyright (C) 2018-2023 / EnjoyDigital / florent@enjoy-digital.fr 8 | * 9 | */ 10 | 11 | #ifndef LITEPCIE_LIB_HELPERS_H 12 | #define LITEPCIE_LIB_HELPERS_H 13 | 14 | #include 15 | #include 16 | 17 | int64_t get_time_ms(void); 18 | 19 | uint32_t litepcie_readl(int fd, uint32_t addr); 20 | void litepcie_writel(int fd, uint32_t addr, uint32_t val); 21 | void litepcie_reload(int fd); 22 | 23 | #define checked_ioctl(...) _check_ioctl(ioctl(__VA_ARGS__), __FILE__, __LINE__) 24 | void _check_ioctl(int status, const char *file, int line); 25 | 26 | #endif /* LITEPCIE_LIB_HELPERS_H */ 27 | -------------------------------------------------------------------------------- /litepcie/software/kernel/flags.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause 2 | * 3 | * LitePCIe driver 4 | * 5 | * This file is part of LitePCIe. 6 | * 7 | * Copyright (C) 2018-2024 / EnjoyDigital / florent@enjoy-digital.fr 8 | * 9 | */ 10 | 11 | #ifndef __HW_FLAGS_H 12 | #define __HW_FLAGS_H 13 | 14 | /* SPI */ 15 | #define SPI_CTRL_START (1 << 0) 16 | #define SPI_CTRL_LENGTH (1 << 8) 17 | #define SPI_STATUS_DONE (1 << 0) 18 | 19 | /* PCIe */ 20 | #define DMA_TABLE_LOOP_INDEX (1 << 0) 21 | #define DMA_TABLE_LOOP_COUNT (1 << 16) 22 | 23 | /* ICAP */ 24 | #define ICAP_CMD_REG 0b00100 25 | #define ICAP_CMD_IPROG 0b01111 26 | 27 | #define ICAP_IDCODE_REG 0b01100 28 | 29 | #define ICAP_BOOTSTS_REG 0b10110 30 | #define ICAP_BOOTSTS_VALID (1 << 0) 31 | #define ICAP_BOOTSTS_FALLBACK (1 << 1) 32 | 33 | 34 | #endif /* __HW_FLAGS_H */ 35 | -------------------------------------------------------------------------------- /litepcie/software/user/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-O2 -Wall -g -I../kernel -Iliblitepcie -MMD -fPIC 2 | LDFLAGS=-g 3 | CC=$(CROSS_COMPILE)gcc 4 | AR=ar 5 | 6 | PROGS=litepcie_util litepcie_test 7 | 8 | all: $(PROGS) 9 | 10 | liblitepcie/liblitepcie.a: liblitepcie/litepcie_dma.o liblitepcie/litepcie_flash.o liblitepcie/litepcie_helpers.o 11 | ar rcs $@ $+ 12 | ranlib $@ 13 | 14 | litepcie_util: liblitepcie/liblitepcie.a litepcie_util.o 15 | $(CC) $(LDFLAGS) -o $@ $^ -Lliblitepcie -llitepcie 16 | 17 | litepcie_test: liblitepcie/liblitepcie.a litepcie_test.o 18 | $(CC) $(LDFLAGS) -o $@ $^ -Lliblitepcie -lm -llitepcie 19 | 20 | clean: 21 | rm -f $(PROGS) *.o *.a *.d *~ liblitepcie/*.a liblitepcie/*.o liblitepcie/*.d 22 | 23 | %.o: %.c 24 | $(CC) -c $(CFLAGS) -o $@ $< 25 | 26 | liblitepcie/%.o: liblitepcie/%.c 27 | $(CC) -c $(CFLAGS) -o $@ $< 28 | 29 | -include $(wildcard *.d) 30 | -------------------------------------------------------------------------------- /litepcie/software/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from shutil import copytree 3 | 4 | from litex.build import tools 5 | 6 | from litex.soc.integration.export import get_csr_header, get_soc_header, get_mem_header 7 | 8 | 9 | def copy_litepcie_software(dst): 10 | src = os.path.abspath(os.path.dirname(__file__)) 11 | copytree(src, dst, dirs_exist_ok=True) 12 | 13 | def generate_litepcie_software_headers(soc, dst): 14 | csr_header = get_csr_header(soc.csr_regions, soc.constants, with_access_functions=False) 15 | tools.write_to_file(os.path.join(dst, "csr.h"), csr_header) 16 | soc_header = get_soc_header(soc.constants, with_access_functions=False) 17 | tools.write_to_file(os.path.join(dst, "soc.h"), soc_header) 18 | mem_header = get_mem_header(soc.mem_regions) 19 | tools.write_to_file(os.path.join(dst, "mem.h"), mem_header) 20 | 21 | def generate_litepcie_software(soc, dst): 22 | copy_litepcie_software(dst) 23 | generate_litepcie_software_headers(soc, os.path.join(dst, "kernel")) 24 | -------------------------------------------------------------------------------- /litepcie/software/user/liblitepcie/litepcie_flash.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause 2 | * 3 | * LitePCIe library 4 | * 5 | * This file is part of LitePCIe. 6 | * 7 | * Copyright (C) 2018-2023 / EnjoyDigital / florent@enjoy-digital.fr 8 | * 9 | */ 10 | 11 | #ifndef LITEPCIE_LIB_FLASH_H 12 | #define LITEPCIE_LIB_FLASH_H 13 | 14 | #include 15 | 16 | #define FLASH_READ_ID_REG 0x9F 17 | 18 | #define FLASH_READ 0x03 19 | #define FLASH_WREN 0x06 20 | #define FLASH_WRDI 0x04 21 | #define FLASH_PP 0x02 22 | #define FLASH_SE 0xD8 23 | #define FLASH_BE 0xC7 24 | #define FLASH_RDSR 0x05 25 | #define FLASH_WRSR 0x01 26 | /* status */ 27 | #define FLASH_WIP 0x01 28 | 29 | #define FLASH_SECTOR_SIZE (1 << 16) 30 | 31 | uint8_t litepcie_flash_read(int fd, uint32_t addr); 32 | int litepcie_flash_get_erase_block_size(int fd); 33 | int litepcie_flash_write(int fd, 34 | uint8_t *buf, uint32_t base, uint32_t size, 35 | void (*progress_cb)(void *opaque, const char *fmt, ...), 36 | void *opaque); 37 | 38 | #endif //LITEPCIE_LIB_FLASH_H 39 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-22.04 8 | steps: 9 | # Checkout Repository 10 | - name: Checkout 11 | uses: actions/checkout@v2 12 | 13 | # Install Tools 14 | - name: Install Tools 15 | run: | 16 | sudo apt-get install wget build-essential 17 | 18 | - name: Set up Python 3.9 19 | uses: actions/setup-python@v4 20 | with: 21 | python-version: "3.9" 22 | cache: "pip" 23 | cache-dependency-path: "setup.py" 24 | 25 | - name: Install Python dependencies 26 | run: | 27 | python3 -m pip install setuptools requests pexpect meson pytest 28 | 29 | # Install (n)Migen / LiteX / Cores 30 | - name: Install LiteX 31 | run: | 32 | wget https://raw.githubusercontent.com/enjoy-digital/litex/master/litex_setup.py 33 | python3 litex_setup.py init install --user 34 | 35 | # Install Project 36 | - name: Install Project 37 | run: python3 setup.py develop --user 38 | 39 | # Test 40 | - name: Run Tests 41 | run: python3 -m pytest -v 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | LiteX ecosystem would not exist without the collaborative work of contributors! Here is below the 2 | list of all the LitePCIe contributors. 3 | 4 | In the source code, each file list the main authors/contributors: 5 | - author(s) that created the initial content. 6 | - contributor(s) that added essential features/improvements. 7 | 8 | If you think you should be in this list and don't find yourself, write to florent@enjoy-digital.fr 9 | and we'll fix it! 10 | 11 | Contributors: 12 | Copyright (c) 2021 Ahmad Fatoum 13 | Copyright (c) 2020 Antmicro 14 | Copyright (c) 2018 Felix Held 15 | Copyright (c) 2015-2025 Florent Kermarrec 16 | Copyright (c) 2021-2025 Gwenhael Goavec-Merou 17 | Copyright (c) 2019-2021 Ilia Sergachev 18 | Copyright (c) 2023-2024 John Simons 19 | Copyright (c) 2024 Liam Murphy 20 | Copyright (c) 2022 Steve Kelly 21 | Copyright (c) 2022-2024 Sylvain Munaut 22 | Copyright (c) 2021 Tim Besard 23 | Copyright (c) 2017 Tim 'mithro' Ansell 24 | Copyright (c) 2023-2024 Tim Paine <3105306+timkpaine@users.noreply.github.com> 25 | Copyright (c) 2021 tongchen126 26 | Copyright (c) 2024 Vladimir Pinchuk 27 | -------------------------------------------------------------------------------- /litepcie/software/kernel/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # TODO: use udev instead 3 | 4 | # Check if litepcie module is already installed. 5 | FOUND=$(lsmod | grep litepcie) 6 | if [ "$FOUND" != "" ] ; then 7 | echo "litepcie module already installed." 8 | exit 0 9 | fi 10 | 11 | # Automatically remove liteuart module if installed. 12 | FOUND=$(lsmod | grep liteuart) 13 | if [ "$FOUND" != "" ] ; then 14 | rmmod liteuart.ko 15 | fi 16 | 17 | # Install litepcie module. 18 | INS=$(insmod litepcie.ko 2>&1) 19 | if [ "$?" != "0" ] ; then 20 | ERR=$(echo $INS | sed -s "s/.*litepcie.ko: //") 21 | case $ERR in 22 | 'Invalid module format') 23 | set -e 24 | echo "Kernel may have changed, try to rebuild module" 25 | make -s clean 26 | make -s 27 | insmod litepcie.ko 28 | set +e 29 | ;; 30 | 'No such file or directory') 31 | set -e 32 | echo "Module not compiled" 33 | make -s 34 | insmod litepcie.ko 35 | set +e 36 | ;; 37 | 'Required key not available') 38 | echo "Can't insert kernel module, secure boot is probably enabled" 39 | echo "Please disable it from BIOS" 40 | exit 1 41 | ;; 42 | *) 43 | >&2 echo $INS 44 | exit 1 45 | esac 46 | fi 47 | 48 | # Install liteuart module. 49 | insmod liteuart.ko 50 | 51 | # Change permissions on litepcie created devices. 52 | for i in `seq 0 16` ; do 53 | chmod 666 /dev/litepcie$i > /dev/null 2>&1 54 | done 55 | 56 | -------------------------------------------------------------------------------- /litepcie/software/user/liblitepcie/litepcie_helpers.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause 2 | * 3 | * LitePCIe library 4 | * 5 | * This file is part of LitePCIe. 6 | * 7 | * Copyright (C) 2018-2023 / EnjoyDigital / florent@enjoy-digital.fr 8 | * 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "litepcie_helpers.h" 18 | #include "litepcie.h" 19 | 20 | int64_t get_time_ms(void) 21 | { 22 | struct timespec ts; 23 | clock_gettime(CLOCK_MONOTONIC, &ts); 24 | return (int64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000U); 25 | } 26 | 27 | uint32_t litepcie_readl(int fd, uint32_t addr) { 28 | struct litepcie_ioctl_reg m; 29 | m.is_write = 0; 30 | m.addr = addr; 31 | checked_ioctl(fd, LITEPCIE_IOCTL_REG, &m); 32 | return m.val; 33 | } 34 | 35 | void litepcie_writel(int fd, uint32_t addr, uint32_t val) { 36 | struct litepcie_ioctl_reg m; 37 | m.is_write = 1; 38 | m.addr = addr; 39 | m.val = val; 40 | checked_ioctl(fd, LITEPCIE_IOCTL_REG, &m); 41 | } 42 | 43 | void litepcie_reload(int fd) { 44 | struct litepcie_ioctl_icap m; 45 | m.addr = 0x4; 46 | m.data = 0xf; 47 | checked_ioctl(fd, LITEPCIE_IOCTL_ICAP, &m); 48 | } 49 | 50 | void _check_ioctl(int status, const char *file, int line) { 51 | if (status) { 52 | fprintf(stderr, "Failed ioctl at %s:%d: %s\n", file, line, strerror(errno)); 53 | abort(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /litepcie/core/common.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2015-2023 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | from migen import * 8 | 9 | from litex.gen import * 10 | 11 | from litepcie.common import * 12 | 13 | # LitePCIe Internal Ports -------------------------------------------------------------------------- 14 | 15 | class LitePCIeSlaveInternalPort: 16 | def __init__(self, data_width, address_width=32, address_decoder=None): 17 | self.address_decoder = address_decoder 18 | self.sink = stream.Endpoint(completion_layout(data_width)) 19 | self.source = stream.Endpoint(request_layout(data_width)) 20 | 21 | 22 | class LitePCIeMasterInternalPort: 23 | def __init__(self, data_width, address_width=32, channel=None, write_only=False, read_only=False): 24 | self.channel = channel 25 | self.write_only = write_only 26 | self.read_only = read_only 27 | self.sink = stream.Endpoint(request_layout(data_width, address_width)) 28 | self.source = stream.Endpoint(completion_layout(data_width)) 29 | 30 | # LitePCIe User Ports ------------------------------------------------------------------------------ 31 | 32 | class LitePCIeSlavePort: 33 | def __init__(self, port): 34 | self.address_decoder = port.address_decoder 35 | self.sink = port.source 36 | self.source = port.sink 37 | 38 | 39 | class LitePCIeMasterPort: 40 | def __init__(self, port): 41 | self.channel = port.channel 42 | self.sink = port.source 43 | self.source = port.sink 44 | -------------------------------------------------------------------------------- /test/test_examples.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2019-2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | import unittest 8 | import os 9 | 10 | # Test Examples ------------------------------------------------------------------------------------ 11 | 12 | class TestExamples(unittest.TestCase): 13 | def target_test(self, target): 14 | os.system("rm -rf bench/build") 15 | os.system("cd bench && python3 {}.py".format(target)) 16 | self.assertEqual(os.path.isfile("bench/build/{}/gateware/{}.v".format(target, target)), True) 17 | self.assertEqual(os.path.isfile("bench/build/{}/software/include/generated/csr.h".format(target)), True) 18 | self.assertEqual(os.path.isfile("bench/build/{}/software/include/generated/soc.h".format(target)), True) 19 | self.assertEqual(os.path.isfile("bench/build/{}/software/include/generated/mem.h".format(target)), True) 20 | 21 | def test_kc705_target(self): 22 | self.target_test("kc705") 23 | 24 | def test_kcu105_target(self): 25 | self.target_test("kcu105") 26 | 27 | def test_fk33_target(self): 28 | self.target_test("fk33") 29 | 30 | def test_xcu1525_target(self): 31 | self.target_test("xcu1525") 32 | 33 | def gen_test(self, name): 34 | os.system("rm -rf examples/build") 35 | os.system("cd examples && python3 ../litepcie/gen.py {}.yml".format(name)) 36 | errors = not os.path.isfile("examples/build/gateware/litepcie_core.v") 37 | os.system("rm -rf examples/build") 38 | return errors 39 | 40 | def test_ac701_gen(self): 41 | errors = self.gen_test("ac701") 42 | self.assertEqual(errors, 0) 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Unless otherwise noted, LitePCIe is Copyright 2015-2024 / EnjoyDigital 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright notice, 9 | this list of conditions and the following disclaimer in the documentation 10 | and/or other materials provided with the distribution. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 16 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | 23 | 24 | Other authors retain ownership of their contributions. If a submission can 25 | reasonably be considered independently copyrightable, it's yours and we 26 | encourage you to claim it with appropriate copyright notices. This submission 27 | then falls under the "otherwise noted" category. All submissions are strongly 28 | encouraged to use the two-clause BSD license reproduced above. 29 | -------------------------------------------------------------------------------- /litepcie/software/user/liblitepcie/litepcie_dma.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause 2 | * 3 | * LitePCIe library 4 | * 5 | * This file is part of LitePCIe. 6 | * 7 | * Copyright (C) 2018-2023 / EnjoyDigital / florent@enjoy-digital.fr 8 | * 9 | */ 10 | 11 | #ifndef LITEPCIE_LIB_DMA_H 12 | #define LITEPCIE_LIB_DMA_H 13 | 14 | #include 15 | #include 16 | #include "litepcie.h" 17 | 18 | struct litepcie_dma_ctrl { 19 | uint8_t use_reader, use_writer, loopback, zero_copy; 20 | struct pollfd fds; 21 | char *buf_rd, *buf_wr; 22 | uint8_t reader_enable; 23 | uint8_t writer_enable; 24 | int64_t reader_hw_count, reader_sw_count; 25 | int64_t writer_hw_count, writer_sw_count; 26 | unsigned buffers_available_read, buffers_available_write; 27 | unsigned usr_read_buf_offset, usr_write_buf_offset; 28 | struct litepcie_ioctl_mmap_dma_info mmap_dma_info; 29 | struct litepcie_ioctl_mmap_dma_update mmap_dma_update; 30 | }; 31 | 32 | void litepcie_dma_set_loopback(int fd, uint8_t loopback_enable); 33 | void litepcie_dma_reader(int fd, uint8_t enable, int64_t *hw_count, int64_t *sw_count); 34 | void litepcie_dma_writer(int fd, uint8_t enable, int64_t *hw_count, int64_t *sw_count); 35 | 36 | uint8_t litepcie_request_dma(int fd, uint8_t reader, uint8_t writer); 37 | void litepcie_release_dma(int fd, uint8_t reader, uint8_t writer); 38 | 39 | int litepcie_dma_init(struct litepcie_dma_ctrl *dma, const char *device_name, uint8_t zero_copy); 40 | void litepcie_dma_cleanup(struct litepcie_dma_ctrl *dma); 41 | void litepcie_dma_process(struct litepcie_dma_ctrl *dma); 42 | char *litepcie_dma_next_read_buffer(struct litepcie_dma_ctrl *dma); 43 | char *litepcie_dma_next_write_buffer(struct litepcie_dma_ctrl *dma); 44 | 45 | #endif /* LITEPCIE_LIB_DMA_H */ 46 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from setuptools import setup 4 | from setuptools import find_packages 5 | 6 | 7 | with open("README.md", "r", encoding="utf-8") as fp: 8 | long_description = fp.read() 9 | 10 | 11 | setup( 12 | name = "litepcie", 13 | version = "2025.08", 14 | description = "Small footprint and configurable PCIe core", 15 | long_description = long_description, 16 | long_description_content_type = "text/markdown", 17 | author = "Florent Kermarrec", 18 | author_email = "florent@enjoy-digital.fr", 19 | url = "http://enjoy-digital.fr", 20 | download_url = "https://github.com/enjoy-digital/litepcie", 21 | test_suite = "test", 22 | license = "BSD", 23 | python_requires = "~=3.8", 24 | install_requires = ["pyyaml", "litex"], 25 | extras_require = { 26 | "develop": [ 27 | "meson" 28 | "pexpect" 29 | "setuptools" 30 | "requests" 31 | ] 32 | }, 33 | packages = find_packages(exclude=("test*", "sim*", "doc*", "examples*")), 34 | include_package_data = True, 35 | keywords = "HDL ASIC FPGA hardware design", 36 | classifiers = [ 37 | "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", 38 | "Environment :: Console", 39 | "Development Status :: 3 - Alpha", 40 | "Intended Audience :: Developers", 41 | "License :: OSI Approved :: BSD License", 42 | "Operating System :: OS Independent", 43 | "Programming Language :: Python", 44 | ], 45 | entry_points = { 46 | "console_scripts": [ 47 | "litepcie_gen=litepcie.gen:main", 48 | ], 49 | }, 50 | ) 51 | -------------------------------------------------------------------------------- /examples/ac701.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2019-2024 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | { 8 | # PHY ---------------------------------------------------------------------- 9 | "phy" : "S7PCIEPHY", # Type of PCIe PHY 10 | "phy_device" : "xc7a", # Type of Device 11 | "phy_lanes" : 4, # Number of lanes 12 | "phy_pcie_data_width" : 128, # PCIe data_width 13 | "phy_data_width" : 128, # Bus data_width 14 | "phy_bar0_size" : 0x40000, # BAR0 size 15 | 16 | # Clocking ----------------------------------------------------------------- 17 | "clk_freq" : 125e6, # User Clk Freq (AXI MMAP/DMA) 18 | "clk_external" : False, # Use external User provided Clk 19 | 20 | # Endpoint ----------------------------------------------------------------- 21 | "ep_max_pending_requests" : 8, 22 | "ep_address_width" : 32, 23 | 24 | # Control ------------------------------------------------------------------ 25 | "ctrl" : False, 26 | 27 | # MMAP Master -------------------------------------------------------------- 28 | "mmap" : True, 29 | "mmap_base" : 0x00020000, 30 | "mmap_size" : 0x00020000, 31 | 32 | # MMAP Slave --------------------------------------------------------------- 33 | "mmap_slave" : True, 34 | "mmap_slave_axi_full" : True, 35 | 36 | # DMA channels ------------------------------------------------------------- 37 | "dma_channels" : 4, # Number of DMA channels 38 | "dma_buffering" : 8192, # Buffering for each channel (in bytes) 39 | "dma_loopback" : True, # Enable DMA loopback capability 40 | "dma_synchronizer" : True, # Enable DMA synchronizer capability 41 | "dma_monitor" : True, # Enable DMA monitoring capability 42 | 43 | # MSI IRQs ----------------------------------------------------------------- 44 | "msi_irqs" : 16, # Number or MSI IRQs 45 | } 46 | -------------------------------------------------------------------------------- /examples/acorn.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2019-2024 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | { 8 | # PHY ---------------------------------------------------------------------- 9 | "phy" : "S7PCIEPHY", # Type of PCIe PHY 10 | "phy_device" : "xc7a", # Type of Device 11 | "phy_lanes" : 4, # Number of lanes 12 | "phy_pcie_data_width" : 128, # PCIe data_width 13 | "phy_data_width" : 128, # Bus data_width 14 | "phy_bar0_size" : 0x40000, # BAR0 size 15 | 16 | # Clocking ----------------------------------------------------------------- 17 | "clk_freq" : 125e6, # User Clk Freq (AXI MMAP/DMA) 18 | "clk_external" : True, # Use external User provided Clk 19 | 20 | # Endpoint ----------------------------------------------------------------- 21 | "ep_max_pending_requests" : 8, 22 | "ep_address_width" : 32, 23 | 24 | # Control ------------------------------------------------------------------ 25 | "ctrl" : False, 26 | 27 | # MMAP Master -------------------------------------------------------------- 28 | "mmap" : True, 29 | "mmap_base" : 0x00020000, 30 | "mmap_size" : 0x00020000, 31 | 32 | # MMAP Slave --------------------------------------------------------------- 33 | "mmap_slave" : True, 34 | "mmap_slave_axi_full" : True, 35 | 36 | # DMA channels ------------------------------------------------------------- 37 | "dma_channels" : 4, # Number of DMA channels 38 | "dma_buffering" : 1024, # Buffering for each channel (in bytes) 39 | "dma_loopback" : True, # Enable DMA loopback capability 40 | "dma_synchronizer" : False, # Enable DMA synchronizer capability 41 | "dma_monitor" : False, # Enable DMA monitoring capability 42 | 43 | # MSI IRQs ----------------------------------------------------------------- 44 | "msi_irqs" : 16, # Number or MSI IRQs 45 | } 46 | -------------------------------------------------------------------------------- /litepcie/software/kernel/litex.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 2 | * 3 | * Common LiteX header providing 4 | * helper functions for accessing CSRs. 5 | * 6 | * Copyright (C) 2019-2020 Antmicro 7 | */ 8 | 9 | #ifndef _LINUX_LITEX_H 10 | #define _LINUX_LITEX_H 11 | 12 | #include 13 | 14 | static inline void _write_litex_subregister(u32 val, void __iomem *addr) 15 | { 16 | writel((u32 __force)cpu_to_le32(val), addr); 17 | } 18 | 19 | static inline u32 _read_litex_subregister(void __iomem *addr) 20 | { 21 | return le32_to_cpu((__le32 __force)readl(addr)); 22 | } 23 | 24 | /* 25 | * LiteX SoC Generator, depending on the configuration, can split a single 26 | * logical CSR (Control&Status Register) into a series of consecutive physical 27 | * registers. 28 | * 29 | * For example, in the configuration with 8-bit CSR Bus, a 32-bit aligned, 30 | * 32-bit wide logical CSR will be laid out as four 32-bit physical 31 | * subregisters, each one containing one byte of meaningful data. 32 | * 33 | * For Linux support, upstream LiteX enforces a 32-bit wide CSR bus, which 34 | * means that only larger-than-32-bit CSRs will be split across multiple 35 | * subregisters (e.g., a 64-bit CSR will be spread across two consecutive 36 | * 32-bit subregisters). 37 | * 38 | * For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus 39 | */ 40 | 41 | static inline void litex_write8(void __iomem *reg, u8 val) 42 | { 43 | _write_litex_subregister(val, reg); 44 | } 45 | 46 | static inline void litex_write16(void __iomem *reg, u16 val) 47 | { 48 | _write_litex_subregister(val, reg); 49 | } 50 | 51 | static inline void litex_write32(void __iomem *reg, u32 val) 52 | { 53 | _write_litex_subregister(val, reg); 54 | } 55 | 56 | static inline void litex_write64(void __iomem *reg, u64 val) 57 | { 58 | _write_litex_subregister(val >> 32, reg); 59 | _write_litex_subregister(val, reg + 4); 60 | } 61 | 62 | static inline u8 litex_read8(void __iomem *reg) 63 | { 64 | return _read_litex_subregister(reg); 65 | } 66 | 67 | static inline u16 litex_read16(void __iomem *reg) 68 | { 69 | return _read_litex_subregister(reg); 70 | } 71 | 72 | static inline u32 litex_read32(void __iomem *reg) 73 | { 74 | return _read_litex_subregister(reg); 75 | } 76 | 77 | static inline u64 litex_read64(void __iomem *reg) 78 | { 79 | return ((u64)_read_litex_subregister(reg) << 32) | 80 | _read_litex_subregister(reg + 4); 81 | } 82 | 83 | #endif /* _LINUX_LITEX_H */ 84 | -------------------------------------------------------------------------------- /litepcie/software/kernel/litepcie.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause 2 | * 3 | * LitePCIe driver 4 | * 5 | * This file is part of LitePCIe. 6 | * 7 | * Copyright (C) 2018-2024 / EnjoyDigital / florent@enjoy-digital.fr 8 | * 9 | */ 10 | 11 | #ifndef _LINUX_LITEPCIE_H 12 | #define _LINUX_LITEPCIE_H 13 | 14 | #include 15 | 16 | #include "csr.h" 17 | #include "config.h" 18 | 19 | struct litepcie_ioctl_reg { 20 | uint32_t addr; 21 | uint32_t val; 22 | uint8_t is_write; 23 | }; 24 | 25 | struct litepcie_ioctl_flash { 26 | int tx_len; /* 8 to 40 */ 27 | __u64 tx_data; /* 8 to 40 bits */ 28 | __u64 rx_data; /* 40 bits */ 29 | }; 30 | 31 | struct litepcie_ioctl_icap { 32 | uint8_t addr; 33 | uint32_t data; 34 | }; 35 | 36 | struct litepcie_ioctl_dma { 37 | uint8_t loopback_enable; 38 | }; 39 | 40 | struct litepcie_ioctl_dma_writer { 41 | uint8_t enable; 42 | int64_t hw_count; 43 | int64_t sw_count; 44 | }; 45 | 46 | struct litepcie_ioctl_dma_reader { 47 | uint8_t enable; 48 | int64_t hw_count; 49 | int64_t sw_count; 50 | }; 51 | 52 | struct litepcie_ioctl_lock { 53 | uint8_t dma_reader_request; 54 | uint8_t dma_writer_request; 55 | uint8_t dma_reader_release; 56 | uint8_t dma_writer_release; 57 | uint8_t dma_reader_status; 58 | uint8_t dma_writer_status; 59 | }; 60 | 61 | struct litepcie_ioctl_mmap_dma_info { 62 | uint64_t dma_tx_buf_offset; 63 | uint64_t dma_tx_buf_size; 64 | uint64_t dma_tx_buf_count; 65 | 66 | uint64_t dma_rx_buf_offset; 67 | uint64_t dma_rx_buf_size; 68 | uint64_t dma_rx_buf_count; 69 | }; 70 | 71 | struct litepcie_ioctl_mmap_dma_update { 72 | int64_t sw_count; 73 | }; 74 | 75 | #define LITEPCIE_IOCTL 'S' 76 | 77 | #define LITEPCIE_IOCTL_REG _IOWR(LITEPCIE_IOCTL, 0, struct litepcie_ioctl_reg) 78 | #define LITEPCIE_IOCTL_FLASH _IOWR(LITEPCIE_IOCTL, 1, struct litepcie_ioctl_flash) 79 | #define LITEPCIE_IOCTL_ICAP _IOWR(LITEPCIE_IOCTL, 2, struct litepcie_ioctl_icap) 80 | 81 | #define LITEPCIE_IOCTL_DMA _IOW(LITEPCIE_IOCTL, 20, struct litepcie_ioctl_dma) 82 | #define LITEPCIE_IOCTL_DMA_WRITER _IOWR(LITEPCIE_IOCTL, 21, struct litepcie_ioctl_dma_writer) 83 | #define LITEPCIE_IOCTL_DMA_READER _IOWR(LITEPCIE_IOCTL, 22, struct litepcie_ioctl_dma_reader) 84 | #define LITEPCIE_IOCTL_MMAP_DMA_INFO _IOR(LITEPCIE_IOCTL, 24, struct litepcie_ioctl_mmap_dma_info) 85 | #define LITEPCIE_IOCTL_LOCK _IOWR(LITEPCIE_IOCTL, 25, struct litepcie_ioctl_lock) 86 | #define LITEPCIE_IOCTL_MMAP_DMA_WRITER_UPDATE _IOW(LITEPCIE_IOCTL, 26, struct litepcie_ioctl_mmap_dma_update) 87 | #define LITEPCIE_IOCTL_MMAP_DMA_READER_UPDATE _IOW(LITEPCIE_IOCTL, 27, struct litepcie_ioctl_mmap_dma_update) 88 | 89 | #endif /* _LINUX_LITEPCIE_H */ 90 | -------------------------------------------------------------------------------- /examples/kcu105.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2019-2024 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | { 8 | # PHY ---------------------------------------------------------------------- 9 | "phy" : "USPCIEPHY", # Type of PCIe PHY 10 | "phy_device" : "xcku", # Type of Device 11 | "phy_lanes" : 4, # Number of lanes 12 | "phy_pcie_data_width" : 128, # PCIe data_width 13 | "phy_data_width" : 128, # Bus data_width 14 | "phy_bar0_size" : 0x40000, # BAR0 size 15 | 16 | # Clocking ----------------------------------------------------------------- 17 | "clk_freq" : 125e6, # User Clk Freq (AXI MMAP/DMA) 18 | "clk_external" : False, # Use external User provided Clk 19 | 20 | # Endpoint ----------------------------------------------------------------- 21 | "ep_max_pending_requests" : 8, 22 | "ep_address_width" : 64, 23 | 24 | # Control ------------------------------------------------------------------ 25 | "ctrl" : False, 26 | 27 | # MMAP Master -------------------------------------------------------------- 28 | "mmap" : True, 29 | "mmap_base" : 0x00020000, 30 | "mmap_size" : 0x00020000, 31 | 32 | # MMAP Slave --------------------------------------------------------------- 33 | "mmap_slave" : True, 34 | 35 | # DMA channels ------------------------------------------------------------- 36 | "dma_channels": { 37 | "dma0": { 38 | "dma_writer" : True, # Enable DMA Writer. 39 | "dma_reader" : True, # Disable DMA Reader. 40 | "dma_buffering" : 8192, # Buffering for each channel (in bytes) 41 | "dma_loopback" : False, # Disable DMA loopback capability 42 | "dma_synchronizer" : False, # Disable DMA synchronizer capability 43 | "dma_monitor" : True, # Enable DMA monitoring capability 44 | }, 45 | "dma1": { 46 | "dma_writer" : True, # Enable DMA Writer. 47 | "dma_reader" : True, # Disable DMA Reader. 48 | "dma_buffering" : 8192, # Buffering for each channel (in bytes) 49 | "dma_loopback" : False, # Disable DMA loopback capability 50 | "dma_synchronizer" : False, # Disable DMA synchronizer capability 51 | "dma_monitor" : True, # Enable DMA monitoring capability 52 | }, 53 | }, 54 | 55 | # MSI IRQs ----------------------------------------------------------------- 56 | "msi_irqs" : 16, # Number or MSI IRQs 57 | } 58 | -------------------------------------------------------------------------------- /test/model/host.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2015-2024 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | from litex.gen import * 8 | 9 | from litepcie.common import * 10 | from litepcie.tlp.common import * 11 | 12 | from test.model.phy import PHY 13 | from test.model.tlp import * 14 | from test.model.chipset import Chipset 15 | 16 | # Helpers ------------------------------------------------------------------------------------------ 17 | 18 | def print_host(s): 19 | print("[HOST] {}".format(s)) 20 | 21 | 22 | # Host model --------------------------------------------------------------------------------------- 23 | 24 | class Host(LiteXModule): 25 | def __init__(self, data_width, root_id, endpoint_id, 26 | bar0_size = 1*MB, 27 | phy_debug = False, 28 | chipset_debug = False, 29 | chipset_split = False, 30 | chipset_reordering = False, 31 | host_debug = False): 32 | self.debug = host_debug 33 | self.chipset_split = chipset_split 34 | 35 | # # # 36 | 37 | self.phy = PHY(data_width, endpoint_id, bar0_size, phy_debug) 38 | self.chipset = Chipset(self.phy, root_id, chipset_debug, chipset_reordering) 39 | self.chipset.set_host_callback(self.callback) 40 | 41 | self.rd_queue = [] 42 | 43 | def malloc(self, base, length): 44 | self.base = base 45 | self.buffer = [0]*(length//4) 46 | 47 | def write_mem(self, adr, data): 48 | if self.debug: 49 | print_host("Writing {} bytes @0x{:08x}".format(len(data)*4, adr)) 50 | current_adr = (adr-self.base)//4 51 | for i in range(len(data)): 52 | self.buffer[current_adr+i] = data[i] 53 | 54 | def read_mem(self, adr, length=1): 55 | if self.debug: 56 | print_host("Reading {} bytes @0x{:08x}".format(length, adr)) 57 | current_adr = (adr-self.base)//4 58 | data = [] 59 | for i in range(length//4): 60 | data.append(self.buffer[current_adr+i]) 61 | return data 62 | 63 | def callback(self, msg): 64 | if isinstance(msg, WR32): 65 | self.write_mem(msg.address, msg.data) 66 | elif isinstance(msg, RD32): 67 | self.rd_queue.append(msg) 68 | elif isinstance(msg, WR64): 69 | self.write_mem(msg.address, msg.data) 70 | elif isinstance(msg, RD64): 71 | self.rd_queue.append(msg) 72 | 73 | @passive 74 | def generator(self): 75 | while True: 76 | if len(self.rd_queue): 77 | msg = self.rd_queue.pop(0) 78 | address = msg.address 79 | length = msg.length*4 80 | data = self.read_mem(address, length) 81 | self.chipset.cmp(msg.requester_id, data, 82 | byte_count = length, 83 | tag = msg.tag, 84 | with_split = self.chipset_split 85 | ) 86 | yield 87 | -------------------------------------------------------------------------------- /litepcie/phy/xilinx_us/axis_iff.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module axis_iff 7 | #( 8 | parameter DAT_B = 32 9 | ) 10 | ( 11 | input clk, 12 | input rst, 13 | 14 | input i_vld, 15 | output o_rdy, 16 | input i_sop, 17 | input i_eop, 18 | input [DAT_B-1:0] i_dat, 19 | 20 | 21 | output o_vld, 22 | input i_rdy, 23 | output o_sop, 24 | output o_eop, 25 | output [DAT_B-1:0] o_dat 26 | ); 27 | 28 | /////////////////////////////////////////////////////////////////////////// 29 | //FIFO instance 30 | localparam FF_B = 8; 31 | localparam FF_L = 256; 32 | 33 | wire ff_empt, ff_full; 34 | reg [FF_B:0] ff_len; 35 | 36 | wire ff_wr, ff_rd; 37 | 38 | reg [FF_B-1:0] wrcnt; 39 | always @(posedge clk) 40 | if (rst) wrcnt <= {FF_B{1'b0}}; 41 | else if (ff_wr) wrcnt <= wrcnt + 1; 42 | 43 | always @(posedge clk) 44 | if (rst) ff_len <= {FF_B+1{1'b0}}; 45 | else 46 | case ({ff_wr, ff_rd}) 47 | 2'b10: ff_len <= ff_len + 1; 48 | 2'b01: ff_len <= ff_len - 1; 49 | default: ff_len <= ff_len; 50 | endcase 51 | 52 | wire [FF_B-1:0] rdcnt; 53 | assign rdcnt = wrcnt - ff_len[FF_B-1:0]; 54 | 55 | wire [FF_B-1:0] rda, wra; 56 | assign rda = ff_rd ? (rdcnt + 1) : rdcnt; 57 | assign wra = wrcnt; 58 | 59 | wire [DAT_B+1:0] ff_wdat; 60 | wire [DAT_B+1:0] ff_rdat; 61 | assign ff_wdat = {i_sop, i_eop, i_dat}; 62 | assign {o_sop, o_eop, o_dat} = ff_rdat; 63 | assign o_rdy = !(ff_len[FF_B] | pktcnt[3]); 64 | assign o_vld = (pktcnt > 0); 65 | 66 | reg [3:0] pktcnt; 67 | assign ff_wr = i_vld & (!(ff_len[FF_B] | pktcnt[3])); 68 | assign ff_rd = i_rdy & (pktcnt > 0); 69 | 70 | /////////////////////////////////////////////////////////////////////////// 71 | //Single dual port RAM 1-clock 72 | 73 | (* ram_style="block" *) 74 | reg [DAT_B+1:0] ram [FF_L-1:0]; 75 | 76 | always @(posedge clk) 77 | if (ff_wr) ram[wra] <= ff_wdat; 78 | 79 | reg [DAT_B+1:0] ff_rdat_m; 80 | always @(posedge clk) 81 | ff_rdat_m <= ram[rda]; 82 | 83 | /////////////////////////////////////////////////////////////////////////// 84 | //same read/write 85 | 86 | wire readsame = ff_wr & (wra == rda); 87 | reg readsame1; 88 | always @(posedge clk) 89 | if (rst) readsame1 <= 1'b0; 90 | else readsame1 <= readsame; 91 | 92 | reg [DAT_B+1:0] ff_wdat1; 93 | always @(posedge clk) 94 | ff_wdat1 <= ff_wdat; 95 | 96 | assign ff_rdat = readsame1 ? ff_wdat1 : ff_rdat_m; 97 | 98 | /////////////////////////////////////////////////////////////////////////// 99 | //Store max 8 packet 100 | 101 | always @(posedge clk) 102 | if (rst) pktcnt <= 4'd0; 103 | else begin 104 | case ({(ff_wr & i_eop), (ff_rd & o_eop)}) 105 | 2'b10: pktcnt <= pktcnt + 1; 106 | 2'b01: pktcnt <= pktcnt - 1; 107 | default: pktcnt <= pktcnt; 108 | endcase 109 | end 110 | 111 | endmodule -------------------------------------------------------------------------------- /litepcie/phy/xilinx_usp/axis_iff.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module axis_iff 7 | #( 8 | parameter DAT_B = 32 9 | ) 10 | ( 11 | input clk, 12 | input rst, 13 | 14 | input i_vld, 15 | output o_rdy, 16 | input i_sop, 17 | input i_eop, 18 | input [DAT_B-1:0] i_dat, 19 | 20 | 21 | output o_vld, 22 | input i_rdy, 23 | output o_sop, 24 | output o_eop, 25 | output [DAT_B-1:0] o_dat 26 | ); 27 | 28 | /////////////////////////////////////////////////////////////////////////// 29 | //FIFO instance 30 | localparam FF_B = 8; 31 | localparam FF_L = 256; 32 | 33 | wire ff_empt, ff_full; 34 | reg [FF_B:0] ff_len; 35 | 36 | wire ff_wr, ff_rd; 37 | 38 | reg [FF_B-1:0] wrcnt; 39 | always @(posedge clk) 40 | if (rst) wrcnt <= {FF_B{1'b0}}; 41 | else if (ff_wr) wrcnt <= wrcnt + 1; 42 | 43 | always @(posedge clk) 44 | if (rst) ff_len <= {FF_B+1{1'b0}}; 45 | else 46 | case ({ff_wr, ff_rd}) 47 | 2'b10: ff_len <= ff_len + 1; 48 | 2'b01: ff_len <= ff_len - 1; 49 | default: ff_len <= ff_len; 50 | endcase 51 | 52 | wire [FF_B-1:0] rdcnt; 53 | assign rdcnt = wrcnt - ff_len[FF_B-1:0]; 54 | 55 | wire [FF_B-1:0] rda, wra; 56 | assign rda = ff_rd ? (rdcnt + 1) : rdcnt; 57 | assign wra = wrcnt; 58 | 59 | wire [DAT_B+1:0] ff_wdat; 60 | wire [DAT_B+1:0] ff_rdat; 61 | assign ff_wdat = {i_sop, i_eop, i_dat}; 62 | assign {o_sop, o_eop, o_dat} = ff_rdat; 63 | assign o_rdy = !(ff_len[FF_B] | pktcnt[3]); 64 | assign o_vld = (pktcnt > 0); 65 | 66 | reg [3:0] pktcnt; 67 | assign ff_wr = i_vld & (!(ff_len[FF_B] | pktcnt[3])); 68 | assign ff_rd = i_rdy & (pktcnt > 0); 69 | 70 | /////////////////////////////////////////////////////////////////////////// 71 | //Single dual port RAM 1-clock 72 | 73 | (* ram_style="block" *) 74 | reg [DAT_B+1:0] ram [FF_L-1:0]; 75 | 76 | always @(posedge clk) 77 | if (ff_wr) ram[wra] <= ff_wdat; 78 | 79 | reg [DAT_B+1:0] ff_rdat_m; 80 | always @(posedge clk) 81 | ff_rdat_m <= ram[rda]; 82 | 83 | /////////////////////////////////////////////////////////////////////////// 84 | //same read/write 85 | 86 | wire readsame = ff_wr & (wra == rda); 87 | reg readsame1; 88 | always @(posedge clk) 89 | if (rst) readsame1 <= 1'b0; 90 | else readsame1 <= readsame; 91 | 92 | reg [DAT_B+1:0] ff_wdat1; 93 | always @(posedge clk) 94 | ff_wdat1 <= ff_wdat; 95 | 96 | assign ff_rdat = readsame1 ? ff_wdat1 : ff_rdat_m; 97 | 98 | /////////////////////////////////////////////////////////////////////////// 99 | //Store max 8 packet 100 | 101 | always @(posedge clk) 102 | if (rst) pktcnt <= 4'd0; 103 | else begin 104 | case ({(ff_wr & i_eop), (ff_rd & o_eop)}) 105 | 2'b10: pktcnt <= pktcnt + 1; 106 | 2'b01: pktcnt <= pktcnt - 1; 107 | default: pktcnt <= pktcnt; 108 | endcase 109 | end 110 | 111 | endmodule -------------------------------------------------------------------------------- /litepcie/software/kernel/config.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause 2 | * 3 | * LitePCIe driver 4 | * 5 | * This file is part of LitePCIe. 6 | * 7 | * Copyright (C) 2018-2024 / EnjoyDigital / florent@enjoy-digital.fr 8 | * 9 | */ 10 | 11 | #ifndef __HW_CONFIG_H 12 | #define __HW_CONFIG_H 13 | #include "soc.h" 14 | 15 | /* PCIe PHY Vendor IDs */ 16 | 17 | #define PCIE_XILINX_VENDOR_ID 0x10ee 18 | #define PCIE_LATTICE_VENDOR_ID 0x1204 19 | #define PCIE_GOWIN_VENDOR_ID 0x22c2 20 | 21 | /* PCIe PHY Device IDs */ 22 | 23 | /* Xilinx */ 24 | #define PCIE_XILINX_DEVICE_ID_S7_GEN2_X1 0x7021 25 | #define PCIE_XILINX_DEVICE_ID_S7_GEN2_X2 0x7022 26 | #define PCIE_XILINX_DEVICE_ID_S7_GEN2_X4 0x7024 27 | #define PCIE_XILINX_DEVICE_ID_S7_GEN2_X8 0x7028 28 | 29 | #define PCIE_XILINX_DEVICE_ID_US_GEN2_X1 0x8021 30 | #define PCIE_XILINX_DEVICE_ID_US_GEN2_X2 0x8022 31 | #define PCIE_XILINX_DEVICE_ID_US_GEN2_X4 0x8024 32 | #define PCIE_XILINX_DEVICE_ID_US_GEN2_X8 0x8028 33 | 34 | #define PCIE_XILINX_DEVICE_ID_US_GEN3_X1 0x8031 35 | #define PCIE_XILINX_DEVICE_ID_US_GEN3_X2 0x8032 36 | #define PCIE_XILINX_DEVICE_ID_US_GEN3_X4 0x8034 37 | #define PCIE_XILINX_DEVICE_ID_US_GEN3_X8 0x8038 38 | 39 | #define PCIE_XILINX_DEVICE_ID_USP_GEN2_X1 0x9021 40 | #define PCIE_XILINX_DEVICE_ID_USP_GEN2_X2 0x9022 41 | #define PCIE_XILINX_DEVICE_ID_USP_GEN2_X4 0x9024 42 | #define PCIE_XILINX_DEVICE_ID_USP_GEN2_X8 0x9028 43 | #define PCIE_XILINX_DEVICE_ID_USP_GEN2_X16 0x902f 44 | 45 | #define PCIE_XILINX_DEVICE_ID_USP_GEN2_X1 0x9021 46 | #define PCIE_XILINX_DEVICE_ID_USP_GEN2_X2 0x9022 47 | #define PCIE_XILINX_DEVICE_ID_USP_GEN2_X4 0x9024 48 | #define PCIE_XILINX_DEVICE_ID_USP_GEN2_X8 0x9028 49 | #define PCIE_XILINX_DEVICE_ID_USP_GEN2_X16 0x902f 50 | 51 | #define PCIE_XILINX_DEVICE_ID_USP_GEN3_X1 0x9031 52 | #define PCIE_XILINX_DEVICE_ID_USP_GEN3_X2 0x9032 53 | #define PCIE_XILINX_DEVICE_ID_USP_GEN3_X4 0x9034 54 | #define PCIE_XILINX_DEVICE_ID_USP_GEN3_X8 0x9038 55 | #define PCIE_XILINX_DEVICE_ID_USP_GEN3_X16 0x903f 56 | 57 | #define PCIE_XILINX_DEVICE_ID_USP_GEN4_X1 0x9041 58 | #define PCIE_XILINX_DEVICE_ID_USP_GEN4_X2 0x9042 59 | #define PCIE_XILINX_DEVICE_ID_USP_GEN4_X4 0x9044 60 | #define PCIE_XILINX_DEVICE_ID_USP_GEN4_X8 0x9048 61 | 62 | /* Lattice */ 63 | 64 | #define PCIE_LATTICE_DEVICE_ID_CPNX_GEN3_X4 0x9c25 65 | 66 | /* Gowin */ 67 | 68 | #define PCIE_GOWIN_DEVICE_ID_GW5AT_GEN2_X4 0x1100 69 | 70 | /* /!\ Keep in sync with csr.h /!\ */ 71 | 72 | /* DMA Flags */ 73 | #define DMA_IRQ_DISABLE (1<<24) 74 | #define DMA_LAST_DISABLE (1<<25) 75 | 76 | #define DMA_CHANNEL_COUNT DMA_CHANNELS 77 | #define DMA_BUFFER_PER_IRQ 32 78 | #define DMA_BUFFER_COUNT 256 79 | #define DMA_BUFFER_SIZE 8192 80 | #define DMA_BUFFER_TOTAL_SIZE (DMA_BUFFER_COUNT*DMA_BUFFER_SIZE) 81 | //#define DMA_BUFFER_ALIGNED 82 | 83 | /* DMA Offsets */ 84 | #define PCIE_DMA_WRITER_ENABLE_OFFSET 0x0000 85 | #define PCIE_DMA_WRITER_TABLE_VALUE_OFFSET 0x0004 86 | #define PCIE_DMA_WRITER_TABLE_WE_OFFSET 0x000c 87 | #define PCIE_DMA_WRITER_TABLE_LOOP_PROG_N_OFFSET 0x0010 88 | #define PCIE_DMA_WRITER_TABLE_LOOP_STATUS_OFFSET 0x0014 89 | #define PCIE_DMA_WRITER_TABLE_LEVEL_OFFSET 0x0018 90 | #define PCIE_DMA_WRITER_TABLE_FLUSH_OFFSET 0x001c 91 | #define PCIE_DMA_READER_ENABLE_OFFSET 0x0020 92 | #define PCIE_DMA_READER_TABLE_VALUE_OFFSET 0x0024 93 | #define PCIE_DMA_READER_TABLE_WE_OFFSET 0x002c 94 | #define PCIE_DMA_READER_TABLE_LOOP_PROG_N_OFFSET 0x0030 95 | #define PCIE_DMA_READER_TABLE_LOOP_STATUS_OFFSET 0x0034 96 | #define PCIE_DMA_READER_TABLE_LEVEL_OFFSET 0x0038 97 | #define PCIE_DMA_READER_TABLE_FLUSH_OFFSET 0x003c 98 | #define PCIE_DMA_LOOPBACK_ENABLE_OFFSET 0x0040 99 | #define PCIE_DMA_BUFFERING_READER_FIFO_DEPTH_ADDR 0x0044 100 | #define PCIE_DMA_BUFFERING_READER_FIFO_LEVEL_ADDR 0x0048 101 | #define PCIE_DMA_BUFFERING_WRITER_FIFO_DEPTH_ADDR 0x004c 102 | #define PCIE_DMA_BUFFERING_WRITER_FIFO_LEVEL_ADDR 0x0050 103 | 104 | /* /!\ Keep in sync with csr.h /!\ */ 105 | 106 | #endif /* __HW_CONFIG_H */ 107 | -------------------------------------------------------------------------------- /litepcie/common.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2015-2023 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | from migen import * 8 | 9 | from litex.gen import * 10 | 11 | from litex.soc.interconnect import stream 12 | from litex.soc.interconnect.stream import * 13 | from litex.soc.interconnect.packet import * 14 | 15 | # Constants/Helpers -------------------------------------------------------------------------------- 16 | 17 | KB = 1024 18 | MB = 1024*KB 19 | GB = 1024*MB 20 | 21 | def get_bar_mask(size): 22 | mask = 0 23 | found = 0 24 | for i in range(32): 25 | if size%2: 26 | found = 1 27 | if found: 28 | mask |= (1 << i) 29 | size = size >> 1 30 | return mask 31 | 32 | # Layouts ------------------------------------------------------------------------------------------ 33 | 34 | def phy_layout(data_width): 35 | layout = [ 36 | ("dat", data_width), 37 | ("be", data_width//8) 38 | ] 39 | return EndpointDescription(layout) 40 | 41 | def configuration_layout(data_width, address_width=32): 42 | layout = [ 43 | # Request Parameters. 44 | ("req_id", 16), # Requester ID. 45 | ("we", 1), # Configuration type; 0 : Read / 1 : Write. 46 | ("bus_number", 8), # Configuration Bus number. 47 | ("device_no", 5), # Configuration Device number. 48 | ("func", 3), # Configuration Function number. 49 | ("ext_reg", 3), # Configuration Extended Register. 50 | ("register_no", 6), # Configuration Register number. 51 | ("tag", 8), # Configuration tag. 52 | 53 | # Data Stream. 54 | ("dat", data_width), 55 | 56 | # Internal LitePCIe Routing/Identification. 57 | ("channel", 8), # Crossbar's channel (Used for internal routing). 58 | ] 59 | return EndpointDescription(layout) 60 | 61 | def request_layout(data_width, address_width=32): 62 | layout = [ 63 | # Request Parameters. 64 | ("req_id", 16), # Requester ID. 65 | ("we", 1), # Request type; 0 : Read / 1 : Write. 66 | ("adr", address_width), # Request address (In Bytes). 67 | ("len", 10), # Request length (In Dwords). 68 | ("tag", 8), # Request tag. 69 | 70 | # Data Stream. 71 | ("dat", data_width), 72 | 73 | # Internal LitePCIe Routing/Identification. 74 | ("channel", 8), # Crossbar's channel (Used for internal routing). 75 | ("user_id", 8), # Packet identification (Used for packet delimitation). 76 | ] 77 | return EndpointDescription(layout) 78 | 79 | def completion_layout(data_width, address_width=32): 80 | layout = [ 81 | # Completion Parameters. 82 | ("req_id", 16), # Requester ID. 83 | ("cmp_id", 16), # Completion ID. 84 | ("adr", address_width), # Completion address (In Bytes). 85 | ("len", 10), # Completion length (In Dwords). 86 | ("end", 1), # Completion end (Current packet is the last). 87 | ("err", 1), # Completion error. 88 | ("tag", 8), # Completion tag. 89 | 90 | # Data Stream. 91 | ("dat", data_width), 92 | 93 | # Internal LitePCIe Routing/Identification. 94 | ("channel", 8), # Crossbar's channel (Used for internal routing). 95 | ("user_id", 8) # Packet identification (Used for packet delimitation). 96 | ] 97 | return EndpointDescription(layout) 98 | 99 | def ptm_layout(data_width): 100 | layout = [ 101 | ("request", 1), # Request. 102 | ("response", 1), # Response. 103 | ("requester_id", 16), # Requester ID. 104 | ("length", 10), # Length. 105 | ("message_code", 8), # Message Code. 106 | ("master_time", 64), # Master Time. 107 | 108 | # Data Stream. 109 | ("dat", data_width), 110 | 111 | # Internal LitePCIe Routing/Identification. 112 | ("channel", 8), # Crossbar's channel (Used for internal routing). 113 | ] 114 | return EndpointDescription(layout) 115 | 116 | 117 | def msi_layout(): 118 | return [("dat", 8)] 119 | 120 | def dma_layout(data_width): 121 | layout = [("data", data_width)] 122 | return EndpointDescription(layout) 123 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | __ _ __ ___ _________ 3 | / / (_) /____ / _ \/ ___/ _/__ 4 | / /__/ / __/ -_) ___/ /___/ // -_) 5 | /____/_/\__/\__/_/ \___/___/\__/ 6 | 7 | Copyright 2015-2024 / EnjoyDigital 8 | 9 | A small footprint and configurable PCIe core 10 | powered by Migen & LiteX 11 | ``` 12 | 13 | [![](https://github.com/enjoy-digital/litepcie/workflows/ci/badge.svg)](https://github.com/enjoy-digital/litepcie/actions) ![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg) 14 | 15 | 16 | [> Intro 17 | -------- 18 | LitePCIe provides a small footprint and configurable PCIe core. 19 | 20 | LitePCIe is part of LiteX libraries whose aims are to lower entry level of 21 | complex FPGA cores by providing simple, elegant and efficient implementations 22 | of components used in today's SoC such as Ethernet, SATA, PCIe, SDRAM Controller... 23 | 24 | Using Migen to describe the HDL allows the core to be highly and easily configurable. 25 | 26 | LitePCIe can be used as LiteX library or can be integrated with your standard 27 | design flow by generating the verilog rtl that you will use as a standard core. 28 | 29 |

30 | 31 | [> Features 32 | ----------- 33 | PHY: 34 | - Xilinx Ultrascale(+) (up to PCIe Gen3 X16). 35 | - Xilinx 7-Series (up to PCIe Gen2 X8). 36 | - Intel Cyclone5 (up to PCIe Gen2 X4). 37 | - 64/128/256/512-bit datapath. 38 | - Clock domain crossing. 39 | 40 | Core: 41 | - TLP layer. 42 | - Reordering. 43 | - MSI (Single, Multi-vector)/MSI-X. 44 | - Crossbar. 45 | 46 | Frontend: 47 | - DMA (with Scatter-Gather). 48 | - MMAP (AXI/Wishbone Slave/Master). 49 | - PTM (on Xilinx 7-Series/Gen2 X1 for now). 50 | 51 | Software: 52 | - Linux Driver (MMAP and DMA). 53 | 54 | [> FPGA Proven 55 | --------------- 56 | LitePCIe is already used in commercial and open-source designs: 57 | - 3G-SDI Capture/Playback board: http://www.enjoy-digital.fr/experience/pcie_3g_sdi.jpg 58 | - SDR MIMO 2x2 board: https://www.amarisoft.com/products-lte-ue-ots-sdr-pcie/#sdr 59 | - SDR MIMO 4x4 board: http://www.enjoy-digital.fr/experience/pcie_ad937x.jpg 60 | - SDR CPRI board: http://www.enjoy-digital.fr/experience/pcie_sfp.jpg 61 | - PCIe TLP sniffer/injector: https://ramtin-amin.fr/#nvmedma 62 | - and others commercial designs... 63 | 64 | [> Possible improvements 65 | ------------------------ 66 | - add standardized interfaces (AXI, Avalon-ST) 67 | - add Intel Stratix support 68 | - add Lattice support 69 | - add more documentation 70 | - ... See below Support and consulting :) 71 | 72 | If you want to support these features, please contact us at florent [AT] 73 | enjoy-digital.fr. 74 | 75 | [> Getting started 76 | ------------------ 77 | 1. Install Python 3.8+ and FPGA vendor's development tools. 78 | 2. Install LiteX and the cores by following the LiteX's wiki [installation guide](https://github.com/enjoy-digital/litex/wiki/Installation). 79 | 3. You can find examples of integration of the core with LiteX in LiteX-Boards and in the examples directory. 80 | 81 | [> Tests 82 | -------- 83 | Unit tests are available in ./test/. 84 | To run all the unit tests: 85 | ```sh 86 | $ ./setup.py test 87 | ``` 88 | 89 | Tests can also be run individually: 90 | ```sh 91 | $ python3 -m unittest test.test_name 92 | ``` 93 | 94 | [> License 95 | ---------- 96 | LitePCIe is released under the very permissive two-clause BSD license. Under 97 | the terms of this license, you are authorized to use LitePCIe for closed-source 98 | proprietary designs. 99 | Even though we do not require you to do so, those things are awesome, so please 100 | do them if possible: 101 | - tell us that you are using LitePCIe 102 | - cite LitePCIe in publications related to research it has helped 103 | - send us feedback and suggestions for improvements 104 | - send us bug reports when something goes wrong 105 | - send us the modifications and improvements you have done to LitePCIe. 106 | 107 | [> Support and consulting 108 | ------------------------- 109 | We love open-source hardware and like sharing our designs with others. 110 | 111 | LitePCIe is developed and maintained by EnjoyDigital. 112 | 113 | If you would like to know more about LitePCIe or if you are already a happy 114 | user and would like to extend it for your needs, EnjoyDigital can provide standard 115 | commercial support as well as consulting services. 116 | 117 | So feel free to contact us, we'd love to work with you! (and eventually shorten 118 | the list of the possible improvements :) 119 | 120 | [> Contact 121 | ---------- 122 | E-mail: florent [AT] enjoy-digital.fr 123 | -------------------------------------------------------------------------------- /litepcie/phy/xilinx_us/s_axis_cc_adapt_256b.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module s_axis_cc_adapt # ( 7 | parameter DATA_WIDTH = 256, 8 | parameter KEEP_WIDTH = DATA_WIDTH/8 9 | )( 10 | 11 | input user_clk, 12 | input user_reset, 13 | 14 | input [DATA_WIDTH-1:0] s_axis_cc_tdata, 15 | input [KEEP_WIDTH-1:0] s_axis_cc_tkeep, 16 | input s_axis_cc_tlast, 17 | output s_axis_cc_tready, 18 | input [3:0] s_axis_cc_tuser, 19 | input s_axis_cc_tvalid, 20 | 21 | output [DATA_WIDTH-1:0] s_axis_cc_tdata_a, 22 | output [KEEP_WIDTH/4-1:0] s_axis_cc_tkeep_a, 23 | output s_axis_cc_tlast_a, 24 | input s_axis_cc_tready_a, 25 | output [32:0] s_axis_cc_tuser_a, 26 | output s_axis_cc_tvalid_a 27 | ); 28 | 29 | wire s_axis_cc_tready_ff, 30 | s_axis_cc_tvalid_ff, 31 | s_axis_cc_tlast_ff; 32 | wire [7:0] s_axis_cc_tkeep_or = {|s_axis_cc_tkeep[31:28], |s_axis_cc_tkeep[27:24], 33 | |s_axis_cc_tkeep[23:20], |s_axis_cc_tkeep[19:16], 34 | |s_axis_cc_tkeep[15:12], |s_axis_cc_tkeep[11:8], 35 | |s_axis_cc_tkeep[7:4], |s_axis_cc_tkeep[3:0]}; 36 | 37 | wire [3:0] s_axis_cc_tuser_ff; 38 | wire [7:0] s_axis_cc_tkeep_ff; 39 | wire [255:0] s_axis_cc_tdata_ff; 40 | 41 | axis_iff #(.DAT_B(256+8+4)) s_axis_cc_iff 42 | ( 43 | .clk (user_clk), 44 | .rst (user_reset), 45 | 46 | .i_vld (s_axis_cc_tvalid), 47 | .o_rdy (s_axis_cc_tready), 48 | .i_sop (1'b0), 49 | .i_eop (s_axis_cc_tlast), 50 | .i_dat ({s_axis_cc_tuser, s_axis_cc_tkeep_or, s_axis_cc_tdata}), 51 | 52 | .o_vld (s_axis_cc_tvalid_ff), 53 | .i_rdy (s_axis_cc_tready_ff), 54 | .o_sop (), 55 | .o_eop (s_axis_cc_tlast_ff), 56 | .o_dat ({s_axis_cc_tuser_ff, s_axis_cc_tkeep_ff, s_axis_cc_tdata_ff}) 57 | ); 58 | 59 | reg [1:0] s_axis_cc_cnt; //0-2 60 | always @(posedge user_clk) 61 | if (user_reset) s_axis_cc_cnt <= 2'd0; 62 | else if (s_axis_cc_tvalid_ff && s_axis_cc_tready_ff) 63 | begin 64 | if (s_axis_cc_tlast_ff) s_axis_cc_cnt <= 2'd0; 65 | else if (!s_axis_cc_cnt[1]) s_axis_cc_cnt <= s_axis_cc_cnt + 1; 66 | end 67 | 68 | wire s_axis_cc_tfirst = s_axis_cc_cnt == 0; 69 | wire s_axis_cc_tsecond = s_axis_cc_cnt == 1; 70 | 71 | wire [6:0] s_axis_cc_lowaddr = s_axis_cc_tdata_ff[70:64]; 72 | wire [1:0] s_axis_cc_at = 2'b0; //address translation 73 | wire [12:0] s_axis_cc_bytecnt = {1'b0, s_axis_cc_tdata_ff[43:32]}; 74 | wire s_axis_cc_lockedrdcmp = (s_axis_cc_tdata_ff[29:24] == 6'b0_01011); //Read-Locked Completion 75 | wire [9:0] s_axis_cc_dwordcnt = s_axis_cc_tdata_ff[9:0]; 76 | wire [2:0] s_axis_cc_cmpstatus = s_axis_cc_tdata_ff[47:45]; 77 | wire s_axis_cc_poison = s_axis_cc_tdata_ff[14]; 78 | wire [15:0] s_axis_cc_requesterid = s_axis_cc_tdata_ff[95:80]; 79 | 80 | wire [7:0] s_axis_cc_tag = s_axis_cc_tdata_ff[79:72]; 81 | wire [15:0] s_axis_cc_completerid = s_axis_cc_tdata_ff[63:48]; 82 | wire s_axis_cc_completerid_en = 1'b0; //must be 0 for End-point 83 | wire [2:0] s_axis_cc_tc = s_axis_cc_tdata_ff[22:20]; 84 | wire [2:0] s_axis_cc_attr = {1'b0, s_axis_cc_tdata_ff[13:12]}; 85 | wire s_axis_cc_td = s_axis_cc_tdata_ff[15] | s_axis_cc_tuser_ff[0]; //ECRC @sop 86 | 87 | 88 | wire [63:0] s_axis_cc_header0 = {s_axis_cc_requesterid, 89 | 2'b0, s_axis_cc_poison, s_axis_cc_cmpstatus, s_axis_cc_dwordcnt, 90 | 2'b0, s_axis_cc_lockedrdcmp, s_axis_cc_bytecnt, 91 | 6'b0, s_axis_cc_at, 92 | 1'b0, s_axis_cc_lowaddr}; 93 | wire [63:0] s_axis_cc_header1 = {s_axis_cc_tdata_ff[127:96], 94 | s_axis_cc_td, s_axis_cc_attr, s_axis_cc_tc, s_axis_cc_completerid_en, 95 | s_axis_cc_completerid, 96 | s_axis_cc_tag 97 | }; 98 | 99 | assign s_axis_cc_tvalid_a = s_axis_cc_tvalid_ff; 100 | 101 | assign s_axis_cc_tready_ff = s_axis_cc_tready_a; 102 | assign s_axis_cc_tdata_a = s_axis_cc_tfirst ? {s_axis_cc_tdata_ff[255:128], s_axis_cc_header1, s_axis_cc_header0} : s_axis_cc_tdata_ff; 103 | assign s_axis_cc_tlast_a = s_axis_cc_tlast_ff; 104 | assign s_axis_cc_tkeep_a = s_axis_cc_tkeep_ff; 105 | assign s_axis_cc_tuser_a = {32'b0, s_axis_cc_tuser_ff[3]}; //{parity, discontinue} 106 | 107 | endmodule -------------------------------------------------------------------------------- /litepcie/phy/xilinx_usp/s_axis_cc_adapt_256b.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module s_axis_cc_adapt # ( 7 | parameter DATA_WIDTH = 256, 8 | parameter KEEP_WIDTH = DATA_WIDTH/8 9 | )( 10 | 11 | input user_clk, 12 | input user_reset, 13 | 14 | input [DATA_WIDTH-1:0] s_axis_cc_tdata, 15 | input [KEEP_WIDTH-1:0] s_axis_cc_tkeep, 16 | input s_axis_cc_tlast, 17 | output s_axis_cc_tready, 18 | input [3:0] s_axis_cc_tuser, 19 | input s_axis_cc_tvalid, 20 | 21 | output [DATA_WIDTH-1:0] s_axis_cc_tdata_a, 22 | output [KEEP_WIDTH/4-1:0] s_axis_cc_tkeep_a, 23 | output s_axis_cc_tlast_a, 24 | input s_axis_cc_tready_a, 25 | output [32:0] s_axis_cc_tuser_a, 26 | output s_axis_cc_tvalid_a 27 | ); 28 | 29 | wire s_axis_cc_tready_ff, 30 | s_axis_cc_tvalid_ff, 31 | s_axis_cc_tlast_ff; 32 | wire [7:0] s_axis_cc_tkeep_or = {|s_axis_cc_tkeep[31:28], |s_axis_cc_tkeep[27:24], 33 | |s_axis_cc_tkeep[23:20], |s_axis_cc_tkeep[19:16], 34 | |s_axis_cc_tkeep[15:12], |s_axis_cc_tkeep[11:8], 35 | |s_axis_cc_tkeep[7:4], |s_axis_cc_tkeep[3:0]}; 36 | 37 | wire [3:0] s_axis_cc_tuser_ff; 38 | wire [7:0] s_axis_cc_tkeep_ff; 39 | wire [255:0] s_axis_cc_tdata_ff; 40 | 41 | axis_iff #(.DAT_B(256+8+4)) s_axis_cc_iff 42 | ( 43 | .clk (user_clk), 44 | .rst (user_reset), 45 | 46 | .i_vld (s_axis_cc_tvalid), 47 | .o_rdy (s_axis_cc_tready), 48 | .i_sop (1'b0), 49 | .i_eop (s_axis_cc_tlast), 50 | .i_dat ({s_axis_cc_tuser, s_axis_cc_tkeep_or, s_axis_cc_tdata}), 51 | 52 | .o_vld (s_axis_cc_tvalid_ff), 53 | .i_rdy (s_axis_cc_tready_ff), 54 | .o_sop (), 55 | .o_eop (s_axis_cc_tlast_ff), 56 | .o_dat ({s_axis_cc_tuser_ff, s_axis_cc_tkeep_ff, s_axis_cc_tdata_ff}) 57 | ); 58 | 59 | reg [1:0] s_axis_cc_cnt; //0-2 60 | always @(posedge user_clk) 61 | if (user_reset) s_axis_cc_cnt <= 2'd0; 62 | else if (s_axis_cc_tvalid_ff && s_axis_cc_tready_ff) 63 | begin 64 | if (s_axis_cc_tlast_ff) s_axis_cc_cnt <= 2'd0; 65 | else if (!s_axis_cc_cnt[1]) s_axis_cc_cnt <= s_axis_cc_cnt + 1; 66 | end 67 | 68 | wire s_axis_cc_tfirst = s_axis_cc_cnt == 0; 69 | wire s_axis_cc_tsecond = s_axis_cc_cnt == 1; 70 | 71 | wire [6:0] s_axis_cc_lowaddr = s_axis_cc_tdata_ff[70:64]; 72 | wire [1:0] s_axis_cc_at = 2'b0; //address translation 73 | wire [12:0] s_axis_cc_bytecnt = {1'b0, s_axis_cc_tdata_ff[43:32]}; 74 | wire s_axis_cc_lockedrdcmp = (s_axis_cc_tdata_ff[29:24] == 6'b0_01011); //Read-Locked Completion 75 | wire [9:0] s_axis_cc_dwordcnt = s_axis_cc_tdata_ff[9:0]; 76 | wire [2:0] s_axis_cc_cmpstatus = s_axis_cc_tdata_ff[47:45]; 77 | wire s_axis_cc_poison = s_axis_cc_tdata_ff[14]; 78 | wire [15:0] s_axis_cc_requesterid = s_axis_cc_tdata_ff[95:80]; 79 | 80 | wire [7:0] s_axis_cc_tag = s_axis_cc_tdata_ff[79:72]; 81 | wire [15:0] s_axis_cc_completerid = s_axis_cc_tdata_ff[63:48]; 82 | wire s_axis_cc_completerid_en = 1'b0; //must be 0 for End-point 83 | wire [2:0] s_axis_cc_tc = s_axis_cc_tdata_ff[22:20]; 84 | wire [2:0] s_axis_cc_attr = {1'b0, s_axis_cc_tdata_ff[13:12]}; 85 | wire s_axis_cc_td = s_axis_cc_tdata_ff[15] | s_axis_cc_tuser_ff[0]; //ECRC @sop 86 | 87 | 88 | wire [63:0] s_axis_cc_header0 = {s_axis_cc_requesterid, 89 | 2'b0, s_axis_cc_poison, s_axis_cc_cmpstatus, s_axis_cc_dwordcnt, 90 | 2'b0, s_axis_cc_lockedrdcmp, s_axis_cc_bytecnt, 91 | 6'b0, s_axis_cc_at, 92 | 1'b0, s_axis_cc_lowaddr}; 93 | wire [63:0] s_axis_cc_header1 = {s_axis_cc_tdata_ff[127:96], 94 | s_axis_cc_td, s_axis_cc_attr, s_axis_cc_tc, s_axis_cc_completerid_en, 95 | s_axis_cc_completerid, 96 | s_axis_cc_tag 97 | }; 98 | 99 | assign s_axis_cc_tvalid_a = s_axis_cc_tvalid_ff; 100 | 101 | assign s_axis_cc_tready_ff = s_axis_cc_tready_a; 102 | assign s_axis_cc_tdata_a = s_axis_cc_tfirst ? {s_axis_cc_tdata_ff[255:128], s_axis_cc_header1, s_axis_cc_header0} : s_axis_cc_tdata_ff; 103 | assign s_axis_cc_tlast_a = s_axis_cc_tlast_ff; 104 | assign s_axis_cc_tkeep_a = s_axis_cc_tkeep_ff; 105 | assign s_axis_cc_tuser_a = {32'b0, s_axis_cc_tuser_ff[3]}; //{parity, discontinue} 106 | 107 | endmodule -------------------------------------------------------------------------------- /test/model/tlp.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2015-2024 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | from litepcie.common import * 8 | from litepcie.tlp.common import * 9 | 10 | 11 | # Helpers/Definitions ------------------------------------------------------------------------------ 12 | 13 | def get_field_data(field, dwords): 14 | return (dwords[field.byte//4] >> field.offset) & (2**field.width-1) 15 | 16 | tlp_headers_dict = { 17 | "RD32": tlp_request_header, 18 | "WR32": tlp_request_header, 19 | "RD64": tlp_request_header, 20 | "WR64": tlp_request_header, 21 | "CPLD": tlp_completion_header, 22 | "CPL": tlp_completion_header 23 | } 24 | 25 | # TLP Layer model ---------------------------------------------------------------------------------- 26 | 27 | class TLP: 28 | def __init__(self, name, dwords, header_dwords=3): 29 | assert header_dwords in [3, 4] 30 | self.name = name 31 | self.header = dwords[:header_dwords] 32 | self.data = dwords[header_dwords:] 33 | self.dwords = self.header + self.data 34 | self.header_dwords = header_dwords 35 | self.decode_dwords() 36 | 37 | def decode_dwords(self): 38 | for k, v in tlp_headers_dict[self.name].fields.items(): 39 | setattr(self, k, get_field_data(v, self.header)) 40 | 41 | def encode_dwords(self, data=[]): 42 | self.header = [0]*self.header_dwords 43 | for k, v in tlp_headers_dict[self.name].fields.items(): 44 | field = tlp_headers_dict[self.name].fields[k] 45 | self.header[field.byte//4] |= (getattr(self, k) << field.offset) 46 | self.data = data 47 | self.dwords = self.header + self.data 48 | return self.dwords 49 | 50 | def __repr__(self): 51 | r = self.name + "\n" 52 | r += "--------\n" 53 | for k in sorted(tlp_headers_dict[self.name].fields.keys()): 54 | r += k + " : 0x{:x}".format(getattr(self, k)) + "\n" 55 | if len(self.data) != 0: 56 | r += "data:\n" 57 | for d in self.data: 58 | r += "{:08x}\n".format(d) 59 | return r 60 | 61 | # RD32 --------------------------------------------------------------------------------------------- 62 | 63 | class RD32(TLP): 64 | def __init__(self, dwords=[0, 0, 0]): 65 | TLP.__init__(self, "RD32", dwords) 66 | 67 | # WR32 --------------------------------------------------------------------------------------------- 68 | 69 | class WR32(TLP): 70 | def __init__(self, dwords=[0, 0, 0]): 71 | TLP.__init__(self, "WR32", dwords) 72 | 73 | # RD64 --------------------------------------------------------------------------------------------- 74 | 75 | class RD64(TLP): 76 | def __init__(self, dwords=[0, 0, 0, 0]): 77 | _dwords = [d for d in dwords] 78 | _dwords[2] = dwords[3] # FIXME: Swap Address LSB/MSB. 79 | _dwords[3] = dwords[2] # FIXME: Swap Address LSB/MSB. 80 | TLP.__init__(self, "RD64", _dwords, header_dwords=4) 81 | 82 | # WR64 --------------------------------------------------------------------------------------------- 83 | 84 | class WR64(TLP): 85 | def __init__(self, dwords=[0, 0, 0, 0]): 86 | _dwords = [d for d in dwords] 87 | _dwords[2] = dwords[3] # FIXME: Swap Address LSB/MSB. 88 | _dwords[3] = dwords[2] # FIXME: Swap Address LSB/MSB. 89 | TLP.__init__(self, "WR64", _dwords, header_dwords=4) 90 | 91 | # CPLD --------------------------------------------------------------------------------------------- 92 | 93 | class CPLD(TLP): 94 | def __init__(self, dwords=[0, 0, 0]): 95 | TLP.__init__(self, "CPLD", dwords) 96 | 97 | # CPL ---------------------------------------------------------------------------------------------- 98 | 99 | class CPL(TLP): 100 | def __init__(self, dwords=[0, 0, 0]): 101 | TLP.__init__(self, "CPL", dwords) 102 | 103 | # Unknown ------------------------------------------------------------------------------------------ 104 | 105 | class Unknown: 106 | def __repr__(self): 107 | r = "UNKNOWN\n" 108 | return r 109 | 110 | # -------------------------------------------------------------------------------------------------- 111 | 112 | fmt_type_dict = { 113 | fmt_type_dict["mem_rd32"]: (RD32, 3), 114 | fmt_type_dict["mem_wr32"]: (WR32, 4), 115 | fmt_type_dict["mem_rd64"]: (RD64, 4), 116 | fmt_type_dict["mem_wr64"]: (WR64, 5), 117 | fmt_type_dict["cpld"]: (CPLD, 4), 118 | fmt_type_dict["cpl"]: ( CPL, 3), 119 | } 120 | 121 | 122 | def parse_dwords(dwords): 123 | f = get_field_data(tlp_common_header.fields["fmt"], dwords) 124 | t = get_field_data(tlp_common_header.fields["type"], dwords) 125 | fmt_type = (f << 5) | t 126 | try: 127 | tlp, min_len = fmt_type_dict[fmt_type] 128 | if len(dwords) >= min_len: 129 | return tlp(dwords) 130 | else: 131 | return Unknown() 132 | except: 133 | return Unknown() 134 | -------------------------------------------------------------------------------- /litepcie/phy/xilinx_us/m_axis_rc_adapt_128b.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module m_axis_rc_adapt # ( 7 | parameter DATA_WIDTH = 128, 8 | parameter KEEP_WIDTH = DATA_WIDTH/8 9 | )( 10 | 11 | input user_clk, 12 | input user_reset, 13 | 14 | output [DATA_WIDTH-1:0] m_axis_rc_tdata, 15 | output [KEEP_WIDTH-1:0] m_axis_rc_tkeep, 16 | output m_axis_rc_tlast, 17 | input [3:0] m_axis_rc_tready, 18 | output [84:0] m_axis_rc_tuser, 19 | output m_axis_rc_tvalid, 20 | 21 | input [DATA_WIDTH-1:0] m_axis_rc_tdata_a, 22 | input [KEEP_WIDTH/4-1:0] m_axis_rc_tkeep_a, 23 | input m_axis_rc_tlast_a, 24 | output [3:0] m_axis_rc_tready_a, 25 | input [84:0] m_axis_rc_tuser_a, 26 | input m_axis_rc_tvalid_a 27 | ); 28 | 29 | reg [1:0] m_axis_rc_cnt; //0-2 30 | always @(posedge user_clk) 31 | if (user_reset) m_axis_rc_cnt <= 2'd0; 32 | else if (m_axis_rc_tvalid_a && m_axis_rc_tready_a) 33 | begin 34 | if (m_axis_rc_tlast_a) m_axis_rc_cnt <= 2'd0; 35 | else if (!m_axis_rc_cnt[1]) m_axis_rc_cnt <= m_axis_rc_cnt + 1; 36 | end 37 | 38 | wire m_axis_rc_sop = (m_axis_rc_cnt == 0); //m_axis_rc_tuser_a[40] 39 | wire m_axis_rc_second = m_axis_rc_cnt == 1; 40 | 41 | //header process 42 | wire m_axis_rc_poisoning = m_axis_rc_tdata_a[46]; 43 | reg m_axis_rc_poisoning_l; 44 | always @(posedge user_clk) 45 | if (m_axis_rc_tvalid_a && m_axis_rc_sop) 46 | begin 47 | m_axis_rc_poisoning_l <= m_axis_rc_poisoning; 48 | end 49 | 50 | wire [9:0] m_axis_rc_dwlen = m_axis_rc_tdata_a[41:32]; 51 | wire [1:0] m_axis_rc_attr = m_axis_rc_tdata_a[93:92]; 52 | wire m_axis_rc_ep = 1'b0; 53 | wire m_axis_rc_td = 1'b0; 54 | wire [2:0] m_axis_rc_tc = m_axis_rc_tdata_a[91:89]; 55 | wire [4:0] m_axis_rc_type; 56 | wire [2:0] m_axis_rc_fmt; 57 | wire [11:0] m_axis_rc_bytecnt = m_axis_rc_tdata_a[27:16]; 58 | wire m_axis_rc_bmc = 1'b0; 59 | wire [2:0] m_axis_rc_cmpstatus = m_axis_rc_tdata_a[45:43]; 60 | wire [15:0] m_axis_rc_completerid = m_axis_rc_tdata_a[87:72]; 61 | 62 | wire [6:0] m_axis_rc_lowaddr = m_axis_rc_tdata_a[6:0]; 63 | wire [7:0] m_axis_rc_tag = m_axis_rc_tdata_a[71:64]; 64 | wire [15:0] m_axis_rc_requesterid = m_axis_rc_tdata_a[63:48]; 65 | 66 | assign {m_axis_rc_fmt, 67 | m_axis_rc_type} = m_axis_rc_tdata_a[29] ? ((m_axis_rc_bytecnt == 0) ? 8'b000_01011 : //Read-Locked Completion w/o data 68 | 8'b010_01011) : //Read-Locked Completion w/ data 69 | ((m_axis_rc_bytecnt == 0) ? 8'b000_01010 : //Completion w/o data 70 | 8'b010_01010); //Completion w/ data 71 | 72 | wire [63:0] m_axis_rc_header0 = {m_axis_rc_completerid, 73 | m_axis_rc_cmpstatus, 74 | m_axis_rc_bmc, 75 | m_axis_rc_bytecnt, 76 | m_axis_rc_fmt[2:0], m_axis_rc_type, 77 | 1'b0, m_axis_rc_tc, 4'b0, 78 | m_axis_rc_td, m_axis_rc_ep, m_axis_rc_attr, 79 | 2'b0, m_axis_rc_dwlen}; 80 | wire [63:0] m_axis_rc_header1 = {m_axis_rc_tdata_a[127:96], 81 | m_axis_rc_requesterid, 82 | m_axis_rc_tag, 83 | 1'b0, m_axis_rc_lowaddr}; 84 | 85 | assign m_axis_rc_tvalid = m_axis_rc_tvalid_a; 86 | assign m_axis_rc_tready_a = m_axis_rc_tready; 87 | assign m_axis_rc_tlast = m_axis_rc_tlast_a; 88 | assign m_axis_rc_tdata = m_axis_rc_sop ? {m_axis_rc_header1, m_axis_rc_header0} : m_axis_rc_tdata_a; 89 | assign m_axis_rc_tkeep = m_axis_rc_sop ? 16'hFFFF : m_axis_rc_tuser_a[15:0]; 90 | assign m_axis_rc_tuser = { 91 | 5'd0, //m_axis_rc_tlast_a, 4'b0, //rx_is_eof only for 128-bit I/F 92 | 2'b0, //reserved 93 | m_axis_rc_sop, 4'b0, //m_axis_rc_tuser_a[32],4'b0, //rx_is_sof, only for 128-bit I/F ????????????????????? 94 | 8'b0, //BAR hit no equivalent for RC 95 | m_axis_rc_sop ? m_axis_rc_poisoning : m_axis_rc_poisoning_l, //rx_err_fwd mapped to Poisoned completion 96 | m_axis_rc_tuser_a[42] //ECRC mapped to discontinue 97 | }; 98 | 99 | endmodule -------------------------------------------------------------------------------- /litepcie/phy/xilinx_usp/m_axis_rc_adapt_128b.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module m_axis_rc_adapt # ( 7 | parameter DATA_WIDTH = 128, 8 | parameter KEEP_WIDTH = DATA_WIDTH/8 9 | )( 10 | 11 | input user_clk, 12 | input user_reset, 13 | 14 | output [DATA_WIDTH-1:0] m_axis_rc_tdata, 15 | output [KEEP_WIDTH-1:0] m_axis_rc_tkeep, 16 | output m_axis_rc_tlast, 17 | input [3:0] m_axis_rc_tready, 18 | output [84:0] m_axis_rc_tuser, 19 | output m_axis_rc_tvalid, 20 | 21 | input [DATA_WIDTH-1:0] m_axis_rc_tdata_a, 22 | input [KEEP_WIDTH/4-1:0] m_axis_rc_tkeep_a, 23 | input m_axis_rc_tlast_a, 24 | output [3:0] m_axis_rc_tready_a, 25 | input [84:0] m_axis_rc_tuser_a, 26 | input m_axis_rc_tvalid_a 27 | ); 28 | 29 | reg [1:0] m_axis_rc_cnt; //0-2 30 | always @(posedge user_clk) 31 | if (user_reset) m_axis_rc_cnt <= 2'd0; 32 | else if (m_axis_rc_tvalid_a && m_axis_rc_tready_a) 33 | begin 34 | if (m_axis_rc_tlast_a) m_axis_rc_cnt <= 2'd0; 35 | else if (!m_axis_rc_cnt[1]) m_axis_rc_cnt <= m_axis_rc_cnt + 1; 36 | end 37 | 38 | wire m_axis_rc_sop = (m_axis_rc_cnt == 0); //m_axis_rc_tuser_a[40] 39 | wire m_axis_rc_second = m_axis_rc_cnt == 1; 40 | 41 | //header process 42 | wire m_axis_rc_poisoning = m_axis_rc_tdata_a[46]; 43 | reg m_axis_rc_poisoning_l; 44 | always @(posedge user_clk) 45 | if (m_axis_rc_tvalid_a && m_axis_rc_sop) 46 | begin 47 | m_axis_rc_poisoning_l <= m_axis_rc_poisoning; 48 | end 49 | 50 | wire [9:0] m_axis_rc_dwlen = m_axis_rc_tdata_a[41:32]; 51 | wire [1:0] m_axis_rc_attr = m_axis_rc_tdata_a[93:92]; 52 | wire m_axis_rc_ep = 1'b0; 53 | wire m_axis_rc_td = 1'b0; 54 | wire [2:0] m_axis_rc_tc = m_axis_rc_tdata_a[91:89]; 55 | wire [4:0] m_axis_rc_type; 56 | wire [2:0] m_axis_rc_fmt; 57 | wire [11:0] m_axis_rc_bytecnt = m_axis_rc_tdata_a[27:16]; 58 | wire m_axis_rc_bmc = 1'b0; 59 | wire [2:0] m_axis_rc_cmpstatus = m_axis_rc_tdata_a[45:43]; 60 | wire [15:0] m_axis_rc_completerid = m_axis_rc_tdata_a[87:72]; 61 | 62 | wire [6:0] m_axis_rc_lowaddr = m_axis_rc_tdata_a[6:0]; 63 | wire [7:0] m_axis_rc_tag = m_axis_rc_tdata_a[71:64]; 64 | wire [15:0] m_axis_rc_requesterid = m_axis_rc_tdata_a[63:48]; 65 | 66 | assign {m_axis_rc_fmt, 67 | m_axis_rc_type} = m_axis_rc_tdata_a[29] ? ((m_axis_rc_bytecnt == 0) ? 8'b000_01011 : //Read-Locked Completion w/o data 68 | 8'b010_01011) : //Read-Locked Completion w/ data 69 | ((m_axis_rc_bytecnt == 0) ? 8'b000_01010 : //Completion w/o data 70 | 8'b010_01010); //Completion w/ data 71 | 72 | wire [63:0] m_axis_rc_header0 = {m_axis_rc_completerid, 73 | m_axis_rc_cmpstatus, 74 | m_axis_rc_bmc, 75 | m_axis_rc_bytecnt, 76 | m_axis_rc_fmt[2:0], m_axis_rc_type, 77 | 1'b0, m_axis_rc_tc, 4'b0, 78 | m_axis_rc_td, m_axis_rc_ep, m_axis_rc_attr, 79 | 2'b0, m_axis_rc_dwlen}; 80 | wire [63:0] m_axis_rc_header1 = {m_axis_rc_tdata_a[127:96], 81 | m_axis_rc_requesterid, 82 | m_axis_rc_tag, 83 | 1'b0, m_axis_rc_lowaddr}; 84 | 85 | assign m_axis_rc_tvalid = m_axis_rc_tvalid_a; 86 | assign m_axis_rc_tready_a = m_axis_rc_tready; 87 | assign m_axis_rc_tlast = m_axis_rc_tlast_a; 88 | assign m_axis_rc_tdata = m_axis_rc_sop ? {m_axis_rc_header1, m_axis_rc_header0} : m_axis_rc_tdata_a; 89 | assign m_axis_rc_tkeep = m_axis_rc_sop ? 16'hFFFF : m_axis_rc_tuser_a[15:0]; 90 | assign m_axis_rc_tuser = { 91 | 5'd0, //m_axis_rc_tlast_a, 4'b0, //rx_is_eof only for 128-bit I/F 92 | 2'b0, //reserved 93 | m_axis_rc_sop, 4'b0, //m_axis_rc_tuser_a[32],4'b0, //rx_is_sof, only for 128-bit I/F ????????????????????? 94 | 8'b0, //BAR hit no equivalent for RC 95 | m_axis_rc_sop ? m_axis_rc_poisoning : m_axis_rc_poisoning_l, //rx_err_fwd mapped to Poisoned completion 96 | m_axis_rc_tuser_a[42] //ECRC mapped to discontinue 97 | }; 98 | 99 | endmodule -------------------------------------------------------------------------------- /litepcie/phy/xilinx_usp/m_axis_rc_adapt_512b.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module m_axis_rc_adapt # ( 7 | parameter DATA_WIDTH = 512, 8 | parameter KEEP_WIDTH = DATA_WIDTH/8 9 | )( 10 | 11 | input user_clk, 12 | input user_reset, 13 | 14 | output [DATA_WIDTH-1:0] m_axis_rc_tdata, 15 | output [KEEP_WIDTH-1:0] m_axis_rc_tkeep, 16 | output m_axis_rc_tlast, 17 | input [3:0] m_axis_rc_tready, 18 | output [84:0] m_axis_rc_tuser, 19 | output m_axis_rc_tvalid, 20 | 21 | input [DATA_WIDTH-1:0] m_axis_rc_tdata_a, 22 | input [KEEP_WIDTH/4-1:0] m_axis_rc_tkeep_a, 23 | input m_axis_rc_tlast_a, 24 | output [3:0] m_axis_rc_tready_a, 25 | input [84:0] m_axis_rc_tuser_a, 26 | input m_axis_rc_tvalid_a 27 | ); 28 | 29 | reg [1:0] m_axis_rc_cnt; //0-2 30 | always @(posedge user_clk) 31 | if (user_reset) m_axis_rc_cnt <= 2'd0; 32 | else if (m_axis_rc_tvalid_a && m_axis_rc_tready_a) 33 | begin 34 | if (m_axis_rc_tlast_a) m_axis_rc_cnt <= 2'd0; 35 | else if (!m_axis_rc_cnt[1]) m_axis_rc_cnt <= m_axis_rc_cnt + 1; 36 | end 37 | 38 | wire m_axis_rc_sop = (m_axis_rc_cnt == 0); //m_axis_rc_tuser_a[40] 39 | wire m_axis_rc_second = m_axis_rc_cnt == 1; 40 | 41 | //header process 42 | wire m_axis_rc_poisoning = m_axis_rc_tdata_a[46]; 43 | reg m_axis_rc_poisoning_l; 44 | always @(posedge user_clk) 45 | if (m_axis_rc_tvalid_a && m_axis_rc_sop) 46 | begin 47 | m_axis_rc_poisoning_l <= m_axis_rc_poisoning; 48 | end 49 | 50 | wire [9:0] m_axis_rc_dwlen = m_axis_rc_tdata_a[41:32]; 51 | wire [1:0] m_axis_rc_attr = m_axis_rc_tdata_a[93:92]; 52 | wire m_axis_rc_ep = 1'b0; 53 | wire m_axis_rc_td = 1'b0; 54 | wire [2:0] m_axis_rc_tc = m_axis_rc_tdata_a[91:89]; 55 | wire [4:0] m_axis_rc_type; 56 | wire [2:0] m_axis_rc_fmt; 57 | wire [11:0] m_axis_rc_bytecnt = m_axis_rc_tdata_a[27:16]; 58 | wire m_axis_rc_bmc = 1'b0; 59 | wire [2:0] m_axis_rc_cmpstatus = m_axis_rc_tdata_a[45:43]; 60 | wire [15:0] m_axis_rc_completerid = m_axis_rc_tdata_a[87:72]; 61 | 62 | wire [6:0] m_axis_rc_lowaddr = m_axis_rc_tdata_a[6:0]; 63 | wire [7:0] m_axis_rc_tag = m_axis_rc_tdata_a[71:64]; 64 | wire [15:0] m_axis_rc_requesterid = m_axis_rc_tdata_a[63:48]; 65 | 66 | assign {m_axis_rc_fmt, 67 | m_axis_rc_type} = m_axis_rc_tdata_a[29] ? ((m_axis_rc_bytecnt == 0) ? 8'b000_01011 : //Read-Locked Completion w/o data 68 | 8'b010_01011) : //Read-Locked Completion w/ data 69 | ((m_axis_rc_bytecnt == 0) ? 8'b000_01010 : //Completion w/o data 70 | 8'b010_01010); //Completion w/ data 71 | 72 | wire [63:0] m_axis_rc_header0 = {m_axis_rc_completerid, 73 | m_axis_rc_cmpstatus, 74 | m_axis_rc_bmc, 75 | m_axis_rc_bytecnt, 76 | m_axis_rc_fmt[2:0], m_axis_rc_type, 77 | 1'b0, m_axis_rc_tc, 4'b0, 78 | m_axis_rc_td, m_axis_rc_ep, m_axis_rc_attr, 79 | 2'b0, m_axis_rc_dwlen}; 80 | wire [63:0] m_axis_rc_header1 = {m_axis_rc_tdata_a[127:96], 81 | m_axis_rc_requesterid, 82 | m_axis_rc_tag, 83 | 1'b0, m_axis_rc_lowaddr}; 84 | 85 | assign m_axis_rc_tvalid = m_axis_rc_tvalid_a; 86 | assign m_axis_rc_tready_a = m_axis_rc_tready; 87 | assign m_axis_rc_tlast = m_axis_rc_tlast_a; 88 | assign m_axis_rc_tdata = m_axis_rc_sop ? {m_axis_rc_tdata_a[511:128], m_axis_rc_header1, m_axis_rc_header0} : m_axis_rc_tdata_a; 89 | assign m_axis_rc_tkeep = m_axis_rc_sop ? {m_axis_rc_tuser_a[63:12], 12'hFFF} : m_axis_rc_tuser_a[63:0]; 90 | assign m_axis_rc_tuser = { 91 | 5'b0, //rx_is_eof only for 128-bit I/F 92 | 2'b0, //reserved 93 | 5'b0, //m_axis_rc_tuser_a[32],4'b0, //rx_is_sof, only for 128-bit I/F ????????????????????? 94 | 8'b0, //BAR hit no equivalent for RC 95 | m_axis_rc_sop ? m_axis_rc_poisoning : m_axis_rc_poisoning_l, //rx_err_fwd mapped to Poisoned completion 96 | m_axis_rc_tuser_a[42] //ECRC mapped to discontinue 97 | }; 98 | 99 | endmodule -------------------------------------------------------------------------------- /litepcie/phy/xilinx_us/m_axis_rc_adapt_256b.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module m_axis_rc_adapt # ( 7 | parameter DATA_WIDTH = 256, 8 | parameter KEEP_WIDTH = DATA_WIDTH/8 9 | )( 10 | 11 | input user_clk, 12 | input user_reset, 13 | 14 | output [DATA_WIDTH-1:0] m_axis_rc_tdata, 15 | output [KEEP_WIDTH-1:0] m_axis_rc_tkeep, 16 | output m_axis_rc_tlast, 17 | input [3:0] m_axis_rc_tready, 18 | output [84:0] m_axis_rc_tuser, 19 | output m_axis_rc_tvalid, 20 | 21 | input [DATA_WIDTH-1:0] m_axis_rc_tdata_a, 22 | input [KEEP_WIDTH/4-1:0] m_axis_rc_tkeep_a, 23 | input m_axis_rc_tlast_a, 24 | output [3:0] m_axis_rc_tready_a, 25 | input [84:0] m_axis_rc_tuser_a, 26 | input m_axis_rc_tvalid_a 27 | ); 28 | 29 | reg [1:0] m_axis_rc_cnt; //0-2 30 | always @(posedge user_clk) 31 | if (user_reset) m_axis_rc_cnt <= 2'd0; 32 | else if (m_axis_rc_tvalid_a && m_axis_rc_tready_a) 33 | begin 34 | if (m_axis_rc_tlast_a) m_axis_rc_cnt <= 2'd0; 35 | else if (!m_axis_rc_cnt[1]) m_axis_rc_cnt <= m_axis_rc_cnt + 1; 36 | end 37 | 38 | wire m_axis_rc_sop = (m_axis_rc_cnt == 0); //m_axis_rc_tuser_a[40] 39 | wire m_axis_rc_second = m_axis_rc_cnt == 1; 40 | 41 | //header process 42 | wire m_axis_rc_poisoning = m_axis_rc_tdata_a[46]; 43 | reg m_axis_rc_poisoning_l; 44 | always @(posedge user_clk) 45 | if (m_axis_rc_tvalid_a && m_axis_rc_sop) 46 | begin 47 | m_axis_rc_poisoning_l <= m_axis_rc_poisoning; 48 | end 49 | 50 | wire [9:0] m_axis_rc_dwlen = m_axis_rc_tdata_a[41:32]; 51 | wire [1:0] m_axis_rc_attr = m_axis_rc_tdata_a[93:92]; 52 | wire m_axis_rc_ep = 1'b0; 53 | wire m_axis_rc_td = 1'b0; 54 | wire [2:0] m_axis_rc_tc = m_axis_rc_tdata_a[91:89]; 55 | wire [4:0] m_axis_rc_type; 56 | wire [2:0] m_axis_rc_fmt; 57 | wire [11:0] m_axis_rc_bytecnt = m_axis_rc_tdata_a[27:16]; 58 | wire m_axis_rc_bmc = 1'b0; 59 | wire [2:0] m_axis_rc_cmpstatus = m_axis_rc_tdata_a[45:43]; 60 | wire [15:0] m_axis_rc_completerid = m_axis_rc_tdata_a[87:72]; 61 | 62 | wire [6:0] m_axis_rc_lowaddr = m_axis_rc_tdata_a[6:0]; 63 | wire [7:0] m_axis_rc_tag = m_axis_rc_tdata_a[71:64]; 64 | wire [15:0] m_axis_rc_requesterid = m_axis_rc_tdata_a[63:48]; 65 | 66 | assign {m_axis_rc_fmt, 67 | m_axis_rc_type} = m_axis_rc_tdata_a[29] ? ((m_axis_rc_bytecnt == 0) ? 8'b000_01011 : //Read-Locked Completion w/o data 68 | 8'b010_01011) : //Read-Locked Completion w/ data 69 | ((m_axis_rc_bytecnt == 0) ? 8'b000_01010 : //Completion w/o data 70 | 8'b010_01010); //Completion w/ data 71 | 72 | wire [63:0] m_axis_rc_header0 = {m_axis_rc_completerid, 73 | m_axis_rc_cmpstatus, 74 | m_axis_rc_bmc, 75 | m_axis_rc_bytecnt, 76 | m_axis_rc_fmt[2:0], m_axis_rc_type, 77 | 1'b0, m_axis_rc_tc, 4'b0, 78 | m_axis_rc_td, m_axis_rc_ep, m_axis_rc_attr, 79 | 2'b0, m_axis_rc_dwlen}; 80 | wire [63:0] m_axis_rc_header1 = {m_axis_rc_tdata_a[127:96], 81 | m_axis_rc_requesterid, 82 | m_axis_rc_tag, 83 | 1'b0, m_axis_rc_lowaddr}; 84 | 85 | assign m_axis_rc_tvalid = m_axis_rc_tvalid_a; 86 | assign m_axis_rc_tready_a = m_axis_rc_tready; 87 | assign m_axis_rc_tlast = m_axis_rc_tlast_a; 88 | assign m_axis_rc_tdata = m_axis_rc_sop ? {m_axis_rc_tdata_a[255:128], m_axis_rc_header1, m_axis_rc_header0} : m_axis_rc_tdata_a; 89 | assign m_axis_rc_tkeep = m_axis_rc_sop ? {m_axis_rc_tuser_a[31:12], 12'hFFF} : m_axis_rc_tuser_a[31:0]; 90 | assign m_axis_rc_tuser = { 91 | 5'b0, //rx_is_eof only for 128-bit I/F 92 | 2'b0, //reserved 93 | 5'b0, //m_axis_rc_tuser_a[32],4'b0, //rx_is_sof, only for 128-bit I/F ????????????????????? 94 | 8'b0, //BAR hit no equivalent for RC 95 | m_axis_rc_sop ? m_axis_rc_poisoning : m_axis_rc_poisoning_l, //rx_err_fwd mapped to Poisoned completion 96 | m_axis_rc_tuser_a[42] //ECRC mapped to discontinue 97 | }; 98 | 99 | 100 | endmodule -------------------------------------------------------------------------------- /litepcie/phy/xilinx_usp/m_axis_rc_adapt_256b.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module m_axis_rc_adapt # ( 7 | parameter DATA_WIDTH = 256, 8 | parameter KEEP_WIDTH = DATA_WIDTH/8 9 | )( 10 | 11 | input user_clk, 12 | input user_reset, 13 | 14 | output [DATA_WIDTH-1:0] m_axis_rc_tdata, 15 | output [KEEP_WIDTH-1:0] m_axis_rc_tkeep, 16 | output m_axis_rc_tlast, 17 | input [3:0] m_axis_rc_tready, 18 | output [84:0] m_axis_rc_tuser, 19 | output m_axis_rc_tvalid, 20 | 21 | input [DATA_WIDTH-1:0] m_axis_rc_tdata_a, 22 | input [KEEP_WIDTH/4-1:0] m_axis_rc_tkeep_a, 23 | input m_axis_rc_tlast_a, 24 | output [3:0] m_axis_rc_tready_a, 25 | input [84:0] m_axis_rc_tuser_a, 26 | input m_axis_rc_tvalid_a 27 | ); 28 | 29 | reg [1:0] m_axis_rc_cnt; //0-2 30 | always @(posedge user_clk) 31 | if (user_reset) m_axis_rc_cnt <= 2'd0; 32 | else if (m_axis_rc_tvalid_a && m_axis_rc_tready_a) 33 | begin 34 | if (m_axis_rc_tlast_a) m_axis_rc_cnt <= 2'd0; 35 | else if (!m_axis_rc_cnt[1]) m_axis_rc_cnt <= m_axis_rc_cnt + 1; 36 | end 37 | 38 | wire m_axis_rc_sop = (m_axis_rc_cnt == 0); //m_axis_rc_tuser_a[40] 39 | wire m_axis_rc_second = m_axis_rc_cnt == 1; 40 | 41 | //header process 42 | wire m_axis_rc_poisoning = m_axis_rc_tdata_a[46]; 43 | reg m_axis_rc_poisoning_l; 44 | always @(posedge user_clk) 45 | if (m_axis_rc_tvalid_a && m_axis_rc_sop) 46 | begin 47 | m_axis_rc_poisoning_l <= m_axis_rc_poisoning; 48 | end 49 | 50 | wire [9:0] m_axis_rc_dwlen = m_axis_rc_tdata_a[41:32]; 51 | wire [1:0] m_axis_rc_attr = m_axis_rc_tdata_a[93:92]; 52 | wire m_axis_rc_ep = 1'b0; 53 | wire m_axis_rc_td = 1'b0; 54 | wire [2:0] m_axis_rc_tc = m_axis_rc_tdata_a[91:89]; 55 | wire [4:0] m_axis_rc_type; 56 | wire [2:0] m_axis_rc_fmt; 57 | wire [11:0] m_axis_rc_bytecnt = m_axis_rc_tdata_a[27:16]; 58 | wire m_axis_rc_bmc = 1'b0; 59 | wire [2:0] m_axis_rc_cmpstatus = m_axis_rc_tdata_a[45:43]; 60 | wire [15:0] m_axis_rc_completerid = m_axis_rc_tdata_a[87:72]; 61 | 62 | wire [6:0] m_axis_rc_lowaddr = m_axis_rc_tdata_a[6:0]; 63 | wire [7:0] m_axis_rc_tag = m_axis_rc_tdata_a[71:64]; 64 | wire [15:0] m_axis_rc_requesterid = m_axis_rc_tdata_a[63:48]; 65 | 66 | assign {m_axis_rc_fmt, 67 | m_axis_rc_type} = m_axis_rc_tdata_a[29] ? ((m_axis_rc_bytecnt == 0) ? 8'b000_01011 : //Read-Locked Completion w/o data 68 | 8'b010_01011) : //Read-Locked Completion w/ data 69 | ((m_axis_rc_bytecnt == 0) ? 8'b000_01010 : //Completion w/o data 70 | 8'b010_01010); //Completion w/ data 71 | 72 | wire [63:0] m_axis_rc_header0 = {m_axis_rc_completerid, 73 | m_axis_rc_cmpstatus, 74 | m_axis_rc_bmc, 75 | m_axis_rc_bytecnt, 76 | m_axis_rc_fmt[2:0], m_axis_rc_type, 77 | 1'b0, m_axis_rc_tc, 4'b0, 78 | m_axis_rc_td, m_axis_rc_ep, m_axis_rc_attr, 79 | 2'b0, m_axis_rc_dwlen}; 80 | wire [63:0] m_axis_rc_header1 = {m_axis_rc_tdata_a[127:96], 81 | m_axis_rc_requesterid, 82 | m_axis_rc_tag, 83 | 1'b0, m_axis_rc_lowaddr}; 84 | 85 | assign m_axis_rc_tvalid = m_axis_rc_tvalid_a; 86 | assign m_axis_rc_tready_a = m_axis_rc_tready; 87 | assign m_axis_rc_tlast = m_axis_rc_tlast_a; 88 | assign m_axis_rc_tdata = m_axis_rc_sop ? {m_axis_rc_tdata_a[255:128], m_axis_rc_header1, m_axis_rc_header0} : m_axis_rc_tdata_a; 89 | assign m_axis_rc_tkeep = m_axis_rc_sop ? {m_axis_rc_tuser_a[31:12], 12'hFFF} : m_axis_rc_tuser_a[31:0]; 90 | assign m_axis_rc_tuser = { 91 | 5'b0, //rx_is_eof only for 128-bit I/F 92 | 2'b0, //reserved 93 | 5'b0, //m_axis_rc_tuser_a[32],4'b0, //rx_is_sof, only for 128-bit I/F ????????????????????? 94 | 8'b0, //BAR hit no equivalent for RC 95 | m_axis_rc_sop ? m_axis_rc_poisoning : m_axis_rc_poisoning_l, //rx_err_fwd mapped to Poisoned completion 96 | m_axis_rc_tuser_a[42] //ECRC mapped to discontinue 97 | }; 98 | 99 | 100 | endmodule -------------------------------------------------------------------------------- /litepcie/phy/xilinx_us/s_axis_cc_adapt_128b.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module s_axis_cc_adapt # ( 7 | parameter DATA_WIDTH = 128, 8 | parameter KEEP_WIDTH = DATA_WIDTH/8 9 | )( 10 | 11 | input user_clk, 12 | input user_reset, 13 | 14 | input [DATA_WIDTH-1:0] s_axis_cc_tdata, 15 | input [KEEP_WIDTH-1:0] s_axis_cc_tkeep, 16 | input s_axis_cc_tlast, 17 | output s_axis_cc_tready, 18 | input [3:0] s_axis_cc_tuser, 19 | input s_axis_cc_tvalid, 20 | 21 | output [DATA_WIDTH-1:0] s_axis_cc_tdata_a, 22 | output [KEEP_WIDTH/4-1:0] s_axis_cc_tkeep_a, 23 | output s_axis_cc_tlast_a, 24 | input s_axis_cc_tready_a, 25 | output [32:0] s_axis_cc_tuser_a, 26 | output s_axis_cc_tvalid_a 27 | ); 28 | 29 | wire s_axis_cc_tready_ff, 30 | s_axis_cc_tvalid_ff, 31 | s_axis_cc_tlast_ff; 32 | wire [3:0] s_axis_cc_tkeep_or = {|s_axis_cc_tkeep[15:12], |s_axis_cc_tkeep[11:8], 33 | |s_axis_cc_tkeep[7:4], |s_axis_cc_tkeep[3:0]}; 34 | 35 | wire [3:0] s_axis_cc_tuser_ff; 36 | wire [3:0] s_axis_cc_tkeep_ff; 37 | wire [127:0] s_axis_cc_tdata_ff; 38 | 39 | axis_iff #(.DAT_B(128+4+4)) s_axis_cc_iff 40 | ( 41 | .clk (user_clk), 42 | .rst (user_reset), 43 | 44 | .i_vld (s_axis_cc_tvalid), 45 | .o_rdy (s_axis_cc_tready), 46 | .i_sop (1'b0), 47 | .i_eop (s_axis_cc_tlast), 48 | .i_dat ({s_axis_cc_tuser, s_axis_cc_tkeep_or, s_axis_cc_tdata}), 49 | 50 | .o_vld (s_axis_cc_tvalid_ff), 51 | .i_rdy (s_axis_cc_tready_ff), 52 | .o_sop (), 53 | .o_eop (s_axis_cc_tlast_ff), 54 | .o_dat ({s_axis_cc_tuser_ff, s_axis_cc_tkeep_ff, s_axis_cc_tdata_ff}) 55 | ); 56 | 57 | reg [1:0] s_axis_cc_cnt; //0-2 58 | always @(posedge user_clk) 59 | if (user_reset) s_axis_cc_cnt <= 2'd0; 60 | else if (s_axis_cc_tvalid_ff && s_axis_cc_tready_ff) 61 | begin 62 | if (s_axis_cc_tlast_ff) s_axis_cc_cnt <= 2'd0; 63 | else if (!s_axis_cc_cnt[1]) s_axis_cc_cnt <= s_axis_cc_cnt + 1; 64 | end 65 | 66 | wire s_axis_cc_tfirst = s_axis_cc_cnt == 0; 67 | wire s_axis_cc_tsecond = s_axis_cc_cnt == 1; 68 | 69 | wire [6:0] s_axis_cc_lowaddr = s_axis_cc_tdata_ff[70:64]; 70 | wire [1:0] s_axis_cc_at = 2'b0; //address translation 71 | wire [12:0] s_axis_cc_bytecnt = {1'b0, s_axis_cc_tdata_ff[43:32]}; 72 | wire s_axis_cc_lockedrdcmp = (s_axis_cc_tdata_ff[29:24] == 6'b0_01011); //Read-Locked Completion 73 | wire [9:0] s_axis_cc_dwordcnt = s_axis_cc_tdata_ff[9:0]; 74 | wire [2:0] s_axis_cc_cmpstatus = s_axis_cc_tdata_ff[47:45]; 75 | wire s_axis_cc_poison = s_axis_cc_tdata_ff[14]; 76 | wire [15:0] s_axis_cc_requesterid = s_axis_cc_tdata_ff[95:80]; 77 | 78 | wire [7:0] s_axis_cc_tag = s_axis_cc_tdata_ff[79:72]; 79 | wire [15:0] s_axis_cc_completerid = s_axis_cc_tdata_ff[63:48]; 80 | wire s_axis_cc_completerid_en = 1'b0; //must be 0 for End-point 81 | wire [2:0] s_axis_cc_tc = s_axis_cc_tdata_ff[22:20]; 82 | wire [2:0] s_axis_cc_attr = {1'b0, s_axis_cc_tdata_ff[13:12]}; 83 | wire s_axis_cc_td = s_axis_cc_tdata_ff[15] | s_axis_cc_tuser_ff[0]; //ECRC @sop 84 | 85 | 86 | wire [63:0] s_axis_cc_header0 = {s_axis_cc_requesterid, 87 | 2'b0, s_axis_cc_poison, s_axis_cc_cmpstatus, s_axis_cc_dwordcnt, 88 | 2'b0, s_axis_cc_lockedrdcmp, s_axis_cc_bytecnt, 89 | 6'b0, s_axis_cc_at, 90 | 1'b0, s_axis_cc_lowaddr}; 91 | wire [63:0] s_axis_cc_header1 = {s_axis_cc_tdata_ff[127:96], 92 | s_axis_cc_td, s_axis_cc_attr, s_axis_cc_tc, s_axis_cc_completerid_en, 93 | s_axis_cc_completerid, 94 | s_axis_cc_tag 95 | }; 96 | 97 | reg [3:0] s_axis_cc_firstbe; 98 | reg [3:0] s_axis_cc_lastbe; 99 | 100 | reg s_axis_cc_tvalid_ff_lat; 101 | always @(posedge user_clk) 102 | if (user_reset) s_axis_cc_tvalid_ff_lat <= 1'd0; 103 | else if (s_axis_cc_tvalid_ff && s_axis_cc_tready_ff) 104 | begin 105 | if (s_axis_cc_tlast_ff) s_axis_cc_tvalid_ff_lat <= 1'd0; 106 | else if (s_axis_cc_tfirst) s_axis_cc_tvalid_ff_lat <= 1'd1; 107 | end 108 | 109 | assign s_axis_cc_tvalid_a = s_axis_cc_tvalid_ff; 110 | assign s_axis_cc_tready_ff = s_axis_cc_tready_a; 111 | assign s_axis_cc_tdata_a = s_axis_cc_tfirst ? {s_axis_cc_header1, s_axis_cc_header0} : s_axis_cc_tdata_ff; 112 | assign s_axis_cc_tlast_a = s_axis_cc_tlast_ff; 113 | assign s_axis_cc_tkeep_a = s_axis_cc_tkeep_ff; 114 | assign s_axis_cc_tuser_a = {32'b0, s_axis_cc_tuser_ff[3]}; //{parity, discontinue} 115 | 116 | endmodule -------------------------------------------------------------------------------- /litepcie/phy/xilinx_usp/s_axis_cc_adapt_128b.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module s_axis_cc_adapt # ( 7 | parameter DATA_WIDTH = 128, 8 | parameter KEEP_WIDTH = DATA_WIDTH/8 9 | )( 10 | 11 | input user_clk, 12 | input user_reset, 13 | 14 | input [DATA_WIDTH-1:0] s_axis_cc_tdata, 15 | input [KEEP_WIDTH-1:0] s_axis_cc_tkeep, 16 | input s_axis_cc_tlast, 17 | output s_axis_cc_tready, 18 | input [3:0] s_axis_cc_tuser, 19 | input s_axis_cc_tvalid, 20 | 21 | output [DATA_WIDTH-1:0] s_axis_cc_tdata_a, 22 | output [KEEP_WIDTH/4-1:0] s_axis_cc_tkeep_a, 23 | output s_axis_cc_tlast_a, 24 | input s_axis_cc_tready_a, 25 | output [32:0] s_axis_cc_tuser_a, 26 | output s_axis_cc_tvalid_a 27 | ); 28 | 29 | wire s_axis_cc_tready_ff, 30 | s_axis_cc_tvalid_ff, 31 | s_axis_cc_tlast_ff; 32 | wire [3:0] s_axis_cc_tkeep_or = {|s_axis_cc_tkeep[15:12], |s_axis_cc_tkeep[11:8], 33 | |s_axis_cc_tkeep[7:4], |s_axis_cc_tkeep[3:0]}; 34 | 35 | wire [3:0] s_axis_cc_tuser_ff; 36 | wire [3:0] s_axis_cc_tkeep_ff; 37 | wire [127:0] s_axis_cc_tdata_ff; 38 | 39 | axis_iff #(.DAT_B(128+4+4)) s_axis_cc_iff 40 | ( 41 | .clk (user_clk), 42 | .rst (user_reset), 43 | 44 | .i_vld (s_axis_cc_tvalid), 45 | .o_rdy (s_axis_cc_tready), 46 | .i_sop (1'b0), 47 | .i_eop (s_axis_cc_tlast), 48 | .i_dat ({s_axis_cc_tuser, s_axis_cc_tkeep_or, s_axis_cc_tdata}), 49 | 50 | .o_vld (s_axis_cc_tvalid_ff), 51 | .i_rdy (s_axis_cc_tready_ff), 52 | .o_sop (), 53 | .o_eop (s_axis_cc_tlast_ff), 54 | .o_dat ({s_axis_cc_tuser_ff, s_axis_cc_tkeep_ff, s_axis_cc_tdata_ff}) 55 | ); 56 | 57 | reg [1:0] s_axis_cc_cnt; //0-2 58 | always @(posedge user_clk) 59 | if (user_reset) s_axis_cc_cnt <= 2'd0; 60 | else if (s_axis_cc_tvalid_ff && s_axis_cc_tready_ff) 61 | begin 62 | if (s_axis_cc_tlast_ff) s_axis_cc_cnt <= 2'd0; 63 | else if (!s_axis_cc_cnt[1]) s_axis_cc_cnt <= s_axis_cc_cnt + 1; 64 | end 65 | 66 | wire s_axis_cc_tfirst = s_axis_cc_cnt == 0; 67 | wire s_axis_cc_tsecond = s_axis_cc_cnt == 1; 68 | 69 | wire [6:0] s_axis_cc_lowaddr = s_axis_cc_tdata_ff[70:64]; 70 | wire [1:0] s_axis_cc_at = 2'b0; //address translation 71 | wire [12:0] s_axis_cc_bytecnt = {1'b0, s_axis_cc_tdata_ff[43:32]}; 72 | wire s_axis_cc_lockedrdcmp = (s_axis_cc_tdata_ff[29:24] == 6'b0_01011); //Read-Locked Completion 73 | wire [9:0] s_axis_cc_dwordcnt = s_axis_cc_tdata_ff[9:0]; 74 | wire [2:0] s_axis_cc_cmpstatus = s_axis_cc_tdata_ff[47:45]; 75 | wire s_axis_cc_poison = s_axis_cc_tdata_ff[14]; 76 | wire [15:0] s_axis_cc_requesterid = s_axis_cc_tdata_ff[95:80]; 77 | 78 | wire [7:0] s_axis_cc_tag = s_axis_cc_tdata_ff[79:72]; 79 | wire [15:0] s_axis_cc_completerid = s_axis_cc_tdata_ff[63:48]; 80 | wire s_axis_cc_completerid_en = 1'b0; //must be 0 for End-point 81 | wire [2:0] s_axis_cc_tc = s_axis_cc_tdata_ff[22:20]; 82 | wire [2:0] s_axis_cc_attr = {1'b0, s_axis_cc_tdata_ff[13:12]}; 83 | wire s_axis_cc_td = s_axis_cc_tdata_ff[15] | s_axis_cc_tuser_ff[0]; //ECRC @sop 84 | 85 | 86 | wire [63:0] s_axis_cc_header0 = {s_axis_cc_requesterid, 87 | 2'b0, s_axis_cc_poison, s_axis_cc_cmpstatus, s_axis_cc_dwordcnt, 88 | 2'b0, s_axis_cc_lockedrdcmp, s_axis_cc_bytecnt, 89 | 6'b0, s_axis_cc_at, 90 | 1'b0, s_axis_cc_lowaddr}; 91 | wire [63:0] s_axis_cc_header1 = {s_axis_cc_tdata_ff[127:96], 92 | s_axis_cc_td, s_axis_cc_attr, s_axis_cc_tc, s_axis_cc_completerid_en, 93 | s_axis_cc_completerid, 94 | s_axis_cc_tag 95 | }; 96 | 97 | reg [3:0] s_axis_cc_firstbe; 98 | reg [3:0] s_axis_cc_lastbe; 99 | 100 | reg s_axis_cc_tvalid_ff_lat; 101 | always @(posedge user_clk) 102 | if (user_reset) s_axis_cc_tvalid_ff_lat <= 1'd0; 103 | else if (s_axis_cc_tvalid_ff && s_axis_cc_tready_ff) 104 | begin 105 | if (s_axis_cc_tlast_ff) s_axis_cc_tvalid_ff_lat <= 1'd0; 106 | else if (s_axis_cc_tfirst) s_axis_cc_tvalid_ff_lat <= 1'd1; 107 | end 108 | 109 | assign s_axis_cc_tvalid_a = s_axis_cc_tvalid_ff; 110 | assign s_axis_cc_tready_ff = s_axis_cc_tready_a; 111 | assign s_axis_cc_tdata_a = s_axis_cc_tfirst ? {s_axis_cc_header1, s_axis_cc_header0} : s_axis_cc_tdata_ff; 112 | assign s_axis_cc_tlast_a = s_axis_cc_tlast_ff; 113 | assign s_axis_cc_tkeep_a = s_axis_cc_tkeep_ff; 114 | assign s_axis_cc_tuser_a = {32'b0, s_axis_cc_tuser_ff[3]}; //{parity, discontinue} 115 | 116 | endmodule -------------------------------------------------------------------------------- /litepcie/core/endpoint.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2015-2023 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | from migen import * 8 | 9 | from litex.gen import * 10 | 11 | from litex.soc.interconnect.csr import * 12 | 13 | from litepcie.tlp.depacketizer import LitePCIeTLPDepacketizer 14 | from litepcie.tlp.packetizer import LitePCIeTLPPacketizer 15 | from litepcie.core.crossbar import LitePCIeCrossbar 16 | 17 | # LitePCIe Endpoint -------------------------------------------------------------------------------- 18 | 19 | class LitePCIeEndpoint(LiteXModule): 20 | def __init__(self, phy, max_pending_requests=4, address_width=32, endianness="big", 21 | cmp_bufs_buffered = True, 22 | with_ptm = False, 23 | ): 24 | self.phy = phy 25 | self.max_pending_requests = max_pending_requests 26 | 27 | # # # 28 | 29 | # Parameters. 30 | optional_packetizer_capabilities = [] 31 | optional_depacketizer_capabilities = [] 32 | if with_ptm: 33 | optional_packetizer_capabilities = ["PTM"] 34 | optional_depacketizer_capabilities = ["PTM", "CONFIGURATION"] 35 | 36 | # TLP Packetizer / Depacketizer ------------------------------------------------------------ 37 | 38 | if hasattr(phy, "sink") and hasattr(phy, "source"): 39 | # Shared Request/Completion channels 40 | self.depacketizer = depacketizer = LitePCIeTLPDepacketizer( 41 | data_width = phy.data_width, 42 | endianness = endianness, 43 | address_mask = phy.bar0_mask, 44 | capabilities = ["REQUEST", "COMPLETION"] + optional_depacketizer_capabilities, 45 | ) 46 | self.packetizer = packetizer = LitePCIeTLPPacketizer( 47 | data_width = phy.data_width, 48 | endianness = endianness, 49 | address_width = address_width, 50 | capabilities = ["REQUEST", "COMPLETION"] + optional_packetizer_capabilities, 51 | ) 52 | self.comb += [ 53 | phy.source.connect(depacketizer.sink), 54 | packetizer.source.connect(phy.sink) 55 | ] 56 | req_source = depacketizer.req_source 57 | cmp_sink = packetizer.cmp_sink 58 | req_sink = packetizer.req_sink 59 | cmp_source = depacketizer.cmp_source 60 | else: 61 | if with_ptm: 62 | raise NotImplementedError 63 | # Separate Request/Completion channels 64 | self.cmp_depacketizer = cmp_depacketizer = LitePCIeTLPDepacketizer( 65 | data_width = phy.data_width, 66 | endianness = endianness, 67 | address_mask = phy.bar0_mask, 68 | capabilities = ["COMPLETION"], 69 | ) 70 | self.req_depacketizer = req_depacketizer = LitePCIeTLPDepacketizer( 71 | data_width = phy.data_width, 72 | endianness = endianness, 73 | address_mask = phy.bar0_mask, 74 | capabilities = ["REQUEST"], 75 | ) 76 | self.cmp_packetizer = cmp_packetizer = LitePCIeTLPPacketizer( 77 | data_width = phy.data_width, 78 | endianness = endianness, 79 | address_width = address_width, 80 | capabilities = ["COMPLETION"], 81 | ) 82 | self.req_packetizer = req_packetizer = LitePCIeTLPPacketizer( 83 | data_width = phy.data_width, 84 | endianness = endianness, 85 | address_width = address_width, 86 | capabilities = ["REQUEST"], 87 | ) 88 | self.comb += [ 89 | phy.cmp_source.connect(cmp_depacketizer.sink), 90 | phy.req_source.connect(req_depacketizer.sink), 91 | cmp_packetizer.source.connect(phy.cmp_sink), 92 | req_packetizer.source.connect(phy.req_sink), 93 | ] 94 | req_source = req_depacketizer.req_source 95 | cmp_sink = cmp_packetizer.cmp_sink 96 | req_sink = req_packetizer.req_sink 97 | cmp_source = cmp_depacketizer.cmp_source 98 | 99 | # Crossbar --------------------------------------------------------------------------------- 100 | 101 | self.crossbar = crossbar = LitePCIeCrossbar( 102 | data_width = phy.data_width, 103 | address_width = address_width, 104 | max_pending_requests = max_pending_requests, 105 | cmp_bufs_buffered = cmp_bufs_buffered, 106 | ) 107 | 108 | # Slave: HOST initiates the transactions --------------------------------------------------- 109 | 110 | self.comb += [ 111 | req_source.connect(crossbar.phy_slave.sink), 112 | crossbar.phy_slave.source.connect(cmp_sink), 113 | ] 114 | 115 | # Master: FPGA initiates the transactions -------------------------------------------------- 116 | 117 | self.comb += [ 118 | crossbar.phy_master.source.connect(req_sink), 119 | cmp_source.connect(crossbar.phy_master.sink), 120 | ] 121 | -------------------------------------------------------------------------------- /litepcie/phy/xilinx_usp/s_axis_cc_adapt_512b.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module s_axis_cc_adapt # ( 7 | parameter DATA_WIDTH = 512, 8 | parameter KEEP_WIDTH = DATA_WIDTH/8 9 | )( 10 | 11 | input user_clk, 12 | input user_reset, 13 | 14 | input [DATA_WIDTH-1:0] s_axis_cc_tdata, 15 | input [KEEP_WIDTH-1:0] s_axis_cc_tkeep, 16 | input s_axis_cc_tlast, 17 | output s_axis_cc_tready, 18 | input [3:0] s_axis_cc_tuser, 19 | input s_axis_cc_tvalid, 20 | 21 | output [DATA_WIDTH-1:0] s_axis_cc_tdata_a, 22 | output [KEEP_WIDTH/4-1:0] s_axis_cc_tkeep_a, 23 | output s_axis_cc_tlast_a, 24 | input s_axis_cc_tready_a, 25 | output [32:0] s_axis_cc_tuser_a, 26 | output s_axis_cc_tvalid_a 27 | ); 28 | 29 | wire s_axis_cc_tready_ff, 30 | s_axis_cc_tvalid_ff, 31 | s_axis_cc_tlast_ff; 32 | wire [15:0] s_axis_cc_tkeep_or = {s_axis_cc_tkeep[60], s_axis_cc_tkeep[56], 33 | s_axis_cc_tkeep[52], s_axis_cc_tkeep[48], 34 | s_axis_cc_tkeep[44], s_axis_cc_tkeep[40], 35 | s_axis_cc_tkeep[36], s_axis_cc_tkeep[32], 36 | s_axis_cc_tkeep[28], s_axis_cc_tkeep[24], 37 | s_axis_cc_tkeep[20], s_axis_cc_tkeep[16], 38 | s_axis_cc_tkeep[12], s_axis_cc_tkeep[8], 39 | s_axis_cc_tkeep[4], s_axis_cc_tkeep[0]}; 40 | 41 | wire [3:0] s_axis_cc_tuser_ff; 42 | wire [15:0] s_axis_cc_tkeep_ff; 43 | wire [511:0] s_axis_cc_tdata_ff; 44 | 45 | axis_iff #(.DAT_B(512+16+4)) s_axis_cc_iff 46 | ( 47 | .clk (user_clk), 48 | .rst (user_reset), 49 | 50 | .i_vld (s_axis_cc_tvalid), 51 | .o_rdy (s_axis_cc_tready), 52 | .i_sop (1'b0), 53 | .i_eop (s_axis_cc_tlast), 54 | .i_dat ({s_axis_cc_tuser, s_axis_cc_tkeep_or, s_axis_cc_tdata}), 55 | 56 | .o_vld (s_axis_cc_tvalid_ff), 57 | .i_rdy (s_axis_cc_tready_ff), 58 | .o_sop (), 59 | .o_eop (s_axis_cc_tlast_ff), 60 | .o_dat ({s_axis_cc_tuser_ff, s_axis_cc_tkeep_ff, s_axis_cc_tdata_ff}) 61 | ); 62 | 63 | reg [1:0] s_axis_cc_cnt; //0-2 64 | always @(posedge user_clk) 65 | if (user_reset) s_axis_cc_cnt <= 2'd0; 66 | else if (s_axis_cc_tvalid_ff && s_axis_cc_tready_ff) 67 | begin 68 | if (s_axis_cc_tlast_ff) s_axis_cc_cnt <= 2'd0; 69 | else if (!s_axis_cc_cnt[1]) s_axis_cc_cnt <= s_axis_cc_cnt + 1; 70 | end 71 | 72 | wire s_axis_cc_tfirst = s_axis_cc_cnt == 0; 73 | wire s_axis_cc_tsecond = s_axis_cc_cnt == 1; 74 | 75 | wire [6:0] s_axis_cc_lowaddr = s_axis_cc_tdata_ff[70:64]; 76 | wire [1:0] s_axis_cc_at = 2'b0; //address translation 77 | wire [12:0] s_axis_cc_bytecnt = {1'b0, s_axis_cc_tdata_ff[43:32]}; 78 | wire s_axis_cc_lockedrdcmp = (s_axis_cc_tdata_ff[29:24] == 6'b0_01011); //Read-Locked Completion 79 | wire [9:0] s_axis_cc_dwordcnt = s_axis_cc_tdata_ff[9:0]; 80 | wire [2:0] s_axis_cc_cmpstatus = s_axis_cc_tdata_ff[47:45]; 81 | wire s_axis_cc_poison = s_axis_cc_tdata_ff[14]; 82 | wire [15:0] s_axis_cc_requesterid = s_axis_cc_tdata_ff[95:80]; 83 | 84 | wire [7:0] s_axis_cc_tag = s_axis_cc_tdata_ff[79:72]; 85 | wire [15:0] s_axis_cc_completerid = s_axis_cc_tdata_ff[63:48]; 86 | wire s_axis_cc_completerid_en = 1'b0; //must be 0 for End-point 87 | wire [2:0] s_axis_cc_tc = s_axis_cc_tdata_ff[22:20]; 88 | wire [2:0] s_axis_cc_attr = {1'b0, s_axis_cc_tdata_ff[13:12]}; 89 | wire s_axis_cc_td = s_axis_cc_tdata_ff[15] | s_axis_cc_tuser_ff[0]; //ECRC @sop 90 | 91 | 92 | wire [63:0] s_axis_cc_header0 = {s_axis_cc_requesterid, 93 | 2'b0, s_axis_cc_poison, s_axis_cc_cmpstatus, s_axis_cc_dwordcnt, 94 | 2'b0, s_axis_cc_lockedrdcmp, s_axis_cc_bytecnt, 95 | 6'b0, s_axis_cc_at, 96 | 1'b0, s_axis_cc_lowaddr}; 97 | wire [63:0] s_axis_cc_header1 = {s_axis_cc_tdata_ff[127:96], 98 | s_axis_cc_td, s_axis_cc_attr, s_axis_cc_tc, s_axis_cc_completerid_en, 99 | s_axis_cc_completerid, 100 | s_axis_cc_tag 101 | }; 102 | 103 | assign s_axis_cc_tvalid_a = s_axis_cc_tvalid_ff; 104 | 105 | assign s_axis_cc_tready_ff = s_axis_cc_tready_a; 106 | assign s_axis_cc_tdata_a = s_axis_cc_tfirst ? {s_axis_cc_tdata_ff[511:128], s_axis_cc_header1, s_axis_cc_header0} : s_axis_cc_tdata_ff; 107 | assign s_axis_cc_tlast_a = s_axis_cc_tlast_ff; 108 | assign s_axis_cc_tkeep_a = s_axis_cc_tkeep_ff; 109 | assign s_axis_cc_tuser_a = {32'b0, s_axis_cc_tuser_ff[3]}; //{parity, discontinue} 110 | 111 | endmodule -------------------------------------------------------------------------------- /bench/kc705.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # This file is part of LitePCIe. 5 | # 6 | # Copyright (c) 2015-2020 Florent Kermarrec 7 | # SPDX-License-Identifier: BSD-2-Clause 8 | 9 | import os 10 | import argparse 11 | 12 | from migen import * 13 | 14 | from litex.gen import * 15 | 16 | from litex_boards.platforms import xilinx_kc705 17 | 18 | from litex.soc.cores.clock import S7MMCM 19 | from litex.soc.interconnect.csr import * 20 | from litex.soc.integration.soc_core import * 21 | from litex.soc.integration.builder import * 22 | 23 | from litepcie.phy.s7pciephy import S7PCIEPHY 24 | from litepcie.core import LitePCIeEndpoint, LitePCIeMSI 25 | from litepcie.frontend.dma import LitePCIeDMA 26 | from litepcie.frontend.wishbone import LitePCIeWishboneBridge 27 | from litepcie.software import generate_litepcie_software 28 | 29 | # CRG ---------------------------------------------------------------------------------------------- 30 | 31 | class _CRG(LiteXModule): 32 | def __init__(self, platform, sys_clk_freq): 33 | self.cd_sys = ClockDomain() 34 | 35 | # # # 36 | 37 | # PLL 38 | self.pll = pll = S7MMCM(speedgrade=-2) 39 | pll.register_clkin(platform.request("clk200"), 200e6) 40 | pll.create_clkout(self.cd_sys, sys_clk_freq) 41 | 42 | # LitePCIeSoC -------------------------------------------------------------------------------------- 43 | 44 | class LitePCIeSoC(SoCMini): 45 | configs = { 46 | # Gen2 data_width, sys_clk_freq 47 | "gen2:x1": (64, int(125e6)), 48 | "gen2:x4": (128, int(200e6)), 49 | "gen2:x8": (128, int(200e6)), 50 | } 51 | def __init__(self, platform, speed="gen2", nlanes=4): 52 | data_width, sys_clk_freq = self.configs[speed + f":x{nlanes}"] 53 | 54 | # SoCMini ---------------------------------------------------------------------------------- 55 | SoCMini.__init__(self, platform, sys_clk_freq, ident=f"LitePCIe example design on KC705 ({speed}:x{nlanes})") 56 | 57 | # CRG -------------------------------------------------------------------------------------- 58 | self.crg = _CRG(platform, sys_clk_freq) 59 | 60 | # UARTBone --------------------------------------------------------------------------------- 61 | self.add_uartbone() 62 | 63 | # PCIe ------------------------------------------------------------------------------------- 64 | # PHY 65 | self.pcie_phy = S7PCIEPHY(platform, platform.request(f"pcie_x{nlanes}"), 66 | data_width = data_width, 67 | bar0_size = 0x20000, 68 | ) 69 | self.pcie_phy.add_ltssm_tracer() 70 | 71 | # Endpoint 72 | self.pcie_endpoint = LitePCIeEndpoint(self.pcie_phy, 73 | endianness = "big", 74 | max_pending_requests = 8 75 | ) 76 | 77 | # Wishbone bridge 78 | self.pcie_bridge = LitePCIeWishboneBridge(self.pcie_endpoint, 79 | base_address = self.mem_map["csr"]) 80 | self.bus.add_master(master=self.pcie_bridge.wishbone) 81 | 82 | # DMA0 83 | self.pcie_dma0 = LitePCIeDMA(self.pcie_phy, self.pcie_endpoint, 84 | with_buffering = True, buffering_depth=1024, 85 | with_loopback = True) 86 | 87 | # DMA1 88 | self.pcie_dma1 = LitePCIeDMA(self.pcie_phy, self.pcie_endpoint, 89 | with_buffering = True, buffering_depth=1024, 90 | with_loopback = True) 91 | 92 | self.add_constant("DMA_CHANNELS", 2) 93 | self.add_constant("DMA_ADDR_WIDTH", 32) 94 | 95 | # MSI 96 | self.pcie_msi = LitePCIeMSI() 97 | self.comb += self.pcie_msi.source.connect(self.pcie_phy.msi) 98 | self.interrupts = { 99 | "PCIE_DMA0_WRITER": self.pcie_dma0.writer.irq, 100 | "PCIE_DMA0_READER": self.pcie_dma0.reader.irq, 101 | "PCIE_DMA1_WRITER": self.pcie_dma1.writer.irq, 102 | "PCIE_DMA1_READER": self.pcie_dma1.reader.irq, 103 | } 104 | for i, (k, v) in enumerate(sorted(self.interrupts.items())): 105 | self.comb += self.pcie_msi.irqs[i].eq(v) 106 | self.add_constant(k + "_INTERRUPT", i) 107 | 108 | # Build -------------------------------------------------------------------------------------------- 109 | 110 | def main(): 111 | parser = argparse.ArgumentParser(description="LitePCIe SoC on KC705") 112 | parser.add_argument("--build", action="store_true", help="Build bitstream") 113 | parser.add_argument("--driver", action="store_true", help="Generate LitePCIe driver") 114 | parser.add_argument("--load", action="store_true", help="Load bitstream (to SRAM)") 115 | parser.add_argument("--nlanes", default=4, help="PCIe lanes: 1, 4 (default) or 8") 116 | args = parser.parse_args() 117 | 118 | platform = xilinx_kc705.Platform() 119 | soc = LitePCIeSoC(platform, nlanes=int(args.nlanes)) 120 | builder = Builder(soc, output_dir="build/kc705", csr_csv="csr.csv") 121 | builder.build(build_name="kc705", run=args.build) 122 | 123 | if args.driver: 124 | generate_litepcie_software(soc, os.path.join(builder.output_dir, "driver")) 125 | 126 | if args.load: 127 | prog = soc.platform.create_programmer() 128 | prog.load_bitstream(os.path.join(builder.gateware_dir, soc.build_name + ".bit")) 129 | 130 | if __name__ == "__main__": 131 | main() 132 | -------------------------------------------------------------------------------- /bench/test_ltssm_tracer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # This file is part of LitePCIe. 5 | # 6 | # Copyright (c) 2022 Sylvain Munaut 7 | # SPDX-License-Identifier: BSD-2-Clause 8 | 9 | import os 10 | import argparse 11 | import socket 12 | 13 | from litex import RemoteClient 14 | 15 | # PCIe LTSSM Dictionary for Xilinx 7-Series -------------------------------------------------------- 16 | 17 | PCIE_LTSSM_7SERIES = { 18 | 0x00 : "Detect Quiet", 19 | 0x01 : "Detect Quiet", 20 | 0x02 : "Detect Active", 21 | 0x03 : "Detect Active", 22 | 0x04 : "Polling Active", 23 | 0x05 : "Polling Configuration", 24 | 0x06 : "Polling Compliance, Pre_Send_EIOS", 25 | 0x07 : "Polling Compliance, Pre_Timeout", 26 | 0x08 : "Polling Compliance, Send_Pattern", 27 | 0x09 : "Polling Compliance, Post_Send_EIOS", 28 | 0x0A : "Polling Compliance, Post_Timeout", 29 | 0x0B : "Configuration Linkwidth, State 0", 30 | 0x0C : "Configuration Linkwidth, State 1", 31 | 0x0D : "Configuration Linkwidth, Accept 0", 32 | 0x0E : "Configuration Linkwidth, Accept 1", 33 | 0x0F : "Configuration Lanenum Wait", 34 | 0x10 : "Configuration Lanenum, Accept", 35 | 0x11 : "Configuration Complete x1", 36 | 0x12 : "Configuration Complete x2", 37 | 0x13 : "Configuration Complete x4", 38 | 0x14 : "Configuration Complete x8", 39 | 0x15 : "Configuration Idle", 40 | 0x16 : "L0", 41 | 0x17 : "L1 Entry0", 42 | 0x18 : "L1 Entry1", 43 | 0x19 : "L1 Entry2 (also used for the L2/L3 Ready pseudo state)", 44 | 0x1A : "L1 Idle", 45 | 0x1B : "L1 Exit", 46 | 0x1C : "Recovery Rcvrlock", 47 | 0x1D : "Recovery Rcvrcfg", 48 | 0x1E : "Recovery Speed_0", 49 | 0x1F : "Recovery Speed_1", 50 | 0x20 : "Recovery Idle", 51 | 0x21 : "Hot Reset", 52 | 0x22 : "Disabled Entry 0", 53 | 0x23 : "Disabled Entry 1", 54 | 0x24 : "Disabled Entry 2", 55 | 0x25 : "Disabled Idle", 56 | 0x26 : "Root Port, Configuration, Linkwidth State 0", 57 | 0x27 : "Root Port, Configuration, Linkwidth State 1", 58 | 0x28 : "Root Port, Configuration, Linkwidth State 2", 59 | 0x29 : "Root Port, Configuration, Link Width Accept 0", 60 | 0x2A : "Root Port, Configuration, Link Width Accept 1", 61 | 0x2B : "Root Port, Configuration, Lanenum_Wait", 62 | 0x2C : "Root Port, Configuration, Lanenum_Accept", 63 | 0x2D : "Timeout To Detect", 64 | 0x2E : "Loopback Entry0", 65 | 0x2F : "Loopback Entry1", 66 | 0x30 : "Loopback Active0", 67 | 0x31 : "Loopback Exit0", 68 | 0x32 : "Loopback Exit1", 69 | 0x33 : "Loopback Master Entry0", 70 | } 71 | 72 | # PCIe LTSSM Dictionary for Xilinx UltraScale and UltraScale+ -------------------------------------- 73 | 74 | PCIE_LTSSM_ULTRASCALE = { 75 | 0x00 : "Detect.Quiet", 76 | 0x01 : "Detect.Active", 77 | 0x02 : "Polling.Active", 78 | 0x03 : "Polling.Compliance", 79 | 0x04 : "Polling.Configuration", 80 | 0x05 : "Configuration.Linkwidth.Start", 81 | 0x06 : "Configuration.Linkwidth.Accept", 82 | 0x07 : "Configuration.Lanenum.Accept", 83 | 0x08 : "Configuration.Lanenum.Wait", 84 | 0x09 : "Configuration.Complete", 85 | 0x0A : "Configuration.Idle", 86 | 0x0B : "Recovery.RcvrLock", 87 | 0x0C : "Recovery.Speed", 88 | 0x0D : "Recovery.RcvrCfg", 89 | 0x0E : "Recovery.Idle", 90 | 0x10 : "L0", 91 | 0x11 : "Rx_L0s.Entry", 92 | 0x12 : "Rx_L0s.Idle", 93 | 0x13 : "Rx_L0s.FTS", 94 | 0x14 : "Tx_L0s.Entry", 95 | 0x15 : "Tx_L0s.Idle", 96 | 0x16 : "Tx_L0s.FTS", 97 | 0x19 : "L2.Idle", 98 | 0x1A : "L2.TransmitWake", 99 | 0x20 : "Disabled", 100 | 0x21 : "Loopback_Entry_Master", 101 | 0x22 : "Loopback_Active_Master", 102 | 0x23 : "Loopback_Exit_Master", 103 | 0x24 : "Loopback_Entry_Slave", 104 | 0x25 : "Loopback_Active_Slave", 105 | 0x26 : "Loopback_Exit_Slave", 106 | 0x27 : "Hot_Reset", 107 | 0x28 : "Recovery_Equalization_Phase0", 108 | 0x29 : "Recovery_Equalization_Phase1", 109 | 0x2A : "Recovery_Equalization_Phase2", 110 | 0x2B : "Recovery_Equalization_Phase3", 111 | } 112 | 113 | # PCIe LTSSM Tracer -------------------------------------------------------------------------------- 114 | def main(): 115 | parser = argparse.ArgumentParser(description="LitePCIe LTSSM tracer.") 116 | parser.add_argument("--csr-csv", default="csr.csv", help="CSR configuration file") 117 | parser.add_argument("--port", default="1234", help="Host bind port.") 118 | parser.add_argument("--family", default='7series', help="FPGA family.", choices=["7series", "ultrascale"]) 119 | args = parser.parse_args() 120 | 121 | bus = RemoteClient( 122 | csr_csv = args.csr_csv, 123 | port = int(args.port, 0) 124 | ) 125 | bus.open() 126 | 127 | ltssm_dict = { 128 | "7series" : PCIE_LTSSM_7SERIES, 129 | "ultrascale" : PCIE_LTSSM_ULTRASCALE 130 | }[args.family] 131 | 132 | # Read history 133 | while True: 134 | v = bus.regs.pcie_phy_ltssm_tracer_history.read() 135 | 136 | ltssm_new = (v >> 0) & 0x3f 137 | ltssm_old = (v >> 6) & 0x3f 138 | overflow = (v >> 30) & 1 139 | valid = (v >> 31) & 1 140 | if not valid: 141 | break 142 | print(f"[0x{ltssm_old:02x}] {ltssm_dict.get(ltssm_old, 'reserved'):<32s} -> [0x{ltssm_new:02x}] {ltssm_dict.get(ltssm_new, 'reserved'):<32s}{('[Overflow, possible unknown intermediate states]' if overflow else ''):s}") 143 | 144 | if __name__ == "__main__": 145 | main() 146 | -------------------------------------------------------------------------------- /bench/kcu105.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # This file is part of LitePCIe. 5 | # 6 | # Copyright (c) 2020 Florent Kermarrec 7 | # SPDX-License-Identifier: BSD-2-Clause 8 | 9 | import os 10 | import argparse 11 | 12 | from migen import * 13 | 14 | from litex.gen import * 15 | 16 | from litex_boards.platforms import xilinx_kcu105 17 | 18 | from litex.soc.cores.clock import USPLL 19 | from litex.soc.interconnect.csr import * 20 | from litex.soc.integration.soc_core import * 21 | from litex.soc.integration.builder import * 22 | 23 | from litepcie.phy.uspciephy import USPCIEPHY 24 | from litepcie.core import LitePCIeEndpoint, LitePCIeMSI 25 | from litepcie.frontend.dma import LitePCIeDMA 26 | from litepcie.frontend.wishbone import LitePCIeWishboneBridge 27 | from litepcie.software import generate_litepcie_software 28 | 29 | # CRG ---------------------------------------------------------------------------------------------- 30 | 31 | class _CRG(LiteXModule): 32 | def __init__(self, platform, sys_clk_freq): 33 | self.clock_domains.cd_sys = ClockDomain() 34 | 35 | # # # 36 | 37 | # PLL 38 | self.pll = pll = USPLL(speedgrade=-2) 39 | pll.register_clkin(platform.request("clk125"), 125e6) 40 | pll.create_clkout(self.cd_sys, sys_clk_freq) 41 | 42 | # LitePCIeSoC -------------------------------------------------------------------------------------- 43 | 44 | class LitePCIeSoC(SoCMini): 45 | configs = { 46 | # Gen3 data_width, sys_clk_freq 47 | "gen3:x4": (128, int(200e6)), 48 | "gen3:x8": (256, int(200e6)), 49 | } 50 | def __init__(self, platform, speed="gen3", nlanes=4): 51 | data_width, sys_clk_freq = self.configs[speed + f":x{nlanes}"] 52 | 53 | # SoCMini ---------------------------------------------------------------------------------- 54 | SoCMini.__init__(self, platform, sys_clk_freq, ident=f"LitePCIe example design on KCU105 ({speed}:x{nlanes})") 55 | 56 | # CRG -------------------------------------------------------------------------------------- 57 | self.crg = _CRG(platform, sys_clk_freq) 58 | 59 | # UARTBone --------------------------------------------------------------------------------- 60 | self.add_uartbone() 61 | 62 | # PCIe ------------------------------------------------------------------------------------- 63 | # PHY 64 | self.pcie_phy = USPCIEPHY(platform, platform.request(f"pcie_x{nlanes}"), 65 | speed = speed, 66 | data_width = data_width, 67 | bar0_size = 0x20000, 68 | ) 69 | self.pcie_phy.add_ltssm_tracer() 70 | 71 | # Endpoint 72 | self.pcie_endpoint = LitePCIeEndpoint(self.pcie_phy, 73 | endianness = "little", 74 | max_pending_requests = 8 75 | ) 76 | 77 | # Wishbone bridge 78 | self.pcie_bridge = LitePCIeWishboneBridge(self.pcie_endpoint, 79 | base_address = self.mem_map["csr"]) 80 | self.bus.add_master(master=self.pcie_bridge.wishbone) 81 | 82 | # DMA0 83 | self.pcie_dma0 = LitePCIeDMA(self.pcie_phy, self.pcie_endpoint, 84 | with_buffering = True, buffering_depth=1024, 85 | with_loopback = True) 86 | 87 | # DMA1 88 | self.pcie_dma1 = LitePCIeDMA(self.pcie_phy, self.pcie_endpoint, 89 | with_buffering = True, buffering_depth=1024, 90 | with_loopback = True) 91 | 92 | self.add_constant("DMA_CHANNELS", 2) 93 | self.add_constant("DMA_ADDR_WIDTH", 32) 94 | 95 | # MSI 96 | self.pcie_msi = LitePCIeMSI() 97 | self.comb += self.pcie_msi.source.connect(self.pcie_phy.msi) 98 | self.interrupts = { 99 | "PCIE_DMA0_WRITER": self.pcie_dma0.writer.irq, 100 | "PCIE_DMA0_READER": self.pcie_dma0.reader.irq, 101 | "PCIE_DMA1_WRITER": self.pcie_dma1.writer.irq, 102 | "PCIE_DMA1_READER": self.pcie_dma1.reader.irq, 103 | } 104 | for i, (k, v) in enumerate(sorted(self.interrupts.items())): 105 | self.comb += self.pcie_msi.irqs[i].eq(v) 106 | self.add_constant(k + "_INTERRUPT", i) 107 | 108 | # Build -------------------------------------------------------------------------------------------- 109 | 110 | def main(): 111 | parser = argparse.ArgumentParser(description="LitePCIe SoC on KCU105") 112 | parser.add_argument("--build", action="store_true", help="Build bitstream") 113 | parser.add_argument("--driver", action="store_true", help="Generate LitePCIe driver") 114 | parser.add_argument("--load", action="store_true", help="Load bitstream (to SRAM)") 115 | parser.add_argument("--speed", default="gen3", help="PCIe speed: gen3") 116 | parser.add_argument("--nlanes", default=4, help="PCIe lanes: 4 (default) or 8") 117 | args = parser.parse_args() 118 | 119 | platform = xilinx_kcu105.Platform() 120 | soc = LitePCIeSoC(platform, speed=args.speed, nlanes=int(args.nlanes)) 121 | builder = Builder(soc, output_dir="build/kcu105", csr_csv="csr.csv") 122 | builder.build(build_name="kcu105", run=args.build) 123 | 124 | if args.driver: 125 | generate_litepcie_software(soc, os.path.join(builder.output_dir, "driver")) 126 | 127 | if args.load: 128 | prog = soc.platform.create_programmer() 129 | prog.load_bitstream(os.path.join(builder.gateware_dir, soc.build_name + ".bit")) 130 | 131 | if __name__ == "__main__": 132 | main() 133 | -------------------------------------------------------------------------------- /bench/fk33.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # This file is part of LitePCIe. 5 | # 6 | # Copyright (c) 2020 Florent Kermarrec 7 | # SPDX-License-Identifier: BSD-2-Clause 8 | 9 | import os 10 | import argparse 11 | 12 | from migen import * 13 | 14 | from litex.gen import * 15 | 16 | from litex_boards.platforms import sqrl_fk33 17 | 18 | from litex.soc.cores.clock import USPPLL 19 | from litex.soc.interconnect.csr import * 20 | from litex.soc.integration.soc_core import * 21 | from litex.soc.integration.builder import * 22 | 23 | from litepcie.phy.usppciephy import USPHBMPCIEPHY 24 | from litepcie.core import LitePCIeEndpoint, LitePCIeMSI 25 | from litepcie.frontend.dma import LitePCIeDMA 26 | from litepcie.frontend.wishbone import LitePCIeWishboneBridge 27 | from litepcie.software import generate_litepcie_software 28 | 29 | # CRG ---------------------------------------------------------------------------------------------- 30 | 31 | class _CRG(LiteXModule): 32 | def __init__(self, platform, sys_clk_freq): 33 | self.cd_sys = ClockDomain() 34 | 35 | # # # 36 | 37 | # PLL 38 | self.pll = pll = USPPLL(speedgrade=-2) 39 | pll.register_clkin(platform.request("clk200"), 200e6) 40 | pll.create_clkout(self.cd_sys, sys_clk_freq) 41 | 42 | # LitePCIeSoC -------------------------------------------------------------------------------------- 43 | 44 | class LitePCIeSoC(SoCMini): 45 | configs = { 46 | # Gen3 data_width, sys_clk_freq 47 | "gen3:x4" : (128, int(200e6)), 48 | "gen3:x8" : (256, int(200e6)), 49 | "gen3:x16": (512, int(200e6)), 50 | } 51 | def __init__(self, platform, speed="gen3", nlanes=4): 52 | data_width, sys_clk_freq = self.configs[speed + f":x{nlanes}"] 53 | 54 | # SoCMini ---------------------------------------------------------------------------------- 55 | SoCMini.__init__(self, platform, sys_clk_freq, ident=f"LitePCIe example design on FK33 ({speed}:x{nlanes})") 56 | 57 | # CRG -------------------------------------------------------------------------------------- 58 | self.crg = _CRG(platform, sys_clk_freq) 59 | 60 | # JTAGBone --------------------------------------------------------------------------------- 61 | self.add_jtagbone() 62 | 63 | # PCIe ------------------------------------------------------------------------------------- 64 | # PHY 65 | self.pcie_phy = USPHBMPCIEPHY(platform, platform.request(f"pcie_x{nlanes}"), 66 | speed = speed, 67 | data_width = data_width, 68 | bar0_size = 0x20000, 69 | ) 70 | self.pcie_phy.add_ltssm_tracer() 71 | 72 | # Endpoint 73 | self.pcie_endpoint = LitePCIeEndpoint(self.pcie_phy, 74 | endianness = "little", 75 | max_pending_requests = 8 76 | ) 77 | 78 | # Wishbone bridge 79 | self.pcie_bridge = LitePCIeWishboneBridge(self.pcie_endpoint, 80 | base_address = self.mem_map["csr"]) 81 | self.bus.add_master(master=self.pcie_bridge.wishbone) 82 | 83 | # DMA0 84 | self.pcie_dma0 = LitePCIeDMA(self.pcie_phy, self.pcie_endpoint, 85 | with_buffering = True, buffering_depth=1024, 86 | with_loopback = True) 87 | 88 | # DMA1 89 | self.pcie_dma1 = LitePCIeDMA(self.pcie_phy, self.pcie_endpoint, 90 | with_buffering = True, buffering_depth=1024, 91 | with_loopback = True) 92 | 93 | self.add_constant("DMA_CHANNELS", 2) 94 | self.add_constant("DMA_ADDR_WIDTH", 32) 95 | 96 | # MSI 97 | self.pcie_msi = LitePCIeMSI() 98 | self.comb += self.pcie_msi.source.connect(self.pcie_phy.msi) 99 | self.interrupts = { 100 | "PCIE_DMA0_WRITER": self.pcie_dma0.writer.irq, 101 | "PCIE_DMA0_READER": self.pcie_dma0.reader.irq, 102 | "PCIE_DMA1_WRITER": self.pcie_dma1.writer.irq, 103 | "PCIE_DMA1_READER": self.pcie_dma1.reader.irq, 104 | } 105 | for i, (k, v) in enumerate(sorted(self.interrupts.items())): 106 | self.comb += self.pcie_msi.irqs[i].eq(v) 107 | self.add_constant(k + "_INTERRUPT", i) 108 | 109 | # Build -------------------------------------------------------------------------------------------- 110 | 111 | def main(): 112 | parser = argparse.ArgumentParser(description="LitePCIe SoC on FK33") 113 | parser.add_argument("--build", action="store_true", help="Build bitstream") 114 | parser.add_argument("--driver", action="store_true", help="Generate LitePCIe driver") 115 | parser.add_argument("--load", action="store_true", help="Load bitstream (to SRAM)") 116 | parser.add_argument("--speed", default="gen3", help="PCIe speed: gen3") 117 | parser.add_argument("--nlanes", default=4, help="PCIe lanes: 4 (default), 8 or 16") 118 | args = parser.parse_args() 119 | 120 | platform = sqrl_fk33.Platform() 121 | soc = LitePCIeSoC(platform, speed=args.speed, nlanes=int(args.nlanes)) 122 | builder = Builder(soc, output_dir="build/fk33", csr_csv="csr.csv") 123 | builder.build(build_name="fk33", run=args.build) 124 | 125 | if args.driver: 126 | generate_litepcie_software(soc, os.path.join(builder.output_dir, "driver")) 127 | 128 | if args.load: 129 | prog = soc.platform.create_programmer() 130 | prog.load_bitstream(os.path.join(builder.gateware_dir, soc.build_name + ".bit")) 131 | 132 | if __name__ == "__main__": 133 | main() 134 | -------------------------------------------------------------------------------- /bench/xcu1525.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # This file is part of LitePCIe. 5 | # 6 | # Copyright (c) 2020 Florent Kermarrec 7 | # SPDX-License-Identifier: BSD-2-Clause 8 | 9 | import os 10 | import argparse 11 | 12 | from migen import * 13 | 14 | from litex.gen import * 15 | 16 | from litex_boards.platforms import sqrl_xcu1525 17 | 18 | from litex.soc.cores.clock import USPPLL 19 | from litex.soc.interconnect.csr import * 20 | from litex.soc.integration.soc_core import * 21 | from litex.soc.integration.builder import * 22 | 23 | from litepcie.phy.usppciephy import USPPCIEPHY 24 | from litepcie.core import LitePCIeEndpoint, LitePCIeMSI 25 | from litepcie.frontend.dma import LitePCIeDMA 26 | from litepcie.frontend.wishbone import LitePCIeWishboneBridge 27 | from litepcie.software import generate_litepcie_software 28 | 29 | # CRG ---------------------------------------------------------------------------------------------- 30 | 31 | class _CRG(LiteXModule): 32 | def __init__(self, platform, sys_clk_freq): 33 | self.cd_sys = ClockDomain() 34 | 35 | # # # 36 | 37 | # PLL 38 | self.pll = pll = USPPLL(speedgrade=-2) 39 | pll.register_clkin(platform.request("clk300"), 300e6) 40 | pll.create_clkout(self.cd_sys, sys_clk_freq) 41 | 42 | # LitePCIeSoC -------------------------------------------------------------------------------------- 43 | 44 | class LitePCIeSoC(SoCMini): 45 | configs = { 46 | # Gen3 data_width, sys_clk_freq 47 | "gen3:x4" : (128, int(200e6)), 48 | "gen3:x8" : (256, int(200e6)), 49 | "gen3:x16": (512, int(200e6)), 50 | } 51 | def __init__(self, platform, speed="gen3", nlanes=4): 52 | data_width, sys_clk_freq = self.configs[speed + f":x{nlanes}"] 53 | 54 | # SoCMini ---------------------------------------------------------------------------------- 55 | SoCMini.__init__(self, platform, sys_clk_freq, ident=f"LitePCIe example design on XCU1525 ({speed}:x{nlanes})") 56 | 57 | # CRG -------------------------------------------------------------------------------------- 58 | self.crg = _CRG(platform, sys_clk_freq) 59 | 60 | # UARTBone --------------------------------------------------------------------------------- 61 | self.add_uartbone() 62 | 63 | # PCIe ------------------------------------------------------------------------------------- 64 | # PHY 65 | self.pcie_phy = USPPCIEPHY(platform, platform.request(f"pcie_x{nlanes}"), 66 | speed = speed, 67 | data_width = data_width, 68 | bar0_size = 0x20000, 69 | ) 70 | self.pcie_phy.add_ltssm_tracer() 71 | platform.add_false_path_constraints(self.crg.cd_sys.clk, self.pcie_phy.cd_pcie.clk) 72 | 73 | # Endpoint 74 | self.pcie_endpoint = LitePCIeEndpoint(self.pcie_phy, 75 | endianness = "little", 76 | max_pending_requests = 8 77 | ) 78 | 79 | # Wishbone bridge 80 | self.pcie_bridge = LitePCIeWishboneBridge(self.pcie_endpoint, 81 | base_address = self.mem_map["csr"]) 82 | self.bus.add_master(master=self.pcie_bridge.wishbone) 83 | 84 | # DMA0 85 | self.pcie_dma0 = LitePCIeDMA(self.pcie_phy, self.pcie_endpoint, 86 | with_buffering = True, buffering_depth=1024, 87 | with_loopback = True) 88 | 89 | # DMA1 90 | self.pcie_dma1 = LitePCIeDMA(self.pcie_phy, self.pcie_endpoint, 91 | with_buffering = True, buffering_depth=1024, 92 | with_loopback = True) 93 | 94 | self.add_constant("DMA_CHANNELS", 2) 95 | self.add_constant("DMA_ADDR_WIDTH", 32) 96 | 97 | # MSI 98 | self.pcie_msi = LitePCIeMSI() 99 | self.comb += self.pcie_msi.source.connect(self.pcie_phy.msi) 100 | self.interrupts = { 101 | "PCIE_DMA0_WRITER": self.pcie_dma0.writer.irq, 102 | "PCIE_DMA0_READER": self.pcie_dma0.reader.irq, 103 | "PCIE_DMA1_WRITER": self.pcie_dma1.writer.irq, 104 | "PCIE_DMA1_READER": self.pcie_dma1.reader.irq, 105 | } 106 | for i, (k, v) in enumerate(sorted(self.interrupts.items())): 107 | self.comb += self.pcie_msi.irqs[i].eq(v) 108 | self.add_constant(k + "_INTERRUPT", i) 109 | 110 | # Build -------------------------------------------------------------------------------------------- 111 | 112 | def main(): 113 | parser = argparse.ArgumentParser(description="LitePCIe SoC on XCU1525") 114 | parser.add_argument("--build", action="store_true", help="Build bitstream") 115 | parser.add_argument("--driver", action="store_true", help="Generate LitePCIe driver") 116 | parser.add_argument("--load", action="store_true", help="Load bitstream (to SRAM)") 117 | parser.add_argument("--speed", default="gen3", help="PCIe speed: gen3") 118 | parser.add_argument("--nlanes", default=4, help="PCIe lanes: 4 (default), 8 or 16") 119 | args = parser.parse_args() 120 | 121 | platform = sqrl_xcu1525.Platform() 122 | soc = LitePCIeSoC(platform, speed=args.speed, nlanes=int(args.nlanes)) 123 | builder = Builder(soc, output_dir="build/xcu1525", csr_csv="csr.csv") 124 | builder.build(build_name="xcu1525", run=args.build) 125 | 126 | if args.driver: 127 | generate_litepcie_software(soc, os.path.join(builder.output_dir, "driver")) 128 | 129 | if args.load: 130 | prog = soc.platform.create_programmer() 131 | prog.load_bitstream(os.path.join(builder.gateware_dir, soc.build_name + ".bit")) 132 | 133 | if __name__ == "__main__": 134 | main() 135 | -------------------------------------------------------------------------------- /litepcie/frontend/axi.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2020 Antmicro 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | from migen import * 8 | 9 | from litex.gen import * 10 | 11 | from litex.soc.interconnect import axi, stream 12 | 13 | from litepcie.common import * 14 | from litepcie.frontend.dma import descriptor_layout, LitePCIeDMAWriter, LitePCIeDMAReader 15 | 16 | # LitePCIeAXISlave --------------------------------------------------------------------------------- 17 | 18 | class LitePCIeAXISlave(LiteXModule): 19 | def __init__(self, endpoint, data_width=32, id_width=1): 20 | self.axi = axi.AXIInterface(data_width=data_width, id_width=id_width) 21 | 22 | # # # 23 | 24 | aw_id = Signal(id_width) 25 | ar_id = Signal(id_width) 26 | r_len = Signal(8) 27 | 28 | desc_rd = stream.Endpoint(descriptor_layout()) 29 | desc_wr = stream.Endpoint(descriptor_layout()) 30 | 31 | port_rd = endpoint.crossbar.get_master_port(read_only=True) 32 | port_wr = endpoint.crossbar.get_master_port(write_only=True) 33 | 34 | # AXI Write Path --------------------------------------------------------------------------- 35 | 36 | # DMA / FIFO / Converter 37 | self.dma_wr = dma_wr = LitePCIeDMAWriter( 38 | endpoint = endpoint, 39 | port = port_wr, 40 | with_table = False) 41 | self.fifo_wr = fifo_wr = stream.SyncFIFO(descriptor_layout(), 16) 42 | self.conv_wr = conv_wr = stream.Converter(nbits_from=data_width, nbits_to=endpoint.phy.data_width) 43 | 44 | # Flow 45 | self.comb += [ 46 | desc_wr.connect(fifo_wr.sink), 47 | fifo_wr.source.connect(dma_wr.desc_sink), 48 | conv_wr.source.connect(dma_wr.sink), 49 | ] 50 | 51 | # FSM (Convert AXI Write Requests to LitePCIe's DMA Descriptors). 52 | self.comb += desc_wr.address.eq(self.axi.aw.addr) # Start address (byte addressed) 53 | self.comb += desc_wr.length.eq((self.axi.aw.len + 1) * (data_width//8)) # Transfer length (in bytes) 54 | 55 | self.fsm_wr = fsm_wr = FSM(reset_state="WRITE-IDLE") 56 | fsm_wr.act("WRITE-IDLE", 57 | self.axi.aw.ready.eq(desc_wr.ready), 58 | desc_wr.valid.eq(self.axi.aw.valid), 59 | If(self.axi.aw.valid & self.axi.aw.ready, 60 | NextValue(aw_id, self.axi.aw.id), # Save id to use it on b channel. 61 | NextState("WRITE-MONITOR"), 62 | ) 63 | ) 64 | 65 | self.comb += [ 66 | conv_wr.sink.data.eq(self.axi.w.data), 67 | conv_wr.sink.last.eq(self.axi.w.last), 68 | ] 69 | fsm_wr.act("WRITE-MONITOR", 70 | conv_wr.sink.valid.eq(self.axi.w.valid), 71 | self.axi.w.ready.eq(conv_wr.sink.ready), 72 | If(self.axi.w.valid & self.axi.w.ready & self.axi.w.last, 73 | NextState("WRITE-RESP"), 74 | ) 75 | ) 76 | 77 | self.comb += [ 78 | self.axi.b.id.eq(aw_id), 79 | self.axi.b.resp.eq(0), 80 | ] 81 | fsm_wr.act("WRITE-RESP", 82 | self.axi.b.valid.eq(1), 83 | If(self.axi.b.ready, 84 | NextState("WRITE-IDLE"), # Write done 85 | ) 86 | ) 87 | 88 | # AXI Read Path ---------------------------------------------------------------------------- 89 | 90 | # DMA / FIFO / Converter 91 | self.dma_rd = dma_rd = LitePCIeDMAReader( 92 | endpoint = endpoint, 93 | port = port_rd, 94 | with_table = False) 95 | self.fifo_rd = fifo_rd = stream.SyncFIFO(descriptor_layout(), 16) 96 | self.conv_rd = conv_rd = stream.Converter(nbits_from=endpoint.phy.data_width, nbits_to=data_width) 97 | 98 | # Flow 99 | self.comb += [ 100 | desc_rd.connect(fifo_rd.sink), 101 | fifo_rd.source.connect(dma_rd.desc_sink), 102 | dma_rd.source.connect(conv_rd.sink), 103 | ] 104 | 105 | # FSM (Convert AXI Read Requests to LitePCIe's DMA Descriptors). 106 | self.comb += desc_rd.address.eq(self.axi.ar.addr) # Starting address (byte addressed) 107 | self.comb += desc_rd.length.eq((self.axi.ar.len + 1) * (data_width//8)) # Transfer length (in bytes) 108 | 109 | self.fsm_rd = fsm_rd = FSM(reset_state="READ-IDLE") 110 | fsm_rd.act("READ-IDLE", 111 | self.axi.ar.ready.eq(desc_rd.ready), 112 | desc_rd.valid.eq(self.axi.ar.valid), 113 | If(self.axi.ar.valid & self.axi.ar.ready, 114 | NextValue(ar_id, self.axi.ar.id), # Save id to use it on r channel. 115 | NextValue(r_len, self.axi.ar.len), 116 | NextState("READ-MONITOR"), 117 | ) 118 | ) 119 | 120 | self.comb += [ 121 | self.axi.r.data.eq(conv_rd.source.data), 122 | self.axi.r.last.eq(r_len == 0), 123 | # We need to provide the same id that was provided on aw channel for the duration of the transfer. 124 | self.axi.r.id.eq(ar_id), 125 | self.axi.r.resp.eq(0), 126 | ] 127 | fsm_rd.act("READ-MONITOR", 128 | self.axi.r.valid.eq(conv_rd.source.valid), 129 | conv_rd.source.ready.eq(self.axi.r.ready), 130 | If(self.axi.r.ready & self.axi.r.valid, 131 | NextValue(r_len, r_len - 1), 132 | If(self.axi.r.last, # Check if we finished the whole AXI transaction. 133 | NextState("READ-IDLE"), 134 | ) 135 | ) 136 | ) 137 | 138 | -------------------------------------------------------------------------------- /litepcie/phy/xilinx_us/s_axis_rq_adapt_256b.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module s_axis_rq_adapt # ( 7 | parameter DATA_WIDTH = 256, 8 | parameter KEEP_WIDTH = DATA_WIDTH/8 9 | )( 10 | 11 | input user_clk, 12 | input user_reset, 13 | 14 | input [DATA_WIDTH-1:0] s_axis_rq_tdata, 15 | input [KEEP_WIDTH-1:0] s_axis_rq_tkeep, 16 | input s_axis_rq_tlast, 17 | output s_axis_rq_tready, 18 | input [3:0] s_axis_rq_tuser, 19 | input s_axis_rq_tvalid, 20 | 21 | output [DATA_WIDTH-1:0] s_axis_rq_tdata_a, 22 | output [KEEP_WIDTH/4-1:0] s_axis_rq_tkeep_a, 23 | output s_axis_rq_tlast_a, 24 | input s_axis_rq_tready_a, 25 | output [59:0] s_axis_rq_tuser_a, 26 | output s_axis_rq_tvalid_a 27 | ); 28 | 29 | wire [7:0] s_axis_rq_tkeep_or = {s_axis_rq_tkeep[28], s_axis_rq_tkeep[24], s_axis_rq_tkeep[20], s_axis_rq_tkeep[16], 30 | s_axis_rq_tkeep[12], s_axis_rq_tkeep[ 8], s_axis_rq_tkeep[ 4], s_axis_rq_tkeep[ 0]}; 31 | 32 | wire s_axis_rq_tvalid_ff; 33 | wire s_axis_rq_tready_ff; 34 | wire s_axis_rq_tlast_ff; 35 | wire [3:0] s_axis_rq_tuser_ff; 36 | wire [7:0] s_axis_rq_tkeep_ff; 37 | wire [255:0] s_axis_rq_tdata_ff; 38 | 39 | axis_iff #(.DAT_B(256+8+4)) s_axis_rq_iff 40 | ( 41 | .clk (user_clk), 42 | .rst (user_reset), 43 | 44 | .i_vld (s_axis_rq_tvalid), 45 | .o_rdy (s_axis_rq_tready), 46 | .i_sop (1'b0), 47 | .i_eop (s_axis_rq_tlast), 48 | .i_dat ({s_axis_rq_tuser, s_axis_rq_tkeep_or, s_axis_rq_tdata}), 49 | 50 | .o_vld (s_axis_rq_tvalid_ff), 51 | .i_rdy (s_axis_rq_tready_ff), 52 | .o_sop (), 53 | .o_eop (s_axis_rq_tlast_ff), 54 | .o_dat ({s_axis_rq_tuser_ff, s_axis_rq_tkeep_ff, s_axis_rq_tdata_ff}) 55 | ); 56 | 57 | reg s_axis_rq_tfirst_ff; 58 | always @(posedge user_clk) 59 | if (user_reset) begin 60 | s_axis_rq_tfirst_ff <= 1'd1; 61 | end 62 | else if (s_axis_rq_tvalid_ff && s_axis_rq_tready_ff) begin 63 | s_axis_rq_tfirst_ff <= 1'd0; 64 | if (s_axis_rq_tlast_ff) begin 65 | s_axis_rq_tfirst_ff <= 1'd1; 66 | end 67 | end 68 | 69 | assign s_axis_rq_tlast_a = s_axis_rq_tlast_ff; 70 | assign s_axis_rq_tready_ff = s_axis_rq_tready_a; 71 | assign s_axis_rq_tvalid_a = s_axis_rq_tvalid_ff; 72 | 73 | wire [10:0] s_axis_rq_dwlen_ff = {1'b0, s_axis_rq_tdata_ff[9:0]}; 74 | wire [3:0] s_axis_rq_reqtype_ff = 75 | {s_axis_rq_tdata_ff[31:30], s_axis_rq_tdata_ff[28:24]} == 7'b0000000 ? 4'b0000 : // Mem Read request. 76 | {s_axis_rq_tdata_ff[31:30], s_axis_rq_tdata_ff[28:24]} == 7'b0000001 ? 4'b0111 : // Mem Read request-locked 77 | {s_axis_rq_tdata_ff[31:30], s_axis_rq_tdata_ff[28:24]} == 7'b0100000 ? 4'b0001 : // Mem Write request. 78 | s_axis_rq_tdata_ff[31:24] == 8'b00000010 ? 4'b0010 : // I/O Read request. 79 | s_axis_rq_tdata_ff[31:24] == 8'b01000010 ? 4'b0011 : // I/O Write request. 80 | s_axis_rq_tdata_ff[31:24] == 8'b00000100 ? 4'b1000 : // Cfg Read Type 0. 81 | s_axis_rq_tdata_ff[31:24] == 8'b01000100 ? 4'b1010 : // Cfg Write Type 0. 82 | s_axis_rq_tdata_ff[31:24] == 8'b00000101 ? 4'b1001 : // Cfg Read Type 1. 83 | s_axis_rq_tdata_ff[31:24] == 8'b01000101 ? 4'b1011 : // Cfg Write Type 1. 84 | 4'b1111; 85 | 86 | wire s_axis_rq_poisoning_ff = s_axis_rq_tdata_ff[14] | s_axis_rq_tuser_ff[1]; // EP must be 0 for request. 87 | wire [15:0] s_axis_rq_requesterid_ff = s_axis_rq_tdata_ff[63:48]; 88 | wire [7:0] s_axis_rq_tag_ff = s_axis_rq_tdata_ff[47:40]; 89 | wire [15:0] s_axis_rq_completerid_ff = 16'b0; // Applicable only to Configuration requests and messages routed by ID. 90 | wire s_axis_rq_requester_en_ff = 1'b0; // Must be 0 for Endpoint. 91 | wire [2:0] s_axis_rq_tc_ff = s_axis_rq_tdata_ff[22:20]; 92 | wire [2:0] s_axis_rq_attr_ff = {1'b0, s_axis_rq_tdata_ff[13:12]}; 93 | wire s_axis_rq_ecrc_ff = s_axis_rq_tdata_ff[15] | s_axis_rq_tuser_ff[0]; //TLP Digest 94 | 95 | wire [63:0] s_axis_rq_tdata_header = { 96 | s_axis_rq_ecrc_ff, 97 | s_axis_rq_attr_ff, 98 | s_axis_rq_tc_ff, 99 | s_axis_rq_requester_en_ff, 100 | s_axis_rq_completerid_ff, 101 | s_axis_rq_tag_ff, 102 | s_axis_rq_requesterid_ff, 103 | s_axis_rq_poisoning_ff, s_axis_rq_reqtype_ff, s_axis_rq_dwlen_ff 104 | }; 105 | 106 | wire [3:0] s_axis_rq_firstbe_ff = s_axis_rq_tdata_ff[35:32]; 107 | wire [3:0] s_axis_rq_lastbe_ff = s_axis_rq_tdata_ff[39:36]; 108 | reg [3:0] s_axis_rq_firstbe_l; 109 | reg [3:0] s_axis_rq_lastbe_l; 110 | 111 | always @(posedge user_clk) 112 | begin 113 | if (s_axis_rq_tvalid_ff && s_axis_rq_tfirst_ff) 114 | begin 115 | s_axis_rq_firstbe_l <= s_axis_rq_firstbe_ff; 116 | s_axis_rq_lastbe_l <= s_axis_rq_lastbe_ff; 117 | end 118 | end 119 | 120 | assign s_axis_rq_tdata_a = s_axis_rq_tfirst_ff ? {s_axis_rq_tdata_ff[255:128], s_axis_rq_tdata_header, s_axis_rq_tdata_ff[95:64], s_axis_rq_tdata_ff[127:96]} : s_axis_rq_tdata_ff; 121 | assign s_axis_rq_tkeep_a = s_axis_rq_tkeep_ff; 122 | assign s_axis_rq_tuser_a[59:8] = {32'b0, 4'b0, 1'b0, 8'b0, 2'b0, 1'b0, s_axis_rq_tuser_ff[3], 3'b0}; 123 | assign s_axis_rq_tuser_a[7:0] = s_axis_rq_tfirst_ff ? {s_axis_rq_lastbe_ff, s_axis_rq_firstbe_ff} : {s_axis_rq_lastbe_l, s_axis_rq_firstbe_l}; 124 | 125 | endmodule 126 | -------------------------------------------------------------------------------- /litepcie/phy/xilinx_usp/s_axis_rq_adapt_256b.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module s_axis_rq_adapt # ( 7 | parameter DATA_WIDTH = 256, 8 | parameter KEEP_WIDTH = DATA_WIDTH/8 9 | )( 10 | 11 | input user_clk, 12 | input user_reset, 13 | 14 | input [DATA_WIDTH-1:0] s_axis_rq_tdata, 15 | input [KEEP_WIDTH-1:0] s_axis_rq_tkeep, 16 | input s_axis_rq_tlast, 17 | output s_axis_rq_tready, 18 | input [3:0] s_axis_rq_tuser, 19 | input s_axis_rq_tvalid, 20 | 21 | output [DATA_WIDTH-1:0] s_axis_rq_tdata_a, 22 | output [KEEP_WIDTH/4-1:0] s_axis_rq_tkeep_a, 23 | output s_axis_rq_tlast_a, 24 | input s_axis_rq_tready_a, 25 | output [59:0] s_axis_rq_tuser_a, 26 | output s_axis_rq_tvalid_a 27 | ); 28 | 29 | wire [7:0] s_axis_rq_tkeep_or = {s_axis_rq_tkeep[28], s_axis_rq_tkeep[24], s_axis_rq_tkeep[20], s_axis_rq_tkeep[16], 30 | s_axis_rq_tkeep[12], s_axis_rq_tkeep[ 8], s_axis_rq_tkeep[ 4], s_axis_rq_tkeep[ 0]}; 31 | 32 | wire s_axis_rq_tvalid_ff; 33 | wire s_axis_rq_tready_ff; 34 | wire s_axis_rq_tlast_ff; 35 | wire [3:0] s_axis_rq_tuser_ff; 36 | wire [7:0] s_axis_rq_tkeep_ff; 37 | wire [255:0] s_axis_rq_tdata_ff; 38 | 39 | axis_iff #(.DAT_B(256+8+4)) s_axis_rq_iff 40 | ( 41 | .clk (user_clk), 42 | .rst (user_reset), 43 | 44 | .i_vld (s_axis_rq_tvalid), 45 | .o_rdy (s_axis_rq_tready), 46 | .i_sop (1'b0), 47 | .i_eop (s_axis_rq_tlast), 48 | .i_dat ({s_axis_rq_tuser, s_axis_rq_tkeep_or, s_axis_rq_tdata}), 49 | 50 | .o_vld (s_axis_rq_tvalid_ff), 51 | .i_rdy (s_axis_rq_tready_ff), 52 | .o_sop (), 53 | .o_eop (s_axis_rq_tlast_ff), 54 | .o_dat ({s_axis_rq_tuser_ff, s_axis_rq_tkeep_ff, s_axis_rq_tdata_ff}) 55 | ); 56 | 57 | reg s_axis_rq_tfirst_ff; 58 | always @(posedge user_clk) 59 | if (user_reset) begin 60 | s_axis_rq_tfirst_ff <= 1'd1; 61 | end 62 | else if (s_axis_rq_tvalid_ff && s_axis_rq_tready_ff) begin 63 | s_axis_rq_tfirst_ff <= 1'd0; 64 | if (s_axis_rq_tlast_ff) begin 65 | s_axis_rq_tfirst_ff <= 1'd1; 66 | end 67 | end 68 | 69 | assign s_axis_rq_tlast_a = s_axis_rq_tlast_ff; 70 | assign s_axis_rq_tready_ff = s_axis_rq_tready_a; 71 | assign s_axis_rq_tvalid_a = s_axis_rq_tvalid_ff; 72 | 73 | wire [10:0] s_axis_rq_dwlen_ff = {1'b0, s_axis_rq_tdata_ff[9:0]}; 74 | wire [3:0] s_axis_rq_reqtype_ff = 75 | {s_axis_rq_tdata_ff[31:30], s_axis_rq_tdata_ff[28:24]} == 7'b0000000 ? 4'b0000 : // Mem Read request. 76 | {s_axis_rq_tdata_ff[31:30], s_axis_rq_tdata_ff[28:24]} == 7'b0000001 ? 4'b0111 : // Mem Read request-locked 77 | {s_axis_rq_tdata_ff[31:30], s_axis_rq_tdata_ff[28:24]} == 7'b0100000 ? 4'b0001 : // Mem Write request. 78 | s_axis_rq_tdata_ff[31:24] == 8'b00000010 ? 4'b0010 : // I/O Read request. 79 | s_axis_rq_tdata_ff[31:24] == 8'b01000010 ? 4'b0011 : // I/O Write request. 80 | s_axis_rq_tdata_ff[31:24] == 8'b00000100 ? 4'b1000 : // Cfg Read Type 0. 81 | s_axis_rq_tdata_ff[31:24] == 8'b01000100 ? 4'b1010 : // Cfg Write Type 0. 82 | s_axis_rq_tdata_ff[31:24] == 8'b00000101 ? 4'b1001 : // Cfg Read Type 1. 83 | s_axis_rq_tdata_ff[31:24] == 8'b01000101 ? 4'b1011 : // Cfg Write Type 1. 84 | 4'b1111; 85 | 86 | wire s_axis_rq_poisoning_ff = s_axis_rq_tdata_ff[14] | s_axis_rq_tuser_ff[1]; // EP must be 0 for request. 87 | wire [15:0] s_axis_rq_requesterid_ff = s_axis_rq_tdata_ff[63:48]; 88 | wire [7:0] s_axis_rq_tag_ff = s_axis_rq_tdata_ff[47:40]; 89 | wire [15:0] s_axis_rq_completerid_ff = 16'b0; // Applicable only to Configuration requests and messages routed by ID. 90 | wire s_axis_rq_requester_en_ff = 1'b0; // Must be 0 for Endpoint. 91 | wire [2:0] s_axis_rq_tc_ff = s_axis_rq_tdata_ff[22:20]; 92 | wire [2:0] s_axis_rq_attr_ff = {1'b0, s_axis_rq_tdata_ff[13:12]}; 93 | wire s_axis_rq_ecrc_ff = s_axis_rq_tdata_ff[15] | s_axis_rq_tuser_ff[0]; //TLP Digest 94 | 95 | wire [63:0] s_axis_rq_tdata_header = { 96 | s_axis_rq_ecrc_ff, 97 | s_axis_rq_attr_ff, 98 | s_axis_rq_tc_ff, 99 | s_axis_rq_requester_en_ff, 100 | s_axis_rq_completerid_ff, 101 | s_axis_rq_tag_ff, 102 | s_axis_rq_requesterid_ff, 103 | s_axis_rq_poisoning_ff, s_axis_rq_reqtype_ff, s_axis_rq_dwlen_ff 104 | }; 105 | 106 | wire [3:0] s_axis_rq_firstbe_ff = s_axis_rq_tdata_ff[35:32]; 107 | wire [3:0] s_axis_rq_lastbe_ff = s_axis_rq_tdata_ff[39:36]; 108 | reg [3:0] s_axis_rq_firstbe_l; 109 | reg [3:0] s_axis_rq_lastbe_l; 110 | 111 | always @(posedge user_clk) 112 | begin 113 | if (s_axis_rq_tvalid_ff && s_axis_rq_tfirst_ff) 114 | begin 115 | s_axis_rq_firstbe_l <= s_axis_rq_firstbe_ff; 116 | s_axis_rq_lastbe_l <= s_axis_rq_lastbe_ff; 117 | end 118 | end 119 | 120 | assign s_axis_rq_tdata_a = s_axis_rq_tfirst_ff ? {s_axis_rq_tdata_ff[255:128], s_axis_rq_tdata_header, s_axis_rq_tdata_ff[95:64], s_axis_rq_tdata_ff[127:96]} : s_axis_rq_tdata_ff; 121 | assign s_axis_rq_tkeep_a = s_axis_rq_tkeep_ff; 122 | assign s_axis_rq_tuser_a[59:8] = {32'b0, 4'b0, 1'b0, 8'b0, 2'b0, 1'b0, s_axis_rq_tuser_ff[3], 3'b0}; 123 | assign s_axis_rq_tuser_a[7:0] = s_axis_rq_tfirst_ff ? {s_axis_rq_lastbe_ff, s_axis_rq_firstbe_ff} : {s_axis_rq_lastbe_l, s_axis_rq_firstbe_l}; 124 | 125 | endmodule 126 | -------------------------------------------------------------------------------- /test/model/chipset.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2015-2024 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | import random 8 | 9 | from litex.gen import * 10 | 11 | from litepcie.common import * 12 | from litepcie.tlp.common import * 13 | 14 | from test.model.tlp import * 15 | 16 | # Helpers ------------------------------------------------------------------------------------------ 17 | 18 | def print_chipset(s): 19 | print("[CHIPSET] {}".format(s)) 20 | 21 | 22 | def find_cmp_tags(queue): 23 | tags = [] 24 | for tag, dwords in queue: 25 | if tag not in tags: 26 | tags.append(tag) 27 | return tags 28 | 29 | 30 | def find_first_cmp_msg(queue, msg_tag): 31 | for i, (tag, dwords) in enumerate(queue): 32 | if tag == msg_tag: 33 | return i 34 | 35 | # Chipset model ------------------------------------------------------------------------------------ 36 | 37 | class Chipset(LiteXModule): 38 | def __init__(self, phy, root_id, debug=False, with_reordering=False): 39 | self.phy = phy 40 | self.root_id = root_id 41 | self.debug = debug 42 | self.with_reordering = with_reordering 43 | 44 | # # # 45 | 46 | self.rd_data = [] 47 | self.cmp_queue = [] 48 | self.en = False 49 | 50 | def set_host_callback(self, callback): 51 | self.host_callback = callback 52 | 53 | def enable(self): 54 | self.en = True 55 | 56 | def disable(self): 57 | self.en = False 58 | 59 | def wr(self, wr_cls, adr, data): 60 | wr = wr_cls() 61 | wr.fmt = 0b10 if isinstance(wr, WR32) else 0b11 62 | wr.type = 0b00000 63 | wr.length = len(data) 64 | wr.first_be = 0xf 65 | wr.address = (adr << 2) 66 | wr.requester_id = self.root_id 67 | dwords = wr.encode_dwords(data) 68 | if self.debug: 69 | print_chipset(">>>>>>>>") 70 | print_chipset(parse_dwords(dwords)) 71 | yield from self.phy.send_blocking(dwords) 72 | 73 | def wr32(self, adr, data): 74 | return self.wr(wr_cls=WR32, adr=adr, data=data) 75 | 76 | def wr64(self, adr, data): 77 | return self.wr(wr_cls=WR64, adr=adr, data=data) 78 | 79 | def rd(self, rd_cls, adr, length=1): 80 | rd = rd_cls() 81 | rd.fmt = 0b00 if isinstance(rd, RD32) else 0b01 82 | rd.type = 0b00000 83 | rd.length = length 84 | rd.first_be = 0xf 85 | rd.address = (adr << 2) 86 | rd.requester_id = self.root_id 87 | dwords = rd.encode_dwords() 88 | if self.debug: 89 | print_chipset(">>>>>>>>") 90 | print_chipset(parse_dwords(dwords)) 91 | yield from self.phy.send_blocking(dwords) 92 | dwords = None 93 | while dwords is None: 94 | dwords = self.phy.receive() 95 | yield 96 | cpld = CPLD(dwords) 97 | self.rd_data = cpld.data 98 | if self.debug: 99 | print_chipset("<<<<<<<<") 100 | print_chipset(cpld) 101 | 102 | def rd32(self, adr, length=1): 103 | return self.rd(rd_cls=RD32, adr=adr, length=length) 104 | 105 | def rd64(self, adr, length=1): 106 | return self.rd(rd_cls=RD64, adr=adr, length=length) 107 | 108 | def cmp(self, req_id, data, byte_count=None, lower_address=0, tag=0, with_split=False): 109 | if with_split: 110 | d = random.choice([64, 128, 256]) 111 | n = byte_count//d 112 | if n == 0: 113 | self.cmp(req_id, data, byte_count=byte_count, tag=tag) 114 | else: 115 | for i in range(n): 116 | cmp_data = data[i*byte_count//(4*n):(i+1)*byte_count//(4*n)] 117 | self.cmp(req_id, cmp_data, 118 | byte_count=byte_count-i*byte_count//n, tag=tag) 119 | else: 120 | if len(data) == 0: 121 | fmt = 0b00 122 | cpl = CPL() 123 | else: 124 | fmt = 0b10 125 | cpl = CPLD() 126 | cpl.fmt = fmt 127 | cpl.type = 0b01010 128 | cpl.length = len(data) 129 | cpl.lower_address = lower_address 130 | cpl.requester_id = req_id 131 | cpl.completer_id = self.root_id 132 | if byte_count is None: 133 | cpl.byte_count = len(data)*4 134 | else: 135 | cpl.byte_count = byte_count 136 | cpl.tag = tag 137 | if len(data) == 0: 138 | dwords = cpl.encode_dwords() 139 | else: 140 | dwords = cpl.encode_dwords(data) 141 | self.cmp_queue.append((tag, dwords)) 142 | 143 | def cmp_callback(self): 144 | if len(self.cmp_queue): 145 | if self.with_reordering: 146 | tags = find_cmp_tags(self.cmp_queue) 147 | tag = random.choice(tags) 148 | n = find_first_cmp_msg(self.cmp_queue, tag) 149 | tag, dwords = self.cmp_queue.pop(n) 150 | else: 151 | tag, dwords = self.cmp_queue.pop(0) 152 | if self.debug: 153 | print_chipset(">>>>>>>>") 154 | print_chipset(parse_dwords(dwords)) 155 | self.phy.send(dwords) 156 | 157 | @passive 158 | def generator(self): 159 | while True: 160 | if self.en: 161 | dwords = self.phy.receive() 162 | if dwords is not None: 163 | msg = parse_dwords(dwords) 164 | if self.debug: 165 | print_chipset("<<<<<<<< (Callback)") 166 | print_chipset(msg) 167 | self.host_callback(msg) 168 | self.cmp_callback() 169 | yield 170 | -------------------------------------------------------------------------------- /test/model/phy.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2015-2024 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | import math 8 | 9 | from litex.gen import * 10 | 11 | from litepcie.common import * 12 | from litepcie.tlp.common import * 13 | 14 | # Helpers ------------------------------------------------------------------------------------------ 15 | 16 | def print_phy(s): 17 | print("[PHY] {}".format(s)) 18 | 19 | # PHY Packet model --------------------------------------------------------------------------------- 20 | 21 | class PHYPacket: 22 | def __init__(self, dat=[], be=[]): 23 | self.dat = dat 24 | self.be = be 25 | self.start = 1 26 | self.done = 0 27 | 28 | # PHY Source model --------------------------------------------------------------------------------- 29 | 30 | class PHYSource(LiteXModule): 31 | def __init__(self, data_width): 32 | self.source = stream.Endpoint(phy_layout(data_width)) 33 | 34 | # # # 35 | 36 | self.packets = [] 37 | self.packet = PHYPacket() 38 | self.packet.done = 1 39 | 40 | def send(self, packet): 41 | self.packets.append(packet) 42 | 43 | def send_blocking(self, packet): 44 | self.send(packet) 45 | while packet.done == 0: 46 | yield 47 | 48 | @passive 49 | def generator(self): 50 | while True: 51 | if len(self.packets) and self.packet.done: 52 | self.packet = self.packets.pop(0) 53 | if self.packet.start and not self.packet.done: 54 | yield self.source.valid.eq(1) 55 | yield self.source.last.eq(len(self.packet.dat) == 1) 56 | yield self.source.dat.eq(self.packet.dat.pop(0)) 57 | yield self.source.be.eq(self.packet.be.pop(0)) 58 | self.packet.start = 0 59 | elif ((yield self.source.valid) == 1 and 60 | (yield self.source.ready) == 1): 61 | yield self.source.last.eq(len(self.packet.dat) == 1) 62 | if len(self.packet.dat) > 0: 63 | yield self.source.valid.eq(1) 64 | yield self.source.dat.eq(self.packet.dat.pop(0)) 65 | yield self.source.be.eq(self.packet.be.pop(0)) 66 | else: 67 | self.packet.done = 1 68 | yield self.source.valid.eq(0) 69 | yield 70 | 71 | # PHY Sink model ----------------------------------------------------------------------------------- 72 | 73 | class PHYSink(Module): 74 | def __init__(self, data_width): 75 | self.sink = stream.Endpoint(phy_layout(data_width)) 76 | 77 | # # # 78 | 79 | self.packet = PHYPacket() 80 | self.first = True 81 | 82 | def receive(self): 83 | self.packet.done = 0 84 | while self.packet.done == 0: 85 | yield 86 | 87 | @passive 88 | def generator(self): 89 | while True: 90 | self.packet.done = 0 91 | yield self.sink.ready.eq(1) 92 | if (yield self.sink.valid) == 1 and self.first: 93 | self.packet.start = 1 94 | self.packet.dat = [(yield self.sink.dat)] 95 | self.packet.be = [(yield self.sink.be)] 96 | self.first = False 97 | elif (yield self.sink.valid): 98 | self.packet.start = 0 99 | self.packet.dat.append((yield self.sink.dat)) 100 | self.packet.be.append((yield self.sink.be)) 101 | if (yield self.sink.valid) == 1 and (yield self.sink.last) == 1: 102 | self.packet.done = 1 103 | self.first = True 104 | yield 105 | 106 | # PHY Layer model ---------------------------------------------------------------------------------- 107 | 108 | class PHY(LiteXModule): 109 | def __init__(self, data_width, id, bar0_size, debug): 110 | self.data_width = data_width 111 | 112 | self.id = id 113 | 114 | self.bar0_size = bar0_size 115 | self.bar0_mask = get_bar_mask(bar0_size) 116 | 117 | self.max_request_size = Signal(10, reset=512) 118 | self.max_payload_size = Signal(8, reset=128) 119 | 120 | self.phy_source = PHYSource(data_width) 121 | self.phy_sink = PHYSink(data_width) 122 | 123 | self.source = self.phy_source.source 124 | self.sink = self.phy_sink.sink 125 | 126 | def dwords2packet(self, dwords): 127 | ratio = self.data_width//32 128 | length = math.ceil(len(dwords)/ratio) 129 | dat = [0]*length 130 | be = [0]*length 131 | for n in range(length): 132 | for i in reversed(range(ratio)): 133 | dat[n] = dat[n] << 32 134 | be[n] = be[n] << 4 135 | try: 136 | dat[n] |= dwords[2*n+i] 137 | be[n] |= 0xF 138 | except: 139 | pass 140 | return dat, be 141 | 142 | def send(self, dwords): 143 | dat, be = self.dwords2packet(dwords) 144 | packet = PHYPacket(dat, be) 145 | self.phy_source.send(packet) 146 | 147 | def send_blocking(self, dwords): 148 | dat, be = self.dwords2packet(dwords) 149 | packet = PHYPacket(dat, be) 150 | yield from self.phy_source.send_blocking(packet) 151 | 152 | def packet2dwords(self, p_dat, p_be): 153 | ratio = self.data_width//32 154 | dwords = [] 155 | for dat, be in zip(p_dat, p_be): 156 | for i in range(ratio): 157 | dword_be = (be >> (4*i)) & 0xf 158 | dword_dat = (dat >> (32*i)) & 0xffffffff 159 | if dword_be == 0xf: 160 | dwords.append(dword_dat) 161 | return dwords 162 | 163 | def receive(self): 164 | if self.phy_sink.packet.done: 165 | self.phy_sink.packet.done = 0 166 | return self.packet2dwords(self.phy_sink.packet.dat, self.phy_sink.packet.be) 167 | else: 168 | return None 169 | 170 | -------------------------------------------------------------------------------- /litepcie/frontend/wishbone.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2015-2023 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | from migen import * 8 | 9 | from litex.gen import * 10 | from litex.gen.genlib.misc import WaitTimer 11 | 12 | from litex.soc.interconnect import wishbone 13 | 14 | from litepcie.common import * 15 | 16 | # Helpers ------------------------------------------------------------------------------------------ 17 | 18 | def map_wishbone_dat(address, data, wishbone_dat, qword_aligned=False): 19 | return [ 20 | If(qword_aligned, 21 | If(address[2], 22 | wishbone_dat.eq(data[:32]) 23 | ).Else( 24 | wishbone_dat.eq(data[32:]) 25 | ) 26 | ).Else( 27 | wishbone_dat.eq(data[:32]) 28 | ) 29 | ] 30 | 31 | # LitePCIeWishboneMaster --------------------------------------------------------------------------- 32 | 33 | class LitePCIeWishboneMaster(LiteXModule): 34 | def __init__(self, endpoint, 35 | address_decoder = lambda a: 1, 36 | base_address = 0x00000000, 37 | qword_aligned = False): 38 | self.bus = self.wishbone = wishbone.Interface() 39 | 40 | # # # 41 | 42 | # Get Slave port from Crossbar. 43 | port = endpoint.crossbar.get_slave_port(address_decoder) 44 | 45 | # Wishbone Master FSM. 46 | self.fsm = fsm = FSM(reset_state="IDLE") 47 | fsm.act("IDLE", 48 | If(port.sink.valid & port.sink.first, 49 | If(port.sink.we, 50 | NextState("DO-WRITE") 51 | ).Else( 52 | NextState("DO-READ") 53 | ) 54 | ).Else( 55 | port.sink.ready.eq(1) 56 | ) 57 | ) 58 | self.sync += [ 59 | self.bus.sel.eq(0xf), 60 | self.bus.adr.eq(port.sink.adr[2:] + (base_address >> 2)), 61 | map_wishbone_dat( 62 | address = port.sink.adr, 63 | data = port.sink.dat, 64 | wishbone_dat = self.bus.dat_w, 65 | qword_aligned = qword_aligned, 66 | ), 67 | ] 68 | fsm.act("DO-WRITE", 69 | self.bus.stb.eq(1), 70 | self.bus.we.eq(1), 71 | self.bus.cyc.eq(1), 72 | If(self.bus.ack, 73 | port.sink.ready.eq(1), 74 | NextState("IDLE") 75 | ) 76 | ) 77 | update_dat = Signal() 78 | fsm.act("DO-READ", 79 | self.bus.stb.eq(1), 80 | self.bus.we.eq(0), 81 | self.bus.cyc.eq(1), 82 | If(self.bus.ack, 83 | update_dat.eq(1), 84 | NextState("ISSUE-READ-COMPLETION") 85 | ) 86 | ) 87 | self.sync += [ 88 | port.source.first.eq(1), 89 | port.source.last.eq(1), 90 | port.source.len.eq(1), 91 | port.source.err.eq(0), 92 | port.source.tag.eq(port.sink.tag), 93 | port.source.adr.eq(port.sink.adr), 94 | port.source.cmp_id.eq(endpoint.phy.id), 95 | port.source.req_id.eq(port.sink.req_id), 96 | If(update_dat, 97 | port.source.dat.eq(self.bus.dat_r) 98 | ) 99 | ] 100 | fsm.act("ISSUE-READ-COMPLETION", 101 | port.source.valid.eq(1), 102 | If(port.source.ready, 103 | port.sink.ready.eq(1), 104 | NextState("IDLE") 105 | ) 106 | ) 107 | 108 | class LitePCIeWishboneBridge(LitePCIeWishboneMaster): pass # initial name 109 | 110 | # LitePCIeWishboneSlave ---------------------------------------------------------------------------- 111 | 112 | class LitePCIeWishboneSlave(LiteXModule): 113 | def __init__(self, endpoint, address_width=32, data_width=32, addressing="word", qword_aligned=False): 114 | assert data_width == 32 115 | self.bus = self.wishbone = wishbone.Interface( 116 | address_width = address_width, 117 | data_width = data_width, 118 | addressing = addressing, 119 | ) 120 | 121 | # # # 122 | 123 | # Timeout. 124 | self.timeout = timeout = WaitTimer(2**16) 125 | 126 | # Get Master port from Crossbar. 127 | port = endpoint.crossbar.get_master_port() 128 | 129 | # Wishbone Slave FSM. 130 | self.fsm = fsm = FSM(reset_state="IDLE") 131 | fsm.act("IDLE", 132 | If(self.bus.stb & self.bus.cyc, 133 | If(self.bus.we, 134 | NextState("ISSUE-WRITE") 135 | ).Else( 136 | NextState("ISSUE-READ") 137 | ) 138 | ) 139 | ) 140 | ashift = {"byte" : 0, "word" : 2}[addressing] 141 | self.comb += [ 142 | port.source.channel.eq(port.channel), 143 | port.source.first.eq(1), 144 | port.source.last.eq(1), 145 | port.source.adr[ashift:].eq(self.bus.adr), 146 | port.source.req_id.eq(endpoint.phy.id), 147 | port.source.tag.eq(0), 148 | port.source.len.eq(1), 149 | port.source.dat.eq(self.bus.dat_w), 150 | ] 151 | fsm.act("ISSUE-WRITE", 152 | timeout.wait.eq(1), 153 | port.source.valid.eq(1), 154 | port.source.we.eq(1), 155 | If(port.source.ready | timeout.done, 156 | self.bus.ack.eq(1), 157 | self.bus.err.eq(timeout.done), 158 | NextState("IDLE") 159 | ) 160 | ) 161 | fsm.act("ISSUE-READ", 162 | timeout.wait.eq(1), 163 | port.source.valid.eq(1), 164 | port.source.we.eq(0), 165 | If(port.source.ready | timeout.done, 166 | NextState("RECEIVE-READ-COMPLETION") 167 | ) 168 | ) 169 | fsm.act("RECEIVE-READ-COMPLETION", 170 | timeout.wait.eq(1), 171 | port.sink.ready.eq(1), 172 | If((port.sink.valid & port.sink.first) | timeout.done, 173 | map_wishbone_dat( 174 | address = port.sink.adr, 175 | data = port.sink.dat, 176 | wishbone_dat = self.bus.dat_r, 177 | qword_aligned = qword_aligned, 178 | ), 179 | self.bus.ack.eq(1), 180 | self.bus.err.eq(timeout.done), 181 | NextState("IDLE") 182 | ) 183 | ) 184 | -------------------------------------------------------------------------------- /litepcie/core/msi.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2015-2023 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | from migen import * 8 | 9 | from litex.gen import * 10 | 11 | from litex.soc.interconnect.csr import * 12 | from litex.soc.interconnect.csr_bus import SRAM 13 | 14 | from litepcie.common import * 15 | 16 | # LitePCIeMSI -------------------------------------------------------------------------------------- 17 | 18 | class LitePCIeMSI(LiteXModule): 19 | def __init__(self, width=32): 20 | self.irqs = Signal(width) 21 | self.source = stream.Endpoint(msi_layout()) 22 | 23 | self.enable = CSRStorage(width, description="""MSI Enable Control.\n 24 | Write bit(s) to ``1`` to enable corresponding MSI IRQ(s).""") 25 | self.clear = CSRStorage(width, description="""MSI Clear Control.\n 26 | Write bit(s) to ``1`` to clear corresponding MSI IRQ(s).""") 27 | self.vector = CSRStatus(width, description="""MSI Vector Status.\n 28 | Current MSI IRQs vector value.""") 29 | 30 | # # # 31 | 32 | enable = Signal(width) 33 | clear = Signal(width) 34 | vector = Signal(width) 35 | 36 | # Memorize and clear IRQ Vector ------------------------------------------------------------ 37 | self.comb += If(self.clear.re, clear.eq(self.clear.storage)) 38 | self.comb += enable.eq(self.enable.storage) 39 | self.comb += self.vector.status.eq(vector) 40 | self.sync += vector.eq(enable & ((vector & ~clear) | self.irqs)) 41 | 42 | # Generate MSI ----------------------------------------------------------------------------- 43 | msi = Signal(width) 44 | self.comb += self.source.valid.eq(msi != 0) 45 | self.sync += [ 46 | msi.eq((msi | self.irqs) & enable), 47 | If(self.source.ready, 48 | msi.eq(self.irqs & enable) 49 | ) 50 | ] 51 | 52 | # LitePCIeMSIMultiVector --------------------------------------------------------------------------- 53 | 54 | class LitePCIeMSIMultiVector(LiteXModule): 55 | def __init__(self, width=32): 56 | self.irqs = Signal(width) 57 | self.source = stream.Endpoint(msi_layout()) 58 | 59 | self.enable = CSRStorage(width, description="""MSI Enable Control.\n 60 | Write bit(s) to ``1`` to enable corresponding MSI IRQ(s).""") 61 | 62 | # # # 63 | 64 | enable = Signal(width) 65 | clear = Signal(width) 66 | vector = Signal(width) 67 | 68 | # Memorize and clear IRQ Vector ------------------------------------------------------------ 69 | self.comb += enable.eq(self.enable.storage) 70 | self.sync += vector.eq(enable & ((vector & ~clear) | self.irqs)) 71 | 72 | # Generate MSI ----------------------------------------------------------------------------- 73 | for i in reversed(range(width)): # Priority given to lower indexes. 74 | self.comb += [ 75 | If(vector[i], 76 | self.source.valid.eq(1), 77 | self.source.dat.eq(i), 78 | If(self.source.ready, 79 | clear.eq(1 << i) 80 | ) 81 | ) 82 | ] 83 | 84 | # LitePCIeMSIX ------------------------------------------------------------------------------------- 85 | 86 | class LitePCIeMSIX(LiteXModule): 87 | def __init__(self, endpoint, width=32, default_enable=0): 88 | assert width <= 64 89 | self.irqs = Signal(width) 90 | self.enable = CSRStorage(width, description="""MSI-X Enable Control.\n 91 | Write bit(s) to ``1`` to enable corresponding MSI-X IRQ(s).""", 92 | reset = default_enable*(2**width-1)) 93 | if width <= 32: 94 | self.reserved0 = CSRStorage() # For 64-bit alignment. 95 | self.pba = CSRStatus(width, description="""MSI-X PBA Table.""") 96 | if width <= 32: 97 | self.reserved1 = CSRStorage() # For 64-bit alignment. 98 | self.specials.table = Memory(4*32, width, init=[0b1 for _ in range(width)]) # MSI-X Table / Masked by default. 99 | 100 | # # # 101 | 102 | enable = Signal(width) 103 | clear = Signal(width) 104 | vector = Signal(width) 105 | 106 | # Memorize and clear IRQ Vector ------------------------------------------------------------ 107 | self.comb += enable.eq(self.enable.storage) 108 | self.sync += vector.eq(enable & ((vector & ~clear) | self.irqs)) 109 | self.comb += self.pba.status.eq(vector) 110 | 111 | # Generate MSI-X --------------------------------------------------------------------------- 112 | msix_valid = Signal() 113 | msix_num = Signal(max=width) 114 | msix_clear = Signal(width) 115 | msix_clear_on_ready = Signal(width) 116 | 117 | for i in reversed(range(width)): # Priority given to lower indexes. 118 | self.comb += [ 119 | If(vector[i], 120 | msix_valid.eq(1), 121 | msix_num.eq(i), 122 | msix_clear.eq(1 << i), 123 | ) 124 | ] 125 | 126 | # Send MSI-X as TLP-Write ------------------------------------------------------------------ 127 | self.port = port = endpoint.crossbar.get_master_port() 128 | self.table_port = table_port = self.table.get_port(has_re=True) 129 | self.specials += table_port 130 | 131 | # Table decoding. 132 | msix_adr = table_port.dat_r[96:128] # Lower Address. 133 | msix_dat = table_port.dat_r[32:64] # Message Data. 134 | msix_mask = table_port.dat_r[0] # Mask, when set to 1, MSI-X message is not generated. 135 | 136 | # FSM. 137 | self.fsm = fsm = FSM(reset_state="IDLE") 138 | fsm.act("IDLE", 139 | table_port.adr.eq(msix_num), 140 | table_port.re.eq(1), 141 | If(msix_valid, 142 | NextValue(msix_clear_on_ready, msix_clear), 143 | NextState("ISSUE-WRITE") 144 | ) 145 | ) 146 | self.comb += [ 147 | port.source.channel.eq(port.channel), 148 | port.source.first.eq(1), 149 | port.source.last.eq(1), 150 | port.source.adr.eq(msix_adr), 151 | port.source.req_id.eq(endpoint.phy.id), 152 | port.source.tag.eq(0), 153 | port.source.len.eq(1), 154 | port.source.dat.eq(msix_dat), 155 | ] 156 | fsm.act("ISSUE-WRITE", 157 | port.source.valid.eq(~msix_mask), 158 | port.source.we.eq(1), 159 | If(port.source.ready | msix_mask, 160 | clear.eq(msix_clear_on_ready), 161 | NextState("IDLE") 162 | ) 163 | ) 164 | -------------------------------------------------------------------------------- /litepcie/core/crossbar.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LitePCIe. 3 | # 4 | # Copyright (c) 2015-2023 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | from migen import * 8 | 9 | from litex.gen import * 10 | 11 | from litepcie.common import * 12 | from litepcie.core.common import * 13 | from litepcie.tlp.controller import LitePCIeTLPController 14 | 15 | # LitePCIe Crossbar -------------------------------------------------------------------------------- 16 | 17 | class LitePCIeCrossbar(LiteXModule): 18 | def __init__(self, data_width, address_width, max_pending_requests, cmp_bufs_buffered=True): 19 | self.data_width = data_width 20 | self.address_width = address_width 21 | self.max_pending_requests = max_pending_requests 22 | self.cmp_bufs_buffered = cmp_bufs_buffered 23 | 24 | self.master = LitePCIeMasterInternalPort(data_width, address_width) 25 | self.slave = LitePCIeSlaveInternalPort(data_width) 26 | self.phy_master = LitePCIeMasterPort(self.master) 27 | self.phy_slave = LitePCIeSlavePort(self.slave) 28 | 29 | self.user_masters = [] 30 | self.user_masters_channel = 0 31 | self.user_slaves = [] 32 | 33 | def get_slave_port(self, address_decoder): 34 | s = LitePCIeSlaveInternalPort( 35 | data_width = self.data_width, 36 | address_decoder = address_decoder) 37 | self.user_slaves.append(s) 38 | return LitePCIeSlavePort(s) 39 | 40 | def get_master_port(self, write_only=False, read_only=False): 41 | m = LitePCIeMasterInternalPort( 42 | data_width = self.data_width, 43 | address_width = self.address_width, 44 | channel = self.user_masters_channel, 45 | write_only = write_only, 46 | read_only = read_only 47 | ) 48 | self.user_masters_channel += 1 49 | self.user_masters.append(m) 50 | return LitePCIeMasterPort(m) 51 | 52 | def filter_masters(self, write_only, read_only): 53 | masters = [] 54 | for m in self.user_masters: 55 | if m.write_only == write_only and m.read_only == read_only: 56 | masters.append(m) 57 | return masters 58 | 59 | def slave_dispatch_arbitrate(self, slaves, slave): 60 | # Dispatch --------------------------------------------------------------------------------- 61 | s_sources = [s.source for s in slaves] 62 | s_dispatcher = Dispatcher(slave.source, s_sources, one_hot=True) 63 | self.submodules += s_dispatcher 64 | for i, s in enumerate(slaves): 65 | self.comb += s_dispatcher.sel[i].eq(s.address_decoder(slave.source.adr)) 66 | 67 | # Arbitrate -------------------------------------------------------------------------------- 68 | s_sinks = [s.sink for s in slaves] 69 | s_arbiter = Arbiter(s_sinks, slave.sink) 70 | self.submodules += s_arbiter 71 | 72 | def master_arbitrate_dispatch(self, masters, master, dispatch=True): 73 | # Arbitrate -------------------------------------------------------------------------------- 74 | m_sinks = [m.sink for m in masters] 75 | m_arbiter = Arbiter(m_sinks, master.sink) 76 | self.submodules += m_arbiter 77 | 78 | # Dispatch --------------------------------------------------------------------------------- 79 | if dispatch: 80 | m_sources = [m.source for m in masters] 81 | m_dispatcher = Dispatcher(master.source, m_sources, one_hot=True) 82 | self.submodules += m_dispatcher 83 | for i, m in enumerate(masters): 84 | if m.channel is not None: 85 | self.comb += m_dispatcher.sel[i].eq(master.source.channel == m.channel) 86 | else: 87 | # Connect to first master. 88 | self.comb += master.source.connect(masters[0].source) 89 | 90 | def do_finalize(self): 91 | # Slave path ------------------------------------------------------------------------------- 92 | # - Dispatch request to user sources (according to address decoder). 93 | # - Arbitrate completion from user sinks. 94 | if self.user_slaves != []: 95 | self.slave_dispatch_arbitrate(self.user_slaves, self.slave) 96 | 97 | # Master path ------------------------------------------------------------------------------ 98 | # Abritrate requests from user sinks 99 | # Dispatch completion to user sources (according to channel) 100 | 101 | # +-------+ 102 | # reqs---> | RD | 103 | # cmps<--- | PORTS |---------+ 104 | # +-------+ +---+----+ +----------+ 105 | # |Arb/Disp|-->|Controller|--+ 106 | # +-------+ +---+----+ +----------+ | 107 | # reqs---> | RW | | | 108 | # cmps<--- | PORTS |---------+ | 109 | # +-------+ +---+----+ 110 | # |Arb/Disp|<--> to/from Packetizer/ 111 | # +-------+ +---+----+ Depacketizer 112 | # reqs---> | WR | +--------+ | 113 | # cmps<--- | PORTS |-----|Arb/Disp|-----------------+ 114 | # +-------+ +--------+ 115 | # 116 | # The controller blocks RD requests when the max number of pending requests have been sent 117 | # (max_pending_requests parameters). 118 | # To avoid blocking write_only ports when RD requests are blocked, a separate arbitration 119 | # stage is used. 120 | 121 | if self.user_masters != []: 122 | masters = [] 123 | 124 | # Arbitrate / dispatch read_only / read_write ports and insert controller -------------- 125 | rd_rw_masters = self.filter_masters(False, True) 126 | rd_rw_masters += self.filter_masters(False, False) 127 | if rd_rw_masters != []: 128 | rd_rw_master = LitePCIeMasterInternalPort(self.data_width, self.address_width) 129 | controller = LitePCIeTLPController( 130 | data_width = self.data_width, 131 | address_width = self.address_width, 132 | max_pending_requests = self.max_pending_requests, 133 | cmp_bufs_buffered = self.cmp_bufs_buffered) 134 | self.submodules.controller = controller 135 | self.master_arbitrate_dispatch(rd_rw_masters, controller.master_in) 136 | masters.append(controller.master_out) 137 | 138 | # Arbitrate / dispatch write_only ports ------------------------------------------------ 139 | wr_masters = self.filter_masters(True, False) 140 | if wr_masters != []: 141 | wr_master = LitePCIeMasterInternalPort(self.data_width, self.address_width) 142 | self.master_arbitrate_dispatch(wr_masters, wr_master) 143 | masters.append(wr_master) 144 | 145 | # Final Arbitrate / dispatch stage ----------------------------------------------------- 146 | self.master_arbitrate_dispatch(masters, self.master, False) 147 | -------------------------------------------------------------------------------- /litepcie/phy/xilinx_usp/m_axis_cq_adapt_512b.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module m_axis_cq_adapt # ( 7 | parameter DATA_WIDTH = 512, 8 | parameter KEEP_WIDTH = DATA_WIDTH/8 9 | )( 10 | 11 | input user_clk, 12 | input user_reset, 13 | 14 | output [DATA_WIDTH-1:0] m_axis_cq_tdata, 15 | output [KEEP_WIDTH-1:0] m_axis_cq_tkeep, 16 | output m_axis_cq_tlast, 17 | input [3:0] m_axis_cq_tready, 18 | output [84:0] m_axis_cq_tuser, 19 | output m_axis_cq_tvalid, 20 | 21 | input [DATA_WIDTH-1:0] m_axis_cq_tdata_a, 22 | input [KEEP_WIDTH/4-1:0] m_axis_cq_tkeep_a, 23 | input m_axis_cq_tlast_a, 24 | output [3:0] m_axis_cq_tready_a, 25 | input [84:0] m_axis_cq_tuser_a, 26 | input m_axis_cq_tvalid_a 27 | ); 28 | 29 | //dword counter: //0-2 & latch 30 | reg [1:0] m_axis_cq_cnt; 31 | always @(posedge user_clk) 32 | if (user_reset) m_axis_cq_cnt <= 2'd0; 33 | else if (m_axis_cq_tvalid_a && m_axis_cq_tready_a) 34 | begin 35 | if (m_axis_cq_tlast_a) m_axis_cq_cnt <= 2'd0; 36 | else if (!m_axis_cq_cnt[1]) m_axis_cq_cnt <= m_axis_cq_cnt + 1; 37 | end 38 | 39 | wire m_axis_cq_sop = (m_axis_cq_cnt == 0) && (!m_axis_cq_tlast_lat); 40 | wire m_axis_cq_second = m_axis_cq_cnt == 1; 41 | 42 | reg m_axis_cq_rdwr_l; 43 | always @(posedge user_clk) 44 | if (user_reset) m_axis_cq_rdwr_l <= 1'd0; 45 | else if (m_axis_cq_tvalid_a && m_axis_cq_sop) m_axis_cq_rdwr_l <= m_axis_cq_tlast_a; 46 | 47 | //processing for tlast: generate new last in case write & last num of dword != 13 + i*16 48 | wire m_axis_cq_read = (m_axis_cq_fmt[1:0] == 2'b0); //Read request 49 | wire m_axis_cq_write = !m_axis_cq_read; 50 | wire [9:0] m_axis_cq_dwlen; 51 | reg m_axis_cq_tlast_dly_en; 52 | always @(posedge user_clk) 53 | if (user_reset) m_axis_cq_tlast_dly_en <= 1'd0; 54 | else if (m_axis_cq_tlast_lat && m_axis_cq_tready) m_axis_cq_tlast_dly_en <= 1'd0; 55 | else if (m_axis_cq_tvalid_a && m_axis_cq_sop) m_axis_cq_tlast_dly_en <= m_axis_cq_tlast_a | (m_axis_cq_dwlen[3:0] != 4'd13); 56 | 57 | reg m_axis_cq_tlast_lat; 58 | always @(posedge user_clk) 59 | if (user_reset) m_axis_cq_tlast_lat <= 1'd0; 60 | else if (m_axis_cq_tlast_lat && m_axis_cq_tready) m_axis_cq_tlast_lat <= 1'd0; 61 | else if (m_axis_cq_tvalid_a && m_axis_cq_tready_a && m_axis_cq_tlast_a) 62 | begin 63 | if (m_axis_cq_sop) m_axis_cq_tlast_lat <= 1'b1; //read or write 64 | else if (m_axis_cq_tlast_dly_en) m_axis_cq_tlast_lat <= 1'b1; 65 | end 66 | 67 | //Generae ready for PCIe IP 68 | assign m_axis_cq_tready_a = ((m_axis_cq_cnt == 0) | m_axis_cq_tready) && (!m_axis_cq_tlast_lat); 69 | 70 | //output for TLP 71 | assign m_axis_cq_tlast = m_axis_cq_tlast_dly_en ? m_axis_cq_tlast_lat : m_axis_cq_tlast_a; 72 | assign m_axis_cq_tvalid = (m_axis_cq_tvalid_a & (|m_axis_cq_cnt)) | m_axis_cq_tlast_lat; 73 | 74 | 75 | ////keep address (low) or data (high), not header 76 | reg [511:0] m_axis_cq_tdata_a1; 77 | reg [63:0] m_axis_cq_tlast_be1; 78 | always @(posedge user_clk) 79 | if (m_axis_cq_tvalid_a && m_axis_cq_tready_a) 80 | begin 81 | m_axis_cq_tdata_a1 <= m_axis_cq_tdata_a; 82 | m_axis_cq_tlast_be1 <= m_axis_cq_tuser_a[79:16]; 83 | end 84 | 85 | //data processing 86 | wire [63:0] m_axis_cq_tdata_hdr = m_axis_cq_tdata_a[127:64]; 87 | 88 | assign m_axis_cq_dwlen = m_axis_cq_tdata_hdr[9:0]; 89 | wire [1:0] m_axis_cq_attr = m_axis_cq_tdata_hdr[61:60]; 90 | wire m_axis_cq_ep = 1'b0; 91 | wire m_axis_cq_td = 1'b0; 92 | wire [2:0] m_axis_cq_tc = m_axis_cq_tdata_hdr[59:57]; 93 | wire [4:0] m_axis_cq_type; 94 | wire [2:0] m_axis_cq_fmt; 95 | wire [7:0] m_axis_cq_be = {m_axis_cq_tuser_a[11:8], m_axis_cq_tuser_a[3:0]}; 96 | wire [7:0] m_axis_cq_tag = m_axis_cq_tdata_hdr[39:32]; 97 | wire [15:0] m_axis_cq_requesterid = m_axis_cq_tdata_hdr[31:16]; 98 | 99 | assign {m_axis_cq_fmt, m_axis_cq_type} = m_axis_cq_tdata_hdr[14:11] == 4'b0000 ? 8'b000_00000 : //Mem read Request 100 | m_axis_cq_tdata_hdr[14:11] == 4'b0111 ? 8'b000_00001 : //Mem Read request-locked 101 | m_axis_cq_tdata_hdr[14:11] == 4'b0001 ? 8'b010_00000 : //Mem write request 102 | m_axis_cq_tdata_hdr[14:11] == 4'b0010 ? 8'b000_00010 : //I/O Read request 103 | m_axis_cq_tdata_hdr[14:11] == 4'b0011 ? 8'b010_00010 : //I/O Write request 104 | m_axis_cq_tdata_hdr[14:11] == 4'b1000 ? 8'b000_00100 : //Cfg Read Type 0 105 | m_axis_cq_tdata_hdr[14:11] == 4'b1010 ? 8'b010_00100 : //Cfg Write Type 0 106 | m_axis_cq_tdata_hdr[14:11] == 4'b1001 ? 8'b000_00101 : //Cfg Read Type 1 107 | m_axis_cq_tdata_hdr[14:11] == 4'b1011 ? 8'b010_00101 : //Cfg Write Type 1 108 | 8'b000_00000; //Mem read Request 109 | 110 | reg [7:0] m_axis_cq_tuser_barhit; 111 | always @(posedge user_clk) 112 | if (m_axis_cq_tvalid_a && m_axis_cq_sop) 113 | m_axis_cq_tuser_barhit <= {1'b0, m_axis_cq_tdata_hdr[50:48], m_axis_cq_tdata_hdr[14:11]}; //only valid @sop 114 | 115 | reg [63:0] m_axis_cq_header; 116 | always @(posedge user_clk) 117 | if (m_axis_cq_tvalid_a && m_axis_cq_sop) 118 | m_axis_cq_header = {m_axis_cq_requesterid, 119 | m_axis_cq_tag, 120 | m_axis_cq_be, 121 | m_axis_cq_fmt, m_axis_cq_type, 122 | 1'b0, m_axis_cq_tc, 4'b0, 123 | m_axis_cq_td, m_axis_cq_ep, m_axis_cq_attr, 124 | 2'b0, m_axis_cq_dwlen}; 125 | 126 | assign m_axis_cq_tdata = (m_axis_cq_rdwr_l | m_axis_cq_second) ? {m_axis_cq_tdata_a[31:0], m_axis_cq_tdata_a1[511:128], m_axis_cq_tdata_a1[31:0], m_axis_cq_header} : 127 | {m_axis_cq_tdata_a[31:0], m_axis_cq_tdata_a1[511:32]}; 128 | assign m_axis_cq_tkeep = m_axis_cq_rdwr_l ? {4'b0, m_axis_cq_tlast_be1[63:16], 12'hFFF} : 129 | m_axis_cq_tlast_lat ? {4'b0, m_axis_cq_tlast_be1[63:4]} : {64{1'b1}}; 130 | assign m_axis_cq_tuser = { 131 | 5'b0, //rx_is_eof only for 128-bit I/F 132 | 2'b0, //reserved 133 | 5'b0, //rx_is_sof only for 128-bit I/F 134 | m_axis_cq_tuser_barhit, 135 | 1'b0, //rx_err_fwd -> no equivalent 136 | m_axis_cq_tuser_a[96] //ECRC mapped to discontinue 137 | }; 138 | 139 | endmodule -------------------------------------------------------------------------------- /litepcie/phy/xilinx_us/m_axis_cq_adapt_256b.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module m_axis_cq_adapt # ( 7 | parameter DATA_WIDTH = 256, 8 | parameter KEEP_WIDTH = DATA_WIDTH/8 9 | )( 10 | 11 | input user_clk, 12 | input user_reset, 13 | 14 | output [DATA_WIDTH-1:0] m_axis_cq_tdata, 15 | output [KEEP_WIDTH-1:0] m_axis_cq_tkeep, 16 | output m_axis_cq_tlast, 17 | input [3:0] m_axis_cq_tready, 18 | output [84:0] m_axis_cq_tuser, 19 | output m_axis_cq_tvalid, 20 | 21 | input [DATA_WIDTH-1:0] m_axis_cq_tdata_a, 22 | input [KEEP_WIDTH/4-1:0] m_axis_cq_tkeep_a, 23 | input m_axis_cq_tlast_a, 24 | output [3:0] m_axis_cq_tready_a, 25 | input [84:0] m_axis_cq_tuser_a, 26 | input m_axis_cq_tvalid_a 27 | ); 28 | 29 | //dword counter: //0-2 & latch 30 | reg [1:0] m_axis_cq_cnt; 31 | always @(posedge user_clk) 32 | if (user_reset) m_axis_cq_cnt <= 2'd0; 33 | else if (m_axis_cq_tvalid_a && m_axis_cq_tready_a) 34 | begin 35 | if (m_axis_cq_tlast_a) m_axis_cq_cnt <= 2'd0; 36 | else if (!m_axis_cq_cnt[1]) m_axis_cq_cnt <= m_axis_cq_cnt + 1; 37 | end 38 | 39 | wire m_axis_cq_sop = (m_axis_cq_cnt == 0) && (!m_axis_cq_tlast_lat); //m_axis_cq_tuser_a[40] 40 | wire m_axis_cq_second = m_axis_cq_cnt == 1; 41 | 42 | reg m_axis_cq_rdwr_l; 43 | always @(posedge user_clk) 44 | if (user_reset) m_axis_cq_rdwr_l <= 1'd0; 45 | else if (m_axis_cq_tvalid_a && m_axis_cq_sop) m_axis_cq_rdwr_l <= m_axis_cq_tlast_a; 46 | 47 | //processing for tlast: generate new last in case write & last num of dword != 5 + i*8 48 | wire m_axis_cq_read = (m_axis_cq_fmt[1:0] == 2'b0); //Read request 49 | wire m_axis_cq_write = !m_axis_cq_read; 50 | wire [9:0] m_axis_cq_dwlen; 51 | reg m_axis_cq_tlast_dly_en; 52 | always @(posedge user_clk) 53 | if (user_reset) m_axis_cq_tlast_dly_en <= 1'd0; 54 | else if (m_axis_cq_tlast_lat && m_axis_cq_tready) m_axis_cq_tlast_dly_en <= 1'd0; 55 | else if (m_axis_cq_tvalid_a && m_axis_cq_sop) m_axis_cq_tlast_dly_en <= m_axis_cq_tlast_a | (m_axis_cq_dwlen[2:0] != 3'd5); 56 | 57 | reg m_axis_cq_tlast_lat; 58 | always @(posedge user_clk) 59 | if (user_reset) m_axis_cq_tlast_lat <= 1'd0; 60 | else if (m_axis_cq_tlast_lat && m_axis_cq_tready) m_axis_cq_tlast_lat <= 1'd0; 61 | else if (m_axis_cq_tvalid_a && m_axis_cq_tready_a && m_axis_cq_tlast_a) 62 | begin 63 | if (m_axis_cq_sop) m_axis_cq_tlast_lat <= 1'b1; 64 | else if (m_axis_cq_tlast_dly_en) m_axis_cq_tlast_lat <= 1'b1; 65 | end 66 | 67 | //Generae ready for PCIe IP 68 | assign m_axis_cq_tready_a = ((m_axis_cq_cnt == 0) | m_axis_cq_tready) && (!m_axis_cq_tlast_lat); 69 | 70 | //output for TLP 71 | assign m_axis_cq_tlast = m_axis_cq_tlast_dly_en ? m_axis_cq_tlast_lat : m_axis_cq_tlast_a; 72 | assign m_axis_cq_tvalid = (m_axis_cq_tvalid_a & (|m_axis_cq_cnt)) | m_axis_cq_tlast_lat; 73 | 74 | 75 | ////keep address (low) or data (high), not header 76 | reg [255:0] m_axis_cq_tdata_a1; 77 | reg [31:0] m_axis_cq_tlast_be1; 78 | always @(posedge user_clk) 79 | if (m_axis_cq_tvalid_a && m_axis_cq_tready_a) 80 | begin 81 | m_axis_cq_tdata_a1 <= m_axis_cq_tdata_a; 82 | m_axis_cq_tlast_be1 <= m_axis_cq_tuser_a[39:8]; 83 | end 84 | 85 | //data processing 86 | wire [63:0] m_axis_cq_tdata_hdr = m_axis_cq_tdata_a[127:64]; 87 | 88 | assign m_axis_cq_dwlen = m_axis_cq_tdata_hdr[9:0]; 89 | wire [1:0] m_axis_cq_attr = m_axis_cq_tdata_hdr[61:60]; 90 | wire m_axis_cq_ep = 1'b0; 91 | wire m_axis_cq_td = 1'b0; 92 | wire [2:0] m_axis_cq_tc = m_axis_cq_tdata_hdr[59:57]; 93 | wire [4:0] m_axis_cq_type; 94 | wire [2:0] m_axis_cq_fmt; 95 | wire [7:0] m_axis_cq_be = m_axis_cq_tuser_a[7:0]; 96 | wire [7:0] m_axis_cq_tag = m_axis_cq_tdata_hdr[39:32]; 97 | wire [15:0] m_axis_cq_requesterid = m_axis_cq_tdata_hdr[31:16]; 98 | 99 | assign {m_axis_cq_fmt, m_axis_cq_type} = m_axis_cq_tdata_hdr[14:11] == 4'b0000 ? 8'b000_00000 : //Mem read Request 100 | m_axis_cq_tdata_hdr[14:11] == 4'b0111 ? 8'b000_00001 : //Mem Read request-locked 101 | m_axis_cq_tdata_hdr[14:11] == 4'b0001 ? 8'b010_00000 : //Mem write request 102 | m_axis_cq_tdata_hdr[14:11] == 4'b0010 ? 8'b000_00010 : //I/O Read request 103 | m_axis_cq_tdata_hdr[14:11] == 4'b0011 ? 8'b010_00010 : //I/O Write request 104 | m_axis_cq_tdata_hdr[14:11] == 4'b1000 ? 8'b000_00100 : //Cfg Read Type 0 105 | m_axis_cq_tdata_hdr[14:11] == 4'b1010 ? 8'b010_00100 : //Cfg Write Type 0 106 | m_axis_cq_tdata_hdr[14:11] == 4'b1001 ? 8'b000_00101 : //Cfg Read Type 1 107 | m_axis_cq_tdata_hdr[14:11] == 4'b1011 ? 8'b010_00101 : //Cfg Write Type 1 108 | 8'b000_00000; //Mem read Request 109 | 110 | reg [7:0] m_axis_cq_tuser_barhit; 111 | always @(posedge user_clk) 112 | if (m_axis_cq_tvalid_a && m_axis_cq_sop) 113 | m_axis_cq_tuser_barhit <= {1'b0, m_axis_cq_tdata_hdr[50:48], m_axis_cq_tdata_hdr[14:11]}; //only valid @sop 114 | 115 | reg [63:0] m_axis_cq_header; 116 | always @(posedge user_clk) 117 | if (m_axis_cq_tvalid_a && m_axis_cq_sop) 118 | m_axis_cq_header = {m_axis_cq_requesterid, 119 | m_axis_cq_tag, 120 | m_axis_cq_be, 121 | m_axis_cq_fmt, m_axis_cq_type, 122 | 1'b0, m_axis_cq_tc, 4'b0, 123 | m_axis_cq_td, m_axis_cq_ep, m_axis_cq_attr, 124 | 2'b0, m_axis_cq_dwlen}; 125 | 126 | assign m_axis_cq_tdata = (m_axis_cq_rdwr_l | m_axis_cq_second) ? {m_axis_cq_tdata_a[31:0], m_axis_cq_tdata_a1[255:128], m_axis_cq_tdata_a1[31:0], m_axis_cq_header} : 127 | {m_axis_cq_tdata_a[31:0], m_axis_cq_tdata_a1[255:32]}; 128 | assign m_axis_cq_tkeep = m_axis_cq_rdwr_l ? {4'b0, m_axis_cq_tlast_be1[31:16], 12'hFFF} : 129 | m_axis_cq_tlast_lat ? {4'b0, m_axis_cq_tlast_be1[31:4]} : 32'hFFFF_FFFF; 130 | assign m_axis_cq_tuser = { 131 | 5'b0, //rx_is_eof only for 128-bit I/F 132 | 2'b0, //reserved 133 | 5'b0, //m_axis_cq_tuser_a[40],4'b0, //rx_is_sof only for 128-bit I/F 134 | m_axis_cq_tuser_barhit, 135 | 1'b0, //rx_err_fwd -> no equivalent 136 | m_axis_cq_tuser_a[41] //ECRC mapped to discontinue 137 | }; 138 | 139 | endmodule -------------------------------------------------------------------------------- /litepcie/phy/xilinx_usp/m_axis_cq_adapt_256b.v: -------------------------------------------------------------------------------- 1 | // This file is part of LitePCIe. 2 | // 3 | // Copyright (c) 2020-2023 Enjoy-Digital 4 | // SPDX-License-Identifier: BSD-2-Clause 5 | 6 | module m_axis_cq_adapt # ( 7 | parameter DATA_WIDTH = 256, 8 | parameter KEEP_WIDTH = DATA_WIDTH/8 9 | )( 10 | 11 | input user_clk, 12 | input user_reset, 13 | 14 | output [DATA_WIDTH-1:0] m_axis_cq_tdata, 15 | output [KEEP_WIDTH-1:0] m_axis_cq_tkeep, 16 | output m_axis_cq_tlast, 17 | input [3:0] m_axis_cq_tready, 18 | output [84:0] m_axis_cq_tuser, 19 | output m_axis_cq_tvalid, 20 | 21 | input [DATA_WIDTH-1:0] m_axis_cq_tdata_a, 22 | input [KEEP_WIDTH/4-1:0] m_axis_cq_tkeep_a, 23 | input m_axis_cq_tlast_a, 24 | output [3:0] m_axis_cq_tready_a, 25 | input [84:0] m_axis_cq_tuser_a, 26 | input m_axis_cq_tvalid_a 27 | ); 28 | 29 | //dword counter: //0-2 & latch 30 | reg [1:0] m_axis_cq_cnt; 31 | always @(posedge user_clk) 32 | if (user_reset) m_axis_cq_cnt <= 2'd0; 33 | else if (m_axis_cq_tvalid_a && m_axis_cq_tready_a) 34 | begin 35 | if (m_axis_cq_tlast_a) m_axis_cq_cnt <= 2'd0; 36 | else if (!m_axis_cq_cnt[1]) m_axis_cq_cnt <= m_axis_cq_cnt + 1; 37 | end 38 | 39 | wire m_axis_cq_sop = (m_axis_cq_cnt == 0) && (!m_axis_cq_tlast_lat); //m_axis_cq_tuser_a[40] 40 | wire m_axis_cq_second = m_axis_cq_cnt == 1; 41 | 42 | reg m_axis_cq_rdwr_l; 43 | always @(posedge user_clk) 44 | if (user_reset) m_axis_cq_rdwr_l <= 1'd0; 45 | else if (m_axis_cq_tvalid_a && m_axis_cq_sop) m_axis_cq_rdwr_l <= m_axis_cq_tlast_a; 46 | 47 | //processing for tlast: generate new last in case write & last num of dword != 5 + i*8 48 | wire m_axis_cq_read = (m_axis_cq_fmt[1:0] == 2'b0); //Read request 49 | wire m_axis_cq_write = !m_axis_cq_read; 50 | wire [9:0] m_axis_cq_dwlen; 51 | reg m_axis_cq_tlast_dly_en; 52 | always @(posedge user_clk) 53 | if (user_reset) m_axis_cq_tlast_dly_en <= 1'd0; 54 | else if (m_axis_cq_tlast_lat && m_axis_cq_tready) m_axis_cq_tlast_dly_en <= 1'd0; 55 | else if (m_axis_cq_tvalid_a && m_axis_cq_sop) m_axis_cq_tlast_dly_en <= m_axis_cq_tlast_a | (m_axis_cq_dwlen[2:0] != 3'd5); 56 | 57 | reg m_axis_cq_tlast_lat; 58 | always @(posedge user_clk) 59 | if (user_reset) m_axis_cq_tlast_lat <= 1'd0; 60 | else if (m_axis_cq_tlast_lat && m_axis_cq_tready) m_axis_cq_tlast_lat <= 1'd0; 61 | else if (m_axis_cq_tvalid_a && m_axis_cq_tready_a && m_axis_cq_tlast_a) 62 | begin 63 | if (m_axis_cq_sop) m_axis_cq_tlast_lat <= 1'b1; 64 | else if (m_axis_cq_tlast_dly_en) m_axis_cq_tlast_lat <= 1'b1; 65 | end 66 | 67 | //Generae ready for PCIe IP 68 | assign m_axis_cq_tready_a = ((m_axis_cq_cnt == 0) | m_axis_cq_tready) && (!m_axis_cq_tlast_lat); 69 | 70 | //output for TLP 71 | assign m_axis_cq_tlast = m_axis_cq_tlast_dly_en ? m_axis_cq_tlast_lat : m_axis_cq_tlast_a; 72 | assign m_axis_cq_tvalid = (m_axis_cq_tvalid_a & (|m_axis_cq_cnt)) | m_axis_cq_tlast_lat; 73 | 74 | 75 | ////keep address (low) or data (high), not header 76 | reg [255:0] m_axis_cq_tdata_a1; 77 | reg [31:0] m_axis_cq_tlast_be1; 78 | always @(posedge user_clk) 79 | if (m_axis_cq_tvalid_a && m_axis_cq_tready_a) 80 | begin 81 | m_axis_cq_tdata_a1 <= m_axis_cq_tdata_a; 82 | m_axis_cq_tlast_be1 <= m_axis_cq_tuser_a[39:8]; 83 | end 84 | 85 | //data processing 86 | wire [63:0] m_axis_cq_tdata_hdr = m_axis_cq_tdata_a[127:64]; 87 | 88 | assign m_axis_cq_dwlen = m_axis_cq_tdata_hdr[9:0]; 89 | wire [1:0] m_axis_cq_attr = m_axis_cq_tdata_hdr[61:60]; 90 | wire m_axis_cq_ep = 1'b0; 91 | wire m_axis_cq_td = 1'b0; 92 | wire [2:0] m_axis_cq_tc = m_axis_cq_tdata_hdr[59:57]; 93 | wire [4:0] m_axis_cq_type; 94 | wire [2:0] m_axis_cq_fmt; 95 | wire [7:0] m_axis_cq_be = m_axis_cq_tuser_a[7:0]; 96 | wire [7:0] m_axis_cq_tag = m_axis_cq_tdata_hdr[39:32]; 97 | wire [15:0] m_axis_cq_requesterid = m_axis_cq_tdata_hdr[31:16]; 98 | 99 | assign {m_axis_cq_fmt, m_axis_cq_type} = m_axis_cq_tdata_hdr[14:11] == 4'b0000 ? 8'b000_00000 : //Mem read Request 100 | m_axis_cq_tdata_hdr[14:11] == 4'b0111 ? 8'b000_00001 : //Mem Read request-locked 101 | m_axis_cq_tdata_hdr[14:11] == 4'b0001 ? 8'b010_00000 : //Mem write request 102 | m_axis_cq_tdata_hdr[14:11] == 4'b0010 ? 8'b000_00010 : //I/O Read request 103 | m_axis_cq_tdata_hdr[14:11] == 4'b0011 ? 8'b010_00010 : //I/O Write request 104 | m_axis_cq_tdata_hdr[14:11] == 4'b1000 ? 8'b000_00100 : //Cfg Read Type 0 105 | m_axis_cq_tdata_hdr[14:11] == 4'b1010 ? 8'b010_00100 : //Cfg Write Type 0 106 | m_axis_cq_tdata_hdr[14:11] == 4'b1001 ? 8'b000_00101 : //Cfg Read Type 1 107 | m_axis_cq_tdata_hdr[14:11] == 4'b1011 ? 8'b010_00101 : //Cfg Write Type 1 108 | 8'b000_00000; //Mem read Request 109 | 110 | reg [7:0] m_axis_cq_tuser_barhit; 111 | always @(posedge user_clk) 112 | if (m_axis_cq_tvalid_a && m_axis_cq_sop) 113 | m_axis_cq_tuser_barhit <= {1'b0, m_axis_cq_tdata_hdr[50:48], m_axis_cq_tdata_hdr[14:11]}; //only valid @sop 114 | 115 | reg [63:0] m_axis_cq_header; 116 | always @(posedge user_clk) 117 | if (m_axis_cq_tvalid_a && m_axis_cq_sop) 118 | m_axis_cq_header = {m_axis_cq_requesterid, 119 | m_axis_cq_tag, 120 | m_axis_cq_be, 121 | m_axis_cq_fmt, m_axis_cq_type, 122 | 1'b0, m_axis_cq_tc, 4'b0, 123 | m_axis_cq_td, m_axis_cq_ep, m_axis_cq_attr, 124 | 2'b0, m_axis_cq_dwlen}; 125 | 126 | assign m_axis_cq_tdata = (m_axis_cq_rdwr_l | m_axis_cq_second) ? {m_axis_cq_tdata_a[31:0], m_axis_cq_tdata_a1[255:128], m_axis_cq_tdata_a1[31:0], m_axis_cq_header} : 127 | {m_axis_cq_tdata_a[31:0], m_axis_cq_tdata_a1[255:32]}; 128 | assign m_axis_cq_tkeep = m_axis_cq_rdwr_l ? {4'b0, m_axis_cq_tlast_be1[31:16], 12'hFFF} : 129 | m_axis_cq_tlast_lat ? {4'b0, m_axis_cq_tlast_be1[31:4]} : 32'hFFFF_FFFF; 130 | assign m_axis_cq_tuser = { 131 | 5'b0, //rx_is_eof only for 128-bit I/F 132 | 2'b0, //reserved 133 | 5'b0, //m_axis_cq_tuser_a[40],4'b0, //rx_is_sof only for 128-bit I/F 134 | m_axis_cq_tuser_barhit, 135 | 1'b0, //rx_err_fwd -> no equivalent 136 | m_axis_cq_tuser_a[41] //ECRC mapped to discontinue 137 | }; 138 | 139 | endmodule --------------------------------------------------------------------------------