Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,5 @@ CHANGELOG_GEN.md
# Container Artifacts
.pyusbip/
.cache/

CLAUDE.md
12 changes: 11 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,16 @@ elseif(platform STREQUAL PULPOpen)
elseif(platform STREQUAL GAP9)
message(STATUS "Building for platform 'GAP9'")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(ENV{KCONFIG_CONFIG} DeeployTest/Platforms/GAP9/sdk.config)

# Select SDK config based on simulator type
if(SIMULATOR STREQUAL "board")
set(ENV{KCONFIG_CONFIG} DeeployTest/Platforms/GAP9/sdk_board.config)
message(STATUS "[GAP9] Using board SDK configuration")
else()
set(ENV{KCONFIG_CONFIG} DeeployTest/Platforms/GAP9/sdk_gvsoc.config)
message(STATUS "[GAP9] Using GVSoC SDK configuration")
endif()

include($ENV{GAP_SDK_HOME}/utils/cmake/setup.cmake)
elseif(platform STREQUAL Generic)
message(STATUS "Building for platform 'Generic'")
Expand Down Expand Up @@ -225,6 +234,7 @@ endif()
if(platform STREQUAL GAP9)
project(${TESTNAME} LANGUAGES C ASM)
include(${CMAKE_CURRENT_LIST_DIR}/cmake/gap9/gap9_gvsoc.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/cmake/gap9/gap9_board.cmake)
add_compile_options(
-Wno-error=unknown-pragmas
)
Expand Down
5 changes: 5 additions & 0 deletions DeeployTest/Platforms/GAP9/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ target_include_directories(${ProjectId} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/inc)
target_link_libraries(${ProjectId} PRIVATE network deeploylib)
target_compile_options(${ProjectId} INTERFACE network)
add_gvsoc_emulation(${ProjectId} "gap9.evk")
add_board_deployment(${ProjectId} "gap9.evk")

if(POWER_MEASUREMENT)
target_compile_definitions(${ProjectId} PRIVATE POWER_MEASUREMENT)
endif()

