Skip to content

Commit 3b011bb

Browse files
Automatic On-Board GAP9 Deployment (#178)
* Add option to deploy on the board for the GAP9 platform * Add proper D flag for GAP9 board * Make pane name agnostic of the config * Fix usbip host resolve for Linux platforms * Fix hostname resolution for Macos * Live print of the simulator cmd * Revert gap9 docker link * Add optional GPIO toggling for power measurements for GAP9 * Format * Cleanup file handles to avoid unhandled exeception in pytest * format * Remove unused GPIO and update gitignore * Align gap9-run.sh mount point with README convention Mount the host working directory to /app/Deeploy inside the container (matching README.md / README_GAP9.md) instead of /app/work. * Document 'board' as a valid -s simulator choice * Clarify -h text for board simulator and powerMeasurement * README_GAP9: document -s board and --powerMeasurement --------- Co-authored-by: Run Wang <samanthawangdl@gmail.com>
1 parent 1f6128f commit 3b011bb

16 files changed

Lines changed: 301 additions & 45 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,5 @@ CHANGELOG_GEN.md
5757
# Container Artifacts
5858
.pyusbip/
5959
.cache/
60+
61+
CLAUDE.md

CMakeLists.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,16 @@ elseif(platform STREQUAL PULPOpen)
3636
elseif(platform STREQUAL GAP9)
3737
message(STATUS "Building for platform 'GAP9'")
3838
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
39-
set(ENV{KCONFIG_CONFIG} DeeployTest/Platforms/GAP9/sdk.config)
39+
40+
# Select SDK config based on simulator type
41+
if(SIMULATOR STREQUAL "board")
42+
set(ENV{KCONFIG_CONFIG} DeeployTest/Platforms/GAP9/sdk_board.config)
43+
message(STATUS "[GAP9] Using board SDK configuration")
44+
else()
45+
set(ENV{KCONFIG_CONFIG} DeeployTest/Platforms/GAP9/sdk_gvsoc.config)
46+
message(STATUS "[GAP9] Using GVSoC SDK configuration")
47+
endif()
48+
4049
include($ENV{GAP_SDK_HOME}/utils/cmake/setup.cmake)
4150
elseif(platform STREQUAL Generic)
4251
message(STATUS "Building for platform 'Generic'")
@@ -225,6 +234,7 @@ endif()
225234
if(platform STREQUAL GAP9)
226235
project(${TESTNAME} LANGUAGES C ASM)
227236
include(${CMAKE_CURRENT_LIST_DIR}/cmake/gap9/gap9_gvsoc.cmake)
237+
include(${CMAKE_CURRENT_LIST_DIR}/cmake/gap9/gap9_board.cmake)
228238
add_compile_options(
229239
-Wno-error=unknown-pragmas
230240
)

DeeployTest/Platforms/GAP9/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ target_include_directories(${ProjectId} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/inc)
2020
target_link_libraries(${ProjectId} PRIVATE network deeploylib)
2121
target_compile_options(${ProjectId} INTERFACE network)
2222
add_gvsoc_emulation(${ProjectId} "gap9.evk")
23+
add_board_deployment(${ProjectId} "gap9.evk")
24+
25+
if(POWER_MEASUREMENT)
26+
target_compile_definitions(${ProjectId} PRIVATE POWER_MEASUREMENT)
27+
endif()
2328

2429
# RW: Waive sign comparison warnings from pulp_nn_utils.h
2530
target_compile_options(network PRIVATE
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# SPDX-FileCopyrightText: 2025 ETH Zurich and University of Bologna
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
CONFIG_BOARD_GAP9MOD_V1_0_B=y
6+
CONFIG_BOARD_GAP9EVK_V1_3=y
7+
8+
CONFIG_DRIVER_CLUSTER=y
9+
CONFIG_DRIVER_CLUSTER_CONF_PROPERTY_ICACHE_CONF=0x7FF
10+
11+
CONFIG_DRIVER_TYPE_FLASH=y
12+
CONFIG_DRIVER_TYPE_RAM=y
13+
14+
CONFIG_DRIVER_MRAM=y
15+
CONFIG_READFS_FLASH_TYPE_OSPI=y
16+
17+
CONFIG_DRIVER_READFS=y
18+
# CONFIG_READFS_FLASH_TYPE_MRAM=y
19+
20+
CONFIG_DRIVER_APS256XXN=y
21+
CONFIG_DRIVER_RAM_API=y
22+
23+
CONFIG_ENABLE_LIBMATH=y
24+
25+
# OS float printf
26+
CONFIG_IO_PRINTF_FLOAT_ENABLE=y
27+
CONFIG_IO_PRINTF_FLOAT_EXPONENT_ENABLE=y
28+
29+
# CONFIG_PLATFORM_GVSOC=y
30+
CONFIG_PLATFORM_BOARD=y
31+
# CONFIG_DRIVER_CLUSTERDECOMPRESSOR=n
32+
33+
#CONFIG_CL_MASTER_CORE_STACK_SIZE=14000
34+
#CONFIG_CL_SLAVE_CORE_STACK_SIZE=1000

DeeployTest/Platforms/GAP9/sdk.config renamed to DeeployTest/Platforms/GAP9/sdk_gvsoc.config

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ CONFIG_IO_PRINTF_FLOAT_ENABLE=y
2727
CONFIG_IO_PRINTF_FLOAT_EXPONENT_ENABLE=y
2828

2929
CONFIG_PLATFORM_GVSOC=y
30+
# CONFIG_PLATFORM_BOARD=y
3031
# CONFIG_DRIVER_CLUSTERDECOMPRESSOR=n
3132

3233
# GAP9 cluster stack size configuration
3334
# Uncomment and adjust these values if you need to modify stack sizes:
3435
# CONFIG_CL_MASTER_CORE_STACK_SIZE=14000
35-
# CONFIG_CL_SLAVE_CORE_STACK_SIZE=1000
36+
# CONFIG_CL_SLAVE_CORE_STACK_SIZE=1000

DeeployTest/Platforms/GAP9/src/deeploytest.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
// RW: Remove MAINSTACKSIZE because gap9-sdk does not use it
1717
#define SLAVESTACKSIZE 3800
1818

19+
#ifdef POWER_MEASUREMENT
20+
unsigned int GPIOs = 89;
21+
#define WRITE_GPIO(x) pi_gpio_pin_write(GPIOs, x)
22+
#endif
23+
1924
struct pi_device cluster_dev;
2025
uint32_t total_cycles = 0;
2126

@@ -78,6 +83,13 @@ void RunNetworkWrapper(void *args) {
7883
}
7984

8085
int main(void) {
86+
87+
#ifdef POWER_MEASUREMENT
88+
pi_pad_function_set(GPIOs, 1);
89+
pi_gpio_pin_configure(GPIOs, PI_GPIO_OUTPUT);
90+
pi_gpio_pin_write(GPIOs, 0);
91+
#endif
92+
8193
#ifndef CI
8294
uint32_t core_id = pi_core_id(), cluster_id = pi_cluster_id();
8395
printf("[%d %d] Hello World!\n", cluster_id, core_id);
@@ -119,8 +131,17 @@ int main(void) {
119131

120132
pi_cluster_task(&cluster_task, RunNetworkWrapper, NULL);
121133
cluster_task.slave_stack_size = SLAVESTACKSIZE;
134+
135+
#ifdef POWER_MEASUREMENT
136+
WRITE_GPIO(1);
137+
#endif
138+
122139
pi_cluster_send_task_to_cl(&cluster_dev, &cluster_task);
123140

141+
#ifdef POWER_MEASUREMENT
142+
WRITE_GPIO(0);
143+
#endif
144+
124145
#ifndef CI
125146
printf("Output:\r\n");
126147
#endif

DeeployTest/deeployRunner_gap9.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
# Define parser setup callback to add GAP9-specific arguments
1313
def setup_parser(parser):
1414
parser.add_argument('--cores', type = int, default = 8, help = 'Number of cores (default: 8)\n')
15+
parser.add_argument('--powerMeasurement',
16+
action = 'store_true',
17+
default = False,
18+
help = 'Enable GPIO toggling around the inference window for external '
19+
'power measurement (e.g. PPK2). Only meaningful with -s board.\n')
1520

1621
sys.exit(
1722
main(default_platform = "GAP9",

DeeployTest/deeployRunner_tiled_gap9.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
# Define parser setup callback to add GAP9-specific arguments
1313
def setup_parser(parser):
1414
parser.add_argument('--cores', type = int, default = 8, help = 'Number of cores (default: 8)\n')
15+
parser.add_argument('--powerMeasurement',
16+
action = 'store_true',
17+
default = False,
18+
help = 'Enable GPIO toggling around the inference window for external '
19+
'power measurement (e.g. PPK2). Only meaningful with -s board.\n')
1520

1621
sys.exit(
1722
main(default_platform = "GAP9",

DeeployTest/testUtils/core/execution.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
# SPDX-License-Identifier: Apache-2.0
44

55
import os
6+
import re
67
import shutil
78
import subprocess
8-
import sys
99
from pathlib import Path
1010

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

150150

151+
# Source: https://stackoverflow.com/a/38662876
152+
def escapeAnsi(line):
153+
ansi_escape = re.compile(r'(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]')
154+
return ansi_escape.sub('', line)
155+
156+
151157
def run_simulation(config: DeeployTestConfig, skip: bool = False) -> TestResult:
152158
"""
153159
Run simulation and parse output.
@@ -191,15 +197,29 @@ def run_simulation(config: DeeployTestConfig, skip: bool = False) -> TestResult:
191197

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

194-
result = subprocess.run(cmd, capture_output = True, text = True, env = env)
195-
196-
if result.stdout:
197-
print(result.stdout, end = '')
198-
if result.stderr:
199-
print(result.stderr, end = '', file = sys.stderr)
200+
cmd_str = " ".join(cmd)
201+
with subprocess.Popen(cmd_str,
202+
stdout = subprocess.PIPE,
203+
stderr = subprocess.STDOUT,
204+
shell = True,
205+
encoding = 'utf-8') as process:
206+
207+
with open('out.txt', 'a', encoding = 'utf-8') as fileHandle:
208+
fileHandle.write(
209+
f"################## Testing {config.test_dir} on {config.platform} Platform ##################\n")
210+
211+
result = ""
212+
while True:
213+
output = process.stdout.readline()
214+
if output == '' and process.poll() is not None:
215+
break
216+
if output:
217+
print(output.strip())
218+
result += output
219+
fileHandle.write(f"{escapeAnsi(output)}")
200220

201221
# Parse output for error count and cycles
202-
test_result = parse_test_output(result.stdout, result.stderr)
222+
test_result = parse_test_output(result, "")
203223

204224
if not test_result.success and test_result.error_count == -1:
205225
log.warning(f"Could not parse error count from output")

DeeployTest/testUtils/deeployRunner.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ def __init__(self,
6565
dest = 'simulator',
6666
type = str,
6767
default = None,
68-
help = 'Simulator to use (gvsoc, banshee, qemu, vsim, host, none)\n')
68+
help = 'Simulator to use: gvsoc, banshee, qemu, vsim, host, none — '
69+
'or "board" to flash and run on the physical target (GAP9 only)\n')
6970
self.add_argument('-v', action = 'count', dest = 'verbose', default = 0, help = 'Increase verbosity level\n')
7071
self.add_argument('-D',
7172
dest = 'cmake',
@@ -404,7 +405,6 @@ def main(default_platform: Optional[str] = None,
404405
# Extract platform-specific CMake args from parsed args if available
405406
if platform_specific_cmake_args is None:
406407
platform_specific_cmake_args = []
407-
408408
# Check for platform-specific arguments in args object and build CMake args
409409
if hasattr(args, 'cores'):
410410
platform_specific_cmake_args.append(f"-DNUM_CORES={args.cores}")
@@ -414,6 +414,12 @@ def main(default_platform: Optional[str] = None,
414414
if hasattr(args, 'num_clusters'):
415415
platform_specific_cmake_args.append(f"-DNUM_CLUSTERS={args.num_clusters}")
416416

417+
if hasattr(args, 'powerMeasurement') and args.powerMeasurement:
418+
platform_specific_cmake_args.append("-DPOWER_MEASUREMENT=ON")
419+
420+
if platform == 'GAP9':
421+
platform_specific_cmake_args.append("-D SIMULATOR=" + simulator)
422+
417423
config = create_config_from_args(args, platform, simulator, tiling_enabled, platform_specific_cmake_args)
418424

419425
print_configuration(config)

0 commit comments

Comments
 (0)