Merge pull request #1199 from sergachev/feature/zynqmp

cores/cpu: add ZynqMP (UltraScale+ MPSoC) support
This commit is contained in:
enjoy-digital 2022-02-07 07:53:25 +01:00 committed by GitHub
commit bd3d063d87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 520 additions and 8 deletions

View File

@ -0,0 +1 @@
from litex.soc.cores.cpu.zynqmp.core import ZynqMP

View File

@ -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;
}

View File

@ -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)

View File

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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));

View File

@ -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