From 5aee6359e622a6b4b2e3bc472505f815485ac340 Mon Sep 17 00:00:00 2001 From: Ilia Sergachev Date: Sat, 5 Feb 2022 23:53:09 +0100 Subject: [PATCH] cores/cpu: add ZynqMP (UltraScale+ MPSoC) support --- litex/soc/cores/cpu/zynqmp/__init__.py | 1 + litex/soc/cores/cpu/zynqmp/boot-helper.c | 5 + litex/soc/cores/cpu/zynqmp/core.py | 82 ++++++ litex/soc/cores/cpu/zynqmp/crt0.c | 0 litex/soc/cores/cpu/zynqmp/irq.h | 37 +++ litex/soc/cores/cpu/zynqmp/system.h | 53 ++++ litex/soc/integration/soc_core.py | 2 +- litex/soc/software/bios/Makefile | 2 + litex/soc/software/bios/linker-zynqmp.ld | 320 +++++++++++++++++++++++ litex/soc/software/libxil/Makefile | 26 +- 10 files changed, 520 insertions(+), 8 deletions(-) create mode 100644 litex/soc/cores/cpu/zynqmp/__init__.py create mode 100644 litex/soc/cores/cpu/zynqmp/boot-helper.c create mode 100644 litex/soc/cores/cpu/zynqmp/core.py create mode 100644 litex/soc/cores/cpu/zynqmp/crt0.c create mode 100644 litex/soc/cores/cpu/zynqmp/irq.h create mode 100644 litex/soc/cores/cpu/zynqmp/system.h create mode 100644 litex/soc/software/bios/linker-zynqmp.ld diff --git a/litex/soc/cores/cpu/zynqmp/__init__.py b/litex/soc/cores/cpu/zynqmp/__init__.py new file mode 100644 index 000000000..f9ab86a93 --- /dev/null +++ b/litex/soc/cores/cpu/zynqmp/__init__.py @@ -0,0 +1 @@ +from litex.soc.cores.cpu.zynqmp.core import ZynqMP diff --git a/litex/soc/cores/cpu/zynqmp/boot-helper.c b/litex/soc/cores/cpu/zynqmp/boot-helper.c new file mode 100644 index 000000000..4dd8ae2d3 --- /dev/null +++ b/litex/soc/cores/cpu/zynqmp/boot-helper.c @@ -0,0 +1,5 @@ +void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr); + +void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr) { + goto *addr; +} diff --git a/litex/soc/cores/cpu/zynqmp/core.py b/litex/soc/cores/cpu/zynqmp/core.py new file mode 100644 index 000000000..6181e07e1 --- /dev/null +++ b/litex/soc/cores/cpu/zynqmp/core.py @@ -0,0 +1,82 @@ +from migen import * +from litex.soc.cores.cpu import CPU +from litex.soc.interconnect import axi + + +class ZynqMP(CPU): + variants = ["standard"] + family = "aarch64" + name = "zynqmp" + human_name = "Zynq Ultrascale+ MPSoC" + data_width = 64 + endianness = "little" + reset_address = 0xc000_0000 + gcc_triple = "aarch64-none-elf" + gcc_flags = "" + linker_output_format = "elf64-littleaarch64" + nop = "nop" + io_regions = { # Origin, Length. + 0x8000_0000: 0x4000_0000, + 0xe000_0000: 0xff_2000_0000 # TODO: there are more details here + } + + @property + def mem_map(self): + return { + "sram": 0x0000_0000, # DDR low in fact + "rom": 0xc000_0000, # Quad SPI memory + } + + def __init__(self, platform, variant, *args, **kwargs): + super().__init__(*args, **kwargs) + self.platform = platform + self.reset = Signal() + self.periph_buses = [] # Peripheral buses (Connected to main SoC's bus). + self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). + self.axi_gp_masters = [] # General Purpose AXI Masters. + + self.clock_domains.cd_ps = ClockDomain() + + self.ps_name = "ps" + self.ps_tcl = [] + self.config = {'PSU__FPGA_PL0_ENABLE': 1} # enable pl_clk0 + rst_n = Signal() + self.cpu_params = dict( + o_pl_clk0=ClockSignal("ps"), + o_pl_resetn0=rst_n + ) + self.comb += ResetSignal("ps").eq(~rst_n) + self.ps_tcl.append(f"set ps [create_ip -vendor xilinx.com -name zynq_ultra_ps_e -module_name {self.ps_name}]") + + def add_axi_gp_master(self): + assert len(self.axi_gp_masters) < 3 + n = len(self.axi_gp_masters) + axi_gpn = axi.AXIInterface(data_width=32, address_width=32, id_width=16) + self.config[f'PSU__USE__M_AXI_GP{n}'] = 1 + self.config[f'PSU__MAXIGP{n}__DATA_WIDTH'] = axi_gpn.data_width + self.axi_gp_masters.append(axi_gpn) + self.cpu_params['i_maxihpm0_fpd_aclk'] = ClockSignal("ps") + layout = axi_gpn.layout_flat() + dir_map = {DIR_M_TO_S: 'o', DIR_S_TO_M: 'i'} + for group, signal, direction in layout: + sig_name = group + signal + if sig_name in ['bfirst', 'blast', 'rfirst', 'arfirst', 'arlast', 'awfirst', 'awlast', 'wfirst', 'wid']: + continue + direction = dir_map[direction] + self.cpu_params[f'{direction}_maxigp{n}_{group}{signal}'] = getattr(getattr(axi_gpn, group), signal) + + return axi_gpn + + def do_finalize(self): + if len(self.ps_tcl): + self.ps_tcl.append("set_property -dict [list \\") + for config, value in self.config.items(): + self.ps_tcl.append("CONFIG.{} {} \\".format(config, '{{' + str(value) + '}}')) + self.ps_tcl.append(f"] [get_ips {self.ps_name}]") + + self.ps_tcl += [ + f"generate_target all [get_ips {self.ps_name}]", + f"synth_ip [get_ips {self.ps_name}]" + ] + self.platform.toolchain.pre_synthesis_commands += self.ps_tcl + self.specials += Instance(self.ps_name, **self.cpu_params) diff --git a/litex/soc/cores/cpu/zynqmp/crt0.c b/litex/soc/cores/cpu/zynqmp/crt0.c new file mode 100644 index 000000000..e69de29bb diff --git a/litex/soc/cores/cpu/zynqmp/irq.h b/litex/soc/cores/cpu/zynqmp/irq.h new file mode 100644 index 000000000..4c87950ef --- /dev/null +++ b/litex/soc/cores/cpu/zynqmp/irq.h @@ -0,0 +1,37 @@ +#ifndef __IRQ_H +#define __IRQ_H + +#ifdef __cplusplus +extern "C" { +#endif + +static inline unsigned int irq_getie(void) +{ + return 0; /* FIXME */ +} + +static inline void irq_setie(unsigned int ie) +{ + /* FIXME */ +} + +static inline unsigned int irq_getmask(void) +{ + return 0; /* FIXME */ +} + +static inline void irq_setmask(unsigned int mask) +{ + /* FIXME */ +} + +static inline unsigned int irq_pending(void) +{ + return 0; /* FIXME */ +} + +#ifdef __cplusplus +} +#endif + +#endif /* __IRQ_H */ diff --git a/litex/soc/cores/cpu/zynqmp/system.h b/litex/soc/cores/cpu/zynqmp/system.h new file mode 100644 index 000000000..7061ae886 --- /dev/null +++ b/litex/soc/cores/cpu/zynqmp/system.h @@ -0,0 +1,53 @@ +#ifndef __SYSTEM_H +#define __SYSTEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "xuartps_hw.h" +#include "xil_cache.h" + +__attribute__((unused)) static void flush_cpu_icache(void){}; + +__attribute__((unused)) static void flush_cpu_dcache(void) { + Xil_DCacheFlush(); +}; + +void flush_l2_cache(void); // TODO: use Xil_L2CacheFlush(); ! + +void busy_wait(unsigned int ms); +void busy_wait_us(unsigned int us); + +#define CSR_UART_BASE +#define UART_POLLING + +static inline void uart_rxtx_write(char c) { + XUartPs_WriteReg(STDOUT_BASEADDRESS, XUARTPS_FIFO_OFFSET, (uint32_t) c); +} + +static inline uint8_t uart_rxtx_read(void) { + return XUartPs_ReadReg(STDOUT_BASEADDRESS, XUARTPS_FIFO_OFFSET); +} + +static inline uint8_t uart_txfull_read(void) { + return XUartPs_IsTransmitFull(STDOUT_BASEADDRESS); +} + +static inline uint8_t uart_rxempty_read(void) { + return !XUartPs_IsReceiveData(STDOUT_BASEADDRESS); +} + +static inline void uart_ev_pending_write(uint8_t x) {} + +static inline uint8_t uart_ev_pending_read(void) { + return 0; +} + +static inline void uart_ev_enable_write(uint8_t x) {} + +#ifdef __cplusplus +} +#endif + +#endif /* __SYSTEM_H */ diff --git a/litex/soc/integration/soc_core.py b/litex/soc/integration/soc_core.py index 6aaae1e0f..999699aaf 100644 --- a/litex/soc/integration/soc_core.py +++ b/litex/soc/integration/soc_core.py @@ -156,7 +156,7 @@ class SoCCore(LiteXSoC): integrated_rom_size = 4*len(integrated_rom_init) # Disable ROM when no CPU/hard-CPU. - if cpu_type in [None, "zynq7000", "eos_s3"]: + if cpu_type in [None, "zynq7000", "zynqmp", "eos_s3"]: integrated_rom_init = [] integrated_rom_size = 0 self.integrated_rom_size = integrated_rom_size diff --git a/litex/soc/software/bios/Makefile b/litex/soc/software/bios/Makefile index aa9085931..aa48af354 100755 --- a/litex/soc/software/bios/Makefile +++ b/litex/soc/software/bios/Makefile @@ -41,6 +41,8 @@ endif ifeq ($(CPU), zynq7000) LSCRIPT = linker-zynq.ld +else ifeq ($(CPU), zynqmp) +LSCRIPT = linker-zynqmp.ld else LSCRIPT = linker.ld endif diff --git a/litex/soc/software/bios/linker-zynqmp.ld b/litex/soc/software/bios/linker-zynqmp.ld new file mode 100644 index 000000000..24f3ead1e --- /dev/null +++ b/litex/soc/software/bios/linker-zynqmp.ld @@ -0,0 +1,320 @@ +/*******************************************************************/ +/* Copyright (c) 2010-2016 Xilinx, Inc. All rights reserved. */ +/* */ +/* Description : Cortex-A53 Linker Script */ +/*******************************************************************/ + +INCLUDE generated/output_format.ld +ENTRY(_start) + +INCLUDE generated/regions.ld + +_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000; +_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x2000; + +_EL0_STACK_SIZE = DEFINED(_EL0_STACK_SIZE) ? _EL0_STACK_SIZE : 1024; +_EL1_STACK_SIZE = DEFINED(_EL1_STACK_SIZE) ? _EL1_STACK_SIZE : 2048; +_EL2_STACK_SIZE = DEFINED(_EL2_STACK_SIZE) ? _EL2_STACK_SIZE : 1024; + +ENTRY(_vector_table) + +SECTIONS +{ +.text : { + _ftext = .; + KEEP (*(.vectors)) + *(.boot) + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + *(.plt) + *(.gnu_warning) + *(.gcc_execpt_table) + *(.glue_7) + *(.glue_7t) + *(.ARM.extab) + *(.gnu.linkonce.armextab.*) +} > sram + +.commands : +{ + PROVIDE_HIDDEN (__bios_cmd_start = .); + KEEP(*(.bios_cmd)) + PROVIDE_HIDDEN (__bios_cmd_end = .); +} > sram + +.init (ALIGN(64)) : { + PROVIDE_HIDDEN (__bios_init_start = .); + KEEP (*(.bios_init)) + PROVIDE_HIDDEN (__bios_init_end = .); +} > sram + +.fini (ALIGN(64)) : { + KEEP (*(.fini)) +} > sram + +.interp : { + KEEP (*(.interp)) +} > sram + +.note-ABI-tag : { + KEEP (*(.note-ABI-tag)) +} > sram + +.rodata : { + . = ALIGN(64); + __rodata_start = .; + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + __rodata_end = .; +} > sram + +.rodata1 : { + . = ALIGN(64); + __rodata1_start = .; + *(.rodata1) + *(.rodata1.*) + + /* Make sure the file is aligned on disk as well + as in memory; CRC calculation requires that. */ + FILL(0); + . = ALIGN(8); + + __rodata1_end = .; +} > sram + +.sdata2 : { + . = ALIGN(64); + __sdata2_start = .; + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + __sdata2_end = .; +} > sram + +.sbss2 : { + . = ALIGN(64); + __sbss2_start = .; + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + __sbss2_end = .; +} > sram + +.data : { + . = ALIGN(64); + __data_start = .; + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.jcr) + *(.got) + *(.got.plt) + __data_end = .; +} > sram + +.data1 : { + . = ALIGN(64); + __data1_start = .; + *(.data1) + *(.data1.*) + + /* Make sure the file is aligned on disk as well + as in memory; CRC calculation requires that. */ + FILL(0); + . = ALIGN(8); + + __data1_end = .; +} > sram + +.got : { + *(.got) +} > sram + +.got1 : { + *(.got1) +} > sram + +.got2 : { + *(.got2) +} > sram + +.note.gnu.build-id : { + KEEP (*(.note.gnu.build-id)) +} > sram + +.ctors : { + . = ALIGN(64); + __CTOR_LIST__ = .; + ___CTORS_LIST___ = .; + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + __CTOR_END__ = .; + ___CTORS_END___ = .; +} > sram + +.dtors : { + . = ALIGN(64); + __DTOR_LIST__ = .; + ___DTORS_LIST___ = .; + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + __DTOR_END__ = .; + ___DTORS_END___ = .; +} > sram + +.fixup : { + __fixup_start = .; + *(.fixup) + __fixup_end = .; +} > sram + +.eh_frame : { + *(.eh_frame) +} > sram + +.eh_framehdr : { + __eh_framehdr_start = .; + *(.eh_framehdr) + __eh_framehdr_end = .; +} > sram + +.gcc_except_table : { + *(.gcc_except_table) +} > sram + +.mmu_tbl0 (ALIGN(4096)) : { + __mmu_tbl0_start = .; + *(.mmu_tbl0) + __mmu_tbl0_end = .; +} > sram + +.mmu_tbl1 (ALIGN(4096)) : { + __mmu_tbl1_start = .; + *(.mmu_tbl1) + __mmu_tbl1_end = .; +} > sram + +.mmu_tbl2 (ALIGN(4096)) : { + __mmu_tbl2_start = .; + *(.mmu_tbl2) + __mmu_tbl2_end = .; +} > sram + +.ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + *(.gnu.linkonce.armexidix.*.*) + __exidx_end = .; +} > sram + +.preinit_array : { + . = ALIGN(64); + __preinit_array_start = .; + KEEP (*(SORT(.preinit_array.*))) + KEEP (*(.preinit_array)) + __preinit_array_end = .; +} > sram + +.init_array : { + . = ALIGN(64); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; +} > sram + +.fini_array : { + . = ALIGN(64); + __fini_array_start = .; + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array)) + __fini_array_end = .; +} > sram + +.ARM.attributes : { + __ARM.attributes_start = .; + *(.ARM.attributes) + __ARM.attributes_end = .; +} > sram + +.sdata : { + . = ALIGN(64); + __sdata_start = .; + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + __sdata_end = .; +} > sram + +.sbss (NOLOAD) : { + . = ALIGN(64); + __sbss_start = .; + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + . = ALIGN(64); + __sbss_end = .; +} > sram + +.tdata : { + . = ALIGN(64); + __tdata_start = .; + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + __tdata_end = .; +} > sram + +.tbss : { + . = ALIGN(64); + __tbss_start = .; + *(.tbss) + *(.tbss.*) + *(.gnu.linkonce.tb.*) + __tbss_end = .; +} > sram + +.bss (NOLOAD) : { + . = ALIGN(64); + __bss_start__ = .; + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(64); + __bss_end__ = .; +} > sram + +_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 ); + +_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 ); + +.stack (NOLOAD) : { + . = ALIGN(64); + _el3_stack_end = .; + . += _STACK_SIZE; + __el3_stack = .; + _el2_stack_end = .; + . += _EL2_STACK_SIZE; + . = ALIGN(64); + __el2_stack = .; + _el1_stack_end = .; + . += _EL1_STACK_SIZE; + . = ALIGN(64); + __el1_stack = .; + _el0_stack_end = .; + . += _EL0_STACK_SIZE; + . = ALIGN(64); + __el0_stack = .; +} > sram + +_end = .; +} + +PROVIDE(_edata_rom = LOADADDR(.data) + SIZEOF(.data)); diff --git a/litex/soc/software/libxil/Makefile b/litex/soc/software/libxil/Makefile index eeb018fce..8346310d9 100644 --- a/litex/soc/software/libxil/Makefile +++ b/litex/soc/software/libxil/Makefile @@ -9,23 +9,35 @@ OBJECTS = xil_cache.o \ xil_exception.o \ asm_vectors.o \ boot.o \ - cpu_init.o \ translation_table.o \ xil-crt0.o \ vectors.o \ xtime_l.o -libxil.a: $(OBJECTS) - $(AR) crs $@ $^ - -%.o: embeddedsw/lib/bsp/standalone/src/arm/cortexa9/%.c - $(compile) - %.o: embeddedsw/lib/bsp/standalone/src/arm/common/%.c $(compile) +ifeq ($(CPU), zynqmp) +%.o: embeddedsw/lib/bsp/standalone/src/arm/ARMv8/64bit/%.c + $(compile) +%.o: embeddedsw/lib/bsp/standalone/src/arm/ARMv8/64bit/gcc/%.S + $(assemble) +%.o: embeddedsw/lib/bsp/standalone/src/arm/ARMv8/64bit/platform/ZynqMP/gcc/%.S + $(assemble) + +else ifeq ($(CPU), zynq7000) + +OBJECTS += cpu_init.o + +%.o: embeddedsw/lib/bsp/standalone/src/arm/cortexa9/%.c + $(compile) %.o: embeddedsw/lib/bsp/standalone/src/arm/cortexa9/gcc/%.S $(assemble) +endif + +libxil.a: $(OBJECTS) + $(AR) crs $@ $^ + clean: $(RM) $(OBJECTS) libxil.a