From 6ce945dce0d069cd8c1a7723c534fa8742409c52 Mon Sep 17 00:00:00 2001 From: Germain Haugou Date: Mon, 13 May 2024 18:58:44 +0200 Subject: [PATCH] sw: Add possibility to get ocd putchar on gvsoc (#126) Co-authored-by: Germain Haugou --- sw/snRuntime/src/openocd.h | 34 +++++++++++++++++++ sw/snRuntime/src/start.c | 4 +++ target/snitch_cluster/README.md | 5 +++ .../sw/runtime/rtl/src/putchar.c | 22 ++++++++++++ .../sw/runtime/rtl/src/snitch_cluster_start.c | 2 ++ target/snitch_cluster/sw/toolchain.mk | 6 ++++ 6 files changed, 73 insertions(+) create mode 100644 sw/snRuntime/src/openocd.h diff --git a/sw/snRuntime/src/openocd.h b/sw/snRuntime/src/openocd.h new file mode 100644 index 000000000..699ace9ca --- /dev/null +++ b/sw/snRuntime/src/openocd.h @@ -0,0 +1,34 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +/* riscv semihosting standard: + * IN: a0 holds syscall number + * IN: a1 holds pointer to arg struct + * OUT: a0 holds return value (if exists) + */ +static inline long __ocd_semihost(long n, long _a1) { + register long a0 asm("a0") = n; + register long a1 asm("a1") = _a1; + + // riscv magic values for semihosting + asm volatile( + ".option norvc;\t\n" + "slli zero,zero,0x1f\t\n" + "ebreak\t\n" + "srai zero,zero,0x7\t\n" + ".option rvc;\t\n" + : "+r"(a0) + : "r"(a1)); + + return a0; +} + +static inline int __ocd_semihost_write(int fd, uint8_t *buffer, int len) { + uint32_t args[3] = {(long)fd, (long)buffer, (long)len}; + __asm__ __volatile__("" : : : "memory"); + return __ocd_semihost(0x05, (long)args); +} diff --git a/sw/snRuntime/src/start.c b/sw/snRuntime/src/start.c index 582e93b8e..31f6e7c97 100644 --- a/sw/snRuntime/src/start.c +++ b/sw/snRuntime/src/start.c @@ -99,8 +99,12 @@ static inline void snrt_init_libs() { snrt_alloc_init(); } #ifdef SNRT_CRT0_EXIT static inline void snrt_exit_default(int exit_code) { exit_code = snrt_global_all_to_all_reduction(exit_code); +#ifdef OPENOCD_SEMIHOSTING + if (snrt_global_core_idx() == 0) __ocd_semihost(0x18, (long)exit_code); +#else if (snrt_global_core_idx() == 0) *(snrt_exit_code_destination()) = (exit_code << 1) | 1; +#endif } #ifndef SNRT_CRT0_ALTERNATE_EXIT static inline void snrt_exit(int exit_code) { snrt_exit_default(exit_code); } diff --git a/target/snitch_cluster/README.md b/target/snitch_cluster/README.md index cb2bd2f69..69777ada7 100644 --- a/target/snitch_cluster/README.md +++ b/target/snitch_cluster/README.md @@ -60,6 +60,9 @@ make DEBUG=ON sw # for Banshee simulation (requires slightly different runtime) make SELECT_RUNTIME=banshee DEBUG=ON sw + +# to use OpenOCD semi-hosting for putchar and termination +make DEBUG=ON OPENOCD_SEMIHOSTING=ON sw ``` The `sw` target first generates some C header files which depend on the hardware configuration. Hence, the need to generate the software for the same configuration as your hardware. Afterwards, it recursively invokes the `make` target in the `sw` subdirectory to build the apps/kernels which have been developed in that directory. @@ -70,6 +73,8 @@ The `SELECT_RUNTIME` flag is set by default to `rtl`. To build the software with ___Note:__ the RTL is not the only source which is generated from the configuration file. The software stack also depends on the configuration file. Make sure you always build the software with the same configuration of the hardware you are going to run it on._ +___Note:__ on GVSOC, it is better to use OpenOCD semi-hosting to prevent putchar from disturbing the DRAMSys timing model._ + ### Running a simulation Create the `logs` directory to host the simulation traces: diff --git a/target/snitch_cluster/sw/runtime/rtl/src/putchar.c b/target/snitch_cluster/sw/runtime/rtl/src/putchar.c index 0ad9500f0..ea5841888 100644 --- a/target/snitch_cluster/sw/runtime/rtl/src/putchar.c +++ b/target/snitch_cluster/sw/runtime/rtl/src/putchar.c @@ -2,6 +2,26 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 +#ifdef OPENOCD_SEMIHOSTING + +#include + +#define PUTC_BUFFER_LEN 1024 +static int putchar_index[SNRT_CLUSTER_NUM * SNRT_CLUSTER_CORE_NUM] = {0}; +static char putchar_data[SNRT_CLUSTER_NUM * SNRT_CLUSTER_CORE_NUM] + [PUTC_BUFFER_LEN]; + +// Provide an implementation for putchar. +void _putchar(char character) { + volatile char *buf = putchar_data[snrt_hartid()]; + buf[putchar_index[snrt_hartid()]++] = character; + if (putchar_index[snrt_hartid()] == PUTC_BUFFER_LEN || character == '\n') { + __ocd_semihost_write(1, (uint8_t *)buf, putchar_index[snrt_hartid()]); + putchar_index[snrt_hartid()] = 0; + } +} + +#else extern uintptr_t volatile tohost, fromhost; // Rudimentary string buffer for putc calls. @@ -34,3 +54,5 @@ void _putchar(char character) { buf->hdr.size = 0; } } + +#endif \ No newline at end of file diff --git a/target/snitch_cluster/sw/runtime/rtl/src/snitch_cluster_start.c b/target/snitch_cluster/sw/runtime/rtl/src/snitch_cluster_start.c index effe02495..3a4ab9b7c 100644 --- a/target/snitch_cluster/sw/runtime/rtl/src/snitch_cluster_start.c +++ b/target/snitch_cluster/sw/runtime/rtl/src/snitch_cluster_start.c @@ -11,8 +11,10 @@ #define SNRT_CRT0_POST_BARRIER #define SNRT_CRT0_EXIT +#ifndef OPENOCD_SEMIHOSTING static inline volatile uint32_t* snrt_exit_code_destination() { return (volatile uint32_t*)&tohost; } +#endif #include "start.c" diff --git a/target/snitch_cluster/sw/toolchain.mk b/target/snitch_cluster/sw/toolchain.mk index d363059b9..1b7013177 100644 --- a/target/snitch_cluster/sw/toolchain.mk +++ b/target/snitch_cluster/sw/toolchain.mk @@ -42,6 +42,12 @@ RISCV_CFLAGS += -O3 ifeq ($(DEBUG), ON) RISCV_CFLAGS += -g endif + +ifeq ($(OPENOCD_SEMIHOSTING), ON) +RISCV_CFLAGS += -DOPENOCD_SEMIHOSTING +endif + + # Required by math library to avoid conflict with stdint definition RISCV_CFLAGS += -D__DEFINED_uint64_t