target/espressif: add system level tracing feature 06/7606/6
authorErhan Kurubas <erhan.kurubas@espressif.com>
Thu, 13 Apr 2023 22:07:18 +0000 (00:07 +0200)
committerAntonio Borneo <borneo.antonio@gmail.com>
Sat, 27 May 2023 06:38:51 +0000 (06:38 +0000)
Produces traces compatible with SEGGER SystemView tool.

Signed-off-by: Erhan Kurubas <erhan.kurubas@espressif.com>
Change-Id: If1057309edbb91ed2cf1ebf9137c378d3deb9b88
Reviewed-on: https://review.openocd.org/c/openocd/+/7606
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
doc/openocd.texi
src/target/espressif/Makefile.am
src/target/espressif/esp32_apptrace.c
src/target/espressif/esp32_sysview.c [new file with mode: 0644]
src/target/espressif/esp32_sysview.h [new file with mode: 0644]
src/target/espressif/segger_sysview.h [new file with mode: 0644]

index d0bc3f9f50b0551081682701f2576869e839b56d..9b485c5e1f434f92d85328ef9ee16d36346bcdc4 100644 (file)
@@ -11271,6 +11271,40 @@ w/o OpenOCD command and keeps only the latest data window which fit into the buf
 Data will be stored to specified destination.
 @end deffn
 
