Skip to content
Draft

Magia #166

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
17 changes: 17 additions & 0 deletions Deeploy/Targets/Magia/Bindings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# 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 Deeploy.Targets.Magia.Templates import AddTemplate

BasicTransformer = CodeTransformation([])

MagiaAddBindings = [
NodeBinding(AddChecker([PointerClass(int8_t), PointerClass(int8_t)], [PointerClass(int32_t)]),
AddTemplate.referenceTemplate, BasicTransformer),
]
40 changes: 40 additions & 0 deletions Deeploy/Targets/Magia/Deployer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# 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.
]
113 changes: 113 additions & 0 deletions Deeploy/Targets/Magia/Platform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# SPDX-FileCopyrightText: 2026 ETH Zurich and University of Bologna
#
# SPDX-License-Identifier: Apache-2.0

import numpy as np
import onnx_graphsurgeon as gs

from Deeploy.DeeployTypes import ConstantBuffer, DeploymentEngine, DeploymentPlatform, NetworkContext, NodeMapper, \
NodeTemplate, StructBuffer, TopologyOptimizer, TransientBuffer, VariableBuffer
from Deeploy.Targets.Generic.Layers import AddLayer
from Deeploy.Targets.Generic.Parsers import AddParser
from Deeploy.Targets.Generic.Templates import AllocateTemplate as BasicAllocateTemplate
from Deeploy.Targets.Magia.Bindings import MagiaAddBindings
from Deeploy.Targets.Magia.Templates import AllocateTemplate, FreeTemplate

AddMapper = NodeMapper(AddParser(), MagiaAddBindings)

MagiaMapping = {'Add': AddLayer([AddMapper])}


class MagiaVariableBuffer(VariableBuffer):

initTemplate = AllocateTemplate.magiaInitTemplate
allocTemplate = AllocateTemplate.magiaAllocateTemplate
deallocTemplate = FreeTemplate.magiaFreeTemplate

def _bufferRepresentation(self):

if hasattr(self, "_memoryLevel"):
memoryLevel = self._memoryLevel
else:
memoryLevel = None

return {
"type": self._instance,
"name": self.name,
"size": int(np.prod(self.shape)),
"_memoryLevel": memoryLevel
}


class MagiaTransientBuffer(TransientBuffer):

initTemplate = AllocateTemplate.magiaInitTemplate
allocTemplate = AllocateTemplate.magiaAllocateTemplate
deallocTemplate = FreeTemplate.magiaFreeTemplate

def _bufferRepresentation(self):

if hasattr(self, "_memoryLevel"):
memoryLevel = self._memoryLevel
else:
memoryLevel = None

return {"type": self._type, "name": self.name, "size": self.size, "_memoryLevel": memoryLevel}


class MagiaConstantBuffer(ConstantBuffer):

initTemplate = AllocateTemplate.magiaGlobalInitTemplate
allocTemplate = AllocateTemplate.magiaGlobalAllocateTemplate
deallocTemplate = FreeTemplate.magiaGlobalTemplate

def _bufferRepresentation(self):
operatorRepresentation = super()._bufferRepresentation()

if hasattr(self, "_memoryLevel"):
memoryLevel = self._memoryLevel
else:
memoryLevel = None

operatorRepresentation["_memoryLevel"] = memoryLevel

return operatorRepresentation


class MagiaStructBuffer(StructBuffer):

initTemplate = BasicAllocateTemplate.referenceStructInitTemplate
allocTemplate = BasicAllocateTemplate.referenceStructAllocateTemplate
deallocTemplate = NodeTemplate("")


MagiaOptimizer = TopologyOptimizer(
[
# Insert here the ONNX optimization passes.
],
name = "MagiaOptimizer")

_includeList = ["tile.h", "idma.h", "redmule.h", "eventunit.h"]


class MagiaMeshEngine(DeploymentEngine):

def __init__(self,
name: str,
Mapping = MagiaMapping,
initCode = "",
includeList = _includeList,
n_tiles: int = 4) -> None:
super().__init__(name, Mapping, initCode, includeList)
self.n_tiles = n_tiles


class MagiaPlatform(DeploymentPlatform):

