#include "esirisc.h"
-#define RESET_TIMEOUT 5000 /* 5s */
-#define STEP_TIMEOUT 1000 /* 1s */
+#define RESET_TIMEOUT 5000 /* 5s */
+#define STEP_TIMEOUT 1000 /* 1s */
/*
* eSi-RISC targets support a configurable number of interrupts;
* up to 32 interrupts are supported.
*/
-static const char * const esirisc_exceptions[] = {
- "Reset", "HardwareFailure", "NMI", "InstBreakpoint", "DataBreakpoint",
- "Unsupported", "PrivilegeViolation", "InstBusError", "DataBusError",
- "AlignmentError", "ArithmeticError", "SystemCall", "MemoryManagement",
- "Unrecoverable", "Reserved",
-
- "Interrupt0", "Interrupt1", "Interrupt2", "Interrupt3",
- "Interrupt4", "Interrupt5", "Interrupt6", "Interrupt7",
- "Interrupt8", "Interrupt9", "Interrupt10", "Interrupt11",
- "Interrupt12", "Interrupt13", "Interrupt14", "Interrupt15",
- "Interrupt16", "Interrupt17", "Interrupt18", "Interrupt19",
- "Interrupt20", "Interrupt21", "Interrupt22", "Interrupt23",
- "Interrupt24", "Interrupt25", "Interrupt26", "Interrupt27",
- "Interrupt28", "Interrupt29", "Interrupt30", "Interrupt31",
+static const char * const esirisc_exception_strings[] = {
+ [EID_RESET] = "Reset",
+ [EID_HARDWARE_FAILURE] = "HardwareFailure",
+ [EID_NMI] = "NMI",
+ [EID_INST_BREAKPOINT] = "InstBreakpoint",
+ [EID_DATA_BREAKPOINT] = "DataBreakpoint",
+ [EID_UNSUPPORTED] = "Unsupported",
+ [EID_PRIVILEGE_VIOLATION] = "PrivilegeViolation",
+ [EID_INST_BUS_ERROR] = "InstBusError",
+ [EID_DATA_BUS_ERROR] = "DataBusError",
+ [EID_ALIGNMENT_ERROR] = "AlignmentError",
+ [EID_ARITHMETIC_ERROR] = "ArithmeticError",
+ [EID_SYSTEM_CALL] = "SystemCall",
+ [EID_MEMORY_MANAGEMENT] = "MemoryManagement",
+ [EID_UNRECOVERABLE] = "Unrecoverable",
+ [EID_INTERRUPTn+0] = "Interrupt0",
+ [EID_INTERRUPTn+1] = "Interrupt1",
+ [EID_INTERRUPTn+2] = "Interrupt2",
+ [EID_INTERRUPTn+3] = "Interrupt3",
+ [EID_INTERRUPTn+4] = "Interrupt4",
+ [EID_INTERRUPTn+5] = "Interrupt5",
+ [EID_INTERRUPTn+6] = "Interrupt6",
+ [EID_INTERRUPTn+7] = "Interrupt7",
+ [EID_INTERRUPTn+8] = "Interrupt8",
+ [EID_INTERRUPTn+9] = "Interrupt9",
+ [EID_INTERRUPTn+10] = "Interrupt10",
+ [EID_INTERRUPTn+11] = "Interrupt11",
+ [EID_INTERRUPTn+12] = "Interrupt12",
+ [EID_INTERRUPTn+13] = "Interrupt13",
+ [EID_INTERRUPTn+14] = "Interrupt14",
+ [EID_INTERRUPTn+15] = "Interrupt15",
+ [EID_INTERRUPTn+16] = "Interrupt16",
+ [EID_INTERRUPTn+17] = "Interrupt17",
+ [EID_INTERRUPTn+18] = "Interrupt18",
+ [EID_INTERRUPTn+19] = "Interrupt19",
+ [EID_INTERRUPTn+20] = "Interrupt20",
+ [EID_INTERRUPTn+21] = "Interrupt21",
+ [EID_INTERRUPTn+22] = "Interrupt22",
+ [EID_INTERRUPTn+23] = "Interrupt23",
+ [EID_INTERRUPTn+24] = "Interrupt24",
+ [EID_INTERRUPTn+25] = "Interrupt25",
+ [EID_INTERRUPTn+26] = "Interrupt26",
+ [EID_INTERRUPTn+27] = "Interrupt27",
+ [EID_INTERRUPTn+28] = "Interrupt28",
+ [EID_INTERRUPTn+29] = "Interrupt29",
+ [EID_INTERRUPTn+30] = "Interrupt30",
+ [EID_INTERRUPTn+31] = "Interrupt31",
};
/*
retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, &etc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: ETC", target_name(target));
+ LOG_ERROR("%s: failed to read Thread CSR: ETC", target_name(target));
return retval;
}
retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, etc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: ETC", target_name(target));
+ LOG_ERROR("%s: failed to write Thread CSR: ETC", target_name(target));
return retval;
}
retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, &etc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: ETC", target_name(target));
+ LOG_ERROR("%s: failed to read Thread CSR: ETC", target_name(target));
return retval;
}
retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, etc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: ETC", target_name(target));
+ LOG_ERROR("%s: failed to write Thread CSR: ETC", target_name(target));
return retval;
}
int retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC,
&esirisc->etc_save);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: ETC", target_name(target));
+ LOG_ERROR("%s: failed to read Thread CSR: ETC", target_name(target));
return retval;
}
int retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC,
esirisc->etc_save);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: ETC", target_name(target));
+ LOG_ERROR("%s: failed to write Thread CSR: ETC", target_name(target));
return retval;
}
int retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_HWDC,
&esirisc->hwdc_save);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: HWDC", target_name(target));
+ LOG_ERROR("%s: failed to read Thread CSR: HWDC", target_name(target));
return retval;
}
int retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_HWDC,
esirisc->hwdc_save);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: HWDC", target_name(target));
+ LOG_ERROR("%s: failed to write Debug CSR: HWDC", target_name(target));
return retval;
}
retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBAn + bp_index,
breakpoint->address);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: IBA", target_name(target));
+ LOG_ERROR("%s: failed to write Debug CSR: IBA", target_name(target));
return retval;
}
/* enable instruction breakpoint */
retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, &ibc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: IBC", target_name(target));
+ LOG_ERROR("%s: failed to read Debug CSR: IBC", target_name(target));
return retval;
}
retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, ibc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: IBC", target_name(target));
+ LOG_ERROR("%s: failed to write Debug CSR: IBC", target_name(target));
return retval;
}
/* disable instruction breakpoint */
retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, &ibc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: IBC", target_name(target));
+ LOG_ERROR("%s: failed to read Debug CSR: IBC", target_name(target));
return retval;
}
retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, ibc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: IBC", target_name(target));
+ LOG_ERROR("%s: failed to write Debug CSR: IBC", target_name(target));
return retval;
}
/* clear instruction breakpoints */
int retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, 0);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: IBC", target_name(target));
+ LOG_ERROR("%s: failed to write Debug CSR: IBC", target_name(target));
return retval;
}
retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBAn + wp_index,
watchpoint->address);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: DBA", target_name(target));
+ LOG_ERROR("%s: failed to write Debug CSR: DBA", target_name(target));
return retval;
}
/* specify data breakpoint size */
retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBS, &dbs);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: DBS", target_name(target));
+ LOG_ERROR("%s: failed to read Debug CSR: DBS", target_name(target));
return retval;
}
retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBS, dbs);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: DBS", target_name(target));
+ LOG_ERROR("%s: failed to write Debug CSR: DBS", target_name(target));
return retval;
}
/* enable data breakpoint */
retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, &dbc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: DBC", target_name(target));
+ LOG_ERROR("%s: failed to read Debug CSR: DBC", target_name(target));
return retval;
}
retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, dbc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: DBC", target_name(target));
+ LOG_ERROR("%s: failed to write Debug CSR: DBC", target_name(target));
return retval;
}
/* disable data breakpoint */
retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, &dbc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: DBC", target_name(target));
+ LOG_ERROR("%s: failed to read Debug CSR: DBC", target_name(target));
return retval;
}
retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, dbc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: DBC", target_name(target));
+ LOG_ERROR("%s: failed to write Debug CSR: DBC", target_name(target));
return retval;
}
/* clear data breakpoints */
int retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, 0);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: DBC", target_name(target));
+ LOG_ERROR("%s: failed to write Debug CSR: DBC", target_name(target));
return retval;
}
retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, &dc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: DC", target_name(target));
+ LOG_ERROR("%s: failed to read Debug CSR: DC", target_name(target));
return retval;
}
retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, dc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: DC", target_name(target));
+ LOG_ERROR("%s: failed to write Debug CSR: DC", target_name(target));
return retval;
}
retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, &dc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: DC", target_name(target));
+ LOG_ERROR("%s: failed to read Debug CSR: DC", target_name(target));
return retval;
}
retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, dc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: DC", target_name(target));
+ LOG_ERROR("%s: failed to write Debug CSR: DC", target_name(target));
return retval;
}
/* read exception table address */
retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETA, &eta);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: ETA", target_name(target));
+ LOG_ERROR("%s: failed to read Thread CSR: ETA", target_name(target));
return retval;
}
/* write reset entry point */
retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_EPC, epc);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to write CSR: EPC", target_name(target));
+ LOG_ERROR("%s: failed to write Thread CSR: EPC", target_name(target));
return retval;
}
uint32_t eid = buf_get_u32(esirisc->eid->value, 0, esirisc->eid->size);
uint32_t ed = buf_get_u32(esirisc->ed->value, 0, esirisc->ed->size);
- LOG_DEBUG("-");
-
- const char *exception = "Unknown";
- if (eid < ARRAY_SIZE(esirisc_exceptions))
- exception = esirisc_exceptions[eid];
-
LOG_USER("target halted due to %s, exception: %s\n"
- "EPC: 0x%" PRIx32 " ECAS: 0x%" PRIx32 " EID: 0x%" PRIx32 " ED: 0x%" PRIx32,
- debug_reason_name(target), exception, epc, ecas, eid, ed);
+ "EPC: 0x%" PRIx32 ", ECAS: 0x%" PRIx32 ", EID: 0x%" PRIx32 ", ED: 0x%" PRIx32,
+ debug_reason_name(target), esirisc_exception_strings[eid], epc, ecas, eid, ed);
return ERROR_OK;
}
*/
if (esirisc->gdb_arch == NULL && target_was_examined(target))
esirisc->gdb_arch = alloc_printf("esirisc:%d_bit_%d_reg_%s",
- esirisc->num_bits, esirisc->num_regs, esirisc_cache_arch(esirisc));
+ esirisc->num_bits, esirisc->num_regs, esirisc_cache_arch_name(esirisc));
return esirisc->gdb_arch;
}
retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_ARCH0, &csr);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: ARCH0", target_name(target));
+ LOG_ERROR("%s: failed to read Configuration CSR: ARCH0", target_name(target));
return retval;
}
retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_MEM, &csr);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: MEM", target_name(target));
+ LOG_ERROR("%s: failed to read Configuration CSR: MEM", target_name(target));
return retval;
}
retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_IC, &csr);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: IC", target_name(target));
+ LOG_ERROR("%s: failed to read Configuration CSR: IC", target_name(target));
return retval;
}
retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_DC, &csr);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: DC", target_name(target));
+ LOG_ERROR("%s: failed to read Configuration CSR: DC", target_name(target));
return retval;
}
retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_DBG, &csr);
if (retval != ERROR_OK) {
- LOG_ERROR("%s: failed to read CSR: DBG", target_name(target));
+ LOG_ERROR("%s: failed to read Configuration CSR: DBG", target_name(target));
return retval;
}
esirisc->num_breakpoints = (csr >> 7) & 0xf; /* DBG.BP */
esirisc->num_watchpoints = (csr >> 12) & 0xf; /* DBG.WP */
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_TRACE, &csr);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read Configuration CSR: TRACE", target_name(target));
+ return retval;
+ }
+
+ esirisc->has_trace = !!(csr & 1<<0); /* TRACE.T */
+
return ERROR_OK;
}
target_set_examined(target);
LOG_INFO("%s: %d bit, %d registers, %s%s%s", target_name(target),
- esirisc->num_bits, esirisc->num_regs,
- target_endianness(target),
- esirisc->has_icache ? ", icache" : "",
- esirisc->has_dcache ? ", dcache" : "");
+ esirisc->num_bits, esirisc->num_regs,
+ target_endianness(target),
+ esirisc->has_icache ? ", icache" : "",
+ esirisc->has_dcache ? ", dcache" : "");
- LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints", target_name(target),
- esirisc->num_breakpoints, esirisc->num_watchpoints);
+ LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints%s", target_name(target),
+ esirisc->num_breakpoints, esirisc->num_watchpoints,
+ esirisc->has_trace ? ", trace" : "");
}
return ERROR_OK;
}
}
- command_print(CMD_CTX, "esirisc cache_arch %s", esirisc_cache_arch(esirisc));
+ command_print(CMD_CTX, "esirisc cache_arch %s", esirisc_cache_arch_name(esirisc));
return ERROR_OK;
}
}
static const struct command_registration esirisc_exec_command_handlers[] = {
- {
- .name = "cache_arch",
- .handler = handle_esirisc_cache_arch_command,
- .mode = COMMAND_ANY,
- .help = "configure cache architecture",
- .usage = "['harvard'|'von_neumann']",
- },
{
.name = "flush_caches",
.handler = handle_esirisc_flush_caches_command,
.help = "flush instruction and data caches",
.usage = "",
},
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration esirisc_any_command_handlers[] = {
+ {
+ .name = "cache_arch",
+ .handler = handle_esirisc_cache_arch_command,
+ .mode = COMMAND_ANY,
+ .help = "configure cache architecture",
+ .usage = "['harvard'|'von_neumann']",
+ },
{
.name = "hwdc",
.handler = handle_esirisc_hwdc_command,
.help = "configure hardware debug control",
.usage = "['all'|'none'|mask ...]",
},
+ {
+ .chain = esirisc_exec_command_handlers
+ },
+ {
+ .chain = esirisc_trace_command_handlers
+ },
COMMAND_REGISTRATION_DONE
};
.mode = COMMAND_ANY,
.help = "eSi-RISC command group",
.usage = "",
- .chain = esirisc_exec_command_handlers,
+ .chain = esirisc_any_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2018 by Square, Inc. *
+ * Steven Stallion <stallion@squareup.com> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/binarybuffer.h>
+#include <helper/command.h>
+#include <helper/fileio.h>
+#include <helper/log.h>
+#include <helper/types.h>
+#include <target/target.h>
+
+#include "esirisc.h"
+
+#define BIT_MASK(x) ((1 << (x)) - 1)
+
+/* Control Fields */
+#define CONTROL_ST (1<<0) /* Start */
+#define CONTROL_SP (1<<1) /* Stop */
+#define CONTROL_W (1<<2) /* Wrap */
+#define CONTROL_FC (1<<3) /* Flow Control */
+#define CONTROL_FMT(x) (((x) << 4) & 0x30) /* Format */
+#define CONTROL_PCB(x) (((x) << 10) & 0x7c00) /* PC Bits */
+
+/* Status Fields */
+#define STATUS_T (1<<0) /* Trace Started */
+#define STATUS_TD (1<<1) /* Trace Disabled */
+#define STATUS_W (1<<2) /* Wrapped */
+#define STATUS_O (1<<3) /* Overflow */
+
+/* Trigger Fields */
+#define TRIGGER_TST(x) (((x) << 0) & 0xf) /* Trigger Start */
+#define TRIGGER_DST (1<<7) /* Delay Start */
+#define TRIGGER_TSP(x) (((x) << 8) & 0xf00) /* Trigger Stop */
+#define TRIGGER_DSP (1<<15) /* Delay Start */
+
+static const char * const esirisc_trace_delay_strings[] = {
+ "none", "start", "stop", "both",
+};
+
+static const char * const esirisc_trace_format_strings[] = {
+ "full", "branch", "icache",
+};
+
+static const char * const esirisc_trace_id_strings[] = {
+ "sequential instruction",
+ "pipeline stall",
+ "direct branch",
+ "extended ID",
+};
+
+static const char * const esirisc_trace_ext_id_strings[] = {
+ "", /* unused */
+ "exception",
+ "eret",
+ "stop instruction",
+ "wait instruction",
+ "multicycle instruction",
+ "count",
+ "initial",
+ "indirect branch",
+ "end of trace",
+ "final",
+};
+
+static const char * const esirisc_trace_trigger_strings[] = {
+ "none", "pc", "load", "store", "exception", "eret", "wait", "stop",
+ "high", "low", /* start only */
+};
+
+static int esirisc_trace_clear_status(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ int retval;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_STATUS, ~0);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write Trace CSR: Status", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_trace_get_status(struct target *target, uint32_t *status)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ int retval = esirisc_jtag_read_csr(jtag_info, CSR_TRACE, CSR_TRACE_STATUS, status);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read Trace CSR: Status", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_trace_start(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ uint32_t control;
+ int retval;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_TRACE, CSR_TRACE_CONTROL, &control);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read Trace CSR: Control", target_name(target));
+ return retval;
+ }
+
+ control |= CONTROL_ST;
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_CONTROL, control);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write Trace CSR: Control", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_trace_stop(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ uint32_t control;
+ int retval;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_TRACE, CSR_TRACE_CONTROL, &control);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read Trace CSR: Control", target_name(target));
+ return retval;
+ }
+
+ control |= CONTROL_SP;
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_CONTROL, control);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write Trace CSR: Control", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_trace_init(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+ uint32_t control, trigger;
+ int retval;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ /* stop if running and clear status */
+ retval = esirisc_trace_stop(target);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = esirisc_trace_clear_status(target);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* initialize Control CSR */
+ control = CONTROL_FMT(trace_info->format)
+ | CONTROL_PCB(trace_info->pc_bits);
+
+ if (trace_info->buffer_wrap)
+ control |= CONTROL_W;
+
+ if (trace_info->flow_control)
+ control |= CONTROL_FC;
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_CONTROL, control);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write Trace CSR: Control", target_name(target));
+ return retval;
+ }
+
+ /* initialize buffer CSRs */
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_BUFFER_START,
+ trace_info->buffer_start);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write Trace CSR: BufferStart", target_name(target));
+ return retval;
+ }
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_BUFFER_END,
+ trace_info->buffer_end);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write Trace CSR: BufferEnd", target_name(target));
+ return retval;
+ }
+
+ /*
+ * The BufferCurrent CSR must be initialized to the same value as
+ * BufferStart before tracing can be enabled:
+ */
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_BUFFER_CUR,
+ trace_info->buffer_start);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write Trace CSR: BufferCurrent", target_name(target));
+ return retval;
+ }
+
+ /* initialize Trigger CSR */
+ trigger = TRIGGER_TST(trace_info->start_trigger)
+ | TRIGGER_TSP(trace_info->stop_trigger);
+
+ if (trace_info->delay == ESIRISC_TRACE_DELAY_START
+ || trace_info->delay == ESIRISC_TRACE_DELAY_BOTH) {
+ trigger |= TRIGGER_DST;
+ }
+
+ if (trace_info->delay == ESIRISC_TRACE_DELAY_STOP
+ || trace_info->delay == ESIRISC_TRACE_DELAY_BOTH) {
+ trigger |= TRIGGER_DSP;
+ }
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_TRIGGER, trigger);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write Trace CSR: Trigger", target_name(target));
+ return retval;
+ }
+
+ /* initialize StartData/StartMask CSRs */
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_START_DATA,
+ trace_info->start_data);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write Trace CSR: StartData", target_name(target));
+ return retval;
+ }
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_START_MASK,
+ trace_info->start_mask);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write Trace CSR: StartMask", target_name(target));
+ return retval;
+ }
+
+ /* initialize StopData/StopMask CSRs */
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_STOP_DATA,
+ trace_info->stop_data);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write Trace CSR: StopData", target_name(target));
+ return retval;
+ }
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_STOP_MASK,
+ trace_info->stop_mask);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write Trace CSR: StopMask", target_name(target));
+ return retval;
+ }
+
+ /* initialize Delay CSR */
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_DELAY,
+ trace_info->delay_cycles);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write Trace CSR: Delay", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_trace_buf_get_u32(uint8_t *buffer, uint32_t size,
+ unsigned *pos, unsigned count, uint32_t *value)
+{
+ const unsigned num_bits = size * 8;
+
+ if (*pos+count > num_bits)
+ return ERROR_FAIL;
+
+ *value = buf_get_u32(buffer, *pos, count);
+ *pos += count;
+
+ return ERROR_OK;
+}
+
+static int esirisc_trace_buf_get_pc(struct target *target, uint8_t *buffer, uint32_t size,
+ unsigned *pos, uint32_t *value)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+ int retval;
+
+ retval = esirisc_trace_buf_get_u32(buffer, size, pos, trace_info->pc_bits, value);
+ if (retval != ERROR_OK)
+ return retval;
+
+ *value <<= esirisc->num_bits - trace_info->pc_bits;
+
+ return ERROR_OK;
+}
+
+static int esirisc_trace_read_memory(struct target *target, target_addr_t address, uint32_t size,
+ uint8_t *buffer)
+{
+ int retval;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ retval = target_read_memory(target, address, 1, size, buffer);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read trace data", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_trace_read_buffer(struct target *target, uint8_t *buffer)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+ uint32_t buffer_cur, status;
+ int retval;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_TRACE, CSR_TRACE_BUFFER_CUR, &buffer_cur);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read Trace CSR: BufferCurrent", target_name(target));
+ return retval;
+ }
+
+ /*
+ * If the buffer has wrapped, the BufferCurrent CSR indicates the
+ * next address to be written (ie. the start address). These bytes
+ * must be dumped first to maintain coherency when analyzing
+ * captured data.
+ */
+ retval = esirisc_trace_get_status(target, &status);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (status & STATUS_W) {
+ uint32_t size = trace_info->buffer_end - buffer_cur;
+
+ retval = esirisc_trace_read_memory(target, buffer_cur, size, buffer);
+ if (retval != ERROR_OK)
+ return retval;
+
+ buffer += size;
+ }
+
+ return esirisc_trace_read_memory(target, trace_info->buffer_start,
+ buffer_cur - trace_info->buffer_start, buffer);
+}
+
+static int esirisc_trace_analyze_full(struct command_context *cmd_ctx, uint8_t *buffer, uint32_t size)
+{
+ struct target *target = get_current_target(cmd_ctx);
+ const uint32_t num_bits = size * 8;
+ int retval;
+
+ unsigned pos = 0;
+ while (pos < num_bits) {
+ uint32_t id;
+
+ retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 2, &id);
+ if (retval != ERROR_OK)
+ goto fail;
+
+ switch (id) {
+ case ESIRISC_TRACE_ID_EXECUTE:
+ case ESIRISC_TRACE_ID_STALL:
+ case ESIRISC_TRACE_ID_BRANCH:
+ command_print(cmd_ctx, "%s", esirisc_trace_id_strings[id]);
+ break;
+
+ case ESIRISC_TRACE_ID_EXTENDED: {
+ uint32_t ext_id;
+
+ retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 4, &ext_id);
+ if (retval != ERROR_OK)
+ goto fail;
+
+ switch (ext_id) {
+ case ESIRISC_TRACE_EXT_ID_STOP:
+ case ESIRISC_TRACE_EXT_ID_WAIT:
+ case ESIRISC_TRACE_EXT_ID_MULTICYCLE:
+ command_print(cmd_ctx, "%s", esirisc_trace_ext_id_strings[ext_id]);
+ break;
+
+ case ESIRISC_TRACE_EXT_ID_ERET:
+ case ESIRISC_TRACE_EXT_ID_PC:
+ case ESIRISC_TRACE_EXT_ID_INDIRECT:
+ case ESIRISC_TRACE_EXT_ID_END_PC: {
+ uint32_t pc;
+
+ retval = esirisc_trace_buf_get_pc(target, buffer, size, &pos, &pc);
+ if (retval != ERROR_OK)
+ goto fail;
+
+ command_print(cmd_ctx, "%s PC: 0x%" PRIx32,
+ esirisc_trace_ext_id_strings[ext_id], pc);
+
+ if (ext_id == ESIRISC_TRACE_EXT_ID_END_PC) {
+ command_print(cmd_ctx, "--- end of trace ---");
+ return ERROR_OK;
+ }
+ break;
+ }
+ case ESIRISC_TRACE_EXT_ID_EXCEPTION: {
+ uint32_t eid, epc;
+
+ retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 6, &eid);
+ if (retval != ERROR_OK)
+ goto fail;
+
+ retval = esirisc_trace_buf_get_pc(target, buffer, size, &pos, &epc);
+ if (retval != ERROR_OK)
+ goto fail;
+
+ command_print(cmd_ctx, "%s EID: 0x%" PRIx32 ", EPC: 0x%" PRIx32,
+ esirisc_trace_ext_id_strings[ext_id], eid, epc);
+ break;
+ }
+ case ESIRISC_TRACE_EXT_ID_COUNT: {
+ uint32_t count;
+
+ retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 6, &count);
+ if (retval != ERROR_OK)
+ goto fail;
+
+ command_print(cmd_ctx, "repeats %" PRId32 " %s", count,
+ (count == 1) ? "time" : "times");
+ break;
+ }
+ case ESIRISC_TRACE_EXT_ID_END:
+ command_print(cmd_ctx, "--- end of trace ---");
+ return ERROR_OK;
+
+ default:
+ command_print(cmd_ctx, "invalid extended trace ID: %" PRId32, ext_id);
+ return ERROR_FAIL;
+ }
+ break;
+ }
+ default:
+ command_print(cmd_ctx, "invalid trace ID: %" PRId32, id);
+ return ERROR_FAIL;
+ }
+ }
+
+fail:
+ command_print(cmd_ctx, "trace buffer too small");
+ return ERROR_BUF_TOO_SMALL;
+}
+
+static int esirisc_trace_analyze_simple(struct command_context *cmd_ctx, uint8_t *buffer, uint32_t size)
+{
+ struct target *target = get_current_target(cmd_ctx);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+ const uint32_t end_of_trace = BIT_MASK(trace_info->pc_bits) << 1;
+ const uint32_t num_bits = size * 8;
+ int retval;
+
+ unsigned pos = 0;
+ while (pos < num_bits) {
+ uint32_t pc;
+
+ retval = esirisc_trace_buf_get_pc(target, buffer, size, &pos, &pc);
+ if (retval != ERROR_OK)
+ break;
+
+ if (pc == end_of_trace) {
+ command_print(cmd_ctx, "--- end of trace ---");
+ return ERROR_OK;
+ }
+
+ command_print(cmd_ctx, "PC: 0x%" PRIx32, pc);
+ }
+
+ command_print(cmd_ctx, "trace buffer too small");
+ return ERROR_BUF_TOO_SMALL;
+}
+
+static int esirisc_trace_analyze(struct command_context *cmd_ctx, uint8_t *buffer, uint32_t size)
+{
+ struct target *target = get_current_target(cmd_ctx);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+
+ switch (trace_info->format) {
+ case ESIRISC_TRACE_FORMAT_FULL:
+ command_print(cmd_ctx, "--- full pipeline ---");
+ return esirisc_trace_analyze_full(cmd_ctx, buffer, size);
+
+ case ESIRISC_TRACE_FORMAT_BRANCH:
+ command_print(cmd_ctx, "--- branches taken ---");
+ return esirisc_trace_analyze_full(cmd_ctx, buffer, size);
+
+ case ESIRISC_TRACE_FORMAT_ICACHE:
+ command_print(cmd_ctx, "--- icache misses ---");
+ return esirisc_trace_analyze_simple(cmd_ctx, buffer, size);
+
+ default:
+ command_print(cmd_ctx, "invalid trace format: %i", trace_info->format);
+ return ERROR_FAIL;
+ }
+}
+
+static int esirisc_trace_analyze_buffer(struct command_context *cmd_ctx)
+{
+ struct target *target = get_current_target(cmd_ctx);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+ uint8_t *buffer;
+ uint32_t size;
+ int retval;
+
+ size = esirisc_trace_buffer_size(trace_info);
+ buffer = calloc(1, size);
+ if (buffer == NULL) {
+ command_print(cmd_ctx, "out of memory");
+ return ERROR_FAIL;
+ }
+
+ retval = esirisc_trace_read_buffer(target, buffer);
+ if (retval != ERROR_OK)
+ goto done;
+
+ retval = esirisc_trace_analyze(cmd_ctx, buffer, size);
+
+done:
+ free(buffer);
+
+ return retval;
+}
+
+static int esirisc_trace_analyze_memory(struct command_context *cmd_ctx,
+ target_addr_t address, uint32_t size)
+{
+ struct target *target = get_current_target(cmd_ctx);
+ uint8_t *buffer;
+ int retval;
+
+ buffer = calloc(1, size);
+ if (buffer == NULL) {
+ command_print(cmd_ctx, "out of memory");
+ return ERROR_FAIL;
+ }
+
+ retval = esirisc_trace_read_memory(target, address, size, buffer);
+ if (retval != ERROR_OK)
+ goto done;
+
+ retval = esirisc_trace_analyze(cmd_ctx, buffer, size);
+
+done:
+ free(buffer);
+
+ return retval;
+}
+
+static int esirisc_trace_dump(struct command_context *cmd_ctx, const char *filename,
+ uint8_t *buffer, uint32_t size)
+{
+ struct fileio *fileio;
+ size_t size_written;
+ int retval;
+
+ retval = fileio_open(&fileio, filename, FILEIO_WRITE, FILEIO_BINARY);
+ if (retval != ERROR_OK) {
+ command_print(cmd_ctx, "could not open dump file: %s", filename);
+ return retval;
+ }
+
+ retval = fileio_write(fileio, size, buffer, &size_written);
+ if (retval == ERROR_OK)
+ command_print(cmd_ctx, "trace data dumped to: %s", filename);
+ else
+ command_print(cmd_ctx, "could not write dump file: %s", filename);
+
+ fileio_close(fileio);
+
+ return retval;
+}
+
+static int esirisc_trace_dump_buffer(struct command_context *cmd_ctx, const char *filename)
+{
+ struct target *target = get_current_target(cmd_ctx);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+ uint8_t *buffer;
+ uint32_t size;
+ int retval;
+
+ size = esirisc_trace_buffer_size(trace_info);
+ buffer = calloc(1, size);
+ if (buffer == NULL) {
+ command_print(cmd_ctx, "out of memory");
+ return ERROR_FAIL;
+ }
+
+ retval = esirisc_trace_read_buffer(target, buffer);
+ if (retval != ERROR_OK)
+ goto done;
+
+ retval = esirisc_trace_dump(cmd_ctx, filename, buffer, size);
+
+done:
+ free(buffer);
+
+ return retval;
+}
+
+static int esirisc_trace_dump_memory(struct command_context *cmd_ctx, const char *filename,
+ target_addr_t address, uint32_t size)
+{
+ struct target *target = get_current_target(cmd_ctx);
+ uint8_t *buffer;
+ int retval;
+
+ buffer = calloc(1, size);
+ if (buffer == NULL) {
+ command_print(cmd_ctx, "out of memory");
+ return ERROR_FAIL;
+ }
+
+ retval = esirisc_trace_read_memory(target, address, size, buffer);
+ if (retval != ERROR_OK)
+ goto done;
+
+ retval = esirisc_trace_dump(cmd_ctx, filename, buffer, size);
+
+done:
+ free(buffer);
+
+ return retval;
+}
+
+COMMAND_HANDLER(handle_esirisc_trace_init_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+
+ if (!esirisc->has_trace) {
+ command_print(CMD_CTX, "target does not support trace");
+ return ERROR_FAIL;
+ }
+
+ int retval = esirisc_trace_init(target);
+ if (retval == ERROR_OK)
+ command_print(CMD_CTX, "trace initialized");
+
+ return retval;
+}
+
+COMMAND_HANDLER(handle_esirisc_trace_info_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+
+ if (!esirisc->has_trace) {
+ command_print(CMD_CTX, "target does not support trace");
+ return ERROR_FAIL;
+ }
+
+ if (esirisc_trace_is_fifo(trace_info))
+ command_print(CMD_CTX, "trace FIFO address: 0x%" TARGET_PRIxADDR,
+ trace_info->buffer_start);
+ else {
+ command_print(CMD_CTX, "trace buffer start: 0x%" TARGET_PRIxADDR,
+ trace_info->buffer_start);
+ command_print(CMD_CTX, "trace buffer end: 0x%" TARGET_PRIxADDR,
+ trace_info->buffer_end);
+ command_print(CMD_CTX, "trace buffer will %swrap",
+ trace_info->buffer_wrap ? "" : "not ");
+ }
+
+ command_print(CMD_CTX, "flow control: %s",
+ trace_info->flow_control ? "enabled" : "disabled");
+
+ command_print(CMD_CTX, "trace format: %s",
+ esirisc_trace_format_strings[trace_info->format]);
+ command_print(CMD_CTX, "number of PC bits: %i", trace_info->pc_bits);
+
+ command_print(CMD_CTX, "start trigger: %s",
+ esirisc_trace_trigger_strings[trace_info->start_trigger]);
+ command_print(CMD_CTX, "start data: 0x%" PRIx32, trace_info->start_data);
+ command_print(CMD_CTX, "start mask: 0x%" PRIx32, trace_info->start_mask);
+
+ command_print(CMD_CTX, "stop trigger: %s",
+ esirisc_trace_trigger_strings[trace_info->stop_trigger]);
+ command_print(CMD_CTX, "stop data: 0x%" PRIx32, trace_info->stop_data);
+ command_print(CMD_CTX, "stop mask: 0x%" PRIx32, trace_info->stop_mask);
+
+ command_print(CMD_CTX, "trigger delay: %s",
+ esirisc_trace_delay_strings[trace_info->delay]);
+ command_print(CMD_CTX, "trigger delay cycles: %i", trace_info->delay_cycles);
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_esirisc_trace_status_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ uint32_t status;
+
+ if (!esirisc->has_trace) {
+ command_print(CMD_CTX, "target does not support trace");
+ return ERROR_FAIL;
+ }
+
+ int retval = esirisc_trace_get_status(target, &status);
+ if (retval != ERROR_OK)
+ return retval;
+
+ command_print(CMD_CTX, "trace is %s%s%s%s",
+ (status & STATUS_T) ? "started" : "stopped",
+ (status & STATUS_TD) ? ", disabled" : "",
+ (status & STATUS_W) ? ", wrapped" : "",
+ (status & STATUS_O) ? ", overflowed" : "");
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_esirisc_trace_start_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+
+ if (!esirisc->has_trace) {
+ command_print(CMD_CTX, "target does not support trace");
+ return ERROR_FAIL;
+ }
+
+ int retval = esirisc_trace_start(target);
+ if (retval == ERROR_OK)
+ command_print(CMD_CTX, "trace started");
+
+ return retval;
+}
+
+COMMAND_HANDLER(handle_esirisc_trace_stop_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+
+ if (!esirisc->has_trace) {
+ command_print(CMD_CTX, "target does not support trace");
+ return ERROR_FAIL;
+ }
+
+ int retval = esirisc_trace_stop(target);
+ if (retval == ERROR_OK)
+ command_print(CMD_CTX, "trace stopped");
+
+ return retval;
+}
+
+COMMAND_HANDLER(handle_esirisc_trace_analyze_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+ target_addr_t address;
+ uint32_t size;
+
+ if (!esirisc->has_trace) {
+ command_print(CMD_CTX, "target does not support trace");
+ return ERROR_FAIL;
+ }
+
+ if (CMD_ARGC != 0 && CMD_ARGC != 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (CMD_ARGC == 0) {
+ /*
+ * Use of the Trace FIFO typically involves DMA to a peripheral
+ * (eg. SPI) or a separately managed buffer in memory, neither
+ * of which may be under our control. If the destination address
+ * and size are known in the latter case, they may be specified
+ * as arguments as a workaround.
+ */
+ if (esirisc_trace_is_fifo(trace_info)) {
+ command_print(CMD_CTX, "analyze from FIFO not supported");
+ return ERROR_FAIL;
+ }
+
+ return esirisc_trace_analyze_buffer(CMD_CTX);
+ } else {
+ COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
+
+ return esirisc_trace_analyze_memory(CMD_CTX, address, size);
+ }
+}
+
+COMMAND_HANDLER(handle_esirisc_trace_dump_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+ target_addr_t address;
+ uint32_t size;
+
+ if (!esirisc->has_trace) {
+ command_print(CMD_CTX, "target does not support trace");
+ return ERROR_FAIL;
+ }
+
+ if (CMD_ARGC != 1 && CMD_ARGC != 3)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (CMD_ARGC == 1) {
+ /* also see: handle_esirisc_trace_analyze_command() */
+ if (esirisc_trace_is_fifo(trace_info)) {
+ command_print(CMD_CTX, "dump from FIFO not supported");
+ return ERROR_FAIL;
+ }
+
+ return esirisc_trace_dump_buffer(CMD_CTX, CMD_ARGV[0]);
+ } else {
+ COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
+
+ return esirisc_trace_dump_memory(CMD_CTX, CMD_ARGV[2], address, size);
+ }
+}
+
+COMMAND_HANDLER(handle_esirisc_trace_buffer_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+ uint32_t size;
+
+ if (CMD_ARGC < 2 || CMD_ARGC > 3)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_ADDRESS(CMD_ARGV[0], trace_info->buffer_start);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
+
+ trace_info->buffer_end = trace_info->buffer_start + size;
+
+ if (CMD_ARGC == 3) {
+ if (strcmp("wrap", CMD_ARGV[2]) == 0)
+ trace_info->buffer_wrap = true;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_esirisc_trace_fifo_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_ADDRESS(CMD_ARGV[0], trace_info->buffer_start);
+
+ /* FIFOs have the same start and end address */
+ trace_info->buffer_end = trace_info->buffer_start;
+ trace_info->buffer_wrap = true;
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_esirisc_trace_flow_control_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (strcmp(CMD_ARGV[0], "enable") == 0)
+ trace_info->flow_control = true;
+ else if (strcmp(CMD_ARGV[0], "disable") == 0)
+ trace_info->flow_control = false;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_esirisc_trace_format_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+ int pc_bits;
+
+ if (CMD_ARGC != 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (strcmp(CMD_ARGV[0], "full") == 0)
+ trace_info->format = ESIRISC_TRACE_FORMAT_FULL;
+ else if (strcmp(CMD_ARGV[0], "branch") == 0)
+ trace_info->format = ESIRISC_TRACE_FORMAT_BRANCH;
+ else if (strcmp(CMD_ARGV[0], "icache") == 0)
+ trace_info->format = ESIRISC_TRACE_FORMAT_ICACHE;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], pc_bits);
+
+ if (pc_bits < 1 || pc_bits > 31) {
+ command_print(CMD_CTX, "invalid pc_bits: %i; must be 1..31", pc_bits);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ trace_info->pc_bits = pc_bits;
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_esirisc_trace_trigger_start_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+
+ if (CMD_ARGC != 1 && CMD_ARGC != 3)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (strcmp(CMD_ARGV[0], "none") == 0)
+ trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_NONE;
+ else if (strcmp(CMD_ARGV[0], "pc") == 0)
+ trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_PC;
+ else if (strcmp(CMD_ARGV[0], "load") == 0)
+ trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_LOAD;
+ else if (strcmp(CMD_ARGV[0], "store") == 0)
+ trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_STORE;
+ else if (strcmp(CMD_ARGV[0], "exception") == 0)
+ trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_EXCEPTION;
+ else if (strcmp(CMD_ARGV[0], "eret") == 0)
+ trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_ERET;
+ else if (strcmp(CMD_ARGV[0], "wait") == 0)
+ trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_WAIT;
+ else if (strcmp(CMD_ARGV[0], "stop") == 0)
+ trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_STOP;
+ else if (strcmp(CMD_ARGV[0], "high") == 0)
+ trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_HIGH;
+ else if (strcmp(CMD_ARGV[0], "low") == 0)
+ trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_LOW;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (CMD_ARGC == 3) {
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], trace_info->start_data);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], trace_info->start_mask);
+ } else {
+ trace_info->start_data = 0;
+ trace_info->start_mask = 0;
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_esirisc_trace_trigger_stop_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+
+ if (CMD_ARGC != 1 && CMD_ARGC != 3)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (strcmp(CMD_ARGV[0], "none") == 0)
+ trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_NONE;
+ else if (strcmp(CMD_ARGV[0], "pc") == 0)
+ trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_PC;
+ else if (strcmp(CMD_ARGV[0], "load") == 0)
+ trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_LOAD;
+ else if (strcmp(CMD_ARGV[0], "store") == 0)
+ trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_STORE;
+ else if (strcmp(CMD_ARGV[0], "exception") == 0)
+ trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_EXCEPTION;
+ else if (strcmp(CMD_ARGV[0], "eret") == 0)
+ trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_ERET;
+ else if (strcmp(CMD_ARGV[0], "wait") == 0)
+ trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_WAIT;
+ else if (strcmp(CMD_ARGV[0], "stop") == 0)
+ trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_STOP;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (CMD_ARGC == 3) {
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], trace_info->stop_data);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], trace_info->stop_mask);
+ } else {
+ trace_info->stop_data = 0;
+ trace_info->stop_mask = 0;
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_esirisc_trace_trigger_delay_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_trace *trace_info = &esirisc->trace_info;
+
+ if (CMD_ARGC < 1 || CMD_ARGC > 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (strcmp(CMD_ARGV[0], "none") == 0)
+ trace_info->delay = ESIRISC_TRACE_DELAY_NONE;
+ else if (strcmp(CMD_ARGV[0], "start") == 0)
+ trace_info->delay = ESIRISC_TRACE_DELAY_START;
+ else if (strcmp(CMD_ARGV[0], "stop") == 0)
+ trace_info->delay = ESIRISC_TRACE_DELAY_STOP;
+ else if (strcmp(CMD_ARGV[0], "both") == 0)
+ trace_info->delay = ESIRISC_TRACE_DELAY_BOTH;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (trace_info->delay == ESIRISC_TRACE_DELAY_NONE)
+ trace_info->delay_cycles = 0;
+ else {
+ if (CMD_ARGC != 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], trace_info->delay_cycles);
+ }
+
+ return ERROR_OK;
+}
+
+static const struct command_registration esirisc_trace_exec_command_handlers[] = {
+ {
+ .name = "init",
+ .handler = handle_esirisc_trace_init_command,
+ .mode = COMMAND_EXEC,
+ .help = "initialize trace collection",
+ .usage = "",
+ },
+ {
+ .name = "info",
+ .handler = handle_esirisc_trace_info_command,
+ .mode = COMMAND_EXEC,
+ .help = "display trace configuration",
+ .usage = "",
+ },
+ {
+ .name = "status",
+ .handler = handle_esirisc_trace_status_command,
+ .mode = COMMAND_EXEC,
+ .help = "display trace collection status",
+ .usage = "",
+ },
+ {
+ .name = "start",
+ .handler = handle_esirisc_trace_start_command,
+ .mode = COMMAND_EXEC,
+ .help = "start trace collection",
+ .usage = "",
+ },
+ {
+ .name = "stop",
+ .handler = handle_esirisc_trace_stop_command,
+ .mode = COMMAND_EXEC,
+ .help = "stop trace collection",
+ .usage = "",
+ },
+ {
+ .name = "analyze",
+ .handler = handle_esirisc_trace_analyze_command,
+ .mode = COMMAND_EXEC,
+ .usage = "[address size]",
+ .help = "analyze collected trace data",
+ },
+ {
+ .name = "dump",
+ .handler = handle_esirisc_trace_dump_command,
+ .mode = COMMAND_EXEC,
+ .help = "dump collected trace data to file",
+ .usage = "[address size] filename",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration esirisc_trace_trigger_any_command_handlers[] = {
+ {
+ .name = "start",
+ .handler = handle_esirisc_trace_trigger_start_command,
+ .mode = COMMAND_ANY,
+ .help = "configure trigger start condition",
+ .usage = "('none'|'pc'|'load'|'store'|'exception'|'eret'|'wait'|'stop'|'high'|'low')"
+ " [start_data start_mask]",
+ },
+ {
+ .name = "stop",
+ .handler = handle_esirisc_trace_trigger_stop_command,
+ .mode = COMMAND_ANY,
+ .help = "configure trigger stop condition",
+ .usage = "('none'|'pc'|'load'|'store'|'exception'|'eret'|'wait'|'stop')"
+ " [stop_data stop_mask]",
+ },
+ {
+ .name = "delay",
+ .handler = handle_esirisc_trace_trigger_delay_command,
+ .mode = COMMAND_ANY,
+ .help = "configure trigger start/stop delay in clock cycles",
+ .usage = "('none'|'start'|'stop'|'both') [cycles]",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration esirisc_trace_any_command_handlers[] = {
+ {
+ .name = "buffer",
+ .handler = handle_esirisc_trace_buffer_command,
+ .mode = COMMAND_ANY,
+ .help = "configure trace buffer",
+ .usage = "address size ['wrap']",
+ },
+ {
+ .name = "fifo",
+ .handler = handle_esirisc_trace_fifo_command,
+ .mode = COMMAND_ANY,
+ .help = "configure trace FIFO",
+ .usage = "address",
+ },
+ {
+ .name = "flow_control",
+ .handler = handle_esirisc_trace_flow_control_command,
+ .mode = COMMAND_ANY,
+ .help = "enable or disable stalling CPU to collect trace data",
+ .usage = "('enable'|'disable')",
+ },
+ {
+ .name = "format",
+ .handler = handle_esirisc_trace_format_command,
+ .mode = COMMAND_ANY,
+ .help = "configure trace format",
+ .usage = "('full'|'branch'|'icache') pc_bits",
+ },
+ {
+ .name = "trigger",
+ .mode = COMMAND_ANY,
+ .help = "eSi-Trace trigger command group",
+ .usage = "",
+ .chain = esirisc_trace_trigger_any_command_handlers,
+ },
+ {
+ .chain = esirisc_trace_exec_command_handlers
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+const struct command_registration esirisc_trace_command_handlers[] = {
+ {
+ .name = "trace",
+ .mode = COMMAND_ANY,
+ .help = "eSi-Trace command group",
+ .usage = "",
+ .chain = esirisc_trace_any_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};