+@deffn {Command} {esp sysview} (start file://<outfile1> [file://<outfile2>] [<poll_period> [<trace_size> [<stop_tmo> [<wait4halt> [<skip_size>]]]]])
+Starts @uref{https://www.segger.com/products/development-tools/systemview/, SEGGER SystemView}
+compatible tracing. Data will be stored to specified destination.
+For dual-core chips traces from every core will be saved to separate files.
+Resulting files can be open in "SEGGER SystemView" application.
+@url{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#openocd-systemview-tracing-command-options}
+The meaning of the arguments is identical to @command{esp apptrace start}.
+@end deffn
+
+@deffn {Command} {esp sysview} (stop)
+Stops SystremView compatible tracing started with above command.
+@url{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#openocd-systemview-tracing-command-options}
+@end deffn
+
+@deffn {Command} {esp sysview} (status)
+Requests ongoing SystremView compatible tracing status.
+@url{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#openocd-systemview-tracing-command-options}
+@end deffn
+
+@deffn {Command} {esp sysview_mcore} (start file://<outfile> [<poll_period> [<trace_size> [<stop_tmo> [<wait4halt> [<skip_size>]]]]])
+This command is identical to @command{esp sysview start}, but uses Espressif multi-core extension to
+@uref{https://www.segger.com/products/development-tools/systemview/, SEGGER SystemView} data format.
+Data will be stored to specified destination. Tracing data from all cores are saved in the same file.
+The meaning of the arguments is identical to @command{esp sysview start}.
+@end deffn
+
+@deffn {Command} {esp sysview_mcore} (stop)
+Stops Espressif multi-core SystremView tracing started with above command.
+@end deffn
+
+@deffn {Command} {esp sysview_mcore} (status)
+Requests ongoing Espressif multi-core SystremView tracing status.
+@end deffn
+
 @anchor{softwaredebugmessagesandtracing}
 @section Software Debug Messages and Tracing
 @cindex Linux-ARM DCC support
index c1759ed77f7aea7a9187c87b79106b73addd7d70..14625d4b36eefb50522fe7a90904c0bb25aef24c 100644 (file)
@@ -15,5 +15,8 @@ noinst_LTLIBRARIES += %D%/libespressif.la
        %D%/esp32.c \
        %D%/esp32s2.c \
        %D%/esp32s3.c \
+       %D%/esp32_sysview.c \
+       %D%/esp32_sysview.h \
+       %D%/segger_sysview.h \
        %D%/esp_semihosting.c \
        %D%/esp_semihosting.h
index 291503e530e75f11186f1e7638d160d82072ba49..0c510ffbf83ba2edbfafea701ed2a37b2248f276 100644 (file)
@@ -32,6 +32,8 @@
 #include "esp_xtensa_smp.h"
 #include "esp_xtensa_apptrace.h"
 #include "esp32_apptrace.h"
+#include "esp32_sysview.h"
+#include "segger_sysview.h"
 
 #define ESP32_APPTRACE_USER_BLOCK_CORE(_v_)     ((_v_) >> 15)
 #define ESP32_APPTRACE_USER_BLOCK_LEN(_v_)      ((_v_) & ~BIT(15))
@@ -82,6 +84,8 @@ static int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx *ctx,
 static struct esp32_apptrace_block *esp32_apptrace_free_block_get(struct esp32_apptrace_cmd_ctx *ctx);
 static int esp32_apptrace_handle_trace_block(struct esp32_apptrace_cmd_ctx *ctx,
        struct esp32_apptrace_block *block);
+static int esp32_sysview_start(struct esp32_apptrace_cmd_ctx *ctx);
+static int esp32_sysview_stop(struct esp32_apptrace_cmd_ctx *ctx);
 
 static const bool s_time_stats_enable = true;
 
@@ -1118,10 +1122,7 @@ static int esp32_apptrace_poll(void *priv)
                        return ERROR_FAIL;
                }
        }
-       res =
-               ctx->hw->data_read(ctx->cpus[fired_target_num],
-               target_state[fired_target_num].data_len,
-               block->data,
+       res = ctx->hw->data_read(ctx->cpus[fired_target_num], target_state[fired_target_num].data_len, block->data,
                target_state[fired_target_num].block_id,
                /* do not ack target data in sync mode,
                   esp32_apptrace_handle_trace_block() can write response data and will do ack thereafter */
@@ -1215,6 +1216,11 @@ static int esp32_apptrace_poll(void *priv)
        return ERROR_OK;
 }
 
+static inline bool is_sysview_mode(int mode)
+{
+       return mode == ESP_APPTRACE_CMD_MODE_SYSVIEW || mode == ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE;
+}
+
 static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx)
 {
        if (duration_measure(&ctx->read_time) != 0)
@@ -1222,7 +1228,12 @@ static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx)
        int res = target_unregister_timer_callback(esp32_apptrace_poll, ctx);
        if (res != ERROR_OK)
                LOG_ERROR("Failed to unregister target timer handler (%d)!", res);
-
+       if (is_sysview_mode(ctx->mode)) {
+               /* stop tracing */
+               res = esp32_sysview_stop(ctx);
+               if (res != ERROR_OK)
+                       LOG_ERROR("sysview: Failed to stop tracing!");
+       }
        /* data processor is alive, so wait for all received blocks to be processed */
        res = esp32_apptrace_wait_tracing_finished(ctx);
        if (res != ERROR_OK)
@@ -1236,6 +1247,190 @@ static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx)
                LOG_ERROR("Failed to cleanup cmd ctx (%d)!", res);
 }
 
+/* this function must be called after connecting to targets */
+static int esp32_sysview_start(struct esp32_apptrace_cmd_ctx *ctx)
+{
+       uint8_t cmds[] = { SEGGER_SYSVIEW_COMMAND_ID_START };
+       uint32_t fired_target_num = 0;
+       struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM];
+       struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
+
+       /* get current block id */
+       int res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num);
+       if (res != ERROR_OK) {
+               LOG_ERROR("sysview: Failed to read target data info!");
+               return res;
+       }
+       if (fired_target_num == UINT32_MAX) {
+               /* it can happen that there is no pending target data, but block was switched
+                * in this case block_ids on both CPUs are equal, so select the first one */
+               fired_target_num = 0;
+       }
+       /* start tracing */
+       res = esp_apptrace_usr_block_write(ctx->hw, ctx->cpus[fired_target_num], target_state[fired_target_num].block_id,
+               cmds, sizeof(cmds));
+       if (res != ERROR_OK) {
+               LOG_ERROR("sysview: Failed to start tracing!");
+               return res;
+       }
+       cmd_data->sv_trace_running = 1;
+       return res;
+}
+
+static int esp32_sysview_stop(struct esp32_apptrace_cmd_ctx *ctx)
+{
+       uint32_t old_block_id, fired_target_num = 0, empty_target_num = 0;
+       struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM];
+       struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
+       uint8_t cmds[] = { SEGGER_SYSVIEW_COMMAND_ID_STOP };
+       struct duration wait_time;
+
+       struct esp32_apptrace_block *block = esp32_apptrace_free_block_get(ctx);
+       if (!block) {
+               LOG_ERROR("Failed to get free block for data on (%s)!", target_name(ctx->cpus[fired_target_num]));
+               return ERROR_FAIL;
+       }
+
+       /* halt all CPUs (not only one), otherwise it can happen that there is no target data and
+        * while we are queueing commands another CPU switches tracing block */
+       int res = esp32_apptrace_safe_halt_targets(ctx, target_state);
+       if (res != ERROR_OK) {
+               LOG_ERROR("sysview: Failed to halt targets (%d)!", res);
+               return res;
+       }
+       /* it can happen that there is no pending target data
+        * in this case block_ids on both CPUs are equal, so the first one will be selected */
+       for (unsigned int k = 0; k < ctx->cores_num; k++) {
+               if (target_state[k].data_len) {
+                       fired_target_num = k;
+                       break;
+               }
+       }
+       if (target_state[fired_target_num].data_len) {
+               /* read pending data without ack, they will be acked when stop command is queued */
+               res = ctx->hw->data_read(ctx->cpus[fired_target_num], target_state[fired_target_num].data_len, block->data,
+                       target_state[fired_target_num].block_id,
+                       false /*no ack target data*/);
+               if (res != ERROR_OK) {
+                       LOG_ERROR("sysview: Failed to read data on (%s)!", target_name(ctx->cpus[fired_target_num]));
+                       return res;
+               }
+               /* process data */
+               block->data_len = target_state[fired_target_num].data_len;
+               res = esp32_apptrace_handle_trace_block(ctx, block);
+               if (res != ERROR_OK) {
+                       LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len);
+                       return res;
+               }
+       }
+       /* stop tracing and ack target data */
+       res = esp_apptrace_usr_block_write(ctx->hw, ctx->cpus[fired_target_num], target_state[fired_target_num].block_id,
+               cmds,
+               sizeof(cmds));
+       if (res != ERROR_OK) {
+               LOG_ERROR("sysview: Failed to stop tracing!");
+               return res;
+       }
+       if (ctx->cores_num > 1) {
+               empty_target_num = fired_target_num ? 0 : 1;
+               /* ack target data on another CPU */
+               res = ctx->hw->ctrl_reg_write(ctx->cpus[empty_target_num], target_state[fired_target_num].block_id,
+                       0 /*target data ack*/,
+                       true /*host connected*/,
+                       false /*no host data*/);
+               if (res != ERROR_OK) {
+                       LOG_ERROR("sysview: Failed to ack data on target '%s' (%d)!",
+                               target_name(ctx->cpus[empty_target_num]), res);
+                       return res;
+               }
+       }
+       /* resume targets to allow command processing */
+       LOG_INFO("Resume targets");
+       bool smp_resumed = false;
+       for (unsigned int k = 0; k < ctx->cores_num; k++) {
+               if (smp_resumed && ctx->cpus[k]->smp) {
+                       /* in SMP mode we need to call target_resume for one core only */
+                       continue;
+               }
+               res = target_resume(ctx->cpus[k], 1, 0, 1, 0);
+               if (res != ERROR_OK) {
+                       LOG_ERROR("sysview: Failed to resume target '%s' (%d)!", target_name(ctx->cpus[k]), res);
+                       return res;
+               }
+               if (ctx->cpus[k]->smp)
+                       smp_resumed = true;
+       }
+       /* wait for block switch (command sent), so we can disconnect from targets */
+       old_block_id = target_state[fired_target_num].block_id;
+       if (duration_start(&wait_time) != 0) {
+               LOG_ERROR("Failed to start trace stop timeout measurement!");
+               return ERROR_FAIL;
+       }
+       /* we are waiting for the last data from tracing block and also there can be data in the pended
+        * data buffer */
+       /* so we are expecting two TRX block switches at most or stopping due to timeout */
+       while (cmd_data->sv_trace_running) {
+               res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num);
+               if (res != ERROR_OK) {
+                       LOG_ERROR("sysview: Failed to read targets data info!");
+                       return res;
+               }
+               if (fired_target_num == UINT32_MAX) {
+                       /* it can happen that there is no pending (last) target data, but block was
+                        * switched */
+                       /* in this case block_ids on both CPUs are equal, so select the first one */
+                       fired_target_num = 0;
+               }
+               if (target_state[fired_target_num].block_id != old_block_id) {
+                       if (target_state[fired_target_num].data_len) {
+                               /* read last data and ack them */
+                               res = ctx->hw->data_read(ctx->cpus[fired_target_num],
+                                       target_state[fired_target_num].data_len,
+                                       block->data,
+                                       target_state[fired_target_num].block_id,
+                                       true /*ack target data*/);
+                               if (res != ERROR_OK) {
+                                       LOG_ERROR("sysview: Failed to read last data on (%s)!", target_name(ctx->cpus[fired_target_num]));
+                               } else {
+                                       if (ctx->cores_num > 1) {
+                                               /* ack target data on another CPU */
+                                               empty_target_num = fired_target_num ? 0 : 1;
+                                               res = ctx->hw->ctrl_reg_write(ctx->cpus[empty_target_num],
+                                                       target_state[fired_target_num].block_id,
+                                                       0 /*all read*/,
+                                                       true /*host connected*/,
+                                                       false /*no host data*/);
+                                               if (res != ERROR_OK) {
+                                                       LOG_ERROR("sysview: Failed to ack data on target '%s' (%d)!",
+                                                               target_name(ctx->cpus[empty_target_num]), res);
+                                                       return res;
+                                               }
+                                       }
+                                       /* process data */
+                                       block->data_len = target_state[fired_target_num].data_len;
+                                       res = esp32_apptrace_handle_trace_block(ctx, block);
+                                       if (res != ERROR_OK) {
+                                               LOG_ERROR("Failed to process trace block %" PRId32 " bytes!",
+                                                       block->data_len);
+                                               return res;
+                                       }
+                               }
+                               old_block_id = target_state[fired_target_num].block_id;
+                       }
+               }
+               if (duration_measure(&wait_time) != 0) {
+                       LOG_ERROR("Failed to start trace stop timeout measurement!");
+                       return ERROR_FAIL;
+               }
+               const float stop_tmo = LOG_LEVEL_IS(LOG_LVL_DEBUG) ? 30.0 : 0.5;
+               if (duration_elapsed(&wait_time) >= stop_tmo) {
+                       LOG_INFO("Stop waiting for the last data due to timeout.");
+                       break;
+               }
+       }
+       return res;
+}
+
 int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const char **argv, int argc)
 {
        static struct esp32_apptrace_cmd_ctx s_at_cmd_ctx;
@@ -1264,17 +1459,39 @@ int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const c
        old_state = target->state;
 
        if (strcmp(argv[0], "start") == 0) {
-               res = esp32_apptrace_cmd_init(&s_at_cmd_ctx,
-                       cmd,
-                       mode,
-                       &argv[1],
-                       argc - 1);
-               if (res != ERROR_OK) {
-                       command_print(cmd, "Failed to init cmd ctx (%d)!", res);
-                       return res;
+               if (is_sysview_mode(mode)) {
+                       /* init cmd context */
+                       res = esp32_sysview_cmd_init(&s_at_cmd_ctx,
+                               cmd,
+                               mode,
+                               mode == ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE,
+                               &argv[1],
+                               argc - 1);
+                       if (res != ERROR_OK) {
+                               command_print(cmd, "Failed to init cmd ctx (%d)!", res);
+                               return res;
+                       }
+                       cmd_data = s_at_cmd_ctx.cmd_priv;
+                       if (cmd_data->skip_len != 0) {
+                               s_at_cmd_ctx.running = 0;
+                               esp32_sysview_cmd_cleanup(&s_at_cmd_ctx);
+                               command_print(cmd, "Data skipping not supported!");
+                               return ERROR_FAIL;
+                       }
+                       s_at_cmd_ctx.process_data = esp32_sysview_process_data;
+               } else {
+                       res = esp32_apptrace_cmd_init(&s_at_cmd_ctx,
+                               cmd,
+                               mode,
+                               &argv[1],
+                               argc - 1);
+                       if (res != ERROR_OK) {
+                               command_print(cmd, "Failed to init cmd ctx (%d)!", res);
+                               return res;
+                       }
+                       cmd_data = s_at_cmd_ctx.cmd_priv;
+                       s_at_cmd_ctx.process_data = esp32_apptrace_process_data;
                }
-               cmd_data = s_at_cmd_ctx.cmd_priv;
-               s_at_cmd_ctx.process_data = esp32_apptrace_process_data;
                s_at_cmd_ctx.auto_clean = esp32_apptrace_cmd_stop;
                if (cmd_data->wait4halt) {
                        res = esp32_apptrace_wait4halt(&s_at_cmd_ctx, target);
@@ -1288,6 +1505,17 @@ int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const c
                        command_print(cmd, "Failed to connect to targets (%d)!", res);
                        goto _on_start_error;
                }
+               if (is_sysview_mode(mode)) {
+                       /* start tracing */
+                       res = esp32_sysview_start(&s_at_cmd_ctx);
+                       if (res != ERROR_OK) {
+                               esp32_apptrace_connect_targets(&s_at_cmd_ctx, false, old_state == TARGET_RUNNING);
+                               s_at_cmd_ctx.running = 0;
+                               esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx);
+                               command_print(cmd, "sysview: Failed to start tracing!");
+                               return res;
+                       }
+               }
                res = target_register_timer_callback(esp32_apptrace_poll,
                        cmd_data->poll_period,
                        TARGET_TIMER_TYPE_PERIODIC,
@@ -1309,6 +1537,10 @@ int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const c
                esp32_apptrace_print_stats(&s_at_cmd_ctx);
                return ERROR_OK;
        } else if (strcmp(argv[0], "dump") == 0) {
+               if (is_sysview_mode(mode)) {
+                       command_print(cmd, "Not supported!");
+                       return ERROR_FAIL;
+               }
                /* [dump outfile] - post-mortem dump without connection to targets */
                res = esp32_apptrace_cmd_init(&s_at_cmd_ctx,
                        cmd,
@@ -1349,7 +1581,10 @@ int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const c
 
 _on_start_error:
        s_at_cmd_ctx.running = 0;
-       esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx);
+       if (is_sysview_mode(mode))
+               esp32_sysview_cmd_cleanup(&s_at_cmd_ctx);
+       else
+               esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx);
        return res;
 }
 
@@ -1358,6 +1593,16 @@ COMMAND_HANDLER(esp32_cmd_apptrace)
        return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_GEN, CMD_ARGV, CMD_ARGC);
 }
 