def __init__(self,
engines = [MagiaMeshEngine("MagiaMesh")],
variableBuffer = MagiaVariableBuffer,
constantBuffer = MagiaConstantBuffer,
structBuffer = MagiaStructBuffer,
transientBuffer = MagiaTransientBuffer) -> None:
super().__init__(engines, variableBuffer, constantBuffer, structBuffer, transientBuffer)
37 changes: 37 additions & 0 deletions Deeploy/Targets/Magia/Templates/AddTemplate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# SPDX-FileCopyrightText: 2024 ETH Zurich and University of Bologna
#
# SPDX-License-Identifier: Apache-2.0

from typing import Dict, List, Tuple

from Deeploy.DeeployTypes import NetworkContext, NodeTemplate, OperatorRepresentation


class _MagiaAddTemplate(NodeTemplate):

def alignToContext(self, ctxt: NetworkContext,
operatorRepresentation: OperatorRepresentation) -> Tuple[NetworkContext, Dict, List[str]]:

data_in_1 = ctxt.lookup(operatorRepresentation['data_in_1'])
data_in_2 = ctxt.lookup(operatorRepresentation['data_in_2'])
data_out = ctxt.lookup(operatorRepresentation['data_out'])

input_1_offset = 0
if hasattr(data_in_1, "_signed") and hasattr(data_in_1, "nLevels"):
input_1_offset = (data_in_1._signed == 0) * int(data_in_1.nLevels / 2)
input_2_offset = 0
if hasattr(data_in_2, "_signed") and hasattr(data_in_2, "nLevels"):
input_2_offset = (data_in_2._signed == 0) * int(data_in_2.nLevels / 2)
output_offset = 0
if hasattr(data_out, "_signed") and hasattr(data_out, "nLevels"):
output_offset = -(data_out._signed == 0) * int(data_out.nLevels // 2)

operatorRepresentation['offset'] = input_1_offset + input_2_offset + output_offset

return ctxt, operatorRepresentation, []


referenceTemplate = _MagiaAddTemplate("""
// Magia Add (Name: ${nodeName}, Op: ${nodeOp})
MAGIA_Add(${data_in_1}, ${data_in_2}, ${data_out}, ${size}, ${offset});
""")
25 changes: 25 additions & 0 deletions Deeploy/Targets/Magia/Templates/AllocateTemplate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# SPDX-FileCopyrightText: 2021 ETH Zurich and University of Bologna
#
# SPDX-License-Identifier: Apache-2.0

from Deeploy.DeeployTypes import NodeTemplate

magiaInitTemplate = NodeTemplate("${type.typeName} ${name};\n")

magiaAllocateTemplate = NodeTemplate("""
% if _memoryLevel == "L1":
${name} = (${type.typeName}) magia_l1_malloc(sizeof(${type.referencedType.typeName}) * ${size});\n
% elif _memoryLevel == "L2" or _memoryLevel is None:
${name} = (${type.typeName}) magia_l2_malloc(sizeof(${type.referencedType.typeName}) * ${size});\n
% endif
""")

magiaGlobalInitTemplate = NodeTemplate("""
% if _memoryLevel == "L1":
static ${type.referencedType.typeName} ${name}[${size}] = {${values}};\n
% elif _memoryLevel == "L2" or _memoryLevel is None:
extern ${type.referencedType.typeName} ${name}[${size}] = {${values}};\n
% endif
""")

magiaGlobalAllocateTemplate = NodeTemplate("")
15 changes: 15 additions & 0 deletions Deeploy/Targets/Magia/Templates/FreeTemplate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# SPDX-FileCopyrightText: 2023 ETH Zurich and University of Bologna
#
# SPDX-License-Identifier: Apache-2.0

from Deeploy.DeeployTypes import NodeTemplate

magiaFreeTemplate = NodeTemplate("""
% if _memoryLevel == "L1":
magia_l1_free(${name}, sizeof(${type.referencedType.typeName}) * ${size});
% elif _memoryLevel == "L2" or _memoryLevel is None:
magia_l2_free(${name}, sizeof(${type.referencedType.typeName}) * ${size});
% endif
""")

magiaGlobalTemplate = NodeTemplate("magia_l2_free(${name}, sizeof(${type.referencedType.typeName}) * ${size});")
5 changes: 5 additions & 0 deletions Deeploy/Targets/Magia/Templates/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# SPDX-FileCopyrightText: 2024 ETH Zurich and University of Bologna
#
# SPDX-License-Identifier: Apache-2.0

from . import *
Empty file.
113 changes: 113 additions & 0 deletions DeeployTest/Platforms/Magia/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2025 University of Bologna and Fondazione Chips-IT.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Alberto Dequino <alberto.dequino@unibo.it>
// Alex Marchioni <alex.marchioni@chips.it>

#include <stdint.h>
#include "testinputs.h"
#include "testoutputs.h"
#include "Network.h"



int main(void) {

uint32_t hartid = get_hartid();
uint32_t l1_tile_base = get_l1_base(hartid);
uint32_t cycle_start, cycle_stop;

/* Init tile's iDMA, Redmule, fsync, event-unit */
idma_config_t idma_cfg = {.hartid = hartid};
idma_controller_t idma_ctrl = {
.base = NULL,
.cfg = &idma_cfg,
.api = &idma_api,
};

redmule_config_t redmule_cfg = {.hartid = hartid};
redmule_controller_t redmule_ctrl = {
.base = NULL,
.cfg = &redmule_cfg,
.api = &redmule_api,
};

fsync_config_t fsync_cfg = {.hartid = hartid};
fsync_controller_t fsync_ctrl = {
.base = NULL,
.cfg = &fsync_cfg,
.api = &fsync_api,
};

fsync_init(&fsync_ctrl);
idma_init(&idma_ctrl);
redmule_init(&redmule_ctrl);

eu_config_t eu_cfg = {.hartid = hartid};
eu_controller_t eu_ctrl = {
.base = NULL,
.cfg = &eu_cfg,
.api = &eu_api,
};
eu_init(&eu_ctrl);
eu_fsync_init(&eu_ctrl, 0);
eu_redmule_init(&eu_ctrl, 0);
eu_idma_init(&eu_ctrl, 0);


/* initialization */
InitNetwork();

fsync_sync_level(&fsync_ctrl, MAX_SYNC_LVL - 1, 0);
eu_fsync_wait(&eu_ctrl, WAIT_MODE);

/* input copy */
// TODO: check if memcopy is necessary!!!
if (hartid == 0) {
for (uint32_t buf = 0; buf < num_inputs; buf++) {
memcpy(inputs[buf], _inputs[buf], inputs_bytes[buf]);
}
}

fsync_sync_global(&fsync_ctrl);
eu_fsync_wait(&eu_ctrl, WAIT_MODE);

/* execution */
cycle_start = perf_get_cycles();
RunNetwork();
cycle_stop = perf_get_cycles();
printf("id: %d, cycles: %d\n", hartid, cycle_stop - cycle_start);

fsync_sync_global(&fsync_ctrl);
eu_fsync_wait(&eu_ctrl, WAIT_MODE);

/* comparison */
uint32_t errors = 0;
uint32_t tests = 0;
OUTPUTTYPE *computed_buf;
OUTPUTTYPE *expected_buf;
if (hartid == 0) {
for (uint32_t buf = 0; buf < num_outputs; buf++) {
tests += outputs_bytes[buf] / sizeof(OUTPUTTYPE);
for (uint32_t i = 0; i < outputs_bytes[buf] / sizeof(OUTPUTTYPE); i++) {
OUTPUTTYPE expected = ((OUTPUTTYPE *)_outputs[buf])[i];
OUTPUTTYPE computed = ((OUTPUTTYPE *)outputs[buf])[i];
OUTPUTTYPE diff = (computed > expected) ? (computed - expected) : (expected - computed);
if(diff > 0) {
if (ISOUTPUTFLOAT) {
// printf("Expected %10.6f computed: %10.6f diff: %10.6f (at index %u in output %u)\n",
// expected, computed, diff, i, buf);
} else {
printf("Expected %d computed: %d diff: %d (at index %u in output %u)\n",
expected, computed, diff, i, buf);
}
errors++;
}
}
}
printf("Number of errors: %d\n", errors);
}

return errors;
}
Loading