Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 33 additions & 11 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,25 +1,47 @@
next_steps.*
build/
output*
list/
transcript
# Environment & secrets
.env
.env.*
.env.local

# IDE & editor
.vscode/
gvsoc_config.json

# python
__pycache__/
*.pyc

# Build & output
build/
output/
output_*.txt
next_steps.*
power_report.csv

# Logs & traces
log.txt
trace_file.txt
insn.txt
debug_*
compile_commands.json

# CMake
CMakeCache.txt
cmake_install.cmake
CMakeFiles
CMakeFiles/
compile_commands.json
/*/Makefile
/*/*/Makefile
/*/*/*/Makefile
/*/*/*/*/Makefile
log.txt
gvsoc/

# Test & CI
testsuite.py
test.conf
testsuite*
test.conf
testlogs/

# Project-specific
gvsoc/
gvsoc_config.json
power_report.csv
list/
transcript
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
set(CMAKE_VERBOSE_MAKEFILE TRUE)

set(CMAKE_EXE_LINKER_FLAGS_INIT "--specs=nosys.specs")
set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE
set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE
"-Wl,--whole-archive <LIBRARY> -Wl,--no-whole-archive"
)
set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED True)
Expand Down Expand Up @@ -80,6 +80,7 @@ add_subdirectory(targets)
add_subdirectory(hal)
# add_subdirectory(devices)
add_subdirectory(drivers)
add_subdirectory(kernels)

################################################################################
# Testing #
Expand Down
60 changes: 52 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright (C) 2025 ETH Zurich and University of Bologna
#
# Licensed under the Solderpad Hardware License, Version 0.51
# (the "License"); you may not use this file except in compliance
# Licensed under the Solderpad Hardware License, Version 0.51
# (the "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
Expand All @@ -15,7 +15,7 @@
#
# Authors: Victor Isachi <victor.isachi@unibo.it>
# Alberto Dequino <alberto.dequino@unibo.it>
#
#
# Magia-sdk Makefile

SHELL := /bin/bash
Expand Down Expand Up @@ -47,6 +47,14 @@ ISA ?= rv32imcxgap9
gui ?= 0
tiles ?= 2

LLVM_CMAKE ?= cmake
LLVM_DIR ?= llvm
LLVM_REPO ?= git@github.com:pulp-platform/llvm-project.git
LLVM_COMMIT ?= b494f2d8dde88723026db8ec16ac6c7ee1e140ca
LLVM_INSTALL_DIR ?= $(CURR_DIR)/llvm/install
LLVM_BUILD_DIR ?= $(LLVM_DIR)/llvm-project/build
LLVM_JOBS ?= 8

tiles_2 := $(shell echo $$(( $(tiles) * $(tiles) )))
tiles_log := $(shell awk 'BEGIN { printf "%.0f", log($(tiles_2))/log(2) }')
tiles_log_real := $(shell awk 'BEGIN { printf "%.0f", log($(tiles))/log(2) }')
Expand Down Expand Up @@ -85,7 +93,7 @@ endif
set_mesh:
ifeq ($(tiles), 1)
$(eval mesh_dv=0)
endif
endif

run: set_mesh
@echo 'Magia is available at https://github.com/pulp-platform/MAGIA.git'
Expand All @@ -107,10 +115,10 @@ else ifeq ($(platform), rtl)
cp ./build/bin/$(test) $(BUILD_DIR)/build/verif
objcopy --srec-len 1 --output-target=srec $(BIN) $(BIN).s19
scripts/parse_s19.pl $(BIN).s19 > $(BIN).txt
python3 scripts/s19tomem.py $(BIN).txt $(BUILD_DIR)/build/stim_instr.txt $(BUILD_DIR)/build/stim_data.txt
python3 scripts/s19tomem.py $(BIN).txt $(BUILD_DIR)/build/stim_instr.txt $(BUILD_DIR)/build/stim_data.txt
cd $(BUILD_DIR) && \
cp -sf ../../../sim/modelsim.ini modelsim.ini && \
ln -sfn ../../../sim/work work
ln -sfn ../../../sim/work work
riscv32-unknown-elf-objdump -d -S -Mmarch=$(ISA) $(BIN) > $(BIN).dump
riscv32-unknown-elf-objdump -d -l -s -Mmarch=$(ISA) $(BIN) > $(BIN).objdump
python3 scripts/objdump2itb.py $(BIN).objdump > $(BIN).itb
Expand Down Expand Up @@ -171,8 +179,44 @@ gvsoc_init:
cd $(GVSOC_DIR) && \
git submodule update --init --recursive && \
cd core && \
git checkout lz/magia-v2-core && \
git checkout master && \
cd ../pulp && \
git checkout lz/magia-v2-pulp
git checkout master

llvm:
mkdir -p $(LLVM_DIR)
if [ ! -d "$(LLVM_DIR)/llvm-project/.git" ]; then \
cd $(LLVM_DIR) && git clone $(LLVM_REPO); \
fi
cd $(LLVM_DIR)/llvm-project && \
git checkout $(LLVM_COMMIT) && \
git submodule update --init --recursive --jobs=$(LLVM_JOBS) .
mkdir -p $(LLVM_INSTALL_DIR)
cd $(LLVM_DIR)/llvm-project && mkdir -p build && cd build && \
$(LLVM_CMAKE) \
-DCMAKE_INSTALL_PREFIX=$(LLVM_INSTALL_DIR) \
-DCMAKE_CXX_COMPILER=${CXX} \
-DCMAKE_C_COMPILER=${CC} \
-DLLVM_OPTIMIZED_TABLEGEN=True \
-DLLVM_ENABLE_PROJECTS="clang;lld" \
-DLLVM_TARGETS_TO_BUILD="RISCV" \
-DLLVM_DEFAULT_TARGET_TRIPLE=riscv32-unknown-elf \
-DLLVM_ENABLE_LLD=False \
-DLLVM_APPEND_VC_REV=ON \
-DCMAKE_BUILD_TYPE=Release \
../llvm && \
make -j$(LLVM_JOBS) all && \
make install

deploy:
ifndef test
$(error Proper formatting is: make deploy test=<test_name> platform=rtl|gvsoc)
endif
ifndef platform
$(error Proper formatting is: make run test=<test_name> platform=rtl|gvsoc)
endif
python deployment/generate.py \
-s ./deployment/tests/$(test) \
-d ./tests/magia/mesh/$(test) && \
make clean build tiles=$(tiles) compiler=$(compiler) eval=$(eval) && \
make run test=test_$(test) platform=$(platform)
72 changes: 66 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ The following *optional* parameters can be specified when running the make comma
1. Initialize the GVSoC submodule:

`make gvsoc_init`

2. Build the Magia architecture (*this command may take time and return an error, please be patient.*):

`make MAGIA <target_platform> <tiles> <build_mode> <fsync_mode>`

And/Or the GVSoC module:
Expand Down Expand Up @@ -90,7 +90,7 @@ The following *optional* parameters can be specified when running the make comma

`make run test=<test_name> <platform>`

***WARNING: YOU HAVE TO REBUILD BOTH RTL/GVSOC AND THE TEST BINARY EACH TIME YOU WANT TO TEST A MAGIA MESH WITH A DIFFERENT NUMBER OF TILES.***
***WARNING: YOU HAVE TO REBUILD BOTH RTL/GVSOC AND THE TEST BINARY EACH TIME YOU WANT TO TEST A MAGIA MESH WITH A DIFFERENT NUMBER OF TILES.***

If you want to run gvsoc or a binary from outside the magia-sdk directory you can edit the **GVSOC_ABS_PATH** and **BIN_ABS_PATH** option in Makefile or directly on the *run* command line.

Expand Down Expand Up @@ -122,7 +122,7 @@ To add your own test, you have to integrate a new test folder inside the **tests
4. Add to the *\<test_name\>* directory:

1. A new CMakeList.txt file following this template:

set(TEST_NAME <test_name>)

file(GLOB_RECURSE TEST_SRCS
Expand All @@ -142,11 +142,71 @@ To add your own test, you have to integrate a new test folder inside the **tests
TARGET ${TEST_NAME}
POST_BUILD
COMMAND ${CMAKE_OBJDUMP} -dhS -Mmarch=${ISA} $<TARGET_FILE:${TEST_NAME}> > $<TARGET_FILE:${TEST_NAME}>.s)

2. An **src** directory containing your test's source (.c) files

3. An **include** directory containing your test's header (.h) files


## Deployment with Deeploy

[Deeploy](https://github.com/pulp-platform/Deeploy) is a code generation framework that takes an ONNX model and produces C inference code targeting a specific hardware platform. In this SDK it is used to automatically generate mesh tests from a network description.

### User: generating and running a test

Each deployable test lives under `deployment/tests/<test_name>/` and must contain three files:
```
deployment/tests/<test_name>/
├── network.onnx # ONNX model
├── inputs.npz # reference input tensors
└── outputs.npz # reference output tensors
```

To generate the corresponding test, build it, and run it on the simulator, use:

```
make deploy test=<test_name> platform=rtl|gvsoc [tiles=<tiles>] [compiler=<compiler>] [eval=<eval>]
```

This will:
1. Generate a complete test under `tests/magia/mesh/<test_name>/` (C sources, headers, `CMakeLists.txt`)
2. Build the test binary (`make clean build`)
3. Run it on the selected platform (`make run`)

The available `tiles`, `compiler`, and `eval` parameters are the same as described in the [Getting started](#getting-started-and-usage) section.

### Developer: how the pipeline works

The code generation is driven by `deployment/generate.py`, which can also be invoked directly:

```
python deployment/generate.py -s deployment/tests/<test_name> -d tests/magia/mesh/<test_name> [-v]
```

The script performs the following steps:

1. **Load** the ONNX model and the reference I/O tensors from the source directory.
2. **Deploy** the model usign the Deeploy Target for Magia (defined in `deployment/MagiaDeeployTarget/`)
3. **Generate** the following files in the destination directory:
- `include/network.h` — buffer declarations and `InitNetwork`/`RunNetwork` prototypes
- `src/network.c` — generated inference code calling into `kernels/`
- `include/test.h` — C arrays with the reference inputs and outputs
- `src/test.c` — test harness (copied from `deployment/test.c`)
- `CMakeLists.txt` — build file linking against `runtime`, `hal`, and `kernels`


#### Adding support for a new operator

Supporting a new ONNX operator requires four coordinated additions:

1. **Kernel** — implement the C kernel in `kernels/src/` and expose it in `kernels/include/`.
2. **Template** — add a Deeploy `NodeTemplate` in `deployment/MagiaDeeployTarget/Templates/` that renders the C call to the kernel.
3. **Bindings** — add the type bindings for the operator in `deployment/MagiaDeeployTarget/Bindings.py`.
4. **Registration** — add a `NodeMapper` using the appropriate Deeploy parser and the new bindings, then register it in the `MagiaMapping` dict inside `deployment/MagiaDeeployTarget/Platform.py`.

See the `Add` operator (`AddTemplate.py`, `Bindings.py`, `kernels/src/add.c`) as a reference implementation.


## Folder Structure

### README.md
Expand All @@ -171,7 +231,7 @@ Contains the weak definitions of this SDK APIs. These are the API instruction th
Contains the architecture-specific implementation and source code for the HAL APIs. Despite each implementation having different names, thanks to an aliasing system the programmer can use the same name for the same API instruction on different architectures.

### devices
Nothing there.
Nothing there.

If MAGIA ever evolves to have a host-offload mechanism, this folder will contain the trampoline functions.

Expand Down
23 changes: 23 additions & 0 deletions deployment/MagiaDeeployTarget/Bindings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# SPDX-FileCopyrightText: 2024 ETH Zurich and University of Bologna
#
# SPDX-License-Identifier: Apache-2.0


from Deeploy.AbstractDataTypes import PointerClass
from Deeploy.CommonExtensions.DataTypes import int8_t, int32_t
from Deeploy.DeeployTypes import CodeTransformation, NodeBinding
from Deeploy.Targets.Generic.TypeCheckers import AddChecker
from MagiaDeeployTarget.Templates import AddTemplate

BasicTransformer = CodeTransformation([])

MagiaAddBindings = [
NodeBinding(
AddChecker(
[PointerClass(int8_t), PointerClass(int8_t)],
[PointerClass(int32_t)]
),
AddTemplate.referenceTemplate,
BasicTransformer,
),
]
46 changes: 46 additions & 0 deletions deployment/MagiaDeeployTarget/Deployer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# SPDX-FileCopyrightText: 2026 ETH Zurich and University of Bologna
#
# SPDX-License-Identifier: Apache-2.0

from typing import Callable, Dict, List, Type

import numpy as np
import onnx_graphsurgeon as gs

from Deeploy.AbstractDataTypes import Pointer
from Deeploy.CommonExtensions.NetworkDeployers.SignPropDeployer import SignPropDeployer
from Deeploy.DeeployTypes import ConstantBuffer, DeploymentPlatform, NodeTemplate, TopologyOptimizer, VariableBuffer


class MagiaDeployer(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,
inputOffsets = inputOffsets,
)

self.loweringOptimizer.passes += [
# Extra optimizer passes on the lowering optimization pass.
# It seems to be different than the "normal" optimization passes
# defined on the Platform.
]
Loading