commit
b033d91738
|
@ -0,0 +1 @@
|
|||
from litex.soc.cores.cpu.cva6.core import CVA6
|
|
@ -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
|
|
@ -0,0 +1,196 @@
|
|||
#
|
||||
# This file is part of LiteX.
|
||||
#
|
||||
# Copyright (c) 2021 Hensoldt Cyber GmbH <www.hensoldt-cyber.com>
|
||||
# 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__ "
|
||||
flags += f" -DUART_POLLING"
|
||||
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)
|
|
@ -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
|
|
@ -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 */
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef __IRQ_H
|
||||
#define __IRQ_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <system.h>
|
||||
#include <generated/csr.h>
|
||||
#include <generated/soc.h>
|
||||
|
||||
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 */
|
|
@ -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 <csr-defs.h>
|
||||
|
||||
#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 */
|
|
@ -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/"),
|
||||
}
|
||||
|
|
|
@ -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"))
|
||||
|
|
Loading…
Reference in New Issue