diff --git a/litex/soc/cores/cpu/cva5/__init__.py b/litex/soc/cores/cpu/cva5/__init__.py new file mode 100644 index 000000000..edc8b2d70 --- /dev/null +++ b/litex/soc/cores/cpu/cva5/__init__.py @@ -0,0 +1 @@ +from litex.soc.cores.cpu.cva5.core import CVA5 diff --git a/litex/soc/cores/cpu/cva5/boot-helper.S b/litex/soc/cores/cpu/cva5/boot-helper.S new file mode 100644 index 000000000..6dd74aaeb --- /dev/null +++ b/litex/soc/cores/cpu/cva5/boot-helper.S @@ -0,0 +1,4 @@ +.section .text, "ax", @progbits +.global boot_helper +boot_helper: + jr x13 diff --git a/litex/soc/cores/cpu/cva5/core.py b/litex/soc/cores/cpu/cva5/core.py new file mode 100644 index 000000000..e0233a292 --- /dev/null +++ b/litex/soc/cores/cpu/cva5/core.py @@ -0,0 +1,129 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2022 Eric Matthews +# SPDX-License-Identifier: BSD-2-Clause + +import os + +from migen import * + +from litex import get_data_mod +from litex.soc.interconnect import wishbone +from litex.soc.interconnect.csr import * +from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32 + +# Variants ----------------------------------------------------------------------------------------- + +CPU_VARIANTS = ["minimal", "standard"] + +# GCC Flags ---------------------------------------------------------------------------------------- + +GCC_FLAGS = { + "minimal" : "-march=rv32i -mabi=ilp32 ", + "standard" : "-march=rv32im -mabi=ilp32 " +} + +# CVA5 ----------------------------------------------------------------------------------------- + +class CVA5(CPU): + category = "softcore" + family = "riscv" + name = "cva5" + human_name = "CVA5" + variants = CPU_VARIANTS + data_width = 32 + endianness = "little" + gcc_triple = CPU_GCC_TRIPLE_RISCV32 + linker_output_format = "elf32-littleriscv" + nop = "nop" + io_regions = {0x80000000: 0x80000000} # origin, length + + # GCC Flags. + @property + def gcc_flags(self): + flags = GCC_FLAGS[self.variant] + flags += "-D__cva5__" + return flags + + def __init__(self, platform, variant="standard"): + self.platform = platform + self.variant = variant + self.reset = Signal() + self.ibus = ibus = wishbone.Interface() + self.dbus = dbus = wishbone.Interface() + self.idbus = idbus = wishbone.Interface() + self.periph_buses = [ibus, dbus] if (variant == "minimal") else [idbus] + self.memory_buses = [] + self.interrupt = Signal(2) + + self.cpu_params = dict( + p_LITEX_VARIANT = CPU_VARIANTS.index(variant), + p_RESET_VEC = 0, + p_NON_CACHABLE_L = 0x80000000, + p_NON_CACHABLE_H = 0xFFFFFFFF, + + i_clk = ClockSignal("sys"), + i_rst = ResetSignal("sys"), + i_litex_interrupt = self.interrupt + ) + if variant == "minimal" : + self.cpu_params.update( + o_ibus_adr = ibus.adr, + o_ibus_dat_w = ibus.dat_w, + o_ibus_sel = ibus.sel, + o_ibus_cyc = ibus.cyc, + o_ibus_stb = ibus.stb, + o_ibus_we = ibus.we, + o_ibus_cti = ibus.cti, + o_ibus_bte = ibus.bte, + i_ibus_dat_r = ibus.dat_r, + i_ibus_ack = ibus.ack, + i_ibus_err = ibus.err, + + o_dbus_adr = dbus.adr, + o_dbus_dat_w = dbus.dat_w, + o_dbus_sel = dbus.sel, + o_dbus_cyc = dbus.cyc, + o_dbus_stb = dbus.stb, + o_dbus_we = dbus.we, + o_dbus_cti = dbus.cti, + o_dbus_bte = dbus.bte, + i_dbus_dat_r = dbus.dat_r, + i_dbus_ack = dbus.ack, + i_dbus_err = dbus.err + ) + else : + self.cpu_params.update( + o_idbus_adr = idbus.adr, + o_idbus_dat_w = idbus.dat_w, + o_idbus_sel = idbus.sel, + o_idbus_cyc = idbus.cyc, + o_idbus_stb = idbus.stb, + o_idbus_we = idbus.we, + o_idbus_cti = idbus.cti, + o_idbus_bte = idbus.bte, + i_idbus_dat_r = idbus.dat_r, + i_idbus_ack = idbus.ack, + i_idbus_err = idbus.err, + ) + self.add_sources(platform) + + def set_reset_address(self, reset_address): + assert not hasattr(self, "reset_address") + self.reset_address = reset_address + self.cpu_params.update(p_RESET_VEC = reset_address) + + @staticmethod + def add_sources(platform): + cva5_path = get_data_mod("cpu", "cva5").data_location + with open(os.path.join(cva5_path, 'tools/compile_order'), 'r') as f: + for line in f: + if line.strip() != '': + platform.add_source(os.path.join(cva5_path, line.strip())) + platform.add_source(os.path.join(cva5_path, 'examples/litex/l1_to_wishbone.sv')) + platform.add_source(os.path.join(cva5_path, 'examples/litex/litex_wrapper.sv')) + + def do_finalize(self): + assert hasattr(self, "reset_address") + self.specials += Instance("litex_wrapper", **self.cpu_params) diff --git a/litex/soc/cores/cpu/cva5/crt0.S b/litex/soc/cores/cpu/cva5/crt0.S new file mode 100644 index 000000000..e3db641cc --- /dev/null +++ b/litex/soc/cores/cpu/cva5/crt0.S @@ -0,0 +1,89 @@ +.global main +.global isr +.global _start + +_start: + j crt_init + nop + nop + nop + nop + nop + nop + nop + +.global trap_entry +trap_entry: + sw x1, - 1*4(sp) + sw x5, - 2*4(sp) + sw x6, - 3*4(sp) + sw x7, - 4*4(sp) + sw x10, - 5*4(sp) + sw x11, - 6*4(sp) + sw x12, - 7*4(sp) + sw x13, - 8*4(sp) + sw x14, - 9*4(sp) + sw x15, -10*4(sp) + sw x16, -11*4(sp) + sw x17, -12*4(sp) + sw x28, -13*4(sp) + sw x29, -14*4(sp) + sw x30, -15*4(sp) + sw x31, -16*4(sp) + addi sp,sp,-16*4 + call isr + lw x1 , 15*4(sp) + lw x5, 14*4(sp) + lw x6, 13*4(sp) + lw x7, 12*4(sp) + lw x10, 11*4(sp) + lw x11, 10*4(sp) + lw x12, 9*4(sp) + lw x13, 8*4(sp) + lw x14, 7*4(sp) + lw x15, 6*4(sp) + lw x16, 5*4(sp) + lw x17, 4*4(sp) + lw x28, 3*4(sp) + lw x29, 2*4(sp) + lw x30, 1*4(sp) + lw x31, 0*4(sp) + addi sp,sp,16*4 + mret + .text + + +crt_init: + la sp, _fstack + la a0, trap_entry + csrw mtvec, a0 + +data_init: + la a0, _fdata + la a1, _edata + la a2, _fdata_rom +data_loop: + beq a0,a1,data_done + lw a3,0(a2) + sw a3,0(a0) + add a0,a0,4 + add a2,a2,4 + j data_loop +data_done: + +bss_init: + la a0, _fbss + la a1, _ebss +bss_loop: + beq a0,a1,bss_done + sw zero,0(a0) + add a0,a0,4 + j bss_loop +bss_done: + + li a0, 0x880 //880 enable timer + external interrupt (until mstatus.MIE is set, they will never trigger an interrupt) + csrw mie,a0 + + call main +infinit_loop: + j infinit_loop diff --git a/litex/soc/cores/cpu/cva5/csr-defs.h b/litex/soc/cores/cpu/cva5/csr-defs.h new file mode 100644 index 000000000..a57326bff --- /dev/null +++ b/litex/soc/cores/cpu/cva5/csr-defs.h @@ -0,0 +1,8 @@ +#ifndef CSR_DEFS__H +#define CSR_DEFS__H + +#define CSR_MSTATUS_MIE 0x8 + +#define CSR_IRQ_EXTERNAL_OFFSET 0xB + +#endif /* CSR_DEFS__H */ diff --git a/litex/soc/cores/cpu/cva5/irq.h b/litex/soc/cores/cpu/cva5/irq.h new file mode 100644 index 000000000..779fc1434 --- /dev/null +++ b/litex/soc/cores/cpu/cva5/irq.h @@ -0,0 +1,41 @@ +#ifndef __IRQ_H +#define __IRQ_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +static inline unsigned int irq_getie(void) +{ + return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0; +} + +static inline void irq_setie(unsigned int ie) +{ + if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE); +} + +static inline unsigned int irq_getmask(void) +{ + return (csrr(mie) >> CSR_IRQ_EXTERNAL_OFFSET); +} + +static inline void irq_setmask(unsigned int mask) +{ + if (mask) csrs(mie,CSR_IRQ_EXTERNAL_OFFSET); else csrc(mie,CSR_IRQ_EXTERNAL_OFFSET); +} + +static inline unsigned int irq_pending(void) +{ + return ((csrr(mie) | csrr(mip)) >> CSR_IRQ_EXTERNAL_OFFSET) & 0x1; +} + +#ifdef __cplusplus +} +#endif + +#endif /* __IRQ_H */ diff --git a/litex/soc/cores/cpu/cva5/system.h b/litex/soc/cores/cpu/cva5/system.h new file mode 100644 index 000000000..0fc6422da --- /dev/null +++ b/litex/soc/cores/cpu/cva5/system.h @@ -0,0 +1,66 @@ +#ifndef __SYSTEM_H +#define __SYSTEM_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CSR_ACCESSORS_DEFINED + +#ifdef __ASSEMBLER__ +#define MMPTR(x) x +#else /* ! __ASSEMBLER__ */ +#define MMPTR(a) (*((volatile uint32_t *)(a))) + +//As CVA5 will attempt to re-order loads before stores, a fence after I/O writes is required to ensure +//that subsequent loads (to different addresses) are not completed before this store +static inline void csr_write_simple(unsigned long v, unsigned long a) +{ + MMPTR(a) = v; + asm volatile ("fence;"); +} + +static inline unsigned long csr_read_simple(unsigned long a) +{ + return MMPTR(a); +} +#endif /* ! __ASSEMBLER__ */ + +__attribute__((unused)) static void flush_cpu_icache(void) { }; +__attribute__((unused)) static void flush_cpu_dcache(void) { }; + +void flush_l2_cache(void); + +void busy_wait(unsigned int ms); +void busy_wait_us(unsigned int us); + +#define csrr(reg) ({ unsigned long __tmp; \ + asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define csrw(reg, val) ({ \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrw " #reg ", %0" :: "i"(val)); \ + else \ + asm volatile ("csrw " #reg ", %0" :: "r"(val)); }) + +#define csrs(reg, bit) ({ \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrs x0, " #reg ", %0" :: "i"(bit)); \ + else \ + asm volatile ("csrrs x0, " #reg ", %0" :: "r"(bit)); }) + +#define csrc(reg, bit) ({ \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrc x0, " #reg ", %0" :: "i"(bit)); \ + else \ + asm volatile ("csrrc x0, " #reg ", %0" :: "r"(bit)); }) + +#ifdef __cplusplus +} +#endif + +#endif /* __SYSTEM_H */ diff --git a/litex_setup.py b/litex_setup.py index 34d7d1288..000ba5d6a 100755 --- a/litex_setup.py +++ b/litex_setup.py @@ -106,6 +106,7 @@ git_repos = { "pythondata-cpu-blackparrot": GitRepo(url="https://github.com/litex-hub/"), "pythondata-cpu-cv32e40p": GitRepo(url="https://github.com/litex-hub/", clone="recursive"), "pythondata-cpu-cv32e41p": GitRepo(url="https://github.com/litex-hub/", clone="recursive"), + "pythondata-cpu-cva5": GitRepo(url="https://github.com/litex-hub/"), "pythondata-cpu-ibex": GitRepo(url="https://github.com/litex-hub/", clone="recursive", sha1=0xd3d53df), "pythondata-cpu-marocchino": GitRepo(url="https://github.com/litex-hub/"), }