Browse Source

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>
master
Steven Stallion 5 years ago
committed by Matthias Welwarsky
parent
commit
c5eb990825
9 changed files with 1641 additions and 101 deletions
  1. +167
    -12
      doc/openocd.texi
  2. +18
    -11
      src/flash/nor/esirisc_flash.c
  3. +4
    -2
      src/target/Makefile.am
  4. +119
    -73
      src/target/esirisc.c
  5. +9
    -3
      src/target/esirisc.h
  6. +15
    -0
      src/target/esirisc_jtag.c
  7. +1
    -0
      src/target/esirisc_jtag.h
  8. +1203
    -0
      src/target/esirisc_trace.c
  9. +105
    -0
      src/target/esirisc_trace.h

+ 167
- 12
doc/openocd.texi View File

@@ -5723,16 +5723,17 @@ configuration register interface, @option{clock_hz} is the expected clock
frequency, and @option{wait_states} is the number of configured read wait states.

@example
flash bank $_FLASHNAME esirisc base_address size_bytes 0 0 $_TARGETNAME cfg_address clock_hz wait_states
flash bank $_FLASHNAME esirisc base_address size_bytes 0 0 \
$_TARGETNAME cfg_address clock_hz wait_states
@end example

@deffn Command {esirisc_flash mass_erase} (bank_id)
Erases all pages in data memory for the bank identified by @option{bank_id}.
@deffn Command {esirisc flash mass_erase} bank_id
Erase all pages in data memory for the bank identified by @option{bank_id}.
@end deffn

@deffn Command {esirisc_flash ref_erase} (bank_id)
Erases the reference cell for the bank identified by @option{bank_id}. This is
an uncommon operation.
@deffn Command {esirisc flash ref_erase} bank_id
Erase the reference cell for the bank identified by @option{bank_id}. @emph{This
is an uncommon operation.}
@end deffn
@end deffn

