Commit 53d1f9b2 authored by drath's avatar drath
Browse files

- added manpage for OpenOCD (thanks to Uwe Hermann)

- fixed bug in ARM926EJ-S cache handling that caused cache linefills to be disabled after first debug entry
- added support for auto image type detection (thanks to Vincent Palatin)
- further work on ETM trace decoding (tested with a ETB interface using an ETM in normal 16-bit port mode, still experimental)



git-svn-id: svn://svn.berlios.de/openocd/trunk@169 b42882b7-edfa-0310-969c-e2dbd0fdcd60
parent 7087b66f
......@@ -2,7 +2,7 @@
Free and Open On-Chip Debugging, In-System Programming
and Boundary-Scan Testing
Copyright (c) 2004, 2005, 2006 Dominic Rath
Copyright (c) 2004-2007 Dominic Rath
The debugger uses an IEEE 1149-1 compliant JTAG TAP bus master to access on-chip
debug functionality available on ARM7 and ARM9 based microcontrollers /
......@@ -67,22 +67,28 @@ with many Linux distributions.
2. Supported cores
This version of openocd supports the following cores:
This version of openocd supports the following ARM7/9 cores:
- ARM7TDMI(-s)
- ARM9TDMI
- ARM920t
- ARM922t
- ARM926ej-s
- ARM966e
Support for Intel XScale CPUs (PXA25x, PXA27x and IXP4xx) is currently being
developed.
Support for Intel XScale CPUs is also included:
- PXA25x
- IXP42x
PXA27x debugging should be similar to the PXA25x but fails in the current
version of OpenOCD.
3. Host platforms
OpenOCD was originally developed on x86-Linux, but has since then been ported
to run on Windows/Cygwin, native Windows with MinGW, FreeBSD, x86-64-Linux and
(though it's not fully working yet) PowerPC OS-X.
PowerPC OS-X.
4. Documentation
......
......@@ -4,6 +4,8 @@ AC_SEARCH_LIBS([ioperm], [ioperm])
AC_CANONICAL_HOST
AC_CHECK_HEADERS(sys/param.h)
AC_C_BIGENDIAN
AC_CHECK_FUNCS(strndup)
......
.TH "OPENOCD" "1" "May 03, 2007" "" ""
.SH "NAME"
openocd \- A free and open on\-chip debugging, in\-system programming and
boundary\-scan testing tool for ARM systems (currently ARM7/9 and XScale, Cortex\-M3 support to be merged)
.SH "SYNOPSIS"
.B openocd \fR[\fB\-fdlh\fR] [\fB\-\-file\fR <filename>] [\fB\-\-debug\fR <debuglevel>] [\fB\-\-log_output\fR <filename>] [\fB\-\-help]
.SH "DESCRIPTION"
.B OpenOCD
is an on\-chip debugging, in\-system programming and boundary\-scan
testing tool for ARM systems.
.PP
The debugger uses an IEEE 1149\-1 compliant JTAG TAP bus master to access
on\-chip debug functionality available on ARM7/9 and XScale based
microcontrollers / system\-on\-chip solutions.
.PP
User interaction is realized through a telnet command line interface and
a gdb (the GNU debugger) remote protocol server.
.PP
OpenOCD supports various different types of JTAG interfaces/programmers:
* Parallel port wigglers
* Amontec JTAG Accelerator
* FTDI FT2232 based USB devices
* USBJTAG
* OOCD\-Link
* Amontec JTAGkey
* Amontec JTAGkey\-Tiny
* Olimex ARM\-USB\-OCD
* eVerve Signalyzer
* ... other FT2232 based dongles
.PP
It also supports a number of different ARM7/9 cores:
* ARM7TDMI(\-s)
* ARM720t
* ARM9TDMI
* ARM920t
* ARM922t
* ARM926ej\-s
* ARM966e
.PP
Support for Intel XScale CPUs is also included:
* PXA25x
* IXP42x
PXA27x debugging should be similar to the PXA25x but fails in the current
version of OpenOCD.
.SH "OPTIONS"
.TP
.B "\-f, \-\-file <filename>"
Use configuration file
.BR <filename> .
If this option is omitted, the config file
.B openocd.cfg
in the current working directory will be used.
.TP
.B "\-d, \-\-debug <debuglevel>"
Set debug level. Possible values are:
.br
.RB " * " 0 " (errors)"
.br
.RB " * " 1 " (warnings)"
.br
.RB " * " 2 " (informational messages)"
.br
.RB " * " 3 " (debug messages)"
.br
The default level is
.BR 2 .
.TP
.B "\-l, \-\-log_output <filename>"
Redirect log output to the file
.BR <filename> .
Per default the log output is printed on
.BR stderr .
.TP
.B "\-h, \-\-help"
Show a help text and exit.
.\".TP
.\".B "\-v, \-\-version"
.\"Show version information and exit.
.SH "BUGS"
Please report any bugs at
.B http://developer.berlios.de/bugs/?group_id=4148
or on the mailing list
.BR openocd\-development@lists.berlios.de .
.SH "LICENCE"
.B OpenOCD
is covered by the GNU General Public License (GPL), version 2 or later.
.\"
.SH "SEE ALSO"
.SH "AUTHORS"
Dominic Rath <Dominic.Rath@gmx.de>
.br
Magnus Lundin <lundin@mlu.mine.nu>
.br
Michael Fischer <fischermi@t\-online.de>
.br
Spencer Oliver <spen@spen\-soft.co.uk>
.br
and others
.PP
This manual page was written by Uwe Hermann <uwe@hermann\-uwe.de>.
It is licensed under the terms of the GNU GPL (v2 or later).
......@@ -511,8 +511,6 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha
duration_start_measure(&duration);
identify_image_type(&image.type, (argc == 4) ? args[3] : NULL);
image.base_address_set = 1;
image.base_address = strtoul(args[1], NULL, 0);
......@@ -526,7 +524,7 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha
return ERROR_OK;
}
if (image_open(&image, args[1], FILEIO_READ) != ERROR_OK)
if (image_open(&image, args[1], (argc == 4) ? args[3] : NULL) != ERROR_OK)
{
command_print(cmd_ctx, "flash write error: %s", image.error_str);
return ERROR_OK;
......
......@@ -258,6 +258,27 @@ int fileio_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
}
}
int fileio_read_u32(fileio_t *fileio, u32 *data)
{
u8 buf[4];
u32 size_read;
int retval;
switch (fileio->location)
{
case FILEIO_LOCAL:
if ((retval = fileio_local_read(fileio, 4, buf, &size_read)) != ERROR_OK)
return retval;
*data = be_to_h_u32(buf);
break;
default:
ERROR("BUG: should never get here");
exit(-1);
}
return ERROR_OK;
}
int fileio_local_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written)
{
fileio_local_t *fileio_local = fileio->location_private;
......@@ -280,3 +301,24 @@ int fileio_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written)
return ERROR_OK;
}
int fileio_write_u32(fileio_t *fileio, u32 data)
{
u8 buf[4];
u32 size_written;
int retval;
h_u32_to_be(buf, data);
switch (fileio->location)
{
case FILEIO_LOCAL:
if ((retval = fileio_local_write(fileio, 4, buf, &size_written)) != ERROR_OK)
return retval;
break;
default:
ERROR("BUG: should never get here");
}
return ERROR_OK;
}
......@@ -18,7 +18,7 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#define OPENOCD_VERSION "Open On-Chip Debugger (2007-05-30 17:45 CEST)"
#define OPENOCD_VERSION "Open On-Chip Debugger (2007-06-14 12:00 CEST)"
#ifdef HAVE_CONFIG_H
#include "config.h"
......
......@@ -477,7 +477,7 @@ void arm926ejs_pre_restore_context(target_t *target)
/* read-modify-write CP15 cache debug control register
* to reenable I/D-cache linefills and disable WT */
arm926ejs_read_cp15(target, ARM926EJS_CP15_ADDR(7, 0, 15, 0), &cache_dbg_ctrl);
cache_dbg_ctrl |= 0x7;
cache_dbg_ctrl &= ~0x7;
arm926ejs_write_cp15(target, ARM926EJS_CP15_ADDR(7, 0, 15, 0), cache_dbg_ctrl);
}
......
......@@ -2080,3 +2080,37 @@ int thumb_evaluate_opcode(u16 opcode, u32 address, arm_instruction_t *instructio
return -1;
}
int arm_access_size(arm_instruction_t *instruction)
{
if ((instruction->type == ARM_LDRB)
|| (instruction->type == ARM_LDRBT)
|| (instruction->type == ARM_LDRSB)
|| (instruction->type == ARM_STRB)
|| (instruction->type == ARM_STRBT))
{
return 1;
}
else if ((instruction->type == ARM_LDRH)
|| (instruction->type == ARM_LDRSH)
|| (instruction->type == ARM_STRH))
{
return 2;
}
else if ((instruction->type == ARM_LDR)
|| (instruction->type == ARM_LDRT)
|| (instruction->type == ARM_STR)
|| (instruction->type == ARM_STRT))
{
return 4;
}
else if ((instruction->type == ARM_LDRD)
|| (instruction->type == ARM_STRD))
{
return 8;
}
else
{
ERROR("BUG: instruction type %i isn't a load/store instruction", instruction->type);
return 0;
}
}
......@@ -196,6 +196,7 @@ typedef struct arm_instruction_s
extern int arm_evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction);
extern int thumb_evaluate_opcode(u16 opcode, u32 address, arm_instruction_t *instruction);
extern int arm_access_size(arm_instruction_t *instruction);
#define COND(opcode) (arm_condition_strings[(opcode & 0xf0000000)>>28])
......
......@@ -582,11 +582,29 @@ int etb_read_trace(etm_context_t *etm_ctx)
{
etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7;
etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7f8) >> 3;
etm_ctx->trace_data[j].tracesync = (trace_data[i] & 0x800) >> 11;
etm_ctx->trace_data[j].flags = 0;
if ((trace_data[i] & 0x800) >> 11)
{
etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE;
}
if (etm_ctx->trace_data[j].pipestat == STAT_TR)
{
etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7;
etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE;
}
etm_ctx->trace_data[j+1].pipestat = (trace_data[i] & 0x7000) >> 12;
etm_ctx->trace_data[j+1].packet = (trace_data[i] & 0x7f8000) >> 15;
etm_ctx->trace_data[j+1].tracesync = (trace_data[i] & 0x800000) >> 23;
etm_ctx->trace_data[j+1].flags = 0;
if ((trace_data[i] & 0x800000) >> 23)
{
etm_ctx->trace_data[j+1].flags |= ETMV1_TRACESYNC_CYCLE;
}
if (etm_ctx->trace_data[j+1].pipestat == STAT_TR)
{
etm_ctx->trace_data[j+1].pipestat = etm_ctx->trace_data[j+1].packet & 0x7;
etm_ctx->trace_data[j+1].flags |= ETMV1_TRIGGER_CYCLE;
}
j += 2;
}
......@@ -594,7 +612,16 @@ int etb_read_trace(etm_context_t *etm_ctx)
{
etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7;
etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7fff8) >> 3;
etm_ctx->trace_data[j].tracesync = (trace_data[i] & 0x80000) >> 19;
etm_ctx->trace_data[j].flags = 0;
if ((trace_data[i] & 0x80000) >> 19)
{
etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE;
}
if (etm_ctx->trace_data[j].pipestat == STAT_TR)
{
etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7;
etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE;
}
j += 1;
}
......
......@@ -28,6 +28,8 @@
#include "armv4_5.h"
#include "arm7_9_common.h"
#include "arm_disassembler.h"
#include "arm_simulator.h"
#include "log.h"
#include "arm_jtag.h"
......@@ -482,39 +484,499 @@ char *etmv1v1_branch_reason_strings[] =
"reserved",
};
int etmv1_next_packet(etm_context_t *ctx, u8 *packet)
int etm_read_instruction(etm_context_t *ctx, arm_instruction_t *instruction)
{
int i;
int section = -1;
u32 size_read;
u32 opcode;
int retval;
if (!ctx->image)
return ERROR_TRACE_IMAGE_UNAVAILABLE;
/* search for the section the current instruction belongs to */
for (i = 0; i < ctx->image->num_sections; i++)
{
if ((ctx->image->sections[i].base_address <= ctx->current_pc) &&
(ctx->image->sections[i].base_address + ctx->image->sections[i].size > ctx->current_pc))
{
section = i;
break;
}
}
if (section == -1)
{
/* current instruction couldn't be found in the image */
return ERROR_TRACE_INSTRUCTION_UNAVAILABLE;
}
if (ctx->core_state == ARMV4_5_STATE_ARM)
{
u8 buf[4];
if ((retval = image_read_section(ctx->image, section,
ctx->current_pc - ctx->image->sections[section].base_address,
4, buf, &size_read)) != ERROR_OK)
{
ERROR("error while reading instruction: %i", retval);
return ERROR_TRACE_INSTRUCTION_UNAVAILABLE;
}
opcode = target_buffer_get_u32(ctx->target, buf);
arm_evaluate_opcode(opcode, ctx->current_pc, instruction);
}
else if (ctx->core_state == ARMV4_5_STATE_THUMB)
{
u8 buf[2];
if ((retval = image_read_section(ctx->image, section,
ctx->current_pc - ctx->image->sections[section].base_address,
2, buf, &size_read)) != ERROR_OK)
{
ERROR("error while reading instruction: %i", retval);
return ERROR_TRACE_INSTRUCTION_UNAVAILABLE;
}
opcode = target_buffer_get_u16(ctx->target, buf);
thumb_evaluate_opcode(opcode, ctx->current_pc, instruction);
}
else if (ctx->core_state == ARMV4_5_STATE_JAZELLE)
{
ERROR("BUG: tracing of jazelle code not supported");
exit(-1);
}
else
{
ERROR("BUG: unknown core state encountered");
exit(-1);
}
return ERROR_OK;
}
int etmv1_analyse_trace(etm_context_t *ctx)
int etmv1_next_packet(etm_context_t *ctx, u8 *packet, int apo)
{
while (ctx->data_index < ctx->trace_depth)
{
/* if the caller specified an address packet offset, skip until the
* we reach the n-th cycle marked with tracesync */
if (apo > 0)
{
if (ctx->trace_data[ctx->data_index].flags & ETMV1_TRACESYNC_CYCLE)
apo--;
if (apo > 0)
{
ctx->data_index++;
ctx->data_half = 0;
}
continue;
}
/* no tracedata output during a TD cycle
* or in a trigger cycle */
if ((ctx->trace_data[ctx->data_index].pipestat == STAT_TD)
|| (ctx->trace_data[ctx->data_index].flags & ETMV1_TRIGGER_CYCLE))
{
ctx->data_index++;
ctx->data_half = 0;
continue;
}
if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT)
{
if (ctx->data_half == 0)
{
*packet = ctx->trace_data[ctx->data_index].packet & 0xff;
ctx->data_half = 1;
}
else
{
*packet = (ctx->trace_data[ctx->data_index].packet & 0xff00) >> 8;
ctx->data_half = 0;
ctx->data_index++;
}
}
else if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT)
{
*packet = ctx->trace_data[ctx->data_index].packet & 0xff;
ctx->data_index++;
}
else
{
/* on a 4-bit port, a packet will be output during two consecutive cycles */
if (ctx->data_index > (ctx->trace_depth - 2))
return -1;
*packet = ctx->trace_data[ctx->data_index].packet & 0xf;
*packet |= (ctx->trace_data[ctx->data_index + 1].packet & 0xf) << 4;
ctx->data_index += 2;
}
return 0;
}
return -1;
}
int etmv1_branch_address(etm_context_t *ctx)
{
int retval;
u8 packet;
int shift = 0;
int apo;
int i;
/* quit analysis if less than two cycles are left in the trace
* because we can't extract the APO */
if (ctx->data_index > (ctx->trace_depth - 2))
return -1;
/* a BE could be output during an APO cycle, skip the current
* and continue with the new one */
if (ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x4)
return 1;
if (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x4)
return 2;
/* address packet offset encoded in the next two cycles' pipestat bits */
apo = ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x3;
apo |= (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x3) << 2;
/* count number of tracesync cycles between current pipe_index and data_index
* i.e. the number of tracesyncs that data_index already passed by
* to subtract them from the APO */
for (i = ctx->pipe_index; i < ctx->data_index; i++)
{
if (ctx->trace_data[ctx->pipe_index + 1].pipestat & ETMV1_TRACESYNC_CYCLE)
apo--;
}
/* extract up to four 7-bit packets */
do {
if ((retval = etmv1_next_packet(ctx, &packet, (shift == 0) ? apo + 1 : 0)) != 0)
return -1;
ctx->last_branch &= ~(0x7f << shift);
ctx->last_branch |= (packet & 0x7f) << shift;
shift += 7;
} while ((packet & 0x80) && (shift < 28));
/* one last packet holding 4 bits of the address, plus the branch reason code */
if ((shift == 28) && (packet & 0x80))
{
if ((retval = etmv1_next_packet(ctx, &packet, 0)) != 0)
return -1;
ctx->last_branch &= 0x0fffffff;
ctx->last_branch |= (packet & 0x0f) << 28;
ctx->last_branch_reason = (packet & 0x70) >> 4;
shift += 4;
}
else
{
ctx->last_branch_reason = 0;
}
if (shift == 32)
{
ctx->pc_ok = 1;
}
/* if a full address was output, we might have branched into Jazelle state */
if ((shift == 32) && (packet & 0x80))
{
ctx->core_state = ARMV4_5_STATE_JAZELLE;
}
else
{
/* if we didn't branch into Jazelle state, the current processor state is
* encoded in bit 0 of the branch target address */
if (ctx->last_branch & 0x1)
{
ctx->core_state = ARMV4_5_STATE_THUMB;
ctx->last_branch &= ~0x1;
}
else
{
ctx->core_state = ARMV4_5_STATE_ARM;
ctx->last_branch &= ~0x3;
}
}
return 0;
}
int etmv1_data(etm_context_t *ctx, int size, u32 *data)
{
int j;
u8 buf[4];
int retval;
for (j = 0; j < size; j++)
{
if ((retval = etmv1_next_packet(ctx, &buf[j], 0)) != 0)
return -1;
}
if (size == 8)
ERROR("TODO: add support for 64-bit values");
else if (size == 4)
*data = target_buffer_get_u32(ctx->target, buf);
else if (size == 2)
*data = target_buffer_get_u16(ctx->target, buf);
else if (size == 1)
*data = buf[0];
return 0;
}
int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx)
{
int retval;
arm_instruction_t instruction;
/* read the trace data if it wasn't read already */
if (ctx->trace_depth == 0)
ctx->capture_driver->read_trace(ctx);
/* start at the beginning of the captured trace */
ctx->pipe_index = 0;
ctx->data_index = 0;
ctx->data_half = 0;
/* neither the PC nor the data pointer are valid */
ctx->pc_ok = 0;
ctx->ptr_ok = 0;
while (ctx->pipe_index < ctx->trace_depth)
{
switch (ctx->trace_data[ctx->pipe_index].pipestat)