# RW: Waive sign comparison warnings from pulp_nn_utils.h
target_compile_options(network PRIVATE
Expand Down
34 changes: 34 additions & 0 deletions DeeployTest/Platforms/GAP9/sdk_board.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# SPDX-FileCopyrightText: 2025 ETH Zurich and University of Bologna
#
# SPDX-License-Identifier: Apache-2.0

CONFIG_BOARD_GAP9MOD_V1_0_B=y
CONFIG_BOARD_GAP9EVK_V1_3=y

CONFIG_DRIVER_CLUSTER=y
CONFIG_DRIVER_CLUSTER_CONF_PROPERTY_ICACHE_CONF=0x7FF

CONFIG_DRIVER_TYPE_FLASH=y
CONFIG_DRIVER_TYPE_RAM=y

CONFIG_DRIVER_MRAM=y
CONFIG_READFS_FLASH_TYPE_OSPI=y

CONFIG_DRIVER_READFS=y
# CONFIG_READFS_FLASH_TYPE_MRAM=y

CONFIG_DRIVER_APS256XXN=y
CONFIG_DRIVER_RAM_API=y

CONFIG_ENABLE_LIBMATH=y

# OS float printf
CONFIG_IO_PRINTF_FLOAT_ENABLE=y
CONFIG_IO_PRINTF_FLOAT_EXPONENT_ENABLE=y

# CONFIG_PLATFORM_GVSOC=y
CONFIG_PLATFORM_BOARD=y
# CONFIG_DRIVER_CLUSTERDECOMPRESSOR=n

#CONFIG_CL_MASTER_CORE_STACK_SIZE=14000
#CONFIG_CL_SLAVE_CORE_STACK_SIZE=1000
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ CONFIG_IO_PRINTF_FLOAT_ENABLE=y
CONFIG_IO_PRINTF_FLOAT_EXPONENT_ENABLE=y

CONFIG_PLATFORM_GVSOC=y
# CONFIG_PLATFORM_BOARD=y
# CONFIG_DRIVER_CLUSTERDECOMPRESSOR=n

# GAP9 cluster stack size configuration
# Uncomment and adjust these values if you need to modify stack sizes:
# CONFIG_CL_MASTER_CORE_STACK_SIZE=14000
# CONFIG_CL_SLAVE_CORE_STACK_SIZE=1000
# CONFIG_CL_SLAVE_CORE_STACK_SIZE=1000
21 changes: 21 additions & 0 deletions DeeployTest/Platforms/GAP9/src/deeploytest.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
// RW: Remove MAINSTACKSIZE because gap9-sdk does not use it
#define SLAVESTACKSIZE 3800

#ifdef POWER_MEASUREMENT
unsigned int GPIOs = 89;
#define WRITE_GPIO(x) pi_gpio_pin_write(GPIOs, x)
#endif

struct pi_device cluster_dev;
uint32_t total_cycles = 0;

Expand Down Expand Up @@ -78,6 +83,13 @@ void RunNetworkWrapper(void *args) {
}

int main(void) {

#ifdef POWER_MEASUREMENT
pi_pad_function_set(GPIOs, 1);
pi_gpio_pin_configure(GPIOs, PI_GPIO_OUTPUT);
pi_gpio_pin_write(GPIOs, 0);
#endif

#ifndef CI
uint32_t core_id = pi_core_id(), cluster_id = pi_cluster_id();
printf("[%d %d] Hello World!\n", cluster_id, core_id);
Expand Down Expand Up @@ -119,8 +131,17 @@ int main(void) {

pi_cluster_task(&cluster_task, RunNetworkWrapper, NULL);
cluster_task.slave_stack_size = SLAVESTACKSIZE;

#ifdef POWER_MEASUREMENT
WRITE_GPIO(1);
#endif

pi_cluster_send_task_to_cl(&cluster_dev, &cluster_task);

#ifdef POWER_MEASUREMENT
WRITE_GPIO(0);
#endif

#ifndef CI
printf("Output:\r\n");
#endif
Expand Down
5 changes: 5 additions & 0 deletions DeeployTest/deeployRunner_gap9.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
# Define parser setup callback to add GAP9-specific arguments
def setup_parser(parser):
parser.add_argument('--cores', type = int, default = 8, help = 'Number of cores (default: 8)\n')
parser.add_argument('--powerMeasurement',
action = 'store_true',
default = False,
help = 'Enable GPIO toggling around the inference window for external '
'power measurement (e.g. PPK2). Only meaningful with -s board.\n')

sys.exit(
main(default_platform = "GAP9",
Expand Down
5 changes: 5 additions & 0 deletions DeeployTest/deeployRunner_tiled_gap9.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
# Define parser setup callback to add GAP9-specific arguments
def setup_parser(parser):
parser.add_argument('--cores', type = int, default = 8, help = 'Number of cores (default: 8)\n')
parser.add_argument('--powerMeasurement',
action = 'store_true',
default = False,
help = 'Enable GPIO toggling around the inference window for external '
'power measurement (e.g. PPK2). Only meaningful with -s board.\n')

sys.exit(
main(default_platform = "GAP9",
Expand Down
36 changes: 28 additions & 8 deletions DeeployTest/testUtils/core/execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
# SPDX-License-Identifier: Apache-2.0

import os
import re
import shutil
import subprocess
import sys
from pathlib import Path

from Deeploy.Logging import DEFAULT_LOGGER as log
Expand Down Expand Up @@ -148,6 +148,12 @@ def build_binary(config: DeeployTestConfig) -> None:
raise RuntimeError(f"Build failed for {config.test_name}")


# Source: https://stackoverflow.com/a/38662876
def escapeAnsi(line):
ansi_escape = re.compile(r'(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]')
return ansi_escape.sub('', line)


def run_simulation(config: DeeployTestConfig, skip: bool = False) -> TestResult:
"""
Run simulation and parse output.
Expand Down Expand Up @@ -191,15 +197,29 @@ def run_simulation(config: DeeployTestConfig, skip: bool = False) -> TestResult:

log.debug(f"[Execution] Simulation command: {' '.join(cmd)}")

result = subprocess.run(cmd, capture_output = True, text = True, env = env)

if result.stdout:
print(result.stdout, end = '')
if result.stderr:
print(result.stderr, end = '', file = sys.stderr)
cmd_str = " ".join(cmd)
with subprocess.Popen(cmd_str,
stdout = subprocess.PIPE,
stderr = subprocess.STDOUT,
shell = True,
encoding = 'utf-8') as process:

with open('out.txt', 'a', encoding = 'utf-8') as fileHandle:
fileHandle.write(
f"################## Testing {config.test_dir} on {config.platform} Platform ##################\n")

result = ""
while True:
output = process.stdout.readline()
if output == '' and process.poll() is not None:
break
if output:
print(output.strip())
result += output
fileHandle.write(f"{escapeAnsi(output)}")

# Parse output for error count and cycles
test_result = parse_test_output(result.stdout, result.stderr)
test_result = parse_test_output(result, "")

if not test_result.success and test_result.error_count == -1:
log.warning(f"Could not parse error count from output")
Expand Down
10 changes: 8 additions & 2 deletions DeeployTest/testUtils/deeployRunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ def __init__(self,
dest = 'simulator',
type = str,
default = None,
help = 'Simulator to use (gvsoc, banshee, qemu, vsim, host, none)\n')
help = 'Simulator to use: gvsoc, banshee, qemu, vsim, host, none — '
'or "board" to flash and run on the physical target (GAP9 only)\n')
self.add_argument('-v', action = 'count', dest = 'verbose', default = 0, help = 'Increase verbosity level\n')
self.add_argument('-D',
dest = 'cmake',
Expand Down Expand Up @@ -395,7 +396,6 @@ def main(default_platform: Optional[str] = None,
# Extract platform-specific CMake args from parsed args if available
if platform_specific_cmake_args is None:
platform_specific_cmake_args = []

# Check for platform-specific arguments in args object and build CMake args
if hasattr(args, 'cores'):
platform_specific_cmake_args.append(f"-DNUM_CORES={args.cores}")
Expand All @@ -405,6 +405,12 @@ def main(default_platform: Optional[str] = None,
if hasattr(args, 'num_clusters'):
platform_specific_cmake_args.append(f"-DNUM_CLUSTERS={args.num_clusters}")

if hasattr(args, 'powerMeasurement') and args.powerMeasurement:
platform_specific_cmake_args.append("-DPOWER_MEASUREMENT=ON")

if platform == 'GAP9':
platform_specific_cmake_args.append("-D SIMULATOR=" + simulator)

config = create_config_from_args(args, platform, simulator, tiling_enabled, platform_specific_cmake_args)

print_configuration(config)
Expand Down
2 changes: 1 addition & 1 deletion DeeployTest/testUtils/pytestRunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def get_worker_id() -> str:
def create_test_config(
test_name: str,
platform: str,
simulator: Literal['gvsoc', 'banshee', 'qemu', 'vsim', 'vsim.gui', 'host', 'none'],
simulator: Literal['gvsoc', 'banshee', 'qemu', 'vsim', 'vsim.gui', 'host', 'board', 'none'],
deeploy_test_dir: str,
toolchain: str,
toolchain_dir: Optional[str],
Expand Down
10 changes: 6 additions & 4 deletions DeeployTest/testUtils/testRunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,15 +292,15 @@ class TestRunner():

def __init__(self,
platform: str,
simulator: Literal['gvsoc', 'banshee', 'qemu', 'vsim', 'vsim.gui', 'host', 'none'],
simulator: Literal['gvsoc', 'banshee', 'qemu', 'vsim', 'vsim.gui', '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', 'none']:
if simulator not in ['gvsoc', 'banshee', 'qemu', 'vsim', 'vsim.gui', 'host', 'board', 'none']:
raise ValueError(
f"Invalid emulator {simulator} (valid options are 'gvsoc', 'banshee', 'qemu', 'vsim', 'vsim.gui', 'host', 'none')!"
f"Invalid emulator {simulator} (valid options are 'gvsoc', 'banshee', 'qemu', 'vsim', 'vsim.gui', 'host', 'board', 'none')!"
)

if tiling is not argument_parser.tiling_arguments:
Expand Down Expand Up @@ -381,7 +381,7 @@ def configure_cmake_project(self):
else:
self.cmake_args += " -D gvsoc_simulation=OFF"

command = f"$CMAKE -D TOOLCHAIN={self._args.toolchain} -D GVSOC_INSTALL_DIR={self._dir_gvsoc} -D TOOLCHAIN_INSTALL_DIR={self._dir_toolchain} -D GENERATED_SOURCE={self._dir_gen} -D platform={self._platform} {self.cmake_args} -B {self._dir_build} -D TESTNAME={self._name_test} .."
command = f"$CMAKE -D TOOLCHAIN={self._args.toolchain} -D GVSOC_INSTALL_DIR={self._dir_gvsoc} -D TOOLCHAIN_INSTALL_DIR={self._dir_toolchain} -D GENERATED_SOURCE={self._dir_gen} -D platform={self._platform} -D SIMULATOR={self._simulator} {self.cmake_args} -B {self._dir_build} -D TESTNAME={self._name_test} .."

if self._args.verbose >= 3:
command = "VERBOSE=1 " + command + " --log-level debug"
Expand Down Expand Up @@ -414,6 +414,8 @@ def run_simulation(self, out_file = 'out.txt'):

if self._simulator == 'host':
command = f"{self._dir_build}/bin/{self._name_test}"
elif self._simulator == 'board':
command = f"$CMAKE --build {self._dir_build} --target board_{self._name_test}"
else:
command = f"$CMAKE --build {self._dir_build} --target {self._simulator}_{self._name_test}"

Expand Down
27 changes: 25 additions & 2 deletions README_GAP9.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,31 @@ pip install -e .

```sh
cd /app/Deeploy/DeeployTest
python deeployRunner_gap9.py -t ./Tests/Kernels/FP32/MatMul
python deeployRunner_tiled_gap9.py -t ./Tests/Kernels/FP32/MatMul

# Run on GVSoC (default simulator)
python deeployRunner_gap9.py -t ./Tests/Kernels/FP32/MatMul
python deeployRunner_tiled_gap9.py -t ./Tests/Kernels/FP32/MatMul
```

#### Run on the GAP9 board

Pass `-s board` to flash the binary to the connected board via `gapy` and run it
(`board_<test>` CMake target). USB passthrough must already be set up — see
[Use A Real GAP9 Board](#use-a-real-gap9-board-usbip-via-gap9-runsh) below.

```sh
python deeployRunner_gap9.py -t ./Tests/Kernels/FP32/Add/Regular -s board
python deeployRunner_tiled_gap9.py -t ./Tests/Kernels/FP32/Add/Regular -s board
```

#### External power measurement (PPK2)

`--powerMeasurement` toggles a GPIO around the inference window so an external
probe (e.g. Nordic PPK2) can gate its measurement to the compute region. Only
meaningful with `-s board`.

```sh
python deeployRunner_gap9.py -t ./Tests/Kernels/FP32/Add/Regular -s board --powerMeasurement
```

### Use A Real GAP9 Board (USB/IP via gap9-run.sh)
Expand Down
Loading
Loading