@@ -9041,17 +9042,13 @@ Selects whether interrupts will be processed when single stepping. The default c
eSi-RISC is a highly configurable microprocessor architecture for embedded systems
provided by EnSilica. (See: @url{http://www.ensilica.com/risc-ip/}.)

@subsection esirisc specific commands
@subsection eSi-RISC Configuration

@deffn Command {esirisc cache_arch} (@option{harvard}|@option{von_neumann})
Configure the caching architecture. Targets with the @code{UNIFIED_ADDRESS_SPACE}
option disabled employ a Harvard architecture. By default, @option{von_neumann} is assumed.
@end deffn

@deffn Command {esirisc flush_caches}
Flush instruction and data caches. This command requires that the target is halted
when the command is issued and configured with an instruction or data cache.
@end deffn

@deffn Command {esirisc hwdc} (@option{all}|@option{none}|mask ...)
Configure hardware debug control. The HWDC register controls which exceptions return
control back to the debugger. Possible masks are @option{all}, @option{none},
@@ -9059,6 +9056,164 @@ control back to the debugger. Possible masks are @option{all}, @option{none},
By default, @option{reset}, @option{error}, and @option{debug} are enabled.
@end deffn

@subsection eSi-RISC Operation

@deffn Command {esirisc flush_caches}
Flush instruction and data caches. This command requires that the target is halted
when the command is issued and configured with an instruction or data cache.
@end deffn

@subsection eSi-Trace Configuration

eSi-RISC targets may be configured with support for instruction tracing. Trace
data may be written to an in-memory buffer or FIFO. If a FIFO is configured, DMA
is typically employed to move trace data off-device using a high-speed
peripheral (eg. SPI). Collected trace data is encoded in one of three different
formats. At a minimum, @command{esirisc trace buffer} or @command{esirisc trace
fifo} must be issued along with @command{esirisc trace format} before trace data
can be collected.

OpenOCD provides rudimentary analysis of collected trace data. If more detail is
needed, collected trace data can be dumped to a file and processed by external
tooling.

@quotation Issues
OpenOCD is unable to process trace data sent to a FIFO. A potential workaround
for this issue is to configure DMA to copy trace data to an in-memory buffer,
which can then be passed to the @command{esirisc trace analyze} and
@command{esirisc trace dump} commands.

It is possible to corrupt trace data when using a FIFO if the peripheral
responsible for draining data from the FIFO is not fast enough. This can be
managed by enabling flow control, however this can impact timing-sensitive
software operation on the CPU.
@end quotation

@deffn Command {esirisc trace buffer} address size [@option{wrap}]
Configure trace buffer using the provided address and size. If the @option{wrap}
option is specified, trace collection will continue once the end of the buffer
is reached. By default, wrap is disabled.
@end deffn

@deffn Command {esirisc trace fifo} address
Configure trace FIFO using the provided address.
@end deffn

@deffn Command {esirisc trace flow_control} (@option{enable}|@option{disable})
Enable or disable stalling the CPU to collect trace data. By default, flow
control is disabled.
@end deffn

@deffn Command {esirisc trace format} (@option{full}|@option{branch}|@option{icache}) pc_bits
Configure trace format and number of PC bits to be captured. @option{pc_bits}
must be within 1 and 31 as the LSB is not collected. If external tooling is used
to analyze collected trace data, these values must match.

Supported trace formats:
@itemize
@item @option{full} capture full trace data, allowing execution history and
timing to be determined.
@item @option{branch} capture taken branch instructions and branch target
addresses.
@item @option{icache} capture instruction cache misses.
@end itemize
@end deffn

@deffn Command {esirisc trace trigger start} (@option{condition}) [start_data start_mask]
Configure trigger start condition using the provided start data and mask. A
brief description of each condition is provided below; for more detail on how
these values are used, see the eSi-RISC Architecture Manual.

Supported conditions:
@itemize
@item @option{none} manual tracing (see @command{esirisc trace start}).
@item @option{pc} start tracing if the PC matches start data and mask.
@item @option{load} start tracing if the effective address of a load
instruction matches start data and mask.
@item @option{store} start tracing if the effective address of a store
instruction matches start data and mask.
@item @option{exception} start tracing if the EID of an exception matches start
data and mask.
@item @option{eret} start tracing when an @code{ERET} instruction is executed.
@item @option{wait} start tracing when a @code{WAIT} instruction is executed.
@item @option{stop} start tracing when a @code{STOP} instruction is executed.
@item @option{high} start tracing when an external signal is a logical high.
@item @option{low} start tracing when an external signal is a logical low.
@end itemize
@end deffn

@deffn Command {esirisc trace trigger stop} (@option{condition}) [stop_data stop_mask]
Configure trigger stop condition using the provided stop data and mask. A brief
description of each condition is provided below; for more detail on how these
values are used, see the eSi-RISC Architecture Manual.

Supported conditions:
@itemize
@item @option{none} manual tracing (see @command{esirisc trace stop}).
@item @option{pc} stop tracing if the PC matches stop data and mask.
@item @option{load} stop tracing if the effective address of a load
instruction matches stop data and mask.
@item @option{store} stop tracing if the effective address of a store
instruction matches stop data and mask.
@item @option{exception} stop tracing if the EID of an exception matches stop
data and mask.
@item @option{eret} stop tracing when an @code{ERET} instruction is executed.
@item @option{wait} stop tracing when a @code{WAIT} instruction is executed.
@item @option{stop} stop tracing when a @code{STOP} instruction is executed.
@end itemize
@end deffn

@deffn Command {esirisc trace trigger delay} (@option{trigger}) [cycles]
Configure trigger start/stop delay in clock cycles.

Supported triggers:
@itemize
@item @option{none} no delay to start or stop collection.
@item @option{start} delay @option{cycles} after trigger to start collection.
@item @option{stop} delay @option{cycles} after trigger to stop collection.
@item @option{both} delay @option{cycles} after both triggers to start or stop
collection.
@end itemize
@end deffn

@subsection eSi-Trace Operation

@deffn Command {esirisc trace init}
Initialize trace collection. This command must be called any time the
configuration changes. If an trace buffer has been configured, the contents will
be overwritten when trace collection starts.
@end deffn

@deffn Command {esirisc trace info}
Display trace configuration.
@end deffn

@deffn Command {esirisc trace status}
Display trace collection status.
@end deffn

@deffn Command {esirisc trace start}
Start manual trace collection.
@end deffn

@deffn Command {esirisc trace stop}
Stop manual trace collection.
@end deffn

@deffn Command {esirisc trace analyze} [address size]
Analyze collected trace data. This command may only be used if a trace buffer
has been configured. If a trace FIFO has been configured, trace data must be
copied to an in-memory buffer identified by the @option{address} and
@option{size} options using DMA.
@end deffn

@deffn Command {esirisc trace dump} [address size] @file{filename}
Dump collected trace data to file. This command may only be used if a trace
buffer has been configured. If a trace FIFO has been configured, trace data must
be copied to an in-memory buffer identified by the @option{address} and
@option{size} options using DMA.
@end deffn

@section Intel Architecture

Intel Quark X10xx is the first product in the Quark family of SoCs. It is an IA-32


+ 18
- 11
src/flash/nor/esirisc_flash.c View File

@@ -104,9 +104,12 @@ struct esirisc_flash_bank {
uint32_t wait_states;
};

static const struct command_registration esirisc_flash_command_handlers[];

FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command)
{
struct esirisc_flash_bank *esirisc_info;
struct command *esirisc_cmd;

if (CMD_ARGC < 9)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -119,6 +122,10 @@ FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command)

bank->driver_priv = esirisc_info;

/* register commands using existing esirisc context */
esirisc_cmd = command_find_in_context(CMD_CTX, "esirisc");
register_commands(CMD_CTX, esirisc_cmd, esirisc_flash_command_handlers);

return ERROR_OK;
}

