- renamed M5960 USB JTAG to "flyswatter"
[openocd.git] / src / target / xscale.c
index 334924f307b95708b5423ed78091899f3483189f..91078927a76216358ec3697af218d3841a0489b2 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2006 by Dominic Rath                                    *
+ *   Copyright (C) 2006, 2007 by Dominic Rath                              *
  *   Dominic.Rath@gmx.de                                                   *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   Free Software Foundation, Inc.,                                       *
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
+#ifdef HAVE_CONFIG_H
 #include "config.h"
+#endif
+
+#include "replacements.h"
 
 #include "xscale.h"
 
 #include "target.h"
 #include "armv4_5.h"
 #include "arm_simulator.h"
+#include "arm_disassembler.h"
 #include "log.h"
 #include "jtag.h"
 #include "binarybuffer.h"
 #include "time_support.h"
 #include "breakpoints.h"
+#include "fileio.h"
 
 #include <stdlib.h>
 #include <string.h>
 
 #include <sys/types.h>
-#include <sys/stat.h>
 #include <unistd.h>
 #include <errno.h>
 
+
 /* cli handling */
 int xscale_register_commands(struct command_context_s *cmd_ctx);
 
@@ -78,6 +84,8 @@ int xscale_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint);
 void xscale_enable_watchpoints(struct target_s *target);
 void xscale_enable_breakpoints(struct target_s *target);
 
