diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c8a024c15..049c2aa5d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,8 +20,8 @@ if(TOOLCHAIN STREQUAL GCC) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) endif() -set(platform MemPool CACHE STRING "Platform (MemPool, SoftHier, QEMU, Siracusa, Siracusa_w_neureka, PULP-Open, GAP9, Generic, Snitch)") -set_property(CACHE platform PROPERTY STRINGS MemPool SoftHier QEMU Siracusa Siracusa_w_neureka PULP-Open GAP9 Generic Snitch) +set(platform MemPool CACHE STRING "Platform (MemPool, SoftHier, QEMU, Siracusa, Siracusa_w_neureka, PULP-Open, GAP9, Generic, Snitch, Spatz)") +set_property(CACHE platform PROPERTY STRINGS MemPool SoftHier QEMU Siracusa Siracusa_w_neureka PULP-Open GAP9 Generic Snitch Spatz) if(platform STREQUAL MemPool) message(STATUS "Building for platform 'MemPool'") @@ -46,6 +46,8 @@ elseif(platform STREQUAL SoftHier) message(STATUS "Building for platform 'SoftHier'") elseif(platform STREQUAL Chimera) message(STATUS "Building for platform 'Chimera'") +elseif(platform STREQUAL Spatz) + message(STATUS "Building for platform 'Spatz'") else() message(FATAL_ERROR "Invalid platform '${platform}' specified!") endif() @@ -300,4 +302,28 @@ if(platform STREQUAL Chimera) endif() + +if(platform STREQUAL Spatz) + # Only LLVM supported for Spatz + set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/spatz/toolchain_llvm.cmake) + + include(${CMAKE_CURRENT_LIST_DIR}/cmake/spatz/spatz.cmake OPTIONAL) + + project(deeploy LANGUAGES C ASM) + + message(STATUS "============================= ${platform} Configuration ============================") + message(STATUS "[cMake ] ISA = " ${ISA}) + message(STATUS "================================================================================") + message(STATUS "") + + add_subdirectory(TargetLibraries/Generic) + add_subdirectory(TargetLibraries/Spatz) + target_include_directories(deeployspatz PUBLIC TargetLibraries/Generic/inc) + + add_subdirectory(DeeployTest) + target_link_libraries(deeploylib INTERFACE deeploybasic deeployspatz) + +endif() + + print_simulation_config() diff --git a/Deeploy/Targets/Spatz/Bindings.py b/Deeploy/Targets/Spatz/Bindings.py new file mode 100644 index 0000000000..4f78c28f09 --- /dev/null +++ b/Deeploy/Targets/Spatz/Bindings.py @@ -0,0 +1,12 @@ +from Deeploy.DeeployTypes import NodeBinding + +from Deeploy.Targets.Generic.TypeCheckers import AddChecker +from Deeploy.Targets.Spatz.Templates import AddTemplate + + +SpatzAddBindings = [ + NodeBinding( + AddChecker(), + AddTemplate. + ) +] \ No newline at end of file diff --git a/Deeploy/Targets/Spatz/Deployer.py b/Deeploy/Targets/Spatz/Deployer.py new file mode 100644 index 0000000000..2442059606 --- /dev/null +++ b/Deeploy/Targets/Spatz/Deployer.py @@ -0,0 +1,48 @@ +# SPDX-FileCopyrightText: 2023 ETH Zurich and University of Bologna +# +# SPDX-License-Identifier: Apache-2.0 + +from typing import Callable, Dict, Type + +import onnx_graphsurgeon as gs + +from Deeploy.AbstractDataTypes import Pointer +from Deeploy.CommonExtensions.NetworkDeployers.SignPropDeployer import SignPropDeployer +from Deeploy.CommonExtensions.OptimizationPasses.TopologyOptimizationPasses.DebugPasses import DebugPrintMergePass +from Deeploy.CommonExtensions.OptimizationPasses.TopologyOptimizationPasses.LoweringOptimizationPasses import \ + NCHWtoNHWCPass, TransposeMatmulInputsPass +from Deeploy.DeeployTypes import DeploymentPlatform, TopologyOptimizer +from Deeploy.Targets.Generic.TopologyOptimizationPasses.Passes import TransposeConstOptPass, TransposeMergePass + + +class SpatzDeployer(SignPropDeployer): + + def __init__(self, + graph: gs.Graph, + deploymentPlatform: DeploymentPlatform, + inputTypes: Dict[str, Type[Pointer]], + loweringOptimizer: TopologyOptimizer, + scheduler: Callable = lambda x: x, + name: str = 'DeeployNetwork', + default_channels_first = False, + deeployStateDir: str = "DeeployStateDir", + inputOffsets: Dict[str, int] = {}): + + super().__init__(graph, + deploymentPlatform, + inputTypes, + loweringOptimizer, + scheduler, + name, + default_channels_first = default_channels_first, + deeployStateDir = deeployStateDir) + +# self.inputOffsets = inputOffsets +# +# self.loweringOptimizer.passes += [ +# TransposeMatmulInputsPass(), +# NCHWtoNHWCPass(self.default_channels_first), +# TransposeMergePass(), +# TransposeConstOptPass(), +# DebugPrintMergePass() +# ] diff --git a/Deeploy/Targets/Spatz/Platform.py b/Deeploy/Targets/Spatz/Platform.py new file mode 100644 index 0000000000..af09dc227c --- /dev/null +++ b/Deeploy/Targets/Spatz/Platform.py @@ -0,0 +1,71 @@ +from typing import List + +from Deeploy.DeeployTypes import VariableBuffer, TransientBuffer, ConstantBuffer, StructBuffer, \ + NodeMapper, NodeTemplate, TopologyOptimizer, DeploymentEngine, DeploymentPlatform + +# from Deeploy.Targets.Spatz.Bindings import SpatzAddBindings # <- TODO create this +from Deeploy.Targets.Generic.Bindings import BasicAddBindings +from Deeploy.Targets.Generic.Layers import AddLayer +from Deeploy.Targets.Generic.Parsers import AddParser + +from Deeploy.Targets.Generic.Templates import AllocateTemplate as GenericAllocateTemplate +from Deeploy.Targets.Spatz.Templates import AllocateTemplate as SpatzAllocateTemplate +from Deeploy.Targets.Spatz.Templates import FreeTemplate as SpatzFreeTemplate + +SpatzAddMapper = NodeMapper(AddParser(), BasicAddBindings) + +SpatzMapping = { + 'Add': AddLayer([SpatzAddMapper]), + # sparse attention : ... +} + + +class SpatzaVariableBuffer(VariableBuffer): + initTemplate = GenericAllocateTemplate.referenceInitTemplate + allocTemplate = SpatzAllocateTemplate.referenceAllocateTemplate + deallocTemplate = SpatzFreeTemplate.spatzLocalTemplate + + +class SpatzTransientBuffer(TransientBuffer): + initTemplate = GenericAllocateTemplate.referenceInitTemplate + allocTemplate = SpatzAllocateTemplate.referenceAllocateTemplate + deallocTemplate = SpatzFreeTemplate.spatzLocalTemplate + + +class SpatzConstantBuffer(ConstantBuffer): + initTemplate = GenericAllocateTemplate.referenceGlobalInitTemplate + allocTemplate = GenericAllocateTemplate.referenceAllocateTemplate + deallocTemplate = NodeTemplate("") # const not deallocated + + +class SpatzStructBuffer(StructBuffer): + initTemplate = GenericAllocateTemplate.referenceStructInitTemplate + allocTemplate = GenericAllocateTemplate.referenceAllocateTemplate + deallocTemplate = NodeTemplate("") # struct not deallocated ? + + +SpatzOptimizer = TopologyOptimizer([ + # TODO add something ? +], name = "SpatzOptimizer") + +includeList = [ + "DeeploySpatzMath.h", +] + + +class SpatzEngine(DeploymentEngine): + def __init__(self, name: str, Mapping = SpatzMapping, initCode = "", includeList = includeList) -> None: + super().__init__(name, Mapping, initCode, includeList) + + +class SpatzPlatform(DeploymentPlatform): + + def __init__( self, + engines = [SpatzEngine("SpatzVectorProcessor")], + variableBuffer = SpatzaVariableBuffer, + transientBuffer = SpatzTransientBuffer, + constantBuffer = SpatzConstantBuffer, + structBuffer = SpatzStructBuffer, + includeList: List[str] = includeList + ): + super().__init__(engines, variableBuffer, constantBuffer, structBuffer, transientBuffer) diff --git a/Deeploy/Targets/Spatz/Templates/AddTemplate.py b/Deeploy/Targets/Spatz/Templates/AddTemplate.py new file mode 100644 index 0000000000..a4572f625b --- /dev/null +++ b/Deeploy/Targets/Spatz/Templates/AddTemplate.py @@ -0,0 +1,5 @@ +from Deeploy.DeeployTypes import NodeTemplate + +... = NodeTemplate("\ + +") \ No newline at end of file diff --git a/Deeploy/Targets/Spatz/Templates/AllocateTemplate.py b/Deeploy/Targets/Spatz/Templates/AllocateTemplate.py new file mode 100644 index 0000000000..78d24b9f14 --- /dev/null +++ b/Deeploy/Targets/Spatz/Templates/AllocateTemplate.py @@ -0,0 +1,5 @@ +from Deeploy.DeeployTypes import NodeTemplate + +# allocate +referenceAllocateTemplate = NodeTemplate( + "${name} = (${type.typeName}) snrt_l1alloc(${type.referencedType.typeWidth//8} * ${size});\n") diff --git a/Deeploy/Targets/Spatz/Templates/FreeTemplate.py b/Deeploy/Targets/Spatz/Templates/FreeTemplate.py new file mode 100644 index 0000000000..f67cb3de38 --- /dev/null +++ b/Deeploy/Targets/Spatz/Templates/FreeTemplate.py @@ -0,0 +1,5 @@ +from Deeploy.DeeployTypes import NodeTemplate + +# snrt_l1alloc currently does not support free-ing of memory (spatz/sw/snRuntime/src/alloc.c) +spatzLocalTemplate = NodeTemplate("") +spatzGlobalTemplate = NodeTemplate("") \ No newline at end of file diff --git a/DeeployTest/CMakeLists.txt b/DeeployTest/CMakeLists.txt index b7f3535790..71f632cbd2 100644 --- a/DeeployTest/CMakeLists.txt +++ b/DeeployTest/CMakeLists.txt @@ -50,6 +50,8 @@ elseif(DEEPLOY_ARCH STREQUAL SNITCH) add_subdirectory(Platforms/Snitch) elseif(DEEPLOY_ARCH STREQUAL CHIMERA) add_subdirectory(Platforms/Chimera) +elseif(DEEPLOY_ARCH STREQUAL SPATZ) + add_subdirectory(Platforms/Spatz) elseif(platform STREQUAL GAP9) # Search for hex files generated by Python code generator diff --git a/DeeployTest/Platforms/Spatz/CMakeLists.txt b/DeeployTest/Platforms/Spatz/CMakeLists.txt new file mode 100644 index 0000000000..4804a63182 --- /dev/null +++ b/DeeployTest/Platforms/Spatz/CMakeLists.txt @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2024 ETH Zurich and University of Bologna +# +# SPDX-License-Identifier: Apache-2.0 + +set(ProjectId ${TESTNAME}) + +file(GLOB_RECURSE SOURCES + main.c +) + +add_deeploy_executable(${ProjectId} EXCLUDE_FROM_ALL ${SOURCES}) + +target_link_libraries(${ProjectId} PRIVATE network deeploylib) +target_compile_options(${ProjectId} INTERFACE network) + +# Add QuestaSim RTL simulation for Spatz (mirroring Snitch's vsim) +add_spatz_vsim_simulation(${ProjectId}) diff --git a/DeeployTest/Platforms/Spatz/main.c b/DeeployTest/Platforms/Spatz/main.c new file mode 100644 index 0000000000..2ab98ce54d --- /dev/null +++ b/DeeployTest/Platforms/Spatz/main.c @@ -0,0 +1,69 @@ + +#include +#include +#include "printf.h" + +#include "Network.h" +#include "testinputs.h" +#include "testoutputs.h" + +int main() { + const unsigned int cid = snrt_cluster_core_idx(); + + // do it only with one of the two spatz cores + if (cid==0){ + printf("Initializing network...\r\n"); + + InitNetwork(0, 1); + + for (uint32_t buf = 0; buf < DeeployNetwork_num_inputs; buf++) { + snrt_dma_start_1d(DeeployNetwork_inputs[buf], testInputVector[buf], DeeployNetwork_inputs_bytes[buf]); + } + + printf("Running network...\r\n"); + RunNetwork(0, 1); + + int32_t tot_err = 0; + uint32_t tot = 0; + OUTPUTTYPE diff; + OUTPUTTYPE expected, actual; + + for (uint32_t buf = 0; buf < DeeployNetwork_num_outputs; buf++) { + tot += DeeployNetwork_outputs_bytes[buf] / sizeof(OUTPUTTYPE); + for (uint32_t i = 0; + i < DeeployNetwork_outputs_bytes[buf] / sizeof(OUTPUTTYPE); i++) { + expected = ((OUTPUTTYPE *)testOutputVector[buf])[i]; + actual = ((OUTPUTTYPE *)DeeployNetwork_outputs[buf])[i]; + diff = expected - actual; + +#if ISOUTPUTFLOAT == 1 + // RUNWANG: Allow margin of error for float32_t + if ((diff < -1e-4) || (diff > 1e-4)) { + tot_err += 1; + printf("Expected: %10.6f ", (float)expected); + printf("Actual: %10.6f ", (float)actual); + printf("Diff: %10.6f at Index %12u in Output %u\r\n", (float)diff, i, + buf); + } +#else + // RUNWANG: No margin for integer comparison + if (diff != 0) { + tot_err += 1; + printf("Expected: %4d ", expected); + printf("Actual: %4d ", actual); + printf("Diff: %4d at Index %12u in Output %u\r\n", diff, i, buf); + } +#endif + } + } + + printf("Errors: %d out of %d \r\n", tot_err, tot); + + return tot_err; + } else { + // wait for core 0 to finish + snrt_cluster_hw_barrier(); + return 0; + } + +} \ No newline at end of file diff --git a/DeeployTest/deeployRunner_spatz.py b/DeeployTest/deeployRunner_spatz.py new file mode 100644 index 0000000000..58168f3a44 --- /dev/null +++ b/DeeployTest/deeployRunner_spatz.py @@ -0,0 +1,11 @@ +import sys + +from testUtils.deeployRunner import main + +if __name__ == "__main__": + sys.exit( + main( + default_platform = "Spatz", + default_simulator = "vsim", + ) + ) diff --git a/DeeployTest/testUtils/deeployRunner.py b/DeeployTest/testUtils/deeployRunner.py index a5a8d70ef3..0c98e254aa 100644 --- a/DeeployTest/testUtils/deeployRunner.py +++ b/DeeployTest/testUtils/deeployRunner.py @@ -348,6 +348,7 @@ def main(default_platform: Optional[str] = None, "snitch": "Snitch", "chimera": "Chimera", "softhier": "SoftHier", + "spatz": "Spatz", } if args.platform: @@ -388,6 +389,7 @@ def main(default_platform: Optional[str] = None, "Snitch": "gvsoc", "Chimera": "gvsoc", "SoftHier": "gvsoc", + "Spatz": "vsim", } simulator = simulator_map.get(platform, "host") log.info(f"No simulator specified, using default for {platform}: {simulator}") diff --git a/DeeployTest/testUtils/platformMapping.py b/DeeployTest/testUtils/platformMapping.py index 9d526906f9..69a83f1e8d 100644 --- a/DeeployTest/testUtils/platformMapping.py +++ b/DeeployTest/testUtils/platformMapping.py @@ -10,6 +10,8 @@ from Deeploy.DeeployTypes import DeploymentPlatform, NetworkDeployer, TopologyOptimizer from Deeploy.MemoryLevelExtension.MemoryLevels import MemoryHierarchy, MemoryLevel from Deeploy.MemoryLevelExtension.NetworkDeployers.MemoryLevelDeployer import MemoryPlatform, MemoryPlatformWrapper +from Deeploy.Targets.Spatz.Deployer import SpatzDeployer +from Deeploy.Targets.Spatz.Platform import SpatzOptimizer, SpatzPlatform from Deeploy.Targets.Chimera.Deployer import ChimeraDeployer from Deeploy.Targets.Chimera.Platform import ChimeraOptimizer, ChimeraPlatform from Deeploy.Targets.CortexM.Deployer import CMSISDeployer @@ -31,7 +33,7 @@ from Deeploy.Targets.SoftHier.Platform import SoftHierOptimizer, SoftHierPlatform _SIGNPROP_PLATFORMS = ["Apollo3", "Apollo4", "QEMU-ARM", "Generic", "MemPool", "SoftHier"] -_NONSIGNPROP_PLATFORMS = ["Siracusa", "Siracusa_w_neureka", "PULPOpen", "Snitch", "Chimera", "GAP9"] +_NONSIGNPROP_PLATFORMS = ["Siracusa", "Siracusa_w_neureka", "PULPOpen", "Snitch", "Chimera", "GAP9", "Spatz"] _PLATFORMS = _SIGNPROP_PLATFORMS + _NONSIGNPROP_PLATFORMS @@ -76,6 +78,9 @@ def mapPlatform(platformName: str) -> Tuple[DeploymentPlatform, bool]: elif platformName == "Chimera": Platform = ChimeraPlatform() + elif platformName == "Spatz": + Platform = SpatzPlatform() + else: raise RuntimeError(f"Deployment platform {platformName} is not implemented") @@ -272,6 +277,18 @@ def mapDeployer(platform: DeploymentPlatform, name = name, default_channels_first = default_channels_first, deeployStateDir = deeployStateDir) + + elif isinstance(platform, (SpatzPlatform)): + deployer = SpatzDeployer( + graph, + platform, + inputTypes, + SpatzOptimizer, + scheduler, + name = name, + default_channels_first = default_channels_first, + deeployStateDir = deeployStateDir + ) else: raise RuntimeError(f"Deployer for platform {platform} is not implemented") diff --git a/DeeployTest/test_platforms.py b/DeeployTest/test_platforms.py index 6d9f3cfcd7..6be4bef197 100644 --- a/DeeployTest/test_platforms.py +++ b/DeeployTest/test_platforms.py @@ -110,6 +110,14 @@ def param_id(param): "model_tests": SNITCH_MODEL_TESTS, "default_num_cores": SNITCH_DEFAULT_NUM_CORES, }, + "spatz": { + "platform": "Spatz", + "simulator": "vsim", + # TODO: Define KERNEL_TESTS and MODEL_TESTS for Spatz + "kernel_tests": [], + "model_tests": [], + # "default_num_cores": , + }, "gap9": { "platform": "GAP9", "simulator": "gvsoc", diff --git a/Makefile b/Makefile index d40a49da11..24279ecfc3 100644 --- a/Makefile +++ b/Makefile @@ -124,6 +124,7 @@ ${LLVM_INSTALL_DIR}: ${TOOLCHAIN_DIR}/llvm-project llvm: ${LLVM_INSTALL_DIR} +# runtimes for different architectures ${LLVM_CLANG_RT_RISCV_RV32IM}: ${TOOLCHAIN_DIR}/llvm-project cd ${TOOLCHAIN_DIR}/llvm-project && mkdir -p build-compiler-rt-riscv-rv32im \ && cd build-compiler-rt-riscv-rv32im; \ diff --git a/TargetLibraries/Spatz/CMakeLists.txt b/TargetLibraries/Spatz/CMakeLists.txt new file mode 100644 index 0000000000..53b3c3b642 --- /dev/null +++ b/TargetLibraries/Spatz/CMakeLists.txt @@ -0,0 +1,14 @@ +file(GLOB_RECURSE SOURCES + "src/**" +) + +include(cmake/snitch-runtime-precompiled.cmake) + +add_deeploy_library(deeployspatz STATIC ${SOURCES}) +target_include_directories(deeployspatz + PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/inc +) +target_include_directories(deeployspatz SYSTEM PUBLIC ${SNITCH_RUNTIME_INCLUDE}) +target_compile_options(deeployspatz PUBLIC ${SNITCH_RUNTIME_COMPILE_FLAGS}) +target_link_libraries(deeployspatz INTERFACE snitch-runtime) diff --git a/TargetLibraries/Spatz/cmake/snitch-runtime-precompiled.cmake b/TargetLibraries/Spatz/cmake/snitch-runtime-precompiled.cmake new file mode 100644 index 0000000000..84faa71fd4 --- /dev/null +++ b/TargetLibraries/Spatz/cmake/snitch-runtime-precompiled.cmake @@ -0,0 +1,6 @@ +# Copyright 2025 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +# This is a direct reference to the Snitch runtime setup for Spatz. +include(${CMAKE_CURRENT_LIST_DIR}/../../Snitch/cmake/snitch-runtime-precompiled.cmake) diff --git a/TargetLibraries/Spatz/inc/DeeploySpatzMath.h b/TargetLibraries/Spatz/inc/DeeploySpatzMath.h new file mode 100644 index 0000000000..0e856fbf1c --- /dev/null +++ b/TargetLibraries/Spatz/inc/DeeploySpatzMath.h @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2026 ETH Zurich and University of Bologna + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DEEPLOY_SPATZ_MATH_HEADER_ +#define __DEEPLOY_SPATZ_MATH_HEADER_ + +#include +#include + +#include "DeeployBasicMath.h" +#include "snrt.h" + +#define BEGIN_SINGLE_CORE if (core_id == 0) { +#define END_SINGLE_CORE } +#define SINGLE_CORE if (core_id == 0) + +#endif // __DEEPLOY_SPATZ_MATH_HEADER_ diff --git a/TargetLibraries/Spatz/inc/Util.h b/TargetLibraries/Spatz/inc/Util.h new file mode 100644 index 0000000000..893d687fa1 --- /dev/null +++ b/TargetLibraries/Spatz/inc/Util.h @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: 2026 ETH Zurich and University of Bologna +// SPDX-License-Identifier: Apache-2.0 + +#ifndef SPATZ_UTIL_H +#define SPATZ_UTIL_H + +void spatz_util_dummy(void); + +#endif // SPATZ_UTIL_H diff --git a/TargetLibraries/Spatz/src/Util.c b/TargetLibraries/Spatz/src/Util.c new file mode 100644 index 0000000000..9c30c11f49 --- /dev/null +++ b/TargetLibraries/Spatz/src/Util.c @@ -0,0 +1,5 @@ +// SPDX-FileCopyrightText: 2026 ETH Zurich and University of Bologna +// SPDX-License-Identifier: Apache-2.0 + +// Minimal stub for Spatz runtime linkage +void spatz_util_dummy(void) {} diff --git a/cmake/spatz/spatz.cmake b/cmake/spatz/spatz.cmake new file mode 100644 index 0000000000..ea888d4ac9 --- /dev/null +++ b/cmake/spatz/spatz.cmake @@ -0,0 +1,77 @@ +# SPDX-FileCopyrightText: 2024 ETH Zurich and University of Bologna +# +# SPDX-License-Identifier: Apache-2.0 + +# Spatz currently reuses the Snitch runtime layout. +if(DEFINED ENV{SPATZ_HOME}) + set(SPATZ_HOME $ENV{SPATZ_HOME}) +elseif(DEFINED ENV{SNITCH_HOME}) + set(SPATZ_HOME $ENV{SNITCH_HOME}) +else() + message(FATAL_ERROR "Environment variable SPATZ_HOME or SNITCH_HOME must be set.") +endif() + +# Keep compatibility with existing runtime cmake snippets expecting SNITCH_* vars. +set(SNITCH_HOME ${SPATZ_HOME}) +set(SNITCH_RUNTIME_HOME ${SNITCH_HOME}/sw/snRuntime) +set(SNITCH_CLUSTER_HOME ${SNITCH_HOME}/target/snitch_cluster) + +add_compile_definitions( + DEEPLOY_SPATZ_PLATFORM +) + +set(DEEPLOY_ARCH SPATZ) + +set(num_threads ${NUM_CORES}) + +macro(add_spatz_vsim_simulation name) + if(EXISTS ${SPATZ_HOME}/target/spatz_cluster/bin/spatz_cluster.vsim) + set(_SPATZ_VSIM_WORKDIR ${SPATZ_HOME}/target/spatz_cluster) + set(_SPATZ_VSIM_BIN bin/spatz_cluster.vsim) + else() + set(_SPATZ_VSIM_WORKDIR ${SPATZ_HOME}/target/snitch_cluster) + set(_SPATZ_VSIM_BIN bin/snitch_cluster.vsim) + endif() + + add_custom_target(vsim_${name} + WORKING_DIRECTORY ${_SPATZ_VSIM_WORKDIR} + DEPENDS ${name} + COMMAND ${QUESTA} ${_SPATZ_VSIM_BIN} + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${name} || true + COMMENT "Simulating deeploytest with vsim (Spatz)" + POST_BUILD + USES_TERMINAL + VERBATIM + ) +endmacro() + +macro(add_spatz_vsim_gui_simulation name) + if(EXISTS ${SPATZ_HOME}/target/spatz_cluster/bin/spatz_cluster.vsim.gui) + set(_SPATZ_VSIM_GUI_WORKDIR ${SPATZ_HOME}/target/spatz_cluster) + set(_SPATZ_VSIM_GUI_BIN bin/spatz_cluster.vsim.gui) + else() + set(_SPATZ_VSIM_GUI_WORKDIR ${SPATZ_HOME}/target/snitch_cluster) + set(_SPATZ_VSIM_GUI_BIN bin/snitch_cluster.vsim.gui) + endif() + + add_custom_target(vsim.gui_${name} + WORKING_DIRECTORY ${_SPATZ_VSIM_GUI_WORKDIR} + DEPENDS ${name} + COMMAND ${QUESTA} ${_SPATZ_VSIM_GUI_BIN} + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${name} || true + COMMENT "Simulating deeploytest with vsim.gui (Spatz)" + POST_BUILD + USES_TERMINAL + VERBATIM + ) +endmacro() + +add_compile_options( + -ffast-math +) + +add_link_options( + -ffast-math + -Wl,--gc-sections +) + diff --git a/cmake/spatz/toolchain_llvm.cmake b/cmake/spatz/toolchain_llvm.cmake new file mode 100644 index 0000000000..c3f13592e7 --- /dev/null +++ b/cmake/spatz/toolchain_llvm.cmake @@ -0,0 +1,94 @@ +# SPDX-FileCopyrightText: 2024 ETH Zurich and University of Bologna +# +# SPDX-License-Identifier: Apache-2.0 + +set(TOOLCHAIN_PREFIX ${TOOLCHAIN_INSTALL_DIR}/bin) + +set(CMAKE_SYSTEM_NAME Generic) + +set(LLVM_TAG llvm) + +# Crucial: Point CMake to the specialized Clang toolchain instead of system cc +set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}/clang) +set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}/clang++) +set(CMAKE_ASM_COMPILER ${TOOLCHAIN_PREFIX}/clang) +set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}/${LLVM_TAG}-objcopy) +set(CMAKE_OBJDUMP ${TOOLCHAIN_PREFIX}/${LLVM_TAG}-objdump) +set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}/ld.lld) +set(CMAKE_EXECUTABLE_SUFFIX ".elf") + +# ISA definition from user command +set(ISA rv32imafdvzfh_xdma_xfquarter) + +# Compile options based on user's manual compilation commands +add_compile_options( + -target riscv32-unknown-elf + -MP + -mcpu=snitch + # -mcmodel=small # User used small, Snitch uses medany. Keeping user's choice can be risky if code is large. + # Safe compromise: use medany unless 'small' is strictly required, but user command had small. + # deeploy typically uses medany. Let's stick to user's flag if explicit, or Snitch defaults. + # User command: -mcmodel=small + -mcmodel=small + + -ffast-math + -fno-builtin-printf + -fno-common + -falign-loops=16 + -ffunction-sections + -Wextra + + # LLVM specific flags from user command + -mllvm -misched-topdown + -menable-experimental-extensions + -mno-relax + + -march=${ISA} + -mabi=ilp32d + -isystem ${TOOLCHAIN_INSTALL_DIR}/picolibc/riscv/rv32imafd/include + + # Optimization and debug + -O3 + -g + + # Include paths will be handled by CMake target_include_directories + # But we need riscv-opcodes if not standard + # -I.../riscv-opcodes is usually handled by Snitch/Spatz runtime includes +) + +# Link options matching user command +add_link_options( + -target riscv32-unknown-elf + -MP + -mcpu=snitch + -march=${ISA} + -mabi=ilp32d + -mcmodel=small + + -fuse-ld=lld + -nostartfiles + -nostdlib + -ffast-math + -fno-common + -fno-builtin-printf + + -Wl,-z,norelro + -Wl,--gc-sections + -Wl,--no-relax + -L${TOOLCHAIN_INSTALL_DIR}/picolibc/riscv/rv32imafd/lib + -L${TOOLCHAIN_INSTALL_DIR}/lib/clang/15.0.0/lib/baremetal/rv32imafd + + # User had explicit gcc toolchain path: --gcc-toolchain=/usr/pack/... + # In Docker/Deeploy we typically use packaged libs or environment variables. + # We will try to rely on the container's environment first. +) + +# User command linked: -lm -lgcc -lm -lgcc libsnRuntime-cluster.a +# libsnRuntime is handled by our target_link_libraries(deeployspatz ... snitch-runtime) +link_libraries( + -lc + -lclang_rt.builtins-riscv32 +) + +# Required by math library to avoid conflict with stdint definition +add_definitions(-D__DEFINED_intptr_t)