├── .gitmodules ├── README.md ├── firmware ├── Makefile ├── axi_mmap.c ├── isr.c ├── linker.ld ├── main.c ├── sim_debug.c └── sim_debug.h ├── setup.py ├── test_axi.py ├── test_axi2axi_lite.py ├── test_axi_lite.py └── verilog_axi ├── __init__.py ├── axi ├── __init__.py ├── axi_adapter.py ├── axi_cdma.py ├── axi_crossbar.py ├── axi_dma.py ├── axi_dp_ram.py ├── axi_fifo.py ├── axi_interconnect.py ├── axi_ram.py └── axi_register.py ├── axi_axil_adapter.py ├── axi_common.py └── axi_lite ├── __init__.py ├── axil_adapter.py ├── axil_cdc.py ├── axil_crossbar.py ├── axil_dp_ram.py ├── axil_interconnect.py ├── axil_ram.py └── axil_register.py /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "verilog_axi/verilog"] 2 | path = verilog_axi/verilog 3 | url = https://github.com/alexforencich/verilog-axi 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [> Intro 2 | -------- 3 | This repository is an experiment to wrap Alex Forenchich's Verilog-AXI core with LiteX to easily compose AXI systems with it. 4 | 5 | [> AXI-Lite Status 6 | --------------------- 7 | 8 | | Module | Status | 9 | |-------------------|----------------------------| 10 | | axil_adapter | Done, passing simple tests | 11 | | axil_cdc | Done, passing simple tests | 12 | | axil_crossbar | Done, passing simple tests | 13 | | axil_dp_ram | Done, passing simple tests | 14 | | axil_interconnect | Done, passing simple tests | 15 | | axil_ram | Done, passing simple tests | 16 | | axil_register | Done, passing simple tests | 17 | 18 | [> AXI <-> AXI-Lite Status 19 | -------------------------- 20 | 21 | | Module | Status | 22 | |-------------------|--------------------------------------------------| 23 | | axi_axil_adapter | Done, passing simple tests | 24 | 25 | [> AXI Status 26 | ---------------- 27 | 28 | | Module | Status | 29 | |-------------------|--------------------------------------------------| 30 | | axi_adapter | Done, Verilator compil issue | 31 | | axi_cdma | Wrapped, need testing | 32 | | axi_crossbar | Done, passing simple tests | 33 | | axi_dma | Wrapped, need testing | 34 | | axi_dp_ram | Done, passing simple tests | 35 | | axi_fifo | Done, passing simple tests | 36 | | axi_interconnect | Done, passing simple tests | 37 | | axi_ram | Done, passing simple tests | 38 | | axi _register | Done, passing simple tests | 39 | -------------------------------------------------------------------------------- /firmware/Makefile: -------------------------------------------------------------------------------- 1 | BUILD_DIR?=../build/sim 2 | 3 | include $(BUILD_DIR)/software/include/generated/variables.mak 4 | include $(SOC_DIRECTORY)/software/common.mak 5 | 6 | OBJECTS = crt0.o sim_debug.o axi_mmap.o main.o 7 | 8 | all: firmware.bin 9 | 10 | 11 | %.bin: %.elf 12 | $(OBJCOPY) -O binary $< $@ 13 | ifneq ($(OS),Windows_NT) 14 | chmod -x $@ 15 | endif 16 | 17 | vpath %.a $(PACKAGES:%=../%) 18 | 19 | firmware.elf: $(OBJECTS) 20 | $(CC) $(LDFLAGS) -T linker.ld -N -o $@ \ 21 | $(OBJECTS) \ 22 | $(PACKAGES:%=-L$(BUILD_DIR)/software/%) \ 23 | -Wl,--whole-archive \ 24 | -Wl,--gc-sections \ 25 | -Wl,-Map,$@.map \ 26 | $(LIBS:lib%=-l%) 27 | 28 | ifneq ($(OS),Windows_NT) 29 | chmod -x $@ 30 | endif 31 | 32 | # pull in dependency info for *existing* .o files 33 | -include $(OBJECTS:.o=.d) 34 | 35 | VPATH = $(BIOS_DIRECTORY):$(BIOS_DIRECTORY)/cmds:$(CPU_DIRECTORY) 36 | 37 | %.o: %.c 38 | $(compile) 39 | 40 | %.o: %.S 41 | $(assemble) 42 | 43 | clean: 44 | $(RM) $(OBJECTS) *.elf *.bin *.d *.map .*~ *~ 45 | 46 | .PHONY: all clean 47 | -------------------------------------------------------------------------------- /firmware/axi_mmap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "axi_mmap.h" 11 | 12 | /* Test RAM */ 13 | void test_ram(char * name, uint32_t base) { 14 | volatile uint32_t *axi_ram = (uint32_t *) base; 15 | 16 | int errors = 0; 17 | 18 | printf("\nTesting %s at @0x%08x...\n", name, base); 19 | 20 | /* Very simple test */ 21 | axi_ram[0] = 0x5aa55aa5; 22 | axi_ram[1] = 0x12345678; 23 | if (axi_ram[0] != 0x5aa55aa5) 24 | errors++; 25 | if (axi_ram[1] != 0x12345678) 26 | errors++; 27 | 28 | /* Result */ 29 | printf("errors: %d\n", errors); 30 | } 31 | -------------------------------------------------------------------------------- /firmware/isr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void isr(void); 8 | 9 | void isr(void) 10 | { 11 | __attribute__((unused)) unsigned int irqs; 12 | 13 | irqs = irq_pending() & irq_getmask(); 14 | 15 | #ifndef UART_POLLING 16 | if(irqs & (1 << UART_INTERRUPT)) 17 | uart_isr(); 18 | #endif 19 | 20 | } 21 | -------------------------------------------------------------------------------- /firmware/linker.ld: -------------------------------------------------------------------------------- 1 | INCLUDE generated/output_format.ld 2 | ENTRY(_start) 3 | 4 | __DYNAMIC = 0; 5 | 6 | INCLUDE generated/regions.ld 7 | 8 | SECTIONS 9 | { 10 | .text : 11 | { 12 | _ftext = .; 13 | /* Make sure crt0 files come first, and they, and the isr */ 14 | /* don't get disposed of by greedy optimisation */ 15 | *crt0*(.text) 16 | KEEP(*crt0*(.text)) 17 | KEEP(*(.text.isr)) 18 | 19 | *(.text .stub .text.* .gnu.linkonce.t.*) 20 | _etext = .; 21 | } > main_ram 22 | 23 | .rodata : 24 | { 25 | . = ALIGN(8); 26 | _frodata = .; 27 | *(.rodata .rodata.* .gnu.linkonce.r.*) 28 | *(.rodata1) 29 | . = ALIGN(8); 30 | _erodata = .; 31 | } > main_ram 32 | 33 | .data : 34 | { 35 | . = ALIGN(8); 36 | _fdata = .; 37 | *(.data .data.* .gnu.linkonce.d.*) 38 | *(.data1) 39 | _gp = ALIGN(16); 40 | *(.sdata .sdata.* .gnu.linkonce.s.*) 41 | . = ALIGN(8); 42 | _edata = .; 43 | } > sram AT > main_ram 44 | 45 | .bss : 46 | { 47 | . = ALIGN(8); 48 | _fbss = .; 49 | *(.dynsbss) 50 | *(.sbss .sbss.* .gnu.linkonce.sb.*) 51 | *(.scommon) 52 | *(.dynbss) 53 | *(.bss .bss.* .gnu.linkonce.b.*) 54 | *(COMMON) 55 | . = ALIGN(8); 56 | _ebss = .; 57 | _end = .; 58 | } > sram 59 | } 60 | 61 | PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram)); 62 | 63 | PROVIDE(_fdata_rom = LOADADDR(.data)); 64 | PROVIDE(_edata_rom = LOADADDR(.data) + SIZEOF(.data)); 65 | -------------------------------------------------------------------------------- /firmware/main.c: -------------------------------------------------------------------------------- 1 | // This file is Copyright (c) 2020-2022 Florent Kermarrec 2 | // License: BSD 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "sim_debug.h" 15 | #include "axi_mmap.h" 16 | 17 | /*-----------------------------------------------------------------------*/ 18 | /* UART */ 19 | /*-----------------------------------------------------------------------*/ 20 | 21 | static char *readstr(void) 22 | { 23 | char c[2]; 24 | static char s[64]; 25 | static int ptr = 0; 26 | 27 | if(readchar_nonblock()) { 28 | c[0] = getchar(); 29 | c[1] = 0; 30 | switch(c[0]) { 31 | case 0x7f: 32 | case 0x08: 33 | if(ptr > 0) { 34 | ptr--; 35 | fputs("\x08 \x08", stdout); 36 | } 37 | break; 38 | case 0x07: 39 | break; 40 | case '\r': 41 | case '\n': 42 | s[ptr] = 0x00; 43 | fputs("\n", stdout); 44 | ptr = 0; 45 | return s; 46 | default: 47 | if(ptr >= (sizeof(s) - 1)) 48 | break; 49 | fputs(c, stdout); 50 | s[ptr] = c[0]; 51 | ptr++; 52 | break; 53 | } 54 | } 55 | 56 | return NULL; 57 | } 58 | 59 | static char *get_token(char **str) 60 | { 61 | char *c, *d; 62 | 63 | c = (char *)strchr(*str, ' '); 64 | if(c == NULL) { 65 | d = *str; 66 | *str = *str+strlen(*str); 67 | return d; 68 | } 69 | *c = 0; 70 | d = *str; 71 | *str = c+1; 72 | return d; 73 | } 74 | 75 | static void prompt(void) 76 | { 77 | printf("\e[92;1maxi-mmap\e[0m> "); 78 | } 79 | 80 | /*-----------------------------------------------------------------------*/ 81 | /* Help */ 82 | /*-----------------------------------------------------------------------*/ 83 | 84 | static void help(void) 85 | { 86 | puts("\nAXI-MMAP test firmware built "__DATE__" "__TIME__"\n"); 87 | puts("Available commands:"); 88 | puts("help - Show this command"); 89 | puts("reboot - Reboot CPU"); 90 | } 91 | 92 | /*-----------------------------------------------------------------------*/ 93 | /* Commands */ 94 | /*-----------------------------------------------------------------------*/ 95 | 96 | static void reboot_cmd(void) 97 | { 98 | ctrl_reset_write(1); 99 | } 100 | 101 | /*-----------------------------------------------------------------------*/ 102 | /* Console service / Main */ 103 | /*-----------------------------------------------------------------------*/ 104 | 105 | static void console_service(void) 106 | { 107 | char *str; 108 | char *token; 109 | 110 | str = readstr(); 111 | if(str == NULL) return; 112 | token = get_token(&str); 113 | if(strcmp(token, "help") == 0) 114 | help(); 115 | else if(strcmp(token, "reboot") == 0) 116 | reboot_cmd(); 117 | prompt(); 118 | } 119 | 120 | int main(void) 121 | { 122 | 123 | #ifdef CONFIG_CPU_HAS_INTERRUPT 124 | irq_setmask(0); 125 | irq_setie(1); 126 | #endif 127 | uart_init(); 128 | 129 | /* Tests. */ 130 | test_ram("AXI-RAM", AXI_RAM_BASE); 131 | test_ram("AXI-DP-RAM-A", AXI_DP_RAM_A_BASE); 132 | test_ram("AXI-DP-RAM-B", AXI_DP_RAM_B_BASE); 133 | test_ram("AXI-RAM-REG", AXI_RAM_REG_BASE); 134 | test_ram("AXI-RAM-FIFO", AXI_RAM_FIFO_BASE); 135 | test_ram("AXI-RAM-XBAR", AXI_RAM_XBAR_BASE); 136 | test_ram("AXI-RAM-INT", AXI_RAM_INT_BASE); 137 | 138 | /* Console */ 139 | help(); 140 | prompt(); 141 | while(1) { 142 | console_service(); 143 | } 144 | 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /firmware/sim_debug.c: -------------------------------------------------------------------------------- 1 | #include "sim_debug.h" 2 | 3 | #include 4 | #include 5 | 6 | // 0 is used as no marker 7 | #define MAX_N_MARKERS (255 - 1) 8 | 9 | #ifdef CSR_SIM_MARKER_BASE 10 | static int n_markers = 0; 11 | static const char *markers[MAX_N_MARKERS] = {0}; 12 | #endif 13 | 14 | void sim_mark(const char *text) { 15 | #ifdef CSR_SIM_MARKER_BASE 16 | if (text == NULL) { 17 | text = "NO COMMENT"; 18 | } 19 | // 0 is not used 20 | int marker_num = n_markers + 1; 21 | markers[n_markers++] = text; 22 | sim_marker_marker_write(marker_num); 23 | if (n_markers >= MAX_N_MARKERS) { 24 | printf("Max number of markers reached\n"); 25 | n_markers = 0; 26 | } 27 | #else 28 | printf("No sim_marker CSR\n"); 29 | #endif 30 | } 31 | 32 | void sim_markers_summary(void) { 33 | #ifdef CSR_SIM_MARKER_BASE 34 | printf("\nMarkers:\n"); 35 | for (int i = 0; i < n_markers; ++i) { 36 | printf(" %3d: %s\n", i + 1, markers[i]); 37 | } 38 | printf("\n"); 39 | #else 40 | printf("No sim_marker CSR\n"); 41 | #endif 42 | } 43 | 44 | void sim_trace(int on) { 45 | #ifdef CSR_SIM_TRACE_BASE 46 | sim_trace_enable_write(on); 47 | #else 48 | printf("No sim_trace CSR\n"); 49 | #endif 50 | } 51 | 52 | int sim_trace_on(void) { 53 | #ifdef CSR_SIM_TRACE_BASE 54 | return sim_trace_enable_read(); 55 | #else 56 | printf("No sim_trace CSR\n"); 57 | return 0; 58 | #endif 59 | } 60 | 61 | void sim_finish(void) { 62 | #ifdef CSR_SIM_FINISH_BASE 63 | sim_trace(0); 64 | if (n_markers > 0) { 65 | sim_markers_summary(); 66 | } 67 | sim_finish_finish_write(1); 68 | #else 69 | printf("No sim_finish CSR\n"); 70 | #endif 71 | } 72 | -------------------------------------------------------------------------------- /firmware/sim_debug.h: -------------------------------------------------------------------------------- 1 | #ifndef __SIM_DEBUG_H 2 | #define __SIM_DEBUG_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | // add next marker with given comment 9 | void sim_mark(const char *comment); 10 | #define sim_mark_func() sim_mark(__func__) 11 | // print the summary of markers mapping (number -> comment) 12 | void sim_markers_summary(void); 13 | // enable simulation trace dump 14 | void sim_trace(int on); 15 | // check if trace is on 16 | int sim_trace_on(void); 17 | // finish simulation 18 | void sim_finish(void); 19 | 20 | #ifdef __cplusplus 21 | } 22 | #endif 23 | 24 | #endif 25 | 26 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from setuptools import setup 4 | from setuptools import find_packages 5 | 6 | 7 | setup( 8 | name="litex_verilog_axi_test", 9 | description="LiteX Wrappers around Alex Forenchich's Verilog-AXI.", 10 | author="Florent Kermarrec", 11 | author_email="florent@enjoy-digital.fr", 12 | url="http://enjoy-digital.fr", 13 | download_url="https://github.com/enjoy-digital/litex_verilog_axi_test", 14 | test_suite="test", 15 | license="BSD", 16 | python_requires="~=3.6", 17 | install_requires=[], 18 | packages=find_packages(exclude=("test*", "sim*", "doc*")), 19 | include_package_data=True, 20 | platforms=["Any"], 21 | keywords="HDL ASIC FPGA hardware design", 22 | classifiers=[ 23 | "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", 24 | "Environment :: Console", 25 | "Development Status :: Alpha", 26 | "Intended Audience :: Developers", 27 | "License :: OSI Approved :: BSD License", 28 | "Operating System :: OS Independent", 29 | "Programming Language :: Python", 30 | ], 31 | ) 32 | -------------------------------------------------------------------------------- /test_axi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # This file is part of LiteX-Verilog-AXI-Test 5 | # 6 | # Copyright (c) 2022 Florent Kermarrec 7 | # SPDX-License-Identifier: BSD-2-Clause 8 | 9 | import argparse 10 | 11 | from migen import * 12 | 13 | from litex.build.generic_platform import * 14 | from litex.build.sim import SimPlatform 15 | from litex.build.sim.config import SimConfig 16 | from litex.build.sim.verilator import verilator_build_args, verilator_build_argdict 17 | 18 | from litex.soc.interconnect.csr import * 19 | from litex.soc.integration.soc_core import * 20 | from litex.soc.integration.soc import SoCRegion 21 | from litex.soc.integration.builder import * 22 | from litex.soc.interconnect.axi import * 23 | 24 | from verilog_axi.axi_common import * 25 | 26 | # IOs ---------------------------------------------------------------------------------------------- 27 | 28 | _io = [ 29 | # Clk / Rst. 30 | ("sys_clk", 0, Pins(1)), 31 | ("sys_rst", 0, Pins(1)), 32 | 33 | # Serial. 34 | ("serial", 0, 35 | Subsignal("source_valid", Pins(1)), 36 | Subsignal("source_ready", Pins(1)), 37 | Subsignal("source_data", Pins(8)), 38 | 39 | Subsignal("sink_valid", Pins(1)), 40 | Subsignal("sink_ready", Pins(1)), 41 | Subsignal("sink_data", Pins(8)), 42 | ), 43 | ] 44 | 45 | # Platform ----------------------------------------------------------------------------------------- 46 | 47 | class Platform(SimPlatform): 48 | name = "sim" 49 | def __init__(self): 50 | SimPlatform.__init__(self, "SIM", _io) 51 | 52 | # AXISimSoC ---------------------------------------------------------------------------------------- 53 | 54 | class AXISimSoC(SoCCore): 55 | def __init__(self, firmware=None): 56 | # Parameters. 57 | sys_clk_freq = int(100e6) 58 | 59 | # Platform. 60 | platform = Platform() 61 | self.comb += platform.trace.eq(1) 62 | 63 | # CRG -------------------------------------------------------------------------------------- 64 | self.submodules.crg = CRG(platform.request("sys_clk")) 65 | 66 | # SoCCore ---------------------------------------------------------------------------------- 67 | SoCCore.__init__(self, platform, clk_freq=sys_clk_freq, uart_name="sim", 68 | bus_standard ="axi-lite", 69 | integrated_rom_size = 0x10000, 70 | integrated_main_ram_size = 0x10000, 71 | integrated_main_ram_init = get_mem_data(firmware, endianness="little") 72 | ) 73 | self.add_config("BIOS_NO_DELAYS") 74 | self.add_constant("ROM_BOOT_ADDRESS", self.bus.regions["main_ram"].origin) 75 | 76 | # AXI Tests -------------------------------------------------------------------------------- 77 | def axi_syntax_test(): 78 | # AXI Adapter. 79 | # ------------ 80 | from verilog_axi.axi.axi_adapter import AXIAdapter 81 | s_axi = AXIInterface(data_width=32, address_width=32, id_width=8) 82 | m_axi = AXIInterface(data_width=32, address_width=32, id_width=8) 83 | self.submodules.axi_adapter = AXIAdapter(platform, s_axi, m_axi) 84 | 85 | # AXI RAM. 86 | # -------- 87 | from verilog_axi.axi.axi_ram import AXIRAM 88 | s_axi = AXIInterface(data_width=32, address_width=32, id_width=8) 89 | self.submodules.axi_ram = AXIRAM(platform, s_axi, size=0x1000) 90 | 91 | # AXI Register. 92 | # ------------- 93 | from verilog_axi.axi.axi_register import AXIRegister 94 | s_axi = AXIInterface(data_width=32, address_width=32, id_width=8) 95 | m_axi = AXIInterface(data_width=32, address_width=32, id_width=8) 96 | self.submodules.axi_register = AXIRegister(platform, s_axi, m_axi) 97 | 98 | # AXI FIFO. 99 | # --------- 100 | from verilog_axi.axi.axi_fifo import AXIFIFO 101 | s_axi = AXIInterface(data_width=32, address_width=32, id_width=8) 102 | m_axi = AXIInterface(data_width=32, address_width=32, id_width=8) 103 | self.submodules.axi_fifo = AXIFIFO(platform, s_axi, m_axi) 104 | 105 | # AXI DPRAM. 106 | # ---------- 107 | from verilog_axi.axi.axi_dp_ram import AXIDPRAM 108 | s_axi_a = AXIInterface(data_width=32, address_width=32, id_width=8) 109 | s_axi_b = AXIInterface(data_width=32, address_width=32, id_width=8) 110 | self.submodules.axi_dp_ram = AXIDPRAM(platform, s_axi_a, s_axi_b, size=0x1000) 111 | 112 | # AXI Crossbar. 113 | # ------------- 114 | from verilog_axi.axi.axi_crossbar import AXICrossbar 115 | self.submodules.axi_crossbar = AXICrossbar(platform) 116 | self.axi_crossbar.add_slave(s_axi=AXIInterface(data_width=32, address_width=32, id_width=8)) 117 | self.axi_crossbar.add_slave(s_axi=AXIInterface(data_width=32, address_width=32, id_width=8)) 118 | self.axi_crossbar.add_master(m_axi=AXIInterface(data_width=32, address_width=32, id_width=8), origin=0x0000_0000, size=0x0100_0000) 119 | self.axi_crossbar.add_master(m_axi=AXIInterface(data_width=32, address_width=32, id_width=8), origin=0x1000_0000, size=0x0100_0000) 120 | 121 | # AXI Interconnect. 122 | # ----------------- 123 | from verilog_axi.axi.axi_interconnect import AXIInterconnect 124 | self.submodules.axi_interconnect = AXIInterconnect(platform) 125 | self.axi_interconnect.add_slave(s_axi=AXIInterface(data_width=32, address_width=32, id_width=8)) 126 | self.axi_interconnect.add_slave(s_axi=AXIInterface(data_width=32, address_width=32, id_width=8)) 127 | self.axi_interconnect.add_master(m_axi=AXIInterface(data_width=32, address_width=32, id_width=8), origin=0x0000_0000, size=0x0100_0000) 128 | self.axi_interconnect.add_master(m_axi=AXIInterface(data_width=32, address_width=32, id_width=8), origin=0x1000_0000, size=0x0100_0000) 129 | 130 | # AXI CDMA. 131 | # --------- 132 | from verilog_axi.axi.axi_cdma import AXICDMA 133 | m_axi = AXIInterface(data_width=32, address_width=32, id_width=8) 134 | self.submodules.axi_cdma = AXICDMA(platform, m_axi) 135 | 136 | # AXI DMA. 137 | # -------- 138 | from verilog_axi.axi.axi_dma import AXIDMA 139 | m_axi = AXIInterface(data_width=32, address_width=32, id_width=8) 140 | self.submodules.axi_dma = AXIDMA(platform, m_axi) 141 | 142 | def axi_integration_test(): 143 | # AXI Test Mapping. 144 | # ----------------- 145 | axi_map = { 146 | "axi_ram" : 0x010000, 147 | "axi_dp_ram_a" : 0x011000, 148 | "axi_dp_ram_b" : 0x012000, 149 | "axi_ram_reg" : 0x013000, 150 | "axi_ram_fifo" : 0x014000, 151 | "axi_ram_xbar" : 0x100000, 152 | "axi_ram_int" : 0x200000, 153 | } 154 | 155 | # Add AXI RAM to SoC. 156 | # ------------------- 157 | 158 | # Test from LiteX BIOS: 159 | # mem_list 160 | # mem_write 0x5aa55aa5 161 | # mem_read 32 162 | 163 | # 1) Create AXI interface and connect it to SoC. 164 | s_axi = AXIInterface(data_width=32, address_width=32, id_width=1) 165 | self.bus.add_slave("axi_ram", s_axi, region=SoCRegion(origin=axi_map["axi_ram"], size=0x1000)) 166 | # 2) Add AXIRAM. 167 | from verilog_axi.axi.axi_ram import AXIRAM 168 | self.submodules += AXIRAM(platform, s_axi, size=0x1000) 169 | # 3) Debug. 170 | if 0: 171 | self.submodules += AXIAWDebug(s_axi, name="AXIRAM") 172 | self.submodules += AXIWDebug(s_axi, name="AXIRAM") 173 | self.submodules += AXIARDebug(s_axi, name="AXIRAM") 174 | self.submodules += AXIRDebug(s_axi, name="AXIRAM") 175 | 176 | # Add AXI DP RAM to SoC. 177 | # ---------------------- 178 | 179 | # Test from LiteX BIOS: 180 | # mem_list 181 | # mem_write 0x5aa55aa5 182 | # mem_read 32 183 | # mem_write 0xa55aa55a 184 | # mem_read 32 185 | 186 | # 1) Create AXI interfaces and connect them to SoC. 187 | s_axi_a = AXIInterface(data_width=32, address_width=32, id_width=1) 188 | s_axi_b = AXIInterface(data_width=32, address_width=32, id_width=1) 189 | self.bus.add_slave("axi_dp_ram_a", s_axi_a, region=SoCRegion(origin=axi_map["axi_dp_ram_a"], size=0x1000)) 190 | self.bus.add_slave("axi_dp_ram_b", s_axi_b, region=SoCRegion(origin=axi_map["axi_dp_ram_b"], size=0x1000)) 191 | # 2) Add AXIDPRAM. 192 | from verilog_axi.axi.axi_dp_ram import AXIDPRAM 193 | self.submodules += AXIDPRAM(platform, s_axi_a, s_axi_b, size=0x1000) 194 | if 0: 195 | self.submodules += AXIAWDebug(s_axi_a, name="AXIDPRAM_A") 196 | self.submodules += AXIWDebug(s_axi_a, name="AXIDPRAM_A") 197 | self.submodules += AXIARDebug(s_axi_a, name="AXIDPRAM_A") 198 | self.submodules += AXIRDebug(s_axi_a, name="AXIDPRAM_A") 199 | self.submodules += AXIAWDebug(s_axi_b, name="AXIDPRAM_B") 200 | self.submodules += AXIWDebug(s_axi_b, name="AXIDPRAM_B") 201 | self.submodules += AXIARDebug(s_axi_b, name="AXIDPRAM_B") 202 | self.submodules += AXIRDebug(s_axi_b, name="AXIDPRAM_B") 203 | 204 | 205 | # Add AXI RAM to SoC (Through AXI Register). 206 | # ----------------------------------------- 207 | 208 | # Test from LiteX BIOS similar to AXI RAM but with AXI_RAM_REG_BASE. 209 | 210 | # 1) Create AXI interface and connect it to SoC. 211 | s_axi = AXIInterface(data_width=32, address_width=32, id_width=1) 212 | self.bus.add_slave("axi_ram_reg", s_axi, region=SoCRegion(origin=axi_map["axi_ram_reg"], size=0x1000)) 213 | # 2) Add AXIRegister. 214 | from verilog_axi.axi.axi_register import AXIRegister 215 | s_axi_reg = AXIInterface(data_width=32, address_width=32, id_width=1) 216 | self.submodules += AXIRegister(platform, s_axi, s_axi_reg) 217 | # 3) Add AXISRAM. 218 | from verilog_axi.axi.axi_ram import AXIRAM 219 | self.submodules += AXIRAM(platform, s_axi_reg, size=0x1000) 220 | 221 | 222 | # Add AXI RAM to SoC (Through AXI FIFO). 223 | # -------------------------------------- 224 | 225 | # Test from LiteX BIOS similar to AXI RAM but with AXI_RAM_FIFO_BASE. 226 | 227 | # 1) Create AXI interface and connect it to SoC. 228 | s_axi = AXIInterface(data_width=32, address_width=32, id_width=1) 229 | self.bus.add_slave("axi_ram_fifo", s_axi, region=SoCRegion(origin=axi_map["axi_ram_fifo"], size=0x1000)) 230 | # 2) Add AXIFIFO. 231 | from verilog_axi.axi.axi_fifo import AXIFIFO 232 | s_axi_fifo = AXIInterface(data_width=32, address_width=32, id_width=1) 233 | self.submodules += AXIFIFO(platform, s_axi, s_axi_fifo) 234 | # 3) Add AXISRAM. 235 | from verilog_axi.axi.axi_ram import AXIRAM 236 | self.submodules += AXIRAM(platform, s_axi_fifo, size=0x1000) 237 | 238 | # Add AXI RAM to SoC (Through AXI Crossbar). 239 | # ------------------------------------------ 240 | 241 | # Test from LiteX BIOS similar to AXI RAM but with AXI_RAM_XBAR_BASE. 242 | 243 | # 1) Create AXI interface and connect it to SoC. 244 | s_axi = AXIInterface(data_width=32, address_width=32, id_width=1) 245 | self.bus.add_slave("axi_ram_xbar", s_axi, region=SoCRegion(origin=axi_map["axi_ram_xbar"], size=0x10000)) 246 | # 2) Add AXICrossbar (1 Slave / 3 Masters). 247 | from verilog_axi.axi.axi_crossbar import AXICrossbar 248 | self.submodules.axi_crossbar = AXICrossbar(platform) 249 | self.axi_crossbar.add_slave(s_axi=s_axi) 250 | m_axi_0 = AXIInterface(data_width=32, address_width=32, id_width=1) 251 | m_axi_1 = AXIInterface(data_width=32, address_width=32, id_width=1) 252 | m_axi_2 = AXIInterface(data_width=32, address_width=32, id_width=1) 253 | self.axi_crossbar.add_master(m_axi=m_axi_0, origin=axi_map["axi_ram_xbar"] + 0x0000, size=0x1000) 254 | self.axi_crossbar.add_master(m_axi=m_axi_1, origin=axi_map["axi_ram_xbar"] + 0x1000, size=0x1000) 255 | self.axi_crossbar.add_master(m_axi=m_axi_2, origin=axi_map["axi_ram_xbar"] + 0x2000, size=0x1000) 256 | # 3) Add 3 X AXISRAM. 257 | from verilog_axi.axi.axi_ram import AXIRAM 258 | self.submodules += AXIRAM(platform, m_axi_0, size=0x1000) 259 | self.submodules += AXIRAM(platform, m_axi_1, size=0x1000) 260 | self.submodules += AXIRAM(platform, m_axi_2, size=0x1000) 261 | 262 | # Add AXI RAM to SoC (Through AXI Interconnect). 263 | # ------------------------------------------ 264 | 265 | # Test from LiteX BIOS similar to AXI RAM but with AXI_RAM_INT_BASE. 266 | 267 | # 1) Create AXI interface and connect it to SoC. 268 | s_axi = AXIInterface(data_width=32, address_width=32) 269 | self.bus.add_slave("axi_ram_int", s_axi, region=SoCRegion(origin=axi_map["axi_ram_int"], size=0x10000)) 270 | # 2) Add AXIInterconnect (1 Slave / 3 Masters). 271 | from verilog_axi.axi.axi_interconnect import AXIInterconnect 272 | self.submodules.axi_interconnect = AXIInterconnect(platform) 273 | self.axi_interconnect.add_slave(s_axi=s_axi) 274 | m_axi_0 = AXIInterface(data_width=32, address_width=32, id_width=1) 275 | m_axi_1 = AXIInterface(data_width=32, address_width=32, id_width=1) 276 | m_axi_2 = AXIInterface(data_width=32, address_width=32, id_width=1) 277 | self.axi_interconnect.add_master(m_axi=m_axi_0, origin=axi_map["axi_ram_int"] + 0x0000, size=0x1000) 278 | self.axi_interconnect.add_master(m_axi=m_axi_1, origin=axi_map["axi_ram_int"] + 0x1000, size=0x1000) 279 | self.axi_interconnect.add_master(m_axi=m_axi_2, origin=axi_map["axi_ram_int"] + 0x2000, size=0x1000) 280 | # 3) Add 3 X AXISRAM. 281 | from verilog_axi.axi.axi_ram import AXIRAM 282 | self.submodules += AXIRAM(platform, m_axi_0, size=0x1000) 283 | self.submodules += AXIRAM(platform, m_axi_1, size=0x1000) 284 | self.submodules += AXIRAM(platform, m_axi_2, size=0x1000) 285 | # 4) Debug. 286 | if 0: 287 | for i, m_axi in enumerate([s_axi]): 288 | self.submodules += AXIAWDebug(s_axi, name=f"S_AXI_{i}") 289 | self.submodules += AXIWDebug(s_axi, name=f"S_AXI_{i}") 290 | self.submodules += AXIARDebug(s_axi, name=f"S_AXI_{i}") 291 | self.submodules += AXIRDebug(s_axi, name=f"S_AXI_{i}") 292 | for i, m_axi in enumerate([m_axi_0, m_axi_1, m_axi_2]): 293 | self.submodules += AXIAWDebug(m_axi, name=f"M_AXI_{i}") 294 | self.submodules += AXIWDebug(m_axi, name=f"M_AXI_{i}") 295 | self.submodules += AXIARDebug(m_axi, name=f"M_AXI_{i}") 296 | self.submodules += AXIRDebug(m_axi, name=f"M_AXI_{i}") 297 | 298 | axi_syntax_test() 299 | axi_integration_test() 300 | 301 | # Build -------------------------------------------------------------------------------------------- 302 | 303 | def main(): 304 | parser = argparse.ArgumentParser(description="LiteX Verilog AXI test simulation SoC ") 305 | verilator_build_args(parser) 306 | args = parser.parse_args() 307 | verilator_build_kwargs = verilator_build_argdict(args) 308 | sim_config = SimConfig(default_clk="sys_clk") 309 | sim_config.add_module("serial2console", "serial") 310 | 311 | for n in range(2): 312 | # Create SoC. 313 | soc = AXISimSoC(firmware={ 314 | 0 : None, # First loop with no firmware (to generate SoC's software headers). 315 | 1 : "firmware/firmware.bin" # Second loop with compiled firmware. 316 | }[n]) 317 | builder = Builder(soc) 318 | builder.build(sim_config=sim_config, **verilator_build_kwargs, run=n > 0) 319 | 320 | # Compile firmware on first loop. 321 | if (n == 0): 322 | os.system("cd firmware && make clean all") 323 | 324 | if __name__ == "__main__": 325 | main() 326 | -------------------------------------------------------------------------------- /test_axi2axi_lite.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # This file is part of LiteX-Verilog-AXI-Test 5 | # 6 | # Copyright (c) 2022 Florent Kermarrec 7 | # SPDX-License-Identifier: BSD-2-Clause 8 | 9 | import argparse 10 | 11 | from migen import * 12 | 13 | from litex.build.generic_platform import * 14 | from litex.build.sim import SimPlatform 15 | from litex.build.sim.config import SimConfig 16 | from litex.build.sim.verilator import verilator_build_args, verilator_build_argdict 17 | 18 | from litex.soc.interconnect.csr import * 19 | from litex.soc.integration.soc_core import * 20 | from litex.soc.integration.soc import SoCRegion 21 | from litex.soc.integration.builder import * 22 | from litex.soc.interconnect.axi import * 23 | 24 | from verilog_axi.axi_common import * 25 | 26 | # IOs ---------------------------------------------------------------------------------------------- 27 | 28 | _io = [ 29 | # Clk / Rst. 30 | ("sys_clk", 0, Pins(1)), 31 | ("sys_rst", 0, Pins(1)), 32 | 33 | # Serial. 34 | ("serial", 0, 35 | Subsignal("source_valid", Pins(1)), 36 | Subsignal("source_ready", Pins(1)), 37 | Subsignal("source_data", Pins(8)), 38 | 39 | Subsignal("sink_valid", Pins(1)), 40 | Subsignal("sink_ready", Pins(1)), 41 | Subsignal("sink_data", Pins(8)), 42 | ), 43 | ] 44 | 45 | # Platform ----------------------------------------------------------------------------------------- 46 | 47 | class Platform(SimPlatform): 48 | name = "sim" 49 | def __init__(self): 50 | SimPlatform.__init__(self, "SIM", _io) 51 | 52 | # AXISimSoC ---------------------------------------------------------------------------------------- 53 | 54 | class AXISimSoC(SoCCore): 55 | def __init__(self): 56 | # Parameters. 57 | sys_clk_freq = int(100e6) 58 | 59 | # Platform. 60 | platform = Platform() 61 | self.comb += platform.trace.eq(1) 62 | 63 | # CRG -------------------------------------------------------------------------------------- 64 | self.submodules.crg = CRG(platform.request("sys_clk")) 65 | 66 | # SoCCore ---------------------------------------------------------------------------------- 67 | SoCCore.__init__(self, platform, clk_freq=sys_clk_freq, bus_standard="axi-lite", uart_name="sim", integrated_rom_size=0x10000) 68 | self.add_config("BIOS_NO_BOOT") 69 | 70 | # AXI to AXI-Lite Tests -------------------------------------------------------------------- 71 | def axi2axi_lite_syntax_test(): 72 | from verilog_axi.axi_axil_adapter import AXI2AXILiteAdapter 73 | s_axi = AXIInterface(data_width=32, address_width=32, id_width=8) 74 | m_axi_lite = AXILiteInterface(data_width=32, address_width=32) 75 | self.submodules.axi_axi_lite_adapter = AXI2AXILiteAdapter(platform, s_axi, m_axi_lite) 76 | 77 | def axi2axi_lite_integration_test(): 78 | # AXI-Lite Test Mapping. 79 | # ---------------------- 80 | axil_map = { 81 | "axil_ram" : 0x010000, 82 | } 83 | # Add AXI-Lite RAM to SoC. 84 | # ------------------------ 85 | 86 | # Test from LiteX BIOS: 87 | # mem_list 88 | # mem_write 0x5aa55aa5 89 | # mem_read 32 90 | 91 | # 1) Create AXI-Lite interface and connect it to SoC. 92 | s_axi_lite = AXILiteInterface(data_width=32, address_width=32) 93 | self.bus.add_slave("axil_ram", s_axi_lite, region=SoCRegion(origin=axil_map["axil_ram"], size=0x1000)) 94 | # 2) Convert AXI-Lite interface to AXI interface. 95 | s_axi = AXIInterface(data_width=32, address_width=32, id_width=1) 96 | self.submodules += AXILite2AXI(s_axi_lite, s_axi) 97 | # 3) Convert AXI interface to AXI-Lite. 98 | s_axi_lite = AXILiteInterface(data_width=32, address_width=32) 99 | from verilog_axi.axi_axil_adapter import AXI2AXILiteAdapter 100 | self.submodules += AXI2AXILiteAdapter(platform, s_axi, s_axi_lite) 101 | # 4) Add AXILiteRAM. 102 | from verilog_axi.axi_lite.axil_ram import AXILiteRAM 103 | self.submodules += AXILiteRAM(platform, s_axi_lite, size=0x1000) 104 | 105 | axi2axi_lite_syntax_test() 106 | axi2axi_lite_integration_test() 107 | 108 | # Build -------------------------------------------------------------------------------------------- 109 | 110 | def main(): 111 | parser = argparse.ArgumentParser(description="LiteX Verilog AXI test simulation SoC ") 112 | verilator_build_args(parser) 113 | args = parser.parse_args() 114 | verilator_build_kwargs = verilator_build_argdict(args) 115 | sim_config = SimConfig(default_clk="sys_clk") 116 | sim_config.add_module("serial2console", "serial") 117 | 118 | soc = AXISimSoC() 119 | builder = Builder(soc) 120 | builder.build(sim_config=sim_config, **verilator_build_kwargs) 121 | 122 | if __name__ == "__main__": 123 | main() 124 | -------------------------------------------------------------------------------- /test_axi_lite.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # This file is part of LiteX-Verilog-AXI-Test 5 | # 6 | # Copyright (c) 2022 Florent Kermarrec 7 | # SPDX-License-Identifier: BSD-2-Clause 8 | 9 | import argparse 10 | 11 | from migen import * 12 | 13 | from litex.build.generic_platform import * 14 | from litex.build.sim import SimPlatform 15 | from litex.build.sim.config import SimConfig 16 | from litex.build.sim.verilator import verilator_build_args, verilator_build_argdict 17 | 18 | from litex.soc.interconnect.csr import * 19 | from litex.soc.integration.soc_core import * 20 | from litex.soc.integration.soc import SoCRegion 21 | from litex.soc.integration.builder import * 22 | from litex.soc.interconnect.axi import * 23 | 24 | from verilog_axi.axi_common import * 25 | 26 | # IOs ---------------------------------------------------------------------------------------------- 27 | 28 | _io = [ 29 | # Clk / Rst. 30 | ("sys_clk", 0, Pins(1)), 31 | ("sys_rst", 0, Pins(1)), 32 | 33 | # Serial. 34 | ("serial", 0, 35 | Subsignal("source_valid", Pins(1)), 36 | Subsignal("source_ready", Pins(1)), 37 | Subsignal("source_data", Pins(8)), 38 | 39 | Subsignal("sink_valid", Pins(1)), 40 | Subsignal("sink_ready", Pins(1)), 41 | Subsignal("sink_data", Pins(8)), 42 | ), 43 | ] 44 | 45 | # Platform ----------------------------------------------------------------------------------------- 46 | 47 | class Platform(SimPlatform): 48 | name = "sim" 49 | def __init__(self): 50 | SimPlatform.__init__(self, "SIM", _io) 51 | 52 | # AXISimSoC ---------------------------------------------------------------------------------------- 53 | 54 | class AXISimSoC(SoCCore): 55 | def __init__(self): 56 | # Parameters. 57 | sys_clk_freq = int(100e6) 58 | 59 | # Platform. 60 | platform = Platform() 61 | self.comb += platform.trace.eq(1) 62 | 63 | # CRG -------------------------------------------------------------------------------------- 64 | self.submodules.crg = CRG(platform.request("sys_clk")) 65 | 66 | # SoCCore ---------------------------------------------------------------------------------- 67 | SoCCore.__init__(self, platform, clk_freq=sys_clk_freq, bus_standard="axi-lite", uart_name="sim", integrated_rom_size=0x10000) 68 | self.add_config("BIOS_NO_BOOT") 69 | 70 | # AXI-Lite Tests --------------------------------------------------------------------------- 71 | def axi_lite_syntax_test(): 72 | from verilog_axi.axi_lite.axil_adapter import AXILiteAdapter 73 | s_axi_lite = AXILiteInterface(data_width=32, address_width=32) 74 | m_axi_lite = AXILiteInterface(data_width=64, address_width=32) 75 | self.submodules.axi_lite_adapter = AXILiteAdapter(platform, s_axi_lite, m_axi_lite) 76 | 77 | from verilog_axi.axi_lite.axil_ram import AXILiteRAM 78 | s_axi_lite = AXILiteInterface(data_width=32, address_width=32) 79 | self.submodules.axi_lite_ram = AXILiteRAM(platform, s_axi_lite, size=0x1000) 80 | 81 | from verilog_axi.axi_lite.axil_register import AXILiteRegister 82 | s_axi_lite = AXIInterface(data_width=32, address_width=32) 83 | m_axi_lite = AXIInterface(data_width=32, address_width=32) 84 | self.submodules.axi_lite_register = AXILiteRegister(platform, s_axi_lite, m_axi_lite) 85 | 86 | from verilog_axi.axi_lite.axil_cdc import AXILiteCDC 87 | s_axi_lite = AXIInterface(data_width=32, address_width=32) 88 | m_axi_lite = AXIInterface(data_width=32, address_width=32) 89 | self.submodules.axi_lite_cdc = AXILiteCDC(platform, s_axi_lite, m_axi_lite) 90 | 91 | def axi_lite_integration_test(): 92 | # AXI-Lite Test Mapping. 93 | # ---------------------- 94 | axil_map = { 95 | "axil_ram" : 0x010000, 96 | "axil_dp_ram_a" : 0x011000, 97 | "axil_dp_ram_b" : 0x012000, 98 | "axil_ram_reg" : 0x013000, 99 | "axil_ram_cdc" : 0x014000, 100 | "axil_ram_xbar" : 0x100000, 101 | "axil_ram_int" : 0x200000, 102 | } 103 | # Add AXI-Lite RAM to SoC. 104 | # ------------------------ 105 | 106 | # Test from LiteX BIOS: 107 | # mem_list 108 | # mem_write 0x5aa55aa5 109 | # mem_read 32 110 | 111 | # 1) Create AXI-Lite interface and connect it to SoC. 112 | s_axi_lite = AXILiteInterface(data_width=32, address_width=32) 113 | self.bus.add_slave("axil_ram", s_axi_lite, region=SoCRegion(origin=axil_map["axil_ram"], size=0x1000)) 114 | # 2) Add AXILiteRAM. 115 | from verilog_axi.axi_lite.axil_ram import AXILiteRAM 116 | self.submodules += AXILiteRAM(platform, s_axi_lite, size=0x1000) 117 | # 4) Debug. 118 | if 0: 119 | self.submodules += AXIAWDebug(s_axi_lite, name="AXIRAM") 120 | self.submodules += AXIWDebug( s_axi_lite, name="AXIRAM") 121 | self.submodules += AXIARDebug(s_axi_lite, name="AXIRAM") 122 | self.submodules += AXIRDebug( s_axi_lite, name="AXIRAM") 123 | 124 | # Add AXI-Lite DP RAM to SoC. 125 | # --------------------------- 126 | 127 | # Test from LiteX BIOS: 128 | # mem_list 129 | # mem_write 0x5aa55aa5 130 | # mem_read 32 131 | # mem_write 0xa55aa55a 132 | # mem_read 32 133 | 134 | # 1) Create AXI-Lite interfaces and connect them to SoC. 135 | s_axi_lite_a = AXILiteInterface(data_width=32, address_width=32) 136 | s_axi_lite_b = AXILiteInterface(data_width=32, address_width=32) 137 | self.bus.add_slave("axil_dp_ram_a", s_axi_lite_a, region=SoCRegion(origin=axil_map["axil_dp_ram_a"], size=0x1000)) 138 | self.bus.add_slave("axil_dp_ram_b", s_axi_lite_b, region=SoCRegion(origin=axil_map["axil_dp_ram_b"], size=0x1000)) 139 | # 2) Add AXILiteDPRAM. 140 | from verilog_axi.axi_lite.axil_dp_ram import AXILiteDPRAM 141 | self.submodules += AXILiteDPRAM(platform, s_axi_lite_a, s_axi_lite_b, size=0x1000) 142 | if 0: 143 | self.submodules += AXIAWDebug(s_axi_lite_a, name="AXILiteDPRAM_A") 144 | self.submodules += AXIWDebug( s_axi_lite_a, name="AXILiteDPRAM_A") 145 | self.submodules += AXIARDebug(s_axi_lite_a, name="AXILiteDPRAM_A") 146 | self.submodules += AXIRDebug( s_axi_lite_a, name="AXILiteDPRAM_A") 147 | self.submodules += AXIAWDebug(s_axi_lite_b, name="AXILiteDPRAM_B") 148 | self.submodules += AXIWDebug( s_axi_lite_b, name="AXILiteDPRAM_B") 149 | self.submodules += AXIARDebug(s_axi_lite_b, name="AXILiteDPRAM_B") 150 | self.submodules += AXIRDebug( s_axi_lite_b, name="AXILiteDPRAM_B") 151 | 152 | # Add AXI-Lite RAM to SoC (Through AXI-Lite Register). 153 | # ---------------------------------------------------- 154 | 155 | # Test from LiteX BIOS similar to AXI-Lite RAM but with AXIL_RAM_REG_BASE. 156 | 157 | # 1) Create AXI-Lite interface and connect it to SoC. 158 | s_axi_lite = AXILiteInterface(data_width=32, address_width=32) 159 | self.bus.add_slave("axil_ram_reg", s_axi_lite, region=SoCRegion(origin=axil_map["axil_ram_reg"], size=0x1000)) 160 | # 2) Add AXILiteRegister. 161 | from verilog_axi.axi_lite.axil_register import AXILiteRegister 162 | s_axi_lite_reg = AXILiteInterface(data_width=32, address_width=32) 163 | self.submodules += AXILiteRegister(platform, s_axi_lite, s_axi_lite_reg) 164 | # 4) Add AXILiteSRAM. 165 | from verilog_axi.axi_lite.axil_ram import AXILiteRAM 166 | self.submodules += AXILiteRAM(platform, s_axi_lite_reg, size=0x1000) 167 | 168 | # Add AXI-Lite RAM to SoC (Through AXI-Lite CDC). 169 | # ---------------------------------------------------- 170 | 171 | # Test from LiteX BIOS similar to AXI-Lite RAM but with AXIL_RAM_CDC_BASE. 172 | 173 | # 1) Create AXI-Lite interface and connect it to SoC. 174 | s_axi_lite = AXILiteInterface(data_width=32, address_width=32) 175 | self.bus.add_slave("axil_ram_cdc", s_axi_lite, region=SoCRegion(origin=axil_map["axil_ram_cdc"], size=0x1000)) 176 | # 2) Add AXILiteCDC. 177 | from verilog_axi.axi_lite.axil_cdc import AXILiteCDC 178 | s_axi_lite_cdc = AXILiteInterface(data_width=32, address_width=32) 179 | self.submodules += AXILiteCDC(platform, s_axi_lite, s_axi_lite_cdc) 180 | # 4) Add AXILiteSRAM. 181 | from verilog_axi.axi_lite.axil_ram import AXILiteRAM 182 | self.submodules += AXILiteRAM(platform, s_axi_lite_cdc, size=0x1000) 183 | 184 | 185 | # Add AXI RAM to SoC (Through AXI-Lite Crossbar). 186 | # ----------------------------------------------- 187 | 188 | # Test from LiteX BIOS similar to AXI RAM but with AXIL_RAM_XBAR_BASE. 189 | 190 | # 1) Create AXI-Lite interface and connect it to SoC. 191 | s_axi_lite = AXILiteInterface(data_width=32, address_width=32) 192 | self.bus.add_slave("axil_ram_xbar", s_axi_lite, region=SoCRegion(origin=axil_map["axil_ram_xbar"], size=0x10000)) 193 | # 2) Add AXILiteCrossbar (1 Slave / 2 Masters). 194 | from verilog_axi.axi_lite.axil_crossbar import AXILiteCrossbar 195 | self.submodules.axil_crossbar = AXILiteCrossbar(platform) 196 | self.axil_crossbar.add_slave(s_axil=s_axi_lite) 197 | m_axil_0 = AXILiteInterface(data_width=32, address_width=32) 198 | m_axil_1 = AXILiteInterface(data_width=32, address_width=32) 199 | self.axil_crossbar.add_master(m_axil=m_axil_0, origin=axil_map["axil_ram_xbar"] + 0x0000, size=0x1000) 200 | self.axil_crossbar.add_master(m_axil=m_axil_1, origin=axil_map["axil_ram_xbar"] + 0x1000, size=0x1000) 201 | # 4) Add 2 X AXILiteSRAM. 202 | from verilog_axi.axi_lite.axil_ram import AXILiteRAM 203 | self.submodules += AXILiteRAM(platform, m_axil_0, size=0x1000) 204 | self.submodules += AXILiteRAM(platform, m_axil_1, size=0x1000) 205 | 206 | # Add AXI RAM to SoC (Through AXI-Lite Interconnect). 207 | # --------------------------------------------------- 208 | 209 | # Test from LiteX BIOS similar to AXI RAM but with AXIL_RAM_INT_BASE. 210 | 211 | # 1) Create AXI-Lite interface and connect it to SoC. 212 | s_axi_lite = AXILiteInterface(data_width=32, address_width=32) 213 | self.bus.add_slave("axil_ram_int", s_axi_lite, region=SoCRegion(origin=axil_map["axil_ram_int"], size=0x10000)) 214 | # 2) Add AXILiteInterconnect (1 Slave / 2 Masters). 215 | from verilog_axi.axi_lite.axil_interconnect import AXILiteInterconnect 216 | self.submodules.axil_interconnect = AXILiteInterconnect(platform) 217 | self.axil_interconnect.add_slave(s_axil=s_axi_lite) 218 | m_axil_0 = AXILiteInterface(data_width=32, address_width=32) 219 | m_axil_1 = AXILiteInterface(data_width=32, address_width=32) 220 | self.axil_interconnect.add_master(m_axil=m_axil_0, origin=axil_map["axil_ram_int"] + 0x0000, size=0x1000) 221 | self.axil_interconnect.add_master(m_axil=m_axil_1, origin=axil_map["axil_ram_int"] + 0x1000, size=0x1000) 222 | # 4) Add 2 X AXILiteSRAM. 223 | from verilog_axi.axi_lite.axil_ram import AXILiteRAM 224 | self.submodules += AXILiteRAM(platform, m_axil_0, size=0x1000) 225 | self.submodules += AXILiteRAM(platform, m_axil_1, size=0x1000) 226 | 227 | axi_lite_syntax_test() 228 | axi_lite_integration_test() 229 | 230 | # Build -------------------------------------------------------------------------------------------- 231 | 232 | def main(): 233 | parser = argparse.ArgumentParser(description="LiteX Verilog AXI test simulation SoC ") 234 | verilator_build_args(parser) 235 | args = parser.parse_args() 236 | verilator_build_kwargs = verilator_build_argdict(args) 237 | sim_config = SimConfig(default_clk="sys_clk") 238 | sim_config.add_module("serial2console", "serial") 239 | 240 | soc = AXISimSoC() 241 | builder = Builder(soc) 242 | builder.build(sim_config=sim_config, **verilator_build_kwargs) 243 | 244 | if __name__ == "__main__": 245 | main() 246 | -------------------------------------------------------------------------------- /verilog_axi/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoy-digital/litex_verilog_axi_test/70304d8ede2a2e5415d0e4381e1b3d67b32e0f41/verilog_axi/__init__.py -------------------------------------------------------------------------------- /verilog_axi/axi/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoy-digital/litex_verilog_axi_test/70304d8ede2a2e5415d0e4381e1b3d67b32e0f41/verilog_axi/axi/__init__.py -------------------------------------------------------------------------------- /verilog_axi/axi/axi_adapter.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axi_adapter.v. 8 | 9 | import os 10 | 11 | from migen import * 12 | 13 | from litex.soc.interconnect.axi import * 14 | 15 | from verilog_axi.axi_common import * 16 | 17 | # AXI Adapter -------------------------------------------------------------------------------------- 18 | 19 | class AXIAdapter(Module): 20 | def __init__(self, platform, s_axi, m_axi, 21 | convert_burst = True, 22 | convert_narrow_burst = False, 23 | forward_id = True, 24 | ): 25 | self.logger = logging.getLogger("AXIAdapter") 26 | 27 | # Get/Check Parameters. 28 | # --------------------- 29 | 30 | # Clock Domain. 31 | clock_domain = s_axi.clock_domain 32 | if s_axi.clock_domain != m_axi.clock_domain: 33 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 34 | colorer("Different Clock Domain", color="red"), 35 | colorer("AXI interfaces."), 36 | colorer(s_axi.clock_domain), 37 | colorer(m_axi.clock_domain), 38 | colorer("the same"))) 39 | raise AXIError() 40 | else: 41 | self.logger.info(f"Clock Domain: {colorer(clock_domain)}") 42 | 43 | # Address width. 44 | address_width = len(s_axi.aw.addr) 45 | if len(s_axi.aw.addr) != len(m_axi.aw.addr): 46 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 47 | colorer("Different Address Width", color="red"), 48 | colorer("AXI interfaces."), 49 | colorer(len(s_axi.aw.addr)), 50 | colorer(len(m_axi.aw.addr)), 51 | colorer("the same"))) 52 | raise AXIError() 53 | else: 54 | self.logger.info(f"Address Width: {colorer(address_width)}") 55 | 56 | # Data width. 57 | s_data_width = len(s_axi.w.data) 58 | m_data_width = len(m_axi.w.data) 59 | self.logger.info(f"Slave Data Width: {colorer(s_data_width)}") 60 | self.logger.info(f"Master Data Width: {colorer(m_data_width)}") 61 | 62 | # ID width. 63 | id_width = len(s_axi.aw.id) 64 | if len(s_axi.aw.id) != len(m_axi.aw.id): 65 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 66 | colorer("Different ID Width", color="red"), 67 | colorer("AXI interfaces."), 68 | colorer(len(s_axi.aw.id)), 69 | colorer(len(m_axi.aw.id)), 70 | colorer("the same"))) 71 | raise AXIError() 72 | else: 73 | self.logger.info(f"ID Width: {colorer(id_width)}") 74 | 75 | # User width. 76 | for c in ["aw", "w", "b", "ar", "r"]: 77 | m_axi_c = getattr(m_axi, c) 78 | s_axi_c = getattr(s_axi, c) 79 | if s_axi_c.user_width != m_axi_c.user_width: 80 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 81 | colorer("Different User Width", color="red"), 82 | colorer("AXI interfaces."), 83 | colorer(len(s_axi_c.user)), 84 | colorer(len(m_axi_c.user)), 85 | colorer("the same"))) 86 | raise AXIError() 87 | else: 88 | self.logger.info(f"{c.upper()} User Width: {colorer(m_axi_c.user_width)}") 89 | 90 | # Burst. 91 | # FIXME: Add check. 92 | 93 | # Module instance. 94 | # ---------------- 95 | 96 | self.specials += Instance("axi_adapter", 97 | # Parameters. 98 | # ----------- 99 | p_ADDR_WIDTH = address_width, 100 | p_S_DATA_WIDTH = s_data_width, 101 | p_M_DATA_WIDTH = m_data_width, 102 | 103 | p_FORWARD_ID = forward_id and (id_width != 0), 104 | p_ID_WIDTH = id_width, 105 | 106 | p_AWUSER_ENABLE = s_axi.aw.user_width > 0, 107 | p_AWUSER_WIDTH = max(1, s_axi.aw.user_width), 108 | p_WUSER_ENABLE = s_axi.w.user_width > 0, 109 | p_WUSER_WIDTH = max(1, s_axi.w.user_width), 110 | p_BUSER_ENABLE = s_axi.b.user_width > 0, 111 | p_BUSER_WIDTH = max(1, s_axi.b.user_width), 112 | p_ARUSER_ENABLE = s_axi.ar.user_width > 0, 113 | p_ARUSER_WIDTH = max(1, s_axi.ar.user_width), 114 | p_RUSER_ENABLE = s_axi.r.user_width > 0, 115 | p_RUSER_WIDTH = max(1, s_axi.r.user_width), 116 | 117 | p_CONVERT_BURST = convert_burst, 118 | p_CONVERT_NARROW_BURST = convert_narrow_burst, 119 | 120 | # Clk / Rst. 121 | # ---------- 122 | i_clk = ClockSignal(clock_domain), 123 | i_rst = ResetSignal(clock_domain), 124 | 125 | # AXI Slave Interface. 126 | # -------------------- 127 | # AW. 128 | i_s_axi_awid = s_axi.aw.id, 129 | i_s_axi_awaddr = s_axi.aw.addr, 130 | i_s_axi_awlen = s_axi.aw.len, 131 | i_s_axi_awsize = s_axi.aw.size, 132 | i_s_axi_awburst = s_axi.aw.burst, 133 | i_s_axi_awlock = s_axi.aw.lock, 134 | i_s_axi_awcache = s_axi.aw.cache, 135 | i_s_axi_awprot = s_axi.aw.prot, 136 | i_s_axi_awqos = s_axi.aw.qos, 137 | i_s_axi_awregion = s_axi.aw.region, 138 | i_s_axi_awuser = s_axi.aw.user, 139 | i_s_axi_awvalid = s_axi.aw.valid, 140 | o_s_axi_awready = s_axi.aw.ready, 141 | 142 | # W. 143 | i_s_axi_wdata = s_axi.w.data, 144 | i_s_axi_wstrb = s_axi.w.strb, 145 | i_s_axi_wlast = s_axi.w.last, 146 | i_s_axi_wuser = s_axi.w.user, 147 | i_s_axi_wvalid = s_axi.w.valid, 148 | o_s_axi_wready = s_axi.w.ready, 149 | 150 | # B. 151 | o_s_axi_bid = s_axi.b.id, 152 | o_s_axi_bresp = s_axi.b.resp, 153 | o_s_axi_buser = s_axi.b.user, 154 | o_s_axi_bvalid = s_axi.b.valid, 155 | i_s_axi_bready = s_axi.b.ready, 156 | 157 | # AR. 158 | i_s_axi_arid = s_axi.ar.id, 159 | i_s_axi_araddr = s_axi.ar.addr, 160 | i_s_axi_arlen = s_axi.ar.len, 161 | i_s_axi_arsize = s_axi.ar.size, 162 | i_s_axi_arburst = s_axi.ar.burst, 163 | i_s_axi_arlock = s_axi.ar.lock, 164 | i_s_axi_arcache = s_axi.ar.cache, 165 | i_s_axi_arprot = s_axi.ar.prot, 166 | i_s_axi_arqos = s_axi.ar.qos, 167 | i_s_axi_arregion = s_axi.ar.region, 168 | i_s_axi_aruser = s_axi.ar.user, 169 | i_s_axi_arvalid = s_axi.ar.valid, 170 | o_s_axi_arready = s_axi.ar.ready, 171 | 172 | # R. 173 | o_s_axi_rid = s_axi.r.id, 174 | o_s_axi_rdata = s_axi.r.data, 175 | o_s_axi_rresp = s_axi.r.resp, 176 | o_s_axi_rlast = s_axi.r.last, 177 | o_s_axi_ruser = s_axi.r.user, 178 | o_s_axi_rvalid = s_axi.r.valid, 179 | i_s_axi_rready = s_axi.r.ready, 180 | 181 | # AXI Master Interface. 182 | # --------------------- 183 | # AW. 184 | o_m_axi_awid = m_axi.aw.id, 185 | o_m_axi_awaddr = m_axi.aw.addr, 186 | o_m_axi_awlen = m_axi.aw.len, 187 | o_m_axi_awsize = m_axi.aw.size, 188 | o_m_axi_awburst = m_axi.aw.burst, 189 | o_m_axi_awlock = m_axi.aw.lock, 190 | o_m_axi_awcache = m_axi.aw.cache, 191 | o_m_axi_awprot = m_axi.aw.prot, 192 | o_m_axi_awqos = m_axi.aw.qos, 193 | o_m_axi_awregion = m_axi.aw.region, 194 | o_m_axi_awuser = m_axi.aw.user, 195 | o_m_axi_awvalid = m_axi.aw.valid, 196 | i_m_axi_awready = m_axi.aw.ready, 197 | 198 | # W. 199 | o_m_axi_wdata = m_axi.w.data, 200 | o_m_axi_wstrb = m_axi.w.strb, 201 | o_m_axi_wlast = m_axi.w.last, 202 | o_m_axi_wuser = m_axi.w.user, 203 | o_m_axi_wvalid = m_axi.w.valid, 204 | i_m_axi_wready = m_axi.w.ready, 205 | 206 | # B. 207 | i_m_axi_bid = m_axi.b.id, 208 | i_m_axi_bresp = m_axi.b.resp, 209 | i_m_axi_buser = m_axi.b.user, 210 | i_m_axi_bvalid = m_axi.b.valid, 211 | o_m_axi_bready = m_axi.b.ready, 212 | 213 | # AR. 214 | o_m_axi_arid = m_axi.ar.id, 215 | o_m_axi_araddr = m_axi.ar.addr, 216 | o_m_axi_arlen = m_axi.ar.len, 217 | o_m_axi_arsize = m_axi.ar.size, 218 | o_m_axi_arburst = m_axi.ar.burst, 219 | o_m_axi_arlock = m_axi.ar.lock, 220 | o_m_axi_arcache = m_axi.ar.cache, 221 | o_m_axi_arprot = m_axi.ar.prot, 222 | o_m_axi_arqos = m_axi.ar.qos, 223 | o_m_axi_arregion = m_axi.ar.region, 224 | o_m_axi_aruser = m_axi.ar.user, 225 | o_m_axi_arvalid = m_axi.ar.valid, 226 | i_m_axi_arready = m_axi.ar.ready, 227 | 228 | # R. 229 | i_m_axi_rid = m_axi.r.id, 230 | i_m_axi_rdata = m_axi.r.data, 231 | i_m_axi_rresp = m_axi.r.resp, 232 | i_m_axi_rlast = m_axi.r.last, 233 | i_m_axi_ruser = m_axi.r.user, 234 | i_m_axi_rvalid = m_axi.r.valid, 235 | o_m_axi_rready = m_axi.r.ready, 236 | ) 237 | 238 | # Add Sources. 239 | # ------------ 240 | self.add_sources(platform) 241 | 242 | @staticmethod 243 | def add_sources(platform): 244 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 245 | platform.add_source(os.path.join(rtl_dir, "axi_adapter_wr.v")) 246 | platform.add_source(os.path.join(rtl_dir, "axi_adapter_rd.v")) 247 | platform.add_source(os.path.join(rtl_dir, "axi_adapter.v")) 248 | -------------------------------------------------------------------------------- /verilog_axi/axi/axi_cdma.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axi_cdma.v. 8 | 9 | import os 10 | import math 11 | 12 | from migen import * 13 | 14 | from litex.soc.interconnect import stream 15 | from litex.soc.interconnect.axi import * 16 | 17 | from verilog_axi.axi_common import * 18 | 19 | # AXI CDMA ----------------------------------------------------------------------------------------- 20 | 21 | class AXICDMA(Module): 22 | def __init__(self, platform, m_axi, len_width=20, tag_width=8): 23 | self.logger = logging.getLogger("AXICDMA") 24 | 25 | # Get/Check Parameters. 26 | # --------------------- 27 | 28 | # Clock Domain. 29 | clock_domain = m_axi.clock_domain 30 | self.logger.info(f"Clock Domain: {colorer(clock_domain)}") 31 | 32 | # Address width. 33 | address_width = len(m_axi.aw.addr) 34 | self.logger.info(f"Address Width: {colorer(address_width)}") 35 | 36 | # Data width. 37 | data_width = len(m_axi.w.data) 38 | self.logger.info(f"Data Width: {colorer(data_width)}") 39 | 40 | # ID width. 41 | id_width = len(m_axi.aw.id) 42 | self.logger.info(f"ID Width: {colorer(id_width)}") 43 | 44 | # FIXME: Add checks on len/tag_width? 45 | 46 | # Descriptor Endpoints. 47 | # --------------------- 48 | 49 | desc_layout = [ 50 | ("read_addr", address_width), 51 | ("write_addr", address_width), 52 | ("len", len_width), 53 | ("tag", tag_width), 54 | ] 55 | desc_status_layout = [ 56 | ("tag", tag_width), 57 | ("error", 4), 58 | ] 59 | self.desc = desc = stream.Endpoint(desc_layout) 60 | self.desc_status = desc_status = stream.Endpoint(desc_status_layout) 61 | 62 | # Module instance. 63 | # ---------------- 64 | 65 | self.specials += Instance("axi_cdma", 66 | # Parameters. 67 | # ----------- 68 | p_AXI_DATA_WIDTH = data_width, 69 | p_AXI_ADDR_WIDTH = address_width, 70 | p_AXI_ID_WIDTH = id_width, 71 | p_AXI_MAX_BURST_LEN = 16, # FIXME: Expose? 72 | p_LEN_WIDTH = len_width, 73 | p_TAG_WIDTH = tag_width, 74 | p_ENABLE_UNALIGNED = 0, # FIXME: Expose? 75 | 76 | # Clk / Rst. 77 | # ---------- 78 | i_clk = ClockSignal(clock_domain), 79 | i_rst = ResetSignal(clock_domain), 80 | 81 | # AXI Descriptor Input. 82 | # --------------------- 83 | i_s_axis_desc_read_addr = desc.read_addr, 84 | i_s_axis_desc_write_addr = desc.write_addr, 85 | i_s_axis_desc_len = desc.len, 86 | i_s_axis_desc_tag = desc.tag, 87 | i_s_axis_desc_valid = desc.valid, 88 | o_s_axis_desc_ready = desc.ready, 89 | 90 | # AXI Descriptor Output. 91 | # ---------------------- 92 | o_m_axis_desc_status_tag = desc_status.tag, 93 | o_m_axis_desc_status_error = desc_status.error, 94 | o_m_axis_desc_status_valid = desc_status.valid, 95 | 96 | # AXI Master Interface. 97 | # --------------------- 98 | # AW. 99 | i_m_axi_awid = m_axi.aw.id, 100 | i_m_axi_awaddr = m_axi.aw.addr, 101 | i_m_axi_awlen = m_axi.aw.len, 102 | i_m_axi_awsize = m_axi.aw.size, 103 | i_m_axi_awburst = m_axi.aw.burst, 104 | i_m_axi_awlock = m_axi.aw.lock, 105 | i_m_axi_awcache = m_axi.aw.cache, 106 | i_m_axi_awprot = m_axi.aw.prot, 107 | i_m_axi_awvalid = m_axi.aw.valid, 108 | o_m_axi_awready = m_axi.aw.ready, 109 | 110 | # W. 111 | i_m_axi_wdata = m_axi.w.data, 112 | i_m_axi_wstrb = m_axi.w.strb, 113 | i_m_axi_wlast = m_axi.w.last, 114 | i_m_axi_wvalid = m_axi.w.valid, 115 | o_m_axi_wready = m_axi.w.ready, 116 | 117 | # B. 118 | o_m_axi_bid = m_axi.b.id, 119 | o_m_axi_bresp = m_axi.b.resp, 120 | o_m_axi_bvalid = m_axi.b.valid, 121 | i_m_axi_bready = m_axi.b.ready, 122 | 123 | # AR. 124 | i_m_axi_arid = m_axi.ar.id, 125 | i_m_axi_araddr = m_axi.ar.addr, 126 | i_m_axi_arlen = m_axi.ar.len, 127 | i_m_axi_arsize = m_axi.ar.size, 128 | i_m_axi_arburst = m_axi.ar.burst, 129 | i_m_axi_arlock = m_axi.ar.lock, 130 | i_m_axi_arcache = m_axi.ar.cache, 131 | i_m_axi_arprot = m_axi.ar.prot, 132 | i_m_axi_arvalid = m_axi.ar.valid, 133 | o_m_axi_arready = m_axi.ar.ready, 134 | 135 | # R. 136 | o_m_axi_rid = m_axi.r.id, 137 | o_m_axi_rdata = m_axi.r.data, 138 | o_m_axi_rresp = m_axi.r.resp, 139 | o_m_axi_rlast = m_axi.r.last, 140 | o_m_axi_rvalid = m_axi.r.valid, 141 | i_m_axi_rready = m_axi.r.ready, 142 | ) 143 | 144 | # Add Sources. 145 | # ------------ 146 | self.add_sources(platform) 147 | 148 | @staticmethod 149 | def add_sources(platform): 150 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 151 | platform.add_source(os.path.join(rtl_dir, "axi_cdma.v")) 152 | -------------------------------------------------------------------------------- /verilog_axi/axi/axi_crossbar.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axi_crossbar.v. 8 | 9 | import os 10 | import math 11 | 12 | from migen import * 13 | 14 | from litex.soc.interconnect.axi import * 15 | 16 | from verilog_axi.axi_common import * 17 | 18 | # AXI Crossbar Interface --------------------------------------------------------------------------- 19 | 20 | class AXICrossbarInterface: 21 | def __init__(self, axi, origin=None, size=None, 22 | aw_reg = AXIRegister.SIMPLE_BUFFER, 23 | w_reg = AXIRegister.SKID_BUFFER, 24 | b_reg = AXIRegister.SIMPLE_BUFFER, 25 | ar_reg = AXIRegister.SIMPLE_BUFFER, 26 | r_reg = AXIRegister.SKID_BUFFER, 27 | ): 28 | self.axi = axi 29 | self.origin = origin 30 | self.size = size 31 | self.aw_reg = aw_reg 32 | self.w_reg = w_reg 33 | self.b_reg = b_reg 34 | self.ar_reg = ar_reg 35 | self.r_reg = r_reg 36 | 37 | # AXI Crossbar ------------------------------------------------------------------------------------- 38 | 39 | class AXICrossbar(Module): 40 | def __init__(self, platform): 41 | self.logger = logging.getLogger("AXICrossbar") 42 | self.s_axis = {} 43 | self.m_axis = {} 44 | 45 | # Add Sources. 46 | # ------------ 47 | self.add_sources(platform) 48 | 49 | def get_if_name(self, axi): 50 | axi_ifs = {**self.s_axis, **self.m_axis} 51 | for name, axi_if in axi_ifs.items(): 52 | if axi is axi_if.axi: 53 | return name 54 | return None 55 | 56 | def add_slave(self, name=None, s_axi=None, 57 | aw_reg = AXIRegister.SIMPLE_BUFFER, 58 | w_reg = AXIRegister.SKID_BUFFER, 59 | b_reg = AXIRegister.SIMPLE_BUFFER, 60 | ar_reg = AXIRegister.SIMPLE_BUFFER, 61 | r_reg = AXIRegister.SKID_BUFFER): 62 | 63 | # Get/Check Name. 64 | name = f"s_axi{len(self.s_axis)}" if name is None else name 65 | if name in self.s_axis.keys(): 66 | raise ValueError # FIXME: Add error message. 67 | 68 | # Add Slave. 69 | assert isinstance(s_axi, AXIInterface) 70 | s_axi = AXICrossbarInterface( 71 | axi = s_axi, 72 | aw_reg = aw_reg, 73 | w_reg = w_reg, 74 | b_reg = b_reg, 75 | ar_reg = ar_reg, 76 | r_reg = r_reg 77 | ) 78 | self.s_axis[name] = s_axi 79 | 80 | # Info. 81 | self.logger.info(f"Add AXI Slave {name} interface.") 82 | self.logger.info(f" AW Reg: {aw_reg.name}.") 83 | self.logger.info(f" W Reg: { w_reg.name}.") 84 | self.logger.info(f" B Reg: { b_reg.name}.") 85 | self.logger.info(f" AR Reg: {ar_reg.name}.") 86 | self.logger.info(f" R Reg: { r_reg.name}.") 87 | 88 | # Check. 89 | self.get_check_parameters(show=False) 90 | 91 | def add_master(self, name=None, m_axi=None, origin=None, size=None, 92 | aw_reg = AXIRegister.SIMPLE_BUFFER, 93 | w_reg = AXIRegister.SKID_BUFFER, 94 | b_reg = AXIRegister.SIMPLE_BUFFER, 95 | ar_reg = AXIRegister.SIMPLE_BUFFER, 96 | r_reg = AXIRegister.SKID_BUFFER): 97 | 98 | # Get/Check Name. 99 | name = f"m_axi{len(self.m_axis)}" if name is None else name 100 | if name in self.m_axis.keys(): 101 | raise ValueError # FIXME: Add error message. 102 | 103 | # Add Master. 104 | assert isinstance(m_axi, AXIInterface) 105 | assert origin is not None 106 | assert size is not None 107 | m_axi = AXICrossbarInterface( 108 | axi = m_axi, 109 | origin = origin, 110 | size = size, 111 | aw_reg = aw_reg, 112 | w_reg = w_reg, 113 | b_reg = b_reg, 114 | ar_reg = ar_reg, 115 | r_reg = r_reg 116 | ) 117 | self.m_axis[name] = m_axi 118 | 119 | # Info. 120 | self.logger.info(f"Add AXI Master {name} interface.") 121 | self.logger.info(f" Origin: 0x{origin:08x}.") 122 | self.logger.info(f" Size: 0x{size:0x}.") 123 | self.logger.info(f" AW Reg: {aw_reg.name}.") 124 | self.logger.info(f" W Reg: { w_reg.name}.") 125 | self.logger.info(f" B Reg: { b_reg.name}.") 126 | self.logger.info(f" AR Reg: {ar_reg.name}.") 127 | self.logger.info(f" R Reg: { r_reg.name}.") 128 | 129 | # Check. 130 | self.get_check_parameters(show=False) 131 | 132 | def get_check_parameters(self, show=True): 133 | axi_ifs = {**self.s_axis, **self.m_axis} 134 | axis = [axi_if.axi for name, axi_if in axi_ifs.items()] 135 | 136 | # Clock Domain. 137 | self.clock_domain = clock_domain = axis[0].clock_domain 138 | for i, axi in enumerate(axis): 139 | if i == 0: 140 | continue 141 | else: 142 | if axi.clock_domain != clock_domain: 143 | self.logger.error("{} on {} ({}: {} / {}: {}), should be {}.".format( 144 | colorer("Different Clock Domain", color="red"), 145 | colorer("AXI interfaces."), 146 | self.get_if_name(axis[0]), 147 | colorer(clock_domain), 148 | self.get_if_name(axi), 149 | colorer(axi.clock_domain), 150 | colorer("the same"))) 151 | raise AXIError() 152 | if show: 153 | self.logger.info(f"Clock Domain: {colorer(clock_domain)}") 154 | 155 | # Address width. 156 | self.address_width = address_width = len(axis[0].aw.addr) 157 | for i, axi in enumerate(axis): 158 | if i == 0: 159 | continue 160 | else: 161 | if len(axi.aw.addr) != address_width: 162 | self.logger.error("{} on {} ({}: {} / {}: {}), should be {}.".format( 163 | colorer("Different Address Width", color="red"), 164 | colorer("AXI interfaces."), 165 | self.get_if_name(axis[0]), 166 | colorer(address_width), 167 | self.get_if_name(axi), 168 | colorer(len(axi.aw.addr)), 169 | colorer("the same"))) 170 | raise AXIError() 171 | if show: 172 | self.logger.info(f"Address Width: {colorer(address_width)}") 173 | 174 | # Data width. 175 | self.data_width = data_width = len(axis[0].w.data) 176 | for i, axi in enumerate(axis): 177 | if i == 0: 178 | continue 179 | else: 180 | if len(axi.w.data) != data_width: 181 | self.logger.error("{} on {} ({}: {} / {}: {}), should be {}.".format( 182 | colorer("Different Data Width", color="red"), 183 | colorer("AXI interfaces."), 184 | self.get_if_name(axis[0]), 185 | colorer(data_width), 186 | self.get_if_name(axi), 187 | colorer(len(axi.w.data)), 188 | colorer("the same"))) 189 | raise AXIError() 190 | if show: 191 | self.logger.info(f"Data Width: {colorer(data_width)}") 192 | 193 | # Burst. 194 | # FIXME: Add check. 195 | 196 | # User width. 197 | for i, axi in enumerate(axis): 198 | if i == 0: 199 | continue 200 | else: 201 | for c in ["aw", "w", "b", "ar", "r"]: 202 | axi_c_0 = getattr(axis[0], c) 203 | axi_c_i = getattr(axis[i], c) 204 | if not hasattr(axi_c_0, "user_width") and not hasattr(axi_c_i, "user_width"): 205 | continue 206 | if axi_c_0.user_width != axi_c_i.user_width: 207 | self.logger.error("{} on {} ({} / {}), should be {}.".format( 208 | colorer("Different User Width", color="red"), 209 | colorer("AXI interfaces."), 210 | colorer(axi_c_0.user_width), 211 | colorer(axi_c_i.user_width), 212 | colorer("the same"))) 213 | raise AXIError() 214 | else: 215 | self.logger.info(f"{c.upper()} User Width: {colorer(axi_c_0.user_width)}") 216 | 217 | def do_finalize(self): 218 | axis_ifs = {**self.s_axis} 219 | axiss = [axi_if.axi for name, axi_if in axis_ifs.items()] 220 | axim_ifs = {**self.m_axis} 221 | axims = [axi_if.axi for name, axi_if in axim_ifs.items()] 222 | # ID width. Can't be checked until all interfaces have been added. 223 | self.s_id_width = s_id_width = len(axiss[0].aw.id) 224 | self.m_id_width = m_id_width = len(axims[0].aw.id) 225 | self.logger.info(f"Slave ID Width: {colorer(s_id_width)}") 226 | self.logger.info(f"Master ID width: {colorer(m_id_width)}") 227 | if m_id_width != s_id_width + log2_int(len(self.s_axis)): 228 | self.logger.error( 229 | "ID width mismatch. Expected slave ID width of {} and master ID width of {}".format( 230 | s_id_width, m_id_width + log2_int(len(self.s_axis)) 231 | )) 232 | 233 | # Get/Check Parameters. 234 | # --------------------- 235 | self.get_check_parameters() 236 | 237 | # Get/Check Parameters. 238 | # --------------------- 239 | self.logger.info(f"Finalized {len(self.s_axis)}X{len(self.m_axis)} Crossbar:") 240 | self.logger.info(f" Slaves:") 241 | for s_name, s_axi in self.s_axis.items(): 242 | self.logger.info(f" - {s_name}.") 243 | self.logger.info(f" Masters:") 244 | for m_name, m_axi in self.m_axis.items(): 245 | self.logger.info(f" - {m_name}, Origin: 0x{m_axi.origin:08x}, Size: 0x{m_axi.size:0x}.") 246 | 247 | 248 | # Module instance. 249 | # ---------------- 250 | 251 | s_axis = [axi_if.axi for axi_if in self.s_axis.values()] 252 | m_axis = [axi_if.axi for axi_if in self.m_axis.values()] 253 | m_origins = [axi_if.origin for axi_if in self.m_axis.values()] 254 | m_widths = [math.ceil(math.log2(axi_if.size)) for axi_if in self.m_axis.values()] 255 | 256 | def format_m_params(params, width): 257 | value = 0 258 | for param in reversed(params): 259 | value <<= width 260 | value |= param 261 | return Constant(value, len(params)*width) 262 | 263 | 264 | # User Enable/Width computation. 265 | awuser_enable = 0 if not hasattr(s_axis[0].aw, "user") else 1 if s_axis[0].aw.user_width !=0 else 0 266 | awuser_width = 1 if not hasattr(s_axis[0].aw, "user") else len(s_axis[0].aw) 267 | wuser_enable = 0 if not hasattr(s_axis[0].w, "user") else 1 if s_axis[0].w.user_width !=0 else 0 268 | wuser_width = 1 if not hasattr(s_axis[0].w, "user") else len(s_axis[0].w) 269 | buser_enable = 0 if not hasattr(s_axis[0].b, "user") else 1 if s_axis[0].b.user_width !=0 else 0 270 | buser_width = 1 if not hasattr(s_axis[0].b, "user") else len(s_axis[0].b) 271 | aruser_enable = 0 if not hasattr(s_axis[0].ar, "user") else 1 if s_axis[0].ar.user_width !=0 else 0 272 | aruser_width = 1 if not hasattr(s_axis[0].ar, "user") else len(s_axis[0].ar) 273 | ruser_enable = 0 if not hasattr(s_axis[0].r, "user") else 1 if s_axis[0].r.user_width !=0 else 0 274 | ruser_width = 1 if not hasattr(s_axis[0].r, "user") else len(s_axis[0].r) 275 | 276 | self.specials += Instance("axi_crossbar", 277 | # Parameters. 278 | # ----------- 279 | p_S_COUNT = len(s_axis), 280 | p_M_COUNT = len(m_axis), 281 | p_DATA_WIDTH = self.data_width, 282 | p_ADDR_WIDTH = self.address_width, 283 | p_S_ID_WIDTH = self.s_id_width, 284 | p_M_ID_WIDTH = self.m_id_width, 285 | 286 | p_AWUSER_ENABLE = awuser_enable, 287 | p_AWUSER_WIDTH = awuser_width, 288 | p_WUSER_ENABLE = wuser_enable, 289 | p_WUSER_WIDTH = wuser_width, 290 | p_BUSER_ENABLE = buser_enable, 291 | p_BUSER_WIDTH = buser_width, 292 | p_ARUSER_ENABLE = aruser_enable, 293 | p_ARUSER_WIDTH = aruser_width, 294 | p_RUSER_ENABLE = ruser_enable, 295 | p_RUSER_WIDTH = ruser_width, 296 | 297 | # Slave Registers. 298 | p_S_AW_REG_TYPE = format_m_params([axi_if.aw_reg for axi_if in self.s_axis.values()], 2), 299 | p_S_W_REG_TYPE = format_m_params([axi_if.w_reg for axi_if in self.s_axis.values()], 2), 300 | p_S_B_REG_TYPE = format_m_params([axi_if.b_reg for axi_if in self.s_axis.values()], 2), 301 | p_S_AR_REG_TYPE = format_m_params([axi_if.ar_reg for axi_if in self.s_axis.values()], 2), 302 | p_S_R_REG_TYPE = format_m_params([axi_if.r_reg for axi_if in self.s_axis.values()], 2), 303 | 304 | # Masters Origin/Size. 305 | p_M_BASE_ADDR = format_m_params(m_origins, self.address_width), 306 | p_M_ADDR_WIDTH = format_m_params(m_widths, 32), 307 | 308 | # Master Registers. 309 | p_M_AW_REG_TYPE = format_m_params([axi_if.aw_reg for axi_if in self.m_axis.values()], 2), 310 | p_M_W_REG_TYPE = format_m_params([axi_if.w_reg for axi_if in self.m_axis.values()], 2), 311 | p_M_B_REG_TYPE = format_m_params([axi_if.b_reg for axi_if in self.m_axis.values()], 2), 312 | p_M_AR_REG_TYPE = format_m_params([axi_if.ar_reg for axi_if in self.m_axis.values()], 2), 313 | p_M_R_REG_TYPE = format_m_params([axi_if.r_reg for axi_if in self.m_axis.values()], 2), 314 | 315 | # FIXME: Expose other parameters. 316 | 317 | # Clk / Rst. 318 | # ---------- 319 | i_clk = ClockSignal(self.clock_domain), 320 | i_rst = ResetSignal(self.clock_domain), 321 | 322 | # AXI Slave Interfaces. 323 | # -------------------- 324 | # AW. 325 | i_s_axi_awid = Cat(*[s_axi.aw.id for s_axi in s_axis]), 326 | i_s_axi_awaddr = Cat(*[s_axi.aw.addr for s_axi in s_axis]), 327 | i_s_axi_awlen = Cat(*[s_axi.aw.len for s_axi in s_axis]), 328 | i_s_axi_awsize = Cat(*[s_axi.aw.size for s_axi in s_axis]), 329 | i_s_axi_awburst = Cat(*[s_axi.aw.burst for s_axi in s_axis]), 330 | i_s_axi_awlock = Cat(*[s_axi.aw.lock for s_axi in s_axis]), 331 | i_s_axi_awcache = Cat(*[s_axi.aw.cache for s_axi in s_axis]), 332 | i_s_axi_awprot = Cat(*[s_axi.aw.prot for s_axi in s_axis]), 333 | i_s_axi_awqos = Cat(*[s_axi.aw.qos for s_axi in s_axis]), 334 | i_s_axi_awuser = Cat(*[s_axi.aw.user for s_axi in s_axis]), 335 | i_s_axi_awvalid = Cat(*[s_axi.aw.valid for s_axi in s_axis]), 336 | o_s_axi_awready = Cat(*[s_axi.aw.ready for s_axi in s_axis]), 337 | 338 | # W. 339 | i_s_axi_wdata = Cat(*[s_axi.w.data for s_axi in s_axis]), 340 | i_s_axi_wstrb = Cat(*[s_axi.w.strb for s_axi in s_axis]), 341 | i_s_axi_wlast = Cat(*[s_axi.w.last for s_axi in s_axis]), 342 | i_s_axi_wuser = Cat(*[s_axi.w.user for s_axi in s_axis]), 343 | i_s_axi_wvalid = Cat(*[s_axi.w.valid for s_axi in s_axis]), 344 | o_s_axi_wready = Cat(*[s_axi.w.ready for s_axi in s_axis]), 345 | 346 | # B. 347 | o_s_axi_bid = Cat(*[s_axi.b.id for s_axi in s_axis]), 348 | o_s_axi_bresp = Cat(*[s_axi.b.resp for s_axi in s_axis]), 349 | o_s_axi_buser = Cat(*[s_axi.b.user for s_axi in s_axis]), 350 | o_s_axi_bvalid = Cat(*[s_axi.b.valid for s_axi in s_axis]), 351 | i_s_axi_bready = Cat(*[s_axi.b.ready for s_axi in s_axis]), 352 | 353 | # AR. 354 | i_s_axi_arid = Cat(*[s_axi.ar.id for s_axi in s_axis]), 355 | i_s_axi_araddr = Cat(*[s_axi.ar.addr for s_axi in s_axis]), 356 | i_s_axi_arlen = Cat(*[s_axi.ar.len for s_axi in s_axis]), 357 | i_s_axi_arsize = Cat(*[s_axi.ar.size for s_axi in s_axis]), 358 | i_s_axi_arburst = Cat(*[s_axi.ar.burst for s_axi in s_axis]), 359 | i_s_axi_arlock = Cat(*[s_axi.ar.lock for s_axi in s_axis]), 360 | i_s_axi_arcache = Cat(*[s_axi.ar.cache for s_axi in s_axis]), 361 | i_s_axi_arprot = Cat(*[s_axi.ar.prot for s_axi in s_axis]), 362 | i_s_axi_arqos = Cat(*[s_axi.ar.qos for s_axi in s_axis]), 363 | i_s_axi_aruser = Cat(*[s_axi.ar.user for s_axi in s_axis]), 364 | i_s_axi_arvalid = Cat(*[s_axi.ar.valid for s_axi in s_axis]), 365 | o_s_axi_arready = Cat(*[s_axi.ar.ready for s_axi in s_axis]), 366 | 367 | # R. 368 | o_s_axi_rid = Cat(*[s_axi.r.id for s_axi in s_axis]), 369 | o_s_axi_rdata = Cat(*[s_axi.r.data for s_axi in s_axis]), 370 | o_s_axi_rresp = Cat(*[s_axi.r.resp for s_axi in s_axis]), 371 | o_s_axi_rlast = Cat(*[s_axi.r.last for s_axi in s_axis]), 372 | o_s_axi_ruser = Cat(*[s_axi.r.user for s_axi in s_axis]), 373 | o_s_axi_rvalid = Cat(*[s_axi.r.valid for s_axi in s_axis]), 374 | i_s_axi_rready = Cat(*[s_axi.r.ready for s_axi in s_axis]), 375 | 376 | # AXI Master Interfaces. 377 | # ---------------------- 378 | # AW. 379 | o_m_axi_awid = Cat(*[m_axi.aw.id for m_axi in m_axis]), 380 | o_m_axi_awaddr = Cat(*[m_axi.aw.addr for m_axi in m_axis]), 381 | o_m_axi_awlen = Cat(*[m_axi.aw.len for m_axi in m_axis]), 382 | o_m_axi_awsize = Cat(*[m_axi.aw.size for m_axi in m_axis]), 383 | o_m_axi_awburst = Cat(*[m_axi.aw.burst for m_axi in m_axis]), 384 | o_m_axi_awlock = Cat(*[m_axi.aw.lock for m_axi in m_axis]), 385 | o_m_axi_awcache = Cat(*[m_axi.aw.cache for m_axi in m_axis]), 386 | o_m_axi_awprot = Cat(*[m_axi.aw.prot for m_axi in m_axis]), 387 | o_m_axi_awqos = Cat(*[m_axi.aw.qos for m_axi in m_axis]), 388 | o_m_axi_awregion = Cat(*[m_axi.aw.region for m_axi in m_axis]), 389 | o_m_axi_awuser = Cat(*[m_axi.aw.user for m_axi in m_axis]), 390 | o_m_axi_awvalid = Cat(*[m_axi.aw.valid for m_axi in m_axis]), 391 | i_m_axi_awready = Cat(*[m_axi.aw.ready for m_axi in m_axis]), 392 | 393 | # W. 394 | o_m_axi_wdata = Cat(*[m_axi.w.data for m_axi in m_axis]), 395 | o_m_axi_wstrb = Cat(*[m_axi.w.strb for m_axi in m_axis]), 396 | o_m_axi_wlast = Cat(*[m_axi.w.last for m_axi in m_axis]), 397 | o_m_axi_wuser = Cat(*[m_axi.w.user for m_axi in m_axis]), 398 | o_m_axi_wvalid = Cat(*[m_axi.w.valid for m_axi in m_axis]), 399 | i_m_axi_wready = Cat(*[m_axi.w.ready for m_axi in m_axis]), 400 | 401 | # B. 402 | i_m_axi_bid = Cat(*[m_axi.b.id for m_axi in m_axis]), 403 | i_m_axi_bresp = Cat(*[m_axi.b.resp for m_axi in m_axis]), 404 | i_m_axi_buser = Cat(*[m_axi.b.user for m_axi in m_axis]), 405 | i_m_axi_bvalid = Cat(*[m_axi.b.valid for m_axi in m_axis]), 406 | o_m_axi_bready = Cat(*[m_axi.b.ready for m_axi in m_axis]), 407 | 408 | # AR. 409 | o_m_axi_arid = Cat(*[m_axi.ar.id for m_axi in m_axis]), 410 | o_m_axi_araddr = Cat(*[m_axi.ar.addr for m_axi in m_axis]), 411 | o_m_axi_arlen = Cat(*[m_axi.ar.len for m_axi in m_axis]), 412 | o_m_axi_arsize = Cat(*[m_axi.ar.size for m_axi in m_axis]), 413 | o_m_axi_arburst = Cat(*[m_axi.ar.burst for m_axi in m_axis]), 414 | o_m_axi_arlock = Cat(*[m_axi.ar.lock for m_axi in m_axis]), 415 | o_m_axi_arcache = Cat(*[m_axi.ar.cache for m_axi in m_axis]), 416 | o_m_axi_arprot = Cat(*[m_axi.ar.prot for m_axi in m_axis]), 417 | o_m_axi_arqos = Cat(*[m_axi.ar.qos for m_axi in m_axis]), 418 | o_m_axi_arregion = Cat(*[m_axi.ar.region for m_axi in m_axis]), 419 | o_m_axi_aruser = Cat(*[m_axi.ar.user for m_axi in m_axis]), 420 | o_m_axi_arvalid = Cat(*[m_axi.ar.valid for m_axi in m_axis]), 421 | i_m_axi_arready = Cat(*[m_axi.ar.ready for m_axi in m_axis]), 422 | 423 | # R. 424 | i_m_axi_rid = Cat(*[m_axi.r.id for m_axi in m_axis]), 425 | i_m_axi_rdata = Cat(*[m_axi.r.data for m_axi in m_axis]), 426 | i_m_axi_rresp = Cat(*[m_axi.r.resp for m_axi in m_axis]), 427 | i_m_axi_rlast = Cat(*[m_axi.r.last for m_axi in m_axis]), 428 | i_m_axi_ruser = Cat(*[m_axi.r.user for m_axi in m_axis]), 429 | i_m_axi_rvalid = Cat(*[m_axi.r.valid for m_axi in m_axis]), 430 | o_m_axi_rready = Cat(*[m_axi.r.ready for m_axi in m_axis]), 431 | ) 432 | 433 | @staticmethod 434 | def add_sources(platform): 435 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 436 | platform.add_source(os.path.join(rtl_dir, "arbiter.v")) 437 | platform.add_source(os.path.join(rtl_dir, "priority_encoder.v")) 438 | platform.add_source(os.path.join(rtl_dir, "axi_register_wr.v")) 439 | platform.add_source(os.path.join(rtl_dir, "axi_register_rd.v")) 440 | platform.add_source(os.path.join(rtl_dir, "axi_crossbar.v")) 441 | platform.add_source(os.path.join(rtl_dir, "axi_crossbar_wr.v")) 442 | platform.add_source(os.path.join(rtl_dir, "axi_crossbar_rd.v")) 443 | platform.add_source(os.path.join(rtl_dir, "axi_crossbar_addr.v")) -------------------------------------------------------------------------------- /verilog_axi/axi/axi_dma.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axi_dma.v. 8 | 9 | import os 10 | import math 11 | 12 | from migen import * 13 | 14 | from litex.soc.interconnect import stream 15 | from litex.soc.interconnect.axi import * 16 | 17 | from verilog_axi.axi_common import * 18 | 19 | # AXI DMA ------------------------------------------------------------------------------------------ 20 | 21 | class AXIDMA(Module): 22 | def __init__(self, platform, m_axi, len_width=20, tag_width=8, dest_width=1, user_width=1): 23 | self.logger = logging.getLogger("AXIDMA") 24 | 25 | # Get/Check Parameters. 26 | # --------------------- 27 | 28 | # Clock Domain. 29 | clock_domain = m_axi.clock_domain 30 | self.logger.info(f"Clock Domain: {colorer(clock_domain)}") 31 | 32 | # Address width. 33 | address_width = len(m_axi.aw.addr) 34 | self.logger.info(f"Address Width: {colorer(address_width)}") 35 | 36 | # Data width. 37 | data_width = len(m_axi.w.data) 38 | self.logger.info(f"Data Width: {colorer(data_width)}") 39 | 40 | # ID width. 41 | id_width = len(m_axi.aw.id) 42 | self.logger.info(f"ID Width: {colorer(id_width)}") 43 | 44 | # FIXME: Add checks on len/tag/dest_width? 45 | 46 | # Descriptor Endpoints. 47 | # --------------------- 48 | 49 | read_desc_layout = [ 50 | ("addr", address_width), 51 | ("len", len_width), 52 | ("tag", tag_width), 53 | ("id", id_width), 54 | ("dest", dest_width), 55 | ("user", user_width), 56 | ] 57 | read_desc_status_layout = [ 58 | ("tag", tag_width), 59 | ("error", 4), 60 | ] 61 | read_data_layout = [ 62 | ("data", data_width), 63 | ("keep", data_width//8), 64 | ("tag", tag_width), 65 | ("id", id_width), 66 | ("dest", dest_width), 67 | ("user", user_width), 68 | ] 69 | self.read_desc = read_desc = stream.Endpoint(read_desc_layout) 70 | self.read_desc_status = read_desc_status = stream.Endpoint(read_desc_status_layout) 71 | self.read_data = read_data = stream.Endpoint(read_data_layout) 72 | 73 | write_desc_layout = [ 74 | ("addr", address_width), 75 | ("len", len_width), 76 | ("tag", tag_width), 77 | ] 78 | write_desc_status_layout = [ 79 | ("len", len_width), 80 | ("tag", tag_width), 81 | ("id", id_width), 82 | ("dest", dest_width), 83 | ("user", user_width), 84 | ("error", 4), 85 | ] 86 | write_data_layout = [ 87 | ("data", data_width), 88 | ("keep", data_width//8), 89 | ("tag", tag_width), 90 | ("id", id_width), 91 | ("dest", dest_width), 92 | ("user", user_width), 93 | ] 94 | 95 | self.write_desc = write_desc = stream.Endpoint(write_desc_layout) 96 | self.write_desc_status = write_desc_status = stream.Endpoint(write_desc_status_layout) 97 | self.write_data = write_data = stream.Endpoint(write_data_layout) 98 | 99 | # Module instance. 100 | # ---------------- 101 | 102 | self.specials += Instance("axi_dma", 103 | # Parameters. 104 | # ----------- 105 | p_AXI_DATA_WIDTH = data_width, 106 | p_AXI_ADDR_WIDTH = address_width, 107 | p_AXI_ID_WIDTH = id_width, 108 | p_AXI_MAX_BURST_LEN = 16, # FIXME: Expose? 109 | p_AXIS_LAST_ENABLE = 1, 110 | p_AXIS_ID_ENABLE = 0, # FIXME: Expose? 111 | p_AXIS_ID_WIDTH = 8, # FIXME: Expose? 112 | p_AXIS_DEST_ENABLE = 0, # FIXME: Expose? 113 | p_AXIS_DEST_WIDTH = 8, # FIXME: Expose? 114 | p_AXIS_USER_ENABLE = 0, # FIXME: Expose? 115 | p_AXIS_USER_WIDTH = 1, # FIXME: Expose? 116 | p_LEN_WIDTH = len_width, 117 | p_TAG_WIDTH = tag_width, 118 | p_ENABLE_SG = 0, 119 | p_ENABLE_UNALIGNED = 0, # FIXME: Expose? 120 | 121 | # Clk / Rst. 122 | # ---------- 123 | i_clk = ClockSignal(clock_domain), 124 | i_rst = ResetSignal(clock_domain), 125 | 126 | # Configuration. 127 | # -------------- 128 | i_read_enable = 1, # FIXME: Expose. 129 | i_write_enable = 1, # FIXME: Expose. 130 | i_write_abort = 0, # FIXME: Expose. 131 | 132 | # AXI Read Descriptor Input. 133 | # -------------------------- 134 | i_s_axis_read_desc_addr = read_desc.addr, 135 | i_s_axis_read_desc_len = read_desc.len, 136 | i_s_axis_read_desc_tag = read_desc.tag, 137 | i_s_axis_read_desc_id = read_desc.id, 138 | i_s_axis_read_desc_dest = read_desc.dest, 139 | i_s_axis_read_desc_user = read_desc.user, 140 | i_s_axis_read_desc_valid = read_desc.valid, 141 | o_s_axis_read_desc_ready = read_desc.ready, 142 | 143 | # AXI Read Descriptor Status. 144 | # --------------------------- 145 | o_m_axis_read_desc_status_tag = read_desc_status.tag, 146 | o_m_axis_read_desc_status_error = read_desc_status.error, 147 | o_m_axis_read_desc_status_valid = read_desc_status.valid, 148 | 149 | # AXI Read Data Output. 150 | # --------------------- 151 | o_m_axis_read_data_tdata = read_data.data, 152 | o_m_axis_read_data_tkeep = read_data.keep, 153 | o_m_axis_read_data_tvalid = read_data.valid, 154 | i_m_axis_read_data_tready = read_data.ready, 155 | o_m_axis_read_data_tlast = read_data.last, 156 | o_m_axis_read_data_tid = read_data.id, 157 | o_m_axis_read_data_tdest = read_data.dest, 158 | o_m_axis_read_data_tuser = read_data.user, 159 | 160 | # AXI Write Descriptor Input. 161 | # --------------------------- 162 | i_s_axis_write_desc_addr = write_desc.addr, 163 | i_s_axis_write_desc_len = write_desc.len, 164 | i_s_axis_write_desc_tag = write_desc.tag, 165 | i_s_axis_write_desc_valid = write_desc.valid, 166 | o_s_axis_write_desc_ready = write_desc.ready, 167 | 168 | # AXI Write Descriptor Status. 169 | # ---------------------------- 170 | o_m_axis_write_desc_status_len = write_desc_status.len, 171 | o_m_axis_write_desc_status_tag = write_desc_status.tag, 172 | o_m_axis_write_desc_status_id = write_desc_status.id, 173 | o_m_axis_write_desc_status_dest = write_desc_status.dest, 174 | o_m_axis_write_desc_status_user = write_desc_status.user, 175 | o_m_axis_write_desc_status_error = write_desc_status.error, 176 | o_m_axis_write_desc_status_valid = write_desc_status.valid, 177 | 178 | # AXI Write Data Input. 179 | # --------------------- 180 | i_s_axis_write_data_tdata = write_data.data, 181 | i_s_axis_write_data_tkeep = write_data.keep, 182 | i_s_axis_write_data_tvalid = write_data.valid, 183 | o_s_axis_write_data_tready = write_data.ready, 184 | i_s_axis_write_data_tlast = write_data.last, 185 | i_s_axis_write_data_tid = write_data.id, 186 | i_s_axis_write_data_tdest = write_data.dest, 187 | i_s_axis_write_data_tuser = write_data.user, 188 | 189 | # AXI Master Interface. 190 | # --------------------- 191 | # AW. 192 | i_m_axi_awid = m_axi.aw.id, 193 | i_m_axi_awaddr = m_axi.aw.addr, 194 | i_m_axi_awlen = m_axi.aw.len, 195 | i_m_axi_awsize = m_axi.aw.size, 196 | i_m_axi_awburst = m_axi.aw.burst, 197 | i_m_axi_awlock = m_axi.aw.lock, 198 | i_m_axi_awcache = m_axi.aw.cache, 199 | i_m_axi_awprot = m_axi.aw.prot, 200 | i_m_axi_awvalid = m_axi.aw.valid, 201 | o_m_axi_awready = m_axi.aw.ready, 202 | 203 | # W. 204 | i_m_axi_wdata = m_axi.w.data, 205 | i_m_axi_wstrb = m_axi.w.strb, 206 | i_m_axi_wlast = m_axi.w.last, 207 | i_m_axi_wvalid = m_axi.w.valid, 208 | o_m_axi_wready = m_axi.w.ready, 209 | 210 | # B. 211 | o_m_axi_bid = m_axi.b.id, 212 | o_m_axi_bresp = m_axi.b.resp, 213 | o_m_axi_bvalid = m_axi.b.valid, 214 | i_m_axi_bready = m_axi.b.ready, 215 | 216 | # AR. 217 | i_m_axi_arid = m_axi.ar.id, 218 | i_m_axi_araddr = m_axi.ar.addr, 219 | i_m_axi_arlen = m_axi.ar.len, 220 | i_m_axi_arsize = m_axi.ar.size, 221 | i_m_axi_arburst = m_axi.ar.burst, 222 | i_m_axi_arlock = m_axi.ar.lock, 223 | i_m_axi_arcache = m_axi.ar.cache, 224 | i_m_axi_arprot = m_axi.ar.prot, 225 | i_m_axi_arvalid = m_axi.ar.valid, 226 | o_m_axi_arready = m_axi.ar.ready, 227 | 228 | # R. 229 | o_m_axi_rid = m_axi.r.id, 230 | o_m_axi_rdata = m_axi.r.data, 231 | o_m_axi_rresp = m_axi.r.resp, 232 | o_m_axi_rlast = m_axi.r.last, 233 | o_m_axi_rvalid = m_axi.r.valid, 234 | i_m_axi_rready = m_axi.r.ready, 235 | ) 236 | 237 | # Add Sources. 238 | # ------------ 239 | self.add_sources(platform) 240 | 241 | @staticmethod 242 | def add_sources(platform): 243 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 244 | platform.add_source(os.path.join(rtl_dir, "arbiter.v")) 245 | platform.add_source(os.path.join(rtl_dir, "axi_dma_desc_mux.v")) 246 | platform.add_source(os.path.join(rtl_dir, "axi_dma_wr.v")) 247 | platform.add_source(os.path.join(rtl_dir, "axi_dma_rd.v")) 248 | platform.add_source(os.path.join(rtl_dir, "axi_dma.v")) 249 | -------------------------------------------------------------------------------- /verilog_axi/axi/axi_dp_ram.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axi_dp_ram.v. 8 | 9 | import os 10 | import math 11 | 12 | from migen import * 13 | 14 | from litex.soc.interconnect.axi import * 15 | 16 | from verilog_axi.axi_common import * 17 | 18 | # AXI DP RAM --------------------------------------------------------------------------------------- 19 | 20 | class AXIDPRAM(Module): 21 | def __init__(self, platform, s_axi_a, s_axi_b, size=0x1000, 22 | a_pipeline_output = False, 23 | a_interleave = False, 24 | b_pipeline_output = False, 25 | b_interleave = False, 26 | ): 27 | self.logger = logging.getLogger("AXIDPRAM") 28 | 29 | # Get/Check Parameters. 30 | # --------------------- 31 | 32 | # Clock Domain. 33 | self.logger.info(f"Clock Domain A: {colorer(s_axi_a.clock_domain)}") 34 | self.logger.info(f"Clock Domain B: {colorer(s_axi_b.clock_domain)}") 35 | 36 | # Address width. 37 | address_width = len(s_axi_a.aw.addr) 38 | if len(s_axi_a.aw.addr) != len(s_axi_b.aw.addr): 39 | self.logger.error("{} on {} (A: {} / B: {}), should be {}.".format( 40 | colorer("Different Address Width", color="red"), 41 | colorer("AXI interfaces."), 42 | colorer(len(s_axi_a.aw.addr)), 43 | colorer(len(s_axi_b.aw.addr)), 44 | colorer("the same"))) 45 | raise AXIError() 46 | else: 47 | self.logger.info(f"Address Width: {colorer(address_width)}") 48 | 49 | # Data width. 50 | data_width = len(s_axi_a.w.data) 51 | if len(s_axi_a.w.data) != len(s_axi_b.w.data): 52 | self.logger.error("{} on {} (A: {} / B: {}), should be {}.".format( 53 | colorer("Different Data Width", color="red"), 54 | colorer("AXI interfaces."), 55 | colorer(len(s_axi_a.w.data)), 56 | colorer(len(m_axi_b.w.data)), 57 | colorer("the same"))) 58 | raise AXIError() 59 | else: 60 | self.logger.info(f"Data Width: {colorer(data_width)}") 61 | 62 | # ID width. 63 | id_width = len(s_axi_a.aw.id) 64 | if len(s_axi_a.aw.id) != len(s_axi_b.aw.id): 65 | self.logger.error("{} on {} (A: {} / B: {}), should be {}.".format( 66 | colorer("Different ID Width", color="red"), 67 | colorer("AXI interfaces."), 68 | colorer(len(s_axi_a.aw.id)), 69 | colorer(len(s_axi_b.aw.id)), 70 | colorer("the same"))) 71 | raise AXIError() 72 | else: 73 | self.logger.info(f"ID Width: {colorer(address_width)}") 74 | 75 | # Size. 76 | self.logger.info(f"Size: {colorer(size)}bytes") 77 | 78 | # Pipeline/Interleave. 79 | self.logger.info(f"A Pipeline Output: {a_pipeline_output}.") 80 | self.logger.info(f"A Interleave R/W: {a_interleave}.") 81 | self.logger.info(f"B Pipeline Output: {b_pipeline_output}.") 82 | self.logger.info(f"B Interleave R/W: {b_interleave}.") 83 | 84 | # Module instance. 85 | # ---------------- 86 | 87 | self.specials += Instance("axi_dp_ram", 88 | # Parameters. 89 | # ----------- 90 | # Global. 91 | p_DATA_WIDTH = data_width, 92 | p_ADDR_WIDTH = math.ceil(math.log2(size)), 93 | p_ID_WIDTH = id_width, 94 | 95 | # Pipeline/Interleave. 96 | p_A_PIPELINE_OUTPUT = a_pipeline_output, 97 | p_A_INTERLEAVE = a_interleave, 98 | p_B_PIPELINE_OUTPUT = b_pipeline_output, 99 | p_B_INTERLEAVE = b_interleave, 100 | 101 | # Clk / Rst. 102 | # ---------- 103 | i_a_clk = ClockSignal(s_axi_a.clock_domain), 104 | i_a_rst = ResetSignal(s_axi_a.clock_domain), 105 | i_b_clk = ClockSignal(s_axi_b.clock_domain), 106 | i_b_rst = ResetSignal(s_axi_b.clock_domain), 107 | 108 | # AXI A Slave Interface. 109 | # -------------------- 110 | # AW. 111 | i_s_axi_a_awid = s_axi_a.aw.id, 112 | i_s_axi_a_awaddr = s_axi_a.aw.addr, 113 | i_s_axi_a_awlen = s_axi_a.aw.len, 114 | i_s_axi_a_awsize = s_axi_a.aw.size, 115 | i_s_axi_a_awburst = s_axi_a.aw.burst, 116 | i_s_axi_a_awlock = s_axi_a.aw.lock, 117 | i_s_axi_a_awcache = s_axi_a.aw.cache, 118 | i_s_axi_a_awprot = s_axi_a.aw.prot, 119 | i_s_axi_a_awvalid = s_axi_a.aw.valid, 120 | o_s_axi_a_awready = s_axi_a.aw.ready, 121 | 122 | # W. 123 | i_s_axi_a_wdata = s_axi_a.w.data, 124 | i_s_axi_a_wstrb = s_axi_a.w.strb, 125 | i_s_axi_a_wlast = s_axi_a.w.last, 126 | i_s_axi_a_wvalid = s_axi_a.w.valid, 127 | o_s_axi_a_wready = s_axi_a.w.ready, 128 | 129 | # B. 130 | o_s_axi_a_bid = s_axi_a.b.id, 131 | o_s_axi_a_bresp = s_axi_a.b.resp, 132 | o_s_axi_a_bvalid = s_axi_a.b.valid, 133 | i_s_axi_a_bready = s_axi_a.b.ready, 134 | 135 | # AR. 136 | i_s_axi_a_arid = s_axi_a.ar.id, 137 | i_s_axi_a_araddr = s_axi_a.ar.addr, 138 | i_s_axi_a_arlen = s_axi_a.ar.len, 139 | i_s_axi_a_arsize = s_axi_a.ar.size, 140 | i_s_axi_a_arburst = s_axi_a.ar.burst, 141 | i_s_axi_a_arlock = s_axi_a.ar.lock, 142 | i_s_axi_a_arcache = s_axi_a.ar.cache, 143 | i_s_axi_a_arprot = s_axi_a.ar.prot, 144 | i_s_axi_a_arvalid = s_axi_a.ar.valid, 145 | o_s_axi_a_arready = s_axi_a.ar.ready, 146 | 147 | # R. 148 | o_s_axi_a_rid = s_axi_a.r.id, 149 | o_s_axi_a_rdata = s_axi_a.r.data, 150 | o_s_axi_a_rresp = s_axi_a.r.resp, 151 | o_s_axi_a_rlast = s_axi_a.r.last, 152 | o_s_axi_a_rvalid = s_axi_a.r.valid, 153 | i_s_axi_a_rready = s_axi_a.r.ready, 154 | 155 | # AXI B Slave Interface. 156 | # -------------------- 157 | # AW. 158 | i_s_axi_b_awid = s_axi_b.aw.id, 159 | i_s_axi_b_awaddr = s_axi_b.aw.addr, 160 | i_s_axi_b_awlen = s_axi_b.aw.len, 161 | i_s_axi_b_awsize = s_axi_b.aw.size, 162 | i_s_axi_b_awburst = s_axi_b.aw.burst, 163 | i_s_axi_b_awlock = s_axi_b.aw.lock, 164 | i_s_axi_b_awcache = s_axi_b.aw.cache, 165 | i_s_axi_b_awprot = s_axi_b.aw.prot, 166 | i_s_axi_b_awvalid = s_axi_b.aw.valid, 167 | o_s_axi_b_awready = s_axi_b.aw.ready, 168 | 169 | # W. 170 | i_s_axi_b_wdata = s_axi_b.w.data, 171 | i_s_axi_b_wstrb = s_axi_b.w.strb, 172 | i_s_axi_b_wlast = s_axi_b.w.last, 173 | i_s_axi_b_wvalid = s_axi_b.w.valid, 174 | o_s_axi_b_wready = s_axi_b.w.ready, 175 | 176 | # B. 177 | o_s_axi_b_bid = s_axi_b.b.id, 178 | o_s_axi_b_bresp = s_axi_b.b.resp, 179 | o_s_axi_b_bvalid = s_axi_b.b.valid, 180 | i_s_axi_b_bready = s_axi_b.b.ready, 181 | 182 | # AR. 183 | i_s_axi_b_arid = s_axi_b.ar.id, 184 | i_s_axi_b_araddr = s_axi_b.ar.addr, 185 | i_s_axi_b_arlen = s_axi_b.ar.len, 186 | i_s_axi_b_arsize = s_axi_b.ar.size, 187 | i_s_axi_b_arburst = s_axi_b.ar.burst, 188 | i_s_axi_b_arlock = s_axi_b.ar.lock, 189 | i_s_axi_b_arcache = s_axi_b.ar.cache, 190 | i_s_axi_b_arprot = s_axi_b.ar.prot, 191 | i_s_axi_b_arvalid = s_axi_b.ar.valid, 192 | o_s_axi_b_arready = s_axi_b.ar.ready, 193 | 194 | # R. 195 | o_s_axi_b_rid = s_axi_b.r.id, 196 | o_s_axi_b_rdata = s_axi_b.r.data, 197 | o_s_axi_b_rresp = s_axi_b.r.resp, 198 | o_s_axi_b_rlast = s_axi_b.r.last, 199 | o_s_axi_b_rvalid = s_axi_b.r.valid, 200 | i_s_axi_b_rready = s_axi_b.r.ready, 201 | ) 202 | 203 | # Add Sources. 204 | # ------------ 205 | self.add_sources(platform) 206 | 207 | @staticmethod 208 | def add_sources(platform): 209 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 210 | platform.add_source(os.path.join(rtl_dir, "axi_ram_wr_if.v")) 211 | platform.add_source(os.path.join(rtl_dir, "axi_ram_rd_if.v")) 212 | platform.add_source(os.path.join(rtl_dir, "axi_ram_wr_rd_if.v")) 213 | platform.add_source(os.path.join(rtl_dir, "axi_dp_ram.v")) 214 | -------------------------------------------------------------------------------- /verilog_axi/axi/axi_fifo.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axi_fifo.v. 8 | 9 | import os 10 | from migen import * 11 | 12 | from litex.soc.interconnect.axi import * 13 | 14 | from verilog_axi.axi_common import * 15 | 16 | # AXI FIFO ----------------------------------------------------------------------------------------- 17 | 18 | class AXIFIFO(Module): 19 | def __init__(self, platform, s_axi, m_axi, 20 | write_fifo_depth = 32, 21 | write_fifo_delay = 0, 22 | read_fifo_depth = 32, 23 | read_fifo_delay = 0, 24 | ): 25 | self.logger = logging.getLogger("AXIFIFO") 26 | 27 | # Get/Check Parameters. 28 | # --------------------- 29 | 30 | # Clock Domain. 31 | clock_domain = s_axi.clock_domain 32 | if s_axi.clock_domain != m_axi.clock_domain: 33 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 34 | colorer("Different Clock Domain", color="red"), 35 | colorer("AXI interfaces."), 36 | colorer(s_axi.clock_domain), 37 | colorer(m_axi.clock_domain), 38 | colorer("the same"))) 39 | raise AXIError() 40 | else: 41 | self.logger.info(f"Clock Domain: {colorer(clock_domain)}") 42 | 43 | # Address width. 44 | address_width = len(s_axi.aw.addr) 45 | if len(s_axi.aw.addr) != len(m_axi.aw.addr): 46 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 47 | colorer("Different Address Width", color="red"), 48 | colorer("AXI interfaces."), 49 | colorer(len(s_axi.aw.addr)), 50 | colorer(len(m_axi.aw.addr)), 51 | colorer("the same"))) 52 | raise AXIError() 53 | else: 54 | self.logger.info(f"Address Width: {colorer(address_width)}") 55 | 56 | # Data width. 57 | data_width = len(s_axi.w.data) 58 | if len(s_axi.w.data) != len(m_axi.w.data): 59 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 60 | colorer("Different Data Width", color="red"), 61 | colorer("AXI interfaces."), 62 | colorer(len(s_axi.w.data)), 63 | colorer(len(m_axi.w.data)), 64 | colorer("the same"))) 65 | raise AXIError() 66 | else: 67 | self.logger.info(f"Data Width: {colorer(data_width)}") 68 | 69 | # ID width. 70 | id_width = len(s_axi.aw.id) 71 | if len(s_axi.aw.id) != len(m_axi.aw.id): 72 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 73 | colorer("Different ID Width", color="red"), 74 | colorer("AXI interfaces."), 75 | colorer(len(s_axi.aw.id)), 76 | colorer(len(m_axi.aw.id)), 77 | colorer("the same"))) 78 | raise AXIError() 79 | else: 80 | self.logger.info(f"ID Width: {colorer(address_width)}") 81 | 82 | # Depth. 83 | self.logger.info(f"Write FIFO Depth: {write_fifo_depth}.") 84 | self.logger.info(f"Write FIFO Delay: {write_fifo_delay}.") 85 | self.logger.info(f"Read FIFO Depth: {read_fifo_depth}.") 86 | self.logger.info(f"Read FIFO Delay: {read_fifo_delay}.") 87 | 88 | # User width. 89 | for c in ["aw", "w", "b", "ar", "r"]: 90 | m_axi_c = getattr(m_axi, c) 91 | s_axi_c = getattr(s_axi, c) 92 | if s_axi_c.user_width != m_axi_c.user_width: 93 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 94 | colorer("Different User Width", color="red"), 95 | colorer("AXI interfaces."), 96 | colorer(s_axi_c.user_width), 97 | colorer(m_axi_c.user_width), 98 | colorer("the same"))) 99 | raise AXIError() 100 | else: 101 | self.logger.info(f"{c.upper()} User Width: {colorer(m_axi_c.user_width)}") 102 | 103 | # Module instance. 104 | # ---------------- 105 | 106 | self.specials += Instance("axi_fifo", 107 | # Parameters. 108 | # ----------- 109 | p_DATA_WIDTH = data_width, 110 | p_ADDR_WIDTH = address_width, 111 | p_ID_WIDTH = id_width, 112 | 113 | p_AWUSER_ENABLE = s_axi.aw.user_width > 0, 114 | p_AWUSER_WIDTH = max(1, s_axi.aw.user_width), 115 | p_WUSER_ENABLE = s_axi.w.user_width > 0, 116 | p_WUSER_WIDTH = max(1, s_axi.w.user_width), 117 | p_BUSER_ENABLE = s_axi.b.user_width > 0, 118 | p_BUSER_WIDTH = max(1, s_axi.b.user_width), 119 | p_ARUSER_ENABLE = s_axi.ar.user_width > 0, 120 | p_ARUSER_WIDTH = max(1, s_axi.ar.user_width), 121 | p_RUSER_ENABLE = s_axi.r.user_width > 0, 122 | p_RUSER_WIDTH = max(1, s_axi.r.user_width), 123 | 124 | # Depth/Delay. 125 | p_WRITE_FIFO_DEPTH = write_fifo_depth, 126 | p_WRITE_FIFO_DELAY = write_fifo_delay, 127 | p_READ_FIFO_DEPTH = read_fifo_depth, 128 | p_READ_FIFO_DELAY = read_fifo_delay, 129 | 130 | # Clk / Rst. 131 | # ---------- 132 | i_clk = ClockSignal(clock_domain), 133 | i_rst = ResetSignal(clock_domain), 134 | 135 | # AXI Slave Interface. 136 | # -------------------- 137 | # AW. 138 | i_s_axi_awid = s_axi.aw.id, 139 | i_s_axi_awaddr = s_axi.aw.addr, 140 | i_s_axi_awlen = s_axi.aw.len, 141 | i_s_axi_awsize = s_axi.aw.size, 142 | i_s_axi_awburst = s_axi.aw.burst, 143 | i_s_axi_awlock = s_axi.aw.lock, 144 | i_s_axi_awcache = s_axi.aw.cache, 145 | i_s_axi_awprot = s_axi.aw.prot, 146 | i_s_axi_awqos = s_axi.aw.qos, 147 | i_s_axi_awregion = s_axi.aw.region, 148 | i_s_axi_awuser = s_axi.aw.user, 149 | i_s_axi_awvalid = s_axi.aw.valid, 150 | o_s_axi_awready = s_axi.aw.ready, 151 | 152 | # W. 153 | i_s_axi_wdata = s_axi.w.data, 154 | i_s_axi_wstrb = s_axi.w.strb, 155 | i_s_axi_wlast = s_axi.w.last, 156 | i_s_axi_wuser = s_axi.w.user, 157 | i_s_axi_wvalid = s_axi.w.valid, 158 | o_s_axi_wready = s_axi.w.ready, 159 | 160 | # B. 161 | o_s_axi_bid = s_axi.b.id, 162 | o_s_axi_bresp = s_axi.b.resp, 163 | o_s_axi_buser = s_axi.b.user, 164 | o_s_axi_bvalid = s_axi.b.valid, 165 | i_s_axi_bready = s_axi.b.ready, 166 | 167 | # AR. 168 | i_s_axi_arid = s_axi.ar.id, 169 | i_s_axi_araddr = s_axi.ar.addr, 170 | i_s_axi_arlen = s_axi.ar.len, 171 | i_s_axi_arsize = s_axi.ar.size, 172 | i_s_axi_arburst = s_axi.ar.burst, 173 | i_s_axi_arlock = s_axi.ar.lock, 174 | i_s_axi_arcache = s_axi.ar.cache, 175 | i_s_axi_arprot = s_axi.ar.prot, 176 | i_s_axi_arqos = s_axi.ar.qos, 177 | i_s_axi_arregion = s_axi.ar.region, 178 | i_s_axi_aruser = s_axi.ar.user, 179 | i_s_axi_arvalid = s_axi.ar.valid, 180 | o_s_axi_arready = s_axi.ar.ready, 181 | 182 | # R. 183 | o_s_axi_rid = s_axi.r.id, 184 | o_s_axi_rdata = s_axi.r.data, 185 | o_s_axi_rresp = s_axi.r.resp, 186 | o_s_axi_rlast = s_axi.r.last, 187 | o_s_axi_ruser = s_axi.r.user, 188 | o_s_axi_rvalid = s_axi.r.valid, 189 | i_s_axi_rready = s_axi.r.ready, 190 | 191 | # AXI Master Interface. 192 | # --------------------- 193 | # AW. 194 | o_m_axi_awid = m_axi.aw.id, 195 | o_m_axi_awaddr = m_axi.aw.addr, 196 | o_m_axi_awlen = m_axi.aw.len, 197 | o_m_axi_awsize = m_axi.aw.size, 198 | o_m_axi_awburst = m_axi.aw.burst, 199 | o_m_axi_awlock = m_axi.aw.lock, 200 | o_m_axi_awcache = m_axi.aw.cache, 201 | o_m_axi_awprot = m_axi.aw.prot, 202 | o_m_axi_awqos = m_axi.aw.qos, 203 | o_m_axi_awregion = m_axi.aw.region, 204 | o_m_axi_awuser = m_axi.aw.user, 205 | o_m_axi_awvalid = m_axi.aw.valid, 206 | i_m_axi_awready = m_axi.aw.ready, 207 | 208 | # W. 209 | o_m_axi_wdata = m_axi.w.data, 210 | o_m_axi_wstrb = m_axi.w.strb, 211 | o_m_axi_wlast = m_axi.w.last, 212 | o_m_axi_wuser = m_axi.w.user, 213 | o_m_axi_wvalid = m_axi.w.valid, 214 | i_m_axi_wready = m_axi.w.ready, 215 | 216 | # B. 217 | i_m_axi_bid = m_axi.b.id, 218 | i_m_axi_bresp = m_axi.b.resp, 219 | i_m_axi_buser = m_axi.b.user, 220 | i_m_axi_bvalid = m_axi.b.valid, 221 | o_m_axi_bready = m_axi.b.ready, 222 | 223 | # AR. 224 | o_m_axi_arid = m_axi.ar.id, 225 | o_m_axi_araddr = m_axi.ar.addr, 226 | o_m_axi_arlen = m_axi.ar.len, 227 | o_m_axi_arsize = m_axi.ar.size, 228 | o_m_axi_arburst = m_axi.ar.burst, 229 | o_m_axi_arlock = m_axi.ar.lock, 230 | o_m_axi_arcache = m_axi.ar.cache, 231 | o_m_axi_arprot = m_axi.ar.prot, 232 | o_m_axi_arqos = m_axi.ar.qos, 233 | o_m_axi_arregion = m_axi.ar.region, 234 | o_m_axi_aruser = m_axi.ar.user, 235 | o_m_axi_arvalid = m_axi.ar.valid, 236 | i_m_axi_arready = m_axi.ar.ready, 237 | 238 | # R. 239 | i_m_axi_rid = m_axi.r.id, 240 | i_m_axi_rdata = m_axi.r.data, 241 | i_m_axi_rresp = m_axi.r.resp, 242 | i_m_axi_rlast = m_axi.r.last, 243 | i_m_axi_ruser = m_axi.r.user, 244 | i_m_axi_rvalid = m_axi.r.valid, 245 | o_m_axi_rready = m_axi.r.ready, 246 | ) 247 | 248 | # Add Sources. 249 | # ------------ 250 | self.add_sources(platform) 251 | 252 | @staticmethod 253 | def add_sources(platform): 254 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 255 | platform.add_source(os.path.join(rtl_dir, "axi_fifo_wr.v")) 256 | platform.add_source(os.path.join(rtl_dir, "axi_fifo_rd.v")) 257 | platform.add_source(os.path.join(rtl_dir, "axi_fifo.v")) 258 | -------------------------------------------------------------------------------- /verilog_axi/axi/axi_interconnect.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axi_interconnect.v. 8 | 9 | import os 10 | import math 11 | 12 | from migen import * 13 | 14 | from litex.soc.interconnect.axi import * 15 | 16 | from verilog_axi.axi_common import * 17 | 18 | # AXI Interconnect Interface ----------------------------------------------------------------------- 19 | 20 | class AXIInterconnectInterface: 21 | def __init__(self, axi, origin=None, size=None): 22 | self.axi = axi 23 | self.origin = origin 24 | self.size = size 25 | 26 | # AXI Interconnect --------------------------------------------------------------------------------- 27 | 28 | class AXIInterconnect(Module): 29 | def __init__(self, platform): 30 | self.logger = logging.getLogger("AXIInterconnect") 31 | self.s_axis = {} 32 | self.m_axis = {} 33 | 34 | # Add Sources. 35 | # ------------ 36 | self.add_sources(platform) 37 | 38 | def get_if_name(self, axi): 39 | axi_ifs = {**self.s_axis, **self.m_axis} 40 | for name, axi_if in axi_ifs.items(): 41 | if axi is axi_if.axi: 42 | return name 43 | return None 44 | 45 | def add_slave(self, name=None, s_axi=None): 46 | # Get/Check Name. 47 | name = f"s_axi{len(self.s_axis)}" if name is None else name 48 | if name in self.s_axis.keys(): 49 | raise ValueError # FIXME: Add error message. 50 | 51 | # Add Slave. 52 | assert isinstance(s_axi, AXIInterface) 53 | s_axi = AXIInterconnectInterface(axi=s_axi) 54 | self.s_axis[name] = s_axi 55 | 56 | # Info. 57 | self.logger.info(f"Add AXI Slave {name} interface.") 58 | 59 | # Check. 60 | self.get_check_parameters(show=False) 61 | 62 | def add_master(self, name=None, m_axi=None, origin=None, size=None): 63 | 64 | # Get/Check Name. 65 | name = f"m_axi{len(self.m_axis)}" if name is None else name 66 | if name in self.m_axis.keys(): 67 | raise ValueError # FIXME: Add error message. 68 | 69 | # Add Master. 70 | assert isinstance(m_axi, AXIInterface) 71 | assert origin is not None 72 | assert size is not None 73 | m_axi = AXIInterconnectInterface( 74 | axi = m_axi, 75 | origin = origin, 76 | size = size, 77 | ) 78 | self.m_axis[name] = m_axi 79 | 80 | # Info. 81 | self.logger.info(f"Add AXI Master {name} interface.") 82 | self.logger.info(f" Origin: 0x{origin:08x}.") 83 | self.logger.info(f" Size: 0x{size:0x}.") 84 | 85 | # Check. 86 | self.get_check_parameters(show=False) 87 | 88 | def get_check_parameters(self, show=True): 89 | axi_ifs = {**self.s_axis, **self.m_axis} 90 | axis = [axi_if.axi for name, axi_if in axi_ifs.items()] 91 | 92 | # Clock Domain. 93 | self.clock_domain = clock_domain = axis[0].clock_domain 94 | for i, axi in enumerate(axis): 95 | if i == 0: 96 | continue 97 | else: 98 | if axi.clock_domain != clock_domain: 99 | self.logger.error("{} on {} ({}: {} / {}: {}), should be {}.".format( 100 | colorer("Different Clock Domain", color="red"), 101 | colorer("AXI interfaces."), 102 | self.get_if_name(axis[0]), 103 | colorer(clock_domain), 104 | self.get_if_name(axi), 105 | colorer(axi.clock_domain), 106 | colorer("the same"))) 107 | raise AXIError() 108 | if show: 109 | self.logger.info(f"Clock Domain: {colorer(clock_domain)}") 110 | 111 | # Address width. 112 | self.address_width = address_width = len(axis[0].aw.addr) 113 | for i, axi in enumerate(axis): 114 | if i == 0: 115 | continue 116 | else: 117 | if len(axi.aw.addr) != address_width: 118 | self.logger.error("{} on {} ({}: {} / {}: {}), should be {}.".format( 119 | colorer("Different Address Width", color="red"), 120 | colorer("AXI interfaces."), 121 | self.get_if_name(axis[0]), 122 | colorer(address_width), 123 | self.get_if_name(axi), 124 | colorer(len(axi.aw.addr)), 125 | colorer("the same"))) 126 | raise AXIError() 127 | if show: 128 | self.logger.info(f"Address Width: {colorer(address_width)}") 129 | 130 | # Data width. 131 | self.data_width = data_width = len(axis[0].w.data) 132 | for i, axi in enumerate(axis): 133 | if i == 0: 134 | continue 135 | else: 136 | if len(axi.w.data) != data_width: 137 | self.logger.error("{} on {} ({}: {} / {}: {}), should be {}.".format( 138 | colorer("Different Data Width", color="red"), 139 | colorer("AXI interfaces."), 140 | self.get_if_name(axis[0]), 141 | colorer(data_width), 142 | self.get_if_name(axi), 143 | colorer(len(axi.w.data)), 144 | colorer("the same"))) 145 | raise AXIError() 146 | if show: 147 | self.logger.info(f"Data Width: {colorer(data_width)}") 148 | 149 | # ID width. 150 | # FIXME: Add check. 151 | self.id_width = id_width = len(axis[0].aw.id) 152 | if show: 153 | self.logger.info(f"ID Width: {colorer(id_width)}") 154 | 155 | # Burst. 156 | # FIXME: Add check. 157 | 158 | # User width. 159 | for i, axi in enumerate(axis): 160 | if i == 0: 161 | continue 162 | else: 163 | for c in ["aw", "w", "b", "ar", "r"]: 164 | axi_c_0 = getattr(axis[0], c) 165 | axi_c_i = getattr(axis[i], c) 166 | if axi_c_0.user_width != axi_c_i.user_width: 167 | self.logger.error("{} on {} ({} / {}), should be {}.".format( 168 | colorer("Different User Width", color="red"), 169 | colorer("AXI interfaces."), 170 | colorer(axi_c_0.user_width), 171 | colorer(axi_c_i.user_width), 172 | colorer("the same"))) 173 | raise AXIError() 174 | else: 175 | self.logger.info(f"{c.upper()} User Width: {colorer(axi_c_0.user_width)}") 176 | 177 | def do_finalize(self): 178 | # Get/Check Parameters. 179 | # --------------------- 180 | self.get_check_parameters() 181 | 182 | # Get/Check Parameters. 183 | # --------------------- 184 | self.logger.info(f"Finalized {len(self.s_axis)}X{len(self.m_axis)} Interconnect:") 185 | self.logger.info(f" Slaves:") 186 | for s_name, s_axi in self.s_axis.items(): 187 | self.logger.info(f" - {s_name}.") 188 | self.logger.info(f" Masters:") 189 | for m_name, m_axi in self.m_axis.items(): 190 | self.logger.info(f" - {m_name}, Origin: 0x{m_axi.origin:08x}, Size: 0x{m_axi.size:0x}.") 191 | 192 | 193 | # Module instance. 194 | # ---------------- 195 | 196 | s_axis = [axi_if.axi for axi_if in self.s_axis.values()] 197 | m_axis = [axi_if.axi for axi_if in self.m_axis.values()] 198 | m_origins = [axi_if.origin for axi_if in self.m_axis.values()] 199 | m_widths = [math.ceil(math.log2(axi_if.size)) for axi_if in self.m_axis.values()] 200 | 201 | def format_m_params(params, width): 202 | value = 0 203 | for param in reversed(params): 204 | value <<= width 205 | value |= param 206 | return Constant(value, len(params)*width) 207 | 208 | 209 | # User Enable/Width computation. 210 | awuser_enable = 0 if not hasattr(s_axis[0].aw, "user") else 1 211 | awuser_width = 1 if not hasattr(s_axis[0].aw, "user") else len(s_axis[0].aw) 212 | wuser_enable = 0 if not hasattr(s_axis[0].w, "user") else 1 213 | wuser_width = 1 if not hasattr(s_axis[0].w, "user") else len(s_axis[0].w) 214 | buser_enable = 0 if not hasattr(s_axis[0].b, "user") else 1 215 | buser_width = 1 if not hasattr(s_axis[0].b, "user") else len(s_axis[0].b) 216 | aruser_enable = 0 if not hasattr(s_axis[0].ar, "user") else 1 217 | aruser_width = 1 if not hasattr(s_axis[0].ar, "user") else len(s_axis[0].ar) 218 | ruser_enable = 0 if not hasattr(s_axis[0].r, "user") else 1 219 | ruser_width = 1 if not hasattr(s_axis[0].r, "user") else len(s_axis[0].r) 220 | 221 | self.specials += Instance("axi_interconnect", 222 | # Parameters. 223 | # ----------- 224 | p_S_COUNT = len(s_axis), 225 | p_M_COUNT = len(m_axis), 226 | p_DATA_WIDTH = self.data_width, 227 | p_ADDR_WIDTH = self.address_width, 228 | p_ID_WIDTH = self.id_width, 229 | 230 | p_AWUSER_ENABLE = awuser_enable, 231 | p_AWUSER_WIDTH = awuser_width, 232 | p_WUSER_ENABLE = wuser_enable, 233 | p_WUSER_WIDTH = wuser_width, 234 | p_BUSER_ENABLE = buser_enable, 235 | p_BUSER_WIDTH = buser_width, 236 | p_ARUSER_ENABLE = aruser_enable, 237 | p_ARUSER_WIDTH = aruser_width, 238 | p_RUSER_ENABLE = ruser_enable, 239 | p_RUSER_WIDTH = ruser_width, 240 | 241 | # Masters Origin/Size. 242 | p_M_BASE_ADDR = format_m_params(m_origins, self.address_width), 243 | p_M_ADDR_WIDTH = format_m_params(m_widths, 32), 244 | 245 | # FIXME: Expose other parameters. 246 | 247 | # Clk / Rst. 248 | # ---------- 249 | i_clk = ClockSignal(self.clock_domain), 250 | i_rst = ResetSignal(self.clock_domain), 251 | 252 | # AXI Slave Interfaces. 253 | # -------------------- 254 | # AW. 255 | i_s_axi_awid = Cat(*[s_axi.aw.id for s_axi in s_axis]), 256 | i_s_axi_awaddr = Cat(*[s_axi.aw.addr for s_axi in s_axis]), 257 | i_s_axi_awlen = Cat(*[s_axi.aw.len for s_axi in s_axis]), 258 | i_s_axi_awsize = Cat(*[s_axi.aw.size for s_axi in s_axis]), 259 | i_s_axi_awburst = Cat(*[s_axi.aw.burst for s_axi in s_axis]), 260 | i_s_axi_awlock = Cat(*[s_axi.aw.lock for s_axi in s_axis]), 261 | i_s_axi_awcache = Cat(*[s_axi.aw.cache for s_axi in s_axis]), 262 | i_s_axi_awprot = Cat(*[s_axi.aw.prot for s_axi in s_axis]), 263 | i_s_axi_awqos = Cat(*[s_axi.aw.qos for s_axi in s_axis]), 264 | i_s_axi_awuser = Cat(*[s_axi.aw.user for s_axi in s_axis]), 265 | i_s_axi_awvalid = Cat(*[s_axi.aw.valid for s_axi in s_axis]), 266 | o_s_axi_awready = Cat(*[s_axi.aw.ready for s_axi in s_axis]), 267 | 268 | # W. 269 | i_s_axi_wdata = Cat(*[s_axi.w.data for s_axi in s_axis]), 270 | i_s_axi_wstrb = Cat(*[s_axi.w.strb for s_axi in s_axis]), 271 | i_s_axi_wlast = Cat(*[s_axi.w.last for s_axi in s_axis]), 272 | i_s_axi_wuser = Cat(*[s_axi.w.user for s_axi in s_axis]), 273 | i_s_axi_wvalid = Cat(*[s_axi.w.valid for s_axi in s_axis]), 274 | o_s_axi_wready = Cat(*[s_axi.w.ready for s_axi in s_axis]), 275 | 276 | # B. 277 | o_s_axi_bid = Cat(*[s_axi.b.id for s_axi in s_axis]), 278 | o_s_axi_bresp = Cat(*[s_axi.b.resp for s_axi in s_axis]), 279 | o_s_axi_buser = Cat(*[s_axi.b.user for s_axi in s_axis]), 280 | o_s_axi_bvalid = Cat(*[s_axi.b.valid for s_axi in s_axis]), 281 | i_s_axi_bready = Cat(*[s_axi.b.ready for s_axi in s_axis]), 282 | 283 | # AR. 284 | i_s_axi_arid = Cat(*[s_axi.ar.id for s_axi in s_axis]), 285 | i_s_axi_araddr = Cat(*[s_axi.ar.addr for s_axi in s_axis]), 286 | i_s_axi_arlen = Cat(*[s_axi.ar.len for s_axi in s_axis]), 287 | i_s_axi_arsize = Cat(*[s_axi.ar.size for s_axi in s_axis]), 288 | i_s_axi_arburst = Cat(*[s_axi.ar.burst for s_axi in s_axis]), 289 | i_s_axi_arlock = Cat(*[s_axi.ar.lock for s_axi in s_axis]), 290 | i_s_axi_arcache = Cat(*[s_axi.ar.cache for s_axi in s_axis]), 291 | i_s_axi_arprot = Cat(*[s_axi.ar.prot for s_axi in s_axis]), 292 | i_s_axi_arqos = Cat(*[s_axi.ar.qos for s_axi in s_axis]), 293 | i_s_axi_aruser = Cat(*[s_axi.ar.user for s_axi in s_axis]), 294 | i_s_axi_arvalid = Cat(*[s_axi.ar.valid for s_axi in s_axis]), 295 | o_s_axi_arready = Cat(*[s_axi.ar.ready for s_axi in s_axis]), 296 | 297 | # R. 298 | o_s_axi_rid = Cat(*[s_axi.r.id for s_axi in s_axis]), 299 | o_s_axi_rdata = Cat(*[s_axi.r.data for s_axi in s_axis]), 300 | o_s_axi_rresp = Cat(*[s_axi.r.resp for s_axi in s_axis]), 301 | o_s_axi_rlast = Cat(*[s_axi.r.last for s_axi in s_axis]), 302 | o_s_axi_ruser = Cat(*[s_axi.r.user for s_axi in s_axis]), 303 | o_s_axi_rvalid = Cat(*[s_axi.r.valid for s_axi in s_axis]), 304 | i_s_axi_rready = Cat(*[s_axi.r.ready for s_axi in s_axis]), 305 | 306 | # AXI Master Interfaces. 307 | # ---------------------- 308 | # AW. 309 | o_m_axi_awid = Cat(*[m_axi.aw.id for m_axi in m_axis]), 310 | o_m_axi_awaddr = Cat(*[m_axi.aw.addr for m_axi in m_axis]), 311 | o_m_axi_awlen = Cat(*[m_axi.aw.len for m_axi in m_axis]), 312 | o_m_axi_awsize = Cat(*[m_axi.aw.size for m_axi in m_axis]), 313 | o_m_axi_awburst = Cat(*[m_axi.aw.burst for m_axi in m_axis]), 314 | o_m_axi_awlock = Cat(*[m_axi.aw.lock for m_axi in m_axis]), 315 | o_m_axi_awcache = Cat(*[m_axi.aw.cache for m_axi in m_axis]), 316 | o_m_axi_awprot = Cat(*[m_axi.aw.prot for m_axi in m_axis]), 317 | o_m_axi_awqos = Cat(*[m_axi.aw.qos for m_axi in m_axis]), 318 | o_m_axi_awregion = Cat(*[m_axi.aw.region for m_axi in m_axis]), 319 | o_m_axi_awuser = Cat(*[m_axi.aw.user for m_axi in m_axis]), 320 | o_m_axi_awvalid = Cat(*[m_axi.aw.valid for m_axi in m_axis]), 321 | i_m_axi_awready = Cat(*[m_axi.aw.ready for m_axi in m_axis]), 322 | 323 | # W. 324 | o_m_axi_wdata = Cat(*[m_axi.w.data for m_axi in m_axis]), 325 | o_m_axi_wstrb = Cat(*[m_axi.w.strb for m_axi in m_axis]), 326 | o_m_axi_wlast = Cat(*[m_axi.w.last for m_axi in m_axis]), 327 | o_m_axi_wuser = Cat(*[m_axi.w.user for m_axi in m_axis]), 328 | o_m_axi_wvalid = Cat(*[m_axi.w.valid for m_axi in m_axis]), 329 | i_m_axi_wready = Cat(*[m_axi.w.ready for m_axi in m_axis]), 330 | 331 | # B. 332 | i_m_axi_bid = Cat(*[m_axi.b.id for m_axi in m_axis]), 333 | i_m_axi_bresp = Cat(*[m_axi.b.resp for m_axi in m_axis]), 334 | i_m_axi_buser = Cat(*[m_axi.b.user for m_axi in m_axis]), 335 | i_m_axi_bvalid = Cat(*[m_axi.b.valid for m_axi in m_axis]), 336 | o_m_axi_bready = Cat(*[m_axi.b.ready for m_axi in m_axis]), 337 | 338 | # AR. 339 | o_m_axi_arid = Cat(*[m_axi.ar.id for m_axi in m_axis]), 340 | o_m_axi_araddr = Cat(*[m_axi.ar.addr for m_axi in m_axis]), 341 | o_m_axi_arlen = Cat(*[m_axi.ar.len for m_axi in m_axis]), 342 | o_m_axi_arsize = Cat(*[m_axi.ar.size for m_axi in m_axis]), 343 | o_m_axi_arburst = Cat(*[m_axi.ar.burst for m_axi in m_axis]), 344 | o_m_axi_arlock = Cat(*[m_axi.ar.lock for m_axi in m_axis]), 345 | o_m_axi_arcache = Cat(*[m_axi.ar.cache for m_axi in m_axis]), 346 | o_m_axi_arprot = Cat(*[m_axi.ar.prot for m_axi in m_axis]), 347 | o_m_axi_arqos = Cat(*[m_axi.ar.qos for m_axi in m_axis]), 348 | o_m_axi_arregion = Cat(*[m_axi.ar.region for m_axi in m_axis]), 349 | o_m_axi_aruser = Cat(*[m_axi.ar.user for m_axi in m_axis]), 350 | o_m_axi_arvalid = Cat(*[m_axi.ar.valid for m_axi in m_axis]), 351 | i_m_axi_arready = Cat(*[m_axi.ar.ready for m_axi in m_axis]), 352 | 353 | # R. 354 | i_m_axi_rid = Cat(*[m_axi.r.id for m_axi in m_axis]), 355 | i_m_axi_rdata = Cat(*[m_axi.r.data for m_axi in m_axis]), 356 | i_m_axi_rresp = Cat(*[m_axi.r.resp for m_axi in m_axis]), 357 | i_m_axi_rlast = Cat(*[m_axi.r.last for m_axi in m_axis]), 358 | i_m_axi_ruser = Cat(*[m_axi.r.user for m_axi in m_axis]), 359 | i_m_axi_rvalid = Cat(*[m_axi.r.valid for m_axi in m_axis]), 360 | o_m_axi_rready = Cat(*[m_axi.r.ready for m_axi in m_axis]), 361 | ) 362 | 363 | @staticmethod 364 | def add_sources(platform): 365 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 366 | platform.add_source(os.path.join(rtl_dir, "arbiter.v")) 367 | platform.add_source(os.path.join(rtl_dir, "priority_encoder.v")) 368 | platform.add_source(os.path.join(rtl_dir, "axi_interconnect.v")) 369 | -------------------------------------------------------------------------------- /verilog_axi/axi/axi_ram.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axi_ram.v. 8 | 9 | import os 10 | import math 11 | 12 | from migen import * 13 | 14 | from litex.soc.interconnect.axi import * 15 | 16 | from verilog_axi.axi_common import * 17 | 18 | # AXI RAM ------------------------------------------------------------------------------------------ 19 | 20 | class AXIRAM(Module): 21 | def __init__(self, platform, s_axi, size=1024, pipeline_output=False): 22 | self.logger = logging.getLogger("AXIRAM") 23 | 24 | # Get/Check Parameters. 25 | # --------------------- 26 | 27 | # Clock Domain. 28 | clock_domain = s_axi.clock_domain 29 | self.logger.info(f"Clock Domain: {colorer(clock_domain)}") 30 | 31 | # Address width. 32 | address_width = len(s_axi.aw.addr) 33 | self.logger.info(f"Address Width: {colorer(address_width)}") 34 | 35 | # Data width. 36 | data_width = len(s_axi.w.data) 37 | self.logger.info(f"Data Width: {colorer(data_width)}") 38 | 39 | # Size. 40 | self.logger.info(f"Size: {colorer(size)}bytes") 41 | 42 | # ID width. 43 | id_width = len(s_axi.aw.id) 44 | self.logger.info(f"ID Width: {colorer(id_width)}") 45 | 46 | # Module instance. 47 | # ---------------- 48 | 49 | self.specials += Instance("axi_ram", 50 | # Parameters. 51 | # ----------- 52 | p_DATA_WIDTH = data_width, 53 | p_ADDR_WIDTH = math.ceil(math.log2(size)), 54 | p_ID_WIDTH = id_width, 55 | p_PIPELINE_OUTPUT = pipeline_output, 56 | 57 | # Clk / Rst. 58 | # ---------- 59 | i_clk = ClockSignal(clock_domain), 60 | i_rst = ResetSignal(clock_domain), 61 | 62 | # AXI Slave Interface. 63 | # -------------------- 64 | # AW. 65 | i_s_axi_awid = s_axi.aw.id, 66 | i_s_axi_awaddr = s_axi.aw.addr, 67 | i_s_axi_awlen = s_axi.aw.len, 68 | i_s_axi_awsize = s_axi.aw.size, 69 | i_s_axi_awburst = s_axi.aw.burst, 70 | i_s_axi_awlock = s_axi.aw.lock, 71 | i_s_axi_awcache = s_axi.aw.cache, 72 | i_s_axi_awprot = s_axi.aw.prot, 73 | i_s_axi_awvalid = s_axi.aw.valid, 74 | o_s_axi_awready = s_axi.aw.ready, 75 | 76 | # W. 77 | i_s_axi_wdata = s_axi.w.data, 78 | i_s_axi_wstrb = s_axi.w.strb, 79 | i_s_axi_wlast = s_axi.w.last, 80 | i_s_axi_wvalid = s_axi.w.valid, 81 | o_s_axi_wready = s_axi.w.ready, 82 | 83 | # B. 84 | o_s_axi_bid = s_axi.b.id, 85 | o_s_axi_bresp = s_axi.b.resp, 86 | o_s_axi_bvalid = s_axi.b.valid, 87 | i_s_axi_bready = s_axi.b.ready, 88 | 89 | # AR. 90 | i_s_axi_arid = s_axi.ar.id, 91 | i_s_axi_araddr = s_axi.ar.addr, 92 | i_s_axi_arlen = s_axi.ar.len, 93 | i_s_axi_arsize = s_axi.ar.size, 94 | i_s_axi_arburst = s_axi.ar.burst, 95 | i_s_axi_arlock = s_axi.ar.lock, 96 | i_s_axi_arcache = s_axi.ar.cache, 97 | i_s_axi_arprot = s_axi.ar.prot, 98 | i_s_axi_arvalid = s_axi.ar.valid, 99 | o_s_axi_arready = s_axi.ar.ready, 100 | 101 | # R. 102 | o_s_axi_rid = s_axi.r.id, 103 | o_s_axi_rdata = s_axi.r.data, 104 | o_s_axi_rresp = s_axi.r.resp, 105 | o_s_axi_rlast = s_axi.r.last, 106 | o_s_axi_rvalid = s_axi.r.valid, 107 | i_s_axi_rready = s_axi.r.ready, 108 | ) 109 | 110 | # Add Sources. 111 | # ------------ 112 | self.add_sources(platform) 113 | 114 | @staticmethod 115 | def add_sources(platform): 116 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 117 | platform.add_source(os.path.join(rtl_dir, "axi_ram.v")) 118 | -------------------------------------------------------------------------------- /verilog_axi/axi/axi_register.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axi_register.v. 8 | 9 | import os 10 | 11 | from migen import * 12 | 13 | from litex.soc.interconnect.axi import * 14 | 15 | from verilog_axi.axi_common import * 16 | 17 | # AXI Register ------------------------------------------------------------------------------------- 18 | 19 | class AXIRegister(Module): 20 | def __init__(self, platform, s_axi, m_axi, 21 | aw_reg = AXIRegister.SIMPLE_BUFFER, 22 | w_reg = AXIRegister.SKID_BUFFER, 23 | b_reg = AXIRegister.SIMPLE_BUFFER, 24 | ar_reg = AXIRegister.SIMPLE_BUFFER, 25 | r_reg = AXIRegister.SKID_BUFFER, 26 | ): 27 | self.logger = logging.getLogger("AXIAdapter") 28 | 29 | # Get/Check Parameters. 30 | # --------------------- 31 | 32 | # Clock Domain. 33 | clock_domain = s_axi.clock_domain 34 | if s_axi.clock_domain != m_axi.clock_domain: 35 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 36 | colorer("Different Clock Domain", color="red"), 37 | colorer("AXI interfaces."), 38 | colorer(s_axi.clock_domain), 39 | colorer(m_axi.clock_domain), 40 | colorer("the same"))) 41 | raise AXIError() 42 | else: 43 | self.logger.info(f"Clock Domain: {colorer(clock_domain)}") 44 | 45 | # Address width. 46 | address_width = len(s_axi.aw.addr) 47 | if len(s_axi.aw.addr) != len(m_axi.aw.addr): 48 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 49 | colorer("Different Address Width", color="red"), 50 | colorer("AXI interfaces."), 51 | colorer(len(s_axi.aw.addr)), 52 | colorer(len(m_axi.aw.addr)), 53 | colorer("the same"))) 54 | raise AXIError() 55 | else: 56 | self.logger.info(f"Address Width: {colorer(address_width)}") 57 | 58 | # Data width. 59 | data_width = len(s_axi.w.data) 60 | if len(s_axi.w.data) != len(m_axi.w.data): 61 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 62 | colorer("Different Data Width", color="red"), 63 | colorer("AXI interfaces."), 64 | colorer(len(s_axi.w.data)), 65 | colorer(len(m_axi.w.data)), 66 | colorer("the same"))) 67 | raise AXIError() 68 | else: 69 | self.logger.info(f"Data Width: {colorer(data_width)}") 70 | 71 | # ID width. 72 | id_width = len(s_axi.aw.id) 73 | if len(s_axi.aw.id) != len(m_axi.aw.id): 74 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 75 | colorer("Different ID Width", color="red"), 76 | colorer("AXI interfaces."), 77 | colorer(len(s_axi.aw.id)), 78 | colorer(len(m_axi.aw.id)), 79 | colorer("the same"))) 80 | raise AXIError() 81 | else: 82 | self.logger.info(f"ID Width: {colorer(address_width)}") 83 | 84 | # Registers. 85 | self.logger.info(f"AW Reg: {aw_reg.name}.") 86 | self.logger.info(f" W Reg: {w_reg.name}.") 87 | self.logger.info(f" B Reg: {b_reg.name}.") 88 | self.logger.info(f"AR Reg: {ar_reg.name}.") 89 | self.logger.info(f" R Reg: {r_reg.name}.") 90 | 91 | # User width. 92 | for c in ["aw", "w", "b", "ar", "r"]: 93 | m_axi_c = getattr(m_axi, c) 94 | s_axi_c = getattr(s_axi, c) 95 | if s_axi_c.user_width != m_axi_c.user_width: 96 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 97 | colorer("Different User Width", color="red"), 98 | colorer("AXI interfaces."), 99 | colorer(s_axi_c.user_width), 100 | colorer(m_axi_c.user_width), 101 | colorer("the same"))) 102 | raise AXIError() 103 | else: 104 | self.logger.info(f"{c.upper()} User Width: {colorer(m_axi_c.user_width)}") 105 | 106 | # Module instance. 107 | # ---------------- 108 | 109 | self.specials += Instance("axi_register", 110 | # Parameters. 111 | # ----------- 112 | p_DATA_WIDTH = data_width, 113 | p_ADDR_WIDTH = address_width, 114 | p_ID_WIDTH = id_width, 115 | 116 | p_AWUSER_ENABLE = s_axi.aw.user_width > 0, 117 | p_AWUSER_WIDTH = max(1, s_axi.aw.user_width), 118 | p_WUSER_ENABLE = s_axi.w.user_width > 0, 119 | p_WUSER_WIDTH = max(1, s_axi.w.user_width), 120 | p_BUSER_ENABLE = s_axi.b.user_width > 0, 121 | p_BUSER_WIDTH = max(1, s_axi.b.user_width), 122 | p_ARUSER_ENABLE = s_axi.ar.user_width > 0, 123 | p_ARUSER_WIDTH = max(1, s_axi.ar.user_width), 124 | p_RUSER_ENABLE = s_axi.r.user_width > 0, 125 | p_RUSER_WIDTH = max(1, s_axi.r.user_width), 126 | 127 | # Register type. 128 | p_AW_REG_TYPE = aw_reg, 129 | p_W_REG_TYPE = w_reg, 130 | p_B_REG_TYPE = b_reg, 131 | p_AR_REG_TYPE = ar_reg, 132 | p_R_REG_TYPE = r_reg, 133 | 134 | # Clk / Rst. 135 | # ---------- 136 | i_clk = ClockSignal(clock_domain), 137 | i_rst = ResetSignal(clock_domain), 138 | 139 | # AXI Slave Interface. 140 | # -------------------- 141 | # AW. 142 | i_s_axi_awid = s_axi.aw.id, 143 | i_s_axi_awaddr = s_axi.aw.addr, 144 | i_s_axi_awlen = s_axi.aw.len, 145 | i_s_axi_awsize = s_axi.aw.size, 146 | i_s_axi_awburst = s_axi.aw.burst, 147 | i_s_axi_awlock = s_axi.aw.lock, 148 | i_s_axi_awcache = s_axi.aw.cache, 149 | i_s_axi_awprot = s_axi.aw.prot, 150 | i_s_axi_awqos = s_axi.aw.qos, 151 | i_s_axi_awregion = s_axi.aw.region, 152 | i_s_axi_awuser = s_axi.aw.user, 153 | i_s_axi_awvalid = s_axi.aw.valid, 154 | o_s_axi_awready = s_axi.aw.ready, 155 | 156 | # W. 157 | i_s_axi_wdata = s_axi.w.data, 158 | i_s_axi_wstrb = s_axi.w.strb, 159 | i_s_axi_wlast = s_axi.w.last, 160 | i_s_axi_wuser = s_axi.w.user, 161 | i_s_axi_wvalid = s_axi.w.valid, 162 | o_s_axi_wready = s_axi.w.ready, 163 | 164 | # B. 165 | o_s_axi_bid = s_axi.b.id, 166 | o_s_axi_bresp = s_axi.b.resp, 167 | o_s_axi_buser = s_axi.b.user, 168 | o_s_axi_bvalid = s_axi.b.valid, 169 | i_s_axi_bready = s_axi.b.ready, 170 | 171 | # AR. 172 | i_s_axi_arid = s_axi.ar.id, 173 | i_s_axi_araddr = s_axi.ar.addr, 174 | i_s_axi_arlen = s_axi.ar.len, 175 | i_s_axi_arsize = s_axi.ar.size, 176 | i_s_axi_arburst = s_axi.ar.burst, 177 | i_s_axi_arlock = s_axi.ar.lock, 178 | i_s_axi_arcache = s_axi.ar.cache, 179 | i_s_axi_arprot = s_axi.ar.prot, 180 | i_s_axi_arqos = s_axi.ar.qos, 181 | i_s_axi_arregion = s_axi.ar.region, 182 | i_s_axi_aruser = s_axi.ar.user, 183 | i_s_axi_arvalid = s_axi.ar.valid, 184 | o_s_axi_arready = s_axi.ar.ready, 185 | 186 | # R. 187 | o_s_axi_rid = s_axi.r.id, 188 | o_s_axi_rdata = s_axi.r.data, 189 | o_s_axi_rresp = s_axi.r.resp, 190 | o_s_axi_rlast = s_axi.r.last, 191 | o_s_axi_ruser = s_axi.r.user, 192 | o_s_axi_rvalid = s_axi.r.valid, 193 | i_s_axi_rready = s_axi.r.ready, 194 | 195 | # AXI Master Interface. 196 | # --------------------- 197 | # AW. 198 | o_m_axi_awid = m_axi.aw.id, 199 | o_m_axi_awaddr = m_axi.aw.addr, 200 | o_m_axi_awlen = m_axi.aw.len, 201 | o_m_axi_awsize = m_axi.aw.size, 202 | o_m_axi_awburst = m_axi.aw.burst, 203 | o_m_axi_awlock = m_axi.aw.lock, 204 | o_m_axi_awcache = m_axi.aw.cache, 205 | o_m_axi_awprot = m_axi.aw.prot, 206 | o_m_axi_awqos = m_axi.aw.qos, 207 | o_m_axi_awregion = m_axi.aw.region, 208 | o_m_axi_awuser = m_axi.aw.user, 209 | o_m_axi_awvalid = m_axi.aw.valid, 210 | i_m_axi_awready = m_axi.aw.ready, 211 | 212 | # W. 213 | o_m_axi_wdata = m_axi.w.data, 214 | o_m_axi_wstrb = m_axi.w.strb, 215 | o_m_axi_wlast = m_axi.w.last, 216 | o_m_axi_wuser = m_axi.w.user, 217 | o_m_axi_wvalid = m_axi.w.valid, 218 | i_m_axi_wready = m_axi.w.ready, 219 | 220 | # B. 221 | i_m_axi_bid = m_axi.b.id, 222 | i_m_axi_bresp = m_axi.b.resp, 223 | i_m_axi_buser = m_axi.b.user, 224 | i_m_axi_bvalid = m_axi.b.valid, 225 | o_m_axi_bready = m_axi.b.ready, 226 | 227 | # AR. 228 | o_m_axi_arid = m_axi.ar.id, 229 | o_m_axi_araddr = m_axi.ar.addr, 230 | o_m_axi_arlen = m_axi.ar.len, 231 | o_m_axi_arsize = m_axi.ar.size, 232 | o_m_axi_arburst = m_axi.ar.burst, 233 | o_m_axi_arlock = m_axi.ar.lock, 234 | o_m_axi_arcache = m_axi.ar.cache, 235 | o_m_axi_arprot = m_axi.ar.prot, 236 | o_m_axi_arqos = m_axi.ar.qos, 237 | o_m_axi_arregion = m_axi.ar.region, 238 | o_m_axi_aruser = m_axi.ar.user, 239 | o_m_axi_arvalid = m_axi.ar.valid, 240 | i_m_axi_arready = m_axi.ar.ready, 241 | 242 | # R. 243 | i_m_axi_rid = m_axi.r.id, 244 | i_m_axi_rdata = m_axi.r.data, 245 | i_m_axi_rresp = m_axi.r.resp, 246 | i_m_axi_rlast = m_axi.r.last, 247 | i_m_axi_ruser = m_axi.r.user, 248 | i_m_axi_rvalid = m_axi.r.valid, 249 | o_m_axi_rready = m_axi.r.ready, 250 | ) 251 | 252 | # Add Sources. 253 | # ------------ 254 | self.add_sources(platform) 255 | 256 | @staticmethod 257 | def add_sources(platform): 258 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 259 | platform.add_source(os.path.join(rtl_dir, "axi_register_wr.v")) 260 | platform.add_source(os.path.join(rtl_dir, "axi_register_rd.v")) 261 | platform.add_source(os.path.join(rtl_dir, "axi_register.v")) 262 | -------------------------------------------------------------------------------- /verilog_axi/axi_axil_adapter.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axi_axil_adapter.v. 8 | 9 | import os 10 | 11 | from migen import * 12 | 13 | from litex.soc.interconnect.axi import * 14 | 15 | from verilog_axi.axi_common import * 16 | 17 | # AXI to AXI-Lite Adapter -------------------------------------------------------------------------- 18 | 19 | class AXI2AXILiteAdapter(Module): 20 | def __init__(self, platform, s_axi, m_axil, 21 | convert_burst = True, 22 | convert_narrow_burst = False, 23 | ): 24 | self.logger = logging.getLogger("AXI2AXILiteAdapter") 25 | 26 | # Get/Check Parameters. 27 | # --------------------- 28 | assert isinstance(s_axi, AXIInterface) 29 | assert isinstance(m_axil, AXILiteInterface) 30 | 31 | # Clock Domain. 32 | clock_domain = s_axi.clock_domain 33 | if s_axi.clock_domain != m_axil.clock_domain: 34 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 35 | colorer("Different Clock Domain", color="red"), 36 | colorer("AXI interfaces."), 37 | colorer(s_axi.clock_domain), 38 | colorer(m_axil.clock_domain), 39 | colorer("the same"))) 40 | raise AXIError() 41 | else: 42 | self.logger.info(f"Clock Domain: {colorer(clock_domain)}") 43 | 44 | # Address width. 45 | address_width = len(s_axi.aw.addr) 46 | if len(s_axi.aw.addr) != len(m_axil.aw.addr): 47 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 48 | colorer("Different Address Width", color="red"), 49 | colorer("AXI interfaces."), 50 | colorer(len(s_axi.aw.addr)), 51 | colorer(len(m_axil.aw.addr)), 52 | colorer("the same"))) 53 | raise AXIError() 54 | else: 55 | self.logger.info(f"Address Width: {colorer(address_width)}") 56 | 57 | # Data width. 58 | s_data_width = len(s_axi.w.data) 59 | m_data_width = len(m_axil.w.data) 60 | self.logger.info(f"Slave Data Width: {colorer(s_data_width)}") 61 | self.logger.info(f"Master Data Width: {colorer(m_data_width)}") 62 | 63 | # ID width. 64 | id_width = len(s_axi.aw.id) 65 | self.logger.info(f"ID Width: {colorer(address_width)}") 66 | 67 | # Burst. 68 | # FIXME: Add check. 69 | 70 | # Module instance. 71 | # ---------------- 72 | 73 | self.specials += Instance("axi_axil_adapter", 74 | # Parameters. 75 | # ----------- 76 | p_ADDR_WIDTH = address_width, 77 | p_AXI_DATA_WIDTH = s_data_width, 78 | p_AXIL_DATA_WIDTH = m_data_width, 79 | p_CONVERT_BURST = convert_burst, 80 | p_CONVERT_NARROW_BURST = convert_narrow_burst, 81 | 82 | # Clk / Rst. 83 | # ---------- 84 | i_clk = ClockSignal(clock_domain), 85 | i_rst = ResetSignal(clock_domain), 86 | 87 | # AXI Slave Interface. 88 | # -------------------- 89 | # AW. 90 | i_s_axi_awid = s_axi.aw.id, 91 | i_s_axi_awaddr = s_axi.aw.addr, 92 | i_s_axi_awlen = s_axi.aw.len, 93 | i_s_axi_awsize = s_axi.aw.size, 94 | i_s_axi_awburst = s_axi.aw.burst, 95 | i_s_axi_awlock = s_axi.aw.lock, 96 | i_s_axi_awcache = s_axi.aw.cache, 97 | i_s_axi_awprot = s_axi.aw.prot, 98 | i_s_axi_awvalid = s_axi.aw.valid, 99 | o_s_axi_awready = s_axi.aw.ready, 100 | 101 | # W. 102 | i_s_axi_wdata = s_axi.w.data, 103 | i_s_axi_wstrb = s_axi.w.strb, 104 | i_s_axi_wlast = s_axi.w.last, 105 | i_s_axi_wvalid = s_axi.w.valid, 106 | o_s_axi_wready = s_axi.w.ready, 107 | 108 | # B. 109 | o_s_axi_bid = s_axi.b.id, 110 | o_s_axi_bresp = s_axi.b.resp, 111 | o_s_axi_bvalid = s_axi.b.valid, 112 | i_s_axi_bready = s_axi.b.ready, 113 | 114 | # AR. 115 | i_s_axi_arid = s_axi.ar.id, 116 | i_s_axi_araddr = s_axi.ar.addr, 117 | i_s_axi_arlen = s_axi.ar.len, 118 | i_s_axi_arsize = s_axi.ar.size, 119 | i_s_axi_arburst = s_axi.ar.burst, 120 | i_s_axi_arlock = s_axi.ar.lock, 121 | i_s_axi_arcache = s_axi.ar.cache, 122 | i_s_axi_arprot = s_axi.ar.prot, 123 | i_s_axi_arvalid = s_axi.ar.valid, 124 | o_s_axi_arready = s_axi.ar.ready, 125 | 126 | # R. 127 | o_s_axi_rid = s_axi.r.id, 128 | o_s_axi_rdata = s_axi.r.data, 129 | o_s_axi_rresp = s_axi.r.resp, 130 | o_s_axi_rlast = s_axi.r.last, 131 | o_s_axi_rvalid = s_axi.r.valid, 132 | i_s_axi_rready = s_axi.r.ready, 133 | 134 | # AXI-Lite Master Interface. 135 | # -------------------------- 136 | # AW. 137 | o_m_axil_awaddr = m_axil.aw.addr, 138 | o_m_axil_awprot = Open(), # CHECKME. 139 | o_m_axil_awvalid = m_axil.aw.valid, 140 | i_m_axil_awready = m_axil.aw.ready, 141 | 142 | # W. 143 | o_m_axil_wdata = m_axil.w.data, 144 | o_m_axil_wstrb = m_axil.w.strb, 145 | o_m_axil_wvalid = m_axil.w.valid, 146 | i_m_axil_wready = m_axil.w.ready, 147 | 148 | # B. 149 | i_m_axil_bresp = m_axil.b.resp, 150 | i_m_axil_bvalid = m_axil.b.valid, 151 | o_m_axil_bready = m_axil.b.ready, 152 | 153 | # AR. 154 | o_m_axil_araddr = m_axil.ar.addr, 155 | o_m_axil_arprot = Open(), # CHECKME. 156 | o_m_axil_arvalid = m_axil.ar.valid, 157 | i_m_axil_arready = m_axil.ar.ready, 158 | 159 | # R. 160 | i_m_axil_rdata = m_axil.r.data, 161 | i_m_axil_rresp = m_axil.r.resp, 162 | i_m_axil_rvalid = m_axil.r.valid, 163 | o_m_axil_rready = m_axil.r.ready, 164 | ) 165 | 166 | # Add Sources. 167 | # ------------ 168 | self.add_sources(platform) 169 | 170 | @staticmethod 171 | def add_sources(platform): 172 | rtl_dir = os.path.join(os.path.dirname(__file__), "verilog", "rtl") 173 | platform.add_source(os.path.join(rtl_dir, "axi_axil_adapter.v")) 174 | platform.add_source(os.path.join(rtl_dir, "axi_axil_adapter_wr.v")) 175 | platform.add_source(os.path.join(rtl_dir, "axi_axil_adapter_rd.v")) 176 | -------------------------------------------------------------------------------- /verilog_axi/axi_common.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | import sys 8 | import logging 9 | 10 | from enum import IntEnum 11 | 12 | from migen import * 13 | 14 | logging.basicConfig(level=logging.INFO) 15 | 16 | # Helpers ------------------------------------------------------------------------------------------ 17 | 18 | class Open(Signal): pass 19 | 20 | def colorer(s, color="bright"): 21 | header = { 22 | "bright": "\x1b[1m", 23 | "green": "\x1b[32m", 24 | "cyan": "\x1b[36m", 25 | "red": "\x1b[31m", 26 | "yellow": "\x1b[33m", 27 | "underline": "\x1b[4m"}[color] 28 | trailer = "\x1b[0m" 29 | return header + str(s) + trailer 30 | 31 | # AXI Register Type -------------------------------------------------------------------------------- 32 | 33 | class AXIRegister(IntEnum): 34 | BYPASS = 0 35 | SIMPLE_BUFFER = 1 36 | SKID_BUFFER = 2 37 | 38 | # AXI Error ---------------------------------------------------------------------------------------- 39 | 40 | class AXIError(Exception): 41 | def __init__(self): 42 | sys.stderr = None # Error already described, avoid traceback/exception. 43 | 44 | # AXI Debug ---------------------------------------------------------------------------------------- 45 | 46 | class AXIAWDebug(Module): 47 | def __init__(self, axi, name=""): 48 | sync = getattr(self.sync, axi.clock_domain) 49 | sync += If(axi.aw.valid & axi.aw.ready, 50 | Display(f"AXI AW {name}: Addr: 0x%08x, Burst: %d, Len: %d", 51 | axi.aw.addr, 52 | axi.aw.burst, 53 | axi.aw.len 54 | ), 55 | ) 56 | 57 | class AXIWDebug(Module): 58 | def __init__(self, axi, name=""): 59 | sync = getattr(self.sync, axi.clock_domain) 60 | sync += If(axi.w.valid & axi.w.ready, 61 | Display(f"AXI W {name}: Data: 0x%x, Strb: %x, Last: %d", 62 | axi.w.data, 63 | axi.w.strb, 64 | axi.w.last 65 | ), 66 | ) 67 | 68 | class AXIARDebug(Module): 69 | def __init__(self, axi, name=""): 70 | sync = getattr(self.sync, axi.clock_domain) 71 | sync += If(axi.ar.valid & axi.ar.ready, 72 | Display(f"AXI AR {name}: Addr: 0x%08x, Burst: %d, Len: %d", 73 | axi.ar.addr, 74 | axi.ar.burst, 75 | axi.ar.len 76 | ), 77 | ) 78 | 79 | class AXIRDebug(Module): 80 | def __init__(self, axi, name=""): 81 | sync = getattr(self.sync, axi.clock_domain) 82 | sync += If(axi.r.valid & axi.r.ready, 83 | Display(f"AXI R {name}: Data: 0x%x, Last: %d", 84 | axi.r.data, 85 | axi.r.last 86 | ), 87 | ) 88 | -------------------------------------------------------------------------------- /verilog_axi/axi_lite/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enjoy-digital/litex_verilog_axi_test/70304d8ede2a2e5415d0e4381e1b3d67b32e0f41/verilog_axi/axi_lite/__init__.py -------------------------------------------------------------------------------- /verilog_axi/axi_lite/axil_adapter.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axil_adapter.v. 8 | 9 | import os 10 | 11 | from migen import * 12 | 13 | from litex.soc.interconnect.axi import * 14 | 15 | from verilog_axi.axi_common import * 16 | 17 | # AXI-Lite Adapter --------------------------------------------------------------------------------- 18 | 19 | class AXILiteAdapter(Module): 20 | def __init__(self, platform, s_axil, m_axil, 21 | convert_burst = True, 22 | convert_narrow_burst = False, 23 | forward_id = True, 24 | ): 25 | self.logger = logging.getLogger("AXILiteAdapter") 26 | 27 | # Get/Check Parameters. 28 | # --------------------- 29 | 30 | # Clock Domain. 31 | clock_domain = s_axil.clock_domain 32 | if s_axil.clock_domain != m_axil.clock_domain: 33 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 34 | colorer("Different Clock Domain", color="red"), 35 | colorer("AXI-Lite interfaces."), 36 | colorer(s_axil.clock_domain), 37 | colorer(m_axil.clock_domain), 38 | colorer("the same"))) 39 | raise AXIError() 40 | else: 41 | self.logger.info(f"Clock Domain: {colorer(clock_domain)}") 42 | 43 | # Address width. 44 | address_width = len(s_axil.aw.addr) 45 | if len(s_axil.aw.addr) != len(m_axil.aw.addr): 46 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 47 | colorer("Different Address Width", color="red"), 48 | colorer("AXI-Lite interfaces."), 49 | colorer(len(s_axil.aw.addr)), 50 | colorer(len(m_axil.aw.addr)), 51 | colorer("the same"))) 52 | raise AXIError() 53 | else: 54 | self.logger.info(f"Address Width: {colorer(address_width)}") 55 | 56 | # Data width. 57 | s_data_width = len(s_axil.w.data) 58 | m_data_width = len(m_axil.w.data) 59 | self.logger.info(f"Slave Data Width: {colorer(s_data_width)}") 60 | self.logger.info(f"Master Data Width: {colorer(m_data_width)}") 61 | 62 | # Module instance. 63 | # ---------------- 64 | 65 | self.specials += Instance("axil_adapter", 66 | # Parameters. 67 | # ----------- 68 | p_ADDR_WIDTH = address_width, 69 | 70 | p_S_DATA_WIDTH = s_data_width, 71 | p_M_DATA_WIDTH = m_data_width, 72 | 73 | # Clk / Rst. 74 | # ---------- 75 | i_clk = ClockSignal(clock_domain), 76 | i_rst = ResetSignal(clock_domain), 77 | 78 | # AXI-Lite Slave Interface. 79 | # ------------------------- 80 | # AW. 81 | i_s_axil_awaddr = s_axil.aw.addr, 82 | i_s_axil_awprot = 0b0, # CHECKME. 83 | i_s_axil_awvalid = s_axil.aw.valid, 84 | o_s_axil_awready = s_axil.aw.ready, 85 | 86 | # W. 87 | i_s_axil_wdata = s_axil.w.data, 88 | i_s_axil_wstrb = s_axil.w.strb, 89 | i_s_axil_wvalid = s_axil.w.valid, 90 | o_s_axil_wready = s_axil.w.ready, 91 | 92 | # B. 93 | o_s_axil_bresp = s_axil.b.resp, 94 | o_s_axil_bvalid = s_axil.b.valid, 95 | i_s_axil_bready = s_axil.b.ready, 96 | 97 | # AR. 98 | i_s_axil_araddr = s_axil.ar.addr, 99 | i_s_axil_arprot = 0b0, # CHECKME. 100 | i_s_axil_arvalid = s_axil.ar.valid, 101 | o_s_axil_arready = s_axil.ar.ready, 102 | 103 | # R. 104 | o_s_axil_rdata = s_axil.r.data, 105 | o_s_axil_rresp = s_axil.r.resp, 106 | o_s_axil_rvalid = s_axil.r.valid, 107 | i_s_axil_rready = s_axil.r.ready, 108 | 109 | # AXI-Lite Master Interface. 110 | # -------------------------- 111 | # AW. 112 | o_m_axil_awaddr = m_axil.aw.addr, 113 | o_m_axil_awprot = Open(), # CHECKME. 114 | o_m_axil_awvalid = m_axil.aw.valid, 115 | i_m_axil_awready = m_axil.aw.ready, 116 | 117 | # W. 118 | o_m_axil_wdata = m_axil.w.data, 119 | o_m_axil_wstrb = m_axil.w.strb, 120 | o_m_axil_wvalid = m_axil.w.valid, 121 | i_m_axil_wready = m_axil.w.ready, 122 | 123 | # B. 124 | i_m_axil_bresp = m_axil.b.resp, 125 | i_m_axil_bvalid = m_axil.b.valid, 126 | o_m_axil_bready = m_axil.b.ready, 127 | 128 | # AR. 129 | o_m_axil_araddr = m_axil.ar.addr, 130 | o_m_axil_arprot = Open(), # CHECKME. 131 | o_m_axil_arvalid = m_axil.ar.valid, 132 | i_m_axil_arready = m_axil.ar.ready, 133 | 134 | # R. 135 | i_m_axil_rdata = m_axil.r.data, 136 | i_m_axil_rresp = m_axil.r.resp, 137 | i_m_axil_rvalid = m_axil.r.valid, 138 | o_m_axil_rready = m_axil.r.ready, 139 | ) 140 | 141 | # Add Sources. 142 | # ------------ 143 | self.add_sources(platform) 144 | 145 | @staticmethod 146 | def add_sources(platform): 147 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 148 | platform.add_source(os.path.join(rtl_dir, "axil_adapter_wr.v")) 149 | platform.add_source(os.path.join(rtl_dir, "axil_adapter_rd.v")) 150 | platform.add_source(os.path.join(rtl_dir, "axil_adapter.v")) 151 | -------------------------------------------------------------------------------- /verilog_axi/axi_lite/axil_cdc.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axil_cdc.v. 8 | 9 | import os 10 | 11 | from migen import * 12 | 13 | from litex.soc.interconnect.axi import * 14 | 15 | from verilog_axi.axi_common import * 16 | 17 | # AXI-Lite Clock Domain Crossing ------------------------------------------------------------------- 18 | 19 | class AXILiteCDC(Module): 20 | def __init__(self, platform, s_axil, m_axil): 21 | self.logger = logging.getLogger("AXILiteCDC") 22 | 23 | # Get/Check Parameters. 24 | # --------------------- 25 | 26 | # Clock Domain. 27 | self.logger.info(f"Slave Clock Domain: {colorer(s_axil.clock_domain)}") 28 | self.logger.info(f"Master Clock Domain: {colorer(m_axil.clock_domain)}") 29 | 30 | # Address width. 31 | address_width = len(s_axil.aw.addr) 32 | if len(s_axil.aw.addr) != len(m_axil.aw.addr): 33 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 34 | colorer("Different Address Width", color="red"), 35 | colorer("AXI-Lite interfaces."), 36 | colorer(len(s_axil.aw.addr)), 37 | colorer(len(m_axil.aw.addr)), 38 | colorer("the same"))) 39 | raise AXIError() 40 | else: 41 | self.logger.info(f"Address Width: {colorer(address_width)}") 42 | 43 | # Data width. 44 | data_width = len(s_axil.w.data) 45 | if len(s_axil.w.data) != len(m_axil.w.data): 46 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 47 | colorer("Different Data Width", color="red"), 48 | colorer("AXI-Lite interfaces."), 49 | colorer(len(s_axil.w.data)), 50 | colorer(len(m_axil.w.data)), 51 | colorer("the same"))) 52 | raise AXIError() 53 | else: 54 | self.logger.info(f"Data Width: {colorer(data_width)}") 55 | 56 | # Module instance. 57 | # ---------------- 58 | 59 | self.specials += Instance("axil_cdc", 60 | # Parameters. 61 | # ----------- 62 | p_DATA_WIDTH = data_width, 63 | p_ADDR_WIDTH = address_width, 64 | 65 | # Clk / Rst. 66 | # ---------- 67 | i_s_clk = ClockSignal(s_axil.clock_domain), 68 | i_s_rst = ResetSignal(s_axil.clock_domain), 69 | i_m_clk = ClockSignal(m_axil.clock_domain), 70 | i_m_rst = ResetSignal(m_axil.clock_domain), 71 | 72 | # AXI-Lite Slave Interface. 73 | # ------------------------- 74 | # AW. 75 | i_s_axil_awaddr = s_axil.aw.addr, 76 | i_s_axil_awprot = 0b0, # CHECKME. 77 | i_s_axil_awvalid = s_axil.aw.valid, 78 | o_s_axil_awready = s_axil.aw.ready, 79 | 80 | # W. 81 | i_s_axil_wdata = s_axil.w.data, 82 | i_s_axil_wstrb = s_axil.w.strb, 83 | i_s_axil_wvalid = s_axil.w.valid, 84 | o_s_axil_wready = s_axil.w.ready, 85 | 86 | # B. 87 | o_s_axil_bresp = s_axil.b.resp, 88 | o_s_axil_bvalid = s_axil.b.valid, 89 | i_s_axil_bready = s_axil.b.ready, 90 | 91 | # AR. 92 | i_s_axil_araddr = s_axil.ar.addr, 93 | i_s_axil_arprot = 0b0, # CHECKME. 94 | i_s_axil_arvalid = s_axil.ar.valid, 95 | o_s_axil_arready = s_axil.ar.ready, 96 | 97 | # R. 98 | o_s_axil_rdata = s_axil.r.data, 99 | o_s_axil_rresp = s_axil.r.resp, 100 | o_s_axil_rvalid = s_axil.r.valid, 101 | i_s_axil_rready = s_axil.r.ready, 102 | 103 | # AXI-Lite Master Interface. 104 | # -------------------------- 105 | # AW. 106 | o_m_axil_awaddr = m_axil.aw.addr, 107 | o_m_axil_awprot = Open(), # CHECKME. 108 | o_m_axil_awvalid = m_axil.aw.valid, 109 | i_m_axil_awready = m_axil.aw.ready, 110 | 111 | # W. 112 | o_m_axil_wdata = m_axil.w.data, 113 | o_m_axil_wstrb = m_axil.w.strb, 114 | o_m_axil_wvalid = m_axil.w.valid, 115 | i_m_axil_wready = m_axil.w.ready, 116 | 117 | # B. 118 | i_m_axil_bresp = m_axil.b.resp, 119 | i_m_axil_bvalid = m_axil.b.valid, 120 | o_m_axil_bready = m_axil.b.ready, 121 | 122 | # AR. 123 | o_m_axil_araddr = m_axil.ar.addr, 124 | o_m_axil_arprot = Open(), # CHECKME. 125 | o_m_axil_arvalid = m_axil.ar.valid, 126 | i_m_axil_arready = m_axil.ar.ready, 127 | 128 | # R. 129 | i_m_axil_rdata = m_axil.r.data, 130 | i_m_axil_rresp = m_axil.r.resp, 131 | i_m_axil_rvalid = m_axil.r.valid, 132 | o_m_axil_rready = m_axil.r.ready, 133 | ) 134 | 135 | # Add Sources. 136 | # ------------ 137 | self.add_sources(platform) 138 | 139 | @staticmethod 140 | def add_sources(platform): 141 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 142 | platform.add_source(os.path.join(rtl_dir, "axil_cdc_wr.v")) 143 | platform.add_source(os.path.join(rtl_dir, "axil_cdc_rd.v")) 144 | platform.add_source(os.path.join(rtl_dir, "axil_cdc.v")) 145 | -------------------------------------------------------------------------------- /verilog_axi/axi_lite/axil_crossbar.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axil_crossbar.v. 8 | 9 | import os 10 | import math 11 | 12 | from migen import * 13 | 14 | from litex.soc.interconnect.axi import * 15 | 16 | from verilog_axi.axi_common import * 17 | 18 | # AXI Lite Crossbar Interface ---------------------------------------------------------------------- 19 | 20 | class AXILiteCrossbarInterface: 21 | def __init__(self, axi, origin=None, size=None, 22 | aw_reg = AXIRegister.SIMPLE_BUFFER, 23 | w_reg = AXIRegister.SKID_BUFFER, 24 | b_reg = AXIRegister.SIMPLE_BUFFER, 25 | ar_reg = AXIRegister.SIMPLE_BUFFER, 26 | r_reg = AXIRegister.SKID_BUFFER, 27 | ): 28 | self.axi = axi 29 | self.origin = origin 30 | self.size = size 31 | self.aw_reg = aw_reg 32 | self.w_reg = w_reg 33 | self.b_reg = b_reg 34 | self.ar_reg = ar_reg 35 | self.r_reg = r_reg 36 | 37 | # AXI Lite Crossbar -------------------------------------------------------------------------------- 38 | 39 | class AXILiteCrossbar(Module): 40 | def __init__(self, platform): 41 | self.logger = logging.getLogger("AXILiteCrossbar") 42 | self.s_axils = {} 43 | self.m_axils = {} 44 | 45 | # Add Sources. 46 | # ------------ 47 | self.add_sources(platform) 48 | 49 | def get_if_name(self, axil): 50 | axil_ifs = {**self.s_axils, **self.m_axils} 51 | for name, axil_if in axil_ifs.items(): 52 | if axil is axil_if.axi: 53 | return name 54 | return None 55 | 56 | def add_slave(self, name=None, s_axil=None, 57 | aw_reg = AXIRegister.SIMPLE_BUFFER, 58 | w_reg = AXIRegister.SKID_BUFFER, 59 | b_reg = AXIRegister.SIMPLE_BUFFER, 60 | ar_reg = AXIRegister.SIMPLE_BUFFER, 61 | r_reg = AXIRegister.SKID_BUFFER): 62 | 63 | # Get/Check Name. 64 | name = f"s_axil{len(self.s_axils)}" if name is None else name 65 | if name in self.s_axils.keys(): 66 | raise ValueError # FIXME: Add error message. 67 | 68 | # Add Slave. 69 | assert isinstance(s_axil, AXILiteInterface) 70 | s_axil = AXILiteCrossbarInterface( 71 | axi = s_axil, 72 | aw_reg = aw_reg, 73 | w_reg = w_reg, 74 | b_reg = b_reg, 75 | ar_reg = ar_reg, 76 | r_reg = r_reg 77 | ) 78 | self.s_axils[name] = s_axil 79 | 80 | # Info. 81 | self.logger.info(f"Add AXI-Lite Slave {name} interface.") 82 | self.logger.info(f" AW Reg: {aw_reg.name}.") 83 | self.logger.info(f" W Reg: { w_reg.name}.") 84 | self.logger.info(f" B Reg: { b_reg.name}.") 85 | self.logger.info(f" AR Reg: {ar_reg.name}.") 86 | self.logger.info(f" R Reg: { r_reg.name}.") 87 | 88 | # Check. 89 | self.get_check_parameters(show=False) 90 | 91 | def add_master(self, name=None, m_axil=None, origin=None, size=None, 92 | aw_reg = AXIRegister.SIMPLE_BUFFER, 93 | w_reg = AXIRegister.SKID_BUFFER, 94 | b_reg = AXIRegister.SIMPLE_BUFFER, 95 | ar_reg = AXIRegister.SIMPLE_BUFFER, 96 | r_reg = AXIRegister.SKID_BUFFER): 97 | 98 | # Get/Check Name. 99 | name = f"m_axil{len(self.m_axils)}" if name is None else name 100 | if name in self.m_axils.keys(): 101 | raise ValueError # FIXME: Add error message. 102 | 103 | # Add Master. 104 | assert isinstance(m_axil, AXILiteInterface) 105 | assert origin is not None 106 | assert size is not None 107 | m_axil = AXILiteCrossbarInterface( 108 | axi = m_axil, 109 | origin = origin, 110 | size = size, 111 | aw_reg = aw_reg, 112 | w_reg = w_reg, 113 | b_reg = b_reg, 114 | ar_reg = ar_reg, 115 | r_reg = r_reg 116 | ) 117 | self.m_axils[name] = m_axil 118 | 119 | # Info. 120 | self.logger.info(f"Add AXI-Lite Master {name} interface.") 121 | self.logger.info(f" Origin: 0x{origin:08x}.") 122 | self.logger.info(f" Size: 0x{size:0x}.") 123 | self.logger.info(f" AW Reg: {aw_reg.name}.") 124 | self.logger.info(f" W Reg: { w_reg.name}.") 125 | self.logger.info(f" B Reg: { b_reg.name}.") 126 | self.logger.info(f" AR Reg: {ar_reg.name}.") 127 | self.logger.info(f" R Reg: { r_reg.name}.") 128 | 129 | # Check. 130 | self.get_check_parameters(show=False) 131 | 132 | def get_check_parameters(self, show=True): 133 | axil_ifs = {**self.s_axils, **self.m_axils} 134 | axils = [axil_if.axi for name, axil_if in axil_ifs.items()] 135 | 136 | # Clock Domain. 137 | self.clock_domain = clock_domain = axils[0].clock_domain 138 | for i, axi in enumerate(axils): 139 | if i == 0: 140 | continue 141 | else: 142 | if axi.clock_domain != clock_domain: 143 | self.logger.error("{} on {} ({}: {} / {}: {}), should be {}.".format( 144 | colorer("Different Clock Domain", color="red"), 145 | colorer("AXI-Lite interfaces."), 146 | self.get_if_name(axils[0]), 147 | colorer(clock_domain), 148 | self.get_if_name(axi), 149 | colorer(axi.clock_domain), 150 | colorer("the same"))) 151 | raise AXIError() 152 | if show: 153 | self.logger.info(f"Clock Domain: {colorer(clock_domain)}") 154 | 155 | # Address width. 156 | self.address_width = address_width = len(axils[0].aw.addr) 157 | for i, axi in enumerate(axils): 158 | if i == 0: 159 | continue 160 | else: 161 | if len(axi.aw.addr) != address_width: 162 | self.logger.error("{} on {} ({}: {} / {}: {}), should be {}.".format( 163 | colorer("Different Address Width", color="red"), 164 | colorer("AXI-Lite interfaces."), 165 | self.get_if_name(axils[0]), 166 | colorer(address_width), 167 | self.get_if_name(axi), 168 | colorer(len(axi.aw.addr)), 169 | colorer("the same"))) 170 | raise AXIError() 171 | if show: 172 | self.logger.info(f"Address Width: {colorer(address_width)}") 173 | 174 | # Data width. 175 | self.data_width = data_width = len(axils[0].w.data) 176 | for i, axi in enumerate(axils): 177 | if i == 0: 178 | continue 179 | else: 180 | if len(axi.w.data) != data_width: 181 | self.logger.error("{} on {} ({}: {} / {}: {}), should be {}.".format( 182 | colorer("Different Data Width", color="red"), 183 | colorer("AXI-Lite interfaces."), 184 | self.get_if_name(axils[0]), 185 | colorer(data_width), 186 | self.get_if_name(axi), 187 | colorer(len(axi.w.data)), 188 | colorer("the same"))) 189 | raise AXIError() 190 | if show: 191 | self.logger.info(f"Data Width: {colorer(address_width)}") 192 | 193 | def do_finalize(self): 194 | # Get/Check Parameters. 195 | # --------------------- 196 | self.get_check_parameters() 197 | 198 | 199 | # Get/Check Parameters. 200 | # --------------------- 201 | self.logger.info(f"Finalized {len(self.s_axils)}X{len(self.m_axils)} Crossbar:") 202 | self.logger.info(f" Slaves:") 203 | for s_name, s_axil in self.s_axils.items(): 204 | self.logger.info(f" - {s_name}.") 205 | self.logger.info(f" Masters:") 206 | for m_name, m_axi in self.m_axils.items(): 207 | self.logger.info(f" - {m_name}, Origin: 0x{m_axi.origin:08x}, Size: 0x{m_axi.size:0x}.") 208 | 209 | 210 | # Module instance. 211 | # ---------------- 212 | 213 | s_axils = [axil_if.axi for axil_if in self.s_axils.values()] 214 | m_axils = [axil_if.axi for axil_if in self.m_axils.values()] 215 | m_origins = [axil_if.origin for axil_if in self.m_axils.values()] 216 | m_widths = [math.ceil(math.log2(axil_if.size)) for axil_if in self.m_axils.values()] 217 | 218 | def format_m_params(params, width): 219 | value = 0 220 | for param in reversed(params): 221 | value <<= width 222 | value |= param 223 | return Constant(value, len(params)*width) 224 | 225 | self.specials += Instance("axil_crossbar", 226 | # Parameters. 227 | # ----------- 228 | p_S_COUNT = len(s_axils), 229 | p_M_COUNT = len(m_axils), 230 | p_DATA_WIDTH = self.data_width, 231 | p_ADDR_WIDTH = self.address_width, 232 | 233 | # Slave Registers. 234 | p_S_AW_REG_TYPE = format_m_params([axil_if.aw_reg for axil_if in self.s_axils.values()], 2), 235 | p_S_W_REG_TYPE = format_m_params([axil_if.w_reg for axil_if in self.s_axils.values()], 2), 236 | p_S_B_REG_TYPE = format_m_params([axil_if.b_reg for axil_if in self.s_axils.values()], 2), 237 | p_S_AR_REG_TYPE = format_m_params([axil_if.ar_reg for axil_if in self.s_axils.values()], 2), 238 | p_S_R_REG_TYPE = format_m_params([axil_if.r_reg for axil_if in self.s_axils.values()], 2), 239 | 240 | # Masters Origin/Size. 241 | p_M_BASE_ADDR = format_m_params(m_origins, self.address_width), 242 | p_M_ADDR_WIDTH = format_m_params(m_widths, 32), 243 | 244 | # Master Registers. 245 | p_M_AW_REG_TYPE = format_m_params([axil_if.aw_reg for axil_if in self.m_axils.values()], 2), 246 | p_M_W_REG_TYPE = format_m_params([axil_if.w_reg for axil_if in self.m_axils.values()], 2), 247 | p_M_B_REG_TYPE = format_m_params([axil_if.b_reg for axil_if in self.m_axils.values()], 2), 248 | p_M_AR_REG_TYPE = format_m_params([axil_if.ar_reg for axil_if in self.m_axils.values()], 2), 249 | p_M_R_REG_TYPE = format_m_params([axil_if.r_reg for axil_if in self.m_axils.values()], 2), 250 | 251 | # FIXME: Expose other parameters. 252 | 253 | # Clk / Rst. 254 | # ---------- 255 | i_clk = ClockSignal(self.clock_domain), 256 | i_rst = ResetSignal(self.clock_domain), 257 | 258 | # AXI-Lite Slave Interfaces. 259 | # -------------------------- 260 | # AW. 261 | i_s_axil_awaddr = Cat(*[s_axil.aw.addr for s_axil in s_axils]), 262 | i_s_axil_awprot = Cat(*[Constant(0, 3) for s_axil in s_axils]), # CHECKME. 263 | i_s_axil_awvalid = Cat(*[s_axil.aw.valid for s_axil in s_axils]), 264 | o_s_axil_awready = Cat(*[s_axil.aw.ready for s_axil in s_axils]), 265 | 266 | # W. 267 | i_s_axil_wdata = Cat(*[s_axil.w.data for s_axil in s_axils]), 268 | i_s_axil_wstrb = Cat(*[s_axil.w.strb for s_axil in s_axils]), 269 | i_s_axil_wvalid = Cat(*[s_axil.w.valid for s_axil in s_axils]), 270 | o_s_axil_wready = Cat(*[s_axil.w.ready for s_axil in s_axils]), 271 | 272 | # B. 273 | o_s_axil_bresp = Cat(*[s_axil.b.resp for s_axil in s_axils]), 274 | o_s_axil_bvalid = Cat(*[s_axil.b.valid for s_axil in s_axils]), 275 | i_s_axil_bready = Cat(*[s_axil.b.ready for s_axil in s_axils]), 276 | 277 | # AR. 278 | i_s_axil_araddr = Cat(*[s_axil.ar.addr for s_axil in s_axils]), 279 | i_s_axil_arprot = Cat(*[Constant(0, 3) for s_axil in s_axils]), # CHECKME. 280 | i_s_axil_arvalid = Cat(*[s_axil.ar.valid for s_axil in s_axils]), 281 | o_s_axil_arready = Cat(*[s_axil.ar.ready for s_axil in s_axils]), 282 | 283 | # R. 284 | o_s_axil_rdata = Cat(*[s_axil.r.data for s_axil in s_axils]), 285 | o_s_axil_rresp = Cat(*[s_axil.r.resp for s_axil in s_axils]), 286 | o_s_axil_rvalid = Cat(*[s_axil.r.valid for s_axil in s_axils]), 287 | i_s_axil_rready = Cat(*[s_axil.r.ready for s_axil in s_axils]), 288 | 289 | # AXI-Lite Master Interfaces. 290 | # --------------------------- 291 | # AW. 292 | o_m_axil_awaddr = Cat(*[m_axi.aw.addr for m_axi in m_axils]), 293 | o_m_axil_awprot = Cat(*[Signal(3) for m_axi in m_axils]), 294 | o_m_axil_awvalid = Cat(*[m_axi.aw.valid for m_axi in m_axils]), 295 | i_m_axil_awready = Cat(*[m_axi.aw.ready for m_axi in m_axils]), 296 | 297 | # W. 298 | o_m_axil_wdata = Cat(*[m_axi.w.data for m_axi in m_axils]), 299 | o_m_axil_wstrb = Cat(*[m_axi.w.strb for m_axi in m_axils]), 300 | o_m_axil_wvalid = Cat(*[m_axi.w.valid for m_axi in m_axils]), 301 | i_m_axil_wready = Cat(*[m_axi.w.ready for m_axi in m_axils]), 302 | 303 | # B. 304 | i_m_axil_bresp = Cat(*[m_axi.b.resp for m_axi in m_axils]), 305 | i_m_axil_bvalid = Cat(*[m_axi.b.valid for m_axi in m_axils]), 306 | o_m_axil_bready = Cat(*[m_axi.b.ready for m_axi in m_axils]), 307 | 308 | # AR. 309 | o_m_axil_araddr = Cat(*[m_axi.ar.addr for m_axi in m_axils]), 310 | o_m_axil_arprot = Cat(*[Signal(3) for m_axi in m_axils]), 311 | o_m_axil_arvalid = Cat(*[m_axi.ar.valid for m_axi in m_axils]), 312 | i_m_axil_arready = Cat(*[m_axi.ar.ready for m_axi in m_axils]), 313 | 314 | # R. 315 | i_m_axil_rdata = Cat(*[m_axi.r.data for m_axi in m_axils]), 316 | i_m_axil_rresp = Cat(*[m_axi.r.resp for m_axi in m_axils]), 317 | i_m_axil_rvalid = Cat(*[m_axi.r.valid for m_axi in m_axils]), 318 | o_m_axil_rready = Cat(*[m_axi.r.ready for m_axi in m_axils]), 319 | ) 320 | 321 | @staticmethod 322 | def add_sources(platform): 323 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 324 | platform.add_source(os.path.join(rtl_dir, "arbiter.v")) 325 | platform.add_source(os.path.join(rtl_dir, "priority_encoder.v")) 326 | platform.add_source(os.path.join(rtl_dir, "axil_crossbar.v")) 327 | platform.add_source(os.path.join(rtl_dir, "axil_crossbar_wr.v")) 328 | platform.add_source(os.path.join(rtl_dir, "axil_crossbar_rd.v")) 329 | platform.add_source(os.path.join(rtl_dir, "axil_crossbar_addr.v")) 330 | -------------------------------------------------------------------------------- /verilog_axi/axi_lite/axil_dp_ram.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axil_dp_ram.v. 8 | 9 | import os 10 | import math 11 | 12 | from migen import * 13 | 14 | from litex.soc.interconnect.axi import * 15 | 16 | from verilog_axi.axi_common import * 17 | 18 | # AXI-Lite DP RAM ---------------------------------------------------------------------------------- 19 | 20 | class AXILiteDPRAM(Module): 21 | def __init__(self, platform, s_axil_a, s_axil_b, size=0x1000, pipeline_output=False): 22 | self.logger = logging.getLogger("AXILiteDPRAM") 23 | 24 | # Get/Check Parameters. 25 | # --------------------- 26 | 27 | # Clock Domain. 28 | self.logger.info(f"Clock Domain A: {colorer(s_axil_a.clock_domain)}") 29 | self.logger.info(f"Clock Domain B: {colorer(s_axil_b.clock_domain)}") 30 | 31 | # Address width. 32 | address_width = len(s_axil_a.aw.addr) 33 | if len(s_axil_a.aw.addr) != len(s_axil_b.aw.addr): 34 | self.logger.error("{} on {} (A: {} / B: {}), should be {}.".format( 35 | colorer("Different Address Width", color="red"), 36 | colorer("AXI-Lite interfaces."), 37 | colorer(len(s_axil_a.aw.addr)), 38 | colorer(len(s_axil_b.aw.addr)), 39 | colorer("the same"))) 40 | raise AXIError() 41 | else: 42 | self.logger.info(f"Address Width: {colorer(address_width)}") 43 | 44 | # Data width. 45 | data_width = len(s_axil_a.w.data) 46 | if len(s_axil_a.w.data) != len(s_axil_b.w.data): 47 | self.logger.error("{} on {} (A: {} / B: {}), should be {}.".format( 48 | colorer("Different Data Width", color="red"), 49 | colorer("AXI-Lite interfaces."), 50 | colorer(len(s_axil_a.w.data)), 51 | colorer(len(m_axi_b.w.data)), 52 | colorer("the same"))) 53 | raise AXIError() 54 | else: 55 | self.logger.info(f"Data Width: {colorer(data_width)}") 56 | 57 | # Size. 58 | self.logger.info(f"Size: {colorer(size)}bytes") 59 | 60 | # Pipeline. 61 | self.logger.info(f"Pipeline Output: {pipeline_output}.") 62 | 63 | # Module instance. 64 | # ---------------- 65 | 66 | self.specials += Instance("axil_dp_ram", 67 | # Parameters. 68 | # ----------- 69 | # Global. 70 | p_DATA_WIDTH = data_width, 71 | p_ADDR_WIDTH = math.ceil(math.log2(size)), 72 | 73 | # Pipeline. 74 | p_PIPELINE_OUTPUT = pipeline_output, 75 | 76 | # Clk / Rst. 77 | # ---------- 78 | i_a_clk = ClockSignal(s_axil_a.clock_domain), 79 | i_a_rst = ResetSignal(s_axil_a.clock_domain), 80 | i_b_clk = ClockSignal(s_axil_b.clock_domain), 81 | i_b_rst = ResetSignal(s_axil_b.clock_domain), 82 | 83 | # AXI-Lite A Slave Interface. 84 | # --------------------------- 85 | # AW. 86 | i_s_axil_a_awaddr = s_axil_a.aw.addr, 87 | i_s_axil_a_awprot = 0b0, # CHECKME. 88 | i_s_axil_a_awvalid = s_axil_a.aw.valid, 89 | o_s_axil_a_awready = s_axil_a.aw.ready, 90 | 91 | # W. 92 | i_s_axil_a_wdata = s_axil_a.w.data, 93 | i_s_axil_a_wstrb = s_axil_a.w.strb, 94 | i_s_axil_a_wvalid = s_axil_a.w.valid, 95 | o_s_axil_a_wready = s_axil_a.w.ready, 96 | 97 | # B. 98 | o_s_axil_a_bresp = s_axil_a.b.resp, 99 | o_s_axil_a_bvalid = s_axil_a.b.valid, 100 | i_s_axil_a_bready = s_axil_a.b.ready, 101 | 102 | # AR. 103 | i_s_axil_a_araddr = s_axil_a.ar.addr, 104 | i_s_axil_a_arprot = 0b0, # CHECKME. 105 | i_s_axil_a_arvalid = s_axil_a.ar.valid, 106 | o_s_axil_a_arready = s_axil_a.ar.ready, 107 | 108 | # R. 109 | o_s_axil_a_rdata = s_axil_a.r.data, 110 | o_s_axil_a_rresp = s_axil_a.r.resp, 111 | o_s_axil_a_rvalid = s_axil_a.r.valid, 112 | i_s_axil_a_rready = s_axil_a.r.ready, 113 | 114 | # AXI-Lite B Slave Interface. 115 | # --------------------------- 116 | # AW. 117 | i_s_axil_b_awaddr = s_axil_b.aw.addr, 118 | i_s_axil_b_awprot = 0b0, # CHECKME. 119 | i_s_axil_b_awvalid = s_axil_b.aw.valid, 120 | o_s_axil_b_awready = s_axil_b.aw.ready, 121 | 122 | # W. 123 | i_s_axil_b_wdata = s_axil_b.w.data, 124 | i_s_axil_b_wstrb = s_axil_b.w.strb, 125 | i_s_axil_b_wvalid = s_axil_b.w.valid, 126 | o_s_axil_b_wready = s_axil_b.w.ready, 127 | 128 | # B. 129 | o_s_axil_b_bresp = s_axil_b.b.resp, 130 | o_s_axil_b_bvalid = s_axil_b.b.valid, 131 | i_s_axil_b_bready = s_axil_b.b.ready, 132 | 133 | # AR. 134 | i_s_axil_b_araddr = s_axil_b.ar.addr, 135 | i_s_axil_b_arprot = 0b0, # CHECKME. 136 | i_s_axil_b_arvalid = s_axil_b.ar.valid, 137 | o_s_axil_b_arready = s_axil_b.ar.ready, 138 | 139 | # R. 140 | o_s_axil_b_rdata = s_axil_b.r.data, 141 | o_s_axil_b_rresp = s_axil_b.r.resp, 142 | o_s_axil_b_rvalid = s_axil_b.r.valid, 143 | i_s_axil_b_rready = s_axil_b.r.ready, 144 | ) 145 | 146 | # Add Sources. 147 | # ------------ 148 | self.add_sources(platform) 149 | 150 | @staticmethod 151 | def add_sources(platform): 152 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 153 | platform.add_source(os.path.join(rtl_dir, "axil_dp_ram.v")) 154 | -------------------------------------------------------------------------------- /verilog_axi/axi_lite/axil_interconnect.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axil_interconnect.v. 8 | 9 | import os 10 | import math 11 | 12 | from migen import * 13 | 14 | from litex.soc.interconnect.axi import * 15 | 16 | from verilog_axi.axi_common import * 17 | 18 | # AXI Lite Interconnect Interface ---------------------------------------------------------------------- 19 | 20 | class AXILiteInterconnectInterface: 21 | def __init__(self, axi, origin=None, size=None): 22 | self.axi = axi 23 | self.origin = origin 24 | self.size = size 25 | 26 | # AXI Lite Interconnect -------------------------------------------------------------------------------- 27 | 28 | class AXILiteInterconnect(Module): 29 | def __init__(self, platform): 30 | self.logger = logging.getLogger("AXILiteInterconnect") 31 | self.s_axils = {} 32 | self.m_axils = {} 33 | 34 | # Add Sources. 35 | # ------------ 36 | self.add_sources(platform) 37 | 38 | def get_if_name(self, axil): 39 | axil_ifs = {**self.s_axils, **self.m_axils} 40 | for name, axil_if in axil_ifs.items(): 41 | if axil is axil_if.axi: 42 | return name 43 | return None 44 | 45 | def add_slave(self, name=None, s_axil=None): 46 | # Get/Check Name. 47 | name = f"s_axil{len(self.s_axils)}" if name is None else name 48 | if name in self.s_axils.keys(): 49 | raise ValueError # FIXME: Add error message. 50 | 51 | # Add Slave. 52 | assert isinstance(s_axil, AXILiteInterface) 53 | s_axil = AXILiteInterconnectInterface(axi=s_axil) 54 | self.s_axils[name] = s_axil 55 | 56 | # Info. 57 | self.logger.info(f"Add AXI-Lite Slave {name} interface.") 58 | 59 | # Check. 60 | self.get_check_parameters(show=False) 61 | 62 | def add_master(self, name=None, m_axil=None, origin=None, size=None): 63 | # Get/Check Name. 64 | name = f"m_axil{len(self.m_axils)}" if name is None else name 65 | if name in self.m_axils.keys(): 66 | raise ValueError # FIXME: Add error message. 67 | 68 | # Add Master. 69 | assert isinstance(m_axil, AXILiteInterface) 70 | assert origin is not None 71 | assert size is not None 72 | m_axil = AXILiteInterconnectInterface( 73 | axi = m_axil, 74 | origin = origin, 75 | size = size 76 | ) 77 | self.m_axils[name] = m_axil 78 | 79 | # Info. 80 | self.logger.info(f"Add AXI-Lite Master {name} interface.") 81 | self.logger.info(f" Origin: 0x{origin:08x}.") 82 | self.logger.info(f" Size: 0x{size:0x}.") 83 | 84 | # Check. 85 | self.get_check_parameters(show=False) 86 | 87 | def get_check_parameters(self, show=True): 88 | axil_ifs = {**self.s_axils, **self.m_axils} 89 | axils = [axil_if.axi for name, axil_if in axil_ifs.items()] 90 | 91 | # Clock Domain. 92 | self.clock_domain = clock_domain = axils[0].clock_domain 93 | for i, axi in enumerate(axils): 94 | if i == 0: 95 | continue 96 | else: 97 | if axi.clock_domain != clock_domain: 98 | self.logger.error("{} on {} ({}: {} / {}: {}), should be {}.".format( 99 | colorer("Different Clock Domain", color="red"), 100 | colorer("AXI-Lite interfaces."), 101 | self.get_if_name(axils[0]), 102 | colorer(clock_domain), 103 | self.get_if_name(axi), 104 | colorer(axi.clock_domain), 105 | colorer("the same"))) 106 | raise AXIError() 107 | if show: 108 | self.logger.info(f"Clock Domain: {colorer(clock_domain)}") 109 | 110 | # Address width. 111 | self.address_width = address_width = len(axils[0].aw.addr) 112 | for i, axi in enumerate(axils): 113 | if i == 0: 114 | continue 115 | else: 116 | if len(axi.aw.addr) != address_width: 117 | self.logger.error("{} on {} ({}: {} / {}: {}), should be {}.".format( 118 | colorer("Different Address Width", color="red"), 119 | colorer("AXI-Lite interfaces."), 120 | self.get_if_name(axils[0]), 121 | colorer(address_width), 122 | self.get_if_name(axi), 123 | colorer(len(axi.aw.addr)), 124 | colorer("the same"))) 125 | raise AXIError() 126 | if show: 127 | self.logger.info(f"Address Width: {colorer(address_width)}") 128 | 129 | # Data width. 130 | self.data_width = data_width = len(axils[0].w.data) 131 | for i, axi in enumerate(axils): 132 | if i == 0: 133 | continue 134 | else: 135 | if len(axi.w.data) != data_width: 136 | self.logger.error("{} on {} ({}: {} / {}: {}), should be {}.".format( 137 | colorer("Different Data Width", color="red"), 138 | colorer("AXI-Lite interfaces."), 139 | self.get_if_name(axils[0]), 140 | colorer(data_width), 141 | self.get_if_name(axi), 142 | colorer(len(axi.w.data)), 143 | colorer("the same"))) 144 | raise AXIError() 145 | if show: 146 | self.logger.info(f"Data Width: {colorer(address_width)}") 147 | 148 | def do_finalize(self): 149 | # Get/Check Parameters. 150 | # --------------------- 151 | self.get_check_parameters() 152 | 153 | 154 | # Get/Check Parameters. 155 | # --------------------- 156 | self.logger.info(f"Finalized {len(self.s_axils)}X{len(self.m_axils)} Interconnect:") 157 | self.logger.info(f" Slaves:") 158 | for s_name, s_axil in self.s_axils.items(): 159 | self.logger.info(f" - {s_name}.") 160 | self.logger.info(f" Masters:") 161 | for m_name, m_axi in self.m_axils.items(): 162 | self.logger.info(f" - {m_name}, Origin: 0x{m_axi.origin:08x}, Size: 0x{m_axi.size:0x}.") 163 | 164 | 165 | # Module instance. 166 | # ---------------- 167 | 168 | s_axils = [axil_if.axi for axil_if in self.s_axils.values()] 169 | m_axils = [axil_if.axi for axil_if in self.m_axils.values()] 170 | m_origins = [axil_if.origin for axil_if in self.m_axils.values()] 171 | m_widths = [math.ceil(math.log2(axil_if.size)) for axil_if in self.m_axils.values()] 172 | 173 | def format_m_params(params, width): 174 | value = 0 175 | for param in reversed(params): 176 | value <<= width 177 | value |= param 178 | return Constant(value, len(params)*width) 179 | 180 | self.specials += Instance("axil_interconnect", 181 | # Parameters. 182 | # ----------- 183 | p_S_COUNT = len(s_axils), 184 | p_M_COUNT = len(m_axils), 185 | p_DATA_WIDTH = self.data_width, 186 | p_ADDR_WIDTH = self.address_width, 187 | 188 | # Masters Origin/Size. 189 | p_M_BASE_ADDR = format_m_params(m_origins, self.address_width), 190 | p_M_ADDR_WIDTH = format_m_params(m_widths, 32), 191 | 192 | # FIXME: Expose other parameters. 193 | 194 | # Clk / Rst. 195 | # ---------- 196 | i_clk = ClockSignal(self.clock_domain), 197 | i_rst = ResetSignal(self.clock_domain), 198 | 199 | # AXI-Lite Slave Interfaces. 200 | # -------------------------- 201 | # AW. 202 | i_s_axil_awaddr = Cat(*[s_axil.aw.addr for s_axil in s_axils]), 203 | i_s_axil_awprot = Cat(*[Constant(0, 3) for s_axil in s_axils]), # CHECKME. 204 | i_s_axil_awvalid = Cat(*[s_axil.aw.valid for s_axil in s_axils]), 205 | o_s_axil_awready = Cat(*[s_axil.aw.ready for s_axil in s_axils]), 206 | 207 | # W. 208 | i_s_axil_wdata = Cat(*[s_axil.w.data for s_axil in s_axils]), 209 | i_s_axil_wstrb = Cat(*[s_axil.w.strb for s_axil in s_axils]), 210 | i_s_axil_wvalid = Cat(*[s_axil.w.valid for s_axil in s_axils]), 211 | o_s_axil_wready = Cat(*[s_axil.w.ready for s_axil in s_axils]), 212 | 213 | # B. 214 | o_s_axil_bresp = Cat(*[s_axil.b.resp for s_axil in s_axils]), 215 | o_s_axil_bvalid = Cat(*[s_axil.b.valid for s_axil in s_axils]), 216 | i_s_axil_bready = Cat(*[s_axil.b.ready for s_axil in s_axils]), 217 | 218 | # AR. 219 | i_s_axil_araddr = Cat(*[s_axil.ar.addr for s_axil in s_axils]), 220 | i_s_axil_arprot = Cat(*[Constant(0, 3) for s_axil in s_axils]), # CHECKME. 221 | i_s_axil_arvalid = Cat(*[s_axil.ar.valid for s_axil in s_axils]), 222 | o_s_axil_arready = Cat(*[s_axil.ar.ready for s_axil in s_axils]), 223 | 224 | # R. 225 | o_s_axil_rdata = Cat(*[s_axil.r.data for s_axil in s_axils]), 226 | o_s_axil_rresp = Cat(*[s_axil.r.resp for s_axil in s_axils]), 227 | o_s_axil_rvalid = Cat(*[s_axil.r.valid for s_axil in s_axils]), 228 | i_s_axil_rready = Cat(*[s_axil.r.ready for s_axil in s_axils]), 229 | 230 | # AXI-Lite Master Interfaces. 231 | # --------------------------- 232 | # AW. 233 | o_m_axil_awaddr = Cat(*[m_axi.aw.addr for m_axi in m_axils]), 234 | o_m_axil_awprot = Cat(*[Signal(3) for m_axi in m_axils]), 235 | o_m_axil_awvalid = Cat(*[m_axi.aw.valid for m_axi in m_axils]), 236 | i_m_axil_awready = Cat(*[m_axi.aw.ready for m_axi in m_axils]), 237 | 238 | # W. 239 | o_m_axil_wdata = Cat(*[m_axi.w.data for m_axi in m_axils]), 240 | o_m_axil_wstrb = Cat(*[m_axi.w.strb for m_axi in m_axils]), 241 | o_m_axil_wvalid = Cat(*[m_axi.w.valid for m_axi in m_axils]), 242 | i_m_axil_wready = Cat(*[m_axi.w.ready for m_axi in m_axils]), 243 | 244 | # B. 245 | i_m_axil_bresp = Cat(*[m_axi.b.resp for m_axi in m_axils]), 246 | i_m_axil_bvalid = Cat(*[m_axi.b.valid for m_axi in m_axils]), 247 | o_m_axil_bready = Cat(*[m_axi.b.ready for m_axi in m_axils]), 248 | 249 | # AR. 250 | o_m_axil_araddr = Cat(*[m_axi.ar.addr for m_axi in m_axils]), 251 | o_m_axil_arprot = Cat(*[Signal(3) for m_axi in m_axils]), 252 | o_m_axil_arvalid = Cat(*[m_axi.ar.valid for m_axi in m_axils]), 253 | i_m_axil_arready = Cat(*[m_axi.ar.ready for m_axi in m_axils]), 254 | 255 | # R. 256 | i_m_axil_rdata = Cat(*[m_axi.r.data for m_axi in m_axils]), 257 | i_m_axil_rresp = Cat(*[m_axi.r.resp for m_axi in m_axils]), 258 | i_m_axil_rvalid = Cat(*[m_axi.r.valid for m_axi in m_axils]), 259 | o_m_axil_rready = Cat(*[m_axi.r.ready for m_axi in m_axils]), 260 | ) 261 | 262 | @staticmethod 263 | def add_sources(platform): 264 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 265 | platform.add_source(os.path.join(rtl_dir, "arbiter.v")) 266 | platform.add_source(os.path.join(rtl_dir, "axil_interconnect.v")) 267 | -------------------------------------------------------------------------------- /verilog_axi/axi_lite/axil_ram.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axil_ram.v. 8 | 9 | import os 10 | import math 11 | 12 | from migen import * 13 | 14 | from litex.soc.interconnect.axi import * 15 | 16 | from verilog_axi.axi_common import * 17 | 18 | # AXI Lite RAM --------------------------------------------------------------------------------------------------------- 19 | 20 | class AXILiteRAM(Module): 21 | def __init__(self, platform, s_axil, size=1024, pipeline_output=False): 22 | self.logger = logging.getLogger("AXILiteRAM") 23 | 24 | # Get/Check Parameters. 25 | # --------------------- 26 | 27 | # Clock Domain. 28 | clock_domain = s_axil.clock_domain 29 | self.logger.info(f"Clock Domain: {colorer(clock_domain)}") 30 | 31 | # Address width. 32 | address_width = len(s_axil.aw.addr) 33 | self.logger.info(f"Address Width: {colorer(address_width)}") 34 | 35 | # Data width. 36 | data_width = len(s_axil.w.data) 37 | self.logger.info(f"Data Width: {colorer(data_width)}") 38 | 39 | # Size. 40 | self.logger.info(f"Size: {colorer(size)}bytes") 41 | 42 | # Module instance. 43 | # ---------------- 44 | 45 | self.specials += Instance("axil_ram", 46 | # Parameters. 47 | # ----------- 48 | p_DATA_WIDTH = data_width, 49 | p_ADDR_WIDTH = math.ceil(math.log2(size)), 50 | p_PIPELINE_OUTPUT = pipeline_output, 51 | 52 | # Clk / Rst. 53 | # ---------- 54 | i_clk = ClockSignal(clock_domain), 55 | i_rst = ResetSignal(clock_domain), 56 | 57 | # AXI-Lite Slave Interface. 58 | # ------------------------- 59 | # AW. 60 | i_s_axil_awaddr = s_axil.aw.addr, 61 | i_s_axil_awprot = 0b0, # CHECKME. 62 | i_s_axil_awvalid = s_axil.aw.valid, 63 | o_s_axil_awready = s_axil.aw.ready, 64 | 65 | # W. 66 | i_s_axil_wdata = s_axil.w.data, 67 | i_s_axil_wstrb = s_axil.w.strb, 68 | i_s_axil_wvalid = s_axil.w.valid, 69 | o_s_axil_wready = s_axil.w.ready, 70 | 71 | # B. 72 | o_s_axil_bresp = s_axil.b.resp, 73 | o_s_axil_bvalid = s_axil.b.valid, 74 | i_s_axil_bready = s_axil.b.ready, 75 | 76 | # AR. 77 | i_s_axil_araddr = s_axil.ar.addr, 78 | i_s_axil_arprot = 0b0, # CHECKME. 79 | i_s_axil_arvalid = s_axil.ar.valid, 80 | o_s_axil_arready = s_axil.ar.ready, 81 | 82 | # R. 83 | o_s_axil_rdata = s_axil.r.data, 84 | o_s_axil_rresp = s_axil.r.resp, 85 | o_s_axil_rvalid = s_axil.r.valid, 86 | i_s_axil_rready = s_axil.r.ready, 87 | ) 88 | 89 | # Add Sources. 90 | # ------------ 91 | self.add_sources(platform) 92 | 93 | @staticmethod 94 | def add_sources(platform): 95 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 96 | platform.add_source(os.path.join(rtl_dir, "axil_ram.v")) 97 | -------------------------------------------------------------------------------- /verilog_axi/axi_lite/axil_register.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of LiteX-Verilog-AXI-Test 3 | # 4 | # Copyright (c) 2022 Florent Kermarrec 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | 7 | # LiteX wrapper around Alex Forencich Verilog-AXI's axil_register.v. 8 | 9 | import os 10 | 11 | from migen import * 12 | 13 | from litex.soc.interconnect.axi import * 14 | 15 | from verilog_axi.axi_common import * 16 | 17 | # AXI-Lite Register -------------------------------------------------------------------------------- 18 | 19 | class AXILiteRegister(Module): 20 | def __init__(self, platform, s_axil, m_axil, 21 | aw_reg = AXIRegister.SIMPLE_BUFFER, 22 | w_reg = AXIRegister.SIMPLE_BUFFER, 23 | b_reg = AXIRegister.SIMPLE_BUFFER, 24 | ar_reg = AXIRegister.SIMPLE_BUFFER, 25 | r_reg = AXIRegister.SIMPLE_BUFFER, 26 | ): 27 | self.logger = logging.getLogger("AXILiteRegister") 28 | 29 | # Get/Check Parameters. 30 | # --------------------- 31 | 32 | # Clock Domain. 33 | clock_domain = s_axil.clock_domain 34 | if s_axil.clock_domain != m_axil.clock_domain: 35 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 36 | colorer("Different Clock Domain", color="red"), 37 | colorer("AXI-Lite interfaces."), 38 | colorer(s_axil.clock_domain), 39 | colorer(m_axil.clock_domain), 40 | colorer("the same"))) 41 | raise AXIError() 42 | else: 43 | self.logger.info(f"Clock Domain: {colorer(clock_domain)}") 44 | 45 | # Address width. 46 | address_width = len(s_axil.aw.addr) 47 | if len(s_axil.aw.addr) != len(m_axil.aw.addr): 48 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 49 | colorer("Different Address Width", color="red"), 50 | colorer("AXI-Lite interfaces."), 51 | colorer(len(s_axil.aw.addr)), 52 | colorer(len(m_axil.aw.addr)), 53 | colorer("the same"))) 54 | raise AXIError() 55 | else: 56 | self.logger.info(f"Address Width: {colorer(address_width)}") 57 | 58 | # Data width. 59 | data_width = len(s_axil.w.data) 60 | if len(s_axil.w.data) != len(m_axil.w.data): 61 | self.logger.error("{} on {} (Slave: {} / Master: {}), should be {}.".format( 62 | colorer("Different Data Width", color="red"), 63 | colorer("AXI-Lite interfaces."), 64 | colorer(len(s_axil.w.data)), 65 | colorer(len(m_axil.w.data)), 66 | colorer("the same"))) 67 | raise AXIError() 68 | else: 69 | self.logger.info(f"Data Width: {colorer(data_width)}") 70 | 71 | # Registers. 72 | self.logger.info(f"AW Reg: {aw_reg.name}.") 73 | self.logger.info(f" W Reg: {w_reg.name}.") 74 | self.logger.info(f" B Reg: {b_reg.name}.") 75 | self.logger.info(f"AR Reg: {ar_reg.name}.") 76 | self.logger.info(f" R Reg: {r_reg.name}.") 77 | 78 | # Module instance. 79 | # ---------------- 80 | 81 | self.specials += Instance("axil_register", 82 | # Parameters. 83 | # ----------- 84 | p_DATA_WIDTH = data_width, 85 | p_ADDR_WIDTH = address_width, 86 | 87 | # Register type. 88 | p_AW_REG_TYPE = aw_reg, 89 | p_W_REG_TYPE = w_reg, 90 | p_B_REG_TYPE = b_reg, 91 | p_AR_REG_TYPE = ar_reg, 92 | p_R_REG_TYPE = r_reg, 93 | 94 | # Clk / Rst. 95 | # ---------- 96 | i_clk = ClockSignal(clock_domain), 97 | i_rst = ResetSignal(clock_domain), 98 | 99 | # AXI-Lite Slave Interface. 100 | # ------------------------- 101 | # AW. 102 | i_s_axil_awaddr = s_axil.aw.addr, 103 | i_s_axil_awprot = 0b0, # CHECKME. 104 | i_s_axil_awvalid = s_axil.aw.valid, 105 | o_s_axil_awready = s_axil.aw.ready, 106 | 107 | # W. 108 | i_s_axil_wdata = s_axil.w.data, 109 | i_s_axil_wstrb = s_axil.w.strb, 110 | i_s_axil_wvalid = s_axil.w.valid, 111 | o_s_axil_wready = s_axil.w.ready, 112 | 113 | # B. 114 | o_s_axil_bresp = s_axil.b.resp, 115 | o_s_axil_bvalid = s_axil.b.valid, 116 | i_s_axil_bready = s_axil.b.ready, 117 | 118 | # AR. 119 | i_s_axil_araddr = s_axil.ar.addr, 120 | i_s_axil_arprot = 0b0, # CHECKME. 121 | i_s_axil_arvalid = s_axil.ar.valid, 122 | o_s_axil_arready = s_axil.ar.ready, 123 | 124 | # R. 125 | o_s_axil_rdata = s_axil.r.data, 126 | o_s_axil_rresp = s_axil.r.resp, 127 | o_s_axil_rvalid = s_axil.r.valid, 128 | i_s_axil_rready = s_axil.r.ready, 129 | 130 | # AXI-Lite Master Interface. 131 | # -------------------------- 132 | # AW. 133 | o_m_axil_awaddr = m_axil.aw.addr, 134 | o_m_axil_awprot = Open(), # CHECKME. 135 | o_m_axil_awvalid = m_axil.aw.valid, 136 | i_m_axil_awready = m_axil.aw.ready, 137 | 138 | # W. 139 | o_m_axil_wdata = m_axil.w.data, 140 | o_m_axil_wstrb = m_axil.w.strb, 141 | o_m_axil_wvalid = m_axil.w.valid, 142 | i_m_axil_wready = m_axil.w.ready, 143 | 144 | # B. 145 | i_m_axil_bresp = m_axil.b.resp, 146 | i_m_axil_bvalid = m_axil.b.valid, 147 | o_m_axil_bready = m_axil.b.ready, 148 | 149 | # AR. 150 | o_m_axil_araddr = m_axil.ar.addr, 151 | o_m_axil_arprot = Open(), # CHECKME. 152 | o_m_axil_arvalid = m_axil.ar.valid, 153 | i_m_axil_arready = m_axil.ar.ready, 154 | 155 | # R. 156 | i_m_axil_rdata = m_axil.r.data, 157 | i_m_axil_rresp = m_axil.r.resp, 158 | i_m_axil_rvalid = m_axil.r.valid, 159 | o_m_axil_rready = m_axil.r.ready, 160 | ) 161 | 162 | # Add Sources. 163 | # ------------ 164 | self.add_sources(platform) 165 | 166 | @staticmethod 167 | def add_sources(platform): 168 | rtl_dir = os.path.join(os.path.dirname(__file__), "..", "verilog", "rtl") 169 | platform.add_source(os.path.join(rtl_dir, "axil_register_wr.v")) 170 | platform.add_source(os.path.join(rtl_dir, "axil_register_rd.v")) 171 | platform.add_source(os.path.join(rtl_dir, "axil_register.v")) 172 | --------------------------------------------------------------------------------