+int xscale_read_trace(target_t *target);
+
 target_type_t xscale_target =
 {
        .name = "xscale",
@@ -85,6 +93,8 @@ target_type_t xscale_target =
        .poll = xscale_poll,
        .arch_state = xscale_arch_state,
 
+       .target_request_data = NULL,
+
        .halt = xscale_halt,
        .resume = xscale_resume,
        .step = xscale_step,
@@ -990,21 +1000,29 @@ enum target_state xscale_poll(target_t *target)
        {
                if ((retval = xscale_read_tx(target, 0)) == ERROR_OK)
                {
+                       enum target_state previous_state = target->state;
+                       
                        /* there's data to read from the tx register, we entered debug state */
                        xscale->handler_running = 1;
+
+                       target->state = TARGET_HALTED;
                        
                        /* process debug entry, fetching current mode regs */
                        if ((retval = xscale_debug_entry(target)) != ERROR_OK)
                                return retval;
                        
+                       /* debug_entry could have overwritten target state (i.e. immediate resume)
+                        * don't signal event handlers in that case
+                        */
+                       if (target->state != TARGET_HALTED)
+                               return target->state;
+                       
                        /* if target was running, signal that we halted
                         * otherwise we reentered from debug execution */
-                       if (target->state == TARGET_RUNNING)
+                       if (previous_state == TARGET_RUNNING)
                                target_call_event_callbacks(target, TARGET_EVENT_HALTED);
                        else
                                target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
-
-                       target->state = TARGET_HALTED;
                }
                else if (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
                {
@@ -1169,6 +1187,24 @@ int xscale_debug_entry(target_t *target)
        xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (xscale->cp15_control_reg & 0x4U) ? 1 : 0;
        xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (xscale->cp15_control_reg & 0x1000U) ? 1 : 0;
        
+       /* tracing enabled, read collected trace data */
+       if (xscale->trace.buffer_enabled)
+       {
+               xscale_read_trace(target);
+               xscale->trace.buffer_fill--;
+               
+               /* resume if we're still collecting trace data */
+               if ((xscale->arch_debug_reason == XSCALE_DBG_REASON_TB_FULL)
+                       && (xscale->trace.buffer_fill > 0))
+               {
+                       xscale_resume(target, 1, 0x0, 1, 0);
+               }
+               else
+               {
+                       xscale->trace.buffer_enabled = 0;
+               }
+       }
+       
        return ERROR_OK;
 }
 
@@ -1193,9 +1229,6 @@ int xscale_halt(target_t *target)
        else if (target->state == TARGET_RESET)
        {
                DEBUG("target->state == TARGET_RESET");
-               
-               /* clear TRST */
-               jtag_add_reset(0, -1);
        }
        else
        {
@@ -1313,7 +1346,7 @@ int xscale_resume(struct target_s *target, int current, u32 address, int handle_
                        
                        /* send resume request (command 0x30 or 0x31)
                         * clean the trace buffer if it is to be enabled (0x62) */
-                       if (xscale->trace_buffer_enabled)
+                       if (xscale->trace.buffer_enabled)
                        {
                                xscale_send_u32(target, 0x62);
                                xscale_send_u32(target, 0x31);
@@ -1356,7 +1389,7 @@ int xscale_resume(struct target_s *target, int current, u32 address, int handle_
        
        /* send resume request (command 0x30 or 0x31)
         * clean the trace buffer if it is to be enabled (0x62) */
-       if (xscale->trace_buffer_enabled)
+       if (xscale->trace.buffer_enabled)
        {
                xscale_send_u32(target, 0x62);
                xscale_send_u32(target, 0x31);
@@ -1460,7 +1493,7 @@ int xscale_step(struct target_s *target, int current, u32 address, int handle_br
        
        /* send resume request (command 0x30 or 0x31)
         * clean the trace buffer if it is to be enabled (0x62) */
-       if (xscale->trace_buffer_enabled)
+       if (xscale->trace.buffer_enabled)
        {
                xscale_send_u32(target, 0x62);
                xscale_send_u32(target, 0x31);
@@ -1513,22 +1546,32 @@ int xscale_assert_reset(target_t *target)
        xscale_common_t *xscale = armv4_5->arch_info;
        
        DEBUG("target->state: %s", target_state_strings[target->state]);
+
+       /* select DCSR instruction (set endstate to R-T-I to ensure we don't 
+        * end up in T-L-R, which would reset JTAG
+        */ 
+       jtag_add_end_state(TAP_RTI);
+       xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr);
        
-       /* if the handler isn't installed yet, we have to assert TRST, too */
-       if (!xscale->handler_installed)
-       {
-               jtag_add_reset(1, 1);
-       }
-       else
-               jtag_add_reset(-1, 1);
+       /* set Hold reset, Halt mode and Trap Reset */
+       buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1);
+       buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1);
+       xscale_write_dcsr(target, 1, 0);
+
+       /* select BYPASS, because having DCSR selected caused problems on the PXA27x */
+       xscale_jtag_set_instr(xscale->jtag_info.chain_pos, 0x7f);
+       jtag_execute_queue();
+               
+       /* assert reset */      
+       jtag_add_reset(0, 1);
        
        /* sleep 1ms, to be sure we fulfill any requirements */
        jtag_add_sleep(1000);
+       jtag_execute_queue();
        
        target->state = TARGET_RESET;
        
        return ERROR_OK;
-
 }
 
 int xscale_deassert_reset(target_t *target)
@@ -1536,17 +1579,18 @@ int xscale_deassert_reset(target_t *target)
        armv4_5_common_t *armv4_5 = target->arch_info;
        xscale_common_t *xscale = armv4_5->arch_info;
        
-       FILE *binary;
+       fileio_t debug_handler;
        u32 address;
-       struct stat binary_stat;
        u32 binary_size;
 
-       u32 buffer[8];
        u32 buf_cnt;
        int i;
+       int retval;
        
        breakpoint_t *breakpoint = target->breakpoints;
        
+       DEBUG("-");
+       
        xscale->ibcr_available = 2;
        xscale->ibcr0_used = 0;
        xscale->ibcr1_used = 0;
@@ -1567,42 +1611,27 @@ int xscale_deassert_reset(target_t *target)
        
        if (!xscale->handler_installed)
        {
-               /* release TRST */
-               jtag_add_reset(0, -1);
-               jtag_add_sleep(100000);
-               
-               /* set Hold reset, Halt mode and Trap Reset */
-               buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1);
-               buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1);
-               xscale_write_dcsr(target, 1, 0);
-               jtag_add_runtest(100, TAP_RTI);
-               jtag_execute_queue();
-               
                /* release SRST */
                jtag_add_reset(0, 0);
-               /* wait 150ms; 100ms were not enough */
-               jtag_add_sleep(150000);
+               
+               /* wait 300ms; 150 and 100ms were not enough */
+               jtag_add_sleep(3000000);
 
                jtag_add_runtest(2030, TAP_RTI);
                jtag_execute_queue();
-               
+
+               /* set Hold reset, Halt mode and Trap Reset */
+               buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1);
+               buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1);
                xscale_write_dcsr(target, 1, 0);
-               jtag_execute_queue();
-               
-               /* TODO: load debug handler */
-               if (stat("target/xscale/debug_handler.bin", &binary_stat) == -1)
-               {
-                       ERROR("couldn't stat() target/xscale/debug_handler.bin: %s",  strerror(errno));
-                       return ERROR_OK;
-               }
-               
-               if (!(binary = fopen("target/xscale/debug_handler.bin", "r")))
+
+               if (fileio_open(&debug_handler, "target/xscale/debug_handler.bin", FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
                {
-                       ERROR("couldn't open target/xscale/debug_handler.bin: %s", strerror(errno));
+                       ERROR("file open error: %s", debug_handler.error_str);
                        return ERROR_OK;
                }
-               
-               if ((binary_size = binary_stat.st_size) % 4)
+       
+               if ((binary_size = debug_handler.size) % 4)
                {
                        ERROR("debug_handler.bin: size not a multiple of 4");
                        exit(-1);
@@ -1619,41 +1648,51 @@ int xscale_deassert_reset(target_t *target)
                address = xscale->handler_address;
                while (binary_size > 0)
                {
-                       buf_cnt = fread(buffer, 4, 8, binary);
+                       u32 cache_line[8];
+                       u8 buffer[32];
+                       
+                       if ((retval = fileio_read(&debug_handler, 32, buffer, &buf_cnt)) != ERROR_OK)
+                       {
+                               ERROR("reading debug handler failed: %s", debug_handler.error_str);
+                       }
                        
-                       for (i = 0; i < buf_cnt; i++)
+                       for (i = 0; i < buf_cnt; i += 4)
                        {
                                /* convert LE buffer to host-endian u32 */
-                               buffer[i] = buf_get_u32((u8*)(&buffer[i]), 0, 32);
+                               cache_line[i / 4] = le_to_h_u32(&buffer[i]);
                        }
                        
-                       if (buf_cnt < 8)
+                       for (; buf_cnt < 32; buf_cnt += 4)
                        {
-                               for (; buf_cnt < 8; buf_cnt++)
-                               {
-                                       buffer[buf_cnt] = 0xe1a08008;
-                               }
+                                       cache_line[buf_cnt / 4] = 0xe1a08008;
                        }
                        
                        /* only load addresses other than the reset vectors */
                        if ((address % 0x400) != 0x0)
                        {
-                               xscale_load_ic(target, 1, address, buffer);
+                               xscale_load_ic(target, 1, address, cache_line);
                        }
                        
-                       address += buf_cnt * 4;
-                       binary_size -= buf_cnt * 4;
+                       address += buf_cnt;
+                       binary_size -= buf_cnt;
                };
                
                xscale_load_ic(target, 1, 0x0, xscale->low_vectors);
                xscale_load_ic(target, 1, 0xffff0000, xscale->high_vectors);
        
                jtag_add_runtest(30, TAP_RTI);
+
+               jtag_add_sleep(100000);
                
-               /* let the target run (should enter debug handler) */
-               xscale_write_dcsr(target, 0, 0);
+               /* set Hold reset, Halt mode and Trap Reset */
+               buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1);
+               buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1);
+               xscale_write_dcsr(target, 1, 0);
+
+               /* clear Hold reset to let the target run (should enter debug handler) */
+               xscale_write_dcsr(target, 0, 1);
                target->state = TARGET_RUNNING;
-               
+
                if ((target->reset_mode != RESET_HALT) && (target->reset_mode != RESET_INIT))
                {
                        jtag_add_sleep(10000);
@@ -1662,8 +1701,8 @@ int xscale_deassert_reset(target_t *target)
                        xscale_debug_entry(target);
                        target->state = TARGET_HALTED;
                        
-                       /* the PC is now at 0x0 */
-                       buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0);
+                       /* resume the target */
+                       xscale_resume(target, 1, 0x0, 1, 0);
                }
        }
        else
@@ -1683,7 +1722,9 @@ int xscale_soft_reset_halt(struct target_s *target)
 
 int xscale_prepare_reset_halt(struct target_s *target)
 {
-       /* nothing to be done for reset_halt on XScale targets */
+       /* nothing to be done for reset_halt on XScale targets
+        * we always halt after a reset to upload the debug handler
+        */
        return ERROR_OK;
 }
 
@@ -2527,6 +2568,355 @@ int xscale_write_dcsr_sw(target_t *target, u32 value)
        return ERROR_OK;
 }
 
+int xscale_read_trace(target_t *target)
+{
+       /* get pointers to arch-specific information */
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       xscale_trace_data_t **trace_data_p;
+       
+       /* 258 words from debug handler
+        * 256 trace buffer entries
+        * 2 checkpoint addresses
+        */ 
+       u32 trace_buffer[258];
+       int is_address[256];
+       int i, j;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               WARNING("target must be stopped to read trace data");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* send read trace buffer command (command 0x61) */
+       xscale_send_u32(target, 0x61);
+       
+       /* receive trace buffer content */
+       xscale_receive(target, trace_buffer, 258);
+       
+       /* parse buffer backwards to identify address entries */
+       for (i = 255; i >= 0; i--)
+       {
+               is_address[i] = 0;
+               if (((trace_buffer[i] & 0xf0) == 0x90) ||
+                       ((trace_buffer[i] & 0xf0) == 0xd0)) 
+               {
+                       if (i >= 3)
+                               is_address[--i] = 1;
+                       if (i >= 2)
+                               is_address[--i] = 1;
+                       if (i >= 1)
+                               is_address[--i] = 1;
+                       if (i >= 0)
+                               is_address[--i] = 1;
+               }
+       }
+
+       
+       /* search first non-zero entry */
+       for (j = 0; (j < 256) && (trace_buffer[j] == 0) && (!is_address[j]); j++)
+               ;
+
+       if (j == 256)
+       {
+               DEBUG("no trace data collected");
+               return ERROR_XSCALE_NO_TRACE_DATA;
+       }
+               
+       for (trace_data_p = &xscale->trace.data; *trace_data_p; trace_data_p = &(*trace_data_p)->next)
+               ;
+
+       *trace_data_p = malloc(sizeof(xscale_trace_data_t));
+       (*trace_data_p)->next = NULL;
+       (*trace_data_p)->chkpt0 = trace_buffer[256];
+       (*trace_data_p)->chkpt1 = trace_buffer[257];
+       (*trace_data_p)->last_instruction = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
+       (*trace_data_p)->entries = malloc(sizeof(xscale_trace_entry_t) * (256 - j));
+       (*trace_data_p)->depth = 256 - j;
+               
+       for (i = j; i < 256; i++)
+       {
+               (*trace_data_p)->entries[i - j].data = trace_buffer[i];
+               if (is_address[i])
+                       (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_ADDRESS;
+               else
+                       (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_MESSAGE;
+       }
+       
+       return ERROR_OK;
+}
+
+int xscale_read_instruction(target_t *target, arm_instruction_t *instruction)
+{
+       /* get pointers to arch-specific information */
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       int i;
+       int section = -1;
+       u32 size_read;
+       u32 opcode;
+       int retval;
+       
+       if (!xscale->trace.image)
+               return ERROR_TRACE_IMAGE_UNAVAILABLE;
+       
+       /* search for the section the current instruction belongs to */ 
+       for (i = 0; i < xscale->trace.image->num_sections; i++)
+       {
+               if ((xscale->trace.image->sections[i].base_address <= xscale->trace.current_pc) &&
+                       (xscale->trace.image->sections[i].base_address + xscale->trace.image->sections[i].size > xscale->trace.current_pc))
+               {
+                       section = i;
+                       break;
+               }
+       }
+       
+       if (section == -1)
+       {
+               /* current instruction couldn't be found in the image */
+               return ERROR_TRACE_INSTRUCTION_UNAVAILABLE;
+       }
+       
+       if (xscale->trace.core_state == ARMV4_5_STATE_ARM)
+       {
+               u8 buf[4];
+               if ((retval = image_read_section(xscale->trace.image, section, 
+                       xscale->trace.current_pc - xscale->trace.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(target, buf);
+               arm_evaluate_opcode(opcode, xscale->trace.current_pc, instruction);
+       }
+       else if (xscale->trace.core_state == ARMV4_5_STATE_THUMB)
+       {
+               u8 buf[2];
+               if ((retval = image_read_section(xscale->trace.image, section, 
+                       xscale->trace.current_pc - xscale->trace.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(target, buf);
+               thumb_evaluate_opcode(opcode, xscale->trace.current_pc, instruction);
+       }
+       else
+       {
+               ERROR("BUG: unknown core state encountered");
+               exit(-1);
+       }
+       
+       return ERROR_OK;
+}
+
+int xscale_branch_address(xscale_trace_data_t *trace_data, int i, u32 *target)
+{
+       /* if there are less than four entries prior to the indirect branch message
+        * we can't extract the address */
+       if (i < 4)
+       {
+               return -1;
+       }
+       
+       *target = (trace_data->entries[i-1].data) | (trace_data->entries[i-2].data << 8) |
+                               (trace_data->entries[i-3].data << 16) | (trace_data->entries[i-4].data << 24);
+       
+       return 0;
+}
+
+int xscale_analyze_trace(target_t *target, command_context_t *cmd_ctx)
+{
+       /* get pointers to arch-specific information */
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       xscale_common_t *xscale = armv4_5->arch_info;
+       int next_pc_ok = 0;
+       u32 next_pc = 0x0;
+       xscale_trace_data_t *trace_data = xscale->trace.data;
+       int retval;
+       
+       while (trace_data)
+       {
+               int i, chkpt;
+               int rollover;
+               int branch;
+               int exception;
+               xscale->trace.core_state = ARMV4_5_STATE_ARM;
+
+               chkpt = 0;
+               rollover = 0;
+               
+               for (i = 0; i < trace_data->depth; i++)
+               {
+                       next_pc_ok = 0;
+                       branch = 0;
+                       exception = 0;
+                       
+                       if (trace_data->entries[i].type == XSCALE_TRACE_ADDRESS)
+                               continue;
+                       
+                       switch ((trace_data->entries[i].data & 0xf0) >> 4)
+                       {
+                               case 0:         /* Exceptions */
+                               case 1:
+                               case 2:
+                               case 3:
+                               case 4:
+                               case 5:
+                               case 6:
+                               case 7:
+                                       exception = (trace_data->entries[i].data & 0x70) >> 4;
+                                       next_pc_ok = 1;
+                                       next_pc = (trace_data->entries[i].data & 0xf0) >> 2;
+                                       command_print(cmd_ctx, "--- exception %i ---", (trace_data->entries[i].data & 0xf0) >> 4);
+                                       break;
+                               case 8:         /* Direct Branch */
+                                       branch = 1;
+                                       break;
+                               case 9:         /* Indirect Branch */
+                                       branch = 1;
+                                       if (xscale_branch_address(trace_data, i, &next_pc) == 0)
+                                       {
+                                               next_pc_ok = 1;
+                                       }
+                                       break;
+                               case 13:        /* Checkpointed Indirect Branch */
+                                       if (xscale_branch_address(trace_data, i, &next_pc) == 0)
+                                       {
+                                               next_pc_ok = 1;
+                                               if (((chkpt == 0) && (next_pc != trace_data->chkpt0))
+                                                       || ((chkpt == 1) && (next_pc != trace_data->chkpt1)))
+                                                       WARNING("checkpointed indirect branch target address doesn't match checkpoint");
+                                       }
+                                       /* explicit fall-through */
+                               case 12:        /* Checkpointed Direct Branch */
+                                       branch = 1;
+                                       if (chkpt == 0)
+                                       {
+                                               next_pc_ok = 1;
+                                               next_pc = trace_data->chkpt0;
+                                               chkpt++;
+                                       }
+                                       else if (chkpt == 1)
+                                       {
+                                               next_pc_ok = 1;
+                                               next_pc = trace_data->chkpt0;
+                                               chkpt++;
+                                       }
+                                       else
+                                       {
+                                               WARNING("more than two checkpointed branches encountered");
+                                       }
+                                       break;
+                               case 15:        /* Roll-over */
+                                       rollover++;
+                                       continue;
+                               default:        /* Reserved */
+                                       command_print(cmd_ctx, "--- reserved trace message ---");
+                                       ERROR("BUG: trace message %i is reserved", (trace_data->entries[i].data & 0xf0) >> 4);
+                                       return ERROR_OK;
+                       }
+                       
+                       if (xscale->trace.pc_ok)
+                       {
+                               int executed = (trace_data->entries[i].data & 0xf) + rollover * 16;
+                               arm_instruction_t instruction;
+                               
+                               if ((exception == 6) || (exception == 7))
+                               {
+                                       /* IRQ or FIQ exception, no instruction executed */ 
+                                       executed -= 1;
+                               }
+                               
+                               while (executed-- >= 0)
+                               {
+                                       if ((retval = xscale_read_instruction(target, &instruction)) != ERROR_OK)
+                                       {
+                                               /* can't continue tracing with no image available */
+                                               if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE)
+                                               {
+                                                       return retval;
+                                               }
+                                               else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE)
+                                               {
+                                                       /* TODO: handle incomplete images */
+                                               }
+                                       }
+                                       
+                                       /* a precise abort on a load to the PC is included in the incremental
+                                        * word count, other instructions causing data aborts are not included
+                                        */
+                                       if ((executed == 0) && (exception == 4)
+                                               && ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDM)))
+                                       {
+                                               if ((instruction.type == ARM_LDM)
+                                                       && ((instruction.info.load_store_multiple.register_list & 0x8000) == 0))
+                                               {
+                                                       executed--;
+                                               }
+                                               else if (((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDRSH))
+                                                       && (instruction.info.load_store.Rd != 15))
+                                               {
+                                                       executed--;
+                                               }
+                                       }
+
+                                       /* only the last instruction executed
+                                        * (the one that caused the control flow change)
+                                        * could be a taken branch
+                                        */
+                                       if (((executed == -1) && (branch == 1)) &&
+                                               (((instruction.type == ARM_B) ||
+                                                       (instruction.type == ARM_BL) ||
+                                                       (instruction.type == ARM_BLX)) &&
+                                                       (instruction.info.b_bl_bx_blx.target_address != -1)))
+                                       {
+                                               xscale->trace.current_pc = instruction.info.b_bl_bx_blx.target_address;
+                                       }
+                                       else
+                                       {
+                                               xscale->trace.current_pc += (xscale->trace.core_state == ARMV4_5_STATE_ARM) ? 4 : 2;
+                                       }
+                                       command_print(cmd_ctx, "%s", instruction.text);
+                               }
+                               
+                               rollover = 0;
+                       }
+                       
+                       if (next_pc_ok)
+                       {
+                               xscale->trace.current_pc = next_pc;
+                               xscale->trace.pc_ok = 1;
+                       }
+               }
+               
+               for (; xscale->trace.current_pc < trace_data->last_instruction; xscale->trace.current_pc += (xscale->trace.core_state == ARMV4_5_STATE_ARM) ? 4 : 2)
+               {
+                       arm_instruction_t instruction;
+                       if ((retval = xscale_read_instruction(target, &instruction)) != ERROR_OK)
+                       {
+                               /* can't continue tracing with no image available */
+                               if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE)
+                               {
+                                       return retval;
+                               }
+                               else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE)
+                               {
+                                       /* TODO: handle incomplete images */
+                               }
+                       }
+                       command_print(cmd_ctx, "%s", instruction.text);
+               }
+               
+               trace_data = trace_data->next;
+       }
+       
+       return ERROR_OK;
+}
+
 void xscale_build_reg_cache(target_t *target)
 {
        /* get pointers to arch-specific information */
@@ -2580,6 +2970,12 @@ int xscale_init_target(struct command_context_s *cmd_ctx, struct target_s *targe
                ERROR("Reset target to enable debug");
        }
        
+       /* assert TRST once during startup */
+       jtag_add_reset(1, 0);
+       jtag_add_sleep(5000);
+       jtag_add_reset(0, 0);
+       jtag_execute_queue();
+       
        return ERROR_OK;
 }
 
@@ -2674,8 +3070,11 @@ int xscale_init_arch_info(target_t *target, xscale_common_t *xscale, int chain_p
        
        xscale->vector_catch = 0x1;
        
-       xscale->trace_buffer_enabled = 0;
-       xscale->trace_buffer_fill = 0;
+       xscale->trace.capture_status = TRACE_IDLE;
+       xscale->trace.data = NULL;
+       xscale->trace.image = NULL;
+       xscale->trace.buffer_enabled = 0;
+       xscale->trace.buffer_fill = 0;
        
        /* prepare ARMv4/5 specific information */
        armv4_5->arch_info = xscale;
@@ -3008,28 +3407,45 @@ int xscale_handle_trace_buffer_command(struct command_context_s *cmd_ctx, char *
        
        if ((argc >= 1) && (strcmp("enable", args[0]) == 0))
        {
-               xscale->trace_buffer_enabled = 1;
+               xscale_trace_data_t *td, *next_td;
+               xscale->trace.buffer_enabled = 1;
+               
+               /* free old trace data */
+               td = xscale->trace.data;
+               while (td)
+               {
+                       next_td = td->next;
+                       
+                       if (td->entries)
+                               free(td->entries);
+                       free(td);
+                       td = next_td;
+               }
+               xscale->trace.data = NULL;
        }
        else if ((argc >= 1) && (strcmp("disable", args[0]) == 0))
        {
-               xscale->trace_buffer_enabled = 0;
+               xscale->trace.buffer_enabled = 0;
        }
 
        if ((argc >= 2) && (strcmp("fill", args[1]) == 0))
        {
-               xscale->trace_buffer_fill = 1;
+               if (argc >= 3)
+                       xscale->trace.buffer_fill = strtoul(args[2], NULL, 0);
+               else
+                       xscale->trace.buffer_fill = 1;
        }
        else if ((argc >= 2) && (strcmp("wrap", args[1]) == 0))
        {
-               xscale->trace_buffer_fill = 0;
+               xscale->trace.buffer_fill = -1;
        }
        
        command_print(cmd_ctx, "trace buffer %s (%s)", 
-               (xscale->trace_buffer_enabled) ? "enabled" : "disabled",
-               (xscale->trace_buffer_fill) ? "fill" : "wrap");
+               (xscale->trace.buffer_enabled) ? "enabled" : "disabled",
+               (xscale->trace.buffer_fill > 0) ? "fill" : "wrap");
 
        dcsr_value = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32);
-       if (xscale->trace_buffer_fill)
+       if (xscale->trace.buffer_fill >= 0)
                xscale_write_dcsr_sw(target, (dcsr_value & 0xfffffffc) | 2);
        else
                xscale_write_dcsr_sw(target, dcsr_value & 0xfffffffc);
@@ -3037,14 +3453,19 @@ int xscale_handle_trace_buffer_command(struct command_context_s *cmd_ctx, char *
        return ERROR_OK;
 }
 
-int xscale_handle_dump_trace_buffer_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+int xscale_handle_trace_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-       target_t *target = get_current_target(cmd_ctx);
+       target_t *target;
        armv4_5_common_t *armv4_5;
        xscale_common_t *xscale;
-       u32 trace_buffer[258];
-       int is_address[256];
-       int i;
+
+       if (argc < 1)
+       {
+               command_print(cmd_ctx, "usage: xscale trace_image <file> [base address] [type]");
+               return ERROR_OK;
+       }
+       
+       target = get_current_target(cmd_ctx);
        
        if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
        {
@@ -3052,107 +3473,68 @@ int xscale_handle_dump_trace_buffer_command(struct command_context_s *cmd_ctx, c
                return ERROR_OK;
        }
        
-       if (target->state != TARGET_HALTED)
+       if (xscale->trace.image)
        {
-               command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
-               return ERROR_OK;
+               image_close(xscale->trace.image);
+               free(xscale->trace.image);
+               command_print(cmd_ctx, "previously loaded image found and closed");
        }
-
-       /* send read trace buffer command (command 0x61) */
-       xscale_send_u32(target, 0x61);
        
-       /* receive trace buffer content */
-       xscale_receive(target, trace_buffer, 258);
+       xscale->trace.image = malloc(sizeof(image_t));
+       xscale->trace.image->base_address_set = 0;
+       xscale->trace.image->start_address_set = 0;
        
-       for (i = 255; i >= 0; i--)
+       /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */
+       if (argc >= 2)
        {
-               is_address[i] = 0;
-               if (((trace_buffer[i] & 0xf0) == 0x90) ||
-                       ((trace_buffer[i] & 0xf0) == 0xd0)) 
-               {
-                       if (i >= 4)
-                               is_address[--i] = 1;
-                       if (i >= 3)
-                               is_address[--i] = 1;
-                       if (i >= 2)
-                               is_address[--i] = 1;
-                       if (i >= 1)
-                               is_address[--i] = 1;
-               }
+               xscale->trace.image->base_address_set = 1;
+               xscale->trace.image->base_address = strtoul(args[1], NULL, 0);
+       }
+       else
+       {
+               xscale->trace.image->base_address_set = 0;
+       }
+               
+       if (image_open(xscale->trace.image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "image opening error: %s", xscale->trace.image->error_str);
+               free(xscale->trace.image);
+               xscale->trace.image = NULL;
+               return ERROR_OK;
        }
        
-       for (i = 0; i < 256; i++)
+       return ERROR_OK;
+}
+
+int xscale_handle_dump_trace_buffer_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target = get_current_target(cmd_ctx);
+       armv4_5_common_t *armv4_5;
+       xscale_common_t *xscale;
+
+       if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
        {
-#if 0
-               command_print(cmd_ctx, "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x",
-                       trace_buffer[i + 0], trace_buffer[i + 1], trace_buffer[i + 2], trace_buffer[i + 3],
-                       trace_buffer[i + 4], trace_buffer[i + 5], trace_buffer[i + 6], trace_buffer[i + 6]
-                       );
-               i += 8;
-#endif
-               if (is_address[i])
-               {
-                       command_print(cmd_ctx, "address: 0x%2.2x%2.2x%2.2x%2.2x", trace_buffer[i], trace_buffer[i+1], trace_buffer[i+2], trace_buffer[i+3]);
-                       i += 3; 
-               }
-               else
-               {
-                       switch ((trace_buffer[i] & 0xf0) >> 4)
-                       {
-                               case 0:
-                                       command_print(cmd_ctx, "0x%2.2x: reset exception", trace_buffer[i]);
-                                       break;
-                               case 1:
-                                       command_print(cmd_ctx, "0x%2.2x: undef exception", trace_buffer[i]);
-                                       break;
-                               case 2:
-                                       command_print(cmd_ctx, "0x%2.2x: swi exception", trace_buffer[i]);
-                                       break;
-                               case 3:
-                                       command_print(cmd_ctx, "0x%2.2x: pabort exception", trace_buffer[i]);
-                                       break;
-                               case 4:
-                                       command_print(cmd_ctx, "0x%2.2x: dabort exception", trace_buffer[i]);
-                                       break;
-                               case 5:
-                                       command_print(cmd_ctx, "0x%2.2x: invalid", trace_buffer[i]);
-                                       break;
-                               case 6:
-                                       command_print(cmd_ctx, "0x%2.2x: irq exception", trace_buffer[i]);
-                                       break;
-                               case 7:
-                                       command_print(cmd_ctx, "0x%2.2x: fiq exception", trace_buffer[i]);
-                                       break;
-                               case 0x8:
-                                       command_print(cmd_ctx, "0x%2.2x: direct branch", trace_buffer[i]);
-                                       break;
-                               case 0x9:
-                                       command_print(cmd_ctx, "0x%2.2x: indirect branch", trace_buffer[i]);
-                                       break;
-                               case 0xa:
-                                       command_print(cmd_ctx, "0x%2.2x: invalid", trace_buffer[i]);
-                                       break;
-                               case 0xb:
-                                       command_print(cmd_ctx, "0x%2.2x: invalid", trace_buffer[i]);
-                                       break;
-                               case 0xc:
-                                       command_print(cmd_ctx, "0x%2.2x: checkpointed direct branch", trace_buffer[i]);
-                                       break;
-                               case 0xd:
-                                       command_print(cmd_ctx, "0x%2.2x: checkpointed indirect branch", trace_buffer[i]);
-                                       break;
-                               case 0xe:
-                                       command_print(cmd_ctx, "0x%2.2x: invalid", trace_buffer[i]);
-                                       break;
-                               case 0xf:
-                                       command_print(cmd_ctx, "0x%2.2x: rollover", trace_buffer[i]);
-                                       break;
-                       } 
-               }
+               command_print(cmd_ctx, "target isn't an XScale target");
+               return ERROR_OK;
        }
        
-       command_print(cmd_ctx, "chkpt0: 0x%8.8x, chkpt1: 0x%8.8x", trace_buffer[256], trace_buffer[257]);
+       return ERROR_OK;        
+}
+
+int xscale_handle_analyze_trace_buffer_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target = get_current_target(cmd_ctx);
+       armv4_5_common_t *armv4_5;
+       xscale_common_t *xscale;
 
+       if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "target isn't an XScale target");
+               return ERROR_OK;
+       }
+       
+       xscale_analyze_trace(target, cmd_ctx);
+       
        return ERROR_OK;        
 }
 
@@ -3176,7 +3558,10 @@ int xscale_register_commands(struct command_context_s *cmd_ctx)
        register_command(cmd_ctx, xscale_cmd, "trace_buffer", xscale_handle_trace_buffer_command, COMMAND_EXEC, "<enable|disable> ['fill'|'wrap']");
 
        register_command(cmd_ctx, xscale_cmd, "dump_trace_buffer", xscale_handle_dump_trace_buffer_command, COMMAND_EXEC, "dump content of trace buffer");
-       
+       register_command(cmd_ctx, xscale_cmd, "analyze_trace", xscale_handle_analyze_trace_buffer_command, COMMAND_EXEC, "analyze content of trace buffer");
+       register_command(cmd_ctx, xscale_cmd, "trace_image", xscale_handle_trace_image_command,
+               COMMAND_EXEC, "load image from <file> [base address]");
+               
        armv4_5_register_commands(cmd_ctx);
        
        return ERROR_OK;

Linking to existing account procedure

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

SSH host keys fingerprints

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