@@ -435,8 +442,8 @@ static int esirisc_flash_init(struct flash_bank *bank)
esirisc_flash_disable_protect(bank);

/* initialize timing registers */
value = TIMING0_F(esirisc_flash_num_cycles(bank, TNVH)) |
TIMING0_R(esirisc_info->wait_states);
value = TIMING0_F(esirisc_flash_num_cycles(bank, TNVH))
| TIMING0_R(esirisc_info->wait_states);

LOG_DEBUG("TIMING0: 0x%" PRIx32, value);
target_write_u32(target, esirisc_info->cfg + TIMING0, value);
@@ -446,9 +453,9 @@ static int esirisc_flash_init(struct flash_bank *bank)
LOG_DEBUG("TIMING1: 0x%" PRIx32, value);
target_write_u32(target, esirisc_info->cfg + TIMING1, value);

value = TIMING2_T(esirisc_flash_num_cycles(bank, 10)) |
TIMING2_H(esirisc_flash_num_cycles(bank, 100)) |
TIMING2_P(esirisc_flash_num_cycles(bank, TPROG));
value = TIMING2_T(esirisc_flash_num_cycles(bank, 10))
| TIMING2_H(esirisc_flash_num_cycles(bank, 100))
| TIMING2_P(esirisc_flash_num_cycles(bank, TPROG));

LOG_DEBUG("TIMING2: 0x%" PRIx32, value);
target_write_u32(target, esirisc_info->cfg + TIMING2, value);
@@ -579,14 +586,14 @@ static const struct command_registration esirisc_flash_exec_command_handlers[] =
.name = "mass_erase",
.handler = handle_esirisc_flash_mass_erase_command,
.mode = COMMAND_EXEC,
.help = "erases all pages in data memory",
.help = "erase all pages in data memory",
.usage = "bank_id",
},
{
.name = "ref_erase",
.handler = handle_esirisc_flash_ref_erase_command,
.mode = COMMAND_EXEC,
.help = "erases reference cell (uncommon)",
.help = "erase reference cell (uncommon)",
.usage = "bank_id",
},
COMMAND_REGISTRATION_DONE
@@ -594,9 +601,9 @@ static const struct command_registration esirisc_flash_exec_command_handlers[] =

static const struct command_registration esirisc_flash_command_handlers[] = {
{
.name = "esirisc_flash",
.mode = COMMAND_ANY,
.help = "eSi-RISC flash command group",
.name = "flash",
.mode = COMMAND_EXEC,
.help = "eSi-TSMC Flash command group",
.usage = "",
.chain = esirisc_flash_exec_command_handlers,
},
@@ -605,7 +612,6 @@ static const struct command_registration esirisc_flash_command_handlers[] = {

struct flash_driver esirisc_flash = {
.name = "esirisc",
.commands = esirisc_flash_command_handlers,
.usage = "flash bank bank_id 'esirisc' base_address size_bytes 0 0 target "
"cfg_address clock_hz wait_states",
.flash_bank_command = esirisc_flash_bank_command,
@@ -618,4 +624,5 @@ struct flash_driver esirisc_flash = {
.erase_check = default_flash_blank_check,
.protect_check = esirisc_flash_protect_check,
.info = esirisc_flash_info,
.free_driver_priv = default_flash_free_driver_priv,
};

+ 4
- 2
src/target/Makefile.am View File

@@ -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

+ 119
- 73
src/target/esirisc.c View File

@@ -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;
}
@@ -1719,13 +1755,6 @@ 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,
@@ -1733,6 +1762,17 @@ static const struct command_registration esirisc_exec_command_handlers[] = {
.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
};


+ 9
- 3
src/target/esirisc.h View File

@@ -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";
}


+ 15
- 0
src/target/esirisc_jtag.c View File

@@ -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);


+ 1
- 0
src/target/esirisc_jtag.h View File

@@ -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 */


+ 1203
- 0
src/target/esirisc_trace.c
File diff suppressed because it is too large
View File


+ 105
- 0
src/target/esirisc_trace.h View File

@@ -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 */

Loading…
Cancel
Save