From 48b523cf7e12600e188edf647022ba8c7fcc005e Mon Sep 17 00:00:00 2001 From: Massimiliano Giacometti Date: Mon, 9 May 2022 21:12:08 +0200 Subject: [PATCH 1/2] add cva6 cpu --- litex/soc/cores/cpu/cva6/__init__.py | 1 + litex/soc/cores/cpu/cva6/boot-helper.S | 18 +++ litex/soc/cores/cpu/cva6/core.py | 195 +++++++++++++++++++++++++ litex/soc/cores/cpu/cva6/crt0.S | 125 ++++++++++++++++ litex/soc/cores/cpu/cva6/csr-defs.h | 8 + litex/soc/cores/cpu/cva6/irq.h | 41 ++++++ litex/soc/cores/cpu/cva6/system.h | 43 ++++++ litex_setup.py | 1 + 8 files changed, 432 insertions(+) create mode 100644 litex/soc/cores/cpu/cva6/__init__.py create mode 100644 litex/soc/cores/cpu/cva6/boot-helper.S create mode 100644 litex/soc/cores/cpu/cva6/core.py create mode 100644 litex/soc/cores/cpu/cva6/crt0.S create mode 100644 litex/soc/cores/cpu/cva6/csr-defs.h create mode 100644 litex/soc/cores/cpu/cva6/irq.h create mode 100644 litex/soc/cores/cpu/cva6/system.h diff --git a/litex/soc/cores/cpu/cva6/__init__.py b/litex/soc/cores/cpu/cva6/__init__.py new file mode 100644 index 000000000..474a14aa9 --- /dev/null +++ b/litex/soc/cores/cpu/cva6/__init__.py @@ -0,0 +1 @@ +from litex.soc.cores.cpu.cva6.core import CVA6 diff --git a/litex/soc/cores/cpu/cva6/boot-helper.S b/litex/soc/cores/cpu/cva6/boot-helper.S new file mode 100644 index 000000000..657806060 --- /dev/null +++ b/litex/soc/cores/cpu/cva6/boot-helper.S @@ -0,0 +1,18 @@ +.section .text, "ax", @progbits +.global boot_helper +.global smp_ap_args +.global smp_ap_target +.global smp_ap_ready + +boot_helper: + // boot core saves args and jump target for ap cores: + sd a0, smp_ap_args, t1 + sd a1, smp_ap_args+8, t1 + sd a2, smp_ap_args+16, t1 + sd a3, smp_ap_target, t1 + fence w, w + // notify application cores to proceed with boot: + li t0, 1 + sd t0, smp_ap_ready, t1 + // boot core now also ready to boot: + jr a3 diff --git a/litex/soc/cores/cpu/cva6/core.py b/litex/soc/cores/cpu/cva6/core.py new file mode 100644 index 000000000..bef9404b3 --- /dev/null +++ b/litex/soc/cores/cpu/cva6/core.py @@ -0,0 +1,195 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2021 Hensoldt Cyber GmbH +# SPDX-License-Identifier: BSD-2-Clause + +import os +import re + +from migen import * +from migen.fhdl.specials import Tristate + +from litex import get_data_mod +from litex.soc.interconnect import axi +from litex.soc.interconnect import wishbone, stream +from litex.soc.interconnect.csr import * +from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV64 + +class Open(Signal): pass + +# Variants ----------------------------------------------------------------------------------------- + +CPU_VARIANTS = ["standard", "full"] + +# GCC Flags ---------------------------------------------------------------------------------------- + +GCC_FLAGS = { + # /-------- Base ISA + # |/------- Hardware Multiply + Divide + # ||/----- Atomics + # |||/---- Compressed ISA + # ||||/--- Single-Precision Floating-Point + # |||||/-- Double-Precision Floating-Point + # imacfd + "standard": "-march=rv64imac -mabi=lp64 ", + "full": "-march=rv64gc -mabi=lp64 ", +} + +# Helpers ------------------------------------------------------------------------------------------ + +def add_manifest_sources(platform, manifest): + # TODO: create a pythondata-cpu-cva6 package to be installed with litex, then use this generic comment + basedir = get_data_mod("cpu", "cva6").data_location + with open(os.path.join(basedir, manifest), 'r') as f: + for l in f: + res = re.search('\$\{CVA6_REPO_DIR\}/(.+)', l) + if res and not re.match('//', l): + if re.match('\+incdir\+', l): + platform.add_verilog_include_path(os.path.join(basedir, res.group(1))) + else: + platform.add_source(os.path.join(basedir, res.group(1))) + +# CVA6 ----------------------------------------------------------------------------------------- + +class CVA6(CPU): + family = "riscv" + name = "cva6" + human_name = "CVA6" + variants = CPU_VARIANTS + data_width = 64 + endianness = "little" + gcc_triple = CPU_GCC_TRIPLE_RISCV64 + linker_output_format = "elf64-littleriscv" + nop = "nop" + io_regions = {0x80000000: 0x80000000} # Origin, Length. + + has_fpu = ["full"] + + # GCC Flags. + @property + def gcc_flags(self): + flags = GCC_FLAGS[self.variant] + flags += "-D__cva6__ " + return flags + + # Memory Mapping. + @property + def mem_map(self): + return { + "rom" : 0x10000000, + "sram" : 0x20000000, + "csr" : 0x80000000 + } + + jtag_layout = [ + ("tck", 1), + ("tms", 1), + ("trst", 1), + ("tdi", 1), + ("tdo", 1), + ] + + def __init__(self, platform, variant="standard"): + self.platform = platform + self.variant = variant + + data_width = 64 + self.axi_if = axi_if = axi.AXIInterface(data_width=data_width, address_width=data_width, id_width=4) + + wb_if = wishbone.Interface(data_width=data_width, adr_width=data_width-log2_int(data_width//8)) + a2w = axi.AXI2Wishbone(axi_if, wb_if, base_address=0x00000000) + self.submodules += a2w + + self.memory_buses = [] + self.periph_buses = [wb_if] + + self.interrupt = Signal(32) + self.reset = Signal() + + tdo_i = Signal() + tdo_o = Signal() + tdo_oe = Signal() + + pads = Record(self.jtag_layout) + self.pads = pads + self.specials += Tristate(pads.tdo, tdo_o, tdo_oe, tdo_i) + + self.cpu_params = dict( + # Clk / Rst. + i_clk_i = ClockSignal("sys"), + i_rst_n = ~ResetSignal("sys"), + + # Interrupts + i_irq_sources = self.interrupt, + + # AXI interface + o_AWID_o = axi_if.aw.id, + o_AWADDR_o = axi_if.aw.addr, + o_AWLEN_o = axi_if.aw.len, + o_AWSIZE_o = axi_if.aw.size, + o_AWBURST_o = axi_if.aw.burst, + o_AWLOCK_o = axi_if.aw.lock, + o_AWCACHE_o = axi_if.aw.cache, + o_AWPROT_o = axi_if.aw.prot, + o_AWQOS_o = axi_if.aw.qos, + o_AWREGION_o = Open(), + o_AWUSER_o = Open(), + o_AWVALID_o = axi_if.aw.valid, + o_WDATA_o = axi_if.w.data, + o_WSTRB_o = axi_if.w.strb, + o_WLAST_o = axi_if.w.last, + o_WUSER_o = Open(), + o_WVALID_o = axi_if.w.valid, + o_BREADY_o = axi_if.b.ready, + o_ARID_o = axi_if.ar.id, + o_ARADDR_o = axi_if.ar.addr, + o_ARLEN_o = axi_if.ar.len, + o_ARSIZE_o = axi_if.ar.size, + o_ARBURST_o = axi_if.ar.burst, + o_ARLOCK_o = axi_if.ar.lock, + o_ARCACHE_o = axi_if.ar.cache, + o_ARPROT_o = axi_if.ar.prot, + o_ARQOS_o = axi_if.ar.qos, + o_ARUSER_o = Open(), + o_ARREGION_o = Open(), + o_ARVALID_o = axi_if.ar.valid, + o_RREADY_o = axi_if.r.ready, + + i_AWREADY_i = axi_if.aw.ready, + i_ARREADY_i = axi_if.ar.ready, + i_WREADY_i = axi_if.w.ready, + i_BVALID_i = axi_if.b.valid, + i_BID_i = axi_if.b.id, + i_BRESP_i = axi_if.b.resp, + i_BUSER_i = 0, + i_RVALID_i = axi_if.r.valid, + i_RID_i = axi_if.r.id, + i_RDATA_i = axi_if.r.data, + i_RRESP_i = axi_if.r.resp, + i_RLAST_i = axi_if.r.last, + i_RUSER_i = 0, + + # JTAG. + i_trst_n = pads.trst, + i_tck = pads.tck, + i_tms = pads.tms, + i_tdi = pads.tdi, + o_tdo = tdo_o, + o_tdo_oe = tdo_oe, + + # TODO: add trace interface + ) + + # Add Verilog sources. + # TODO: use Flist.cv64a6_imafdc_sv39 and Flist.cv32a6_imac_sv0 instead + add_manifest_sources(platform, 'Flist.cv64a6_imafdc_sv39') + add_manifest_sources(platform, 'Flist.cva6_wrapper') + + def set_reset_address(self, reset_address): + self.reset_address = reset_address + assert reset_address == 0x10000000, "cpu_reset_addr hardcoded in during elaboration!" + + def do_finalize(self): + assert hasattr(self, "reset_address") + self.specials += Instance("cva6_wrapper", **self.cpu_params) diff --git a/litex/soc/cores/cpu/cva6/crt0.S b/litex/soc/cores/cpu/cva6/crt0.S new file mode 100644 index 000000000..677e14f8b --- /dev/null +++ b/litex/soc/cores/cpu/cva6/crt0.S @@ -0,0 +1,125 @@ +.global main +.global isr +.global _start + +.global smp_ap_args +.global smp_ap_target +.global smp_ap_ready + +_start: + j crt_init + nop + nop + nop + nop + nop + nop + nop + +trap_entry: + sd x1, - 1*8(sp) + sd x5, - 2*8(sp) + sd x6, - 3*8(sp) + sd x7, - 4*8(sp) + sd x10, - 5*8(sp) + sd x11, - 6*8(sp) + sd x12, - 7*8(sp) + sd x13, - 8*8(sp) + sd x14, - 9*8(sp) + sd x15, -10*8(sp) + sd x16, -11*8(sp) + sd x17, -12*8(sp) + sd x28, -13*8(sp) + sd x29, -14*8(sp) + sd x30, -15*8(sp) + sd x31, -16*8(sp) + addi sp,sp,-16*8 + call isr + ld x1 , 15*8(sp) + ld x5, 14*8(sp) + ld x6, 13*8(sp) + ld x7, 12*8(sp) + ld x10, 11*8(sp) + ld x11, 10*8(sp) + ld x12, 9*8(sp) + ld x13, 8*8(sp) + ld x14, 7*8(sp) + ld x15, 6*8(sp) + ld x16, 5*8(sp) + ld x17, 4*8(sp) + ld x28, 3*8(sp) + ld x29, 2*8(sp) + ld x30, 1*8(sp) + ld x31, 0*8(sp) + addi sp,sp,16*8 + mret + .text + + +crt_init: + la sp, _fstack + sd zero, smp_ap_ready, t0 + la t0, trap_entry + csrw mtvec, t0 + +smp_select_bp: + csrr a0, mhartid + beqz a0, data_init // hart 0 is bp, everyone else is ap + +smp_ap_loop: + ld t0, smp_ap_ready + beqz t0, smp_ap_loop +smp_ap_boot: + fence r, r + fence.i // i$ flush + ld a0, smp_ap_args // hart ID (but next-stage loads its own) + ld a1, smp_ap_args+8 // DTB pointer (if provded by litex bios) + ld a2, smp_ap_args+16 + ld a3, smp_ap_target + jr a3 +smp_ap_done: + +data_init: + la t0, _fdata + la t1, _edata + la t2, _fdata_rom +data_loop: + beq t0,t1,data_done + ld t3,0(t2) + sd t3,0(t0) + add t0,t0,8 + add t2,t2,8 + j data_loop +data_done: + +bss_init: + la t0, _fbss + la t1, _ebss +bss_loop: + beq t0,t1,bss_done + sd zero,0(t0) + add t0,t0,8 + j bss_loop +bss_done: + + // call plic_init // initialize external interrupt controller + li t0, 0x800 // external interrupt sources only (using LiteX timer); + // NOTE: must still enable mstatus.MIE! + csrw mie,t0 + + call main +inf_loop: + j inf_loop + +.bss + .align 8 +smp_ap_args: + .dword 0 + .dword 0 + .dword 0 + .align 8 +smp_ap_target: + .dword 0 + .align 8 +smp_ap_ready: + .dword 0 diff --git a/litex/soc/cores/cpu/cva6/csr-defs.h b/litex/soc/cores/cpu/cva6/csr-defs.h new file mode 100644 index 000000000..170bd4540 --- /dev/null +++ b/litex/soc/cores/cpu/cva6/csr-defs.h @@ -0,0 +1,8 @@ +#ifndef CSR_DEFS__H +#define CSR_DEFS__H + +#define CSR_MSTATUS_MIE 0x8 + +#define CSR_DCACHE_INFO 0xCC0 + +#endif /* CSR_DEFS__H */ diff --git a/litex/soc/cores/cpu/cva6/irq.h b/litex/soc/cores/cpu/cva6/irq.h new file mode 100644 index 000000000..3d5c4bf9d --- /dev/null +++ b/litex/soc/cores/cpu/cva6/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 0; +} + +static inline void irq_setie(unsigned int ie) +{ + +} + +static inline unsigned int irq_getmask(void) +{ + return 0; +} + +static inline void irq_setmask(unsigned int mask) +{ + +} + +static inline unsigned int irq_pending(void) +{ + return 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* __IRQ_H */ diff --git a/litex/soc/cores/cpu/cva6/system.h b/litex/soc/cores/cpu/cva6/system.h new file mode 100644 index 000000000..5ed09d2a5 --- /dev/null +++ b/litex/soc/cores/cpu/cva6/system.h @@ -0,0 +1,43 @@ +#ifndef __SYSTEM_H +#define __SYSTEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((unused)) static void flush_cpu_icache(void){} /* FIXME: do something useful here! */ +__attribute__((unused)) static void flush_cpu_dcache(void){}; /* FIXME: do something useful here! */ +void flush_l2_cache(void); + +void busy_wait(unsigned int ms); +void busy_wait_us(unsigned int us); + +#include + +#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..9bdd665d8 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-cva6": GitRepo(url="https://github.com/suppamax/", clone="recursive"), "pythondata-cpu-ibex": GitRepo(url="https://github.com/litex-hub/", clone="recursive", sha1=0xd3d53df), "pythondata-cpu-marocchino": GitRepo(url="https://github.com/litex-hub/"), } From c95ddbbff8c68450a653d1a50615e79b6d4769d1 Mon Sep 17 00:00:00 2001 From: Massimiliano Giacometti Date: Thu, 19 May 2022 15:07:46 +0200 Subject: [PATCH 2/2] UART_POLLING --- litex/soc/cores/cpu/cva6/core.py | 1 + test/test_cpu.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/litex/soc/cores/cpu/cva6/core.py b/litex/soc/cores/cpu/cva6/core.py index bef9404b3..fe0691dbb 100644 --- a/litex/soc/cores/cpu/cva6/core.py +++ b/litex/soc/cores/cpu/cva6/core.py @@ -71,6 +71,7 @@ class CVA6(CPU): def gcc_flags(self): flags = GCC_FLAGS[self.variant] flags += "-D__cva6__ " + flags += f" -DUART_POLLING" return flags # Memory Mapping. diff --git a/test/test_cpu.py b/test/test_cpu.py index 02047107b..63e2feac2 100644 --- a/test/test_cpu.py +++ b/test/test_cpu.py @@ -56,6 +56,9 @@ class TestCPU(unittest.TestCase): def test_picorv32(self): self.assertTrue(self.boot_test("picorv32")) + def test_cva6(self): + self.assertTrue(self.boot_test("cva6")) + # OpenRISC CPUs. #def test_mor1kx(self): # self.assertTrue(self.boot_test("mor1kx"))