aboutsummaryrefslogtreecommitdiff
path: root/src/target
diff options
context:
space:
mode:
authorSteven Stallion <stallion@squareup.com>2018-10-24 21:29:03 -0500
committerMatthias Welwarsky <matthias@welwarsky.de>2018-12-12 08:47:44 +0000
commitc5eb99082535574167294443be1e60077e3f6246 (patch)
tree4c2421624ae987ffe38321e9360bb41582953f6c /src/target
parent7ae6b04b982428e6ae3d6daa6f5e77482a460c40 (diff)
esirisc: support eSi-Trace
This patch adds support for instruction tracing to eSi-RISC targets. The command interface is borrowed heavily from ETM; eSi-Trace uses a less sophisticated model for tracing, however the setup and usage is similar. This patch also cleans up the command interfaces of the other esirisc command groups and adds additional debugging information to log messages when dealing with CSRs. This patch "finalizes" support for 32-bit eSi-RISC targets. Change-Id: Ia2a9de79a3c7c066240b5212721fb1b7584a9a45 Signed-off-by: Steven Stallion <stallion@squareup.com> Reviewed-on: http://openocd.zylin.com/4780 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Diffstat (limited to 'src/target')
-rw-r--r--src/target/Makefile.am6
-rw-r--r--src/target/esirisc.c192
-rw-r--r--src/target/esirisc.h12
-rw-r--r--src/target/esirisc_jtag.c15
-rw-r--r--src/target/esirisc_jtag.h1
-rw-r--r--src/target/esirisc_trace.c1203
-rw-r--r--src/target/esirisc_trace.h105
7 files changed, 1456 insertions, 78 deletions
diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index 8e9fcb27..afa5f49b 100644
--- a/src/target/Makefile.am
+++ b/src/target/Makefile.am
@@ -143,7 +143,8 @@ INTEL_IA32_SRC = \
ESIRISC_SRC = \
%D%/esirisc.c \
- %D%/esirisc_jtag.c
+ %D%/esirisc_jtag.c \
+ %D%/esirisc_trace.c
%C%_libtarget_la_SOURCES += \
%D%/algorithm.h \
@@ -228,7 +229,8 @@ ESIRISC_SRC = \
%D%/arm_cti.h \
%D%/esirisc.h \
%D%/esirisc_jtag.h \
- %D%/esirisc_regs.h
+ %D%/esirisc_regs.h \
+ %D%/esirisc_trace.h
include %D%/openrisc/Makefile.am
include %D%/riscv/Makefile.am
diff --git a/src/target/esirisc.c b/src/target/esirisc.c
index 38100e83..3d2954fa 100644
--- a/src/target/esirisc.c
+++ b/src/target/esirisc.c
@@ -34,27 +34,60 @@
#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",
};
/*
@@ -142,7 +175,7 @@ static int esirisc_disable_interrupts(struct target *target)
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;
}
@@ -150,7 +183,7 @@ static int esirisc_disable_interrupts(struct target *target)
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;
}
@@ -169,7 +202,7 @@ static int esirisc_enable_interrupts(struct target *target)
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;
}
@@ -177,7 +210,7 @@ static int esirisc_enable_interrupts(struct target *target)
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;
}
@@ -195,7 +228,7 @@ static int esirisc_save_interrupts(struct target *target)
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;
}
@@ -212,7 +245,7 @@ static int esirisc_restore_interrupts(struct target *target)
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;
}
@@ -230,7 +263,7 @@ static int esirisc_save_hwdc(struct target *target)
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;
}
@@ -248,7 +281,7 @@ static int esirisc_restore_hwdc(struct target *target)
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;
}
@@ -478,14 +511,14 @@ static int esirisc_add_breakpoint(struct target *target, struct breakpoint *brea
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;
}
@@ -493,7 +526,7 @@ static int esirisc_add_breakpoint(struct target *target, struct breakpoint *brea
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;
}
@@ -529,7 +562,7 @@ static int esirisc_remove_breakpoint(struct target *target, struct breakpoint *b
/* 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;
}
@@ -537,7 +570,7 @@ static int esirisc_remove_breakpoint(struct target *target, struct breakpoint *b
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;
}
@@ -557,7 +590,7 @@ static int esirisc_remove_breakpoints(struct target *target)
/* 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;
}
@@ -604,14 +637,14 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc
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;
}
@@ -642,14 +675,14 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc
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;
}
@@ -677,7 +710,7 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc
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;
}
@@ -713,7 +746,7 @@ static int esirisc_remove_watchpoint(struct target *target, struct watchpoint *w
/* 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;
}
@@ -721,7 +754,7 @@ static int esirisc_remove_watchpoint(struct target *target, struct watchpoint *w
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;
}
@@ -741,7 +774,7 @@ static int esirisc_remove_watchpoints(struct target *target)
/* 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;
}
@@ -782,7 +815,7 @@ static int esirisc_disable_step(struct target *target)
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;
}
@@ -790,7 +823,7 @@ static int esirisc_disable_step(struct target *target)
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;
}
@@ -808,7 +841,7 @@ static int esirisc_enable_step(struct target *target)
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;
}
@@ -816,7 +849,7 @@ static int esirisc_enable_step(struct target *target)
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;
}
@@ -1132,7 +1165,7 @@ static int esirisc_reset_entry(struct target *target)
/* 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;
}
@@ -1147,7 +1180,7 @@ static int esirisc_reset_entry(struct target *target)
/* 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;
}
@@ -1215,15 +1248,9 @@ static int esirisc_arch_state(struct target *target)
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;
}
@@ -1242,7 +1269,7 @@ static const char *esirisc_get_gdb_arch(struct target *target)
*/
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;
}
@@ -1477,7 +1504,7 @@ static int esirisc_identify(struct target *target)
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;
}
@@ -1486,7 +1513,7 @@ static int esirisc_identify(struct target *target)
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;
}
@@ -1495,7 +1522,7 @@ static int esirisc_identify(struct target *target)
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;
}
@@ -1503,7 +1530,7 @@ static int esirisc_identify(struct target *target)
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;
}
@@ -1511,13 +1538,21 @@ static int esirisc_identify(struct target *target)
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;
}
@@ -1616,13 +1651,14 @@ static int esirisc_examine(struct target *target)
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;
@@ -1644,7 +1680,7 @@ COMMAND_HANDLER(handle_esirisc_cache_arch_command)
}
}
- 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;
}
@@ -1720,19 +1756,23 @@ COMMAND_HANDLER(handle_esirisc_hwdc_command)
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,
.mode = COMMAND_EXEC,
.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,
@@ -1740,6 +1780,12 @@ static const struct command_registration esirisc_exec_command_handlers[] = {
.help = "configure hardware debug control",
.usage = "['all'|'none'|mask ...]",
},
+ {
+ .chain = esirisc_exec_command_handlers
+ },
+ {
+ .chain = esirisc_trace_command_handlers
+ },
COMMAND_REGISTRATION_DONE
};
@@ -1749,7 +1795,7 @@ static const struct command_registration esirisc_command_handlers[] = {
.mode = COMMAND_ANY,
.help = "eSi-RISC command group",
.usage = "",
- .chain = esirisc_exec_command_handlers,
+ .chain = esirisc_any_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
diff --git a/src/target/esirisc.h b/src/target/esirisc.h
index bb50652a..57deba61 100644
--- a/src/target/esirisc.h
+++ b/src/target/esirisc.h
@@ -20,12 +20,14 @@
#ifndef OPENOCD_TARGET_ESIRISC_H
#define OPENOCD_TARGET_ESIRISC_H
+#include <helper/types.h>
#include <target/breakpoints.h>
#include <target/register.h>
#include <target/target.h>
#include "esirisc_jtag.h"
#include "esirisc_regs.h"
+#include "esirisc_trace.h"
#define MAX_BREAKPOINTS 8
#define MAX_WATCHPOINTS 8
@@ -88,11 +90,15 @@ struct esirisc_common {
int num_regs;
bool has_icache;
bool has_dcache;
- int num_breakpoints;
- int num_watchpoints;
+ bool has_trace;
+ int num_breakpoints;
struct breakpoint *breakpoints_p[MAX_BREAKPOINTS];
+
+ int num_watchpoints;
struct watchpoint *watchpoints_p[MAX_WATCHPOINTS];
+
+ struct esirisc_trace trace_info;
};
union esirisc_memory {
@@ -116,7 +122,7 @@ static inline struct esirisc_common *target_to_esirisc(struct target *target)
return (struct esirisc_common *)target->arch_info;
}
-static inline char *esirisc_cache_arch(struct esirisc_common *esirisc)
+static inline char *esirisc_cache_arch_name(struct esirisc_common *esirisc)
{
return esirisc->cache_arch == ESIRISC_CACHE_HARVARD ? "harvard" : "von_neumann";
}
diff --git a/src/target/esirisc_jtag.c b/src/target/esirisc_jtag.c
index 8ab47fa8..333a6222 100644
--- a/src/target/esirisc_jtag.c
+++ b/src/target/esirisc_jtag.c
@@ -265,6 +265,7 @@ int esirisc_jtag_read_byte(struct esirisc_jtag *jtag_info, uint32_t address, uin
return retval;
*data = *d;
+ LOG_DEBUG("address: 0x%" PRIx32 ", data: 0x%" PRIx8, address, *data);
return ERROR_OK;
}
@@ -292,6 +293,7 @@ int esirisc_jtag_read_hword(struct esirisc_jtag *jtag_info, uint32_t address, ui
return retval;
*data = le_to_h_u16(d);
+ LOG_DEBUG("address: 0x%" PRIx32 ", data: 0x%" PRIx16, address, *data);
return ERROR_OK;
}
@@ -319,6 +321,7 @@ int esirisc_jtag_read_word(struct esirisc_jtag *jtag_info, uint32_t address, uin
return retval;
*data = le_to_h_u32(d);
+ LOG_DEBUG("address: 0x%" PRIx32 ", data: 0x%" PRIx32, address, *data);
return ERROR_OK;
}
@@ -328,6 +331,8 @@ int esirisc_jtag_write_byte(struct esirisc_jtag *jtag_info, uint32_t address, ui
struct scan_field out_fields[2];
uint8_t a[4];
+ LOG_DEBUG("address: 0x%" PRIx32 ", data: 0x%" PRIx8, address, data);
+
out_fields[0].num_bits = 32;
out_fields[0].out_value = a;
h_u32_to_be(a, address);
@@ -346,6 +351,8 @@ int esirisc_jtag_write_hword(struct esirisc_jtag *jtag_info, uint32_t address, u
struct scan_field out_fields[2];
uint8_t a[4], d[2];
+ LOG_DEBUG("address: 0x%" PRIx32 ", data: 0x%" PRIx16, address, data);
+
out_fields[0].num_bits = 32;
out_fields[0].out_value = a;
h_u32_to_be(a, address);
@@ -365,6 +372,8 @@ int esirisc_jtag_write_word(struct esirisc_jtag *jtag_info, uint32_t address, ui
struct scan_field out_fields[2];
uint8_t a[4], d[4];
+ LOG_DEBUG("address: 0x%" PRIx32 ", data: 0x%" PRIx32, address, data);
+
out_fields[0].num_bits = 32;
out_fields[0].out_value = a;
h_u32_to_be(a, address);
@@ -400,6 +409,7 @@ int esirisc_jtag_read_reg(struct esirisc_jtag *jtag_info, uint8_t reg, uint32_t
return retval;
*data = le_to_h_u32(d);
+ LOG_DEBUG("register: 0x%" PRIx32 ", data: 0x%" PRIx32, reg, *data);
return ERROR_OK;
}
@@ -409,6 +419,8 @@ int esirisc_jtag_write_reg(struct esirisc_jtag *jtag_info, uint8_t reg, uint32_t
struct scan_field out_fields[2];
uint8_t d[4];
+ LOG_DEBUG("register: 0x%" PRIx32 ", data: 0x%" PRIx32, reg, data);
+
out_fields[0].num_bits = 8;
out_fields[0].out_value = &reg;
out_fields[0].in_value = NULL;
@@ -445,6 +457,7 @@ int esirisc_jtag_read_csr(struct esirisc_jtag *jtag_info, uint8_t bank, uint8_t
return retval;
*data = le_to_h_u32(d);
+ LOG_DEBUG("bank: 0x%" PRIx32 ", csr: 0x%" PRIx32 ", data: 0x%" PRIx32, bank, csr, *data);
return ERROR_OK;
}
@@ -454,6 +467,8 @@ int esirisc_jtag_write_csr(struct esirisc_jtag *jtag_info, uint8_t bank, uint8_t
struct scan_field out_fields[2];
uint8_t c[2], d[4];
+ LOG_DEBUG("bank: 0x%" PRIx32 ", csr: 0x%" PRIx32 ", data: 0x%" PRIx32, bank, csr, data);
+
out_fields[0].num_bits = 16;
out_fields[0].out_value = c;
h_u16_to_be(c, (csr << 5) | bank);
diff --git a/src/target/esirisc_jtag.h b/src/target/esirisc_jtag.h
index 8189ddc6..5f8fe66b 100644
--- a/src/target/esirisc_jtag.h
+++ b/src/target/esirisc_jtag.h
@@ -20,6 +20,7 @@
#ifndef OPENOCD_TARGET_ESIRISC_JTAG_H
#define OPENOCD_TARGET_ESIRISC_JTAG_H
+#include <helper/types.h>
#include <jtag/jtag.h>
/* TAP Instructions */
diff --git a/src/target/esirisc_trace.c b/src/target/esirisc_trace.c
new file mode 100644
index 00000000..4e0a1552
--- /dev/null
+++ b/src/target/esirisc_trace.c
@@ -0,0 +1,1203 @@
+/***************************************************************************
+ * 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
+};
diff --git a/src/target/esirisc_trace.h b/src/target/esirisc_trace.h
new file mode 100644
index 00000000..c3cc6e99
--- /dev/null
+++ b/src/target/esirisc_trace.h
@@ -0,0 +1,105 @@
+/***************************************************************************
+ * 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/>. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ESIRISC_TRACE_H
+#define OPENOCD_TARGET_ESIRISC_TRACE_H
+
+#include <helper/command.h>
+#include <helper/types.h>
+#include <target/target.h>
+
+enum esirisc_trace_delay {
+ ESIRISC_TRACE_DELAY_NONE,
+ ESIRISC_TRACE_DELAY_START,
+ ESIRISC_TRACE_DELAY_STOP,
+ ESIRISC_TRACE_DELAY_BOTH,
+};
+
+enum esirisc_trace_format {
+ ESIRISC_TRACE_FORMAT_FULL,
+ ESIRISC_TRACE_FORMAT_BRANCH,
+ ESIRISC_TRACE_FORMAT_ICACHE,
+};
+
+enum esirisc_trace_id {
+ ESIRISC_TRACE_ID_EXECUTE,
+ ESIRISC_TRACE_ID_STALL,
+ ESIRISC_TRACE_ID_BRANCH,
+ ESIRISC_TRACE_ID_EXTENDED,
+};
+
+enum esirisc_trace_ext_id {
+ ESIRISC_TRACE_EXT_ID_EXCEPTION = 1,
+ ESIRISC_TRACE_EXT_ID_ERET,
+ ESIRISC_TRACE_EXT_ID_STOP,
+ ESIRISC_TRACE_EXT_ID_WAIT,
+ ESIRISC_TRACE_EXT_ID_MULTICYCLE,
+ ESIRISC_TRACE_EXT_ID_COUNT,
+ ESIRISC_TRACE_EXT_ID_PC,
+ ESIRISC_TRACE_EXT_ID_INDIRECT,
+ ESIRISC_TRACE_EXT_ID_END,
+ ESIRISC_TRACE_EXT_ID_END_PC,
+};
+
+enum esirisc_trace_trigger {
+ ESIRISC_TRACE_TRIGGER_NONE,
+ ESIRISC_TRACE_TRIGGER_PC,
+ ESIRISC_TRACE_TRIGGER_LOAD,
+ ESIRISC_TRACE_TRIGGER_STORE,
+ ESIRISC_TRACE_TRIGGER_EXCEPTION,
+ ESIRISC_TRACE_TRIGGER_ERET,
+ ESIRISC_TRACE_TRIGGER_WAIT,
+ ESIRISC_TRACE_TRIGGER_STOP,
+ ESIRISC_TRACE_TRIGGER_HIGH,
+ ESIRISC_TRACE_TRIGGER_LOW,
+};
+
+struct esirisc_trace {
+ target_addr_t buffer_start;
+ target_addr_t buffer_end;
+ bool buffer_wrap;
+ bool flow_control;
+
+ enum esirisc_trace_format format;
+ int pc_bits;
+
+ enum esirisc_trace_trigger start_trigger;
+ uint32_t start_data;
+ uint32_t start_mask;
+
+ enum esirisc_trace_trigger stop_trigger;
+ uint32_t stop_data;
+ uint32_t stop_mask;
+
+ enum esirisc_trace_delay delay;
+ uint32_t delay_cycles;
+};
+
+extern const struct command_registration esirisc_trace_command_handlers[];
+
+static inline uint32_t esirisc_trace_buffer_size(struct esirisc_trace *trace_info)
+{
+ return trace_info->buffer_end - trace_info->buffer_start;
+}
+
+static inline bool esirisc_trace_is_fifo(struct esirisc_trace *trace_info)
+{
+ return trace_info->buffer_start == trace_info->buffer_end;
+}
+
+#endif /* OPENOCD_TARGET_ESIRISC_TRACE_H */