mirror of
https://github.com/Dasharo/litex.git
synced 2026-03-06 14:58:06 -08:00
Merge branch 'master' into cva5
This commit is contained in:
@@ -25,16 +25,16 @@ altera_reserved_jtag_pads = [
|
||||
|
||||
class AlteraAsyncResetSynchronizerImpl(Module):
|
||||
def __init__(self, cd, async_reset):
|
||||
rst_meta = Signal()
|
||||
rst_meta = Signal(name_override=f'ars_cd_{cd.name}_rst_meta')
|
||||
self.specials += [
|
||||
Instance("DFF",
|
||||
Instance("DFF", name=f'ars_cd_{cd.name}_ff0',
|
||||
i_d = 0,
|
||||
i_clk = cd.clk,
|
||||
i_clrn = 1,
|
||||
i_prn = ~async_reset,
|
||||
o_q = rst_meta
|
||||
),
|
||||
Instance("DFF",
|
||||
Instance("DFF", name=f'ars_cd_{cd.name}_ff1',
|
||||
i_d = rst_meta,
|
||||
i_clk = cd.clk,
|
||||
i_clrn = 1,
|
||||
|
||||
@@ -156,6 +156,7 @@ def _build_script(build_name, create_rbf):
|
||||
script_contents = "# Autogenerated by LiteX / git: " + tools.get_litex_git_revision()
|
||||
script_file = "build_" + build_name + ".sh"
|
||||
script_contents += """
|
||||
set -e -u -x -o pipefail
|
||||
quartus_map --read_settings_files=on --write_settings_files=off {build_name} -c {build_name}
|
||||
quartus_fit --read_settings_files=off --write_settings_files=off {build_name} -c {build_name}
|
||||
quartus_asm --read_settings_files=off --write_settings_files=off {build_name} -c {build_name}
|
||||
|
||||
@@ -230,7 +230,18 @@ class ConstraintManager:
|
||||
except ConstraintError:
|
||||
break
|
||||
if not len(r):
|
||||
raise ValueError
|
||||
raise ValueError(f"Could not request some pin(s) named '{name}'")
|
||||
return Cat(r)
|
||||
|
||||
def request_remaining(self, name):
|
||||
r = []
|
||||
while True:
|
||||
try:
|
||||
r.append(self.request(name))
|
||||
except ConstraintError:
|
||||
break
|
||||
if not len(r):
|
||||
raise ValueError(f"Could not request any pins named '{name}'")
|
||||
return Cat(r)
|
||||
|
||||
def lookup_request(self, name, number=None, loose=False):
|
||||
@@ -321,6 +332,9 @@ class GenericPlatform:
|
||||
def request_all(self, *args, **kwargs):
|
||||
return self.constraint_manager.request_all(*args, **kwargs)
|
||||
|
||||
def request_remaining(self, *args, **kwargs):
|
||||
return self.constraint_manager.request_remaining(*args, **kwargs)
|
||||
|
||||
def lookup_request(self, *args, **kwargs):
|
||||
return self.constraint_manager.lookup_request(*args, **kwargs)
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
from litex.build.openfpga.platform import OpenFPGAPlatform
|
||||
@@ -1,44 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
#
|
||||
# This file is part of LiteX.
|
||||
#
|
||||
# Copyright (c) 2022 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
import os
|
||||
|
||||
from migen import *
|
||||
|
||||
from litex.build.generic_platform import Pins
|
||||
from litex.build.openfpga import OpenFPGAPlatform
|
||||
|
||||
# export LITEX_ENV_OPENFPGA=/home/florent/dev/openfpga/OpenFPGA
|
||||
# export LITEX_ENV_OPENFPGA_SOFA=/home/florent/dev/openfpga/SOFA
|
||||
|
||||
# Minimal Platform ---------------------------------------------------------------------------------
|
||||
|
||||
_io = [
|
||||
("clk", 0, Pins(1)),
|
||||
("led", 0, Pins(1))
|
||||
]
|
||||
|
||||
class Platform(OpenFPGAPlatform):
|
||||
def __init__(self):
|
||||
OpenFPGAPlatform.__init__(self, "FPGA1212_QLSOFA_HD", _io)
|
||||
|
||||
# Minimal Design -----------------------------------------------------------------------------------
|
||||
|
||||
platform = Platform()
|
||||
clk = platform.request("clk")
|
||||
led = platform.request("led")
|
||||
module = Module()
|
||||
module.clock_domains.cd_sys = ClockDomain("sys")
|
||||
module.comb += module.cd_sys.clk.eq(clk)
|
||||
counter = Signal(26)
|
||||
module.comb += led.eq(counter[25])
|
||||
module.sync += counter.eq(counter + 1)
|
||||
|
||||
# Build --------------------------------------------------------------------------------------------
|
||||
|
||||
platform.build(module, run=True)
|
||||
@@ -1,9 +0,0 @@
|
||||
#
|
||||
# This file is part of LiteX.
|
||||
#
|
||||
# Copyright (c) 2022 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
# OpenFPGA Special Overrides ---------------------------------------------------------------------
|
||||
|
||||
openfpga_special_overrides = {}
|
||||
@@ -1,152 +0,0 @@
|
||||
#
|
||||
# This file is part of LiteX.
|
||||
#
|
||||
# Copyright (c) 2022 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
from shutil import which
|
||||
|
||||
from migen.fhdl.structure import _Fragment
|
||||
|
||||
from litex.build.generic_platform import *
|
||||
from litex.build import tools
|
||||
from litex.build.openfpga import common
|
||||
|
||||
# Check Setup --------------------------------------------------------------------------------------
|
||||
|
||||
def _check_setup():
|
||||
if os.getenv("LITEX_ENV_OPENFPGA", False) == False:
|
||||
msg = "Unable to find OpenFPGA toolchain, please:\n"
|
||||
msg += "- Set LITEX_ENV_OPENFPGA environment variant to OpenFPGA's settings path.\n"
|
||||
raise OSError(msg)
|
||||
|
||||
if os.getenv("LITEX_ENV_OPENFPGA_SOFA", False) == False:
|
||||
msg = "Unable to find OpenFPGA's SOFA project, please:\n"
|
||||
msg += "- Set LITEX_ENV_OPENFPGA_SOFA environment variant to OpenFPGA's SOFA settings path.\n"
|
||||
raise OSError(msg)
|
||||
|
||||
# Task Config -------------------------------------------------------------------------------------
|
||||
|
||||
def _build_task_conf(platform, sources, build_dir, build_name):
|
||||
# Get Environnment variables.
|
||||
openfpga_path = os.getenv("LITEX_ENV_OPENFPGA")
|
||||
openfpga_sofa_path = os.getenv("LITEX_ENV_OPENFPGA_SOFA")
|
||||
|
||||
# Get PnR/Task directories from OPENFPGA/SOFA paths.
|
||||
pnr_path = os.path.join(openfpga_sofa_path, platform.device + "_PNR")
|
||||
task_path = os.path.join(pnr_path, platform.device + "_task")
|
||||
|
||||
# Get Config file.
|
||||
task_conf = os.path.join(task_path, "config", "task_simulation.conf")
|
||||
|
||||
# Helpers.
|
||||
def replace_openfpga_task_section(filename, section, contents):
|
||||
lines = []
|
||||
# Read file and replace section with contents.
|
||||
copy = True
|
||||
for line in open(filename, "r"):
|
||||
if not copy and line.startswith("["):
|
||||
copy = True
|
||||
if line.startswith(section):
|
||||
copy = False
|
||||
lines.append(section + "\n")
|
||||
for l in contents:
|
||||
lines.append(l + "\n")
|
||||
lines.append("\n")
|
||||
if copy:
|
||||
lines.append(line)
|
||||
|
||||
# Save file to .orig.
|
||||
os.system(f"mv {filename} {filename}.orig")
|
||||
|
||||
# Write file with replaced section.
|
||||
with open(filename, "w") as f:
|
||||
f.write("".join(lines))
|
||||
|
||||
# Add sources.
|
||||
bench_sources = []
|
||||
for filename, language, library in sources:
|
||||
if language is None:
|
||||
continue
|
||||
if language not in ["verilog"]:
|
||||
raise ValueError("OpenFPGA flow only supports verilog")
|
||||
bench_sources.append(filename)
|
||||
replace_openfpga_task_section(task_conf, "[BENCHMARKS]", [f"bench0={' '.join(bench_sources)}"])
|
||||
|
||||
# Set Top-Level.
|
||||
replace_openfpga_task_section(task_conf, "[SYNTHESIS_PARAM]", [f"bench0_top={build_name}"])
|
||||
|
||||
def _run_task(device):
|
||||
# Get Environnment variables.
|
||||
openfpga_path = os.getenv("LITEX_ENV_OPENFPGA")
|
||||
openfpga_sofa_path = os.getenv("LITEX_ENV_OPENFPGA_SOFA")
|
||||
|
||||
# Get PnR/Task directories from OPENFPGA/SOFA paths.
|
||||
pnr_path = os.path.join(openfpga_sofa_path, device + "_PNR")
|
||||
task_path = os.path.join(pnr_path, device + "_task")
|
||||
|
||||
# Set OPENFPGA_PATH.
|
||||
os.environ["OPENFPGA_PATH"] = os.getenv("LITEX_ENV_OPENFPGA")
|
||||
|
||||
# Run OpenFPGA flow.
|
||||
build_cmd = ["make", "-C", pnr_path, "clean", "runOpenFPGA"]
|
||||
if subprocess.call(build_cmd) != 0:
|
||||
raise OSError("Error occured during OpenFPGA's flow execution.")
|
||||
|
||||
# Copy artifacts.
|
||||
os.system("rm -rf run001")
|
||||
os.system(f"cp -r {task_path}/run001 run001")
|
||||
|
||||
# Display log. FIXME: Do it during build?
|
||||
os.system("cat run001/vpr_arch/top/MIN_ROUTE_CHAN_WIDTH/openfpgashell.log")
|
||||
|
||||
# OpenFPGAToolchain --------------------------------------------------------------------------------
|
||||
|
||||
class OpenFPGAToolchain:
|
||||
attr_translate = {}
|
||||
|
||||
special_overrides = common.openfpga_special_overrides
|
||||
|
||||
def __init__(self):
|
||||
self.clocks = dict()
|
||||
self.false_paths = set()
|
||||
|
||||
def build(self, platform, fragment,
|
||||
build_dir = "build",
|
||||
build_name = "top",
|
||||
run = False,
|
||||
**kwargs):
|
||||
|
||||
# Create Build Directory.
|
||||
os.makedirs(build_dir, exist_ok=True)
|
||||
cwd = os.getcwd()
|
||||
os.chdir(build_dir)
|
||||
|
||||
# Finalize Design.
|
||||
if not isinstance(fragment, _Fragment):
|
||||
fragment = fragment.get_fragment()
|
||||
platform.finalize(fragment)
|
||||
|
||||
# Generate Verilog.
|
||||
v_output = platform.get_verilog(fragment, name=build_name, **kwargs)
|
||||
named_sc, named_pc = platform.resolve_signals(v_output.ns)
|
||||
top_file = build_name + ".v"
|
||||
v_output.write(top_file)
|
||||
platform.add_source(top_file)
|
||||
|
||||
# Check Setup.
|
||||
_check_setup()
|
||||
|
||||
# Generate Task Config.
|
||||
_build_task_conf(platform, platform.sources, build_dir, build_name)
|
||||
|
||||
# Run Task.
|
||||
if run:
|
||||
_run_task(platform.device)
|
||||
|
||||
os.chdir(cwd)
|
||||
|
||||
return v_output.ns
|
||||
@@ -1,28 +0,0 @@
|
||||
#
|
||||
# This file is part of LiteX.
|
||||
#
|
||||
# Copyright (c) 2022 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
import os
|
||||
|
||||
from litex.build.generic_platform import GenericPlatform
|
||||
from litex.build.openfpga import common, openfpga
|
||||
|
||||
# OpenFPGAPlatform -------------------------------------------------------------------------------
|
||||
|
||||
class OpenFPGAPlatform(GenericPlatform):
|
||||
def __init__(self, device, *args, **kwargs):
|
||||
GenericPlatform.__init__(self, device, *args, **kwargs)
|
||||
self.toolchain = openfpga.OpenFPGAToolchain()
|
||||
|
||||
def get_verilog(self, *args, special_overrides=dict(), **kwargs):
|
||||
so = dict(common.openfpga_special_overrides)
|
||||
so.update(special_overrides)
|
||||
return GenericPlatform.get_verilog(self, *args,
|
||||
special_overrides = so,
|
||||
attr_translate = self.toolchain.attr_translate,
|
||||
**kwargs)
|
||||
|
||||
def build(self, *args, **kwargs):
|
||||
return self.toolchain.build(self, *args, **kwargs)
|
||||
@@ -26,18 +26,21 @@ def _build_sdc(clocks, vns, build_name):
|
||||
|
||||
# Script -------------------------------------------------------------------------------------------
|
||||
|
||||
def _build_tcl(name, device, files, build_name):
|
||||
def _build_tcl(name, device, files, build_name, include_paths):
|
||||
tcl = []
|
||||
|
||||
# Create Design.
|
||||
tcl.append(f"create_design {build_name}")
|
||||
|
||||
# Set Device.
|
||||
# TODO (Use Macro for now).
|
||||
tcl.append("set_macro P1=10 P2=20")
|
||||
# FIXME: Directly pass Devices instead of Macro when possible.
|
||||
macro = {"test": "P1=10 P2=20"}[device]
|
||||
tcl.append(f"set_macro {macro}")
|
||||
|
||||
# Add Include Path.
|
||||
# TODO.
|
||||
tcl.append("add_include_path ./")
|
||||
for include_path in include_paths:
|
||||
tcl.append(f"add_include_path {include_path}")
|
||||
|
||||
# Add Sources.
|
||||
for f, typ, lib in files:
|
||||
@@ -107,10 +110,11 @@ class OSFPGAToolchain:
|
||||
|
||||
# Generate build script (.tcl)
|
||||
script = _build_tcl(
|
||||
name = platform.devicename,
|
||||
device = platform.device,
|
||||
files = platform.sources,
|
||||
build_name = build_name,
|
||||
name = platform.devicename,
|
||||
device = platform.device,
|
||||
files = platform.sources,
|
||||
build_name = build_name,
|
||||
include_paths = platform.verilog_include_paths,
|
||||
)
|
||||
|
||||
# Run
|
||||
|
||||
@@ -22,7 +22,7 @@ _io = [
|
||||
|
||||
class Platform(OSFPGAPlatform):
|
||||
def __init__(self):
|
||||
OSFPGAPlatform.__init__(self, device=None, toolchain="raptor", io=_io) # FIXME: Add device support.
|
||||
OSFPGAPlatform.__init__(self, device="test", toolchain="raptor", io=_io)
|
||||
|
||||
# Minimal Design -----------------------------------------------------------------------------------
|
||||
|
||||
64
litex/build/osfpga/test_soc.py
Executable file
64
litex/build/osfpga/test_soc.py
Executable file
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
#
|
||||
# This file is part of LiteX.
|
||||
#
|
||||
# Copyright (c) 2022 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
from migen import *
|
||||
|
||||
from litex.build.io import CRG
|
||||
from litex.build.generic_platform import Pins, Subsignal
|
||||
from litex.build.osfpga import OSFPGAPlatform
|
||||
|
||||
from litex.soc.integration.soc_core import *
|
||||
from litex.soc.integration.builder import *
|
||||
|
||||
# Platform ---------------------------------------------------------------------------------
|
||||
|
||||
_io = [
|
||||
# Clk.
|
||||
("clk", 0, Pins(1)),
|
||||
|
||||
# Serial.
|
||||
("serial", 0,
|
||||
Subsignal("tx", Pins(1)),
|
||||
Subsignal("rx", Pins(1)),
|
||||
),
|
||||
]
|
||||
|
||||
class Platform(OSFPGAPlatform):
|
||||
def __init__(self, toolchain="foedag"):
|
||||
OSFPGAPlatform.__init__(self, device="test", toolchain=toolchain, io=_io)
|
||||
|
||||
# BaseSoC ------------------------------------------------------------------------------------------
|
||||
|
||||
class BaseSoC(SoCCore):
|
||||
def __init__(self, platform, sys_clk_freq=int(10e6), **kwargs):
|
||||
# CRG --------------------------------------------------------------------------------------
|
||||
self.submodules.crg = CRG(platform.request("clk"))
|
||||
|
||||
# SoCCore ----------------------------------------------------------------------------------
|
||||
SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX Test SoC on OS-FPGA", **kwargs)
|
||||
|
||||
# Build --------------------------------------------------------------------------------------------
|
||||
|
||||
def main():
|
||||
from litex.soc.integration.soc import LiteXSoCArgumentParser
|
||||
parser = LiteXSoCArgumentParser(description="LiteX Test SoC on OS-FPGA")
|
||||
target_group = parser.add_argument_group(title="Target options")
|
||||
target_group.add_argument("--build", action="store_true", help="Build design.")
|
||||
target_group.add_argument("--toolchain", default="foedag", help="FPGA toolchain.")
|
||||
builder_args(parser)
|
||||
soc_core_args(parser)
|
||||
args = parser.parse_args()
|
||||
|
||||
platform = Platform(toolchain=args.toolchain)
|
||||
soc = BaseSoC(platform,**soc_core_argdict(args))
|
||||
builder = Builder(soc, **builder_argdict(args))
|
||||
if args.build:
|
||||
builder.build()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -70,8 +70,8 @@ class IntelClocking(Module, AutoCSR):
|
||||
break
|
||||
if valid:
|
||||
break
|
||||
if not valid:
|
||||
all_valid = False
|
||||
if not valid:
|
||||
all_valid = False
|
||||
else:
|
||||
all_valid = False
|
||||
if all_valid:
|
||||
|
||||
@@ -42,13 +42,13 @@ class CPUNone(CPU):
|
||||
data_width = 32
|
||||
endianness = "little"
|
||||
reset_address = 0x00000000
|
||||
io_regions = {0x00000000: 0x100000000} # origin, length
|
||||
io_regions = {0x0000_0000: 0x1_0000_0000} # origin, length
|
||||
periph_buses = []
|
||||
memory_buses = []
|
||||
mem_map = {
|
||||
"csr" : 0x00000000,
|
||||
"ethmac" : 0x00020000, # FIXME: Remove.
|
||||
"spiflash" : 0x10000000, # FIXME: Remove.
|
||||
"csr" : 0x0000_0000,
|
||||
"ethmac" : 0x0002_0000, # FIXME: Remove.
|
||||
"spiflash" : 0x1000_0000, # FIXME: Remove.
|
||||
}
|
||||
|
||||
CPU_GCC_TRIPLE_RISCV64 = (
|
||||
|
||||
@@ -65,17 +65,17 @@ class BlackParrot(CPU):
|
||||
gcc_triple = CPU_GCC_TRIPLE_RISCV64
|
||||
linker_output_format = "elf64-littleriscv"
|
||||
nop = "nop"
|
||||
io_regions = {0x50000000: 0x10000000} # Origin, Length.
|
||||
io_regions = {0x5000_0000: 0x1000_0000} # Origin, Length.
|
||||
|
||||
# Memory Mapping.
|
||||
@property
|
||||
def mem_map(self):
|
||||
# Keep the lower 128MBs for SoC IOs auto-allocation.
|
||||
return {
|
||||
"csr" : 0x58000000,
|
||||
"rom" : 0x70000000,
|
||||
"sram" : 0x71000000,
|
||||
"main_ram" : 0x80000000,
|
||||
"csr" : 0x5800_0000,
|
||||
"rom" : 0x7000_0000,
|
||||
"sram" : 0x7100_0000,
|
||||
"main_ram" : 0x8000_0000,
|
||||
}
|
||||
|
||||
# GCC Flags.
|
||||
@@ -142,7 +142,7 @@ class BlackParrot(CPU):
|
||||
|
||||
def set_reset_address(self, reset_address):
|
||||
self.reset_address = reset_address
|
||||
assert reset_address == 0x70000000, "cpu_reset_addr hardcoded to 7x00000000!"
|
||||
assert reset_address == 0x7000_0000, "cpu_reset_addr hardcoded to 7x00000000!"
|
||||
|
||||
@staticmethod
|
||||
def add_sources(platform, variant="standard"):
|
||||
|
||||
@@ -252,7 +252,7 @@ class CV32E41P(CPU):
|
||||
gcc_triple = CPU_GCC_TRIPLE_RISCV32
|
||||
linker_output_format = "elf32-littleriscv"
|
||||
nop = "nop"
|
||||
io_regions = {0x80000000: 0x80000000} # Origin, Length.
|
||||
io_regions = {0x8000_0000: 0x8000_0000} # Origin, Length.
|
||||
|
||||
# GCC Flags.
|
||||
@property
|
||||
|
||||
1
litex/soc/cores/cpu/cva6/__init__.py
Normal file
1
litex/soc/cores/cpu/cva6/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from litex.soc.cores.cpu.cva6.core import CVA6
|
||||
18
litex/soc/cores/cpu/cva6/boot-helper.S
Normal file
18
litex/soc/cores/cpu/cva6/boot-helper.S
Normal file
@@ -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
|
||||
186
litex/soc/cores/cpu/cva6/core.py
Normal file
186
litex/soc/cores/cpu/cva6/core.py
Normal file
@@ -0,0 +1,186 @@
|
||||
#
|
||||
# This file is part of LiteX.
|
||||
#
|
||||
# Copyright (c) 2021 Hensoldt Cyber GmbH <www.hensoldt-cyber.com>
|
||||
# Copyright (c) 2022 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
from migen import *
|
||||
|
||||
from litex import get_data_mod
|
||||
from litex.soc.interconnect import axi
|
||||
from litex.soc.interconnect import wishbone
|
||||
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):
|
||||
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 = {0x8000_0000: 0x8000_0000} # Origin, Length.
|
||||
|
||||
# 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" : 0x1000_0000,
|
||||
"sram" : 0x2000_0000,
|
||||
"csr" : 0x8000_0000,
|
||||
}
|
||||
|
||||
def __init__(self, platform, variant="standard"):
|
||||
self.platform = platform
|
||||
self.variant = variant
|
||||
self.reset = Signal()
|
||||
self.interrupt = Signal(32)
|
||||
self.axi_lite_if = axi.AXILiteInterface(data_width=64, address_width=32)
|
||||
self.periph_buses = [self.axi_lite_if] # Peripheral buses (Connected to main SoC's bus).
|
||||
self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM).
|
||||
|
||||
# # #
|
||||
|
||||
# AXI <-> AXILite conversion.
|
||||
axi_if = axi.AXIInterface(data_width=64, address_width=32, id_width=4)
|
||||
self.submodules += axi.AXI2AXILite(axi_if, self.axi_lite_if)
|
||||
|
||||
# CPU Instance.
|
||||
self.cpu_params = dict(
|
||||
# Clk / Rst.
|
||||
i_clk_i = ClockSignal("sys"),
|
||||
i_rst_n = ~ResetSignal("sys") | self.reset,
|
||||
|
||||
# AXI interface.
|
||||
o_AWVALID_o = axi_if.aw.valid,
|
||||
i_AWREADY_i = axi_if.aw.ready,
|
||||
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_WVALID_o = axi_if.w.valid,
|
||||
i_WREADY_i = axi_if.w.ready,
|
||||
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(),
|
||||
|
||||
i_BVALID_i = axi_if.b.valid,
|
||||
o_BREADY_o = axi_if.b.ready,
|
||||
i_BID_i = axi_if.b.id,
|
||||
i_BRESP_i = axi_if.b.resp,
|
||||
i_BUSER_i = 0,
|
||||
|
||||
o_ARVALID_o = axi_if.ar.valid,
|
||||
i_ARREADY_i = axi_if.ar.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(),
|
||||
|
||||
i_RVALID_i = axi_if.r.valid,
|
||||
o_RREADY_o = axi_if.r.ready,
|
||||
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,
|
||||
)
|
||||
|
||||
# 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 add_jtag(pads):
|
||||
from migen.fhdl.specials import Tristate
|
||||
self.jtag_tck = Signal()
|
||||
self.jtag_tms = Signal()
|
||||
self.jtag_trst = Signal()
|
||||
self.jtag_tdi = Signal()
|
||||
self.jtag_tdo = Signal()
|
||||
|
||||
tdo_o = Signal()
|
||||
tdo_oe = Signal()
|
||||
self.specials += Tristate(self.jtag_tdo, tdo_o, tdo_oe)
|
||||
|
||||
self.cpu_params.update(
|
||||
i_trst_n = self.jtag_trst,
|
||||
i_tck = self.jtag_tck,
|
||||
i_tms = self.jtag_tms,
|
||||
i_tdi = self.jtag_tdi,
|
||||
o_tdo = tdo_o,
|
||||
o_tdo_oe = tdo_oe,
|
||||
)
|
||||
|
||||
def set_reset_address(self, reset_address):
|
||||
self.reset_address = reset_address
|
||||
assert reset_address == 0x1000_0000, "cpu_reset_addr hardcoded in during elaboration!"
|
||||
|
||||
def do_finalize(self):
|
||||
assert hasattr(self, "reset_address")
|
||||
self.specials += Instance("cva6_wrapper", **self.cpu_params)
|
||||
125
litex/soc/cores/cpu/cva6/crt0.S
Normal file
125
litex/soc/cores/cpu/cva6/crt0.S
Normal file
@@ -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
|
||||
8
litex/soc/cores/cpu/cva6/csr-defs.h
Normal file
8
litex/soc/cores/cpu/cva6/csr-defs.h
Normal file
@@ -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 */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user