+COMMAND_HANDLER(esp32_cmd_sysview)
+{
+       return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_SYSVIEW, CMD_ARGV, CMD_ARGC);
+}
+
+COMMAND_HANDLER(esp32_cmd_sysview_mcore)
+{
+       return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE, CMD_ARGV, CMD_ARGC);
+}
+
 const struct command_registration esp32_apptrace_command_handlers[] = {
        {
                .name = "apptrace",
@@ -1366,7 +1611,25 @@ const struct command_registration esp32_apptrace_command_handlers[] = {
                .help =
                        "App Tracing: application level trace control. Starts, stops or queries tracing process status.",
                .usage =
-                       "[start <destination> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] | [stop] | [status] | [dump <destination>]",
+                       "(start <destination> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status) | (dump <destination>)",
+       },
+       {
+               .name = "sysview",
+               .handler = esp32_cmd_sysview,
+               .mode = COMMAND_EXEC,
+               .help =
+                       "App Tracing: SEGGER SystemView compatible trace control. Starts, stops or queries tracing process status.",
+               .usage =
+                       "(start file://<outfile1> [file://<outfile2>] [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status)",
+       },
+       {
+               .name = "sysview_mcore",
+               .handler = esp32_cmd_sysview_mcore,
+               .mode = COMMAND_EXEC,
+               .help =
+                       "App Tracing: Espressif multi-core SystemView trace control. Starts, stops or queries tracing process status.",
+               .usage =
+                       "(start file://<outfile> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status)",
        },
        COMMAND_REGISTRATION_DONE
 };
diff --git a/src/target/espressif/esp32_sysview.c b/src/target/espressif/esp32_sysview.c
new file mode 100644 (file)
index 0000000..2fe2157
--- /dev/null
@@ -0,0 +1,554 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ *   ESP32 sysview tracing module                                          *
+ *   Copyright (C) 2020 Espressif Systems Ltd.                             *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/log.h>
+#include "esp32_apptrace.h"
+#include "esp32_sysview.h"
+#include "segger_sysview.h"
+
+/* in SystemView mode core ID is passed in event ID field */
+#define ESP32_SYSVIEW_USER_BLOCK_CORE(_v_)  (0)        /* not used */
+#define ESP32_SYSVIEW_USER_BLOCK_LEN(_v_)   (_v_)
+#define ESP32_SYSVIEW_USER_BLOCK_HDR_SZ     2
+
+struct esp_sysview_target2host_hdr {
+       uint8_t block_sz;
+       uint8_t wr_sz;
+};
+#define SYSVIEW_BLOCK_SIZE_OFFSET       0
+#define SYSVIEW_WR_SIZE_OFFSET          1
+
+static int esp_sysview_trace_header_write(struct esp32_apptrace_cmd_ctx *ctx, bool mcore_format);
+static int esp32_sysview_core_id_get(struct target *target, uint8_t *hdr_buf);
+static uint32_t esp32_sysview_usr_block_len_get(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len);
+
+int esp32_sysview_cmd_init(struct esp32_apptrace_cmd_ctx *cmd_ctx,
+       struct command_invocation *cmd,
+       int mode,
+       bool mcore_format,
+       const char **argv,
+       int argc)
+{
+       struct esp32_sysview_cmd_data *cmd_data;
+
+       if (argc < 1) {
+               command_print(cmd, "Not enough args! Need trace data destination!");
+               return ERROR_FAIL;
+       }
+
+       int res = esp32_apptrace_cmd_ctx_init(cmd_ctx, cmd, mode);
+       if (res != ERROR_OK)
+               return res;
+
+       int core_num = cmd_ctx->cores_num;
+
+       if (!mcore_format && argc < core_num) {
+               command_print(cmd, "Not enough args! Need %d trace data destinations!", core_num);
+               res = ERROR_FAIL;
+               goto on_error;
+       }
+
+       cmd_data = calloc(1, sizeof(*cmd_data));
+       if (!cmd_data) {
+               command_print(cmd, "No memory for command data!");
+               res = ERROR_FAIL;
+               goto on_error;
+       }
+       cmd_ctx->cmd_priv = cmd_data;
+       cmd_data->mcore_format = mcore_format;
+
+       /*outfile1 [outfile2] [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] */
+       int dests_num = esp32_apptrace_dest_init(cmd_data->data_dests, argv, !mcore_format ? core_num : 1);
+       if (!mcore_format && dests_num < core_num) {
+               command_print(cmd, "Not enough args! Need %d trace data destinations!", core_num);
+               free(cmd_data);
+               res = ERROR_FAIL;
+               goto on_error;
+       }
+       cmd_data->apptrace.max_len = UINT32_MAX;
+       cmd_data->apptrace.poll_period = 0 /*ms*/;
+       cmd_ctx->stop_tmo = -1.0;       /* infinite */
+       if (argc > dests_num) {
+               /* parse remaining args */
+               esp32_apptrace_cmd_args_parse(cmd_ctx,
+                       &cmd_data->apptrace,
+                       &argv[dests_num],
+                       argc - dests_num);
+       }
+       LOG_USER("App trace params: from %d cores, size %u bytes, stop_tmo %g s, "
+               "poll period %u ms, wait_rst %d, skip %u bytes",
+               cmd_ctx->cores_num,
+               cmd_data->apptrace.max_len,
+               cmd_ctx->stop_tmo,
+               cmd_data->apptrace.poll_period,
+               cmd_data->apptrace.wait4halt,
+               cmd_data->apptrace.skip_len);
+
+       cmd_ctx->trace_format.hdr_sz = ESP32_SYSVIEW_USER_BLOCK_HDR_SZ;
+       cmd_ctx->trace_format.core_id_get = esp32_sysview_core_id_get;
+       cmd_ctx->trace_format.usr_block_len_get = esp32_sysview_usr_block_len_get;
+
+       res = esp_sysview_trace_header_write(cmd_ctx, mcore_format);
+       if (res != ERROR_OK) {
+               command_print(cmd, "Failed to write trace header (%d)!", res);
+               esp32_apptrace_dest_cleanup(cmd_data->data_dests, core_num);
+               free(cmd_data);
+               return res;
+       }
+       return ERROR_OK;
+on_error:
+       cmd_ctx->running = 0;
+       esp32_apptrace_cmd_ctx_cleanup(cmd_ctx);
+       return res;
+}
+
+int esp32_sysview_cmd_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx)
+{
+       struct esp32_sysview_cmd_data *cmd_data = cmd_ctx->cmd_priv;
+
+       esp32_apptrace_dest_cleanup(cmd_data->data_dests, cmd_ctx->cores_num);
+       free(cmd_data);
+       cmd_ctx->cmd_priv = NULL;
+       esp32_apptrace_cmd_ctx_cleanup(cmd_ctx);
+       return ERROR_OK;
+}
+
+static int esp32_sysview_core_id_get(struct target *target, uint8_t *hdr_buf)
+{
+       /* for sysview compressed apptrace header is used, so core id is encoded in sysview packet */
+       return 0;
+}
+
+static uint32_t esp32_sysview_usr_block_len_get(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len)
+{
+       *wr_len = ESP32_SYSVIEW_USER_BLOCK_LEN(hdr_buf[SYSVIEW_WR_SIZE_OFFSET]);
+       return ESP32_SYSVIEW_USER_BLOCK_LEN(hdr_buf[SYSVIEW_BLOCK_SIZE_OFFSET]);
+}
+
+static int esp_sysview_trace_header_write(struct esp32_apptrace_cmd_ctx *ctx, bool mcore_format)
+{
+       struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
+       char *hdr_str;
+       int dests_num;
+
+       if (!mcore_format) {
+               hdr_str = ";\n"
+                       "; Version     " SYSVIEW_MIN_VER_STRING "\n"
+                       "; Author      Espressif Inc\n"
+                       ";\n";
+               dests_num = ctx->cores_num;
+       } else {
+               hdr_str = ";\n"
+                       "; Version     " SYSVIEW_MIN_VER_STRING "\n"
+                       "; Author      Espressif Inc\n"
+                       "; ESP_Extension\n"
+                       ";\n";
+               dests_num = 1;
+       }
+
+       int hdr_len = strlen(hdr_str);
+       for (int i = 0; i < dests_num; i++) {
+               int res = cmd_data->data_dests[i].write(cmd_data->data_dests[i].priv,
+                       (uint8_t *)hdr_str,
+                       hdr_len);
+               if (res != ERROR_OK) {
+                       LOG_ERROR("sysview: Failed to write %u bytes to dest %d!", hdr_len, i);
+                       return ERROR_FAIL;
+               }
+       }
+       return ERROR_OK;
+}
+
+static void sysview_encode_u32(uint8_t **dest, uint32_t val)
+{
+       uint8_t *sv_ptr = *dest;
+       while (val > 0x7F) {
+               *sv_ptr++ = (uint8_t)(val | 0x80);
+               val >>= 7;
+       }
+       *sv_ptr++ = (uint8_t)val;
+       *dest = sv_ptr;
+}
+
+static uint32_t esp_sysview_decode_u32(uint8_t **ptr)
+{
+       uint32_t val = 0;
+       for (int k = 0;; k++, (*ptr)++) {
+               if (**ptr & 0x80) {
+                       val |= (uint32_t)(**ptr & ~0x80) << 7 * k;
+               } else {
+                       val |= (uint32_t)**ptr << 7 * k;
+                       (*ptr)++;
+                       break;
+               }
+       }
+       return val;
+}
+
+static uint16_t esp_sysview_decode_plen(uint8_t **ptr)
+{
+       uint16_t payload_len = 0;
+       uint8_t *p = *ptr;
+       /* here pkt points to encoded payload length */
+       if (*p & 0x80) {
+               payload_len = *(p + 1); /* higher part */
+               payload_len = (payload_len << 7) | (*p & ~0x80);/* lower 7 bits */
+               p += 2; /* payload len (2 bytes) */
+       } else {
+               payload_len = *p;
+               p++;    /* payload len (1 byte) */
+       }
+       *ptr = p;
+
+       return payload_len;
+}
+
+static uint16_t esp_sysview_get_predef_payload_len(uint16_t id, uint8_t *pkt)
+{
+       uint16_t len;
+       uint8_t *ptr = pkt;
+
+       switch (id) {
+       case SYSVIEW_EVTID_OVERFLOW:
+       case SYSVIEW_EVTID_ISR_ENTER:
+       case SYSVIEW_EVTID_TASK_START_EXEC:
+       case SYSVIEW_EVTID_TASK_START_READY:
+       case SYSVIEW_EVTID_TASK_CREATE:
+       case SYSVIEW_EVTID_SYSTIME_CYCLES:
+       case SYSVIEW_EVTID_USER_START:
+       case SYSVIEW_EVTID_USER_STOP:
+       case SYSVIEW_EVTID_TIMER_ENTER:
+               /*ENCODE_U32 */
+               esp_sysview_decode_u32(&ptr);
+               len = ptr - pkt;
+               break;
+       case SYSVIEW_EVTID_TASK_STOP_READY:
+       case SYSVIEW_EVTID_SYSTIME_US:
+               /*2*ENCODE_U32 */
+               esp_sysview_decode_u32(&ptr);
+               esp_sysview_decode_u32(&ptr);
+               len = ptr - pkt;
+               break;
+       case SYSVIEW_EVTID_SYSDESC:
+               /*str(128 + 1) */
+               len = *ptr + 1;
+               break;
+       case SYSVIEW_EVTID_TASK_INFO:
+       case SYSVIEW_EVTID_MODULEDESC:
+               /*2*ENCODE_U32 + str */
+               esp_sysview_decode_u32(&ptr);
+               esp_sysview_decode_u32(&ptr);
+               /* TODO: add support for strings longer then 255 bytes */
+               len = ptr - pkt + *ptr + 1;
+               break;
+       case SYSVIEW_EVTID_STACK_INFO:
+               /*4*ENCODE_U32 */
+               esp_sysview_decode_u32(&ptr);
+               esp_sysview_decode_u32(&ptr);
+               esp_sysview_decode_u32(&ptr);
+               esp_sysview_decode_u32(&ptr);
+               len = ptr - pkt;
+               break;
+       case SYSVIEW_EVTID_ISR_EXIT:
+       case SYSVIEW_EVTID_TASK_STOP_EXEC:
+       case SYSVIEW_EVTID_TRACE_START:
+       case SYSVIEW_EVTID_TRACE_STOP:
+       case SYSVIEW_EVTID_IDLE:
+       case SYSVIEW_EVTID_ISR_TO_SCHEDULER:
+       case SYSVIEW_EVTID_TIMER_EXIT:
+               len = 0;
+               break;
+
+       /*case SYSVIEW_EVTID_NOP: */
+       default:
+               LOG_ERROR("sysview: Unsupported predef event %d!", id);
+               len = 0;
+       }
+       return len;
+}
+
+static uint16_t esp_sysview_parse_packet(uint8_t *pkt_buf,
+       uint32_t *pkt_len,
+       unsigned int *pkt_core_id,
+       uint32_t *delta,
+       uint32_t *delta_len,
+       bool clear_core_bit)
+{
+       uint8_t *pkt = pkt_buf;
+       uint16_t event_id = 0, payload_len = 0;
+
+       *pkt_core_id = 0;
+       *pkt_len = 0;
+       /* 1-2 byte of message type, 0-2  byte of payload length, payload, 1-5 bytes of timestamp. */
+       if (*pkt & 0x80) {
+               if (*(pkt + 1) & (1 << 6)) {
+                       if (clear_core_bit)
+                               *(pkt + 1) &= ~(1 << 6);        /* clear core_id bit */
+                       *pkt_core_id = 1;
+               }
+               event_id = *(pkt + 1) & ~(1 << 6);      /* higher part */
+               event_id = (event_id << 7) | (*pkt & ~0x80);    /* lower 7 bits */
+               pkt += 2;       /* event_id (2 bytes) */
+               /* here pkt points to encoded payload length */
+               payload_len = esp_sysview_decode_plen(&pkt);
+       } else {
+               if (*pkt & (1 << 6)) {
+                       if (clear_core_bit)
+                               *pkt &= ~(1 << 6);      /* clear core_id bit */
+                       *pkt_core_id = 1;
+               }
+               /* event_id (1 byte) */
+               event_id = *pkt & ~(1 << 6);
+               pkt++;
+               if (event_id < 24)
+                       payload_len = esp_sysview_get_predef_payload_len(event_id, pkt);
+               else
+                       payload_len = esp_sysview_decode_plen(&pkt);
+       }
+       pkt += payload_len;
+       uint8_t *delta_start = pkt;
+       *delta = esp_sysview_decode_u32(&pkt);
+       *delta_len = pkt - delta_start;
+       *pkt_len = pkt - pkt_buf;
+       LOG_DEBUG("sysview: evt %d len %d plen %d dlen %d",
+               event_id,
+               *pkt_len,
+               payload_len,
+               *delta_len);
+       return event_id;
+}
+
+static int esp32_sysview_write_packet(struct esp32_sysview_cmd_data *cmd_data,
+       int pkt_core_id, uint32_t pkt_len, uint8_t *pkt_buf, uint32_t delta_len, uint8_t *delta_buf)
+{
+       if (!cmd_data->data_dests[pkt_core_id].write)
+               return ERROR_FAIL;
+
+       int res = cmd_data->data_dests[pkt_core_id].write(cmd_data->data_dests[pkt_core_id].priv, pkt_buf, pkt_len);
+
+       if (res != ERROR_OK) {
+               LOG_ERROR("sysview: Failed to write %u bytes to dest %d!", pkt_len, pkt_core_id);
+               return res;
+       }
+       if (delta_len) {
+               /* write packet with modified delta */
+               res = cmd_data->data_dests[pkt_core_id].write(cmd_data->data_dests[pkt_core_id].priv, delta_buf, delta_len);
+               if (res != ERROR_OK) {
+                       LOG_ERROR("sysview: Failed to write %u bytes of delta to dest %d!", delta_len, pkt_core_id);
+                       return res;
+               }
+       }
+       return ERROR_OK;
+}
+
+static int esp32_sysview_process_packet(struct esp32_apptrace_cmd_ctx *ctx,
+       unsigned int pkt_core_id, uint16_t event_id, uint32_t delta, uint32_t delta_len,
+       uint32_t pkt_len, uint8_t *pkt_buf)
+{
+       struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
+       int pkt_core_changed = 0;
+       uint32_t new_delta_len = 0;
+       uint8_t new_delta_buf[10];
+       uint32_t wr_len = pkt_len;
+
+       if (ctx->cores_num > 1) {
+               if (cmd_data->sv_last_core_id == pkt_core_id) {
+                       /* if this packet is for the same core as the prev one acc delta and write packet unmodified */
+                       cmd_data->sv_acc_time_delta += delta;
+               } else {
+                       /* if this packet is for another core then prev one set acc delta to the packet's delta */
+                       uint8_t *delta_ptr = new_delta_buf;
+                       sysview_encode_u32(&delta_ptr, delta + cmd_data->sv_acc_time_delta);
+                       cmd_data->sv_acc_time_delta = delta;
+                       wr_len -= delta_len;
+                       new_delta_len = delta_ptr - new_delta_buf;
+                       pkt_core_changed = 1;
+               }
+               cmd_data->sv_last_core_id = pkt_core_id;
+       }
+       if (pkt_core_id >= ctx->cores_num) {
+               LOG_WARNING("sysview: invalid core ID in packet %d, must be less then %d! Event id %d",
+                       pkt_core_id,
+                       ctx->cores_num,
+                       event_id);
+               return ERROR_FAIL;
+       }
+       int res = esp32_sysview_write_packet(cmd_data,
+               pkt_core_id,
+               wr_len,
+               pkt_buf,
+               new_delta_len,
+               new_delta_buf);
+       if (res != ERROR_OK)
+               return res;
+       for (unsigned int i = 0; i < ctx->cores_num; i++) {
+               if (pkt_core_id == i)
+                       continue;
+               switch (event_id) {
+               /* messages below should be sent to trace destinations for all cores */
+               case SYSVIEW_EVTID_TRACE_START:
+               case SYSVIEW_EVTID_TRACE_STOP:
+               case SYSVIEW_EVTID_SYSTIME_CYCLES:
+               case SYSVIEW_EVTID_SYSTIME_US:
+               case SYSVIEW_EVTID_SYSDESC:
+               case SYSVIEW_EVTID_TASK_INFO:
+               case SYSVIEW_EVTID_STACK_INFO:
+               case SYSVIEW_EVTID_MODULEDESC:
+               case SYSVIEW_EVTID_INIT:
+               case SYSVIEW_EVTID_NUMMODULES:
+               case SYSVIEW_EVTID_OVERFLOW:
+               case SYSVIEW_EVTID_TASK_START_READY:
+                       /* if packet's source core has changed */
+                       wr_len = pkt_len;
+                       if (pkt_core_changed) {
+                               /* clone packet with unmodified delta */
+                               new_delta_len = 0;
+                       } else {
+                               /* clone packet with modified delta */
+                               uint8_t *delta_ptr = new_delta_buf;
+                               sysview_encode_u32(&delta_ptr, cmd_data->sv_acc_time_delta /*delta has been accumulated above*/);
+                               wr_len -= delta_len;
+                               new_delta_len = delta_ptr - new_delta_buf;
+                       }
+                       LOG_DEBUG("sysview: Redirect %d bytes of event %d to dest %d", wr_len, event_id, i);
+                       res = esp32_sysview_write_packet(cmd_data,
+                               i,
+                               wr_len,
+                               pkt_buf,
+                               new_delta_len,
+                               new_delta_buf);
+                       if (res != ERROR_OK)
+                               return res;
+                       /* messages above are cloned to trace files for both cores,
+                       * so reset acc time delta, both files have actual delta
+                       * info */
+                       cmd_data->sv_acc_time_delta = 0;
+                       break;
+               default:
+                       break;
+               }
+       }
+       return ERROR_OK;
+}
+
+int esp32_sysview_process_data(struct esp32_apptrace_cmd_ctx *ctx,
+       unsigned int core_id,
+       uint8_t *data,
+       uint32_t data_len)
+{
+       struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
+
+       LOG_DEBUG("sysview: Read from target %d bytes [%x %x %x %x]",
+               data_len,
+               data[0],
+               data[1],
+               data[2],
+               data[3]);
+       int res;
+       uint32_t processed = 0;
+       if (core_id >= ctx->cores_num) {
+               LOG_ERROR("sysview: Invalid core id %d in user block!", core_id);
+               return ERROR_FAIL;
+       }
+       if (cmd_data->mcore_format)
+               core_id = 0;
+       if (ctx->tot_len == 0) {
+               /* handle sync seq */
+               if (data_len < SYSVIEW_SYNC_LEN) {
+                       LOG_ERROR("sysview: Invalid init seq len %d!", data_len);
+                       return ERROR_FAIL;
+               }
+               LOG_DEBUG("sysview: Process %d sync bytes", SYSVIEW_SYNC_LEN);
+               uint8_t sync_seq[SYSVIEW_SYNC_LEN] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
+               if (memcmp(data, sync_seq, SYSVIEW_SYNC_LEN) != 0) {
+                       LOG_ERROR("sysview: Invalid init seq [%x %x %x %x %x %x %x %x %x %x]",
+                               data[0], data[1], data[2], data[3], data[4], data[5], data[6],
+                               data[7], data[8], data[9]);
+                       return ERROR_FAIL;
+               }
+               res = cmd_data->data_dests[core_id].write(cmd_data->data_dests[core_id].priv,
+                       data,
+                       SYSVIEW_SYNC_LEN);
+               if (res != ERROR_OK) {
+                       LOG_ERROR("sysview: Failed to write %u sync bytes to dest %d!",
+                               SYSVIEW_SYNC_LEN,
+                               core_id);
+                       return res;
+               }
+               if (!cmd_data->mcore_format) {
+                       for (unsigned int i = 0; i < ctx->cores_num; i++) {
+                               if (core_id == i)
+                                       continue;
+                               res =
+                                       cmd_data->data_dests[i].write(cmd_data->data_dests[i].priv,
+                                       data,
+                                       SYSVIEW_SYNC_LEN);
+                               if (res != ERROR_OK) {
+                                       LOG_ERROR("sysview: Failed to write %u sync bytes to dest %d!", SYSVIEW_SYNC_LEN, core_id ? 0 : 1);
+                                       return res;
+                               }
+                       }
+               }
+               ctx->tot_len += SYSVIEW_SYNC_LEN;
+               processed += SYSVIEW_SYNC_LEN;
+       }
+       while (processed < data_len) {
+               unsigned int pkt_core_id;
+               uint32_t delta_len = 0;
+               uint32_t pkt_len = 0, delta = 0;
+               uint16_t event_id = esp_sysview_parse_packet(data + processed,
+                       &pkt_len,
+                       &pkt_core_id,
+                       &delta,
+                       &delta_len,
+                       !cmd_data->mcore_format);
+               LOG_DEBUG("sysview: Process packet: core %d, %d id, %d bytes [%x %x %x %x]",
+                       pkt_core_id,
+                       event_id,
+                       pkt_len,
+                       data[processed + 0],
+                       data[processed + 1],
+                       data[processed + 2],
+                       data[processed + 3]);
+               if (!cmd_data->mcore_format) {
+                       res = esp32_sysview_process_packet(ctx,
+                               pkt_core_id,
+                               event_id,
+                               delta,
+                               delta_len,
+                               pkt_len,
+                               data + processed);
+                       if (res != ERROR_OK)
+                               return res;
+               } else {
+                       res = cmd_data->data_dests[0].write(cmd_data->data_dests[0].priv, data + processed, pkt_len);
+                       if (res != ERROR_OK) {
+                               LOG_ERROR("sysview: Failed to write %u bytes to dest %d!", pkt_len, 0);
+                               return res;
+                       }
+               }
+               if (event_id == SYSVIEW_EVTID_TRACE_STOP)
+                       cmd_data->sv_trace_running = 0;
+               ctx->tot_len += pkt_len;
+               processed += pkt_len;
+       }
+       LOG_USER("%u ", ctx->tot_len);
+       /* check for stop condition */
+       if (ctx->tot_len > cmd_data->apptrace.skip_len &&
+               (ctx->tot_len - cmd_data->apptrace.skip_len >= cmd_data->apptrace.max_len)) {
+               ctx->running = 0;
+               if (duration_measure(&ctx->read_time) != 0) {
+                       LOG_ERROR("Failed to stop trace read time measure!");
+                       return ERROR_FAIL;
+               }
+       }
+       return ERROR_OK;
+}
diff --git a/src/target/espressif/esp32_sysview.h b/src/target/espressif/esp32_sysview.h
new file mode 100644 (file)
index 0000000..230ce46
--- /dev/null
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   ESP32 sysview tracing module                                          *
+ *   Copyright (C) 2020 Espressif Systems Ltd.                             *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ESP32_SYSVIEW_H
+#define OPENOCD_TARGET_ESP32_SYSVIEW_H
+
+#include <stdint.h>
+#include "esp32_apptrace.h"
+
+struct esp32_sysview_cmd_data {
+       /* Should be the first field. Generic apptrace command handling code accesses it */
+       struct esp32_apptrace_cmd_data apptrace;
+       struct esp32_apptrace_dest data_dests[ESP32_APPTRACE_MAX_CORES_NUM];
+       bool mcore_format;
+       uint32_t sv_acc_time_delta;
+       unsigned int sv_last_core_id;
+       int sv_trace_running;
+};
+
+struct esp32_apptrace_cmd_ctx;
+
+int esp32_sysview_cmd_init(struct esp32_apptrace_cmd_ctx *cmd_ctx,
+       struct command_invocation *cmd,
+       int mode,
+       bool mcore_format,
+       const char **argv,
+       int argc);
+int esp32_sysview_cmd_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx);
+int esp32_sysview_process_data(struct esp32_apptrace_cmd_ctx *ctx,
+       unsigned int core_id,
+       uint8_t *data,
+       uint32_t data_len);
+
+#endif /* OPENOCD_TARGET_ESP32_SYSVIEW_H */
diff --git a/src/target/espressif/segger_sysview.h b/src/target/espressif/segger_sysview.h
new file mode 100644 (file)
index 0000000..d149cab
--- /dev/null
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: BSD-1-Clause */
+/* SPDX-FileCopyrightText: (c) 1995-2021 SEGGER Microcontroller GmbH. All rights reserved. */
+/* SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD */
+
+/*
+* The contend below is extracted from files SEGGER_SYSVIEW.h and SEGGER_SYSVIEW_Int.h in:
+* https://www.segger.com/downloads/systemview/systemview_target_src
+* SystemView version: 3.42
+*/
+
+#ifndef OPENOCD_TARGET_SEGGER_SYSVIEW_H
+#define OPENOCD_TARGET_SEGGER_SYSVIEW_H
+
+#define SYSVIEW_EVTID_NOP                 0    /* Dummy packet. */
+#define SYSVIEW_EVTID_OVERFLOW            1
+#define SYSVIEW_EVTID_ISR_ENTER           2
+#define SYSVIEW_EVTID_ISR_EXIT            3
+#define SYSVIEW_EVTID_TASK_START_EXEC     4
+#define SYSVIEW_EVTID_TASK_STOP_EXEC      5
+#define SYSVIEW_EVTID_TASK_START_READY    6
+#define SYSVIEW_EVTID_TASK_STOP_READY     7
+#define SYSVIEW_EVTID_TASK_CREATE         8
+#define SYSVIEW_EVTID_TASK_INFO           9
+#define SYSVIEW_EVTID_TRACE_START         10
+#define SYSVIEW_EVTID_TRACE_STOP          11
+#define SYSVIEW_EVTID_SYSTIME_CYCLES      12
+#define SYSVIEW_EVTID_SYSTIME_US          13
+#define SYSVIEW_EVTID_SYSDESC             14
+#define SYSVIEW_EVTID_USER_START          15
+#define SYSVIEW_EVTID_USER_STOP           16
+#define SYSVIEW_EVTID_IDLE                17
+#define SYSVIEW_EVTID_ISR_TO_SCHEDULER    18
+#define SYSVIEW_EVTID_TIMER_ENTER         19
+#define SYSVIEW_EVTID_TIMER_EXIT          20
+#define SYSVIEW_EVTID_STACK_INFO          21
+#define SYSVIEW_EVTID_MODULEDESC          22
+
+#define SYSVIEW_EVTID_INIT                24
+#define SYSVIEW_EVTID_NAME_RESOURCE       25
+#define SYSVIEW_EVTID_PRINT_FORMATTED     26
+#define SYSVIEW_EVTID_NUMMODULES          27
+#define SYSVIEW_EVTID_END_CALL            28
+#define SYSVIEW_EVTID_TASK_TERMINATE      29
+
+#define SYSVIEW_EVTID_EX                  31
+//
+// SystemView extended events. Sent with ID 31.
+//
+#define SYSVIEW_EVTID_EX_MARK             0
+#define SYSVIEW_EVTID_EX_NAME_MARKER      1
+#define SYSVIEW_EVTID_EX_HEAP_DEFINE      2
+#define SYSVIEW_EVTID_EX_HEAP_ALLOC       3
+#define SYSVIEW_EVTID_EX_HEAP_ALLOC_EX    4
+#define SYSVIEW_EVTID_EX_HEAP_FREE        5
+
+#define SYSVIEW_SYNC_LEN                  10
+
+#define SYSVIEW_EVENT_ID_MAX             (200)
+
+//
+// Commands that Host can send to target
+//
+enum {
+       SEGGER_SYSVIEW_COMMAND_ID_START = 1,
+       SEGGER_SYSVIEW_COMMAND_ID_STOP,
+       SEGGER_SYSVIEW_COMMAND_ID_GET_SYSTIME,
+       SEGGER_SYSVIEW_COMMAND_ID_GET_TASKLIST,
+       SEGGER_SYSVIEW_COMMAND_ID_GET_SYSDESC,
+       SEGGER_SYSVIEW_COMMAND_ID_GET_NUMMODULES,
+       SEGGER_SYSVIEW_COMMAND_ID_GET_MODULEDESC,
+       SEGGER_SYSVIEW_COMMAND_ID_HEARTBEAT = 127,
+       // Extended commands: Commands >= 128 have a second parameter
+       SEGGER_SYSVIEW_COMMAND_ID_GET_MODULE = 128
+};
+
+/* Minimum compatible SEGGER SystemView tool version */
+#define SYSVIEW_MIN_VER_STRING                 "SEGGER SystemViewer V2.42"
+
+#endif

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)