diff options
author | drath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60> | 2007-05-29 11:23:42 +0000 |
---|---|---|
committer | drath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60> | 2007-05-29 11:23:42 +0000 |
commit | 237e894805dd757cc24029af1b4b1e824c51712b (patch) | |
tree | abe2187fa53c3ba2e51201df0a60a6e10af6cc0f /src/target | |
parent | e8af4de0a7d224e1aa28e72f0de1ddf0bec5beb8 (diff) | |
download | riscv-openocd-237e894805dd757cc24029af1b4b1e824c51712b.zip riscv-openocd-237e894805dd757cc24029af1b4b1e824c51712b.tar.gz riscv-openocd-237e894805dd757cc24029af1b4b1e824c51712b.tar.bz2 |
- split fileio handling into fileio part and image handling
- reworked etm/etb into a generic etm part with trace capture drivers (currently only etb supported)
- added XScale debug handler binary to repository
- added Thumb disassembling (thanks to Vincent Palatin for this patch)
- added support for non-CFI compatible flashes to cfi driver (currently only SST39VFxxx devices supported)
This checkin is experimental, not suitable for general use
git-svn-id: svn://svn.berlios.de/openocd/trunk@155 b42882b7-edfa-0310-969c-e2dbd0fdcd60
Diffstat (limited to 'src/target')
-rw-r--r-- | src/target/Makefile.am | 4 | ||||
-rw-r--r-- | src/target/arm7_9_common.c | 85 | ||||
-rw-r--r-- | src/target/arm7_9_common.h | 7 | ||||
-rw-r--r-- | src/target/arm7tdmi.c | 6 | ||||
-rw-r--r-- | src/target/arm9tdmi.c | 12 | ||||
-rw-r--r-- | src/target/arm_disassembler.c | 787 | ||||
-rw-r--r-- | src/target/arm_disassembler.h | 5 | ||||
-rw-r--r-- | src/target/arm_simulator.c | 50 | ||||
-rw-r--r-- | src/target/armv4_5.h | 8 | ||||
-rw-r--r-- | src/target/etb.c | 543 | ||||
-rw-r--r-- | src/target/etb.h | 12 | ||||
-rw-r--r-- | src/target/etm.c | 686 | ||||
-rw-r--r-- | src/target/etm.h | 131 | ||||
-rw-r--r-- | src/target/target.c | 56 | ||||
-rwxr-xr-x | src/target/xscale/debug_handler.bin | bin | 0 -> 1592 bytes |
15 files changed, 1968 insertions, 424 deletions
diff --git a/src/target/Makefile.am b/src/target/Makefile.am index cf1955a..b1e6f91 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -3,7 +3,7 @@ METASOURCES = AUTO noinst_LIBRARIES = libtarget.a libtarget_a_SOURCES = target.c register.c breakpoints.c armv4_5.c embeddedice.c etm.c arm7tdmi.c arm9tdmi.c \ arm_jtag.c arm7_9_common.c algorithm.c arm920t.c arm720t.c armv4_5_mmu.c armv4_5_cache.c arm_disassembler.c \ - arm966e.c arm926ejs.c etb.c xscale.c arm_simulator.c + arm966e.c arm926ejs.c etb.c xscale.c arm_simulator.c image.c noinst_HEADERS = target.h register.h armv4_5.h embeddedice.h etm.h arm7tdmi.h arm9tdmi.h \ arm_jtag.h arm7_9_common.h arm920t.h arm720t.h armv4_5_mmu.h armv4_5_cache.h breakpoints.h algorithm.h \ - arm_disassembler.h arm966e.h arm926ejs.h etb.h xscale.h arm_simulator.h + arm_disassembler.h arm966e.h arm926ejs.h etb.h xscale.h arm_simulator.h image.h diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index 2c82c91..77a43fe 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -2096,8 +2096,6 @@ int arm7_9_register_commands(struct command_context_s *cmd_ctx) arm7_9_cmd = register_command(cmd_ctx, NULL, "arm7_9", NULL, COMMAND_ANY, "arm7/9 specific commands"); - register_command(cmd_ctx, arm7_9_cmd, "etm", handle_arm7_9_etm_command, COMMAND_CONFIG, NULL); - register_command(cmd_ctx, arm7_9_cmd, "write_xpsr", handle_arm7_9_write_xpsr_command, COMMAND_EXEC, "write program status register <value> <not cpsr|spsr>"); register_command(cmd_ctx, arm7_9_cmd, "write_xpsr_im8", handle_arm7_9_write_xpsr_im8_command, COMMAND_EXEC, "write program status register <8bit immediate> <rotate> <not cpsr|spsr>"); @@ -2115,7 +2113,8 @@ int arm7_9_register_commands(struct command_context_s *cmd_ctx) COMMAND_ANY, "use DCC downloads for larger memory writes <enable|disable>"); armv4_5_register_commands(cmd_ctx); - etb_register_commands(cmd_ctx, arm7_9_cmd); + + etm_register_commands(cmd_ctx); return ERROR_OK; } @@ -2425,83 +2424,6 @@ int handle_arm7_9_dcc_downloads_command(struct command_context_s *cmd_ctx, char return ERROR_OK; } -int handle_arm7_9_etm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - - if (argc != 1) - { - ERROR("incomplete 'arm7_9 etm <target>' command"); - exit(-1); - } - - target = get_target_by_num(strtoul(args[0], NULL, 0)); - - if (!target) - { - ERROR("target number '%s' not defined", args[0]); - exit(-1); - } - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - arm7_9->has_etm = 1; - - return ERROR_OK; -} - -int handle_arm7_9_etb_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - jtag_device_t *jtag_device; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - - if (argc != 2) - { - ERROR("incomplete 'arm7_9 etb <target> <chain_pos>' command"); - exit(-1); - } - - target = get_target_by_num(strtoul(args[0], NULL, 0)); - - if (!target) - { - ERROR("target number '%s' not defined", args[0]); - exit(-1); - } - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - jtag_device = jtag_get_device(strtoul(args[1], NULL, 0)); - - if (!jtag_device) - { - ERROR("jtag device number '%s' not defined", args[1]); - exit(-1); - } - - arm7_9->etb = malloc(sizeof(etb_t)); - - arm7_9->etb->chain_pos = strtoul(args[1], NULL, 0); - arm7_9->etb->cur_scan_chain = -1; - arm7_9->etb->reg_cache = NULL; - arm7_9->etb->RAM_width = 0; - arm7_9->etb->RAM_depth = 0; - - return ERROR_OK; -} - int arm7_9_init_arch_info(target_t *target, arm7_9_common_t *arm7_9) { armv4_5_common_t *armv4_5 = &arm7_9->armv4_5_common; @@ -2515,8 +2437,7 @@ int arm7_9_init_arch_info(target_t *target, arm7_9_common_t *arm7_9) arm7_9->force_hw_bkpts = 0; arm7_9->use_dbgrq = 0; - arm7_9->has_etm = 0; - arm7_9->etb = NULL; + arm7_9->etm_ctx = NULL; arm7_9->has_single_step = 0; arm7_9->has_monitor_mode = 0; arm7_9->has_vector_catch = 0; diff --git a/src/target/arm7_9_common.h b/src/target/arm7_9_common.h index e77beda..fbcb920 100644 --- a/src/target/arm7_9_common.h +++ b/src/target/arm7_9_common.h @@ -25,7 +25,7 @@ #include "breakpoints.h" #include "target.h" -#include "etb.h" +#include "etm.h" #define ARM7_9_COMMON_MAGIC 0x0a790a79 @@ -35,7 +35,6 @@ typedef struct arm7_9_common_s arm_jtag_t jtag_info; reg_cache_t *eice_cache; - reg_cache_t *etm_cache; u32 arm_bkpt; u16 thumb_bkpt; @@ -48,8 +47,8 @@ typedef struct arm7_9_common_s int dbgreq_adjust_pc; int use_dbgrq; - int has_etm; - etb_t *etb; + etm_context_t *etm_ctx; + int has_single_step; int has_monitor_mode; int has_vector_catch; diff --git a/src/target/arm7tdmi.c b/src/target/arm7tdmi.c index 5684dcf..7c6b937 100644 --- a/src/target/arm7tdmi.c +++ b/src/target/arm7tdmi.c @@ -744,10 +744,10 @@ void arm7tdmi_build_reg_cache(target_t *target) (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9); arm7_9->eice_cache = (*cache_p)->next; - if (arm7_9->has_etm) + if (arm7_9->etm_ctx) { - (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, 0); - arm7_9->etm_cache = (*cache_p)->next->next; + (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx); + arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next; } } diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c index 112926d..7ecd1f0 100644 --- a/src/target/arm9tdmi.c +++ b/src/target/arm9tdmi.c @@ -874,16 +874,10 @@ void arm9tdmi_build_reg_cache(target_t *target) (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9); arm7_9->eice_cache = (*cache_p)->next; - if (arm7_9->has_etm) + if (arm7_9->etm_ctx) { - (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, 0); - arm7_9->etm_cache = (*cache_p)->next->next; - } - - if (arm7_9->etb) - { - (*cache_p)->next->next->next = etb_build_reg_cache(arm7_9->etb); - arm7_9->etb->reg_cache = (*cache_p)->next->next->next; + (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx); + arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next; } } diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index dd77928..1c275f5 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -343,7 +343,10 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction) if (!I) /* #+-<offset_12> */ { u32 offset_12 = (opcode & 0xfff); - snprintf(offset, 32, "#%s0x%x", (U) ? "" : "-", offset_12); + if (offset_12) + snprintf(offset, 32, ", #%s0x%x", (U) ? "" : "-", offset_12); + else + snprintf(offset, 32, ""); instruction->info.load_store.offset_mode = 0; instruction->info.load_store.offset.offset = offset_12; @@ -376,26 +379,26 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction) if ((shift_imm == 0x0) && (shift == 0x0)) /* +-<Rm> */ { - snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm); + snprintf(offset, 32, ", %sr%i", (U) ? "" : "-", Rm); } else /* +-<Rm>, <Shift>, #<shift_imm> */ { switch (shift) { case 0x0: /* LSL */ - snprintf(offset, 32, "%sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm); + snprintf(offset, 32, ", %sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm); break; case 0x1: /* LSR */ - snprintf(offset, 32, "%sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm); + snprintf(offset, 32, ", %sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm); break; case 0x2: /* ASR */ - snprintf(offset, 32, "%sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm); + snprintf(offset, 32, ", %sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm); break; case 0x3: /* ROR */ - snprintf(offset, 32, "%sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm); + snprintf(offset, 32, ", %sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm); break; case 0x4: /* RRX */ - snprintf(offset, 32, "%sr%i, RRX", (U) ? "" : "-", Rm); + snprintf(offset, 32, ", %sr%i, RRX", (U) ? "" : "-", Rm); break; } } @@ -405,7 +408,7 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction) { if (W == 0) /* offset */ { - snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]", + snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]", address, opcode, operation, COND(opcode), suffix, Rd, Rn, offset); @@ -413,7 +416,7 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction) } else /* pre-indexed */ { - snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]!", + snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]!", address, opcode, operation, COND(opcode), suffix, Rd, Rn, offset); @@ -422,7 +425,7 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction) } else /* post-indexed */ { - snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i], %s", + snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i]%s", address, opcode, operation, COND(opcode), suffix, Rd, Rn, offset); @@ -1157,7 +1160,10 @@ int evaluate_data_proc(u32 opcode, u32 address, arm_instruction_t *instruction) } else if ((op == 0xd) || (op == 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */ { - snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, %s", + if (opcode==0xe1a00000) /* print MOV r0,r0 as NOP */ + snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tNOP",address, opcode); + else + snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, %s", address, opcode, mnemonic, COND(opcode), (S) ? "S" : "", Rd, shifter_operand); } @@ -1315,3 +1321,762 @@ int arm_evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction) return -1; } +int evaluate_b_bl_blx_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) +{ + u32 offset = opcode & 0x7ff; + u32 opc = (opcode >> 11) & 0x3; + u32 target_address; + char *mnemonic = NULL; + + /* sign extend 11-bit offset */ + if (((opc==0) || (opc==2)) && (offset & 0x00000400)) + offset = 0xfffff800 | offset; + + target_address = address + 4 + (offset<<1); + + switch(opc) + { + /* unconditional branch */ + case 0: + instruction->type = ARM_B; + mnemonic = "B"; + break; + /* BLX suffix */ + case 1: + instruction->type = ARM_BLX; + mnemonic = "BLX"; + break; + /* BL/BLX prefix */ + case 2: + instruction->type = ARM_UNKNOWN_INSTUCTION; + mnemonic = "prefix"; + target_address = offset<<12; + break; + /* BL suffix */ + case 3: + instruction->type = ARM_BL; + mnemonic = "BL"; + break; + } + /* TODO: deals correctly with dual opcodes BL/BLX ... */ + + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s 0x%8.8x", address, opcode,mnemonic, target_address); + + instruction->info.b_bl_bx_blx.reg_operand = -1; + instruction->info.b_bl_bx_blx.target_address = target_address; + + return ERROR_OK; +} + +int evaluate_add_sub_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) +{ + u8 Rd = (opcode >> 0) & 0x7; + u8 Rn = (opcode >> 3) & 0x7; + u8 Rm_imm = (opcode >> 6) & 0x7; + u32 opc = opcode & (1<<9); + u32 reg_imm = opcode & (1<<10); + char *mnemonic; + + if (opc) + { + instruction->type = ARM_SUB; + mnemonic = "SUBS"; + } + else + { + instruction->type = ARM_ADD; + mnemonic = "ADDS"; + } + + instruction->info.data_proc.Rd = Rd; + instruction->info.data_proc.Rn = Rn; + instruction->info.data_proc.S = 1; + + if (reg_imm) + { + instruction->info.data_proc.variant = 0; /*immediate*/ + instruction->info.data_proc.shifter_operand.immediate.immediate = Rm_imm; + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, #%d", + address, opcode, mnemonic, Rd, Rn, Rm_imm); + } + else + { + instruction->info.data_proc.variant = 1; /*immediate shift*/ + instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm_imm; + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, r%i", + address, opcode, mnemonic, Rd, Rn, Rm_imm); + } + + return ERROR_OK; +} + +int evaluate_shift_imm_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) +{ + u8 Rd = (opcode >> 0) & 0x7; + u8 Rm = (opcode >> 3) & 0x7; + u8 imm = (opcode >> 6) & 0x1f; + u8 opc = (opcode >> 11) & 0x3; + char *mnemonic = NULL; + + switch(opc) + { + case 0: + instruction->type = ARM_MOV; + mnemonic = "LSLS"; + instruction->info.data_proc.shifter_operand.immediate_shift.shift = 0; + break; + case 1: + instruction->type = ARM_MOV; + mnemonic = "LSRS"; + instruction->info.data_proc.shifter_operand.immediate_shift.shift = 1; + break; + case 2: + instruction->type = ARM_MOV; + mnemonic = "ASRS"; + instruction->info.data_proc.shifter_operand.immediate_shift.shift = 2; + break; + } + + if ((imm==0) && (opc!=0)) + imm = 32; + + instruction->info.data_proc.Rd = Rd; + instruction->info.data_proc.Rn = -1; + instruction->info.data_proc.S = 1; + + instruction->info.data_proc.variant = 1; /*immediate_shift*/ + instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm; + instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = imm; + + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, #0x%02x", + address, opcode, mnemonic, Rd, Rm, imm); + + return ERROR_OK; +} + +int evaluate_data_proc_imm_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) +{ + u8 imm = opcode & 0xff; + u8 Rd = (opcode >> 8) & 0x7; + u32 opc = (opcode >> 11) & 0x3; + char *mnemonic = NULL; + + instruction->info.data_proc.Rd = Rd; + instruction->info.data_proc.Rn = Rd; + instruction->info.data_proc.S = 1; + instruction->info.data_proc.variant = 0; /*immediate*/ + instruction->info.data_proc.shifter_operand.immediate.immediate = imm; + + switch(opc) + { + case 0: + instruction->type = ARM_MOV; + mnemonic = "MOVS"; + instruction->info.data_proc.Rn = -1; + break; + case 1: + instruction->type = ARM_CMP; + mnemonic = "CMP"; + instruction->info.data_proc.Rd = -1; + break; + case 2: + instruction->type = ARM_ADD; + mnemonic = "ADDS"; + break; + case 3: + instruction->type = ARM_SUB; + mnemonic = "SUBS"; + break; + } + + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, #0x%02x", + address, opcode, mnemonic, Rd, imm); + + return ERROR_OK; +} + +int evaluate_data_proc_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) +{ + u8 high_reg, op, Rm, Rd,H1,H2; + char *mnemonic = NULL; + + high_reg = (opcode & 0x0400) >> 10; + op = (opcode & 0x03C0) >> 6; + + Rd = (opcode & 0x0007); + Rm = (opcode & 0x0038) >> 3; + H1 = (opcode & 0x0080) >> 7; + H2 = (opcode & 0x0040) >> 6; + + instruction->info.data_proc.Rd = Rd; + instruction->info.data_proc.Rn = Rd; + instruction->info.data_proc.S = (!high_reg || (instruction->type == ARM_CMP)); + instruction->info.data_proc.variant = 1 /*immediate shift*/; + instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm; + + if (high_reg) + { + Rd |= H1 << 3; + Rm |= H2 << 3; + op >>= 2; + + switch (op) + { + case 0x0: + instruction->type = ARM_ADD; + mnemonic = "ADD"; + break; + case 0x1: + instruction->type = ARM_CMP; + mnemonic = "CMP"; + break; + case 0x2: + instruction->type = ARM_MOV; + mnemonic = "MOV"; + break; + case 0x3: + if ((opcode & 0x7) == 0x0) + { + instruction->info.b_bl_bx_blx.reg_operand = Rm; + if (H1) + { + instruction->type = ARM_BLX; + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tBLX r%i", address, opcode, Rm); + } + else + { + instruction->type = ARM_BX; + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tBX r%i", address, opcode, Rm); + } + } + else + { + instruction->type = ARM_UNDEFINED_INSTRUCTION; + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address, opcode); + } + return ERROR_OK; + break; + } + } + else + { + switch (op) + { + case 0x0: + instruction->type = ARM_AND; + mnemonic = "ANDS"; + break; + case 0x1: + instruction->type = ARM_EOR; + mnemonic = "EORS"; + break; + case 0x2: + instruction->type = ARM_MOV; + mnemonic = "LSLS"; + instruction->info.data_proc.variant = 2 /*register shift*/; + instruction->info.data_proc.shifter_operand.register_shift.shift = 0; + instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd; + instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm; + break; + case 0x3: + instruction->type = ARM_MOV; + mnemonic = "LSRS"; + instruction->info.data_proc.variant = 2 /*register shift*/; + instruction->info.data_proc.shifter_operand.register_shift.shift = 1; + instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd; + instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm; + break; + case 0x4: + instruction->type = ARM_MOV; + mnemonic = "ASRS"; + instruction->info.data_proc.variant = 2 /*register shift*/; + instruction->info.data_proc.shifter_operand.register_shift.shift = 2; + instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd; + instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm; + break; + case 0x5: + instruction->type = ARM_ADC; + mnemonic = "ADCS"; + break; + case 0x6: + instruction->type = ARM_SBC; + mnemonic = "SBCS"; + break; + case 0x7: + instruction->type = ARM_MOV; + mnemonic = "RORS"; + instruction->info.data_proc.variant = 2 /*register shift*/; + instruction->info.data_proc.shifter_operand.register_shift.shift = 3; + instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd; + instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm; + break; + case 0x8: + instruction->type = ARM_TST; + mnemonic = "TST"; + break; + case 0x9: + instruction->type = ARM_RSB; + mnemonic = "NEGS"; + instruction->info.data_proc.variant = 0 /*immediate*/; + instruction->info.data_proc.shifter_operand.immediate.immediate = 0; + instruction->info.data_proc.Rn = Rm; + break; + case 0xA: + instruction->type = ARM_CMP; + mnemonic = "CMP"; + break; + case 0xB: + instruction->type = ARM_CMN; + mnemonic = "CMN"; + break; + case 0xC: + instruction->type = ARM_ORR; + mnemonic = "ORRS"; + break; + case 0xD: + instruction->type = ARM_MUL; + mnemonic = "MULS"; + break; + case 0xE: + instruction->type = ARM_BIC; + mnemonic = "BICS"; + break; + case 0xF: + instruction->type = ARM_MVN; + mnemonic = "MVNS"; + break; + } + } + + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i", + address, opcode, mnemonic, Rd, Rm); + + return ERROR_OK; +} + +int evaluate_load_literal_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) +{ + u32 immediate; + u8 Rd = (opcode >> 8) & 0x7; + + instruction->type = ARM_LDR; + immediate = opcode & 0x000000ff; + + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tLDR r%i, [PC, #0x%x]", address, opcode, Rd, immediate*4); + + instruction->info.load_store.Rd = Rd; + instruction->info.load_store.Rn = 15 /*PC*/; + instruction->info.load_store.index_mode = 0; /*offset*/ + instruction->info.load_store.offset_mode = 0; /*immediate*/ + instruction->info.load_store.offset.offset = immediate*4; + + return ERROR_OK; +} + +int evaluate_load_store_reg_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) +{ + u8 Rd = (opcode >> 0) & 0x7; + u8 Rn = (opcode >> 3) & 0x7; + u8 Rm = (opcode >> 6) & 0x7; + u8 opc = (opcode >> 9) & 0x7; + char *mnemonic = NULL; + + switch(opc) + { + case 0: + instruction->type = ARM_STR; + mnemonic = "STR"; + break; + case 1: + instruction->type = ARM_STRH; + mnemonic = "STRH"; + break; + case 2: + instruction->type = ARM_STRB; + mnemonic = "STRB"; + break; + case 3: + instruction->type = ARM_LDRSB; + mnemonic = "LDRSB"; + break; + case 4: + instruction->type = ARM_LDR; + mnemonic = "LDR"; + break; + case 5: + instruction->type = ARM_LDRH; + mnemonic = "LDRH"; + break; + case 6: + instruction->type = ARM_LDRB; + mnemonic = "LDRB"; + break; + case 7: + instruction->type = ARM_LDRSH; + mnemonic = "LDRSH"; + break; + } + + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, [r%i, r%i]", address, opcode, mnemonic, Rd, Rn, Rm); + + instruction->info.load_store.Rd = Rd; + instruction->info.load_store.Rn = Rn; + instruction->info.load_store.index_mode = 0; /*offset*/ + instruction->info.load_store.offset_mode = 1; /*register*/ + instruction->info.load_store.offset.reg.Rm = Rm; + + return ERROR_OK; +} + +int evaluate_load_store_imm_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) +{ + u32 offset = (opcode >> 6) & 0x1f; + u8 Rd = (opcode >> 0) & 0x7; + u8 Rn = (opcode >> 3) & 0x7; + u32 L = opcode & (1<<11); + u32 B = opcode & (1<<12); + char *mnemonic; + char suffix = ' '; + u32 shift = 2; + + if (L) + { + instruction->type = ARM_LDR; + mnemonic = "LDR"; + } + else + { + instruction->type = ARM_STR; + mnemonic = "STR"; + } + + if ((opcode&0xF000)==0x8000) + { + suffix = 'H'; + shift = 1; + } + else if (B) + { + suffix = 'B'; + shift = 0; + } + + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s%c r%i, [r%i, #0x%x]", address, opcode, mnemonic, suffix, Rd, Rn, offset<<shift); + + instruction->info.load_store.Rd = Rd; + instruction->info.load_store.Rn = Rn; + instruction->info.load_store.index_mode = 0; /*offset*/ + instruction->info.load_store.offset_mode = 0; /*immediate*/ + instruction->info.load_store.offset.offset = offset<<shift; + + return ERROR_OK; +} + +int evaluate_load_store_stack_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) +{ + u32 offset = opcode & 0xff; + u8 Rd = (opcode >> 8) & 0x7; + u32 L = opcode & (1<<11); + char *mnemonic; + + if (L) + { + instruction->type = ARM_LDR; + mnemonic = "LDR"; + } + else + { + instruction->type = ARM_STR; + mnemonic = "STR"; + } + + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, [SP, #0x%x]", address, opcode, mnemonic, Rd, offset*4); + + instruction->info.load_store.Rd = Rd; + instruction->info.load_store.Rn = 13 /*SP*/; + instruction->info.load_store.index_mode = 0; /*offset*/ + instruction->info.load_store.offset_mode = 0; /*immediate*/ + instruction->info.load_store.offset.offset = offset*4; + + return ERROR_OK; +} + +int evaluate_add_sp_pc_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) +{ + u32 imm = opcode & 0xff; + u8 Rd = (opcode >> 8) & 0x7; + u8 Rn; + u32 SP = opcode & (1<<11); + char *reg_name; + + instruction->type = ARM_ADD; + + if (SP) + { + reg_name = "SP"; + Rn = 13; + } + else + { + reg_name = "PC"; + Rn = 15; + } + + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tADD r%i, %s, #0x%x", address, opcode, Rd,reg_name, imm*4); + + instruction->info.data_proc.variant = 0 /* immediate */; + instruction->info.data_proc.Rd = Rd; + instruction->info.data_proc.Rn = Rn; + instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4; + + return ERROR_OK; +} + +int evaluate_adjust_stack_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) +{ + u32 imm = opcode & 0x7f; + u8 opc = opcode & (1<<7); + char *mnemonic; + + + if (opc) + { + instruction->type = ARM_SUB; + mnemonic = "SUB"; + } + else + { + instruction->type = ARM_ADD; + mnemonic = "ADD"; + } + + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s SP, #0x%x", address, opcode, mnemonic, imm*4); + + instruction->info.data_proc.variant = 0 /* immediate */; + instruction->info.data_proc.Rd = 13 /*SP*/; + instruction->info.data_proc.Rn = 13 /*SP*/; + instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4; + + return ERROR_OK; +} + +int evaluate_breakpoint_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) +{ + u32 imm = opcode & 0xff; + + instruction->type = ARM_BKPT; + + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tBKPT 0x%02x", address, opcode, imm); + + return ERROR_OK; +} + +int evaluate_load_store_multiple_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) +{ + u32 reg_list = opcode & 0xff; + u32 L = opcode & (1<<11); + u32 R = opcode & (1<<8); + u8 Rn = (opcode >> 8) & 7; + u8 addr_mode = 0 /* IA */; + char reg_names[40]; + char *reg_names_p; + char *mnemonic; + char ptr_name[7] = ""; + int i; + + if ((opcode & 0xf000) == 0xc000) + { /* generic load/store multiple */ + if (L) + { + instruction->type = ARM_LDM; + mnemonic = "LDMIA"; + } + else + { + instruction->type = ARM_STM; + mnemonic = "STMIA"; + } + snprintf(ptr_name,7,"r%i!, ",Rn); + } + else + { /* push/pop */ + Rn = 13; /* SP */ + if (L) + { + instruction->type = ARM_LDM; + mnemonic = "POP"; + if (R) + reg_list |= (1<<15) /*PC*/; + } + else + { + instruction->type = ARM_STM; + mnemonic = "PUSH"; + addr_mode = 3; /*DB*/ + if (R) + reg_list |= (1<<14) /*LR*/; + } + } + + reg_names_p = reg_names; + for (i = 0; i <= 15; i++) + { + if (reg_list & (1<<i)) + reg_names_p += snprintf(reg_names_p, (reg_names + 40 - reg_names_p), "r%i, ", i); + } + if (reg_names_p>reg_names) + reg_names_p[-2] = '\0'; + else /* invalid op : no registers */ + reg_names[0] = '\0'; + + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s %s{%s}", address, opcode, mnemonic, ptr_name,reg_names); + + instruction->info.load_store_multiple.register_list = reg_list; + instruction->info.load_store_multiple.Rn = Rn; + instruction->info.load_store_multiple.addressing_mode = addr_mode; + + return ERROR_OK; +} + +int evaluate_cond_branch_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) +{ + u32 offset = opcode & 0xff; + u8 cond = (opcode >> 8) & 0xf; + u32 target_address; + + if (cond == 0xf) + { + instruction->type = ARM_SWI; + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tSWI 0x%02x", address, opcode, offset); + return ERROR_OK; + } + else if (cond == 0xe) + { + instruction->type = ARM_UNDEFINED_INSTRUCTION; + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address, opcode); + return ERROR_OK; + } + + /* sign extend 8-bit offset */ + if (offset & 0x00000080) + offset = 0xffffff00 | offset; + + target_address = address + 4 + (offset<<1); + + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tB%s 0x%8.8x", address, opcode, + arm_condition_strings[cond], target_address); + + instruction->type = ARM_B; + instruction->info.b_bl_bx_blx.reg_operand = -1; + instruction->info.b_bl_bx_blx.target_address = target_address; + + return ERROR_OK; +} + +int thumb_evaluate_opcode(u16 opcode, u32 address, arm_instruction_t *instruction) +{ + /* clear fields, to avoid confusion */ + memset(instruction, 0, sizeof(arm_instruction_t)); + instruction->opcode = opcode; + + if ((opcode & 0xe000) == 0x0000) + { + /* add/substract register or immediate */ + if ((opcode & 0x1800) == 0x1800) + return evaluate_add_sub_thumb(opcode, address, instruction); + /* shift by immediate */ + else + return evaluate_shift_imm_thumb(opcode, address, instruction); + } + + /* Add/substract/compare/move immediate */ + if ((opcode & 0xe000) == 0x2000) + { + return evaluate_data_proc_imm_thumb(opcode, address, instruction); + } + + /* Data processing instructions */ + if ((opcode & 0xf800) == 0x4000) + { + return evaluate_data_proc_thumb(opcode, address, instruction); + } + + /* Load from literal pool */ + if ((opcode & 0xf800) == 0x4800) + { + return evaluate_load_literal_thumb(opcode, address, instruction); + } + + /* Load/Store register offset */ + if ((opcode & 0xf000) == 0x5000) + { + return evaluate_load_store_reg_thumb(opcode, address, instruction); + } + + /* Load/Store immediate offset */ + if (((opcode & 0xe000) == 0x6000) + ||((opcode & 0xf000) == 0x8000)) + { + return evaluate_load_store_imm_thumb(opcode, address, instruction); + } + + /* Load/Store from/to stack */ + if ((opcode & 0xf000) == 0x9000) + { + return evaluate_load_store_stack_thumb(opcode, address, instruction); + } + + /* Add to SP/PC */ + if ((opcode & 0xf000) == 0xa000) + { + return evaluate_add_sp_pc_thumb(opcode, address, instruction); + } + + /* Misc */ + if ((opcode & 0xf000) == 0xb000) + { + if ((opcode & 0x0f00) == 0x0000) + return evaluate_adjust_stack_thumb(opcode, address, instruction); + else if ((opcode & 0x0f00) == 0x0e00) + return evaluate_breakpoint_thumb(opcode, address, instruction); + else if ((opcode & 0x0600) == 0x0400) /* push pop */ + return evaluate_load_store_multiple_thumb(opcode, address, instruction); + else + { + instruction->type = ARM_UNDEFINED_INSTRUCTION; + snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address, opcode); + return ERROR_OK; + } + } + + /* Load/Store multiple */ + if ((opcode & 0xf000) == 0xc000) + { + return evaluate_load_store_multiple_thumb(opcode, address, instruction); + } + + /* Conditional branch + SWI */ + if ((opcode & 0xf000) == 0xd000) + { + return evaluate_cond_branch_thumb(opcode, address, instruction); + } + + if ((opcode & 0xe000) == 0xe000) + { + /* Undefined instructions */ + if ((opcode & 0xf801) == 0xe801) + { + instruction->type = ARM_UNDEFINED_INSTRUCTION; + snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address, opcode); + return ERROR_OK; + } + else + { /* Branch to offset */ + return evaluate_b_bl_blx_thumb(opcode, address, instruction); + } + } + + ERROR("should never reach this point (opcode=%04x)",opcode); + return -1; +} + diff --git a/src/target/arm_disassembler.h b/src/target/arm_disassembler.h index b55c885..bdab113 100644 --- a/src/target/arm_disassembler.h +++ b/src/target/arm_disassembler.h @@ -133,7 +133,7 @@ union arm_shifter_operand } immediate; struct { u8 Rm; - u8 shift; + u8 shift; /* 0: LSL, 1: LSR, 2: ASR, 3: ROR, 4: RRX */ u8 shift_imm; } immediate_shift; struct { @@ -164,7 +164,7 @@ typedef struct arm_load_store_instr_s u32 offset; struct { u8 Rm; - u8 shift; + u8 shift; /* 0: LSL, 1: LSR, 2: ASR, 3: ROR, 4: RRX */ u8 shift_imm; } reg; } offset; @@ -195,6 +195,7 @@ typedef struct arm_instruction_s } arm_instruction_t; 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); #define COND(opcode) (arm_condition_strings[(opcode & 0xf0000000)>>28]) diff --git a/src/target/arm_simulator.c b/src/target/arm_simulator.c index fd0b309..561b14f 100644 --- a/src/target/arm_simulator.c +++ b/src/target/arm_simulator.c @@ -257,6 +257,11 @@ int pass_condition(u32 cpsr, u32 opcode) return 0; } +int thumb_pass_branch_condition(u32 cpsr, u16 opcode) +{ + return pass_condition(cpsr, (opcode & 0x0f00) << 20); +} + /* simulate a single step (if possible) * if the dry_run_pc argument is provided, no state is changed, * but the new pc is stored in the variable pointed at by the argument @@ -275,26 +280,43 @@ int arm_simulate_step(target_t *target, u32 *dry_run_pc) target_read_u32(target, current_pc, &opcode); arm_evaluate_opcode(opcode, current_pc, &instruction); instruction_size = 4; + + /* check condition code (for all instructions) */ + if (!pass_condition(buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), opcode)) + { + if (dry_run_pc) + { + *dry_run_pc = current_pc + instruction_size; + } + else + { + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, current_pc + instruction_size); + } + + return ERROR_OK; + } } else { - /* TODO: add support for Thumb instruction set */ + target_read_u32(target, current_pc, &opcode); + arm_evaluate_opcode(opcode, current_pc, &instruction); instruction_size = 2; - } - - /* check condition code */ - if (!pass_condition(buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), opcode)) - { - if (dry_run_pc) - { - *dry_run_pc = current_pc + instruction_size; - } - else + + /* check condition code (only for branch instructions) */ + if ((!thumb_pass_branch_condition(buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), opcode)) && + (instruction.type == ARM_B)) { - buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, current_pc + instruction_size); + if (dry_run_pc) + { + *dry_run_pc = current_pc + instruction_size; + } + else + { + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, current_pc + instruction_size); + } + + return ERROR_OK; } - - return ERROR_OK; } /* examine instruction type */ diff --git a/src/target/armv4_5.h b/src/target/armv4_5.h index 0ba94ff..36264f3 100644 --- a/src/target/armv4_5.h +++ b/src/target/armv4_5.h @@ -23,7 +23,7 @@ #include "register.h" #include "target.h" -enum armv4_5_mode +typedef enum armv4_5_mode { ARMV4_5_MODE_USR = 16, ARMV4_5_MODE_FIQ = 17, @@ -33,16 +33,16 @@ enum armv4_5_mode ARMV4_5_MODE_UND = 27, ARMV4_5_MODE_SYS = 31, ARMV4_5_MODE_ANY = -1 -}; +} armv4_5_mode_t; extern char* armv4_5_mode_strings[]; -enum armv4_5_state +typedef enum armv4_5_state { ARMV4_5_STATE_ARM, ARMV4_5_STATE_THUMB, ARMV4_5_STATE_JAZELLE, -}; +} armv4_5_state_t; extern char* armv4_5_state_strings[]; diff --git a/src/target/etb.c b/src/target/etb.c index 21f250a..257c4b1 100644 --- a/src/target/etb.c +++ b/src/target/etb.c @@ -21,8 +21,11 @@ #include "config.h" #endif +#include <string.h> + #include "arm7_9_common.h" #include "etb.h" +#include "etm.h" #include "log.h" #include "types.h" @@ -55,16 +58,7 @@ int etb_set_reg_w_exec(reg_t *reg, u8 *buf); int etb_write_reg(reg_t *reg, u32 value); int etb_read_reg(reg_t *reg); -int handle_arm7_9_etb_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_arm7_9_etb_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -char *etmv1_branch_reason_string[] = -{ - "normal pc change", "tracing enabled", "restart after FIFO overflow", - "exit from debug state", "peridoic synchronization point", - "reserved", "reserved", "reserved" -}; - +int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); int etb_set_instr(etb_t *etb, u32 new_instr) { @@ -180,6 +174,74 @@ int etb_get_reg(reg_t *reg) return ERROR_OK; } +int etb_read_ram(etb_t *etb, u32 *data, int num_frames) +{ + scan_field_t fields[3]; + int i; + + jtag_add_end_state(TAP_RTI); + etb_scann(etb, 0x0); + etb_set_instr(etb, 0xc); + + fields[0].device = etb->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = etb->chain_pos; + fields[1].num_bits = 7; + fields[1].out_value = malloc(1); + buf_set_u32(fields[1].out_value, 0, 7, 4); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = etb->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = malloc(1); + buf_set_u32(fields[2].out_value, 0, 1, 0); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1, NULL); + + fields[0].in_handler = buf_to_u32_handler; + + for (i = 0; i < num_frames; i++) + { + /* ensure nR/W reamins set to read */ + buf_set_u32(fields[2].out_value, 0, 1, 0); + + /* address remains set to 0x4 (RAM data) until we read the last frame */ + if (i < num_frames - 1) + buf_set_u32(fields[1].out_value, 0, 7, 4); + else + buf_set_u32(fields[1].out_value, 0, 7, 0); + + fields[0].in_handler_priv = &data[i]; + jtag_add_dr_scan(3, fields, -1, NULL); + } + + jtag_execute_queue(); + + free(fields[1].out_value); + free(fields[2].out_value); + + return ERROR_OK; +} + int etb_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask) { etb_reg_t *etb_reg = reg->arch_info; @@ -333,293 +395,266 @@ int etb_store_reg(reg_t *reg) return etb_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); } -int etb_register_commands(struct command_context_s *cmd_ctx, command_t *arm7_9_cmd) +int etb_register_commands(struct command_context_s *cmd_ctx) { - register_command(cmd_ctx, arm7_9_cmd, "etb", handle_arm7_9_etb_command, COMMAND_CONFIG, NULL); + command_t *etb_cmd; + + etb_cmd = register_command(cmd_ctx, NULL, "etb", NULL, COMMAND_ANY, "Embedded Trace Buffer"); + + register_command(cmd_ctx, etb_cmd, "config", handle_etb_config_command, COMMAND_CONFIG, NULL); + + return ERROR_OK; +} - register_command(cmd_ctx, arm7_9_cmd, "etb_dump", handle_arm7_9_etb_dump_command, COMMAND_EXEC, "dump current ETB content"); +int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + jtag_device_t *jtag_device; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + + if (argc != 2) + { + ERROR("incomplete 'etb config <target> <chain_pos>' command"); + exit(-1); + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + jtag_device = jtag_get_device(strtoul(args[1], NULL, 0)); + + if (!jtag_device) + { + ERROR("jtag device number '%s' not defined", args[1]); + exit(-1); + } + + if (arm7_9->etm_ctx) + { + etb_t *etb = malloc(sizeof(etb_t)); + + arm7_9->etm_ctx->capture_driver_priv = etb; + + etb->chain_pos = strtoul(args[1], NULL, 0); + etb->cur_scan_chain = -1; + etb->reg_cache = NULL; + etb->ram_width = 0; + etb->ram_depth = 0; + } + else + { + ERROR("target has no ETM defined, ETB left unconfigured"); + } return ERROR_OK; } -#define PIPESTAT(x) ((x) & 0x7) -#define TRACEPKT(x) (((x) & 0x7fff8) >> 3) -#define TRACESYNC(x) (((x) & 0x80000) >> 19) +int etb_init(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + + etb->etm_ctx = etm_ctx; + + /* identify ETB RAM depth and width */ + etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_DEPTH]); + etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WIDTH]); + jtag_execute_queue(); + + etb->ram_depth = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32); + etb->ram_width = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32); + + return ERROR_OK; +} -int etmv1_next_packet(int trace_depth, u32 *trace_data, int frame, int *port_half, int apo, u8 *packet) +trace_status_t etb_status(etm_context_t *etm_ctx) { - while (frame < trace_depth) + etb_t *etb = etm_ctx->capture_driver_priv; + + etb->etm_ctx = etm_ctx; + + /* if tracing is currently idle, return this information */ + if (etm_ctx->capture_status == TRACE_IDLE) { - if (apo > 0) - { - if (TRACESYNC(trace_data[frame])) - apo--; - } - else + return etm_ctx->capture_status; + } + else if (etm_ctx->capture_status & TRACE_RUNNING) + { + reg_t *etb_status_reg = &etb->reg_cache->reg_list[ETB_STATUS]; + int etb_timeout = 100; + + /* trace is running, check the ETB status flags */ + etb_get_reg(etb_status_reg); + + /* check Full bit to identify an overflow */ + if (buf_get_u32(etb_status_reg->value, 0, 1) == 1) + etm_ctx->capture_status |= TRACE_OVERFLOWED; + + /* check Triggered bit to identify trigger condition */ + if (buf_get_u32(etb_status_reg->value, 1, 1) == 1) + etm_ctx->capture_status |= TRACE_TRIGGERED; + + /* check AcqComp to identify trace completion */ + if (buf_get_u32(etb_status_reg->value, 2, 1) == 1) { - /* we're looking for a branch address, skip if TRACESYNC isn't set */ - if ((apo == 0) && (!TRACESYNC(trace_data[frame]))) + while (etb_timeout-- && (buf_get_u32(etb_status_reg->value, 3, 1) == 0)) { - frame++; - continue; + /* wait for data formatter idle */ + etb_get_reg(etb_status_reg); } - - /* TRACEPKT is valid if this isn't a TD nor a TRIGGER cycle */ - if (((PIPESTAT(trace_data[frame]) != 0x7) && (PIPESTAT(trace_data[frame]) != 0x6)) - && !((apo == 0) && (!TRACESYNC(trace_data[frame])))) + + if (etb_timeout == 0) + { + ERROR("AcqComp set but DFEmpty won't go high, ETB status: 0x%x", + buf_get_u32(etb_status_reg->value, 0, etb_status_reg->size)); + } + + if (!(etm_ctx->capture_status && TRACE_TRIGGERED)) { - if (*port_half == 0) - { - *packet = TRACEPKT(trace_data[frame]) & 0xff; - *port_half = 1; - } - else - { - *packet = (TRACEPKT(trace_data[frame]) & 0xff00) >> 8; - *port_half = 0; - frame++; - } - return frame; + ERROR("trace completed, but no trigger condition detected"); } + + etm_ctx->capture_status &= ~TRACE_RUNNING; + etm_ctx->capture_status |= TRACE_COMPLETED; } - frame++; } - /* we reached the end of the trace without finding the packet we're looking for - * tracing is finished - */ - return -1; + return etm_ctx->capture_status; } -int handle_arm7_9_etb_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +int etb_read_trace(etm_context_t *etm_ctx) { - int retval; - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - int i, j, k; + etb_t *etb = etm_ctx->capture_driver_priv; int first_frame = 0; - int last_frame; - int addressbits_valid = 0; - u32 address = 0x0; - u32 *trace_data; - int port_half = 0; - int last_instruction = -1; - u8 branch_reason; - u8 packet; - char trace_output[256]; - int trace_output_len; - u8 apo; - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } + int num_frames = etb->ram_depth; + u32 *trace_data = NULL; + int i, j; + + etb_read_reg(&etb->reg_cache->reg_list[ETB_STATUS]); + etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER]); + jtag_execute_queue(); - if (!arm7_9->etb) + /* check if we overflowed, and adjust first frame of the trace accordingly + * if we didn't overflow, read only up to the frame that would be written next, + * i.e. don't read invalid entries + */ + if (buf_get_u32(etb->reg_cache->reg_list[ETB_STATUS].value, 0, 1)) { - command_print(cmd_ctx, "no ETB configured for current target"); - return ERROR_OK; + first_frame = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); } - - if (!(arm7_9->etb->RAM_depth && arm7_9->etb->RAM_width)) + else { - /* identify ETB RAM depth and width */ - etb_read_reg(&arm7_9->etb->reg_cache->reg_list[ETB_RAM_DEPTH]); - etb_read_reg(&arm7_9->etb->reg_cache->reg_list[ETB_RAM_WIDTH]); - jtag_execute_queue(); - - arm7_9->etb->RAM_depth = buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32); - arm7_9->etb->RAM_width = buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32); + num_frames = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); } - trace_data = malloc(sizeof(u32) * arm7_9->etb->RAM_depth); - - etb_read_reg(&arm7_9->etb->reg_cache->reg_list[ETB_STATUS]); - etb_read_reg(&arm7_9->etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER]); - jtag_execute_queue(); - - /* check if we overflowed, and adjust first and last frame of the trace accordingly */ - if (buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_STATUS].value, 1, 1)) + etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_READ_POINTER], first_frame); + + /* read data into temporary array for unpacking */ + trace_data = malloc(sizeof(u32) * num_frames); + etb_read_ram(etb, trace_data, num_frames); + + if (etm_ctx->trace_depth > 0) { - first_frame = buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); + free(etm_ctx->trace_data); } - last_frame = buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32) - 1; - - etb_write_reg(&arm7_9->etb->reg_cache->reg_list[ETB_RAM_READ_POINTER], first_frame); + if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED) + etm_ctx->trace_depth = num_frames * 2; + else + etm_ctx->trace_depth = num_frames; - /* read trace data from ETB */ - i = first_frame; - j = 0; - do { - etb_read_reg(&arm7_9->etb->reg_cache->reg_list[ETB_RAM_DATA]); - jtag_execute_queue(); - trace_data[j++] = buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_RAM_DATA].value, 0, 32); - i++; - } while ((i % arm7_9->etb->RAM_depth) != (first_frame % arm7_9->etb->RAM_depth)); + etm_ctx->trace_data= malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth); - for (i = 0, j = 0; i < arm7_9->etb->RAM_depth; i++) + for (i = 0, j = 0; i < num_frames; i++) { - int trigger = 0; - - trace_output_len = 0; - - /* catch trigger, actual PIPESTAT is encoded in TRACEPKT[2:0] */ - if (PIPESTAT(trace_data[i]) == 0x6) + if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED) { - trigger = 1; - trace_data[i] &= ~0x7; - trace_data[i] |= TRACEPKT(trace_data[i]) & 0x7; - } - - if (addressbits_valid == 32) - { - trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len, - "%i: 0x%8.8x %s", i, address, (trigger) ? "(TRIGGER) " : ""); - } - else if (addressbits_valid != 0) - { - trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len, - "%i: 0x...%x %s", i, address, (trigger) ? "(TRIGGER) " : ""); + 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+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; + + j += 2; } else { - trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len, - "%i: 0xUNK %s", i, (trigger) ? "(TRIGGER) " : ""); - } - - switch (PIPESTAT(trace_data[i])) - { - case 0x0: - trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len, - "IE"); - break; - case 0x1: - trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len, - "ID"); - break; - case 0x2: - /* Instruction exectued - TRACEPKT might be valid, but belongs to another cycle */ - trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len, - "IN"); - break; - case 0x3: - /* WAIT cycle - TRACEPKT is valid, but belongs to another cycle */ - trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len, - "WT"); - break; - case 0x4: - /* following a branch two APO cycles are output on PIPESTAT[1:0] - * but another BE/BD could overwrite the current branch, - * or a trigger could cause the APO to be output on TRACEPKT[1:0] - */ - if ((PIPESTAT(trace_data[i + 1]) == 0x4) - || (PIPESTAT(trace_data[i + 1]) == 0x5)) - { - /* another branch occured, we ignore this one */ - j = (j < i + 1) ? i + 1 : j; - break; - } - else if (PIPESTAT(trace_data[i + 1]) == 0x6) - { - apo = TRACEPKT(trace_data[i + 1]) & 0x3; - } - else - { - apo = PIPESTAT(trace_data[i + 1]) & 0x3; - } - - if ((PIPESTAT(trace_data[i + 2]) == 0x4) - || (PIPESTAT(trace_data[i + 2]) == 0x5)) - { - j = (j < i + 2) ? i + 1 : j; - i = i + 1; - break; - } - else if (PIPESTAT(trace_data[i + 2]) == 0x6) - { - apo |= (TRACEPKT(trace_data[i + 2]) & 0x3) << 2; - } - else - { - apo = (PIPESTAT(trace_data[i + 1]) & 0x3) << 2; - } - - branch_reason = -1; - k = 0; - do - { - if ((j = etmv1_next_packet(arm7_9->etb->RAM_depth, trace_data, j, &port_half, apo, &packet)) != -1) - { - address &= ~(0x7f << (k * 7)); - address |= (packet & 0x7f) << (k * 7); - } - else - { - break; - } - k++; - } while ((k < 5) && (packet & 0x80)); - - if (addressbits_valid < ((k * 7 > 32) ? 32 : k * 7)) - addressbits_valid = (k * 7 > 32) ? 32 : k * 7; - - if (k == 5) - { - branch_reason = (packet & 0x7) >> 4; - trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len, - "BE 0x%x (/%i) (%s)", address, addressbits_valid, etmv1_branch_reason_string[branch_reason]); - } - else - { - trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len, - "BE 0x%x (/%i)", address, addressbits_valid); - } - - break; - case 0x5: - trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len, - "BD"); - break; - case 0x6: - /* We catch the trigger event before we get here */ - ERROR("TR pipestat should have been caught earlier"); - trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len, - "--"); - break; - case 0x7: - /* TRACE disabled - TRACEPKT = invalid */ - trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len, - "TD"); - break; - } - - /* PIPESTAT other than WT (b011) and TD (b111) mean we executed an instruction */ - if ((PIPESTAT(trace_data[i]) & 0x3) != 0x3) - { - last_instruction = i; - address += 4; + 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; + + j += 1; } + } + + free(trace_data); + + return ERROR_OK; +} - /* The group of packets for a particular instruction cannot start on or before any - * previous functional PIPESTAT (IE, IN, ID, BE, or BD) - */ - if (j < last_instruction) - { - j = last_instruction + 1; - } +int etb_start_capture(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + u32 etb_ctrl_value = 0x1; - /* restore trigger PIPESTAT to ensure TRACEPKT is ignored */ - if (trigger == 1) + if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED) + { + if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT) { - trace_data[i] &= ~0x7; - trace_data[i] |= 0x6; + DEBUG("ETB can't run in demultiplexed mode with a 16-bit port"); + return ERROR_ETM_PORTMODE_NOT_SUPPORTED; } - - command_print(cmd_ctx, "%s (raw: 0x%8.8x)", trace_output, trace_data[i]); + etb_ctrl_value |= 0x2; } + if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED) + return ERROR_ETM_PORTMODE_NOT_SUPPORTED; + + etb_write_reg(&etb->reg_cache->reg_list[ETB_TRIGGER_COUNTER], 0x600); + etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER], 0x0); + etb_write_reg(&etb->reg_cache->reg_list[ETB_CTRL], etb_ctrl_value); + jtag_execute_queue(); + + /* we're starting a new trace, initialize capture status */ + etm_ctx->capture_status = TRACE_RUNNING; + + return ERROR_OK; +} + +int etb_stop_capture(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + reg_t *etb_ctrl_reg = &etb->reg_cache->reg_list[ETB_CTRL]; + + etb_write_reg(etb_ctrl_reg, 0x0); + jtag_execute_queue(); + + /* trace stopped, just clear running flag, but preserve others */ + etm_ctx->capture_status &= ~TRACE_RUNNING; + return ERROR_OK; } + +etm_capture_driver_t etb_capture_driver = +{ + .name = "etb", + .register_commands = etb_register_commands, + .init = etb_init, + .status = etb_status, + .start_capture = etb_start_capture, + .stop_capture = etb_stop_capture, + .read_trace = etb_read_trace, +}; diff --git a/src/target/etb.h b/src/target/etb.h index 12e613f..1a579cb 100644 --- a/src/target/etb.h +++ b/src/target/etb.h @@ -25,6 +25,9 @@ #include "register.h"
#include "arm_jtag.h"
+#include "etb.h"
+#include "etm.h"
+
/* ETB registers */
enum
{
@@ -41,13 +44,14 @@ enum typedef struct etb_s
{
+ etm_context_t *etm_ctx;
int chain_pos;
int cur_scan_chain;
reg_cache_t *reg_cache;
/* ETB parameters */
- int RAM_depth;
- int RAM_width;
+ int ram_depth;
+ int ram_width;
} etb_t;
typedef struct etb_reg_s
@@ -56,6 +60,8 @@ typedef struct etb_reg_s etb_t *etb;
} etb_reg_t;
+extern etm_capture_driver_t etb_capture_driver;
+
extern reg_cache_t* etb_build_reg_cache(etb_t *etb);
extern int etb_read_reg(reg_t *reg);
extern int etb_write_reg(reg_t *reg, u32 value);
@@ -64,6 +70,6 @@ extern int etb_store_reg(reg_t *reg); extern int etb_set_reg(reg_t *reg, u32 value);
extern int etb_set_reg_w_exec(reg_t *reg, u8 *buf);
-extern int etb_register_commands(struct command_context_s *cmd_ctx, command_t *arm7_9_cmd);
+extern int etb_register_commands(struct command_context_s *cmd_ctx);
#endif /* ETB_H */
diff --git a/src/target/etm.c b/src/target/etm.c index 016130d..02c3310 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -21,7 +21,10 @@ #include "config.h" #endif +#include <string.h> + #include "etm.h" +#include "etb.h" #include "armv4_5.h" #include "arm7_9_common.h" @@ -33,9 +36,14 @@ #include "target.h" #include "register.h" #include "jtag.h" +#include "fileio.h" #include <stdlib.h> +/* ETM register access functionality + * + */ + bitfield_desc_t etm_comms_ctrl_bitfield_desc[] = { {"R", 1}, @@ -204,13 +212,16 @@ int etm_set_reg_w_exec(reg_t *reg, u8 *buf); int etm_write_reg(reg_t *reg, u32 value); int etm_read_reg(reg_t *reg); -reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg) +command_t *etm_cmd = NULL; + +reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx) { reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t)); reg_t *reg_list = NULL; etm_reg_t *arch_info = NULL; int num_regs = sizeof(etm_reg_arch_info)/sizeof(int); int i; + u32 etm_ctrl_value; /* register a register arch-type for etm registers only once */ if (etm_reg_arch_type == -1) @@ -242,6 +253,44 @@ reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int ex arch_info[i].addr = etm_reg_arch_info[i]; arch_info[i].jtag_info = jtag_info; } + + /* initialize some ETM control register settings */ + etm_get_reg(®_list[ETM_CTRL]); + etm_ctrl_value = buf_get_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size); + + /* clear the ETM powerdown bit (0) */ + etm_ctrl_value &= ~0x1; + + /* configure port width (6:4), mode (17:16) and clocking (13) */ + etm_ctrl_value = (etm_ctrl_value & + ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK & ~ETM_PORT_CLOCK_MASK) + | etm_ctx->portmode; + + buf_set_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size, etm_ctrl_value); + etm_store_reg(®_list[ETM_CTRL]); + + /* the ETM might have an ETB connected */ + if (strcmp(etm_ctx->capture_driver->name, "etb") == 0) + { + etb_t *etb = etm_ctx->capture_driver_priv; + + if (!etb) + { + ERROR("etb selected as etm capture driver, but no ETB configured"); + return ERROR_OK; + } + + reg_cache->next = etb_build_reg_cache(etb); + + etb->reg_cache = reg_cache->next; + + if (etm_ctx->capture_driver->init(etm_ctx) != ERROR_OK) + { + ERROR("ETM capture driver initialization failed"); + exit(-1); + } + } + return reg_cache; } @@ -410,3 +459,638 @@ int etm_store_reg(reg_t *reg) return etm_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); } +/* ETM trace analysis functionality + * + */ +extern etm_capture_driver_t etb_capture_driver; + +etm_capture_driver_t *etm_capture_drivers[] = +{ + &etb_capture_driver, + NULL +}; + +char *etmv1v1_branch_reason_strings[] = +{ + "normal PC change", + "tracing enabled", + "trace restarted after overflow", + "exit from debug", + "periodic synchronization", + "reserved", + "reserved", + "reserved", +}; + +int etmv1_next_packet(etm_context_t *ctx, u8 *packet) +{ + + + return ERROR_OK; +} + +int etmv1_analyse_trace(etm_context_t *ctx) +{ + ctx->pipe_index = 0; + ctx->data_index = 0; + + while (ctx->pipe_index < ctx->trace_depth) + { + switch (ctx->trace_data[ctx->pipe_index].pipestat) + { + case STAT_IE: + case STAT_ID: + break; + case STAT_IN: + DEBUG("IN"); + break; + case STAT_WT: + DEBUG("WT"); + break; + case STAT_BE: + case STAT_BD: + break; + case STAT_TD: + /* TODO: in cycle accurate trace, we have to count cycles */ + DEBUG("TD"); + break; + } + } + + return ERROR_OK; +} + +int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etmv1_tracemode_t tracemode; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!arm7_9->etm_ctx) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + tracemode = arm7_9->etm_ctx->tracemode; + + if (argc == 3) + { + if (strcmp(args[0], "none") == 0) + { + tracemode = ETMV1_TRACE_NONE; + } + else if (strcmp(args[0], "data") == 0) + { + tracemode = ETMV1_TRACE_DATA; + } + else if (strcmp(args[0], "address") == 0) + { + tracemode = ETMV1_TRACE_ADDR; + } + else if (strcmp(args[0], "all") == 0) + { + tracemode = ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR; + } + else + { + command_print(cmd_ctx, "invalid option '%s'", args[0]); + return ERROR_OK; + } + + switch (strtol(args[1], NULL, 0)) + { + case 0: + tracemode |= ETMV1_CONTEXTID_NONE; + break; + case 8: + tracemode |= ETMV1_CONTEXTID_8; + break; + case 16: + tracemode |= ETMV1_CONTEXTID_16; + break; + case 32: + tracemode |= ETMV1_CONTEXTID_32; + break; + default: + command_print(cmd_ctx, "invalid option '%s'", args[1]); + return ERROR_OK; + } + + if (strcmp(args[2], "enable") == 0) + { + tracemode |= ETMV1_CYCLE_ACCURATE; + } + else if (strcmp(args[2], "disable") == 0) + { + tracemode |= 0; + } + else + { + command_print(cmd_ctx, "invalid option '%s'", args[2]); + return ERROR_OK; + } + } + else if (argc != 0) + { + command_print(cmd_ctx, "usage: configure trace mode <none|data|address|all> <context id bits> <enable|disable cycle accurate>"); + return ERROR_OK; + } + + command_print(cmd_ctx, "current tracemode configuration:"); + + switch (tracemode & ETMV1_TRACE_MASK) + { + case ETMV1_TRACE_NONE: + command_print(cmd_ctx, "data tracing: none"); + break; + case ETMV1_TRACE_DATA: + command_print(cmd_ctx, "data tracing: data only"); + break; + case ETMV1_TRACE_ADDR: + command_print(cmd_ctx, "data tracing: address only"); + break; + case ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR: + command_print(cmd_ctx, "data tracing: address and data"); + break; + } + + switch (tracemode & ETMV1_CONTEXTID_MASK) + { + case ETMV1_CONTEXTID_NONE: + command_print(cmd_ctx, "contextid tracing: none"); + break; + case ETMV1_CONTEXTID_8: + command_print(cmd_ctx, "contextid tracing: 8 bit"); + break; + case ETMV1_CONTEXTID_16: + command_print(cmd_ctx, "contextid tracing: 16 bit"); + break; + case ETMV1_CONTEXTID_32: + command_print(cmd_ctx, "contextid tracing: 32 bit"); + break; + } + + if (tracemode & ETMV1_CYCLE_ACCURATE) + { + command_print(cmd_ctx, "cycle-accurate tracing enabled"); + } + else + { + command_print(cmd_ctx, "cycle-accurate tracing disabled"); + } + + /* only update ETM_CTRL register if tracemode changed */ + if (arm7_9->etm_ctx->tracemode != tracemode) + { + reg_t *etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; + + etm_get_reg(etm_ctrl_reg); + + buf_set_u32(etm_ctrl_reg->value, 2, 2, tracemode & ETMV1_TRACE_MASK); + buf_set_u32(etm_ctrl_reg->value, 14, 2, (tracemode & ETMV1_CONTEXTID_MASK) >> 4); + buf_set_u32(etm_ctrl_reg->value, 12, 1, (tracemode & ETMV1_CYCLE_ACCURATE) >> 8); + + etm_store_reg(etm_ctrl_reg); + + arm7_9->etm_ctx->tracemode = tracemode; + + /* invalidate old trace data */ + arm7_9->etm_ctx->capture_status = TRACE_IDLE; + if (arm7_9->etm_ctx->trace_depth > 0) + { + free(arm7_9->etm_ctx->trace_data); + } + arm7_9->etm_ctx->trace_depth = 0; + } + + return ERROR_OK; +} + +int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_portmode_t portmode = 0x0; + etm_context_t *etm_ctx = malloc(sizeof(etm_context_t)); + int i; + + if (argc != 5) + { + ERROR("incomplete 'etm config <target> <port_width> <port_mode> <clocking> <capture_driver>' command"); + exit(-1); + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + switch (strtoul(args[1], NULL, 0)) + { + case 4: + portmode |= ETM_PORT_4BIT; + break; + case 8: + portmode |= ETM_PORT_8BIT; + break; + case 16: + portmode |= ETM_PORT_16BIT; + break; + default: + command_print(cmd_ctx, "unsupported ETM port width '%s', must be 4, 8 or 16", args[1]); + return ERROR_OK; + } + + if (strcmp("normal", args[2]) == 0) + { + portmode |= ETM_PORT_NORMAL; + } + else if (strcmp("multiplexed", args[2]) == 0) + { + portmode |= ETM_PORT_MUXED; + } + else if (strcmp("demultiplexed", args[2]) == 0) + { + portmode |= ETM_PORT_DEMUXED; + } + else + { + command_print(cmd_ctx, "unsupported ETM port mode '%s', must be 'normal', 'multiplexed' or 'demultiplexed'", args[2]); + return ERROR_OK; + } + + if (strcmp("half", args[3]) == 0) + { + portmode |= ETM_PORT_HALF_CLOCK; + } + else if (strcmp("full", args[3]) == 0) + { + portmode |= ETM_PORT_FULL_CLOCK; + } + else + { + command_print(cmd_ctx, "unsupported ETM port clocking '%s', must be 'full' or 'half'", args[3]); + return ERROR_OK; + } + + for (i=0; etm_capture_drivers[i]; i++) + { + if (strcmp(args[4], etm_capture_drivers[i]->name) == 0) + { + if (etm_capture_drivers[i]->register_commands(cmd_ctx) != ERROR_OK) + { + free(etm_ctx); + exit(-1); + } + + etm_ctx->capture_driver = etm_capture_drivers[i]; + + break; + } + } + + etm_ctx->trace_data = NULL; + etm_ctx->trace_depth = 0; + etm_ctx->portmode = portmode; + etm_ctx->tracemode = 0x0; + etm_ctx->core_state = ARMV4_5_STATE_ARM; + etm_ctx->pipe_index = 0; + etm_ctx->data_index = 0; + etm_ctx->current_pc = 0x0; + etm_ctx->pc_ok = 0; + etm_ctx->last_branch = 0x0; + etm_ctx->last_ptr = 0x0; + etm_ctx->context_id = 0x0; + + arm7_9->etm_ctx = etm_ctx; + + etm_register_user_commands(cmd_ctx); + + return ERROR_OK; +} + +int handle_etm_status_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + trace_status_t trace_status; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!arm7_9->etm_ctx) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + trace_status = arm7_9->etm_ctx->capture_driver->status(arm7_9->etm_ctx); + + if (trace_status == TRACE_IDLE) + { + command_print(cmd_ctx, "tracing is idle"); + } + else + { + static char *completed = " completed"; + static char *running = " is running"; + static char *overflowed = ", trace overflowed"; + static char *triggered = ", trace triggered"; + + command_print(cmd_ctx, "trace collection%s%s%s", + (trace_status & TRACE_RUNNING) ? running : completed, + (trace_status & TRACE_OVERFLOWED) ? overflowed : "", + (trace_status & TRACE_TRIGGERED) ? triggered : ""); + + if (arm7_9->etm_ctx->trace_depth > 0) + { + command_print(cmd_ctx, "%i frames of trace data read", arm7_9->etm_ctx->trace_depth); + } + } + + return ERROR_OK; +} + +int handle_etm_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + fileio_t file; + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + u32 size_written; + + if (argc != 1) + { + command_print(cmd_ctx, "usage: etm dump <file>"); + return ERROR_OK; + } + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if (etm_ctx->capture_driver->status == TRACE_IDLE) + { + command_print(cmd_ctx, "trace capture wasn't enabled, no trace data captured"); + return ERROR_OK; + } + + if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) + { + /* TODO: if on-the-fly capture is to be supported, this needs to be changed */ + command_print(cmd_ctx, "trace capture not completed"); + return ERROR_OK; + } + + /* read the trace data if it wasn't read already */ + if (etm_ctx->trace_depth == 0) + etm_ctx->capture_driver->read_trace(etm_ctx); + + if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) + { + command_print(cmd_ctx, "file open error: %s", file.error_str); + return ERROR_OK; + } + + //fileio_write(&file, etm_ctx->trace_depth * 4, (u8*)etm_ctx->trace_data, &size_written); + + fileio_close(&file); + + return ERROR_OK; +} + +int handle_etm_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + fileio_t file; + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + u32 size_read; + + if (argc != 1) + { + command_print(cmd_ctx, "usage: etm load <file>"); + return ERROR_OK; + } + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) + { + command_print(cmd_ctx, "trace capture running, stop first"); + return ERROR_OK; + } + + if (fileio_open(&file, args[0], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) + { + command_print(cmd_ctx, "file open error: %s", file.error_str); + return ERROR_OK; + } + + if (file.size % 4) + { + command_print(cmd_ctx, "size isn't a multiple of 4, no valid trace data"); + return ERROR_OK; + } + + if (etm_ctx->trace_depth > 0) + { + free(etm_ctx->trace_data); + } + + //fileio_read(&file, file.size, (u8*)etm_ctx->trace_data, &size_read); + etm_ctx->trace_depth = file.size / 4; + etm_ctx->capture_status = TRACE_COMPLETED; + + fileio_close(&file); + + return ERROR_OK; +} + +int handle_etm_start_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + reg_t *etm_ctrl_reg; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + /* invalidate old tracing data */ + arm7_9->etm_ctx->capture_status = TRACE_IDLE; + if (arm7_9->etm_ctx->trace_depth > 0) + { + free(arm7_9->etm_ctx->trace_data); + } + arm7_9->etm_ctx->trace_depth = 0; + + etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; + etm_get_reg(etm_ctrl_reg); + + /* Clear programming bit (10), set port selection bit (11) */ + buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x2); + + etm_store_reg(etm_ctrl_reg); + jtag_execute_queue(); + + etm_ctx->capture_driver->start_capture(etm_ctx); + + return ERROR_OK; +} + +int handle_etm_stop_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + reg_t *etm_ctrl_reg; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; + etm_get_reg(etm_ctrl_reg); + + /* Set programming bit (10), clear port selection bit (11) */ + buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x1); + + etm_store_reg(etm_ctrl_reg); + jtag_execute_queue(); + + etm_ctx->capture_driver->stop_capture(etm_ctx); + + return ERROR_OK; +} + +int handle_etm_analyse_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + etmv1_analyse_trace(etm_ctx); + + return ERROR_OK; +} + +int etm_register_commands(struct command_context_s *cmd_ctx) +{ + etm_cmd = register_command(cmd_ctx, NULL, "etm", NULL, COMMAND_ANY, "Embedded Trace Macrocell"); + + register_command(cmd_ctx, etm_cmd, "config", handle_etm_config_command, COMMAND_CONFIG, NULL); + + return ERROR_OK; +} + +int etm_register_user_commands(struct command_context_s *cmd_ctx) +{ + register_command(cmd_ctx, etm_cmd, "tracemode", handle_etm_tracemode_command, + COMMAND_EXEC, "configure trace mode <none|data|address|all> <context id bits> <enable|disable cycle accurate>"); + + register_command(cmd_ctx, etm_cmd, "status", handle_etm_status_command, + COMMAND_EXEC, "display current target's ETM status"); + register_command(cmd_ctx, etm_cmd, "start", handle_etm_start_command, + COMMAND_EXEC, "start ETM trace collection"); + register_command(cmd_ctx, etm_cmd, "stop", handle_etm_stop_command, + COMMAND_EXEC, "stop ETM trace collection"); + + register_command(cmd_ctx, etm_cmd, "analyze", handle_etm_stop_command, + COMMAND_EXEC, "anaylze collected ETM trace"); + + register_command(cmd_ctx, etm_cmd, "dump", handle_etm_dump_command, + COMMAND_EXEC, "dump captured trace data <file>"); + register_command(cmd_ctx, etm_cmd, "load", handle_etm_load_command, + COMMAND_EXEC, "load trace data for analysis <file>"); + + return ERROR_OK; +} diff --git a/src/target/etm.h b/src/target/etm.h index 4b24e5c..5959178 100644 --- a/src/target/etm.h +++ b/src/target/etm.h @@ -1,7 +1,10 @@ /***************************************************************************
- * Copyright (C) 2005 by Dominic Rath *
+ * Copyright (C) 2005, 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
+ * Copyright (C) 2007 by Vincent Palatin *
+ * vincent.palatin_openocd@m4x.org *
+ * *
* 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 *
@@ -20,11 +23,14 @@ #ifndef ETM_H
#define ETM_H
+#include "trace.h"
#include "target.h"
#include "register.h"
#include "arm_jtag.h"
-// ETM registers (V1.2 protocol)
+#include "armv4_5.h"
+
+/* ETM registers (V1.3 protocol) */
enum
{
ETM_CTRL = 0x00,
@@ -58,14 +64,123 @@ enum ETM_CONTEXTID_COMPARATOR_MASK = 0x6f,
};
-
typedef struct etm_reg_s
{
int addr;
arm_jtag_t *jtag_info;
} etm_reg_t;
-extern reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg);
+typedef enum
+{
+ /* Port width */
+ ETM_PORT_4BIT = 0x00,
+ ETM_PORT_8BIT = 0x10,
+ ETM_PORT_16BIT = 0x20,
+ ETM_PORT_WIDTH_MASK = 0x70,
+ /* Port modes */
+ ETM_PORT_NORMAL = 0x00000,
+ ETM_PORT_MUXED = 0x10000,
+ ETM_PORT_DEMUXED = 0x20000,
+ ETM_PORT_MODE_MASK = 0x30000,
+ /* Clocking modes */
+ ETM_PORT_FULL_CLOCK = 0x0000,
+ ETM_PORT_HALF_CLOCK = 0x1000,
+ ETM_PORT_CLOCK_MASK = 0x1000,
+} etm_portmode_t;
+
+typedef enum
+{
+ /* Data trace */
+ ETMV1_TRACE_NONE = 0x00,
+ ETMV1_TRACE_DATA = 0x01,
+ ETMV1_TRACE_ADDR = 0x02,
+ ETMV1_TRACE_MASK = 0x03,
+ /* ContextID */
+ ETMV1_CONTEXTID_NONE = 0x00,
+ ETMV1_CONTEXTID_8 = 0x10,
+ ETMV1_CONTEXTID_16 = 0x20,
+ ETMV1_CONTEXTID_32 = 0x30,
+ ETMV1_CONTEXTID_MASK = 0x30,
+ /* Misc */
+ ETMV1_CYCLE_ACCURATE = 0x100
+} etmv1_tracemode_t;
+
+/* forward-declare ETM context */
+struct etm_context_s;
+
+typedef struct etm_capture_driver_s
+{
+ char *name;
+ int (*register_commands)(struct command_context_s *cmd_ctx);
+ int (*init)(struct etm_context_s *etm_ctx);
+ trace_status_t (*status)(struct etm_context_s *etm_ctx);
+ int (*read_trace)(struct etm_context_s *etm_ctx);
+ int (*start_capture)(struct etm_context_s *etm_ctx);
+ int (*stop_capture)(struct etm_context_s *etm_ctx);
+} etm_capture_driver_t;
+
+typedef struct etmv1_trace_data_s
+{
+ u8 pipestat; /* pipeline cycle this packet belongs to */
+ u16 packet; /* packet data (4, 8 or 16 bit) */
+ int tracesync; /* 1 if tracesync was set on this packet */
+} etmv1_trace_data_t;
+
+/* describe a trace context
+ * if support for ETMv2 or ETMv3 is to be implemented,
+ * this will have to be split into version independent elements
+ * and a version specific part
+ */
+typedef struct etm_context_s
+{
+ reg_cache_t *reg_cache; /* ETM register cache */
+ etm_capture_driver_t *capture_driver; /* driver used to access ETM data */
+ void *capture_driver_priv; /* capture driver private data */
+ trace_status_t capture_status; /* current state of capture run */
+ etmv1_trace_data_t *trace_data; /* trace data */
+ u32 trace_depth; /* number of trace cycles to be analyzed, 0 if no trace data available */
+ etm_portmode_t portmode; /* normal, multiplexed or demultiplexed */
+ etmv1_tracemode_t tracemode; /* type of information the trace contains (data, addres, contextID, ...) */
+ armv4_5_state_t core_state; /* current core state (ARM, Thumb, Jazelle) */
+// trace_image_provider_t image_provider; /* source for target opcodes */
+ u32 pipe_index; /* current trace cycle */
+ u32 data_index; /* cycle holding next data packet */
+ u32 current_pc; /* current program counter */
+ u32 pc_ok; /* full PC has been acquired */
+ u32 last_branch; /* last branch address output */
+ u32 last_ptr; /* address of the last data access */
+ u32 context_id; /* context ID of the code being traced */
+} etm_context_t;
+
+/* PIPESTAT values */
+typedef enum
+{
+ STAT_IE = 0x0,
+ STAT_ID = 0x1,
+ STAT_IN = 0x2,
+ STAT_WT = 0x3,
+ STAT_BE = 0x4,
+ STAT_BD = 0x5,
+ STAT_TR = 0x6,
+ STAT_TD = 0x7
+} etmv1_pipestat_t;
+
+/* branch reason values */
+typedef enum
+{
+ BR_NORMAL = 0x0, /* Normal PC change : periodic synchro (ETMv1.1) */
+ BR_ENABLE = 0x1, /* Trace has been enabled */
+ BR_RESTART = 0x2, /* Trace restarted after a FIFO overflow */
+ BR_NODEBUG = 0x3, /* ARM has exited for debug state */
+ BR_PERIOD = 0x4, /* Peridioc synchronization point (ETM>=v1.2)*/
+ BR_RSVD5 = 0x5, /* reserved */
+ BR_RSVD6 = 0x6, /* reserved */
+ BR_RSVD7 = 0x7, /* reserved */
+} etmv1_branch_reason_t;
+
+extern char *etmv1v1_branch_reason_strings[];
+
+extern reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx);
extern int etm_read_reg(reg_t *reg);
extern int etm_write_reg(reg_t *reg, u32 value);
extern int etm_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask);
@@ -73,4 +188,12 @@ extern int etm_store_reg(reg_t *reg); extern int etm_set_reg(reg_t *reg, u32 value);
extern int etm_set_reg_w_exec(reg_t *reg, u8 *buf);
+int etm_register_commands(struct command_context_s *cmd_ctx);
+int etm_register_user_commands(struct command_context_s *cmd_ctx);
+extern etm_context_t* etm_create_context(etm_portmode_t portmode, char *capture_driver_name);
+
+#define ERROR_ETM_INVALID_DRIVER (-1300)
+#define ERROR_ETM_PORTMODE_NOT_SUPPORTED (-1301)
+#define ERROR_ETM_CAPTURE_INIT_FAILED (-1302)
+
#endif /* ETM_H */
diff --git a/src/target/target.c b/src/target/target.c index 050a523..e980ae4 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -43,6 +43,7 @@ #include <time_support.h> #include <fileio.h> +#include <image.h> int cli_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv); @@ -1656,12 +1657,9 @@ int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char u32 address; u8 *buffer; u32 buf_cnt; - u32 binary_size; - - fileio_t file; - enum fileio_pri_type pri_type = FILEIO_IMAGE; - fileio_image_t image_info; - enum fileio_sec_type sec_type; + u32 image_size; + + image_t image; duration_t duration; char *duration_text; @@ -1674,40 +1672,41 @@ int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char return ERROR_OK; } - memset(&file, 0, sizeof(fileio_t)); - fileio_identify_image_type(&sec_type, (argc == 3) ? args[2] : NULL); + identify_image_type(&image.type, (argc == 3) ? args[2] : NULL); - image_info.base_address = strtoul(args[1], NULL, 0); - image_info.has_start_address = 0; + image.base_address_set = 1; + image.base_address = strtoul(args[1], NULL, 0); + + image.start_address_set = 0; buffer = malloc(128 * 1024); duration_start_measure(&duration); - if (fileio_open(&file, args[0], FILEIO_READ, - pri_type, &image_info, sec_type) != ERROR_OK) + if (image_open(&image, args[0], FILEIO_READ) != ERROR_OK) { - command_print(cmd_ctx, "load_image error: %s", file.error_str); + command_print(cmd_ctx, "load_image error: %s", image.error_str); return ERROR_OK; } - binary_size = file.size; - address = image_info.base_address; - while ((binary_size > 0) && - (fileio_read(&file, 128 * 1024, buffer, &buf_cnt) == ERROR_OK)) + image_size = image.size; + address = image.base_address; + + while ((image_size > 0) && + (image_read(&image, 128 * 1024, buffer, &buf_cnt) == ERROR_OK)) { target_write_buffer(target, address, buf_cnt, buffer); address += buf_cnt; - binary_size -= buf_cnt; + image_size -= buf_cnt; } free(buffer); duration_stop_measure(&duration, &duration_text); - command_print(cmd_ctx, "downloaded %lli byte in %s", file.size, duration_text); + command_print(cmd_ctx, "downloaded %u byte in %s", image.size, duration_text); free(duration_text); - fileio_close(&file); + image_close(&image); return ERROR_OK; @@ -1715,8 +1714,7 @@ int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) { - fileio_t file; - fileio_image_t image_info; + fileio_t fileio; u32 address; u32 size; @@ -1742,13 +1740,9 @@ int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char return ERROR_OK; } - image_info.base_address = address; - image_info.has_start_address = 0; - - if (fileio_open(&file, args[0], FILEIO_WRITE, - FILEIO_IMAGE, &image_info, FILEIO_PLAIN) != ERROR_OK) + if (fileio_open(&fileio, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) { - command_print(cmd_ctx, "dump_image error: %s", file.error_str); + command_print(cmd_ctx, "dump_image error: %s", fileio.error_str); return ERROR_OK; } @@ -1760,16 +1754,16 @@ int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char u32 this_run_size = (size > 560) ? 560 : size; target->type->read_memory(target, address, 4, this_run_size / 4, buffer); - fileio_write(&file, this_run_size, buffer, &size_written); + fileio_write(&fileio, this_run_size, buffer, &size_written); size -= this_run_size; address += this_run_size; } - fileio_close(&file); + fileio_close(&fileio); duration_stop_measure(&duration, &duration_text); - command_print(cmd_ctx, "dumped %lli byte in %s", file.size, duration_text); + command_print(cmd_ctx, "dumped %lli byte in %s", fileio.size, duration_text); free(duration_text); return ERROR_OK; diff --git a/src/target/xscale/debug_handler.bin b/src/target/xscale/debug_handler.bin Binary files differnew file mode 100755 index 0000000..2dde185 --- /dev/null +++ b/src/target/xscale/debug_handler.bin |