+ *target = 0;
+ else
+ *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);
+}
+
+static inline void xscale_display_instruction(struct target *target, uint32_t pc,
+ struct arm_instruction *instruction,
+ struct command_context *cmd_ctx)
+{
+ int retval = xscale_read_instruction(target, pc, instruction);
+ if (retval == ERROR_OK)
+ command_print(cmd_ctx, "%s", instruction->text);
+ else
+ command_print(cmd_ctx, "0x%8.8" PRIx32 "\t<not found in image>", pc);
+}
+
+static int xscale_analyze_trace(struct target *target, struct command_context *cmd_ctx)
+{
+ struct xscale_common *xscale = target_to_xscale(target);
+ struct xscale_trace_data *trace_data = xscale->trace.data;
+ int i, retval;
+ uint32_t breakpoint_pc;
+ struct arm_instruction instruction;
+ uint32_t current_pc = 0; /* initialized when address determined */
+
+ if (!xscale->trace.image)
+ LOG_WARNING("No trace image loaded; use 'xscale trace_image'");
+
+ /* loop for each trace buffer that was loaded from target */
+ while (trace_data)
+ {
+ int chkpt = 0; /* incremented as checkpointed entries found */
+ int j;
+
+ /* FIXME: set this to correct mode when trace buffer is first enabled */
+ xscale->trace.core_state = ARM_STATE_ARM;
+
+ /* loop for each entry in this trace buffer */
+ for (i = 0; i < trace_data->depth; i++)
+ {
+ int exception = 0;
+ uint32_t chkpt_reg = 0x0;
+ uint32_t branch_target = 0;
+ int count;
+
+ /* trace entry type is upper nybble of 'message byte' */
+ int trace_msg_type = (trace_data->entries[i].data & 0xf0) >> 4;
+
+ /* Target addresses of indirect branches are written into buffer
+ * before the message byte representing the branch. Skip past it */
+ if (trace_data->entries[i].type == XSCALE_TRACE_ADDRESS)
+ continue;
+
+ switch (trace_msg_type)
+ {
+ 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;
+
+ /* FIXME: vector table may be at ffff0000 */
+ branch_target = (trace_data->entries[i].data & 0xf0) >> 2;
+ break;
+
+ case 8: /* Direct Branch */
+ break;
+
+ case 9: /* Indirect Branch */
+ xscale_branch_address(trace_data, i, &branch_target);
+ break;
+
+ case 13: /* Checkpointed Indirect Branch */
+ xscale_branch_address(trace_data, i, &branch_target);
+ if ((trace_data->num_checkpoints == 2) && (chkpt == 0))
+ chkpt_reg = trace_data->chkpt1; /* 2 chkpts, this is oldest */
+ else
+ chkpt_reg = trace_data->chkpt0; /* 1 chkpt, or 2 and newest */
+
+ chkpt++;
+ break;
+
+ case 12: /* Checkpointed Direct Branch */
+ if ((trace_data->num_checkpoints == 2) && (chkpt == 0))
+ chkpt_reg = trace_data->chkpt1; /* 2 chkpts, this is oldest */
+ else
+ chkpt_reg = trace_data->chkpt0; /* 1 chkpt, or 2 and newest */
+
+ /* if no current_pc, checkpoint will be starting point */
+ if (current_pc == 0)
+ branch_target = chkpt_reg;
+
+ chkpt++;
+ break;
+
+ case 15: /* Roll-over */
+ break;
+
+ default: /* Reserved */
+ LOG_WARNING("trace is suspect: invalid trace message byte");
+ continue;
+
+ }
+
+ /* If we don't have the current_pc yet, but we did get the branch target
+ * (either from the trace buffer on indirect branch, or from a checkpoint reg),
+ * then we can start displaying instructions at the next iteration, with
+ * branch_target as the starting point.
+ */
+ if (current_pc == 0)
+ {
+ current_pc = branch_target; /* remains 0 unless branch_target obtained */
+ continue;
+ }
+
+ /* We have current_pc. Read and display the instructions from the image.
+ * First, display count instructions (lower nybble of message byte). */
+ count = trace_data->entries[i].data & 0x0f;
+ for (j = 0; j < count; j++)
+ {
+ xscale_display_instruction(target, current_pc, &instruction, cmd_ctx);
+ current_pc += xscale->trace.core_state == ARM_STATE_ARM ? 4 : 2;
+ }
+
+ /* An additional instruction is implicitly added to count for
+ * rollover and some exceptions: undef, swi, prefetch abort. */
+ if ((trace_msg_type == 15) || (exception > 0 && exception < 4))
+ {
+ xscale_display_instruction(target, current_pc, &instruction, cmd_ctx);
+ current_pc += xscale->trace.core_state == ARM_STATE_ARM ? 4 : 2;
+ }
+
+ if (trace_msg_type == 15) /* rollover */
+ continue;
+
+ if (exception)
+ {
+ command_print(cmd_ctx, "--- exception %i ---", exception);
+ continue;
+ }
+
+ /* not exception or rollover; next instruction is a branch and is
+ * not included in the count */
+ xscale_display_instruction(target, current_pc, &instruction, cmd_ctx);
+
+ /* for direct branches, extract branch destination from instruction */
+ if ((trace_msg_type == 8) || (trace_msg_type == 12))
+ {
+ retval = xscale_read_instruction(target, current_pc, &instruction);
+ if (retval == ERROR_OK)
+ current_pc = instruction.info.b_bl_bx_blx.target_address;
+ else
+ current_pc = 0; /* branch destination unknown */