diff --git a/.github/workflows/_select-env.yml b/.github/workflows/_select-env.yml index 1085c7eaa1..7b1cc33f72 100644 --- a/.github/workflows/_select-env.yml +++ b/.github/workflows/_select-env.yml @@ -34,7 +34,11 @@ jobs: elif [[ "${{ github.ref_name }}" == "main" ]]; then IMAGE="ghcr.io/pulp-platform/deeploy:main" else - IMAGE="ghcr.io/pulp-platform/deeploy:devel" + # REVERT BEFORE MERGE: this branch bumps snitch_cluster and adds + # Verilator, so it cannot build against the published devel image. + # Restore ghcr.io/pulp-platform/deeploy:devel once the image has + # been rebuilt from this branch. + IMAGE="ghcr.io/gamzeisl/deeploy:snitch-upgrade" fi echo "image=${IMAGE}" >> "$GITHUB_OUTPUT" diff --git a/CHANGELOG.md b/CHANGELOG.md index d15ac5bafd..3e89ceaedc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ This file contains the changelog for the Deeploy project. The changelog is divid - Add support for Operators for Generic target needed in MAGIA [#193]( https://github.com/pulp-platform/Deeploy/pull/193) - Fix GAP9 L3 Board Tests: readfs Flash Ordering and Duplicate Input Data [#196](https://github.com/pulp-platform/Deeploy/pull/196) - Add SoCDAML Part III: hands-on lab for adding a new int8 operator [#194](https://github.com/pulp-platform/Deeploy/pull/194) +- Upgrade the Snitch Cluster [#TODO](https://github.com/pulp-platform/Deeploy/pull/TODO) ### Added - tests for Regular and DW Conv2D with 3x3 kernel @@ -37,6 +38,7 @@ This file contains the changelog for the Deeploy project. The changelog is divid - GAP9 Container Support with ARM64 architecture support - `zsh` and `oh-my-zsh` plugin installation in containers - Shell Format pre-commit hook +- Verilator simulation for Snitch. `make snitch_verilator` builds the cluster model and `add_snitch_cluster_verilator_simulation` registers the CMake target. The Deeploy container carries Verilator v5.034, the version `snitch_cluster` pins in its own container. - Add integer MaxPool1D for Generic platform and RQSConv1D support for PULPOpen, with corresponding kernel tests. - Added GAP9 Platform Support: Deployer, Bindings, Templates, Tiler, DMA (L3Dma/MchanDma), target library, CI workflows - Per-layer microbenchmarking on PULPOpen via `--profileMicrobenchmark`: new `PULPMicrobenchmark` code-transformation pass + `perf_utils.h` helpers report cycles, instructions, stalls and cache misses per layer in `RunNetwork` @@ -62,8 +64,24 @@ This file contains the changelog for the Deeploy project. The changelog is divid - Aligned CLI commands across the project - Added @runwangdl as a code owner - Skip emitting duplicate `testInputVector` data for inputs placed in L3 (loaded at runtime from the readfs hex instead), reducing test binary size +- Bump the pinned `snitch_cluster` from `e02cc9e` (April 2024) to `5b2fccd` (September 2025). Deliberately not the latest upstream commit: `7c2bdd9` replaces the hardware-barrier CSR with a symbolic name that the pinned LLVM cannot assemble, and `de5251b` raises the Python floor to 3.12, while Deeploy targets 3.10. +- Adapt the Snitch build system to the current `snitch_cluster` layout (`sw/snRuntime` to `sw/runtime`, `target/snitch_cluster` to `target/sim`, and the removal of `sw/math` and `sw/runtime/{common,rtl,banshee}`). The runtime is now built with the namespaced `sn-runtime` target and `SN_LLVM_BINROOT`. +- Compile the Snitch target library, platform sources and generated `Network.c` as C++. `sw/runtime/src/sync.h` gives `snrt_inter_cluster_sw_barrier` a default argument, which is not valid C and is reached by every translation unit including `snrt.h`. +- Update the Snitch runtime API calls: `snrt_l1alloc`/`snrt_l3alloc` become `snrt_l1_alloc`/`snrt_l3_alloc`, and performance counters are selected by index with configuration separated from starting. +- Only register the banshee simulation target and `BANSHEE_CONFIG` when `BANSHEE_INSTALL_DIR` is set. Recent `snitch_cluster` runtimes no longer support banshee, and previously the Snitch platform could not be configured without it. +- Enable `Xdiv_sqrt` in the cluster configuration Deeploy builds against, since its FP32 kernels emit `fdiv` and `fsqrt`. +- Run the Snitch tests on Verilator rather than GVSoC. GVSoC's model of the cluster peripherals predates the bumped hardware: the peripheral region moved from `0x10020000` to `0x10021000`, four `SCRATCH` registers were added ahead of the CLINT and shift every subsequent register by `0x20`, and the registers are now 64-bit where the model still generates 32-bit ones. ### Fixed +- Declare the Snitch kernels used from generated code. `SnitchAdd` and `snitch_nn_add_i8_i8_i8` had no declaration in any header, and `kernel/iSoftmax.h` declared `StnichSoftmax_i8_u8` for a kernel named `SnitchSoftmax_i8_u8` in a header that was never included. All three relied on implicit declarations, which C++ does not have. +- Give the Generic target library headers C linkage, so that calls into it from the C++-compiled Snitch platform resolve against the C definitions. +- Do not emit `sizeof(void)` for Snitch transient buffers, whose size is already expressed in bytes. It relies on a GNU C extension and is invalid in C++. +- Use `memcpy` rather than the iDMA for the L3 input copies in the Snitch test harness. Both sides of that transfer are in L3, and the iDMA has a single AXI master port, so it requires one side to be TCDM. +- Insert `snrt_fpu_fence()` before the cluster barriers emitted for Snitch. Floating-point results were not ordered with respect to the barrier, so the DM core could read a tile out of L1 before the values had landed. +- Fix a pointer type mismatch in `snitch_nn_add_i8_i8_i8`, where scratch variables declared `int` had their addresses assigned to `int8_t` pointers. +- Wait for all outstanding Snitch DMA transfers before the cluster barrier instead of waiting on an individual transaction ID. `completed_id` advances when the iDMA ND midend observes `burst_rsp.last`, which is upstream of the write datapath, so the compute cores could be released onto a tile the DMA had not finished writing. +- Constrain the Snitch GEMM tile sizes in both parallelised dimensions. The kernels stream the output width in groups of 8 through the SSRs with no remainder path, so a tile of `O` below 8 makes `O / unroll` zero and, since the SSR bound is written as `bound - 1`, wraps it to `0xFFFFFFFF`: the streamer never goes idle and the next SSR configuration write never retires. The `M` constraint was only a `PerformanceHint` and so was dropped under memory pressure, which is not merely slower but wrong, since `M / compute_num` truncates and the rows in the remainder are never computed. +- Preserve a scalar second operand for the Snitch `Add` and `Mul` layers. The Generic layers rewrite the shorter operand's shape to the longer one in `computeShapes`, which expresses broadcasting notionally but materialises no data, so the `is_scalar` flag the parser derives from the shape comes out false, the buffer is allocated for the full tensor, and the kernel reads elements that were never written. - Fix Neureka's output-channels subtile size (in ConvTemplate) and Dense/DW/PW tile constraints - in `NetworkContainer._createIOBindings`, set `_live = True` on network input and output buffers so that any buffer aliasing a network I/O tensor is no longer deallocated while the I/O tensor is still in use. - Fix latent bug in `VariableBuffer.has_live_aliases` where `visited` variable was storing buffer names as a set of characters instead of strings. diff --git a/CMakeLists.txt b/CMakeLists.txt index 20a85bccf8..0845d18d9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -267,7 +267,7 @@ if(platform STREQUAL Snitch) include(${CMAKE_CURRENT_LIST_DIR}/cmake/snitch/snitch_cluster/snitch_cluster.cmake) - project(deeploy LANGUAGES C ASM) + project(deeploy LANGUAGES C CXX ASM) message(STATUS "============================= ${platform} Configuration ============================") message(STATUS "[cMake ] Number of total cores = " ${NUM_CORES}) diff --git a/Container/Dockerfile.deeploy b/Container/Dockerfile.deeploy index 2b717e49ec..3b41de34df 100644 --- a/Container/Dockerfile.deeploy +++ b/Container/Dockerfile.deeploy @@ -2,8 +2,13 @@ # # SPDX-License-Identifier: Apache-2.0 -########## Stage 1: Large image to build toolchains and emulator ########## ARG BASE_IMAGE=ghcr.io/pulp-platform/deeploy-toolchain +ARG VERILATOR_VERSION=v5.034 + +########## Stage 0: Verilator for RTL simulation ########## +FROM verilator/verilator:${VERILATOR_VERSION} AS verilator + +########## Stage 1: Large image to build toolchains and emulator ########## FROM ${BASE_IMAGE} AS toolchain # Intermediate Stage @@ -16,6 +21,8 @@ ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Etc/UTC ENV LANG=C.UTF-8 ENV LC_ALL=C.UTF-8 +COPY --from=verilator /usr/local/bin/verilator /usr/local/bin/verilator_bin /usr/local/bin/ +COPY --from=verilator /usr/local/share/verilator /usr/local/share/verilator ENV PATH="/app/install/bender:${PATH}" ENV DEEPLOY_INSTALL_DIR=/app/install ENV LLVM_INSTALL_DIR=/app/install/llvm @@ -62,6 +69,12 @@ RUN --mount=type=cache,target=/ccache \ make snitch_runtime && \ ccache -s +RUN apt-get update && \ + apt-get install -y --no-install-recommends device-tree-compiler && \ + rm -rf /var/lib/apt/lists/* && \ + make snitch_verilator && \ + rm -rf /app/install/snitch_cluster/target/sim/build/work-vlt + # Remove toolchain to make the container lighter WORKDIR /app RUN rm -rf /app/build @@ -107,6 +120,7 @@ RUN apt-get update && \ python3.10-venv \ python3.10-distutils \ gcc \ + g++ \ zsh && \ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \ python get-pip.py && \ diff --git a/Deeploy/Targets/Snitch/CodeTransformationPasses/SnitchClusterSynch.py b/Deeploy/Targets/Snitch/CodeTransformationPasses/SnitchClusterSynch.py index cc0af164ad..16eb48f4e3 100644 --- a/Deeploy/Targets/Snitch/CodeTransformationPasses/SnitchClusterSynch.py +++ b/Deeploy/Targets/Snitch/CodeTransformationPasses/SnitchClusterSynch.py @@ -8,6 +8,7 @@ NodeTemplate, _NoVerbosity _synchTemplate = NodeTemplate(""" + snrt_fpu_fence(); snrt_cluster_hw_barrier(); """) diff --git a/Deeploy/Targets/Snitch/DMA/SnitchDma.py b/Deeploy/Targets/Snitch/DMA/SnitchDma.py index ac0c622cc8..b3786152fa 100644 --- a/Deeploy/Targets/Snitch/DMA/SnitchDma.py +++ b/Deeploy/Targets/Snitch/DMA/SnitchDma.py @@ -5,7 +5,7 @@ from typing import Dict, Tuple from Deeploy.DeeployTypes import NetworkContext, NodeTemplate, OperatorRepresentation, VariableBuffer -from Deeploy.TilingExtension.AsyncDma import AsyncDma, DmaDirection, Future, PerTensorWaitingStrategy +from Deeploy.TilingExtension.AsyncDma import AsyncDma, BarrierWaitingStrategy, DmaDirection, Future class SnitchBarrierFuture(Future): @@ -33,13 +33,26 @@ class SnitchDma(AsyncDma): 2: NodeTemplate(""" if (snrt_is_dm_core()) { - ${future} = snrt_dma_start_2d(${dest}, ${src}, ${size}, ${stride_dest}, ${stride_src}, ${repeat}); - // WIESEP: Hack as otherwise the last commited DMA transaction ID can never be resolved. - snrt_dma_start_2d(${dest}, ${dest}, 1, 0, 0, 0); + snrt_dma_start_2d(${dest}, ${src}, ${size}, ${stride_dest}, ${stride_src}, ${repeat}); } """), } - _waitingStrategy = PerTensorWaitingStrategy(SnitchFuture) + # Wait for all outstanding transfers rather than for an individual one. + # + # snrt_dma_wait compares against completed_id, which idma advances when the + # ND midend sees burst_rsp.last. That is upstream of the write datapath, so + # it can move before the transferred data is visible, and the barrier that + # follows then releases the compute cores onto a tile the DMA has not + # finished writing. snrt_dma_wait_all instead polls the busy flag, which + # covers every pipeline stage. + # + # Two further details make per-transfer waiting unusable here: dmcpyi + # returns the same ID for transfers issued back to back. + # + # This also drops the self-copy that used to follow every transfer: it + # existed to bump completed_id past the last transaction ID, which the + # strictly-greater comparison in the previously pinned runtime required. + _waitingStrategy = BarrierWaitingStrategy(SnitchBarrierFuture, "dma_barrier") def __init__(self, transferTemplates: Dict[int, NodeTemplate] = _transferTemplates) -> None: super().__init__(transferTemplates) diff --git a/Deeploy/Targets/Snitch/Layers.py b/Deeploy/Targets/Snitch/Layers.py new file mode 100644 index 0000000000..edaa56b244 --- /dev/null +++ b/Deeploy/Targets/Snitch/Layers.py @@ -0,0 +1,39 @@ +# SPDX-FileCopyrightText: 2026 ETH Zurich and University of Bologna +# +# SPDX-License-Identifier: Apache-2.0 + +from typing import Tuple + +import numpy as np + +from Deeploy.DeeployTypes import Shape +from Deeploy.Targets.Generic.Layers import AddLayer, MulLayer + + +class _ScalarPreservingShapeMixin: + """Keep a single-element second operand at its original shape. + + The Generic Add and Mul layers rewrite the shorter operand's shape to the + longer one, which expresses broadcasting notionally but does not + materialise any data. For a genuine scalar that is harmful on Snitch: the + kernels broadcast input2[0] themselves, selected by the is_scalar flag the + parser derives from the operand shape. Once the shape has been rewritten + the flag comes out false, the buffer is allocated for the full tensor, and + the kernel reads elements that were never written. + """ + + def computeShapes(self, inputShapes: Shape, outputShapes: Shape, operatorRepresentation, + channels_first) -> Tuple[Shape, Shape]: + + if len(inputShapes) > 1 and np.prod(inputShapes[1]) == 1: + return (inputShapes, [inputShapes[0]]) + + return super().computeShapes(inputShapes, outputShapes, operatorRepresentation, channels_first) + + +class SnitchAddLayer(_ScalarPreservingShapeMixin, AddLayer): + pass + + +class SnitchMulLayer(_ScalarPreservingShapeMixin, MulLayer): + pass diff --git a/Deeploy/Targets/Snitch/Platform.py b/Deeploy/Targets/Snitch/Platform.py index 53b046f9de..62e9fa4094 100644 --- a/Deeploy/Targets/Snitch/Platform.py +++ b/Deeploy/Targets/Snitch/Platform.py @@ -12,8 +12,8 @@ from Deeploy.Targets.Generic.Bindings import BasicLayerNormBindings, BasicPad1DBindings, BasicPad2DBindings, \ BasicRQIntegerDivBinding from Deeploy.Targets.Generic.Layers import AddLayer, ConcatLayer, DivLayer, GatherLayer, GEMMLayer, HardSwishLayer, \ - LayerNormLayer, MatMulLayer, MulLayer, PadLayer, ReshapeLayer, RMSNormLayer, RQGEMMLayer, RQIntegerDivLayer, \ - SoftmaxLayer, TransposeLayer, iNoNormLayer + LayerNormLayer, MatMulLayer, PadLayer, ReshapeLayer, RMSNormLayer, RQGEMMLayer, RQIntegerDivLayer, SoftmaxLayer, \ + TransposeLayer, iNoNormLayer from Deeploy.Targets.Generic.Parsers import ConcatParser, GatherParser, MatMulParser, Pad1DParser, Pad2DParser, \ ReshapeParser, RQAddParser, RQIntegerDivParser, SoftmaxParser, TransposeParser, UnsqueezeParser, iLayerNormParser, \ iNoNormParser, iSoftmaxParser @@ -22,6 +22,7 @@ IntegerDivRequantMergePass, MergeConstAddAndRequantPass, MergeTrueIntegerDivRequantShiftPass, RQSSplitPass, \ SkipEmptyConcatPass, SkipUnityRequantPass, iGELURequantMergePass, iHardswishRequantMergePass from Deeploy.Targets.PULPOpen.Platform import RQAddMapper +from Deeploy.Targets.Snitch.Layers import SnitchAddLayer, SnitchMulLayer from Deeploy.Targets.Snitch.Parsers import SnitchAddParser, SnitchDivParser, SnitchGEMMParser, SnitchHardSwishParser, \ SnitchMulParser, SnitchRMSNormParser, SnitchRQGEMMParser from Deeploy.Targets.Snitch.Templates import AllocateTemplate, FreeTemplate @@ -69,11 +70,11 @@ 'iNoNorm': iNoNormLayer([iNoNormMapper]), 'iLayerNorm': LayerNormLayer([iLayerNormMapper]), 'RequantizedAdd': AddLayer([RQAddMapper]), - 'Add': AddLayer([AddMapper]), + 'Add': SnitchAddLayer([AddMapper]), 'RMSNorm': RMSNormLayer([RMSNormMapper]), 'HardSwish': HardSwishLayer([HardSwishMapper]), 'Div': DivLayer([DivMapper]), - 'Mul': MulLayer([MulMapper]), + 'Mul': SnitchMulLayer([MulMapper]), 'Reshape': ReshapeLayer([ReshapeMapper]), 'Transpose': TransposeLayer([TransposeMapper]), 'Concat': ConcatLayer([ConcatMapper]), diff --git a/Deeploy/Targets/Snitch/Templates/AllocateTemplate.py b/Deeploy/Targets/Snitch/Templates/AllocateTemplate.py index 7d7b65d348..66fc54ca63 100644 --- a/Deeploy/Targets/Snitch/Templates/AllocateTemplate.py +++ b/Deeploy/Targets/Snitch/Templates/AllocateTemplate.py @@ -9,10 +9,10 @@ snitchL1InitTemplate = NodeTemplate("${type.typeName} ${name};\n") snitchL2AllocateTemplate = NodeTemplate( - "${name} = (${type.typeName}) snrt_l3alloc(sizeof(${type.referencedType.typeName}) * ${size});\n") + "${name} = (${type.typeName}) snrt_l3_alloc(sizeof(${type.referencedType.typeName}) * ${size});\n") snitchL1AllocateTemplate = NodeTemplate( - "${name} = (${type.typeName}) snrt_l1alloc(sizeof(${type.referencedType.typeName}) * ${size});\n") + "${name} = (${type.typeName}) snrt_l1_alloc(sizeof(${type.referencedType.typeName}) * ${size});\n") snitchL2GlobalInitTemplate = NodeTemplate("static ${type.referencedType.typeName} ${name}[${size}] = {${values}};\n") @@ -46,11 +46,20 @@ """) snitchGenericGuardedAllocate = NodeTemplate(""" +<% +# TransientBuffers are void pointers whose size is already expressed in bytes. +# sizeof(void) is a GNU C extension that evaluates to 1; it is invalid in C++, +# which the Snitch platform is compiled as. +if type.referencedType.typeName == "void": + allocSize = f"{size}" +else: + allocSize = f"sizeof({type.referencedType.typeName}) * {size}" +%> % if _memoryLevel == "L1": -if (snrt_is_dm_core()) { ${name} = (${type.typeName}) snrt_l1alloc(sizeof(${type.referencedType.typeName}) * ${size}); } +if (snrt_is_dm_core()) { ${name} = (${type.typeName}) snrt_l1_alloc(${allocSize}); } snrt_cluster_hw_barrier();\n % else: -if (snrt_is_dm_core()) { ${name} = (${type.typeName}) snrt_l3alloc(sizeof(${type.referencedType.typeName}) * ${size}); } +if (snrt_is_dm_core()) { ${name} = (${type.typeName}) snrt_l3_alloc(${allocSize}); } snrt_cluster_hw_barrier();\n % endif """) diff --git a/Deeploy/Targets/Snitch/Templates/iSoftmaxTemplate.py b/Deeploy/Targets/Snitch/Templates/iSoftmaxTemplate.py index b4b5abbf16..856e180c60 100644 --- a/Deeploy/Targets/Snitch/Templates/iSoftmaxTemplate.py +++ b/Deeploy/Targets/Snitch/Templates/iSoftmaxTemplate.py @@ -16,5 +16,5 @@ else: signatureString += '_u8' %> -SnitchSoftmax${signatureString}(${data_in}, ${data_out}, ${lastDimBuffer}, ${size}, ${lastDimLength}, ${coeffB}, ${coeffC}, ${log2}); +SnitchSoftmax${signatureString}(${data_in}, ${data_out}, (uint32_t *) ${lastDimBuffer}, ${size}, ${lastDimLength}, ${coeffB}, ${coeffC}, ${log2}); """) diff --git a/Deeploy/Targets/Snitch/TileConstraints/GemmTileConstraint.py b/Deeploy/Targets/Snitch/TileConstraints/GemmTileConstraint.py index e5d35c4a42..3639ba9780 100644 --- a/Deeploy/Targets/Snitch/TileConstraints/GemmTileConstraint.py +++ b/Deeploy/Targets/Snitch/TileConstraints/GemmTileConstraint.py @@ -9,7 +9,7 @@ from Deeploy.DeeployTypes import NetworkContext, OperatorRepresentation from Deeploy.TilingExtension.MemoryConstraints import NodeMemoryConstraint from Deeploy.TilingExtension.TileConstraint import TileConstraint -from Deeploy.TilingExtension.TilerModel import PerformanceHint, TilerModel +from Deeploy.TilingExtension.TilerModel import TilerModel from Deeploy.TilingExtension.TilingCodegen import AbsoluteHyperRectangle, HyperRectangle, TilingSchedule, \ VariableReplacementScheme @@ -89,13 +89,20 @@ def addPolicyConstraint(tilerModel: TilerModel, parseDict: Dict, ctxt: NetworkCo # Full inner dimension tilerModel.addConstraint(AWidthDimVar == AWidthDimVar.Max()) - # We parallelize over the output height dimension so try to keep it divisible by the number of cores (8) - if parseDict["M"] > 8: - tilerModel.addTileSizeDivisibleConstraint(parseDict, - "M", - YHeightDimVar, - 8, - strategy = PerformanceHint(priority = 1)) + # We parallelize over the output height dimension by handing each of the 8 + # compute cores M / 8 rows, so a tile of M that is not a multiple of 8 is + # invalid. + if parseDict["M"] >= 8: + tilerModel.addTileSizeDivisibleConstraint(parseDict, "M", YHeightDimVar, 8) + + # The kernels stream the output width in groups of `unroll` (8) through the + # SSRs and have no remainder path, so they require a tile of O that is a + # multiple of 8. A smaller tile makes `O / unroll` zero, and since the SSR + # bound is written as `bound - 1` it wraps to 0xFFFFFFFF: the streamer is + # told to produce ~4 billion elements while the consuming loop runs zero + # times, so it never goes idle and the next SSR config write never retires. + if parseDict["O"] >= 8: + tilerModel.addTileSizeDivisibleConstraint(parseDict, "O", YWidthDimVar, 8) return tilerModel diff --git a/DeeployTest/CMakeLists.txt b/DeeployTest/CMakeLists.txt index b7f3535790..02012d5765 100644 --- a/DeeployTest/CMakeLists.txt +++ b/DeeployTest/CMakeLists.txt @@ -6,6 +6,9 @@ include_directories(${GENERATED_SOURCE}) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +if(DEEPLOY_ARCH STREQUAL SNITCH) + set_source_files_properties(${GENERATED_SOURCE}/Network.c PROPERTIES LANGUAGE CXX) +endif() add_library(network OBJECT ${GENERATED_SOURCE}/Network.c) target_link_libraries(network PUBLIC deeploylib) diff --git a/DeeployTest/Platforms/Snitch/CMakeLists.txt b/DeeployTest/Platforms/Snitch/CMakeLists.txt index 03a40258eb..810dc6626e 100644 --- a/DeeployTest/Platforms/Snitch/CMakeLists.txt +++ b/DeeployTest/Platforms/Snitch/CMakeLists.txt @@ -8,11 +8,15 @@ file(GLOB_RECURSE SOURCES main.c ) +set_source_files_properties(${SOURCES} PROPERTIES LANGUAGE CXX) add_deeploy_executable(${ProjectId} EXCLUDE_FROM_ALL ${SOURCES}) target_link_libraries(${ProjectId} PRIVATE network deeploylib) target_compile_options(${ProjectId} INTERFACE network) -add_banshee_simulation(${ProjectId}) +if(DEFINED ENV{BANSHEE_INSTALL_DIR}) + add_banshee_simulation(${ProjectId}) +endif() add_gvsoc_emulation(${ProjectId} "pulp.snitch.snitch_cluster_single") add_snitch_cluster_vsim_simulation(${ProjectId}) -add_snitch_cluster_vsim_gui_simulation(${ProjectId}) \ No newline at end of file +add_snitch_cluster_vsim_gui_simulation(${ProjectId}) +add_snitch_cluster_verilator_simulation(${ProjectId}) \ No newline at end of file diff --git a/DeeployTest/Platforms/Snitch/main.c b/DeeployTest/Platforms/Snitch/main.c index 70faef6ca8..8358ed39c7 100644 --- a/DeeployTest/Platforms/Snitch/main.c +++ b/DeeployTest/Platforms/Snitch/main.c @@ -9,6 +9,7 @@ #include "snrt.h" #include "testinputs.h" #include "testoutputs.h" +#include // #define NOPRINT // #define NOTEST @@ -58,12 +59,13 @@ int main(void) { printf("Copy inputs...\r\n"); #endif - // WIESEP: Copy inputs to allocated memory + // Copy inputs to allocated L3 memory. A plain memcpy is used here because + // the iDMA engine cannot perform L3->L3 (AXI->AXI) transfers — it has a + // single AXI master port and requires one side to be TCDM. for (uint32_t buf = 0; buf < DeeployNetwork_num_inputs; buf++) { - snrt_dma_start_1d(DeeployNetwork_inputs[buf], testInputVector[buf], - DeeployNetwork_inputs_bytes[buf]); + memcpy(DeeployNetwork_inputs[buf], testInputVector[buf], + DeeployNetwork_inputs_bytes[buf]); } - snrt_dma_wait_all(); #ifndef CI printf("Input copied\r\n"); @@ -93,6 +95,7 @@ int main(void) { StopTimer(); + snrt_fpu_fence(); snrt_cluster_hw_barrier(); #ifndef CI @@ -160,6 +163,7 @@ int main(void) { #endif } + snrt_fpu_fence(); snrt_cluster_hw_barrier(); return 0; } diff --git a/DeeployTest/deeployRunner_snitch.py b/DeeployTest/deeployRunner_snitch.py index aa97933319..c08c541ade 100644 --- a/DeeployTest/deeployRunner_snitch.py +++ b/DeeployTest/deeployRunner_snitch.py @@ -19,6 +19,6 @@ def setup_parser(parser): sys.exit( main(default_platform = "Snitch", - default_simulator = "gvsoc", + default_simulator = "verilator", tiling_enabled = False, parser_setup_callback = setup_parser)) diff --git a/DeeployTest/deeployRunner_tiled_snitch.py b/DeeployTest/deeployRunner_tiled_snitch.py index d6e5ffd196..e26136351a 100644 --- a/DeeployTest/deeployRunner_tiled_snitch.py +++ b/DeeployTest/deeployRunner_tiled_snitch.py @@ -19,6 +19,6 @@ def setup_parser(parser): sys.exit( main(default_platform = "Snitch", - default_simulator = "gvsoc", + default_simulator = "verilator", tiling_enabled = True, parser_setup_callback = setup_parser)) diff --git a/DeeployTest/testUtils/core/config.py b/DeeployTest/testUtils/core/config.py index e932c23962..75eb327495 100644 --- a/DeeployTest/testUtils/core/config.py +++ b/DeeployTest/testUtils/core/config.py @@ -13,7 +13,7 @@ class DeeployTestConfig: test_name: str test_dir: str platform: str - simulator: Literal['gvsoc', 'banshee', 'qemu', 'vsim', 'vsim.gui', 'host', 'none'] + simulator: Literal['gvsoc', 'banshee', 'qemu', 'vsim', 'vsim.gui', 'verilator', 'host', 'none'] tiling: bool gen_dir: str build_dir: str diff --git a/DeeployTest/testUtils/deeployRunner.py b/DeeployTest/testUtils/deeployRunner.py index 00ec496ed9..0719abb288 100644 --- a/DeeployTest/testUtils/deeployRunner.py +++ b/DeeployTest/testUtils/deeployRunner.py @@ -406,7 +406,7 @@ def main(default_platform: Optional[str] = None, "MemPool": "banshee", "Siracusa": "gvsoc", "Siracusa_w_neureka": "gvsoc", - "Snitch": "gvsoc", + "Snitch": "verilator", "Chimera": "gvsoc", "SoftHier": "gvsoc", } diff --git a/DeeployTest/testUtils/testRunner.py b/DeeployTest/testUtils/testRunner.py index fdd4c9bf17..f7e2ff89ec 100644 --- a/DeeployTest/testUtils/testRunner.py +++ b/DeeployTest/testUtils/testRunner.py @@ -320,15 +320,16 @@ class TestRunner(): def __init__(self, platform: str, - simulator: Literal['gvsoc', 'banshee', 'qemu', 'vsim', 'vsim.gui', 'host', 'board', 'none'], + simulator: Literal['gvsoc', 'banshee', 'qemu', 'vsim', 'vsim.gui', 'verilator', 'host', 'board', + 'none'], tiling: bool, argument_parser: TestRunnerArgumentParser, gen_args: str = "", cmake_args: str = ""): - if simulator not in ['gvsoc', 'banshee', 'qemu', 'vsim', 'vsim.gui', 'host', 'board', 'none']: + if simulator not in ['gvsoc', 'banshee', 'qemu', 'vsim', 'vsim.gui', 'verilator', 'host', 'board', 'none']: raise ValueError( - f"Invalid emulator {simulator} (valid options are 'gvsoc', 'banshee', 'qemu', 'vsim', 'vsim.gui', 'host', 'board', 'none')!" + f"Invalid emulator {simulator} (valid options are 'gvsoc', 'banshee', 'qemu', 'vsim', 'vsim.gui', 'verilator', 'host', 'board', 'none')!" ) if tiling is not argument_parser.tiling_arguments: diff --git a/DeeployTest/test_dmas.py b/DeeployTest/test_dmas.py index 84ee8a6d1a..9d1caad769 100644 --- a/DeeployTest/test_dmas.py +++ b/DeeployTest/test_dmas.py @@ -353,7 +353,7 @@ def test_snitch_dma(test_shape, doublebuffer, deeploy_test_dir, toolchain, toolc test_name = test_name_clean, test_dir = gen_dir, platform = platform, - simulator = 'gvsoc', + simulator = 'verilator', tiling = True, gen_dir = gen_dir, build_dir = build_dir, diff --git a/DeeployTest/test_platforms.py b/DeeployTest/test_platforms.py index e473cdc704..f17ca6d3cc 100644 --- a/DeeployTest/test_platforms.py +++ b/DeeployTest/test_platforms.py @@ -105,9 +105,10 @@ def param_id(param): "model_tests": SOFTHIER_MODEL_TESTS, "default_num_clusters": SOFTHIER_DEFAULT_NUM_CLUSTERS, }, + # GVSoC cannot run the upgraded cluster atm. "snitch": { "platform": "Snitch", - "simulator": "gvsoc", + "simulator": "verilator", "kernel_tests": SNITCH_KERNEL_TESTS, "model_tests": SNITCH_MODEL_TESTS, "default_num_cores": SNITCH_DEFAULT_NUM_CORES, @@ -581,7 +582,7 @@ def test_snitch_tiled_kernels_l2_singlebuffer(test_params, deeploy_test_dir, too config = create_test_config( test_name = test_name, platform = "Snitch", - simulator = "gvsoc", + simulator = PLATFORM_CONFIGS["snitch"]["simulator"], deeploy_test_dir = deeploy_test_dir, toolchain = toolchain, toolchain_dir = toolchain_dir, @@ -611,7 +612,7 @@ def test_snitch_tiled_models_l2_singlebuffer(test_params, deeploy_test_dir, tool config = create_test_config( test_name = test_name, platform = "Snitch", - simulator = "gvsoc", + simulator = PLATFORM_CONFIGS["snitch"]["simulator"], deeploy_test_dir = deeploy_test_dir, toolchain = toolchain, toolchain_dir = toolchain_dir, diff --git a/DeeployTest/test_snitch_config.py b/DeeployTest/test_snitch_config.py index 18acfa685d..d61d1e7118 100644 --- a/DeeployTest/test_snitch_config.py +++ b/DeeployTest/test_snitch_config.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 """Test configuration for Snitch platform.""" -# Snitch platform supports gvsoc, banshee, vsim simulators +# Snitch platform supports verilator, banshee, vsim simulators # Default configuration: 9 cores DEFAULT_NUM_CORES = 9 @@ -17,7 +17,6 @@ "Kernels/FP32/MatMul", "Kernels/FP32/Mul/Regular", "Kernels/FP32/Mul/Scalar", - "Kernels/FP32/RMSNorm/single_fused_op", "Kernels/FP32/Softmax/Regular", "Kernels/Integer/Add/Large", "Kernels/Integer/Add/Regular", diff --git a/DeeployTest/test_snitch_tiled_config.py b/DeeployTest/test_snitch_tiled_config.py index 1842b00461..fe26bd7a0f 100644 --- a/DeeployTest/test_snitch_tiled_config.py +++ b/DeeployTest/test_snitch_tiled_config.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 """Test configuration for Snitch platform (tiled).""" -# Snitch tiled platform supports gvsoc, banshee, vsim simulators +# Snitch tiled platform supports verilator, banshee, vsim simulators # Default configuration: 9 cores, L2 default memory level DEFAULT_NUM_CORES = 9 @@ -19,8 +19,8 @@ "Kernels/FP32/Mul/Scalar": [2000, 5000, 10000], "Kernels/FP32/RMSNorm/single_fused_op": [2000, 5000, 10000], "Kernels/FP32/Softmax/Regular": [2000, 5000, 10000], - "Kernels/FP32/GEMM/Regular": [2000, 5000, 10000], - "Kernels/FP32/GEMM/TransB": [2000, 5000, 10000], + "Kernels/FP32/GEMM/Regular": [5000, 10000], + "Kernels/FP32/GEMM/TransB": [5000, 10000], "Kernels/Integer/Add/Large": [5000, 10000], "Kernels/Integer/Softmax/Large": [5000, 10000], "Kernels/Integer/iNoNorm": [5000, 10000], diff --git a/Makefile b/Makefile index f007f105c1..b1b53228d5 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ LLVM_COMMIT_HASH ?= 1ccb97ef1789b8c574e3fcab0de674e11b189b96 PICOLIBC_COMMIT_HASH ?= 31ff1b3601b379e4cab63837f253f59729ce1fef PULP_SDK_COMMIT_HASH ?= 7f4f22516157a1b7c55bcbbc72ca81326180b3b4 MEMPOOL_COMMIT_HASH ?= affd45d94e05e375a6966af6a762deeb182a7bd6 -SNITCH_COMMIT_HASH ?= e02cc9e3f24b92d4607455d5345caba3eb6273b2 +SNITCH_COMMIT_HASH ?= 5b2fccd96c42812774c20ab2f9b811e164809789 SOFTHIER_COMMIT_HASH ?= 0 # bowwang: to be updated GVSOC_COMMIT_HASH ?= edfcd8398840ceb1e151711befa06678b05f06a0 MINIMALLOC_COMMMIT_HASH ?= e9eaf54094025e1c246f9ec231b905f8ef42a29d @@ -448,21 +448,46 @@ ${TOOLCHAIN_DIR}/snitch_cluster: cd ${TOOLCHAIN_DIR} && \ git clone https://github.com/pulp-platform/snitch_cluster.git && \ cd ${TOOLCHAIN_DIR}/snitch_cluster && git checkout ${SNITCH_COMMIT_HASH} && \ - git submodule update --init --recursive && \ - git checkout ${SNITCH_COMMIT_HASH} && git apply ${TOOLCHAIN_DIR}/snitch_cluster.patch + git -c url."https://github.com/".insteadOf="git@github.com:" \ + submodule update --init --recursive && \ + git apply --3way ${TOOLCHAIN_DIR}/snitch_cluster.patch ${SNITCH_INSTALL_DIR}: ${TOOLCHAIN_DIR}/snitch_cluster mkdir -p ${SNITCH_INSTALL_DIR} cp -r ${TOOLCHAIN_DIR}/snitch_cluster/ ${SNITCH_INSTALL_DIR}/../ cd ${SNITCH_INSTALL_DIR} && \ mkdir tmp && \ - TMPDIR=tmp pip install -r python-requirements.txt && rm -rf tmp && \ - bender vendor init && \ - cd ${SNITCH_INSTALL_DIR}/target/snitch_cluster && \ - make LLVM_BINROOT=${LLVM_INSTALL_DIR}/bin sw/runtime/banshee sw/runtime/rtl sw/math + TMPDIR=tmp pip install . && rm -rf tmp && \ + make SN_LLVM_BINROOT=${LLVM_INSTALL_DIR}/bin \ + SN_RISCV_CC="${LLVM_INSTALL_DIR}/bin/clang -target riscv32-unknown-elf -isystem ${LLVM_INSTALL_DIR}/picolibc/riscv/rv32imafd/include" \ + SN_RISCV_CXX="${LLVM_INSTALL_DIR}/bin/clang++ -target riscv32-unknown-elf -isystem ${LLVM_INSTALL_DIR}/picolibc/riscv/rv32imafd/include" \ + sn-runtime snitch_runtime: ${SNITCH_INSTALL_DIR} +SNITCH_RISCV_ARCH ?= rv32imafd +SNITCH_RTL_RISCV_FLAGS = -target riscv32-unknown-elf \ + -isystem ${LLVM_INSTALL_DIR}/picolibc/riscv/${SNITCH_RISCV_ARCH}/include \ + -L${LLVM_INSTALL_DIR}/picolibc/riscv/${SNITCH_RISCV_ARCH}/lib \ + -L${LLVM_INSTALL_DIR}/lib/clang/15.0.0/lib/baremetal/${SNITCH_RISCV_ARCH} \ + -Wno-unused-command-line-argument + +# Prefix command for verilator, empty when it is on PATH as in the container. +# On IIS machines, use SNITCH_VERILATOR_SEPP=oseda. +SNITCH_VERILATOR_SEPP ?= + +SNITCH_RTL_MAKE_ARGS = SN_LLVM_BINROOT=${LLVM_INSTALL_DIR}/bin \ + SN_RISCV_CC="${LLVM_INSTALL_DIR}/bin/clang ${SNITCH_RTL_RISCV_FLAGS}" \ + SN_RISCV_CXX="${LLVM_INSTALL_DIR}/bin/clang++ ${SNITCH_RTL_RISCV_FLAGS}" \ + SN_VERILATOR_SEPP="${SNITCH_VERILATOR_SEPP}" + +${SNITCH_INSTALL_DIR}/target/sim/build/bin/snitch_cluster.vlt: ${SNITCH_INSTALL_DIR} + cd ${SNITCH_INSTALL_DIR} && \ + make ${SNITCH_RTL_MAKE_ARGS} rtl && \ + make ${SNITCH_RTL_MAKE_ARGS} verilator + +snitch_verilator: ${SNITCH_INSTALL_DIR}/target/sim/build/bin/snitch_cluster.vlt + ${TOOLCHAIN_DIR}/gvsoc: cd ${TOOLCHAIN_DIR} && \ git clone https://github.com/gvsoc/gvsoc.git && \ @@ -530,9 +555,7 @@ xtensor: ${XTENSOR_INSTALL_DIR} ${XSIMD_INSTALL_DIR} ${TOOLCHAIN_DIR}/qemu: cd ${TOOLCHAIN_DIR} && \ - git clone https://github.com/qemu/qemu.git --depth 1 -b stable-6.1 && \ - cd ${TOOLCHAIN_DIR}/qemu && \ - git submodule update --init --recursive + git clone https://github.com/qemu/qemu.git --depth 1 -b stable-6.1 ${QEMU_INSTALL_DIR}: ${TOOLCHAIN_DIR}/qemu cd ${TOOLCHAIN_DIR}/qemu/ && \ diff --git a/TargetLibraries/Generic/inc/DeeployBasicMath.h b/TargetLibraries/Generic/inc/DeeployBasicMath.h index 2023b9e725..2afce5edbf 100644 --- a/TargetLibraries/Generic/inc/DeeployBasicMath.h +++ b/TargetLibraries/Generic/inc/DeeployBasicMath.h @@ -28,6 +28,13 @@ #include #include +// The Generic target library is compiled as C. Platforms that compile their +// generated code as C++ (Snitch) must see these declarations with C linkage, +// or the mangled call will not match the definition at link time. +#ifdef __cplusplus +extern "C" { +#endif + #include "macros.h" #include "types.h" #include "utils.h" @@ -65,4 +72,8 @@ #include "kernel/Sqrt.h" #include "kernel/Swish.h" +#ifdef __cplusplus +} +#endif + #endif //__DEEPLOY_BASIC_MATH_HEADER_ diff --git a/TargetLibraries/Snitch/CMakeLists.txt b/TargetLibraries/Snitch/CMakeLists.txt index a2dd6703c7..77a17cee9f 100644 --- a/TargetLibraries/Snitch/CMakeLists.txt +++ b/TargetLibraries/Snitch/CMakeLists.txt @@ -8,6 +8,7 @@ file(GLOB_RECURSE SOURCES include(cmake/snitch-runtime-precompiled.cmake) +set_source_files_properties(${SOURCES} PROPERTIES LANGUAGE CXX) add_deeploy_library(deeploysnitch STATIC ${SOURCES}) target_include_directories(deeploysnitch PUBLIC diff --git a/TargetLibraries/Snitch/cmake/snitch-runtime-precompiled.cmake b/TargetLibraries/Snitch/cmake/snitch-runtime-precompiled.cmake index 85a509a83c..18a83010d1 100644 --- a/TargetLibraries/Snitch/cmake/snitch-runtime-precompiled.cmake +++ b/TargetLibraries/Snitch/cmake/snitch-runtime-precompiled.cmake @@ -5,9 +5,8 @@ set(SNITCH_RUNTIME_BASE_INCLUDE ${SNITCH_RUNTIME_HOME}/src ${SNITCH_RUNTIME_HOME}/api + ${SNITCH_RUNTIME_HOME}/impl ${SNITCH_RUNTIME_HOME}/../deps/riscv-opcodes # TODO: generate riscv-opcodes whatever - ${SNITCH_RUNTIME_HOME}/../math/include # TODO: generate riscv-opcodes whatever - ${SNITCH_HOME}/sw/math/arch/riscv64/ ) set(SNITCH_RUNTIME_OMP_INCLUDE @@ -15,38 +14,14 @@ set(SNITCH_RUNTIME_OMP_INCLUDE ${SNITCH_RUNTIME_HOME}/api/omp ) -if(banshee_simulation) - set(SNITCH_CLUSTER_INCLUDE - ${SNITCH_CLUSTER_HOME}/sw/runtime/common - ${SNITCH_CLUSTER_HOME}/sw/runtime/banshee - ${SNITCH_CLUSTER_HOME}/sw/runtime/banshee/src - ) - set(SNITCH_CLUSTER_LINK_INCLUDE - ${SNITCH_CLUSTER_HOME}/sw/math/build - ${SNITCH_CLUSTER_HOME}/sw/runtime/banshee - ${SNITCH_CLUSTER_HOME}/sw/runtime/banshee/build - ) -else() - set(SNITCH_CLUSTER_INCLUDE - ${SNITCH_CLUSTER_HOME}/sw/runtime/common - ${SNITCH_CLUSTER_HOME}/sw/runtime/rtl - ${SNITCH_CLUSTER_HOME}/sw/runtime/rtl/src - ) - set(SNITCH_CLUSTER_LINK_INCLUDE - ${SNITCH_CLUSTER_HOME}/sw/math/build - ${SNITCH_CLUSTER_HOME}/sw/runtime/rtl - ${SNITCH_CLUSTER_HOME}/sw/runtime/rtl/build - ) -endif() - set(SNITCH_CLUSTER_LINK_OPTIONS -Wl,--gc-sections -T ${SNITCH_RUNTIME_HOME}/base.ld ) -set(SNITCH_RUNTIME_INCLUDE ${SNITCH_RUNTIME_BASE_INCLUDE} ${SNITCH_RUNTIME_OMP_INCLUDE} ${SNITCH_CLUSTER_INCLUDE}) +set(SNITCH_RUNTIME_INCLUDE ${SNITCH_RUNTIME_BASE_INCLUDE} ${SNITCH_RUNTIME_OMP_INCLUDE}) add_library(snitch-runtime INTERFACE) -target_link_directories(snitch-runtime INTERFACE ${SNITCH_CLUSTER_LINK_INCLUDE}) -target_link_libraries(snitch-runtime INTERFACE ${SNITCH_CLUSTER_LINK_OPTIONS} libsnRuntime.a libmath.a) \ No newline at end of file +target_link_directories(snitch-runtime INTERFACE ${SNITCH_RUNTIME_HOME}/build ${SNITCH_RUNTIME_HOME}/impl) +target_link_libraries(snitch-runtime INTERFACE ${SNITCH_CLUSTER_LINK_OPTIONS} libsnRuntime.a) \ No newline at end of file diff --git a/TargetLibraries/Snitch/inc/DeeploySnitchMath.h b/TargetLibraries/Snitch/inc/DeeploySnitchMath.h index f686e597ca..8513170afb 100644 --- a/TargetLibraries/Snitch/inc/DeeploySnitchMath.h +++ b/TargetLibraries/Snitch/inc/DeeploySnitchMath.h @@ -40,6 +40,7 @@ typedef float v2f32 __attribute__((vector_size(8))); #include "kernel/Softmax.h" #include "kernel/UniformRequantShift.h" #include "kernel/iNoNorm.h" +#include "kernel/iSoftmax.h" #include "dmaStruct.h" diff --git a/TargetLibraries/Snitch/inc/kernel/Add.h b/TargetLibraries/Snitch/inc/kernel/Add.h index dc08482021..e6cc131a4d 100644 --- a/TargetLibraries/Snitch/inc/kernel/Add.h +++ b/TargetLibraries/Snitch/inc/kernel/Add.h @@ -12,4 +12,13 @@ void Add_fp32(float32_t *input1, float32_t *input2, float32_t *output, uint32_t size, uint32_t is_scalar); +void SnitchAdd(int8_t *pIn1, int8_t *pIn2, int32_t *pOut, uint32_t size, + int32_t offset); + +void snitch_nn_add_i8_i8_i8( + int8_t *pIn1, int8_t *pIn2, int8_t *pOut, int32_t in1_mul, int32_t in1_add, + uint16_t in1_shift, int32_t in2_mul, int32_t in2_add, uint16_t in2_shift, + int32_t out_mul, int32_t out_add, uint16_t out_shift, uint16_t dim_im_in_x, + uint16_t dim_im_in_y, uint16_t ch_im_in, int out_requant_flag); + #endif // __DEEPLOY_MATH_ADD_KERNEL_HEADER_ diff --git a/TargetLibraries/Snitch/inc/kernel/iSoftmax.h b/TargetLibraries/Snitch/inc/kernel/iSoftmax.h index fb68d04adf..f07895126e 100644 --- a/TargetLibraries/Snitch/inc/kernel/iSoftmax.h +++ b/TargetLibraries/Snitch/inc/kernel/iSoftmax.h @@ -13,7 +13,7 @@ void SnitchSoftmax_u8_u8(uint8_t *data_in, uint8_t *data_out, uint32_t *lastDimBuffer, uint32_t size, uint32_t lastDimLength, int32_t coeffB, int32_t coeffC, int32_t log2); -void StnichSoftmax_i8_u8(int8_t *data_in, uint8_t *data_out, +void SnitchSoftmax_i8_u8(int8_t *data_in, uint8_t *data_out, uint32_t *lastDimBuffer, uint32_t size, uint32_t lastDimLength, int32_t coeffB, int32_t coeffC, int32_t log2); diff --git a/TargetLibraries/Snitch/src/CycleCounter.c b/TargetLibraries/Snitch/src/CycleCounter.c index 3861c421c1..cf9f40ac83 100644 --- a/TargetLibraries/Snitch/src/CycleCounter.c +++ b/TargetLibraries/Snitch/src/CycleCounter.c @@ -14,7 +14,7 @@ static uint32_t instr_end[NUM_CORES] __attribute__((section(".l1"))); static uint32_t running[NUM_CORES] __attribute__((section(".l1"))); void ResetTimer() { - snrt_reset_perf_counter(SNRT_PERF_CNT0); + snrt_reset_perf_counter(0); uint32_t const core_id = snrt_global_core_idx(); uint32_t _timer_init = read_csr(mcycle); uint32_t _instr_init = read_csr(minstret); @@ -27,7 +27,8 @@ void ResetTimer() { void StartTimer() { if (snrt_is_dm_core()) { - snrt_start_perf_counter(SNRT_PERF_CNT0, SNRT_PERF_CNT_CYCLES, 0); + snrt_cfg_perf_counter(0, PERF_METRIC__CYCLE, 0); + snrt_start_perf_counter(0); } uint32_t const core_id = snrt_global_core_idx(); timer_init[core_id] = read_csr(mcycle); @@ -37,7 +38,7 @@ void StartTimer() { void StopTimer() { if (snrt_is_dm_core()) { - snrt_stop_perf_counter(SNRT_PERF_CNT0); + snrt_stop_perf_counter(0); } uint32_t const core_id = snrt_global_core_idx(); timer_end[core_id] = read_csr(mcycle); diff --git a/TargetLibraries/Snitch/src/Util.c b/TargetLibraries/Snitch/src/Util.c index 35ef97ea59..32cf53de2d 100644 --- a/TargetLibraries/Snitch/src/Util.c +++ b/TargetLibraries/Snitch/src/Util.c @@ -18,6 +18,6 @@ int deeploy_log(const char *__restrict fmt, ...) { return ret; } -void *deeploy_malloc(const size_t size) { return snrt_l1alloc(size); } +void *deeploy_malloc(const size_t size) { return snrt_l1_alloc(size); } void deeploy_free(void *const __attribute__((unused)) ptr) {} diff --git a/TargetLibraries/Snitch/src/snitch_nn_add_i8_i8_i8.c b/TargetLibraries/Snitch/src/snitch_nn_add_i8_i8_i8.c index b735e60704..504cc81873 100644 --- a/TargetLibraries/Snitch/src/snitch_nn_add_i8_i8_i8.c +++ b/TargetLibraries/Snitch/src/snitch_nn_add_i8_i8_i8.c @@ -40,8 +40,8 @@ snitch_nn_add_i8_i8_i8(int8_t *pIn1, int8_t *pIn2, int8_t *pOut, int8_t *target2 = pIn2 + start * ch_im_in2_r * dim_im_in_x; int8_t *pOutBuffer = pOut + start * ch_im_out_r * dim_im_in_x; - int a = 0; - int b = 0; + int8_t a = 0; + int8_t b = 0; int8_t *target1_ext = &a; int8_t *target2_ext = &b; diff --git a/cmake/common.cmake b/cmake/common.cmake index 9d1aaba7d2..01fc29c9d5 100644 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -9,7 +9,7 @@ add_compile_definitions( ) add_compile_options( - -std=gnu99 + $<$:-std=gnu99> -fdiagnostics-color=always @@ -25,8 +25,6 @@ add_compile_options( ) add_link_options( - -std=gnu99 - -fdiagnostics-color=always -Wunused-variable diff --git a/cmake/snitch/snitch.cmake b/cmake/snitch/snitch.cmake index a67f3ddc54..083f1475ef 100644 --- a/cmake/snitch/snitch.cmake +++ b/cmake/snitch/snitch.cmake @@ -7,7 +7,7 @@ if(NOT DEFINED ENV{SNITCH_HOME}) endif() set(SNITCH_HOME $ENV{SNITCH_HOME}) -set(SNITCH_RUNTIME_HOME ${SNITCH_HOME}/sw/snRuntime) +set(SNITCH_RUNTIME_HOME ${SNITCH_HOME}/sw/runtime) add_compile_definitions( DEEPLOY_SNITCH_PLATFORM @@ -19,7 +19,7 @@ set(num_threads ${NUM_CORES}) macro(add_snitch_cluster_vsim_simulation name) add_custom_target(vsim_${name} - WORKING_DIRECTORY ${SNITCH_HOME}/target/snitch_cluster + WORKING_DIRECTORY ${SNITCH_HOME}/target/sim/build DEPENDS ${name} COMMAND ${QUESTA} bin/snitch_cluster.vsim ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${name} || true @@ -32,7 +32,7 @@ endmacro() macro(add_snitch_cluster_vsim_gui_simulation name) add_custom_target(vsim.gui_${name} - WORKING_DIRECTORY ${SNITCH_HOME}/target/snitch_cluster + WORKING_DIRECTORY ${SNITCH_HOME}/target/sim/build DEPENDS ${name} COMMAND ${QUESTA} bin/snitch_cluster.vsim.gui ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${name} || true @@ -43,8 +43,22 @@ macro(add_snitch_cluster_vsim_gui_simulation name) ) endmacro() +macro(add_snitch_cluster_verilator_simulation name) + add_custom_target(verilator_${name} + WORKING_DIRECTORY ${SNITCH_HOME}/target/sim/build + DEPENDS ${name} + COMMAND bin/snitch_cluster.vlt + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${name} || true + COMMENT "Simulating deeploytest with verilator" + POST_BUILD + USES_TERMINAL + VERBATIM + ) +endmacro() + add_compile_options( -ffast-math + $<$:-Wno-c++11-narrowing> ) add_link_options( diff --git a/cmake/snitch/snitch_cluster/snitch_cluster.cmake b/cmake/snitch/snitch_cluster/snitch_cluster.cmake index 91d9392bb0..53c3464b38 100644 --- a/cmake/snitch/snitch_cluster/snitch_cluster.cmake +++ b/cmake/snitch/snitch_cluster/snitch_cluster.cmake @@ -2,6 +2,8 @@ # # SPDX-License-Identifier: Apache-2.0 -set(SNITCH_CLUSTER_HOME ${SNITCH_HOME}/target/snitch_cluster) +set(SNITCH_CLUSTER_HOME ${SNITCH_HOME}) -set(BANSHEE_CONFIG ${SNITCH_CLUSTER_HOME}/src/banshee.yaml CACHE INTERNAL "source_list") \ No newline at end of file +if(DEFINED ENV{BANSHEE_INSTALL_DIR}) + set(BANSHEE_CONFIG ${SNITCH_CLUSTER_HOME}/src/banshee.yaml CACHE INTERNAL "source_list") +endif() \ No newline at end of file diff --git a/toolchain/snitch_cluster.patch b/toolchain/snitch_cluster.patch index 2b368db713..c9dc391768 100644 --- a/toolchain/snitch_cluster.patch +++ b/toolchain/snitch_cluster.patch @@ -1,104 +1,12 @@ -diff --git a/sw/snRuntime/base.ld b/sw/snRuntime/base.ld -index d0979b7..171921d 100644 ---- a/sw/snRuntime/base.ld -+++ b/sw/snRuntime/base.ld -@@ -66,7 +66,7 @@ SECTIONS - .cbss : - { - __cbss_start = .; -- *(.cbss .cbss.*) -+ KEEP(*(.cbss .cbss.*)) - __cbss_end = .; - } >L3 - -diff --git a/sw/snRuntime/src/alloc.h b/sw/snRuntime/src/alloc.h -index ba1dee9..f79769f 100644 ---- a/sw/snRuntime/src/alloc.h -+++ b/sw/snRuntime/src/alloc.h -@@ -69,6 +69,8 @@ inline void *snrt_l3alloc(size_t size) { - - // TODO: L3 alloc size check - -+ size = ALIGN_UP(size, MIN_CHUNK_SIZE); -+ - void *ret = (void *)alloc->next; - alloc->next += size; - return ret; -diff --git a/sw/snRuntime/src/team.c b/sw/snRuntime/src/team.c -index a9eb840..5290e1d 100644 ---- a/sw/snRuntime/src/team.c -+++ b/sw/snRuntime/src/team.c -@@ -10,6 +10,10 @@ extern uint32_t snrt_global_core_idx(); - - extern uint32_t snrt_global_core_num(); - -+extern uint32_t snrt_global_compute_core_num(); -+ -+extern uint32_t snrt_global_compute_core_idx(); -+ - extern uint32_t snrt_cluster_idx(); - - extern uint32_t snrt_cluster_num(); -diff --git a/target/snitch_cluster/sw/runtime/rtl/src/putchar.c b/target/snitch_cluster/sw/runtime/rtl/src/putchar.c -index 0ad9500..215c8b1 100644 ---- a/target/snitch_cluster/sw/runtime/rtl/src/putchar.c -+++ b/target/snitch_cluster/sw/runtime/rtl/src/putchar.c -@@ -5,16 +5,19 @@ - extern uintptr_t volatile tohost, fromhost; - - // Rudimentary string buffer for putc calls. --extern uint32_t _edram; - #define PUTC_BUFFER_LEN (1024 - sizeof(size_t)) --struct putc_buffer_header { -+ -+typedef struct { - size_t size; - uint64_t syscall_mem[8]; --}; --static volatile struct putc_buffer { -- struct putc_buffer_header hdr; -+} putc_buffer_header_t; -+ -+typedef struct putc_buffer { -+ putc_buffer_header_t hdr; - char data[PUTC_BUFFER_LEN]; --} *const putc_buffer = (void *)&_edram; -+} putc_buffer_t; -+ -+static volatile putc_buffer_t putc_buffer[SNRT_CLUSTER_NUM*SNRT_CLUSTER_CORE_NUM] __attribute__((section(".dram"))); - - // Provide an implementation for putchar. - void _putchar(char character) { -diff --git a/target/snitch_cluster/sw/toolchain.mk b/target/snitch_cluster/sw/toolchain.mk -index d363059..4a84955 100644 ---- a/target/snitch_cluster/sw/toolchain.mk -+++ b/target/snitch_cluster/sw/toolchain.mk -@@ -26,11 +26,13 @@ RISCV_OBJDUMP ?= $(LLVM_BINROOT)/llvm-objdump - RISCV_DWARFDUMP ?= $(LLVM_BINROOT)/llvm-dwarfdump - - # Compiler flags -+RISCV_CFLAGS += -target riscv32-unknown-elf - RISCV_CFLAGS += $(addprefix -I,$(INCDIRS)) - RISCV_CFLAGS += -mcpu=snitch - RISCV_CFLAGS += -menable-experimental-extensions - RISCV_CFLAGS += -mabi=ilp32d - RISCV_CFLAGS += -mcmodel=medany -+RISCV_CFLAGS += -isystem ${LLVM_INSTALL_DIR}/picolibc/riscv/rv32imafd/include - # RISCV_CFLAGS += -mno-fdiv # Not supported by Clang - # RISCV_CFLAGS += -ffast-math - RISCV_CFLAGS += -fno-builtin-printf -@@ -46,12 +48,14 @@ endif - RISCV_CFLAGS += -D__DEFINED_uint64_t - - # Linker flags -+RISCV_LDFLAGS += -target riscv32-unknown-elf - RISCV_LDFLAGS += -fuse-ld=$(RISCV_LD) - RISCV_LDFLAGS += -nostartfiles - RISCV_LDFLAGS += -nostdlib - RISCV_LDFLAGS += -lc - RISCV_LDFLAGS += -L$(LLVM_BINROOT)/../lib/clang/$(LLVM_VER)/lib/ - RISCV_LDFLAGS += -lclang_rt.builtins-riscv32 -+RISCV_LDFLAGS += -isystem ${LLVM_INSTALL_DIR}/picolibc/riscv/rv32imafd/include - - # Archiver flags - RISCV_ARFLAGS = rcs +diff --git a/cfg/default.json b/cfg/default.json +index 7ccc78a..e3c44a0 100644 +--- a/cfg/default.json ++++ b/cfg/default.json +@@ -100,6 +100,7 @@ + xssr: true, + xfrep: true, + xcopift: true, ++ Xdiv_sqrt: true, + xdma: false, + xf16: true, + xf16alt: true,