aboutsummaryrefslogtreecommitdiff
path: root/src/target
diff options
context:
space:
mode:
Diffstat (limited to 'src/target')
-rw-r--r--src/target/Makefile.am7
-rw-r--r--src/target/algorithm.c54
-rw-r--r--src/target/algorithm.h53
-rw-r--r--src/target/arm720t.c625
-rw-r--r--src/target/arm720t.h43
-rw-r--r--src/target/arm7_9_common.c2339
-rw-r--r--src/target/arm7_9_common.h129
-rw-r--r--src/target/arm7tdmi.c780
-rw-r--r--src/target/arm7tdmi.h46
-rw-r--r--src/target/arm920t.c967
-rw-r--r--src/target/arm920t.h45
-rw-r--r--src/target/arm9tdmi.c848
-rw-r--r--src/target/arm9tdmi.h51
-rw-r--r--src/target/arm_jtag.c116
-rw-r--r--src/target/arm_jtag.h42
-rw-r--r--src/target/armv4_5.c583
-rw-r--r--src/target/armv4_5.h237
-rw-r--r--src/target/armv4_5_cache.c112
-rw-r--r--src/target/armv4_5_cache.h49
-rw-r--r--src/target/armv4_5_mmu.c358
-rw-r--r--src/target/armv4_5_mmu.h52
-rw-r--r--src/target/breakpoints.c219
-rw-r--r--src/target/breakpoints.h70
-rw-r--r--src/target/embeddedice.c301
-rw-r--r--src/target/embeddedice.h90
-rw-r--r--src/target/etm.c409
-rw-r--r--src/target/etm.h76
-rw-r--r--src/target/register.c100
-rw-r--r--src/target/register.h69
-rw-r--r--src/target/target.c1701
-rw-r--r--src/target/target.h231
31 files changed, 10802 insertions, 0 deletions
diff --git a/src/target/Makefile.am b/src/target/Makefile.am
new file mode 100644
index 00000000..7e26762b
--- /dev/null
+++ b/src/target/Makefile.am
@@ -0,0 +1,7 @@
+INCLUDES = -I$(top_srcdir)/src/gdb -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/jtag -I$(top_srcdir)/src/xsvf $(all_includes)
+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
+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
diff --git a/src/target/algorithm.c b/src/target/algorithm.c
new file mode 100644
index 00000000..fdebfc58
--- /dev/null
+++ b/src/target/algorithm.c
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "config.h"
+#include "algorithm.h"
+
+#include "log.h"
+#include "configuration.h"
+#include "binarybuffer.h"
+
+#include <stdlib.h>
+
+
+void init_mem_param(mem_param_t *param, u32 address, u32 size, enum param_direction direction)
+{
+ param->address = address;
+ param->size = size;
+ param->value = malloc(size);
+ param->direction = direction;
+}
+
+void destroy_mem_param(mem_param_t *param)
+{
+ free(param->value);
+}
+
+void init_reg_param(reg_param_t *param, char *reg_name, u32 size, enum param_direction direction)
+{
+ param->reg_name = reg_name;
+ param->size = size;
+ param->value = malloc(CEIL(size, 8));
+ param->direction = direction;
+}
+
+void destroy_reg_param(reg_param_t *param)
+{
+ free(param->value);
+}
diff --git a/src/target/algorithm.h b/src/target/algorithm.h
new file mode 100644
index 00000000..e248ba5a
--- /dev/null
+++ b/src/target/algorithm.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef ALGORITHM_H
+#define ALGORITHM_H
+
+#include "types.h"
+
+enum param_direction
+{
+ PARAM_IN,
+ PARAM_OUT,
+ PARAM_IN_OUT
+};
+
+typedef struct mem_param_s
+{
+ u32 address;
+ u32 size;
+ u8 *value;
+ enum param_direction direction;
+} mem_param_t;
+
+typedef struct reg_param_s
+{
+ char *reg_name;
+ u32 size;
+ u8 *value;
+ enum param_direction direction;
+} reg_param_t;
+
+extern void init_mem_param(mem_param_t *param, u32 address, u32 size, enum param_direction direction);
+extern void destroy_mem_param(mem_param_t *param);
+extern void init_reg_param(reg_param_t *param, char *reg_name, u32 size, enum param_direction direction);
+extern void destroy_reg_param(reg_param_t *param);
+
+#endif /* ALGORITHM_H */
diff --git a/src/target/arm720t.c b/src/target/arm720t.c
new file mode 100644
index 00000000..68ea3d1c
--- /dev/null
+++ b/src/target/arm720t.c
@@ -0,0 +1,625 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "config.h"
+
+#include "arm720t.h"
+#include "jtag.h"
+#include "log.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#if 1
+#define _DEBUG_INSTRUCTION_EXECUTION_
+#endif
+
+/* cli handling */
+int arm720t_register_commands(struct command_context_s *cmd_ctx);
+
+int arm720t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int arm720t_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int arm720t_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int arm720t_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+/* forward declarations */
+int arm720t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
+int arm720t_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
+int arm720t_quit();
+int arm720t_arch_state(struct target_s *target, char *buf, int buf_size);
+int arm720t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
+int arm720t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
+int arm720t_soft_reset_halt(struct target_s *target);
+
+target_type_t arm720t_target =
+{
+ .name = "arm720t",
+
+ .poll = arm7_9_poll,
+ .arch_state = arm720t_arch_state,
+
+ .halt = arm7_9_halt,
+ .resume = arm7_9_resume,
+ .step = arm7_9_step,
+
+ .assert_reset = arm7_9_assert_reset,
+ .deassert_reset = arm7_9_deassert_reset,
+ .soft_reset_halt = arm720t_soft_reset_halt,
+
+ .get_gdb_reg_list = armv4_5_get_gdb_reg_list,
+
+ .read_memory = arm720t_read_memory,
+ .write_memory = arm720t_write_memory,
+ .bulk_write_memory = arm7_9_bulk_write_memory,
+
+ .run_algorithm = armv4_5_run_algorithm,
+
+ .add_breakpoint = arm7_9_add_breakpoint,
+ .remove_breakpoint = arm7_9_remove_breakpoint,
+ .add_watchpoint = arm7_9_add_watchpoint,
+ .remove_watchpoint = arm7_9_remove_watchpoint,
+
+ .register_commands = arm720t_register_commands,
+ .target_command = arm720t_target_command,
+ .init_target = arm720t_init_target,
+ .quit = arm720t_quit
+};
+
+int arm720t_scan_cp15(target_t *target, u32 out, u32 *in, int instruction, int clock)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+ scan_field_t fields[2];
+ u8 out_buf[4];
+ u8 instruction_buf = instruction;
+
+ out = flip_u32(out, 32);
+ buf_set_u32(out_buf, 0, 32, out);
+
+ jtag_add_end_state(TAP_PD);
+ arm_jtag_scann(jtag_info, 0xf);
+ arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
+
+ fields[0].device = jtag_info->chain_pos;
+ fields[0].num_bits = 1;
+ fields[0].out_value = &instruction_buf;
+ 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 = jtag_info->chain_pos;
+ fields[1].num_bits = 32;
+ fields[1].out_value = out_buf;
+ fields[1].out_mask = NULL;
+ if (in)
+ {
+ fields[1].in_value = (u8*)in;
+ fields[1].in_handler = arm_jtag_buf_to_u32_flip;
+ fields[1].in_handler_priv = in;
+ } else
+ {
+ fields[1].in_value = NULL;
+ fields[1].in_handler = NULL;
+ fields[1].in_handler_priv = NULL;
+ }
+ fields[1].in_check_value = NULL;
+ fields[1].in_check_mask = NULL;
+
+ jtag_add_dr_scan(2, fields, -1);
+
+ if (clock)
+ jtag_add_runtest(0, -1);
+
+#ifdef _DEBUG_INSTRUCTION_EXECUTION_
+ jtag_execute_queue();
+
+ if (in)
+ DEBUG("out: %8.8x, in: %8.8x, instruction: %i, clock: %i", out, *in, instruction, clock);
+ else
+ DEBUG("out: %8.8x, instruction: %i, clock: %i", out, instruction, clock);
+#else
+ DEBUG("out: %8.8x, instruction: %i, clock: %i", in, out, instruction, clock);
+#endif
+
+ return ERROR_OK;
+}
+
+int arm720t_read_cp15(target_t *target, u32 opcode, u32 *value)
+{
+ /* fetch CP15 opcode */
+ arm720t_scan_cp15(target, opcode, NULL, 1, 1);
+ /* "DECODE" stage */
+ arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1);
+ /* "EXECUTE" stage (1) */
+ arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0);
+ arm720t_scan_cp15(target, 0x0, NULL, 0, 1);
+ /* "EXECUTE" stage (2) */
+ arm720t_scan_cp15(target, 0x0, NULL, 0, 1);
+ /* "EXECUTE" stage (3), CDATA is read */
+ arm720t_scan_cp15(target, ARMV4_5_NOP, value, 1, 1);
+
+ return ERROR_OK;
+}
+
+int arm720t_write_cp15(target_t *target, u32 opcode, u32 value)
+{
+ /* fetch CP15 opcode */
+ arm720t_scan_cp15(target, opcode, NULL, 1, 1);
+ /* "DECODE" stage */
+ arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1);
+ /* "EXECUTE" stage (1) */
+ arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0);
+ arm720t_scan_cp15(target, 0x0, NULL, 0, 1);
+ /* "EXECUTE" stage (2) */
+ arm720t_scan_cp15(target, value, NULL, 0, 1);
+ arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1);
+
+ return ERROR_OK;
+}
+
+u32 arm720t_get_ttb(target_t *target)
+{
+ u32 ttb = 0x0;
+
+ arm720t_read_cp15(target, 0xee120f10, &ttb);
+ jtag_execute_queue();
+
+ ttb &= 0xffffc000;
+
+ return ttb;
+}
+
+void arm720t_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
+{
+ u32 cp15_control;
+
+ /* read cp15 control register */
+ arm720t_read_cp15(target, 0xee110f10, &cp15_control);
+ jtag_execute_queue();
+
+ if (mmu)
+ cp15_control &= ~0x1U;
+
+ if (d_u_cache || i_cache)
+ cp15_control &= ~0x4U;
+
+ arm720t_write_cp15(target, 0xee010f10, cp15_control);
+}
+
+void arm720t_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
+{
+ u32 cp15_control;
+
+ /* read cp15 control register */
+ arm720t_read_cp15(target, 0xee110f10, &cp15_control);
+ jtag_execute_queue();
+
+ if (mmu)
+ cp15_control |= 0x1U;
+
+ if (d_u_cache || i_cache)
+ cp15_control |= 0x4U;
+
+ arm720t_write_cp15(target, 0xee010f10, cp15_control);
+}
+
+void arm720t_post_debug_entry(target_t *target)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
+ arm720t_common_t *arm720t = arm7tdmi->arch_info;
+
+ /* examine cp15 control reg */
+ arm720t_read_cp15(target, 0xee110f10, &arm720t->cp15_control_reg);
+ jtag_execute_queue();
+ DEBUG("cp15_control_reg: %8.8x", arm720t->cp15_control_reg);
+
+ arm720t->armv4_5_mmu.mmu_enabled = (arm720t->cp15_control_reg & 0x1U) ? 1 : 0;
+ arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm720t->cp15_control_reg & 0x4U) ? 1 : 0;
+ arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
+
+ /* save i/d fault status and address register */
+ arm720t_read_cp15(target, 0xee150f10, &arm720t->fsr);
+ arm720t_read_cp15(target, 0xee160f10, &arm720t->far);
+ jtag_execute_queue();
+}
+
+void arm720t_pre_restore_context(target_t *target)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
+ arm720t_common_t *arm720t = arm7tdmi->arch_info;
+
+ /* restore i/d fault status and address register */
+ arm720t_write_cp15(target, 0xee050f10, arm720t->fsr);
+ arm720t_write_cp15(target, 0xee060f10, arm720t->far);
+}
+
+int arm720t_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm7tdmi_common_t **arm7tdmi_p, arm720t_common_t **arm720t_p)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9;
+ arm7tdmi_common_t *arm7tdmi;
+ arm720t_common_t *arm720t;
+
+ if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
+ {
+ return -1;
+ }
+
+ arm7_9 = armv4_5->arch_info;
+ if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC)
+ {
+ return -1;
+ }
+
+ arm7tdmi = arm7_9->arch_info;
+ if (arm7tdmi->common_magic != ARM7TDMI_COMMON_MAGIC)
+ {
+ return -1;
+ }
+
+ arm720t = arm7tdmi->arch_info;
+ if (arm720t->common_magic != ARM720T_COMMON_MAGIC)
+ {
+ return -1;
+ }
+
+ *armv4_5_p = armv4_5;
+ *arm7_9_p = arm7_9;
+ *arm7tdmi_p = arm7tdmi;
+ *arm720t_p = arm720t;
+
+ return ERROR_OK;
+}
+
+int arm720t_arch_state(struct target_s *target, char *buf, int buf_size)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
+ arm720t_common_t *arm720t = arm7tdmi->arch_info;
+
+ char *state[] =
+ {
+ "disabled", "enabled"
+ };
+
+ if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
+ {
+ ERROR("BUG: called for a non-ARMv4/5 target");
+ exit(-1);
+ }
+
+ snprintf(buf, buf_size,
+ "target halted in %s state due to %s, current mode: %s\n"
+ "cpsr: 0x%8.8x pc: 0x%8.8x\n"
+ "MMU: %s, Cache: %s",
+ armv4_5_state_strings[armv4_5->core_state],
+ target_debug_reason_strings[target->debug_reason],
+ armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)],
+ buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
+ buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32),
+ state[arm720t->armv4_5_mmu.mmu_enabled],
+ state[arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled]);
+
+ return ERROR_OK;
+}
+
+int arm720t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
+{
+ int retval;
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
+ arm720t_common_t *arm720t = arm7tdmi->arch_info;
+
+ /* disable cache, but leave MMU enabled */
+ if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)
+ arm720t_disable_mmu_caches(target, 0, 1, 0);
+
+ retval = arm7_9_read_memory(target, address, size, count, buffer);
+
+ if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)
+ arm720t_enable_mmu_caches(target, 0, 1, 0);
+
+ return retval;
+}
+
+int arm720t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
+{
+ int retval;
+
+ if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK)
+ return retval;
+
+ return retval;
+}
+
+int arm720t_soft_reset_halt(struct target_s *target)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
+ arm720t_common_t *arm720t = arm7tdmi->arch_info;
+ reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
+
+ if (target->state == TARGET_RUNNING)
+ {
+ target->type->halt(target);
+ }
+
+ while (buf_get_u32(dbg_stat->value, EICE_DBG_CONTROL_DBGACK, 1) == 0)
+ {
+ embeddedice_read_reg(dbg_stat);
+ jtag_execute_queue();
+ }
+
+ target->state = TARGET_HALTED;
+
+ /* SVC, ARM state, IRQ and FIQ disabled */
+ buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3);
+ armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
+ armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
+
+ /* start fetching from 0x0 */
+ buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0);
+ armv4_5->core_cache->reg_list[15].dirty = 1;
+ armv4_5->core_cache->reg_list[15].valid = 1;
+
+ armv4_5->core_mode = ARMV4_5_MODE_SVC;
+ armv4_5->core_state = ARMV4_5_STATE_ARM;
+
+ arm720t_disable_mmu_caches(target, 1, 1, 1);
+ arm720t->armv4_5_mmu.mmu_enabled = 0;
+ arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0;
+ arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
+
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+
+ return ERROR_OK;
+}
+
+int arm720t_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
+{
+ arm7tdmi_init_target(cmd_ctx, target);
+
+ return ERROR_OK;
+
+}
+
+int arm720t_quit()
+{
+
+ return ERROR_OK;
+}
+
+int arm720t_init_arch_info(target_t *target, arm720t_common_t *arm720t, int chain_pos, char *variant)
+{
+ arm7tdmi_common_t *arm7tdmi = &arm720t->arm7tdmi_common;
+ arm7_9_common_t *arm7_9 = &arm7tdmi->arm7_9_common;
+
+ arm7tdmi_init_arch_info(target, arm7tdmi, chain_pos, variant);
+
+ arm7tdmi->arch_info = arm720t;
+ arm720t->common_magic = ARM720T_COMMON_MAGIC;
+
+ arm7_9->post_debug_entry = arm720t_post_debug_entry;
+ arm7_9->pre_restore_context = arm720t_pre_restore_context;
+
+ arm720t->armv4_5_mmu.armv4_5_cache.ctype = -1;
+ arm720t->armv4_5_mmu.get_ttb = arm720t_get_ttb;
+ arm720t->armv4_5_mmu.read_memory = arm7_9_read_memory;
+ arm720t->armv4_5_mmu.write_memory = arm7_9_write_memory;
+ arm720t->armv4_5_mmu.disable_mmu_caches = arm720t_disable_mmu_caches;
+ arm720t->armv4_5_mmu.enable_mmu_caches = arm720t_enable_mmu_caches;
+ arm720t->armv4_5_mmu.has_tiny_pages = 0;
+ arm720t->armv4_5_mmu.mmu_enabled = 0;
+
+ return ERROR_OK;
+}
+
+int arm720t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
+{
+ int chain_pos;
+ char *variant = NULL;
+ arm720t_common_t *arm720t = malloc(sizeof(arm720t_common_t));
+
+ if (argc < 4)
+ {
+ ERROR("'target arm720t' requires at least one additional argument");
+ exit(-1);
+ }
+
+ chain_pos = strtoul(args[3], NULL, 0);
+
+ if (argc >= 5)
+ variant = strdup(args[4]);
+
+ DEBUG("chain_pos: %i, variant: %s", chain_pos, variant);
+
+ arm720t_init_arch_info(target, arm720t, chain_pos, variant);
+
+ return ERROR_OK;
+}
+
+int arm720t_register_commands(struct command_context_s *cmd_ctx)
+{
+ int retval;
+ command_t *arm720t_cmd;
+
+
+ retval = arm7tdmi_register_commands(cmd_ctx);
+
+ arm720t_cmd = register_command(cmd_ctx, NULL, "arm720t", NULL, COMMAND_ANY, NULL);
+
+ register_command(cmd_ctx, arm720t_cmd, "cp15", arm720t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register <opcode> [value]");
+ register_command(cmd_ctx, arm720t_cmd, "virt2phys", arm720t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa <va>");
+
+ register_command(cmd_ctx, arm720t_cmd, "mdw_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory words <physical addr> [count]");
+ register_command(cmd_ctx, arm720t_cmd, "mdh_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words <physical addr> [count]");
+ register_command(cmd_ctx, arm720t_cmd, "mdb_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes <physical addr> [count]");
+
+ register_command(cmd_ctx, arm720t_cmd, "mww_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory word <physical addr> <value>");
+ register_command(cmd_ctx, arm720t_cmd, "mwh_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word <physical addr> <value>");
+ register_command(cmd_ctx, arm720t_cmd, "mwb_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte <physical addr> <value>");
+
+ return ERROR_OK;
+}
+
+int arm720t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ int retval;
+ target_t *target = get_current_target(cmd_ctx);
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ arm7tdmi_common_t *arm7tdmi;
+ arm720t_common_t *arm720t;
+ arm_jtag_t *jtag_info;
+
+ if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM720t target");
+ return ERROR_OK;
+ }
+
+ jtag_info = &arm7_9->jtag_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+ return ERROR_OK;
+ }
+
+ /* one or more argument, access a single register (write if second argument is given */
+ if (argc >= 1)
+ {
+ u32 opcode = strtoul(args[0], NULL, 0);
+
+ if (argc == 1)
+ {
+ u32 value;
+ if ((retval = arm720t_read_cp15(target, opcode, &value)) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "couldn't access cp15 with opcode 0x%8.8x", opcode);
+ return ERROR_OK;
+ }
+ jtag_execute_queue();
+
+ command_print(cmd_ctx, "0x%8.8x: 0x%8.8x", opcode, value);
+ }
+ else if (argc == 2)
+ {
+ u32 value = strtoul(args[1], NULL, 0);
+ if ((retval = arm720t_write_cp15(target, opcode, value)) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "couldn't access cp15 with opcode 0x%8.8x", opcode);
+ return ERROR_OK;
+ }
+ command_print(cmd_ctx, "0x%8.8x: 0x%8.8x", opcode, value);
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int arm720t_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = get_current_target(cmd_ctx);
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ arm7tdmi_common_t *arm7tdmi;
+ arm720t_common_t *arm720t;
+ arm_jtag_t *jtag_info;
+
+ if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM720t target");
+ return ERROR_OK;
+ }
+
+ jtag_info = &arm7_9->jtag_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+ return ERROR_OK;
+ }
+
+ return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu);
+}
+
+int arm720t_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = get_current_target(cmd_ctx);
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ arm7tdmi_common_t *arm7tdmi;
+ arm720t_common_t *arm720t;
+ arm_jtag_t *jtag_info;
+
+ if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM720t target");
+ return ERROR_OK;
+ }
+
+ jtag_info = &arm7_9->jtag_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+ return ERROR_OK;
+ }
+
+ return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu);
+}
+
+int arm720t_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = get_current_target(cmd_ctx);
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ arm7tdmi_common_t *arm7tdmi;
+ arm720t_common_t *arm720t;
+ arm_jtag_t *jtag_info;
+
+ if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM720t target");
+ return ERROR_OK;
+ }
+
+ jtag_info = &arm7_9->jtag_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+ return ERROR_OK;
+ }
+
+ return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu);
+}
+
diff --git a/src/target/arm720t.h b/src/target/arm720t.h
new file mode 100644
index 00000000..2479b548
--- /dev/null
+++ b/src/target/arm720t.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef ARM720T_H
+#define ARM720T_H
+
+#include "target.h"
+#include "register.h"
+#include "embeddedice.h"
+#include "arm_jtag.h"
+#include "arm7tdmi.h"
+#include "armv4_5_mmu.h"
+#include "armv4_5_cache.h"
+
+#define ARM720T_COMMON_MAGIC 0xa720a720
+
+typedef struct arm720t_common_s
+{
+ int common_magic;
+ armv4_5_mmu_common_t armv4_5_mmu;
+ arm7tdmi_common_t arm7tdmi_common;
+ u32 cp15_control_reg;
+ u32 fsr;
+ u32 far;
+} arm720t_common_t;
+
+#endif /* ARM720T_H */
diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c
new file mode 100644
index 00000000..d167041f
--- /dev/null
+++ b/src/target/arm7_9_common.c
@@ -0,0 +1,2339 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "config.h"
+
+#include "embeddedice.h"
+#include "target.h"
+#include "armv4_5.h"
+#include "arm_jtag.h"
+#include "jtag.h"
+#include "log.h"
+#include "arm7_9_common.h"
+#include "breakpoints.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <errno.h>
+
+int arm7_9_debug_entry(target_t *target);
+int arm7_9_enable_sw_bkpts(struct target_s *target);
+
+/* command handler forward declarations */
+int handle_arm7_9_write_xpsr_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_arm7_9_write_xpsr_im8_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_arm7_9_read_core_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_arm7_9_write_core_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_arm7_9_sw_bkpts_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_arm7_9_force_hw_bkpts_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_arm7_9_dbgrq_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_arm7_9_fast_writes_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_arm7_9_dcc_downloads_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+int arm7_9_reinit_embeddedice(target_t *target)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ breakpoint_t *breakpoint = target->breakpoints;
+
+ arm7_9->wp_available = 2;
+ arm7_9->wp0_used = 0;
+ arm7_9->wp1_used = 0;
+
+ /* mark all hardware breakpoints as unset */
+ while (breakpoint)
+ {
+ if (breakpoint->type == BKPT_HARD)
+ {
+ breakpoint->set = 0;
+ }
+ breakpoint = breakpoint->next;
+ }
+
+ if (arm7_9->sw_bkpts_enabled && arm7_9->sw_bkpts_use_wp)
+ {
+ arm7_9->sw_bkpts_enabled = 0;
+ arm7_9_enable_sw_bkpts(target);
+ }
+
+ arm7_9->reinit_embeddedice = 0;
+
+ return ERROR_OK;
+}
+
+int arm7_9_jtag_callback(enum jtag_event event, void *priv)
+{
+ target_t *target = priv;
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ /* a test-logic reset occured
+ * the EmbeddedICE registers have been reset
+ * hardware breakpoints have been cleared
+ */
+ if (event == JTAG_TRST_ASSERTED)
+ {
+ arm7_9->reinit_embeddedice = 1;
+ }
+
+ return ERROR_OK;
+}
+
+int arm7_9_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
+ {
+ return -1;
+ }
+
+ if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC)
+ {
+ return -1;
+ }
+
+ *armv4_5_p = armv4_5;
+ *arm7_9_p = arm7_9;
+
+ return ERROR_OK;
+}
+
+int arm7_9_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (arm7_9->force_hw_bkpts)
+ breakpoint->type = BKPT_HARD;
+
+ if (breakpoint->set)
+ {
+ WARNING("breakpoint already set");
+ return ERROR_OK;
+ }
+
+ if (breakpoint->type == BKPT_HARD)
+ {
+ /* either an ARM (4 byte) or Thumb (2 byte) breakpoint */
+ u32 mask = (breakpoint->length == 4) ? 0x3u : 0x1u;
+ if (!arm7_9->wp0_used)
+ {
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE], breakpoint->address);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], mask);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffffu);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE);
+
+ jtag_execute_queue();
+ arm7_9->wp0_used = 1;
+ breakpoint->set = 1;
+ }
+ else if (!arm7_9->wp1_used)
+ {
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], breakpoint->address);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], mask);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], 0xffffffffu);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], EICE_W_CTRL_ENABLE);
+
+ jtag_execute_queue();
+ arm7_9->wp1_used = 1;
+ breakpoint->set = 2;
+ }
+ else
+ {
+ ERROR("BUG: no hardware comparator available");
+ return ERROR_OK;
+ }
+ }
+ else if (breakpoint->type == BKPT_SOFT)
+ {
+ if (breakpoint->length == 4)
+ {
+ target->type->read_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr);
+ target->type->write_memory(target, breakpoint->address, 4, 1, (u8*)(&arm7_9->arm_bkpt));
+ }
+ else
+ {
+ target->type->read_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr);
+ target->type->read_memory(target, breakpoint->address, 2, 1, (u8*)(&arm7_9->arm_bkpt));
+ }
+ breakpoint->set = 1;
+ }
+
+ return ERROR_OK;
+
+}
+
+int arm7_9_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (!breakpoint->set)
+ {
+ WARNING("breakpoint not set");
+ return ERROR_OK;
+ }
+
+ if (breakpoint->type == BKPT_HARD)
+ {
+ if (breakpoint->set == 1)
+ {
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0);
+ jtag_execute_queue();
+ arm7_9->wp0_used = 0;
+ }
+ else if (breakpoint->set == 2)
+ {
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0);
+ jtag_execute_queue();
+ arm7_9->wp1_used = 0;
+ }
+ breakpoint->set = 0;
+ }
+ else
+ {
+ if (breakpoint->length == 4)
+ {
+ target->type->write_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr);
+ }
+ else
+ {
+ target->type->write_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr);
+ }
+ breakpoint->set = 0;
+ }
+
+ return ERROR_OK;
+}
+
+int arm7_9_add_breakpoint(struct target_s *target, u32 address, u32 length, enum breakpoint_type type)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (arm7_9->force_hw_bkpts)
+ {
+ type = BKPT_HARD;
+ }
+
+ if ((type == BKPT_SOFT) && (arm7_9->sw_bkpts_enabled == 0))
+ {
+ INFO("sw breakpoint requested, but software breakpoints not enabled");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ if ((type == BKPT_HARD) && (arm7_9->wp_available < 1))
+ {
+ INFO("no watchpoint unit available for hardware breakpoint");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ if (type == BKPT_HARD)
+ arm7_9->wp_available--;
+
+ if ((length != 2) && (length != 4))
+ {
+ INFO("only breakpoints of two (Thumb) or four (ARM) bytes length supported");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ return ERROR_OK;
+}
+
+int arm7_9_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (breakpoint->set)
+ {
+ arm7_9_unset_breakpoint(target, breakpoint);
+ }
+
+ arm7_9->wp_available++;
+
+ return ERROR_OK;
+}
+
+int arm7_9_set_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ int rw_mask = 1;
+ u32 mask;
+
+ mask = watchpoint->length - 1;
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (watchpoint->rw == WPT_ACCESS)
+ rw_mask = 0;
+ else
+ rw_mask = 1;
+
+ if (!arm7_9->wp0_used)
+ {
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE], watchpoint->address);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], mask);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], watchpoint->mask);
+ if( watchpoint->mask != 0xffffffffu )
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_VALUE], watchpoint->value);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], 0xff & ~EICE_W_CTRL_nOPC & ~rw_mask);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE | EICE_W_CTRL_nOPC | (watchpoint->rw & 1));
+
+ jtag_execute_queue();
+ watchpoint->set = 1;
+ arm7_9->wp0_used = 2;
+ }
+ else if (!arm7_9->wp1_used)
+ {
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], watchpoint->address);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], mask);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], watchpoint->mask);
+ if( watchpoint->mask != 0xffffffffu )
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_VALUE], watchpoint->value);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], 0xff & ~EICE_W_CTRL_nOPC & ~rw_mask);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], EICE_W_CTRL_ENABLE | EICE_W_CTRL_nOPC | (watchpoint->rw & 1));
+
+ jtag_execute_queue();
+ watchpoint->set = 2;
+ arm7_9->wp1_used = 2;
+ }
+ else
+ {
+ ERROR("BUG: no hardware comparator available");
+ return ERROR_OK;
+ }
+
+ return ERROR_OK;
+}
+
+int arm7_9_unset_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (!watchpoint->set)
+ {
+ WARNING("breakpoint not set");
+ return ERROR_OK;
+ }
+
+ if (watchpoint->set == 1)
+ {
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0);
+ jtag_execute_queue();
+ arm7_9->wp0_used = 0;
+ }
+ else if (watchpoint->set == 2)
+ {
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0);
+ jtag_execute_queue();
+ arm7_9->wp1_used = 0;
+ }
+ watchpoint->set = 0;
+
+ return ERROR_OK;
+}
+
+int arm7_9_add_watchpoint(struct target_s *target, u32 address, u32 length, enum watchpoint_rw rw)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (arm7_9->wp_available < 1)
+ {
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ if ((length != 1) && (length != 2) && (length != 4))
+ {
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ arm7_9->wp_available--;
+
+ return ERROR_OK;
+}
+
+int arm7_9_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (watchpoint->set)
+ {
+ arm7_9_unset_watchpoint(target, watchpoint);
+ }
+
+ arm7_9->wp_available++;
+
+ return ERROR_OK;
+}
+
+int arm7_9_enable_sw_bkpts(struct target_s *target)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ int retval;
+
+ if (arm7_9->sw_bkpts_enabled)
+ return ERROR_OK;
+
+ if (arm7_9->wp_available-- < 1)
+ {
+ WARNING("can't enable sw breakpoints with no watchpoint unit available");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ if (!arm7_9->wp0_used)
+ {
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_VALUE], arm7_9->arm_bkpt);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0x0);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0xffffffffu);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE);
+ arm7_9->sw_bkpts_enabled = 1;
+ arm7_9->wp0_used = 3;
+ }
+ else if (!arm7_9->wp1_used)
+ {
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_VALUE], arm7_9->arm_bkpt);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], 0x0);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], 0xffffffffu);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff);
+ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], EICE_W_CTRL_ENABLE);
+ arm7_9->sw_bkpts_enabled = 2;
+ arm7_9->wp1_used = 3;
+ }
+ else
+ {
+ ERROR("BUG: both watchpoints used, but wp_available >= 1");
+ exit(-1);
+ }
+
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ {
+ ERROR("error writing EmbeddedICE registers to enable sw breakpoints");
+ exit(-1);
+ };
+
+ return ERROR_OK;
+}
+
+int arm7_9_disable_sw_bkpts(struct target_s *target)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ if (!arm7_9->sw_bkpts_enabled)
+ return ERROR_OK;
+
+ if (arm7_9->sw_bkpts_enabled == 1)
+ {
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0);
+ arm7_9->sw_bkpts_enabled = 0;
+ arm7_9->wp0_used = 0;
+ arm7_9->wp_available++;
+ }
+ else if (arm7_9->sw_bkpts_enabled == 2)
+ {
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0);
+ arm7_9->sw_bkpts_enabled = 0;
+ arm7_9->wp1_used = 0;
+ arm7_9->wp_available++;
+ }
+
+ return ERROR_OK;
+}
+
+int arm7_9_execute_sys_speed(struct target_s *target)
+{
+ int timeout;
+ int retval;
+
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+ reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
+
+ /* set RESTART instruction */
+ jtag_add_end_state(TAP_RTI);
+ arm_jtag_set_instr(jtag_info, 0x4);
+
+ for (timeout=0; timeout<50; timeout++)
+ {
+ /* read debug status register */
+ embeddedice_read_reg(dbg_stat);
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ return retval;
+ if ((buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1))
+ && (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_SYSCOMP, 1)))
+ break;
+ usleep(100000);
+ }
+ if (timeout == 50)
+ {
+ ERROR("timeout waiting for SYSCOMP & DBGACK, last DBG_STATUS: %x", buf_get_u32(dbg_stat->value, 0, dbg_stat->size));
+ return ERROR_TARGET_TIMEOUT;
+ }
+
+ return ERROR_OK;
+}
+
+int arm7_9_execute_fast_sys_speed(struct target_s *target)
+{
+ u8 check_value[4], check_mask[4];
+
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+ reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
+
+ /* set RESTART instruction */
+ jtag_add_end_state(TAP_RTI);
+ arm_jtag_set_instr(jtag_info, 0x4);
+
+ /* check for DBGACK and SYSCOMP set (others don't care) */
+ buf_set_u32(check_value, 0, 32, 0x9);
+ buf_set_u32(check_mask, 0, 32, 0x9);
+
+ /* read debug status register */
+ embeddedice_read_reg_w_check(dbg_stat, check_value, check_value);
+
+ return ERROR_OK;
+}
+
+enum target_state arm7_9_poll(target_t *target)
+{
+ int retval;
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
+ reg_t *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL];
+
+ if (arm7_9->reinit_embeddedice)
+ {
+ arm7_9_reinit_embeddedice(target);
+ }
+
+ /* read debug status register */
+ embeddedice_read_reg(dbg_stat);
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_JTAG_QUEUE_FAILED:
+ ERROR("JTAG queue failed while reading EmbeddedICE status register");
+ exit(-1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1))
+ {
+ DEBUG("DBGACK set, dbg_state->value: 0x%x", buf_get_u32(dbg_stat->value, 0, 32));
+ if ((target->state == TARGET_UNKNOWN))
+ {
+ WARNING("DBGACK set while target was in unknown state. Reset or initialize target before resuming");
+ target->state = TARGET_RUNNING;
+ }
+ if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET))
+ {
+ target->state = TARGET_HALTED;
+ if ((retval = arm7_9_debug_entry(target)) != ERROR_OK)
+ return retval;
+
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+ }
+ if (target->state == TARGET_DEBUG_RUNNING)
+ {
+ target->state = TARGET_HALTED;
+ if ((retval = arm7_9_debug_entry(target)) != ERROR_OK)
+ return retval;
+
+ target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
+ }
+ }
+ else
+ {
+ if (target->state != TARGET_DEBUG_RUNNING)
+ target->state = TARGET_RUNNING;
+ }
+
+ return target->state;
+}
+
+int arm7_9_assert_reset(target_t *target)
+{
+ int retval;
+
+ DEBUG("target->state: %s", target_state_strings[target->state]);
+
+ if (target->state == TARGET_HALTED || target->state == TARGET_UNKNOWN)
+ {
+ /* assert SRST and TRST */
+ /* system would get ouf sync if we didn't reset test-logic, too */
+ if ((retval = jtag_add_reset(1, 1)) != ERROR_OK)
+ {
+ if (retval == ERROR_JTAG_RESET_CANT_SRST)
+ {
+ WARNING("can't assert srst");
+ return retval;
+ }
+ else
+ {
+ ERROR("unknown error");
+ exit(-1);
+ }
+ }
+ jtag_add_sleep(5000);
+ if ((retval = jtag_add_reset(0, 1)) != ERROR_OK)
+ {
+ if (retval == ERROR_JTAG_RESET_WOULD_ASSERT_TRST)
+ {
+ WARNING("srst resets test logic, too");
+ retval = jtag_add_reset(1, 1);
+ }
+ }
+ }
+ else
+ {
+ if ((retval = jtag_add_reset(0, 1)) != ERROR_OK)
+ {
+ if (retval == ERROR_JTAG_RESET_WOULD_ASSERT_TRST)
+ {
+ WARNING("srst resets test logic, too");
+ retval = jtag_add_reset(1, 1);
+ }
+
+ if (retval == ERROR_JTAG_RESET_CANT_SRST)
+ {
+ WARNING("can't assert srst");
+ return retval;
+ }
+ else if (retval != ERROR_OK)
+ {
+ ERROR("unknown error");
+ exit(-1);
+ }
+ }
+ }
+
+ target->state = TARGET_RESET;
+ jtag_add_sleep(50000);
+
+ armv4_5_invalidate_core_regs(target);
+
+ return ERROR_OK;
+
+}
+
+int arm7_9_deassert_reset(target_t *target)
+{
+ DEBUG("target->state: %s", target_state_strings[target->state]);
+
+ /* deassert reset lines */
+ jtag_add_reset(0, 0);
+
+ return ERROR_OK;
+
+}
+
+int arm7_9_soft_reset_halt(struct target_s *target)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
+ int i;
+
+ if (target->state == TARGET_RUNNING)
+ {
+ target->type->halt(target);
+ }
+
+ while (buf_get_u32(dbg_stat->value, EICE_DBG_CONTROL_DBGACK, 1) == 0)
+ {
+ embeddedice_read_reg(dbg_stat);
+ jtag_execute_queue();
+ }
+ target->state = TARGET_HALTED;
+
+ /* all register content is now invalid */
+ armv4_5_invalidate_core_regs(target);
+
+ /* SVC, ARM state, IRQ and FIQ disabled */
+ buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3);
+ armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
+ armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
+
+ /* start fetching from 0x0 */
+ buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0);
+ armv4_5->core_cache->reg_list[15].dirty = 1;
+ armv4_5->core_cache->reg_list[15].valid = 1;
+
+ armv4_5->core_mode = ARMV4_5_MODE_SVC;
+ armv4_5->core_state = ARMV4_5_STATE_ARM;
+
+ /* reset registers */
+ for (i = 0; i <= 14; i++)
+ {
+ buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).value, 0, 32, 0xffffffff);
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).dirty = 1;
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).valid = 1;
+ }
+
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+
+ return ERROR_OK;
+}
+
+int arm7_9_halt(target_t *target)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ reg_t *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL];
+
+ DEBUG("target->state: %s", target_state_strings[target->state]);
+
+ if (target->state == TARGET_HALTED)
+ {
+ WARNING("target was already halted");
+ return ERROR_TARGET_ALREADY_HALTED;
+ }
+
+ if (target->state == TARGET_UNKNOWN)
+ {
+ WARNING("target was in unknown state when halt was requested");
+ }
+
+ if (arm7_9->use_dbgrq)
+ {
+ /* program EmbeddedICE Debug Control Register to assert DBGRQ
+ */
+ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGRQ, 1, 1);
+ embeddedice_store_reg(dbg_ctrl);
+ }
+ else
+ {
+ /* program watchpoint unit to match on any address
+ */
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0xffffffff);
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffff);
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x100);
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], 0xf7);
+ }
+
+ target->debug_reason = DBG_REASON_DBGRQ;
+
+ return ERROR_OK;
+}
+
+int arm7_9_clear_halt(target_t *target)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ reg_t *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL];
+
+ if (arm7_9->use_dbgrq)
+ {
+ /* program EmbeddedICE Debug Control Register to deassert DBGRQ
+ */
+ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGRQ, 1, 0);
+ embeddedice_store_reg(dbg_ctrl);
+ }
+ else
+ {
+ /* restore registers if watchpoint unit 0 was in use
+ */
+ if (arm7_9->wp0_used)
+ {
+ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK]);
+ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK]);
+ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK]);
+ }
+ /* control value always has to be restored, as it was either disabled,
+ * or enabled with possibly different bits
+ */
+ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE]);
+ }
+
+ return ERROR_OK;
+}
+
+int arm7_9_debug_entry(target_t *target)
+{
+ int i;
+ u32 context[16];
+ u32* context_p[16];
+ u32 r0_thumb, pc_thumb;
+ u32 cpsr;
+ int retval;
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
+ reg_t *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL];
+
+#ifdef _DEBUG_ARM7_9_
+ DEBUG("");
+#endif
+
+ if (arm7_9->pre_debug_entry)
+ arm7_9->pre_debug_entry(target);
+
+ /* program EmbeddedICE Debug Control Register to assert DBGACK and INTDIS
+ * ensure that DBGRQ is cleared
+ */
+ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGACK, 1, 1);
+ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGRQ, 1, 0);
+ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_INTDIS, 1, 1);
+ embeddedice_store_reg(dbg_ctrl);
+
+ arm7_9_clear_halt(target);
+
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_JTAG_QUEUE_FAILED:
+ ERROR("JTAG queue failed while writing EmbeddedICE control register");
+ exit(-1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ((retval = arm7_9->examine_debug_reason(target)) != ERROR_OK)
+ return retval;
+
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* if the target is in Thumb state, change to ARM state */
+ if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_ITBIT, 1))
+ {
+ DEBUG("target entered debug from Thumb state");
+ /* Entered debug from Thumb mode */
+ armv4_5->core_state = ARMV4_5_STATE_THUMB;
+ arm7_9->change_to_arm(target, &r0_thumb, &pc_thumb);
+ DEBUG("r0_thumb: 0x%8.8x, pc_thumb: 0x%8.8x", r0_thumb, pc_thumb);
+ }
+ else
+ {
+ DEBUG("target entered debug from ARM state");
+ /* Entered debug from ARM mode */
+ armv4_5->core_state = ARMV4_5_STATE_ARM;
+ }
+
+ for (i = 0; i < 16; i++)
+ context_p[i] = &context[i];
+ /* save core registers (r0 - r15 of current core mode) */
+ arm7_9->read_core_regs(target, 0xffff, context_p);
+
+ arm7_9->read_xpsr(target, &cpsr, 0);
+
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ return retval;
+ buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32, cpsr);
+ armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 0;
+ armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
+
+ armv4_5->core_mode = cpsr & 0x1f;
+ DEBUG("target entered debug state in %s mode", armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)]);
+
+ if (armv4_5_mode_to_number(armv4_5->core_mode) == -1)
+ {
+ target->state = TARGET_UNKNOWN;
+ ERROR("cpsr contains invalid mode value - communication failure");
+ return ERROR_TARGET_FAILURE;
+ }
+
+ if (armv4_5->core_state == ARMV4_5_STATE_THUMB)
+ {
+ DEBUG("thumb state, applying fixups");
+ context[0] = r0_thumb;
+ context[15] = pc_thumb;
+ } else if (armv4_5->core_state == ARMV4_5_STATE_ARM)
+ {
+ /* adjust value stored by STM */
+ context[15] -= 3 * 4;
+ }
+
+ if ((target->debug_reason == DBG_REASON_BREAKPOINT)
+ || (target->debug_reason == DBG_REASON_SINGLESTEP)
+ || (target->debug_reason == DBG_REASON_WATCHPOINT)
+ || (target->debug_reason == DBG_REASON_WPTANDBKPT)
+ || ((target->debug_reason == DBG_REASON_DBGRQ) && (arm7_9->use_dbgrq == 0)))
+ context[15] -= 3 * ((armv4_5->core_state == ARMV4_5_STATE_ARM) ? 4 : 2);
+ else if (target->debug_reason == DBG_REASON_DBGRQ)
+ context[15] -= arm7_9->dbgreq_adjust_pc * ((armv4_5->core_state == ARMV4_5_STATE_ARM) ? 4 : 2);
+ else
+ {
+ ERROR("unknown debug reason: %i", target->debug_reason);
+ }
+
+
+ for (i=0; i<=15; i++)
+ {
+ buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).value, 0, 32, context[i]);
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).dirty = 0;
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).valid = 1;
+ }
+
+ DEBUG("entered debug state at PC 0x%x", context[15]);
+
+ /* exceptions other than USR & SYS have a saved program status register */
+ if ((armv4_5_mode_to_number(armv4_5->core_mode) != ARMV4_5_MODE_USR) && (armv4_5_mode_to_number(armv4_5->core_mode) != ARMV4_5_MODE_SYS))
+ {
+ u32 spsr;
+ arm7_9->read_xpsr(target, &spsr, 1);
+ jtag_execute_queue();
+ buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, spsr);
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).dirty = 0;
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).valid = 1;
+ }
+
+ /* r0 and r15 (pc) have to be restored later */
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = 1;
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 15).dirty = 1;
+
+ if ((retval = jtag->execute_queue()) != ERROR_OK)
+ return retval;
+
+ if (arm7_9->post_debug_entry)
+ arm7_9->post_debug_entry(target);
+
+ return ERROR_OK;
+}
+
+int arm7_9_full_context(target_t *target)
+{
+ int i;
+ int retval;
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ DEBUG("");
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* iterate through processor modes (User, FIQ, IRQ, SVC, ABT, UND)
+ * SYS shares registers with User, so we don't touch SYS
+ */
+ for(i = 0; i < 6; i++)
+ {
+ u32 mask = 0;
+ u32* reg_p[16];
+ int j;
+ int valid = 1;
+
+ /* check if there are invalid registers in the current mode
+ */
+ for (j = 0; j <= 16; j++)
+ {
+ if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid == 0)
+ valid = 0;
+ }
+
+ if (!valid)
+ {
+ u32 tmp_cpsr;
+
+ /* change processor mode */
+ tmp_cpsr = buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8) & 0xE0;
+ tmp_cpsr |= armv4_5_number_to_mode(i);
+ arm7_9->write_xpsr_im8(target, tmp_cpsr & 0xff, 0, 0);
+
+ for (j = 0; j < 15; j++)
+ {
+ if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid == 0)
+ {
+ reg_p[j] = (u32*)ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).value;
+ mask |= 1 << j;
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid = 1;
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0;
+ }
+ }
+
+ /* if only the PSR is invalid, mask is all zeroes */
+ if (mask)
+ arm7_9->read_core_regs(target, mask, reg_p);
+
+ /* check if the PSR has to be read */
+ if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).valid == 0)
+ {
+ arm7_9->read_xpsr(target, (u32*)ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).value, 1);
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).valid = 1;
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0;
+ }
+ }
+ }
+
+ /* restore processor mode */
+ arm7_9->write_xpsr_im8(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8), 0, 0);
+
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ {
+ ERROR("JTAG failure");
+ exit(-1);
+ }
+ return ERROR_OK;
+}
+
+int arm7_9_restore_context(target_t *target)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ reg_t *reg;
+ armv4_5_core_reg_t *reg_arch_info;
+ enum armv4_5_mode current_mode = armv4_5->core_mode;
+ int i, j;
+ int dirty;
+ int mode_change;
+
+ DEBUG("");
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (arm7_9->pre_restore_context)
+ arm7_9->pre_restore_context(target);
+
+ /* iterate through processor modes (User, FIQ, IRQ, SVC, ABT, UND)
+ * SYS shares registers with User, so we don't touch SYS
+ */
+ for (i = 0; i < 6; i++)
+ {
+ DEBUG("examining %s mode", armv4_5_mode_strings[i]);
+ dirty = 0;
+ mode_change = 0;
+ /* check if there are dirty registers in the current mode
+ */
+ for (j = 0; j <= 16; j++)
+ {
+ reg = &ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j);
+ reg_arch_info = reg->arch_info;
+ if (reg->dirty == 1)
+ {
+ if (reg->valid == 1)
+ {
+ dirty = 1;
+ DEBUG("examining dirty reg: %s", reg->name);
+ if ((reg_arch_info->mode != ARMV4_5_MODE_ANY)
+ && (reg_arch_info->mode != current_mode)
+ && !((reg_arch_info->mode == ARMV4_5_MODE_USR) && (armv4_5->core_mode == ARMV4_5_MODE_SYS))
+ && !((reg_arch_info->mode == ARMV4_5_MODE_SYS) && (armv4_5->core_mode == ARMV4_5_MODE_USR)))
+ {
+ mode_change = 1;
+ DEBUG("require mode change");
+ }
+ }
+ else
+ {
+ ERROR("BUG: dirty register '%s', but no valid data", reg->name);
+ exit(-1);
+ }
+ }
+ }
+
+ if (dirty)
+ {
+ u32 mask = 0x0;
+ int num_regs = 0;
+ u32 regs[16];
+
+ if (mode_change)
+ {
+ u32 tmp_cpsr;
+
+ /* change processor mode */
+ tmp_cpsr = buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8) & 0xE0;
+ tmp_cpsr |= armv4_5_number_to_mode(i);
+ arm7_9->write_xpsr_im8(target, tmp_cpsr & 0xff, 0, 0);
+ current_mode = armv4_5_number_to_mode(i);
+ }
+
+ for (j = 0; j <= 14; j++)
+ {
+ reg = &ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j);
+ reg_arch_info = reg->arch_info;
+
+
+ if (reg->dirty == 1)
+ {
+ regs[j] = buf_get_u32(reg->value, 0, 32);
+ mask |= 1 << j;
+ num_regs++;
+ reg->dirty = 0;
+ reg->valid = 1;
+ DEBUG("writing register %i of mode %s with value 0x%8.8x", j, armv4_5_mode_strings[i], regs[j]);
+ }
+ }
+
+ if (mask)
+ {
+ arm7_9->write_core_regs(target, mask, regs);
+ }
+
+ reg = &ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16);
+ reg_arch_info = reg->arch_info;
+ if ((reg->dirty) && (reg_arch_info->mode != ARMV4_5_MODE_ANY))
+ {
+ DEBUG("writing SPSR of mode %i with value 0x%8.8x", i, buf_get_u32(reg->value, 0, 32));
+ arm7_9->write_xpsr(target, buf_get_u32(reg->value, 0, 32), 1);
+ }
+ }
+ }
+
+ if ((armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty == 0) && (armv4_5->core_mode != current_mode))
+ {
+ /* restore processor mode */
+ u32 tmp_cpsr;
+
+ tmp_cpsr = buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8) & 0xE0;
+ tmp_cpsr |= armv4_5_number_to_mode(i);
+ DEBUG("writing lower 8 bit of cpsr with value 0x%2.2x", tmp_cpsr);
+ arm7_9->write_xpsr_im8(target, tmp_cpsr & 0xff, 0, 0);
+ }
+ else if (armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty == 1)
+ {
+ /* CPSR has been changed, full restore necessary */
+ DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32));
+ arm7_9->write_xpsr(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), 0);
+ armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 0;
+ armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
+ }
+
+ /* restore PC */
+ DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
+ arm7_9->write_pc(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
+ armv4_5->core_cache->reg_list[15].dirty = 0;
+
+ if (arm7_9->post_restore_context)
+ arm7_9->post_restore_context(target);
+
+ return ERROR_OK;
+}
+
+int arm7_9_restart_core(struct target_s *target)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* set RESTART instruction */
+ jtag_add_end_state(TAP_RTI);
+ arm_jtag_set_instr(jtag_info, 0x4);
+
+ jtag_add_runtest(1, TAP_RTI);
+ if ((jtag_execute_queue()) != ERROR_OK)
+ {
+ exit(-1);
+ }
+
+ return ERROR_OK;
+}
+
+void arm7_9_enable_watchpoints(struct target_s *target)
+{
+ watchpoint_t *watchpoint = target->watchpoints;
+
+ while (watchpoint)
+ {
+ if (watchpoint->set == 0)
+ arm7_9_set_watchpoint(target, watchpoint);
+ watchpoint = watchpoint->next;
+ }
+}
+
+void arm7_9_enable_breakpoints(struct target_s *target)
+{
+ breakpoint_t *breakpoint = target->breakpoints;
+
+ /* set any pending breakpoints */
+ while (breakpoint)
+ {
+ if (breakpoint->set == 0)
+ arm7_9_set_breakpoint(target, breakpoint);
+ breakpoint = breakpoint->next;
+ }
+}
+
+void arm7_9_disable_bkpts_and_wpts(struct target_s *target)
+{
+ breakpoint_t *breakpoint = target->breakpoints;
+ watchpoint_t *watchpoint = target->watchpoints;
+
+ /* set any pending breakpoints */
+ while (breakpoint)
+ {
+ if (breakpoint->set != 0)
+ arm7_9_unset_breakpoint(target, breakpoint);
+ breakpoint = breakpoint->next;
+ }
+
+ while (watchpoint)
+ {
+ if (watchpoint->set != 0)
+ arm7_9_unset_watchpoint(target, watchpoint);
+ watchpoint = watchpoint->next;
+ }
+}
+
+int arm7_9_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ breakpoint_t *breakpoint = target->breakpoints;
+ reg_t *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL];
+
+ DEBUG("");
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (!debug_execution)
+ {
+ target_free_all_working_areas(target);
+ }
+
+ /* current = 1: continue on current pc, otherwise continue at <address> */
+ if (!current)
+ buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address);
+
+ /* the front-end may request us not to handle breakpoints */
+ if (handle_breakpoints)
+ {
+ if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32))))
+ {
+ DEBUG("unset breakpoint at 0x%8.8x", breakpoint->address);
+ arm7_9_unset_breakpoint(target, breakpoint);
+
+ DEBUG("enable single-step");
+ arm7_9->enable_single_step(target);
+
+ target->debug_reason = DBG_REASON_SINGLESTEP;
+
+ arm7_9_restore_context(target);
+
+ if (armv4_5->core_state == ARMV4_5_STATE_ARM)
+ arm7_9->branch_resume(target);
+ else if (armv4_5->core_state == ARMV4_5_STATE_THUMB)
+ {
+ arm7_9->branch_resume_thumb(target);
+ }
+ else
+ {
+ ERROR("unhandled core state");
+ exit(-1);
+ }
+
+ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGACK, 1, 0);
+ embeddedice_write_reg(dbg_ctrl, buf_get_u32(dbg_ctrl->value, 0, dbg_ctrl->size));
+ arm7_9_execute_sys_speed(target);
+
+ DEBUG("disable single-step");
+ arm7_9->disable_single_step(target);
+
+ arm7_9_debug_entry(target);
+ DEBUG("new PC after step: 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
+
+ DEBUG("set breakpoint at 0x%8.8x", breakpoint->address);
+ arm7_9_set_breakpoint(target, breakpoint);
+ }
+ }
+
+ /* enable any pending breakpoints and watchpoints */
+ arm7_9_enable_breakpoints(target);
+ arm7_9_enable_watchpoints(target);
+
+ arm7_9_restore_context(target);
+
+ if (armv4_5->core_state == ARMV4_5_STATE_ARM)
+ {
+ arm7_9->branch_resume(target);
+ }
+ else if (armv4_5->core_state == ARMV4_5_STATE_THUMB)
+ {
+ arm7_9->branch_resume_thumb(target);
+ }
+ else
+ {
+ ERROR("unhandled core state");
+ exit(-1);
+ }
+
+ /* deassert DBGACK and INTDIS */
+ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGACK, 1, 0);
+ /* INTDIS only when we really resume, not during debug execution */
+ if (!debug_execution)
+ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_INTDIS, 1, 0);
+ embeddedice_write_reg(dbg_ctrl, buf_get_u32(dbg_ctrl->value, 0, dbg_ctrl->size));
+
+ arm7_9_restart_core(target);
+
+ target->debug_reason = DBG_REASON_NOTHALTED;
+
+ if (!debug_execution)
+ {
+ /* registers are now invalid */
+ armv4_5_invalidate_core_regs(target);
+ target->state = TARGET_RUNNING;
+ target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+ }
+ else
+ {
+ target->state = TARGET_DEBUG_RUNNING;
+ target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
+ }
+
+ DEBUG("target resumed");
+
+ return ERROR_OK;
+}
+
+void arm7_9_enable_eice_step(target_t *target)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ /* setup an inverse breakpoint on the current PC
+ * - comparator 1 matches the current address
+ * - rangeout from comparator 1 is connected to comparator 0 rangein
+ * - comparator 0 matches any address, as long as rangein is low */
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0xffffffff);
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffff);
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x100);
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], 0x77);
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], 0);
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], 0xffffffff);
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0);
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], 0xf7);
+}
+
+void arm7_9_disable_eice_step(target_t *target)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK]);
+ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK]);
+ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE]);
+ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK]);
+ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE]);
+ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK]);
+ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK]);
+ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK]);
+ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE]);
+}
+
+int arm7_9_step(struct target_s *target, int current, u32 address, int handle_breakpoints)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ breakpoint_t *breakpoint = target->breakpoints;
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* current = 1: continue on current pc, otherwise continue at <address> */
+ if (!current)
+ buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address);
+
+ /* the front-end may request us not to handle breakpoints */
+ if (handle_breakpoints)
+ if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32))))
+ arm7_9_unset_breakpoint(target, breakpoint);
+
+ target->debug_reason = DBG_REASON_SINGLESTEP;
+
+ arm7_9_restore_context(target);
+
+ arm7_9->enable_single_step(target);
+
+ if (armv4_5->core_state == ARMV4_5_STATE_ARM)
+ {
+ arm7_9->branch_resume(target);
+ }
+ else if (armv4_5->core_state == ARMV4_5_STATE_THUMB)
+ {
+ arm7_9->branch_resume_thumb(target);
+ }
+ else
+ {
+ ERROR("unhandled core state");
+ exit(-1);
+ }
+
+ target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+
+ arm7_9_execute_sys_speed(target);
+ arm7_9->disable_single_step(target);
+
+ /* registers are now invalid */
+ armv4_5_invalidate_core_regs(target);
+
+ arm7_9_debug_entry(target);
+
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+
+ if (breakpoint)
+ arm7_9_set_breakpoint(target, breakpoint);
+
+ DEBUG("target stepped");
+
+ return ERROR_OK;
+
+}
+
+int arm7_9_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode)
+{
+ u32* reg_p[16];
+ int retval;
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ enum armv4_5_mode reg_mode = ((armv4_5_core_reg_t*)ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, num).arch_info)->mode;
+
+ if ((num < 0) || (num > 16))
+ return ERROR_INVALID_ARGUMENTS;
+
+ if ((mode != ARMV4_5_MODE_ANY)
+ && (mode != armv4_5->core_mode)
+ && (reg_mode != ARMV4_5_MODE_ANY))
+ {
+ u32 tmp_cpsr;
+
+ /* change processor mode */
+ tmp_cpsr = buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8) & 0xE0;
+ tmp_cpsr |= mode;
+ arm7_9->write_xpsr_im8(target, tmp_cpsr & 0xff, 0, 0);
+ }
+
+ if ((num >= 0) && (num <= 15))
+ {
+ /* read a normal core register */
+ reg_p[num] = (u32*)ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, num).value;
+
+ arm7_9->read_core_regs(target, 1 << num, reg_p);
+ }
+ else
+ {
+ /* read a program status register
+ * if the register mode is MODE_ANY, we read the cpsr, otherwise a spsr
+ */
+ armv4_5_core_reg_t *arch_info = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, num).arch_info;
+ int spsr = (arch_info->mode == ARMV4_5_MODE_ANY) ? 0 : 1;
+
+ arm7_9->read_xpsr(target, (u32*)ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, num).value, spsr);
+ }
+
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, num).valid = 1;
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, num).dirty = 0;
+
+ if ((mode != ARMV4_5_MODE_ANY)
+ && (mode != armv4_5->core_mode)
+ && (reg_mode != ARMV4_5_MODE_ANY)) {
+ /* restore processor mode */
+ arm7_9->write_xpsr_im8(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8), 0, 0);
+ }
+
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ {
+ ERROR("JTAG failure");
+ exit(-1);
+ }
+
+ return ERROR_OK;
+
+}
+
+int arm7_9_write_core_reg(struct target_s *target, int num, enum armv4_5_mode mode, u32 value)
+{
+ u32 reg[16];
+ int retval;
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ enum armv4_5_mode reg_mode = ((armv4_5_core_reg_t*)ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, num).arch_info)->mode;
+
+ if ((num < 0) || (num > 16))
+ return ERROR_INVALID_ARGUMENTS;
+
+ if ((mode != ARMV4_5_MODE_ANY)
+ && (mode != armv4_5->core_mode)
+ && (reg_mode != ARMV4_5_MODE_ANY)) {
+ u32 tmp_cpsr;
+
+ /* change processor mode */
+ tmp_cpsr = buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8) & 0xE0;
+ tmp_cpsr |= mode;
+ arm7_9->write_xpsr_im8(target, tmp_cpsr & 0xff, 0, 0);
+ }
+
+ if ((num >= 0) && (num <= 15))
+ {
+ /* write a normal core register */
+ reg[num] = value;
+
+ arm7_9->write_core_regs(target, 1 << num, reg);
+ }
+ else
+ {
+ /* write a program status register
+ * if the register mode is MODE_ANY, we write the cpsr, otherwise a spsr
+ */
+ armv4_5_core_reg_t *arch_info = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, num).arch_info;
+ int spsr = (arch_info->mode == ARMV4_5_MODE_ANY) ? 0 : 1;
+
+ arm7_9->write_xpsr(target, value, spsr);
+ }
+
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, num).valid = 1;
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, num).dirty = 0;
+
+ if ((mode != ARMV4_5_MODE_ANY)
+ && (mode != armv4_5->core_mode)
+ && (reg_mode != ARMV4_5_MODE_ANY)) {
+ /* restore processor mode */
+ arm7_9->write_xpsr_im8(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8), 0, 0);
+ }
+
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ {
+ ERROR("JTAG failure");
+ exit(-1);
+ }
+
+ return ERROR_OK;
+
+}
+
+int arm7_9_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ u32 reg[16];
+ u32 *reg_p[16];
+ int num_accesses = 0;
+ int thisrun_accesses;
+ u32 *buf32;
+ u16 *buf16;
+ u8 *buf8;
+ int i;
+ u32 cpsr;
+ int retval;
+ int last_reg = 0;
+
+ DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count);
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* sanitize arguments */
+ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer))
+ return ERROR_INVALID_ARGUMENTS;
+
+ if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
+ return ERROR_TARGET_UNALIGNED_ACCESS;
+
+ for (i = 0; i < 16; i++)
+ {
+ reg_p[i] = &reg[i];
+ }
+
+ /* load the base register with the address of the first word */
+ reg[0] = address;
+ arm7_9->write_core_regs(target, 0x1, reg);
+
+ switch (size)
+ {
+ case 4:
+ buf32 = (u32*)buffer;
+ while (num_accesses < count)
+ {
+ u32 reg_list;
+ thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses);
+ reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe;
+
+ arm7_9->load_word_regs(target, reg_list);
+ arm7_9_execute_sys_speed(target);
+
+ arm7_9->read_core_regs(target, reg_list, reg_p);
+ jtag_execute_queue();
+
+ for (i = 1; i <= thisrun_accesses; i++)
+ {
+ if (i > last_reg)
+ last_reg = i;
+ *(buf32++) = reg[i];
+ }
+ num_accesses += thisrun_accesses;
+ }
+ break;
+ case 2:
+ buf16 = (u16*)buffer;
+ while (num_accesses < count)
+ {
+ u32 reg_list;
+ thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses);
+ reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe;
+
+ for (i = 1; i <= thisrun_accesses; i++)
+ {
+ if (i > last_reg)
+ last_reg = i;
+ arm7_9->load_hword_reg(target, i);
+ arm7_9_execute_sys_speed(target);
+ }
+
+ arm7_9->read_core_regs(target, reg_list, reg_p);
+ jtag_execute_queue();
+
+ for (i = 1; i <= thisrun_accesses; i++)
+ {
+ *(buf16++) = reg[i] & 0xffff;
+ }
+ num_accesses += thisrun_accesses;
+ }
+ break;
+ case 1:
+ buf8 = buffer;
+ while (num_accesses < count)
+ {
+ u32 reg_list;
+ thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses);
+ reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe;
+
+ for (i = 1; i <= thisrun_accesses; i++)
+ {
+ if (i > last_reg)
+ last_reg = i;
+ arm7_9->load_byte_reg(target, i);
+ arm7_9_execute_sys_speed(target);
+ }
+
+ arm7_9->read_core_regs(target, reg_list, reg_p);
+ jtag_execute_queue();
+
+ for (i = 1; i <= thisrun_accesses; i++)
+ {
+ *(buf8++) = reg[i] & 0xff;
+ }
+ num_accesses += thisrun_accesses;
+ }
+ break;
+ default:
+ ERROR("BUG: we shouldn't get here");
+ exit(-1);
+ break;
+ }
+
+ for (i=0; i<=last_reg; i++)
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).dirty = 1;
+
+ arm7_9->read_xpsr(target, &cpsr, 0);
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ {
+ ERROR("JTAG error while reading cpsr");
+ exit(-1);
+ }
+
+ if (((cpsr & 0x1f) == ARMV4_5_MODE_ABT) && (armv4_5->core_mode != ARMV4_5_MODE_ABT))
+ {
+ ERROR("memory read caused data abort");
+
+ arm7_9->write_xpsr_im8(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8), 0, 0);
+
+ return ERROR_TARGET_DATA_ABORT;
+ }
+
+ return ERROR_OK;
+}
+
+int arm7_9_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ u32 reg[16];
+ int num_accesses = 0;
+ int thisrun_accesses;
+ u32 *buf32;
+ u16 *buf16;
+ u8 *buf8;
+ int i;
+ u32 cpsr;
+ int retval;
+ int last_reg = 0;
+
+ DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count);
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* sanitize arguments */
+ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer))
+ return ERROR_INVALID_ARGUMENTS;
+
+ if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
+ return ERROR_TARGET_UNALIGNED_ACCESS;
+
+ /* load the base register with the address of the first word */
+ reg[0] = address;
+ arm7_9->write_core_regs(target, 0x1, reg);
+
+ switch (size)
+ {
+ case 4:
+ buf32 = (u32*)buffer;
+ while (num_accesses < count)
+ {
+ u32 reg_list;
+ thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses);
+ reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe;
+
+ for (i = 1; i <= thisrun_accesses; i++)
+ {
+ if (i > last_reg)
+ last_reg = i;
+ reg[i] = *buf32++;
+ }
+
+ arm7_9->write_core_regs(target, reg_list, reg);
+
+ arm7_9->store_word_regs(target, reg_list);
+
+ /* fast memory writes are only safe when the target is running
+ * from a sufficiently high clock (32 kHz is usually too slow)
+ */
+ if (arm7_9->fast_memory_writes)
+ arm7_9_execute_fast_sys_speed(target);
+ else
+ arm7_9_execute_sys_speed(target);
+
+ num_accesses += thisrun_accesses;
+ }
+ break;
+ case 2:
+ buf16 = (u16*)buffer;
+ while (num_accesses < count)
+ {
+ u32 reg_list;
+ thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses);
+ reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe;
+
+ for (i = 1; i <= thisrun_accesses; i++)
+ {
+ if (i > last_reg)
+ last_reg = i;
+ reg[i] = *buf16++ & 0xffff;
+ }
+
+ arm7_9->write_core_regs(target, reg_list, reg);
+
+ for (i = 1; i <= thisrun_accesses; i++)
+ {
+ arm7_9->store_hword_reg(target, i);
+
+ /* fast memory writes are only safe when the target is running
+ * from a sufficiently high clock (32 kHz is usually too slow)
+ */
+ if (arm7_9->fast_memory_writes)
+ arm7_9_execute_fast_sys_speed(target);
+ else
+ arm7_9_execute_sys_speed(target);
+ }
+
+ num_accesses += thisrun_accesses;
+ }
+ break;
+ case 1:
+ buf8 = buffer;
+ while (num_accesses < count)
+ {
+ u32 reg_list;
+ thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses);
+ reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe;
+
+ for (i = 1; i <= thisrun_accesses; i++)
+ {
+ if (i > last_reg)
+ last_reg = i;
+ reg[i] = *buf8++ & 0xff;
+ }
+
+ arm7_9->write_core_regs(target, reg_list, reg);
+
+ for (i = 1; i <= thisrun_accesses; i++)
+ {
+ arm7_9->store_byte_reg(target, i);
+ /* fast memory writes are only safe when the target is running
+ * from a sufficiently high clock (32 kHz is usually too slow)
+ */
+ if (arm7_9->fast_memory_writes)
+ arm7_9_execute_fast_sys_speed(target);
+ else
+ arm7_9_execute_sys_speed(target);
+ }
+
+ num_accesses += thisrun_accesses;
+ }
+ break;
+ default:
+ ERROR("BUG: we shouldn't get here");
+ exit(-1);
+ break;
+ }
+
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ {
+ ERROR("JTAG error while writing target memory");
+ exit(-1);
+ }
+
+ for (i=0; i<=last_reg; i++)
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).dirty = 1;
+
+ arm7_9->read_xpsr(target, &cpsr, 0);
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ {
+ ERROR("JTAG error while reading cpsr");
+ exit(-1);
+ }
+
+ if (((cpsr & 0x1f) == ARMV4_5_MODE_ABT) && (armv4_5->core_mode != ARMV4_5_MODE_ABT))
+ {
+ ERROR("memory write caused data abort");
+
+ arm7_9->write_xpsr_im8(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8), 0, 0);
+
+ return ERROR_TARGET_DATA_ABORT;
+ }
+
+ return ERROR_OK;
+}
+
+int arm7_9_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ enum armv4_5_state core_state = armv4_5->core_state;
+ u32 r0 = buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32);
+ u32 r1 = buf_get_u32(armv4_5->core_cache->reg_list[1].value, 0, 32);
+ u32 pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
+ int i;
+
+ u32 dcc_code[] =
+ {
+ /* MRC TST BNE MRC STR B */
+ 0xee101e10, 0xe3110001, 0x0afffffc, 0xee111e10, 0xe4801004, 0xeafffff9
+ };
+
+ if (!arm7_9->dcc_downloads)
+ return target->type->write_memory(target, address, 4, count, buffer);
+
+ /* regrab previously allocated working_area, or allocate a new one */
+ if (!arm7_9->dcc_working_area)
+ {
+ /* make sure we have a working area */
+ if (target_alloc_working_area(target, 24, &arm7_9->dcc_working_area) != ERROR_OK)
+ {
+ INFO("no working area available, falling back to memory writes");
+ return target->type->write_memory(target, address, 4, count, buffer);
+ }
+
+ /* write DCC code to working area */
+ target->type->write_memory(target, arm7_9->dcc_working_area->address, 4, 6, (u8*)dcc_code);
+ }
+
+ buf_set_u32(armv4_5->core_cache->reg_list[0].value, 0, 32, address);
+ armv4_5->core_cache->reg_list[0].valid = 1;
+ armv4_5->core_cache->reg_list[0].dirty = 1;
+ armv4_5->core_state = ARMV4_5_STATE_ARM;
+
+ arm7_9_resume(target, 0, arm7_9->dcc_working_area->address, 1, 1);
+
+ for (i = 0; i < count; i++)
+ {
+ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], buf_get_u32(buffer, 0, 32));
+ buffer += 4;
+ }
+
+ target->type->halt(target);
+
+ while (target->state != TARGET_HALTED)
+ target->type->poll(target);
+
+ /* restore target state */
+ buf_set_u32(armv4_5->core_cache->reg_list[0].value, 0, 32, r0);
+ armv4_5->core_cache->reg_list[0].valid = 1;
+ armv4_5->core_cache->reg_list[0].dirty = 1;
+ buf_set_u32(armv4_5->core_cache->reg_list[1].value, 0, 32, r1);
+ armv4_5->core_cache->reg_list[1].valid = 1;
+ armv4_5->core_cache->reg_list[1].dirty = 1;
+ buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, pc);
+ armv4_5->core_cache->reg_list[15].valid = 1;
+ armv4_5->core_cache->reg_list[15].dirty = 1;
+ armv4_5->core_state = core_state;
+
+ return ERROR_OK;
+}
+
+int arm7_9_register_commands(struct command_context_s *cmd_ctx)
+{
+ command_t *arm7_9_cmd;
+
+ arm7_9_cmd = register_command(cmd_ctx, NULL, "arm7_9", NULL, COMMAND_ANY, 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>");
+
+ register_command(cmd_ctx, arm7_9_cmd, "write_core_reg", handle_arm7_9_write_core_reg_command, COMMAND_EXEC, "write core register <num> <mode> <value>");
+
+ register_command(cmd_ctx, arm7_9_cmd, "sw_bkpts", handle_arm7_9_sw_bkpts_command, COMMAND_EXEC, "support for software breakpoints <enable|disable>");
+ register_command(cmd_ctx, arm7_9_cmd, "force_hw_bkpts", handle_arm7_9_force_hw_bkpts_command, COMMAND_EXEC, "use hardware breakpoints for all breakpoints (disables sw breakpoint support) <enable|disable>");
+ register_command(cmd_ctx, arm7_9_cmd, "dbgrq", handle_arm7_9_dbgrq_command,
+ COMMAND_ANY, "use EmbeddedICE dbgrq instead of breakpoint for target halt requests <enable|disable>");
+ register_command(cmd_ctx, arm7_9_cmd, "fast_writes", handle_arm7_9_fast_writes_command,
+ COMMAND_ANY, "use fast memory writes instead of slower but potentially unsafe slow writes <enable|disable>");
+ register_command(cmd_ctx, arm7_9_cmd, "dcc_downloads", handle_arm7_9_dcc_downloads_command,
+ COMMAND_ANY, "use DCC downloads for larger memory writes <enable|disable>");
+
+ armv4_5_register_commands(cmd_ctx);
+
+ return ERROR_OK;
+}
+
+int handle_arm7_9_write_xpsr_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ u32 value;
+ int spsr;
+ int retval;
+ target_t *target = get_current_target(cmd_ctx);
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+
+ 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 (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "can't write registers while running");
+ return ERROR_OK;
+ }
+
+ if (argc < 2)
+ {
+ command_print(cmd_ctx, "usage: write_xpsr <value> <not cpsr|spsr>");
+ return ERROR_OK;
+ }
+
+ value = strtoul(args[0], NULL, 0);
+ spsr = strtol(args[1], NULL, 0);
+
+ arm7_9->write_xpsr(target, value, spsr);
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ {
+ ERROR("JTAG error while writing to xpsr");
+ exit(-1);
+ }
+
+ return ERROR_OK;
+}
+
+int handle_arm7_9_write_xpsr_im8_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ u32 value;
+ int rotate;
+ int spsr;
+ int retval;
+ target_t *target = get_current_target(cmd_ctx);
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+
+ 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 (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "can't write registers while running");
+ return ERROR_OK;
+ }
+
+ if (argc < 3)
+ {
+ command_print(cmd_ctx, "usage: write_xpsr_im8 <im8> <rotate> <not cpsr|spsr>");
+ return ERROR_OK;
+ }
+
+ value = strtoul(args[0], NULL, 0);
+ rotate = strtol(args[1], NULL, 0);
+ spsr = strtol(args[2], NULL, 0);
+
+ arm7_9->write_xpsr_im8(target, value, rotate, spsr);
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ {
+ ERROR("JTAG error while writing 8-bit immediate to xpsr");
+ exit(-1);
+ }
+
+ return ERROR_OK;
+}
+
+int handle_arm7_9_write_core_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ u32 value;
+ u32 mode;
+ int num;
+ target_t *target = get_current_target(cmd_ctx);
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+
+ 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 (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "can't write registers while running");
+ return ERROR_OK;
+ }
+
+ if (argc < 3)
+ {
+ command_print(cmd_ctx, "usage: write_core_reg <num> <mode> <value>");
+ return ERROR_OK;
+ }
+
+ num = strtol(args[0], NULL, 0);
+ mode = strtoul(args[1], NULL, 0);
+ value = strtoul(args[2], NULL, 0);
+
+ arm7_9_write_core_reg(target, num, mode, value);
+
+ return ERROR_OK;
+}
+
+int handle_arm7_9_sw_bkpts_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;
+ arm7_9_common_t *arm7_9;
+
+ 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 (argc == 0)
+ {
+ command_print(cmd_ctx, "software breakpoints %s", (arm7_9->sw_bkpts_enabled) ? "enabled" : "disabled");
+ return ERROR_OK;
+ }
+
+ if (strcmp("enable", args[0]) == 0)
+ {
+ if (arm7_9->sw_bkpts_use_wp)
+ {
+ arm7_9_enable_sw_bkpts(target);
+ }
+ else
+ {
+ arm7_9->sw_bkpts_enabled = 1;
+ }
+ }
+ else if (strcmp("disable", args[0]) == 0)
+ {
+ if (arm7_9->sw_bkpts_use_wp)
+ {
+ arm7_9_disable_sw_bkpts(target);
+ }
+ else
+ {
+ arm7_9->sw_bkpts_enabled = 0;
+ }
+ }
+ else
+ {
+ command_print(cmd_ctx, "usage: arm7_9 sw_bkpts <enable|disable>");
+ }
+
+ command_print(cmd_ctx, "software breakpoints %s", (arm7_9->sw_bkpts_enabled) ? "enabled" : "disabled");
+
+ return ERROR_OK;
+}
+
+int handle_arm7_9_force_hw_bkpts_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;
+ arm7_9_common_t *arm7_9;
+
+ 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 ((argc >= 1) && (strcmp("enable", args[0]) == 0))
+ {
+ arm7_9->force_hw_bkpts = 1;
+ if (arm7_9->sw_bkpts_use_wp)
+ {
+ arm7_9_disable_sw_bkpts(target);
+ }
+ }
+ else if ((argc >= 1) && (strcmp("disable", args[0]) == 0))
+ {
+ arm7_9->force_hw_bkpts = 0;
+ }
+ else
+ {
+ command_print(cmd_ctx, "usage: arm7_9 force_hw_bkpts <enable|disable>");
+ }
+
+ command_print(cmd_ctx, "force hardware breakpoints %s", (arm7_9->force_hw_bkpts) ? "enabled" : "disabled");
+
+ return ERROR_OK;
+}
+
+int handle_arm7_9_dbgrq_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;
+ arm7_9_common_t *arm7_9;
+
+ 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 (argc > 0)
+ {
+ if (strcmp("enable", args[0]) == 0)
+ {
+ arm7_9->use_dbgrq = 1;
+ }
+ else if (strcmp("disable", args[0]) == 0)
+ {
+ arm7_9->use_dbgrq = 0;
+ }
+ else
+ {
+ command_print(cmd_ctx, "usage: arm7_9 dbgrq <enable|disable>");
+ }
+ }
+
+ command_print(cmd_ctx, "use of EmbeddedICE dbgrq instead of breakpoint for target halt %s", (arm7_9->use_dbgrq) ? "enabled" : "disabled");
+
+ return ERROR_OK;
+}
+
+int handle_arm7_9_fast_writes_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;
+ arm7_9_common_t *arm7_9;
+
+ 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 (argc > 0)
+ {
+ if (strcmp("enable", args[0]) == 0)
+ {
+ arm7_9->fast_memory_writes = 1;
+ }
+ else if (strcmp("disable", args[0]) == 0)
+ {
+ arm7_9->fast_memory_writes = 0;
+ }
+ else
+ {
+ command_print(cmd_ctx, "usage: arm7_9 fast_writes <enable|disable>");
+ }
+ }
+
+ command_print(cmd_ctx, "fast memory writes are %s", (arm7_9->fast_memory_writes) ? "enabled" : "disabled");
+
+ return ERROR_OK;
+}
+
+int handle_arm7_9_dcc_downloads_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;
+ arm7_9_common_t *arm7_9;
+
+ 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 (argc > 0)
+ {
+ if (strcmp("enable", args[0]) == 0)
+ {
+ arm7_9->dcc_downloads = 1;
+ }
+ else if (strcmp("disable", args[0]) == 0)
+ {
+ arm7_9->dcc_downloads = 0;
+ }
+ else
+ {
+ command_print(cmd_ctx, "usage: arm7_9 dcc_downloads <enable|disable>");
+ }
+ }
+
+ command_print(cmd_ctx, "dcc downloads are %s", (arm7_9->dcc_downloads) ? "enabled" : "disabled");
+
+ 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;
+
+ arm7_9->common_magic = ARM7_9_COMMON_MAGIC;
+
+ arm_jtag_setup_connection(&arm7_9->jtag_info);
+ arm7_9->wp_available = 2;
+ arm7_9->wp0_used = 0;
+ arm7_9->wp1_used = 0;
+ arm7_9->force_hw_bkpts = 0;
+ arm7_9->use_dbgrq = 0;
+ arm7_9->has_etm = 0;
+
+ arm7_9->reinit_embeddedice = 0;
+
+ arm7_9->dcc_working_area = NULL;
+
+ arm7_9->fast_memory_writes = 0;
+ arm7_9->dcc_downloads = 0;
+
+ jtag_register_event_callback(arm7_9_jtag_callback, target);
+
+ armv4_5->arch_info = arm7_9;
+ armv4_5->read_core_reg = arm7_9_read_core_reg;
+ armv4_5->write_core_reg = arm7_9_write_core_reg;
+ armv4_5->full_context = arm7_9_full_context;
+
+ armv4_5_init_arch_info(target, armv4_5);
+
+ return ERROR_OK;
+}
diff --git a/src/target/arm7_9_common.h b/src/target/arm7_9_common.h
new file mode 100644
index 00000000..f03ae496
--- /dev/null
+++ b/src/target/arm7_9_common.h
@@ -0,0 +1,129 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef ARM7_9_COMMON_H
+#define ARM7_9_COMMON_H
+
+#include "armv4_5.h"
+#include "arm_jtag.h"
+#include "breakpoints.h"
+#include "target.h"
+
+#define ARM7_9_COMMON_MAGIC 0x0a790a79
+
+typedef struct arm7_9_common_s
+{
+ int common_magic;
+
+ arm_jtag_t jtag_info;
+ reg_cache_t *eice_cache;
+ reg_cache_t *etm_cache;
+
+ u32 arm_bkpt;
+ u16 thumb_bkpt;
+ int sw_bkpts_use_wp;
+ int wp_available;
+ int wp0_used;
+ int wp1_used;
+ int sw_bkpts_enabled;
+ int force_hw_bkpts;
+ int dbgreq_adjust_pc;
+ int use_dbgrq;
+ int has_etm;
+
+ int reinit_embeddedice;
+
+ struct working_area_s *dcc_working_area;
+
+ int fast_memory_writes;
+ int dcc_downloads;
+
+ int (*examine_debug_reason)(target_t *target);
+
+ void (*change_to_arm)(target_t *target, u32 *r0, u32 *pc);
+
+ void (*read_core_regs)(target_t *target, u32 mask, u32* core_regs[16]);
+ void (*read_xpsr)(target_t *target, u32 *xpsr, int spsr);
+
+ void (*write_xpsr)(target_t *target, u32 xpsr, int spsr);
+ void (*write_xpsr_im8)(target_t *target, u8 xpsr_im, int rot, int spsr);
+ void (*write_core_regs)(target_t *target, u32 mask, u32 core_regs[16]);
+
+ void (*load_word_regs)(target_t *target, u32 mask);
+ void (*load_hword_reg)(target_t *target, int num);
+ void (*load_byte_reg)(target_t *target, int num);
+
+ void (*store_word_regs)(target_t *target, u32 mask);
+ void (*store_hword_reg)(target_t *target, int num);
+ void (*store_byte_reg)(target_t *target, int num);
+
+ void (*write_pc)(target_t *target, u32 pc);
+ void (*branch_resume)(target_t *target);
+ void (*branch_resume_thumb)(target_t *target);
+
+ void (*enable_single_step)(target_t *target);
+ void (*disable_single_step)(target_t *target);
+
+ void (*pre_debug_entry)(target_t *target);
+ void (*post_debug_entry)(target_t *target);
+
+ void (*pre_restore_context)(target_t *target);
+ void (*post_restore_context)(target_t *target);
+
+ armv4_5_common_t armv4_5_common;
+ void *arch_info;
+
+} arm7_9_common_t;
+
+int arm7_9_register_commands(struct command_context_s *cmd_ctx);
+
+enum target_state arm7_9_poll(target_t *target);
+
+int arm7_9_assert_reset(target_t *target);
+int arm7_9_deassert_reset(target_t *target);
+int arm7_9_reset_request_halt(target_t *target);
+int arm7_9_early_halt(target_t *target);
+int arm7_9_soft_reset_halt(struct target_s *target);
+
+int arm7_9_halt(target_t *target);
+int arm7_9_debug_entry(target_t *target);
+int arm7_9_full_context(target_t *target);
+int arm7_9_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution);
+int arm7_9_step(struct target_s *target, int current, u32 address, int handle_breakpoints);
+int arm7_9_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode);
+int arm7_9_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
+int arm7_9_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
+int arm7_9_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer);
+
+int arm7_9_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_prams, reg_param_t *reg_param, u32 entry_point, void *arch_info);
+
+int arm7_9_add_breakpoint(struct target_s *target, u32 address, u32 length, enum breakpoint_type type);
+int arm7_9_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint);
+int arm7_9_add_watchpoint(struct target_s *target, u32 address, u32 length, enum watchpoint_rw rw);
+int arm7_9_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint);
+
+void arm7_9_enable_eice_step(target_t *target);
+void arm7_9_disable_eice_step(target_t *target);
+
+int arm7_9_execute_sys_speed(struct target_s *target);
+
+int arm7_9_init_arch_info(target_t *target, arm7_9_common_t *arm7_9);
+
+
+#endif /* ARM7_9_COMMON_H */
diff --git a/src/target/arm7tdmi.c b/src/target/arm7tdmi.c
new file mode 100644
index 00000000..c2079477
--- /dev/null
+++ b/src/target/arm7tdmi.c
@@ -0,0 +1,780 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "config.h"
+
+#include "arm7tdmi.h"
+
+#include "arm7_9_common.h"
+#include "register.h"
+#include "target.h"
+#include "armv4_5.h"
+#include "embeddedice.h"
+#include "etm.h"
+#include "log.h"
+#include "jtag.h"
+#include "arm_jtag.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#if 0
+#define _DEBUG_INSTRUCTION_EXECUTION_
+#endif
+
+/* cli handling */
+int arm7tdmi_register_commands(struct command_context_s *cmd_ctx);
+
+/* forward declarations */
+int arm7tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
+int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
+int arm7tdmi_quit();
+
+/* target function declarations */
+enum target_state arm7tdmi_poll(struct target_s *target);
+int arm7tdmi_halt(target_t *target);
+int arm7tdmi_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
+
+target_type_t arm7tdmi_target =
+{
+ .name = "arm7tdmi",
+
+ .poll = arm7_9_poll,
+ .arch_state = armv4_5_arch_state,
+
+ .halt = arm7_9_halt,
+ .resume = arm7_9_resume,
+ .step = arm7_9_step,
+
+ .assert_reset = arm7_9_assert_reset,
+ .deassert_reset = arm7_9_deassert_reset,
+ .soft_reset_halt = arm7_9_soft_reset_halt,
+
+ .get_gdb_reg_list = armv4_5_get_gdb_reg_list,
+
+ .read_memory = arm7_9_read_memory,
+ .write_memory = arm7_9_write_memory,
+ .bulk_write_memory = arm7_9_bulk_write_memory,
+
+ .run_algorithm = armv4_5_run_algorithm,
+
+ .add_breakpoint = arm7_9_add_breakpoint,
+ .remove_breakpoint = arm7_9_remove_breakpoint,
+ .add_watchpoint = arm7_9_add_watchpoint,
+ .remove_watchpoint = arm7_9_remove_watchpoint,
+
+ .register_commands = arm7tdmi_register_commands,
+ .target_command = arm7tdmi_target_command,
+ .init_target = arm7tdmi_init_target,
+ .quit = arm7tdmi_quit
+};
+
+int arm7tdmi_examine_debug_reason(target_t *target)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ /* only check the debug reason if we don't know it already */
+ if ((target->debug_reason != DBG_REASON_DBGRQ)
+ && (target->debug_reason != DBG_REASON_SINGLESTEP))
+ {
+ scan_field_t fields[2];
+ u8 databus[4];
+ u8 breakpoint;
+
+ jtag_add_end_state(TAP_PD);
+
+ fields[0].device = arm7_9->jtag_info.chain_pos;
+ fields[0].num_bits = 1;
+ fields[0].out_value = NULL;
+ fields[0].out_mask = NULL;
+ fields[0].in_value = &breakpoint;
+ 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 = arm7_9->jtag_info.chain_pos;
+ fields[1].num_bits = 32;
+ fields[1].out_value = NULL;
+ fields[1].out_mask = NULL;
+ fields[1].in_value = databus;
+ fields[1].in_check_value = NULL;
+ fields[1].in_check_mask = NULL;
+ fields[1].in_handler = NULL;
+ fields[1].in_handler_priv = NULL;
+
+ arm_jtag_scann(&arm7_9->jtag_info, 0x1);
+ arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr);
+
+ jtag_add_dr_scan(2, fields, TAP_PD);
+ jtag_execute_queue();
+
+ fields[0].in_value = NULL;
+ fields[0].out_value = &breakpoint;
+ fields[1].in_value = NULL;
+ fields[1].out_value = databus;
+
+ jtag_add_dr_scan(2, fields, TAP_PD);
+
+ if (breakpoint & 1)
+ target->debug_reason = DBG_REASON_WATCHPOINT;
+ else
+ target->debug_reason = DBG_REASON_BREAKPOINT;
+ }
+
+ return ERROR_OK;
+}
+
+/* put an instruction in the ARM7TDMI pipeline or write the data bus, and optionally read data */
+int arm7tdmi_clock_out(arm_jtag_t *jtag_info, u32 out, u32 *in, int breakpoint)
+{
+ scan_field_t fields[2];
+ u8 out_buf[4];
+ u8 breakpoint_buf;
+
+ out = flip_u32(out, 32);
+ buf_set_u32(out_buf, 0, 32, out);
+ buf_set_u32(&breakpoint_buf, 0, 1, breakpoint);
+
+ jtag_add_end_state(TAP_PD);
+ arm_jtag_scann(jtag_info, 0x1);
+ arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
+
+ fields[0].device = jtag_info->chain_pos;
+ fields[0].num_bits = 1;
+ fields[0].out_value = &breakpoint_buf;
+ 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 = jtag_info->chain_pos;
+ fields[1].num_bits = 32;
+ fields[1].out_value = out_buf;
+ fields[1].out_mask = NULL;
+ if (in)
+ {
+ fields[1].in_value = (u8*)in;
+ fields[1].in_handler = arm_jtag_buf_to_u32_flip;
+ fields[1].in_handler_priv = in;
+ } else
+ {
+ fields[1].in_value = NULL;
+ fields[1].in_handler = NULL;
+ fields[1].in_handler_priv = NULL;
+ }
+
+ fields[1].in_check_value = NULL;
+ fields[1].in_check_mask = NULL;
+
+ jtag_add_dr_scan(2, fields, -1);
+
+ jtag_add_runtest(0, -1);
+
+#ifdef _DEBUG_INSTRUCTION_EXECUTION_
+{
+ char* in_string;
+ jtag_execute_queue();
+
+ if (in)
+ {
+ in_string = buf_to_char((u8*)in, 32);
+ DEBUG("out: 0x%8.8x, in: %s", flip_u32(out, 32), in_string);
+ free(in_string);
+ }
+ else
+ DEBUG("out: 0x%8.8x", flip_u32(out, 32));
+}
+#endif
+
+ return ERROR_OK;
+}
+
+/* put an instruction in the ARM7TDMI pipeline, and optionally read data */
+int arm7tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in)
+{
+ scan_field_t fields[2];
+
+ jtag_add_end_state(TAP_PD);
+ arm_jtag_scann(jtag_info, 0x1);
+ arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
+
+ fields[0].device = jtag_info->chain_pos;
+ fields[0].num_bits = 1;
+ 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 = jtag_info->chain_pos;
+ fields[1].num_bits = 32;
+ fields[1].out_value = NULL;
+ fields[1].out_mask = NULL;
+ fields[1].in_value = (u8*)in;
+ fields[1].in_handler = arm_jtag_buf_to_u32_flip;
+ fields[1].in_handler_priv = in;
+ fields[1].in_check_value = NULL;
+ fields[1].in_check_mask = NULL;
+
+ jtag_add_dr_scan(2, fields, -1);
+
+ jtag_add_runtest(0, -1);
+
+#ifdef _DEBUG_INSTRUCTION_EXECUTION_
+{
+ char* in_string;
+ jtag_execute_queue();
+
+ if (in)
+ {
+ in_string = buf_to_char((u8*)in, 32);
+ DEBUG("in: %s", in_string);
+ free(in_string);
+ }
+}
+#endif
+
+ return ERROR_OK;
+}
+
+void arm7tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* save r0 before using it and put system in ARM state
+ * to allow common handling of ARM and THUMB debugging */
+
+ /* fetch STR r0, [r0] */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
+ /* nothing fetched, STR r0, [r0] in Execute (2) */
+ arm7tdmi_clock_data_in(jtag_info, r0);
+
+ /* MOV r0, r15 fetched, STR in Decode */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), NULL, 0);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
+ /* nothing fetched, STR r0, [r0] in Execute (2) */
+ arm7tdmi_clock_data_in(jtag_info, pc);
+
+ /* fetch MOV */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV_IM(0, 0x0), NULL, 0);
+
+ /* fetch BX */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), NULL, 0);
+ /* NOP fetched, BX in Decode, MOV in Execute */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
+ /* NOP fetched, BX in Execute (1) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
+
+ jtag_execute_queue();
+
+ /* fix program counter:
+ * MOV r0, r15 was the 4th instruction (+6)
+ * reading PC in Thumb state gives address of instruction + 4
+ */
+ *pc -= 0xa;
+
+}
+
+void arm7tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16])
+{
+ int i;
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* STMIA r0-15, [r0] at debug speed
+ * register values will start to appear on 4th DCLK
+ */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0);
+
+ /* fetch NOP, STM in DECODE stage */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* fetch NOP, STM in EXECUTE stage (1st cycle) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+
+ for (i = 0; i <= 15; i++)
+ {
+ if (mask & (1 << i))
+ /* nothing fetched, STM still in EXECUTE (1+i cycle) */
+ arm7tdmi_clock_data_in(jtag_info, core_regs[i]);
+ }
+
+}
+
+void arm7tdmi_read_xpsr(target_t *target, u32 *xpsr, int spsr)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* MRS r0, cpsr */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), NULL, 0);
+
+ /* STR r0, [r15] */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), NULL, 0);
+ /* fetch NOP, STR in DECODE stage */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* fetch NOP, STR in EXECUTE stage (1st cycle) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* nothing fetched, STR still in EXECUTE (2nd cycle) */
+ arm7tdmi_clock_data_in(jtag_info, xpsr);
+
+}
+
+void arm7tdmi_write_xpsr(target_t *target, u32 xpsr, int spsr)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ DEBUG("xpsr: %8.8x, spsr: %i", xpsr, spsr);
+
+ /* MSR1 fetched */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), NULL, 0);
+ /* MSR2 fetched, MSR1 in DECODE */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), NULL, 0);
+ /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), NULL, 0);
+ /* nothing fetched, MSR1 in EXECUTE (2) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), NULL, 0);
+ /* nothing fetched, MSR2 in EXECUTE (2) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* nothing fetched, MSR3 in EXECUTE (2) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* NOP fetched, MSR4 in EXECUTE (1) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* nothing fetched, MSR4 in EXECUTE (2) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+}
+
+void arm7tdmi_write_xpsr_im8(target_t *target, u8 xpsr_im, int rot, int spsr)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr);
+
+ /* MSR fetched */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), NULL, 0);
+ /* NOP fetched, MSR in DECODE */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* NOP fetched, MSR in EXECUTE (1) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* nothing fetched, MSR in EXECUTE (2) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+
+}
+
+void arm7tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16])
+{
+ int i;
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* LDMIA r0-15, [r0] at debug speed
+ * register values will start to appear on 4th DCLK
+ */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), NULL, 0);
+
+ /* fetch NOP, LDM in DECODE stage */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* fetch NOP, LDM in EXECUTE stage (1st cycle) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+
+ for (i = 0; i <= 15; i++)
+ {
+ if (mask & (1 << i))
+ /* nothing fetched, LDM still in EXECUTE (1+i cycle) */
+ arm7tdmi_clock_out(jtag_info, core_regs[i], NULL, 0);
+ }
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+
+}
+
+void arm7tdmi_load_word_regs(target_t *target, u32 mask)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* put system-speed load-multiple into the pipeline */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), NULL, 0);
+
+}
+
+void arm7tdmi_load_hword_reg(target_t *target, int num)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* put system-speed load half-word into the pipeline */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), NULL, 0);
+
+}
+
+void arm7tdmi_load_byte_reg(target_t *target, int num)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* put system-speed load byte into the pipeline */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), NULL, 0);
+
+}
+
+void arm7tdmi_store_word_regs(target_t *target, u32 mask)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* put system-speed store-multiple into the pipeline */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), NULL, 0);
+
+}
+
+void arm7tdmi_store_hword_reg(target_t *target, int num)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* put system-speed store half-word into the pipeline */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), NULL, 0);
+
+}
+
+void arm7tdmi_store_byte_reg(target_t *target, int num)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* put system-speed store byte into the pipeline */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), NULL, 0);
+
+}
+
+void arm7tdmi_write_pc(target_t *target, u32 pc)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* LDMIA r0-15, [r0] at debug speed
+ * register values will start to appear on 4th DCLK
+ */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), NULL, 0);
+ /* fetch NOP, LDM in DECODE stage */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* fetch NOP, LDM in EXECUTE stage (1st cycle) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* nothing fetched, LDM in EXECUTE stage (1st cycle) load register */
+ arm7tdmi_clock_out(jtag_info, pc, NULL, 0);
+ /* nothing fetched, LDM in EXECUTE stage (2nd cycle) load register */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* nothing fetched, LDM in EXECUTE stage (3rd cycle) load register */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* fetch NOP, LDM in EXECUTE stage (4th cycle) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* fetch NOP, LDM in EXECUTE stage (5th cycle) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+}
+
+void arm7tdmi_branch_resume(target_t *target)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffa, 0), NULL, 0);
+
+}
+
+void arm7tdmi_branch_resume_thumb(target_t *target)
+{
+ DEBUG("");
+
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+ reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
+
+ /* LDMIA r0, [r0] at debug speed
+ * register values will start to appear on 4th DCLK
+ */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), NULL, 0);
+
+ /* fetch NOP, LDM in DECODE stage */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* fetch NOP, LDM in EXECUTE stage (1st cycle) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+ /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */
+ arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) | 1, NULL, 0);
+ /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+
+ /* Branch and eXchange */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_BX(0), NULL, 0);
+
+ embeddedice_read_reg(dbg_stat);
+
+ /* fetch NOP, BX in DECODE stage */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+
+ /* target is now in Thumb state */
+ embeddedice_read_reg(dbg_stat);
+
+ /* fetch NOP, BX in EXECUTE stage (1st cycle) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
+
+ /* target is now in Thumb state */
+ embeddedice_read_reg(dbg_stat);
+
+ /* clean r0 bits to avoid alignment problems */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV_IM(0, 0x0), NULL, 0);
+ /* load r0 value, MOV_IM in Decode*/
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR(0, 0), NULL, 0);
+ /* fetch NOP, LDR in Decode, MOV_IM in Execute */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
+ /* fetch NOP, LDR in Execute */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
+ /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */
+ arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32), NULL, 0);
+ /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
+
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
+
+ embeddedice_read_reg(dbg_stat);
+
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 1);
+ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f7), NULL, 0);
+
+}
+
+void arm7tdmi_build_reg_cache(target_t *target)
+{
+ reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+ arm7tdmi_common_t *arch_info = arm7_9->arch_info;
+
+
+ (*cache_p) = armv4_5_build_reg_cache(target, armv4_5);
+ armv4_5->core_cache = (*cache_p);
+
+ (*cache_p)->next = embeddedice_build_reg_cache(target, jtag_info, 0);
+ arm7_9->eice_cache = (*cache_p)->next;
+
+ if (arm7_9->has_etm)
+ {
+ (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, 0);
+ arm7_9->etm_cache = (*cache_p)->next->next;
+ }
+
+ if (arch_info->has_monitor_mode)
+ (*cache_p)->next->reg_list[0].size = 6;
+ else
+ (*cache_p)->next->reg_list[0].size = 3;
+
+ (*cache_p)->next->reg_list[1].size = 5;
+
+}
+
+int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
+{
+
+ arm7tdmi_build_reg_cache(target);
+
+ return ERROR_OK;
+
+}
+
+int arm7tdmi_quit()
+{
+
+ return ERROR_OK;
+}
+
+int arm7tdmi_init_arch_info(target_t *target, arm7tdmi_common_t *arm7tdmi, int chain_pos, char *variant)
+{
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ int has_etm = 0;
+
+ arm7_9 = &arm7tdmi->arm7_9_common;
+ armv4_5 = &arm7_9->armv4_5_common;
+
+ /* prepare JTAG information for the new target */
+ arm7_9->jtag_info.chain_pos = chain_pos;
+ arm7_9->jtag_info.scann_size = 4;
+
+ /* register arch-specific functions */
+ arm7_9->examine_debug_reason = arm7tdmi_examine_debug_reason;
+ arm7_9->change_to_arm = arm7tdmi_change_to_arm;
+ arm7_9->read_core_regs = arm7tdmi_read_core_regs;
+ arm7_9->read_xpsr = arm7tdmi_read_xpsr;
+
+ arm7_9->write_xpsr = arm7tdmi_write_xpsr;
+ arm7_9->write_xpsr_im8 = arm7tdmi_write_xpsr_im8;
+ arm7_9->write_core_regs = arm7tdmi_write_core_regs;
+
+ arm7_9->load_word_regs = arm7tdmi_load_word_regs;
+ arm7_9->load_hword_reg = arm7tdmi_load_hword_reg;
+ arm7_9->load_byte_reg = arm7tdmi_load_byte_reg;
+
+ arm7_9->store_word_regs = arm7tdmi_store_word_regs;
+ arm7_9->store_hword_reg = arm7tdmi_store_hword_reg;
+ arm7_9->store_byte_reg = arm7tdmi_store_byte_reg;
+
+ arm7_9->write_pc = arm7tdmi_write_pc;
+ arm7_9->branch_resume = arm7tdmi_branch_resume;
+ arm7_9->branch_resume_thumb = arm7tdmi_branch_resume_thumb;
+
+ arm7_9->enable_single_step = arm7_9_enable_eice_step;
+ arm7_9->disable_single_step = arm7_9_disable_eice_step;
+
+ arm7_9->pre_debug_entry = NULL;
+ arm7_9->post_debug_entry = NULL;
+
+ arm7_9->pre_restore_context = NULL;
+ arm7_9->post_restore_context = NULL;
+
+ /* initialize arch-specific breakpoint handling */
+ buf_set_u32((u8*)(&arm7_9->arm_bkpt), 0, 32, 0xdeeedeee);
+ buf_set_u32((u8*)(&arm7_9->thumb_bkpt), 0, 16, 0xdeee);
+
+ arm7_9->sw_bkpts_use_wp = 1;
+ arm7_9->sw_bkpts_enabled = 0;
+ arm7_9->dbgreq_adjust_pc = 2;
+ arm7_9->arch_info = arm7tdmi;
+
+ arm7tdmi->has_monitor_mode = 0;
+ arm7tdmi->arch_info = NULL;
+ arm7tdmi->common_magic = ARM7TDMI_COMMON_MAGIC;
+
+ if (variant)
+ {
+ if (strcmp(variant, "arm7tdmi-s_r4") == 0)
+ arm7tdmi->has_monitor_mode = 1;
+ else if (strcmp(variant, "arm7tdmi_r4") == 0)
+ arm7tdmi->has_monitor_mode = 1;
+ else if (strcmp(variant, "lpc2000") == 0)
+ {
+ arm7tdmi->has_monitor_mode = 1;
+ has_etm = 1;
+ }
+ arm7tdmi->variant = strdup(variant);
+ }
+ else
+ arm7tdmi->variant = strdup("");
+
+ arm7_9_init_arch_info(target, arm7_9);
+
+ arm7_9->has_etm = has_etm;
+
+ return ERROR_OK;
+}
+
+/* target arm7tdmi <endianess> <startup_mode> <chain_pos> <variant> */
+int arm7tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
+{
+ int chain_pos;
+ char *variant = NULL;
+ arm7tdmi_common_t *arm7tdmi = malloc(sizeof(arm7tdmi_common_t));
+
+ if (argc < 4)
+ {
+ ERROR("'target arm7tdmi' requires at least one additional argument");
+ exit(-1);
+ }
+
+ chain_pos = strtoul(args[2], NULL, 0);
+
+ if (argc >= 5)
+ variant = args[4];
+
+ arm7tdmi_init_arch_info(target, arm7tdmi, chain_pos, variant);
+
+ return ERROR_OK;
+}
+
+int arm7tdmi_register_commands(struct command_context_s *cmd_ctx)
+{
+ int retval;
+
+ retval = arm7_9_register_commands(cmd_ctx);
+
+ return ERROR_OK;
+
+}
+
diff --git a/src/target/arm7tdmi.h b/src/target/arm7tdmi.h
new file mode 100644
index 00000000..ca2df8b6
--- /dev/null
+++ b/src/target/arm7tdmi.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef ARM7TDMI_H
+#define ARM7TDMI_H
+
+#include "target.h"
+#include "register.h"
+#include "armv4_5.h"
+#include "embeddedice.h"
+#include "arm_jtag.h"
+#include "arm7_9_common.h"
+
+#define ARM7TDMI_COMMON_MAGIC 0x00a700a7
+
+typedef struct arm7tdmi_common_s
+{
+ int common_magic;
+ char *variant;
+ int has_monitor_mode;
+ void *arch_info;
+ arm7_9_common_t arm7_9_common;
+} arm7tdmi_common_t;
+
+int arm7tdmi_register_commands(struct command_context_s *cmd_ctx);
+int arm7tdmi_init_arch_info(target_t *target, arm7tdmi_common_t *arm7tdmi, int chain_pos, char *variant);
+int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
+
+
+#endif /* ARM7TDMI_H */
diff --git a/src/target/arm920t.c b/src/target/arm920t.c
new file mode 100644
index 00000000..eb0fa7df
--- /dev/null
+++ b/src/target/arm920t.c
@@ -0,0 +1,967 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "config.h"
+
+#include "arm920t.h"
+#include "jtag.h"
+#include "log.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#if 0
+#define _DEBUG_INSTRUCTION_EXECUTION_
+#endif
+
+/* cli handling */
+int arm920t_register_commands(struct command_context_s *cmd_ctx);
+
+int arm920t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int arm920t_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int arm920t_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int arm920t_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int arm920t_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int arm920t_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+/* forward declarations */
+int arm920t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
+int arm920t_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
+int arm920t_quit();
+int arm920t_arch_state(struct target_s *target, char *buf, int buf_size);
+int arm920t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
+int arm920t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
+int arm920t_soft_reset_halt(struct target_s *target);
+
+target_type_t arm920t_target =
+{
+ .name = "arm920t",
+
+ .poll = arm7_9_poll,
+ .arch_state = arm920t_arch_state,
+
+ .halt = arm7_9_halt,
+ .resume = arm7_9_resume,
+ .step = arm7_9_step,
+
+ .assert_reset = arm7_9_assert_reset,
+ .deassert_reset = arm7_9_deassert_reset,
+ .soft_reset_halt = arm920t_soft_reset_halt,
+
+ .get_gdb_reg_list = armv4_5_get_gdb_reg_list,
+
+ .read_memory = arm920t_read_memory,
+ .write_memory = arm920t_write_memory,
+ .bulk_write_memory = arm7_9_bulk_write_memory,
+
+ .run_algorithm = armv4_5_run_algorithm,
+
+ .add_breakpoint = arm7_9_add_breakpoint,
+ .remove_breakpoint = arm7_9_remove_breakpoint,
+ .add_watchpoint = arm7_9_add_watchpoint,
+ .remove_watchpoint = arm7_9_remove_watchpoint,
+
+ .register_commands = arm920t_register_commands,
+ .target_command = arm920t_target_command,
+ .init_target = arm920t_init_target,
+ .quit = arm920t_quit
+};
+
+int arm920t_read_cp15_physical(target_t *target, int reg_addr, u32 *value)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+ scan_field_t fields[4];
+ u8 access_type_buf = 1;
+ u8 reg_addr_buf = reg_addr & 0x3f;
+ u8 nr_w_buf = 0;
+
+ jtag_add_end_state(TAP_RTI);
+ arm_jtag_scann(jtag_info, 0xf);
+ arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
+
+ fields[0].device = jtag_info->chain_pos;
+ fields[0].num_bits = 1;
+ fields[0].out_value = &access_type_buf;
+ 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 = jtag_info->chain_pos;
+ fields[1].num_bits = 32;
+ fields[1].out_value = NULL;
+ 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 = jtag_info->chain_pos;
+ fields[2].num_bits = 6;
+ fields[2].out_value = &reg_addr_buf;
+ 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;
+
+ fields[3].device = jtag_info->chain_pos;
+ fields[3].num_bits = 1;
+ fields[3].out_value = &nr_w_buf;
+ fields[3].out_mask = NULL;
+ fields[3].in_value = NULL;
+ fields[3].in_check_value = NULL;
+ fields[3].in_check_mask = NULL;
+ fields[3].in_handler = NULL;
+ fields[3].in_handler_priv = NULL;
+
+ jtag_add_dr_scan(4, fields, -1);
+
+ fields[1].in_value = (u8*)value;
+
+ jtag_add_dr_scan(4, fields, -1);
+
+ return ERROR_OK;
+}
+
+int arm920t_write_cp15_physical(target_t *target, int reg_addr, u32 value)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+ scan_field_t fields[4];
+ u8 access_type_buf = 1;
+ u8 reg_addr_buf = reg_addr & 0x3f;
+ u8 nr_w_buf = 1;
+
+ jtag_add_end_state(TAP_RTI);
+ arm_jtag_scann(jtag_info, 0xf);
+ arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
+
+ fields[0].device = jtag_info->chain_pos;
+ fields[0].num_bits = 1;
+ fields[0].out_value = &access_type_buf;
+ 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 = jtag_info->chain_pos;
+ fields[1].num_bits = 32;
+ fields[1].out_value = (u8*)&value;
+ 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 = jtag_info->chain_pos;
+ fields[2].num_bits = 6;
+ fields[2].out_value = &reg_addr_buf;
+ 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;
+
+ fields[3].device = jtag_info->chain_pos;
+ fields[3].num_bits = 1;
+ fields[3].out_value = &nr_w_buf;
+ fields[3].out_mask = NULL;
+ fields[3].in_value = NULL;
+ fields[3].in_check_value = NULL;
+ fields[3].in_check_mask = NULL;
+ fields[3].in_handler = NULL;
+ fields[3].in_handler_priv = NULL;
+
+ jtag_add_dr_scan(4, fields, -1);
+
+ return ERROR_OK;
+}
+
+int arm920t_read_cp15_interpreted(target_t *target, u32 opcode, u32 *value)
+{
+ u32 cp15c15 = 0x0;
+ scan_field_t fields[4];
+ u8 access_type_buf = 0; /* interpreted access */
+ u8 reg_addr_buf = 0x0;
+ u8 nr_w_buf = 0;
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+ u32* context_p[1];
+
+ /* read-modify-write CP15 test state register
+ * to enable interpreted access mode */
+ arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
+ jtag_execute_queue();
+ cp15c15 |= 1; /* set interpret mode */
+ arm920t_write_cp15_physical(target, 0x1e, cp15c15);
+
+ jtag_add_end_state(TAP_RTI);
+ arm_jtag_scann(jtag_info, 0xf);
+ arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
+
+ fields[0].device = jtag_info->chain_pos;
+ fields[0].num_bits = 1;
+ fields[0].out_value = &access_type_buf;
+ 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 = jtag_info->chain_pos;
+ fields[1].num_bits = 32;
+ fields[1].out_value = (u8*)&opcode;
+ 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 = jtag_info->chain_pos;
+ fields[2].num_bits = 6;
+ fields[2].out_value = &reg_addr_buf;
+ 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;
+
+ fields[3].device = jtag_info->chain_pos;
+ fields[3].num_bits = 1;
+ fields[3].out_value = &nr_w_buf;
+ fields[3].out_mask = NULL;
+ fields[3].in_value = NULL;
+ fields[3].in_check_value = NULL;
+ fields[3].in_check_mask = NULL;
+ fields[3].in_handler = NULL;
+ fields[3].in_handler_priv = NULL;
+
+ jtag_add_dr_scan(4, fields, -1);
+
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDR(0, 15), 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
+ arm7_9_execute_sys_speed(target);
+ jtag_execute_queue();
+
+ /* read-modify-write CP15 test state register
+ * to disable interpreted access mode */
+ arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
+ jtag_execute_queue();
+ cp15c15 &= ~1U; /* clear interpret mode */
+ arm920t_write_cp15_physical(target, 0x1e, cp15c15);
+
+ context_p[0] = value;
+ arm9tdmi_read_core_regs(target, 0x1, context_p);
+ jtag_execute_queue();
+
+ DEBUG("opcode: %8.8x, value: %8.8x", opcode, *value);
+
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = 1;
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 15).dirty = 1;
+
+ return ERROR_OK;
+}
+
+int arm920t_write_cp15_interpreted(target_t *target, u32 opcode, u32 value, u32 address)
+{
+ u32 cp15c15 = 0x0;
+ scan_field_t fields[4];
+ u8 access_type_buf = 0; /* interpreted access */
+ u8 reg_addr_buf = 0x0;
+ u8 nr_w_buf = 0;
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+ u32 regs[2];
+
+ regs[0] = value;
+ regs[1] = address;
+
+ arm9tdmi_write_core_regs(target, 0x3, regs);
+
+ /* read-modify-write CP15 test state register
+ * to enable interpreted access mode */
+ arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
+ jtag_execute_queue();
+ cp15c15 |= 1; /* set interpret mode */
+ arm920t_write_cp15_physical(target, 0x1e, cp15c15);
+
+ jtag_add_end_state(TAP_RTI);
+ arm_jtag_scann(jtag_info, 0xf);
+ arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
+
+ fields[0].device = jtag_info->chain_pos;
+ fields[0].num_bits = 1;
+ fields[0].out_value = &access_type_buf;
+ 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 = jtag_info->chain_pos;
+ fields[1].num_bits = 32;
+ fields[1].out_value = (u8*)&opcode;
+ 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 = jtag_info->chain_pos;
+ fields[2].num_bits = 6;
+ fields[2].out_value = &reg_addr_buf;
+ 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;
+
+ fields[3].device = jtag_info->chain_pos;
+ fields[3].num_bits = 1;
+ fields[3].out_value = &nr_w_buf;
+ fields[3].out_mask = NULL;
+ fields[3].in_value = NULL;
+ fields[3].in_check_value = NULL;
+ fields[3].in_check_mask = NULL;
+ fields[3].in_handler = NULL;
+ fields[3].in_handler_priv = NULL;
+
+ jtag_add_dr_scan(4, fields, -1);
+
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 1), 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
+ arm7_9_execute_sys_speed(target);
+ jtag_execute_queue();
+
+ /* read-modify-write CP15 test state register
+ * to disable interpreted access mode */
+ arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
+ jtag_execute_queue();
+ cp15c15 &= ~1U; /* set interpret mode */
+ arm920t_write_cp15_physical(target, 0x1e, cp15c15);
+
+ DEBUG("opcode: %8.8x, value: %8.8x, address: %8.8x", opcode, value, address);
+
+ return ERROR_OK;
+}
+
+u32 arm920t_get_ttb(target_t *target)
+{
+ int retval;
+ u32 ttb = 0x0;
+
+ if ((retval = arm920t_read_cp15_interpreted(target, 0xeebf0f51, &ttb)) != ERROR_OK)
+ return retval;
+
+ return ttb;
+}
+
+void arm920t_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
+{
+ u32 cp15_control;
+
+ /* read cp15 control register */
+ arm920t_read_cp15_physical(target, 0x2, &cp15_control);
+ jtag_execute_queue();
+
+ if (mmu)
+ cp15_control &= ~0x1U;
+
+ if (d_u_cache)
+ cp15_control &= ~0x4U;
+
+ if (i_cache)
+ cp15_control &= ~0x1000U;
+
+ arm920t_write_cp15_physical(target, 0x2, cp15_control);
+}
+
+void arm920t_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
+{
+ u32 cp15_control;
+
+ /* read cp15 control register */
+ arm920t_read_cp15_physical(target, 0x2, &cp15_control);
+ jtag_execute_queue();
+
+ if (mmu)
+ cp15_control |= 0x1U;
+
+ if (d_u_cache)
+ cp15_control |= 0x4U;
+
+ if (i_cache)
+ cp15_control |= 0x1000U;
+
+ arm920t_write_cp15_physical(target, 0x2, cp15_control);
+}
+
+void arm920t_post_debug_entry(target_t *target)
+{
+ u32 cp15c15;
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
+ arm920t_common_t *arm920t = arm9tdmi->arch_info;
+
+ /* examine cp15 control reg */
+ arm920t_read_cp15_physical(target, 0x2, &arm920t->cp15_control_reg);
+ jtag_execute_queue();
+ DEBUG("cp15_control_reg: %8.8x", arm920t->cp15_control_reg);
+
+ if (arm920t->armv4_5_mmu.armv4_5_cache.ctype == -1)
+ {
+ u32 cache_type_reg;
+ /* identify caches */
+ arm920t_read_cp15_physical(target, 0x1, &cache_type_reg);
+ jtag_execute_queue();
+ armv4_5_identify_cache(cache_type_reg, &arm920t->armv4_5_mmu.armv4_5_cache);
+ }
+
+ arm920t->armv4_5_mmu.mmu_enabled = (arm920t->cp15_control_reg & 0x1U) ? 1 : 0;
+ arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm920t->cp15_control_reg & 0x4U) ? 1 : 0;
+ arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm920t->cp15_control_reg & 0x1000U) ? 1 : 0;
+
+ /* save i/d fault status and address register */
+ arm920t_read_cp15_interpreted(target, 0xee150f10, &arm920t->d_fsr);
+ arm920t_read_cp15_interpreted(target, 0xee150f30, &arm920t->i_fsr);
+ arm920t_read_cp15_interpreted(target, 0xee160f10, &arm920t->d_far);
+ arm920t_read_cp15_interpreted(target, 0xee160f30, &arm920t->i_far);
+
+ /* read-modify-write CP15 test state register
+ * to disable I/D-cache linefills */
+ arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
+ jtag_execute_queue();
+ cp15c15 |= 0x600;
+ arm920t_write_cp15_physical(target, 0x1e, cp15c15);
+
+}
+
+void arm920t_pre_restore_context(target_t *target)
+{
+ u32 cp15c15;
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
+ arm920t_common_t *arm920t = arm9tdmi->arch_info;
+
+ /* restore i/d fault status and address register */
+ arm920t_write_cp15_interpreted(target, 0xee050f10, arm920t->d_fsr, 0x0);
+ arm920t_write_cp15_interpreted(target, 0xee050f30, arm920t->i_fsr, 0x0);
+ arm920t_write_cp15_interpreted(target, 0xee060f10, arm920t->d_far, 0x0);
+ arm920t_write_cp15_interpreted(target, 0xee060f30, arm920t->i_far, 0x0);
+
+ /* read-modify-write CP15 test state register
+ * to reenable I/D-cache linefills */
+ arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
+ jtag_execute_queue();
+ cp15c15 &= ~0x600U;
+ arm920t_write_cp15_physical(target, 0x1e, cp15c15);
+
+}
+
+int arm920t_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p, arm920t_common_t **arm920t_p)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9;
+ arm9tdmi_common_t *arm9tdmi;
+ arm920t_common_t *arm920t;
+
+ if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
+ {
+ return -1;
+ }
+
+ arm7_9 = armv4_5->arch_info;
+ if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC)
+ {
+ return -1;
+ }
+
+ arm9tdmi = arm7_9->arch_info;
+ if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC)
+ {
+ return -1;
+ }
+
+ arm920t = arm9tdmi->arch_info;
+ if (arm920t->common_magic != ARM920T_COMMON_MAGIC)
+ {
+ return -1;
+ }
+
+ *armv4_5_p = armv4_5;
+ *arm7_9_p = arm7_9;
+ *arm9tdmi_p = arm9tdmi;
+ *arm920t_p = arm920t;
+
+ return ERROR_OK;
+}
+
+int arm920t_arch_state(struct target_s *target, char *buf, int buf_size)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
+ arm920t_common_t *arm920t = arm9tdmi->arch_info;
+
+ char *state[] =
+ {
+ "disabled", "enabled"
+ };
+
+ if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
+ {
+ ERROR("BUG: called for a non-ARMv4/5 target");
+ exit(-1);
+ }
+
+ snprintf(buf, buf_size,
+ "target halted in %s state due to %s, current mode: %s\n"
+ "cpsr: 0x%8.8x pc: 0x%8.8x\n"
+ "MMU: %s, D-Cache: %s, I-Cache: %s",
+ armv4_5_state_strings[armv4_5->core_state],
+ target_debug_reason_strings[target->debug_reason],
+ armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)],
+ buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
+ buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32),
+ state[arm920t->armv4_5_mmu.mmu_enabled],
+ state[arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled],
+ state[arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled]);
+
+ return ERROR_OK;
+}
+
+int arm920t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
+{
+ int retval;
+
+ retval = arm7_9_read_memory(target, address, size, count, buffer);
+
+ return retval;
+}
+
+int arm920t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
+{
+ int retval;
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
+ arm920t_common_t *arm920t = arm9tdmi->arch_info;
+
+ if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK)
+ return retval;
+
+ if (((size == 4) || (size == 2)) && (count == 1))
+ {
+ if (arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)
+ {
+ DEBUG("D-Cache enabled, writing through to main memory");
+ u32 pa, cb, ap;
+ int type, domain;
+
+ pa = armv4_5_mmu_translate_va(target, &arm920t->armv4_5_mmu, address, &type, &cb, &domain, &ap);
+ if (type == -1)
+ return ERROR_OK;
+ /* cacheable & bufferable means write-back region */
+ if (cb == 3)
+ armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, pa, size, count, buffer);
+ }
+
+ if (arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled)
+ {
+ DEBUG("I-Cache enabled, invalidating affected I-Cache line");
+ arm920t_write_cp15_interpreted(target, 0xee070f35, 0x0, address);
+ }
+ }
+
+ return retval;
+}
+
+int arm920t_soft_reset_halt(struct target_s *target)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
+ arm920t_common_t *arm920t = arm9tdmi->arch_info;
+ reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
+
+ if (target->state == TARGET_RUNNING)
+ {
+ target->type->halt(target);
+ }
+
+ while (buf_get_u32(dbg_stat->value, EICE_DBG_CONTROL_DBGACK, 1) == 0)
+ {
+ embeddedice_read_reg(dbg_stat);
+ jtag_execute_queue();
+ }
+
+ target->state = TARGET_HALTED;
+
+ /* SVC, ARM state, IRQ and FIQ disabled */
+ buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3);
+ armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
+ armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
+
+ /* start fetching from 0x0 */
+ buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0);
+ armv4_5->core_cache->reg_list[15].dirty = 1;
+ armv4_5->core_cache->reg_list[15].valid = 1;
+
+ armv4_5->core_mode = ARMV4_5_MODE_SVC;
+ armv4_5->core_state = ARMV4_5_STATE_ARM;
+
+ arm920t_disable_mmu_caches(target, 1, 1, 1);
+ arm920t->armv4_5_mmu.mmu_enabled = 0;
+ arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0;
+ arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
+
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+
+ return ERROR_OK;
+}
+
+int arm920t_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
+{
+ arm9tdmi_init_target(cmd_ctx, target);
+
+ return ERROR_OK;
+
+}
+
+int arm920t_quit()
+{
+
+ return ERROR_OK;
+}
+
+int arm920t_init_arch_info(target_t *target, arm920t_common_t *arm920t, int chain_pos, char *variant)
+{
+ arm9tdmi_common_t *arm9tdmi = &arm920t->arm9tdmi_common;
+ arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common;
+
+ arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant);
+
+ arm9tdmi->arch_info = arm920t;
+ arm920t->common_magic = ARM920T_COMMON_MAGIC;
+
+ arm7_9->post_debug_entry = arm920t_post_debug_entry;
+ arm7_9->pre_restore_context = arm920t_pre_restore_context;
+
+ arm920t->armv4_5_mmu.armv4_5_cache.ctype = -1;
+ arm920t->armv4_5_mmu.get_ttb = arm920t_get_ttb;
+ arm920t->armv4_5_mmu.read_memory = arm7_9_read_memory;
+ arm920t->armv4_5_mmu.write_memory = arm7_9_write_memory;
+ arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches;
+ arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches;
+ arm920t->armv4_5_mmu.has_tiny_pages = 1;
+ arm920t->armv4_5_mmu.mmu_enabled = 0;
+
+ arm9tdmi->has_single_step = 1;
+
+ return ERROR_OK;
+}
+
+int arm920t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
+{
+ int chain_pos;
+ char *variant = NULL;
+ arm920t_common_t *arm920t = malloc(sizeof(arm920t_common_t));
+
+ if (argc < 4)
+ {
+ ERROR("'target arm920t' requires at least one additional argument");
+ exit(-1);
+ }
+
+ chain_pos = strtoul(args[3], NULL, 0);
+
+ if (argc >= 5)
+ variant = strdup(args[4]);
+
+ DEBUG("chain_pos: %i, variant: %s", chain_pos, variant);
+
+ arm920t_init_arch_info(target, arm920t, chain_pos, variant);
+
+ return ERROR_OK;
+}
+
+int arm920t_register_commands(struct command_context_s *cmd_ctx)
+{
+ int retval;
+ command_t *arm920t_cmd;
+
+
+ retval = arm9tdmi_register_commands(cmd_ctx);
+
+ arm920t_cmd = register_command(cmd_ctx, NULL, "arm920t", NULL, COMMAND_ANY, "arm920t specific commands");
+
+ register_command(cmd_ctx, arm920t_cmd, "cp15", arm920t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register <num> [value]");
+ register_command(cmd_ctx, arm920t_cmd, "cp15i", arm920t_handle_cp15i_command, COMMAND_EXEC, "display/modify cp15 (interpreted access) <opcode> [value] [address]");
+ register_command(cmd_ctx, arm920t_cmd, "cache_info", arm920t_handle_cache_info_command, COMMAND_EXEC, "display information about target caches");
+ register_command(cmd_ctx, arm920t_cmd, "virt2phys", arm920t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa <va>");
+
+ register_command(cmd_ctx, arm920t_cmd, "mdw_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory words <physical addr> [count]");
+ register_command(cmd_ctx, arm920t_cmd, "mdh_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words <physical addr> [count]");
+ register_command(cmd_ctx, arm920t_cmd, "mdb_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes <physical addr> [count]");
+
+ register_command(cmd_ctx, arm920t_cmd, "mww_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory word <physical addr> <value>");
+ register_command(cmd_ctx, arm920t_cmd, "mwh_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word <physical addr> <value>");
+ register_command(cmd_ctx, arm920t_cmd, "mwb_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte <physical addr> <value>");
+
+ return ERROR_OK;
+}
+
+int arm920t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ int retval;
+ target_t *target = get_current_target(cmd_ctx);
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ arm9tdmi_common_t *arm9tdmi;
+ arm920t_common_t *arm920t;
+ arm_jtag_t *jtag_info;
+
+ if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM920t target");
+ return ERROR_OK;
+ }
+
+ jtag_info = &arm7_9->jtag_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+ return ERROR_OK;
+ }
+
+ /* one or more argument, access a single register (write if second argument is given */
+ if (argc >= 1)
+ {
+ int address = strtoul(args[0], NULL, 0);
+
+ if (argc == 1)
+ {
+ u32 value;
+ if ((retval = arm920t_read_cp15_physical(target, address, &value)) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "couldn't access reg %i", address);
+ return ERROR_OK;
+ }
+ jtag_execute_queue();
+
+ command_print(cmd_ctx, "%i: %8.8x", address, value);
+ }
+ else if (argc == 2)
+ {
+ u32 value = strtoul(args[1], NULL, 0);
+ if ((retval = arm920t_write_cp15_physical(target, address, value)) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "couldn't access reg %i", address);
+ return ERROR_OK;
+ }
+ command_print(cmd_ctx, "%i: %8.8x", address, value);
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int arm920t_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ int retval;
+ target_t *target = get_current_target(cmd_ctx);
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ arm9tdmi_common_t *arm9tdmi;
+ arm920t_common_t *arm920t;
+ arm_jtag_t *jtag_info;
+
+ if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM920t target");
+ return ERROR_OK;
+ }
+
+ jtag_info = &arm7_9->jtag_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+ return ERROR_OK;
+ }
+
+ /* one or more argument, access a single register (write if second argument is given */
+ if (argc >= 1)
+ {
+ u32 opcode = strtoul(args[0], NULL, 0);
+
+ if (argc == 1)
+ {
+ u32 value;
+ if ((retval = arm920t_read_cp15_interpreted(target, opcode, &value)) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "couldn't execute %8.8x", opcode);
+ return ERROR_OK;
+ }
+
+ command_print(cmd_ctx, "%8.8x: %8.8x", opcode, value);
+ }
+ else if (argc == 2)
+ {
+ u32 value = strtoul(args[1], NULL, 0);
+ if ((retval = arm920t_write_cp15_interpreted(target, opcode, value, 0)) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "couldn't execute %8.8x", opcode);
+ return ERROR_OK;
+ }
+ command_print(cmd_ctx, "%8.8x: %8.8x", opcode, value);
+ }
+ else if (argc == 3)
+ {
+ u32 value = strtoul(args[1], NULL, 0);
+ u32 address = strtoul(args[2], NULL, 0);
+ if ((retval = arm920t_write_cp15_interpreted(target, opcode, value, address)) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "couldn't execute %8.8x", opcode);
+ return ERROR_OK;
+ }
+ command_print(cmd_ctx, "%8.8x: %8.8x %8.8x", opcode, value, address);
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int arm920t_handle_cache_info_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;
+ arm7_9_common_t *arm7_9;
+ arm9tdmi_common_t *arm9tdmi;
+ arm920t_common_t *arm920t;
+
+ if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM920t target");
+ return ERROR_OK;
+ }
+
+ return armv4_5_handle_cache_info_command(cmd_ctx, &arm920t->armv4_5_mmu.armv4_5_cache);
+}
+
+int arm920t_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = get_current_target(cmd_ctx);
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ arm9tdmi_common_t *arm9tdmi;
+ arm920t_common_t *arm920t;
+ arm_jtag_t *jtag_info;
+
+ if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM920t target");
+ return ERROR_OK;
+ }
+
+ jtag_info = &arm7_9->jtag_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+ return ERROR_OK;
+ }
+
+ return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu);
+}
+
+int arm920t_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = get_current_target(cmd_ctx);
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ arm9tdmi_common_t *arm9tdmi;
+ arm920t_common_t *arm920t;
+ arm_jtag_t *jtag_info;
+
+ if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM920t target");
+ return ERROR_OK;
+ }
+
+ jtag_info = &arm7_9->jtag_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+ return ERROR_OK;
+ }
+
+ return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu);
+}
+
+int arm920t_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = get_current_target(cmd_ctx);
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ arm9tdmi_common_t *arm9tdmi;
+ arm920t_common_t *arm920t;
+ arm_jtag_t *jtag_info;
+
+ if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM920t target");
+ return ERROR_OK;
+ }
+
+ jtag_info = &arm7_9->jtag_info;
+
+ if (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+ return ERROR_OK;
+ }
+
+ return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu);
+}
diff --git a/src/target/arm920t.h b/src/target/arm920t.h
new file mode 100644
index 00000000..bedf31f2
--- /dev/null
+++ b/src/target/arm920t.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef ARM920T_H
+#define ARM920T_H
+
+#include "target.h"
+#include "register.h"
+#include "embeddedice.h"
+#include "arm_jtag.h"
+#include "arm9tdmi.h"
+#include "armv4_5_mmu.h"
+#include "armv4_5_cache.h"
+
+#define ARM920T_COMMON_MAGIC 0xa920a920
+
+typedef struct arm920t_common_s
+{
+ int common_magic;
+ armv4_5_mmu_common_t armv4_5_mmu;
+ arm9tdmi_common_t arm9tdmi_common;
+ u32 cp15_control_reg;
+ u32 d_fsr;
+ u32 i_fsr;
+ u32 d_far;
+ u32 i_far;
+} arm920t_common_t;
+
+#endif /* ARM920T_H */
diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c
new file mode 100644
index 00000000..48b201a1
--- /dev/null
+++ b/src/target/arm9tdmi.c
@@ -0,0 +1,848 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "config.h"
+
+#include "arm9tdmi.h"
+
+#include "arm7_9_common.h"
+#include "register.h"
+#include "target.h"
+#include "armv4_5.h"
+#include "embeddedice.h"
+#include "log.h"
+#include "jtag.h"
+#include "arm_jtag.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#if 0
+#define _DEBUG_INSTRUCTION_EXECUTION_
+#endif
+
+/* cli handling */
+int arm9tdmi_register_commands(struct command_context_s *cmd_ctx);
+
+/* forward declarations */
+int arm9tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
+int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
+int arm9tdmi_quit();
+
+/* target function declarations */
+enum target_state arm9tdmi_poll(struct target_s *target);
+int arm9tdmi_halt(target_t *target);
+int arm9tdmi_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
+
+target_type_t arm9tdmi_target =
+{
+ .name = "arm9tdmi",
+
+ .poll = arm7_9_poll,
+ .arch_state = armv4_5_arch_state,
+
+ .halt = arm7_9_halt,
+ .resume = arm7_9_resume,
+ .step = arm7_9_step,
+
+ .assert_reset = arm7_9_assert_reset,
+ .deassert_reset = arm7_9_deassert_reset,
+ .soft_reset_halt = arm7_9_soft_reset_halt,
+
+ .get_gdb_reg_list = armv4_5_get_gdb_reg_list,
+
+ .read_memory = arm7_9_read_memory,
+ .write_memory = arm7_9_write_memory,
+ .bulk_write_memory = arm7_9_bulk_write_memory,
+
+ .add_breakpoint = arm7_9_add_breakpoint,
+ .remove_breakpoint = arm7_9_remove_breakpoint,
+ .add_watchpoint = arm7_9_add_watchpoint,
+ .remove_watchpoint = arm7_9_remove_watchpoint,
+
+ .register_commands = arm9tdmi_register_commands,
+ .target_command = arm9tdmi_target_command,
+ .init_target = arm9tdmi_init_target,
+ .quit = arm9tdmi_quit
+};
+
+int arm9tdmi_examine_debug_reason(target_t *target)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+
+ /* only check the debug reason if we don't know it already */
+ if ((target->debug_reason != DBG_REASON_DBGRQ)
+ && (target->debug_reason != DBG_REASON_SINGLESTEP))
+ {
+ scan_field_t fields[3];
+ u8 databus[4];
+ u8 instructionbus[4];
+ u8 debug_reason;
+
+ jtag_add_end_state(TAP_PD);
+
+ fields[0].device = arm7_9->jtag_info.chain_pos;
+ fields[0].num_bits = 32;
+ fields[0].out_value = NULL;
+ fields[0].out_mask = NULL;
+ fields[0].in_value = databus;
+ 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 = arm7_9->jtag_info.chain_pos;
+ fields[1].num_bits = 3;
+ fields[1].out_value = NULL;
+ fields[1].out_mask = NULL;
+ fields[1].in_value = &debug_reason;
+ 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 = arm7_9->jtag_info.chain_pos;
+ fields[2].num_bits = 32;
+ fields[2].out_value = NULL;
+ fields[2].out_mask = NULL;
+ fields[2].in_value = instructionbus;
+ fields[2].in_check_value = NULL;
+ fields[2].in_check_mask = NULL;
+ fields[2].in_handler = NULL;
+ fields[2].in_handler_priv = NULL;
+
+ arm_jtag_scann(&arm7_9->jtag_info, 0x1);
+ arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr);
+
+ jtag_add_dr_scan(3, fields, TAP_PD);
+ jtag_execute_queue();
+
+ fields[0].in_value = NULL;
+ fields[0].out_value = databus;
+ fields[1].in_value = NULL;
+ fields[1].out_value = &debug_reason;
+ fields[2].in_value = NULL;
+ fields[2].out_value = instructionbus;
+
+ jtag_add_dr_scan(3, fields, TAP_PD);
+
+ if (debug_reason & 0x4)
+ if (debug_reason & 0x2)
+ target->debug_reason = DBG_REASON_WPTANDBKPT;
+ else
+ target->debug_reason = DBG_REASON_WATCHPOINT;
+ else
+ target->debug_reason = DBG_REASON_BREAKPOINT;
+ }
+
+ return ERROR_OK;
+}
+
+/* put an instruction in the ARM9TDMI pipeline or write the data bus, and optionally read data */
+int arm9tdmi_clock_out(arm_jtag_t *jtag_info, u32 instr, u32 out, u32 *in, int sysspeed)
+{
+ scan_field_t fields[3];
+ u8 out_buf[4];
+ u8 instr_buf[4];
+ u8 sysspeed_buf = 0x0;
+
+ /* prepare buffer */
+ buf_set_u32(out_buf, 0, 32, out);
+
+ instr = flip_u32(instr, 32);
+ buf_set_u32(instr_buf, 0, 32, instr);
+
+ if (sysspeed)
+ buf_set_u32(&sysspeed_buf, 2, 1, 1);
+
+ jtag_add_end_state(TAP_PD);
+ arm_jtag_scann(jtag_info, 0x1);
+ arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
+
+ fields[0].device = jtag_info->chain_pos;
+ fields[0].num_bits = 32;
+ fields[0].out_value = out_buf;
+ fields[0].out_mask = NULL;
+ if (in)
+ {
+ fields[0].in_value = (u8*)in;
+ } else
+ {
+ 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 = jtag_info->chain_pos;
+ fields[1].num_bits = 3;
+ fields[1].out_value = &sysspeed_buf;
+ 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 = jtag_info->chain_pos;
+ fields[2].num_bits = 32;
+ fields[2].out_value = instr_buf;
+ 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);
+
+ jtag_add_runtest(0, -1);
+
+#ifdef _DEBUG_INSTRUCTION_EXECUTION_
+ {
+ char* in_string;
+ jtag_execute_queue();
+
+ if (in)
+ {
+ in_string = buf_to_char((u8*)in, 32);
+ DEBUG("instr: 0x%8.8x, out: 0x%8.8x, in: %s", flip_u32(instr, 32), out, in_string);
+ free(in_string);
+ }
+ else
+ DEBUG("instr: 0x%8.8x, out: 0x%8.8x", flip_u32(instr, 32), out);
+ }
+#endif
+
+ return ERROR_OK;
+}
+
+/* just read data (instruction and data-out = don't care) */
+int arm9tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in)
+{
+ scan_field_t fields[3];
+
+ jtag_add_end_state(TAP_PD);
+ arm_jtag_scann(jtag_info, 0x1);
+ arm_jtag_set_instr(jtag_info, jtag_info->intest_instr);
+
+ fields[0].device = jtag_info->chain_pos;
+ fields[0].num_bits = 32;
+ fields[0].out_value = NULL;
+ fields[0].out_mask = NULL;
+ fields[0].in_value = (u8*)in;
+ fields[0].in_handler = NULL;
+ fields[0].in_handler_priv = NULL;
+ fields[0].in_check_value = NULL;
+ fields[0].in_check_mask = NULL;
+
+ fields[1].device = jtag_info->chain_pos;
+ fields[1].num_bits = 3;
+ fields[1].out_value = NULL;
+ fields[1].out_mask = NULL;
+ fields[1].in_value = NULL;
+ fields[1].in_handler = NULL;
+ fields[1].in_handler_priv = NULL;
+ fields[1].in_check_value = NULL;
+ fields[1].in_check_mask = NULL;
+
+ fields[2].device = jtag_info->chain_pos;
+ fields[2].num_bits = 32;
+ fields[2].out_value = NULL;
+ 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);
+
+ jtag_add_runtest(0, -1);
+
+#ifdef _DEBUG_INSTRUCTION_EXECUTION_
+ {
+ char* in_string;
+ jtag_execute_queue();
+
+ if (in)
+ {
+ in_string = buf_to_char((u8*)in, 32);
+ DEBUG("in: %s", in_string);
+ free(in_string);
+ }
+ }
+#endif
+
+ return ERROR_OK;
+}
+
+void arm9tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* save r0 before using it and put system in ARM state
+ * to allow common handling of ARM and THUMB debugging */
+
+ /* fetch STR r0, [r0] */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
+ /* STR r0, [r0] in Memory */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, r0, 0);
+
+ /* MOV r0, r15 fetched, STR in Decode */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
+ /* nothing fetched, STR r0, [r0] in Memory */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, pc, 0);
+
+ /* fetch MOV */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV_IM(0, 0x0), 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
+
+ /* fetch BX */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), 0, NULL, 0);
+ /* NOP fetched, BX in Decode, MOV in Execute */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
+ /* NOP fetched, BX in Execute (1) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
+
+ jtag_execute_queue();
+
+ /* fix program counter:
+ * MOV r0, r15 was the 5th instruction (+8)
+ * reading PC in Thumb state gives address of instruction + 4
+ */
+ *pc -= 0xc;
+}
+
+void arm9tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16])
+{
+ int i;
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* STMIA r0-15, [r0] at debug speed
+ * register values will start to appear on 4th DCLK
+ */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
+
+ /* fetch NOP, STM in DECODE stage */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* fetch NOP, STM in EXECUTE stage (1st cycle) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+
+ for (i = 0; i <= 15; i++)
+ {
+ if (mask & (1 << i))
+ /* nothing fetched, STM in MEMORY (i'th cycle) */
+ arm9tdmi_clock_data_in(jtag_info, core_regs[i]);
+ }
+
+}
+
+void arm9tdmi_read_xpsr(target_t *target, u32 *xpsr, int spsr)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* MRS r0, cpsr */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+
+ /* STR r0, [r15] */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0, NULL, 0);
+ /* fetch NOP, STR in DECODE stage */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* fetch NOP, STR in EXECUTE stage (1st cycle) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* nothing fetched, STR in MEMORY */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0);
+
+}
+
+void arm9tdmi_write_xpsr(target_t *target, u32 xpsr, int spsr)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ DEBUG("xpsr: %8.8x, spsr: %i", xpsr, spsr);
+
+ /* MSR1 fetched */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0);
+ /* MSR2 fetched, MSR1 in DECODE */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0);
+ /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0);
+ /* nothing fetched, MSR1 in EXECUTE (2) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* nothing fetched, MSR1 in EXECUTE (3) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0);
+ /* nothing fetched, MSR2 in EXECUTE (2) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* nothing fetched, MSR2 in EXECUTE (3) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* nothing fetched, MSR3 in EXECUTE (2) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* nothing fetched, MSR3 in EXECUTE (3) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* NOP fetched, MSR4 in EXECUTE (1) */
+ /* last MSR writes flags, which takes only one cycle */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+}
+
+void arm9tdmi_write_xpsr_im8(target_t *target, u8 xpsr_im, int rot, int spsr)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr);
+
+ /* MSR fetched */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0);
+ /* NOP fetched, MSR in DECODE */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* NOP fetched, MSR in EXECUTE (1) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+
+ /* rot == 4 writes flags, which takes only one cycle */
+ if (rot != 4)
+ {
+ /* nothing fetched, MSR in EXECUTE (2) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* nothing fetched, MSR in EXECUTE (3) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ }
+}
+
+void arm9tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16])
+{
+ int i;
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* LDMIA r0-15, [r0] at debug speed
+ * register values will start to appear on 4th DCLK
+ */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
+
+ /* fetch NOP, LDM in DECODE stage */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* fetch NOP, LDM in EXECUTE stage (1st cycle) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+
+ for (i = 0; i <= 15; i++)
+ {
+ if (mask & (1 << i))
+ /* nothing fetched, LDM still in EXECUTE (1+i cycle) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0);
+ }
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+
+}
+
+void arm9tdmi_load_word_regs(target_t *target, u32 mask)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* put system-speed load-multiple into the pipeline */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
+
+}
+
+void arm9tdmi_load_hword_reg(target_t *target, int num)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* put system-speed load half-word into the pipeline */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
+}
+
+void arm9tdmi_load_byte_reg(target_t *target, int num)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* put system-speed load byte into the pipeline */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
+
+}
+
+void arm9tdmi_store_word_regs(target_t *target, u32 mask)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* put system-speed store-multiple into the pipeline */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
+
+}
+
+void arm9tdmi_store_hword_reg(target_t *target, int num)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* put system-speed store half-word into the pipeline */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
+
+}
+
+void arm9tdmi_store_byte_reg(target_t *target, int num)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* put system-speed store byte into the pipeline */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
+
+}
+
+void arm9tdmi_write_pc(target_t *target, u32 pc)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ /* LDMIA r0-15, [r0] at debug speed
+ * register values will start to appear on 4th DCLK
+ */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0, NULL, 0);
+
+ /* fetch NOP, LDM in DECODE stage */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* fetch NOP, LDM in EXECUTE stage (1st cycle) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* nothing fetched, LDM in EXECUTE stage (2nd cycle) (output data) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, pc, NULL, 0);
+ /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* fetch NOP, LDM in EXECUTE stage (4th cycle) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* fetch NOP, LDM in EXECUTE stage (5th cycle) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+
+}
+
+void arm9tdmi_branch_resume(target_t *target)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffc, 0), 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
+
+}
+
+void arm9tdmi_branch_resume_thumb(target_t *target)
+{
+ DEBUG("");
+
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+ reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
+
+ /* LDMIA r0-15, [r0] at debug speed
+ * register values will start to appear on 4th DCLK
+ */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), 0, NULL, 0);
+
+ /* fetch NOP, LDM in DECODE stage */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* fetch NOP, LDM in EXECUTE stage (1st cycle) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+ /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) | 1, NULL, 0);
+ /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+
+ /* Branch and eXchange */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0, NULL, 0);
+
+ embeddedice_read_reg(dbg_stat);
+
+ /* fetch NOP, BX in DECODE stage */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+
+ embeddedice_read_reg(dbg_stat);
+
+ /* fetch NOP, BX in EXECUTE stage (1st cycle) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
+
+ /* target is now in Thumb state */
+ embeddedice_read_reg(dbg_stat);
+
+ /* clean r0 bits to avoid alignment problems */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV_IM(0, 0x0), 0, NULL, 0);
+ /* load r0 value, MOV_IM in Decode*/
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR(0, 0), 0, NULL, 0);
+ /* fetch NOP, LDR in Decode, MOV_IM in Execute */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
+ /* fetch NOP, LDR in Execute */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
+ /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32), NULL, 0);
+ /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
+
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
+
+ embeddedice_read_reg(dbg_stat);
+
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f6), 0, NULL, 1);
+ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
+
+}
+
+void arm9tdmi_enable_single_step(target_t *target)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm9tdmi_common_t *arm9 = arm7_9->arch_info;
+
+ if (arm9->has_single_step)
+ {
+ buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 1);
+ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]);
+ }
+ else
+ {
+ arm7_9_enable_eice_step(target);
+ }
+}
+
+void arm9tdmi_disable_single_step(target_t *target)
+{
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm9tdmi_common_t *arm9 = arm7_9->arch_info;
+
+ if (arm9->has_single_step)
+ {
+ buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 0);
+ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]);
+ }
+ else
+ {
+ arm7_9_disable_eice_step(target);
+ }
+}
+
+void arm9tdmi_build_reg_cache(target_t *target)
+{
+ reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
+ /* get pointers to arch-specific information */
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+ arm_jtag_t *jtag_info = &arm7_9->jtag_info;
+ arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
+
+
+ (*cache_p) = armv4_5_build_reg_cache(target, armv4_5);
+ armv4_5->core_cache = (*cache_p);
+
+ (*cache_p)->next = embeddedice_build_reg_cache(target, jtag_info, 0);
+ arm7_9->eice_cache = (*cache_p)->next;
+
+ if (arm9tdmi->has_monitor_mode)
+ (*cache_p)->next->reg_list[0].size = 6;
+ else
+ (*cache_p)->next->reg_list[0].size = 4;
+
+ (*cache_p)->next->reg_list[1].size = 5;
+
+}
+
+int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
+{
+
+ arm9tdmi_build_reg_cache(target);
+
+ return ERROR_OK;
+
+}
+
+int arm9tdmi_quit()
+{
+
+ return ERROR_OK;
+}
+
+int arm9tdmi_init_arch_info(target_t *target, arm9tdmi_common_t *arm9tdmi, int chain_pos, char *variant)
+{
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+
+ arm7_9 = &arm9tdmi->arm7_9_common;
+ armv4_5 = &arm7_9->armv4_5_common;
+
+ /* prepare JTAG information for the new target */
+ arm7_9->jtag_info.chain_pos = chain_pos;
+ arm7_9->jtag_info.scann_size = 5;
+
+ /* register arch-specific functions */
+ arm7_9->examine_debug_reason = arm9tdmi_examine_debug_reason;
+ arm7_9->change_to_arm = arm9tdmi_change_to_arm;
+ arm7_9->read_core_regs = arm9tdmi_read_core_regs;
+ arm7_9->read_xpsr = arm9tdmi_read_xpsr;
+
+ arm7_9->write_xpsr = arm9tdmi_write_xpsr;
+ arm7_9->write_xpsr_im8 = arm9tdmi_write_xpsr_im8;
+ arm7_9->write_core_regs = arm9tdmi_write_core_regs;
+
+ arm7_9->load_word_regs = arm9tdmi_load_word_regs;
+ arm7_9->load_hword_reg = arm9tdmi_load_hword_reg;
+ arm7_9->load_byte_reg = arm9tdmi_load_byte_reg;
+
+ arm7_9->store_word_regs = arm9tdmi_store_word_regs;
+ arm7_9->store_hword_reg = arm9tdmi_store_hword_reg;
+ arm7_9->store_byte_reg = arm9tdmi_store_byte_reg;
+
+ arm7_9->write_pc = arm9tdmi_write_pc;
+ arm7_9->branch_resume = arm9tdmi_branch_resume;
+ arm7_9->branch_resume_thumb = arm9tdmi_branch_resume_thumb;
+
+ arm7_9->enable_single_step = arm9tdmi_enable_single_step;
+ arm7_9->disable_single_step = arm9tdmi_disable_single_step;
+
+ arm7_9->pre_debug_entry = NULL;
+ arm7_9->post_debug_entry = NULL;
+
+ arm7_9->pre_restore_context = NULL;
+ arm7_9->post_restore_context = NULL;
+
+ /* initialize arch-specific breakpoint handling */
+ buf_set_u32((u8*)(&arm7_9->arm_bkpt), 0, 32, 0xdeeedeee);
+ buf_set_u32((u8*)(&arm7_9->thumb_bkpt), 0, 16, 0xdeee);
+
+ arm7_9->sw_bkpts_use_wp = 1;
+ arm7_9->sw_bkpts_enabled = 0;
+ arm7_9->dbgreq_adjust_pc = 3;
+ arm7_9->arch_info = arm9tdmi;
+ arm7_9->use_dbgrq = 1;
+
+ arm9tdmi->common_magic = ARM9TDMI_COMMON_MAGIC;
+ arm9tdmi->has_monitor_mode = 0;
+ arm9tdmi->has_single_step = 0;
+ arm9tdmi->arch_info = NULL;
+
+ if (variant)
+ {
+ if (strcmp(variant, "arm920t") == 0)
+ arm9tdmi->has_single_step = 1;
+ else if (strcmp(variant, "arm922t") == 0)
+ arm9tdmi->has_single_step = 1;
+ else if (strcmp(variant, "arm940t") == 0)
+ arm9tdmi->has_single_step = 1;
+ }
+
+ arm7_9_init_arch_info(target, arm7_9);
+
+ return ERROR_OK;
+}
+
+/* target arm9tdmi <endianess> <startup_mode> <chain_pos> <variant>*/
+int arm9tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
+{
+ int chain_pos;
+ char *variant = NULL;
+ arm9tdmi_common_t *arm9tdmi = malloc(sizeof(arm9tdmi_common_t));
+
+ if (argc < 4)
+ {
+ ERROR("'target arm9tdmi' requires at least one additional argument");
+ exit(-1);
+ }
+
+ chain_pos = strtoul(args[3], NULL, 0);
+
+ if (argc >= 5)
+ variant = strdup(args[4]);
+
+ arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant);
+
+ return ERROR_OK;
+}
+
+int arm9tdmi_register_commands(struct command_context_s *cmd_ctx)
+{
+ int retval;
+
+ retval = arm7_9_register_commands(cmd_ctx);
+
+ return ERROR_OK;
+
+}
+
diff --git a/src/target/arm9tdmi.h b/src/target/arm9tdmi.h
new file mode 100644
index 00000000..7bbaac7c
--- /dev/null
+++ b/src/target/arm9tdmi.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef ARM9TDMI_H
+#define ARM9TDMI_H
+
+#include "target.h"
+#include "register.h"
+#include "armv4_5.h"
+#include "embeddedice.h"
+#include "arm_jtag.h"
+#include "arm7_9_common.h"
+
+#define ARM9TDMI_COMMON_MAGIC 0x00a900a9
+
+typedef struct arm9tdmi_common_s
+{
+ int common_magic;
+ char *variant;
+ int has_monitor_mode;
+ int has_single_step;
+ void *arch_info;
+ arm7_9_common_t arm7_9_common;
+} arm9tdmi_common_t;
+
+extern int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
+extern int arm9tdmi_init_arch_info(target_t *target, arm9tdmi_common_t *arm9tdmi, int chain_pos, char *variant);
+extern int arm9tdmi_register_commands(struct command_context_s *cmd_ctx);
+
+extern int arm9tdmi_clock_out(arm_jtag_t *jtag_info, u32 instr, u32 out, u32 *in, int sysspeed);
+extern int arm9tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in);
+extern void arm9tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16]);
+extern void arm9tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16]);
+
+#endif /* ARM9TDMI_H */
diff --git a/src/target/arm_jtag.c b/src/target/arm_jtag.c
new file mode 100644
index 00000000..c401d8f3
--- /dev/null
+++ b/src/target/arm_jtag.c
@@ -0,0 +1,116 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "config.h"
+
+#include "arm_jtag.h"
+
+#include "binarybuffer.h"
+#include "log.h"
+#include "jtag.h"
+
+#include <stdlib.h>
+
+int arm_jtag_set_instr(arm_jtag_t *jtag_info, u32 new_instr)
+{
+ jtag_device_t *device = jtag_get_device(jtag_info->chain_pos);
+
+ if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr)
+ {
+ scan_field_t field;
+
+ field.device = jtag_info->chain_pos;
+ field.num_bits = device->ir_length;
+ field.out_value = calloc(CEIL(field.num_bits, 8), 1);
+ buf_set_u32(field.out_value, 0, field.num_bits, new_instr);
+ field.out_mask = NULL;
+ field.in_value = NULL;
+ field.in_check_value = NULL;
+ field.in_check_mask = NULL;
+ field.in_handler = NULL;
+ field.in_handler_priv = NULL;
+
+ jtag_add_ir_scan(1, &field, -1);
+
+ free(field.out_value);
+ }
+
+ return ERROR_OK;
+}
+
+int arm_jtag_scann(arm_jtag_t *jtag_info, u32 new_scan_chain)
+{
+ if(jtag_info->cur_scan_chain != new_scan_chain)
+ {
+ scan_field_t field;
+
+ field.device = jtag_info->chain_pos;
+ field.num_bits = jtag_info->scann_size;
+ field.out_value = calloc(CEIL(field.num_bits, 8), 1);
+ buf_set_u32(field.out_value, 0, field.num_bits, new_scan_chain);
+ field.out_mask = NULL;
+ //field.in_value = &scan_n_capture;
+ field.in_value = NULL;
+ field.in_check_value = NULL;
+ field.in_check_mask = NULL;
+ field.in_handler = NULL;
+ field.in_handler_priv = NULL;
+
+ arm_jtag_set_instr(jtag_info, jtag_info->scann_instr);
+ jtag_add_dr_scan(1, &field, -1);
+
+ jtag_info->cur_scan_chain = new_scan_chain;
+
+ free(field.out_value);
+ }
+
+ return ERROR_OK;
+}
+
+int arm_jtag_reset_callback(enum jtag_event event, void *priv)
+{
+ arm_jtag_t *jtag_info = priv;
+
+ if (event == JTAG_TRST_ASSERTED)
+ {
+ jtag_info->cur_scan_chain = 0;
+ }
+
+ return ERROR_OK;
+}
+
+int arm_jtag_setup_connection(arm_jtag_t *jtag_info)
+{
+ jtag_info->scann_instr = 0x2;
+ jtag_info->cur_scan_chain = 0;
+ jtag_info->intest_instr = 0xc;
+
+ jtag_register_event_callback(arm_jtag_reset_callback, jtag_info);
+
+ return ERROR_OK;
+}
+
+int arm_jtag_buf_to_u32_flip(u8 *in_buf, void *priv)
+{
+ u32 *dest = priv;
+
+ *dest = flip_u32(buf_get_u32(in_buf, 0, 32), 32);
+
+ return ERROR_OK;
+}
diff --git a/src/target/arm_jtag.h b/src/target/arm_jtag.h
new file mode 100644
index 00000000..a9f90846
--- /dev/null
+++ b/src/target/arm_jtag.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef ARM_JTAG
+#define ARM_JTAG
+
+#include "types.h"
+
+typedef struct arm_jtag_s
+{
+ int chain_pos;
+
+ int scann_size;
+ u32 scann_instr;
+ int cur_scan_chain;
+
+ u32 intest_instr;
+} arm_jtag_t;
+
+extern int arm_jtag_set_instr(arm_jtag_t *jtag_info, u32 new_instr);
+extern int arm_jtag_scann(arm_jtag_t *jtag_info, u32 new_scan_chain);
+extern int arm_jtag_buf_to_u32_flip(u8 *in_buf, void *priv);
+extern int arm_jtag_setup_connection(arm_jtag_t *jtag_info);
+
+#endif /* ARM_JTAG */
+
diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c
new file mode 100644
index 00000000..51fd4b42
--- /dev/null
+++ b/src/target/armv4_5.c
@@ -0,0 +1,583 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "config.h"
+
+#include "armv4_5.h"
+
+#include "target.h"
+#include "register.h"
+#include "log.h"
+#include "binarybuffer.h"
+#include "command.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+bitfield_desc_t armv4_5_psr_bitfield_desc[] =
+{
+ {"M[4:0]", 5},
+ {"T", 1},
+ {"F", 1},
+ {"I", 1},
+ {"reserved", 16},
+ {"J", 1},
+ {"reserved", 2},
+ {"Q", 1},
+ {"V", 1},
+ {"C", 1},
+ {"Z", 1},
+ {"N", 1},
+};
+
+char* armv4_5_core_reg_list[] =
+{
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13_usr", "lr_usr", "pc",
+
+ "r8_fiq", "r9_fiq", "r10_fiq", "r11_fiq", "r12_fiq", "r13_fiq", "lr_fiq",
+
+ "r13_irq", "lr_irq",
+
+ "r13_svc", "lr_svc",
+
+ "r13_abt", "lr_abt",
+
+ "r13_und", "lr_und",
+
+ "cpsr", "spsr_fiq", "spsr_irq", "spsr_svc", "spsr_abt", "spsr_und"
+};
+
+char* armv4_5_mode_strings[] =
+{
+ "User", "FIQ", "IRQ", "Supervisor", "Abort", "Undefined", "System"
+};
+
+char* armv4_5_state_strings[] =
+{
+ "ARM", "Thumb", "Jazelle"
+};
+
+int armv4_5_core_reg_arch_type = -1;
+
+armv4_5_core_reg_t armv4_5_core_reg_list_arch_info[] =
+{
+ {0, ARMV4_5_MODE_ANY, NULL, NULL},
+ {1, ARMV4_5_MODE_ANY, NULL, NULL},
+ {2, ARMV4_5_MODE_ANY, NULL, NULL},
+ {3, ARMV4_5_MODE_ANY, NULL, NULL},
+ {4, ARMV4_5_MODE_ANY, NULL, NULL},
+ {5, ARMV4_5_MODE_ANY, NULL, NULL},
+ {6, ARMV4_5_MODE_ANY, NULL, NULL},
+ {7, ARMV4_5_MODE_ANY, NULL, NULL},
+ {8, ARMV4_5_MODE_ANY, NULL, NULL},
+ {9, ARMV4_5_MODE_ANY, NULL, NULL},
+ {10, ARMV4_5_MODE_ANY, NULL, NULL},
+ {11, ARMV4_5_MODE_ANY, NULL, NULL},
+ {12, ARMV4_5_MODE_ANY, NULL, NULL},
+ {13, ARMV4_5_MODE_USR, NULL, NULL},
+ {14, ARMV4_5_MODE_USR, NULL, NULL},
+ {15, ARMV4_5_MODE_ANY, NULL, NULL},
+
+ {8, ARMV4_5_MODE_FIQ, NULL, NULL},
+ {9, ARMV4_5_MODE_FIQ, NULL, NULL},
+ {10, ARMV4_5_MODE_FIQ, NULL, NULL},
+ {11, ARMV4_5_MODE_FIQ, NULL, NULL},
+ {12, ARMV4_5_MODE_FIQ, NULL, NULL},
+ {13, ARMV4_5_MODE_FIQ, NULL, NULL},
+ {14, ARMV4_5_MODE_FIQ, NULL, NULL},
+
+ {13, ARMV4_5_MODE_IRQ, NULL, NULL},
+ {14, ARMV4_5_MODE_IRQ, NULL, NULL},
+
+ {13, ARMV4_5_MODE_SVC, NULL, NULL},
+ {14, ARMV4_5_MODE_SVC, NULL, NULL},
+
+ {13, ARMV4_5_MODE_ABT, NULL, NULL},
+ {14, ARMV4_5_MODE_ABT, NULL, NULL},
+
+ {13, ARMV4_5_MODE_UND, NULL, NULL},
+ {14, ARMV4_5_MODE_UND, NULL, NULL},
+
+ {16, ARMV4_5_MODE_ANY, NULL, NULL},
+ {16, ARMV4_5_MODE_FIQ, NULL, NULL},
+ {16, ARMV4_5_MODE_IRQ, NULL, NULL},
+ {16, ARMV4_5_MODE_SVC, NULL, NULL},
+ {16, ARMV4_5_MODE_ABT, NULL, NULL},
+ {16, ARMV4_5_MODE_UND, NULL, NULL}
+};
+
+/* map core mode (USR, FIQ, ...) and register number to indizes into the register cache */
+int armv4_5_core_reg_map[7][17] =
+{
+ { /* USR */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31
+ },
+ { /* FIQ */
+ 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 15, 32
+ },
+ { /* IRQ */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 23, 24, 15, 33
+ },
+ { /* SVC */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 25, 26, 15, 34
+ },
+ { /* ABT */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 27, 28, 15, 35
+ },
+ { /* UND */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 29, 30, 15, 36
+ },
+ { /* SYS */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31
+ }
+};
+
+u8 armv4_5_gdb_dummy_fp_value[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+reg_t armv4_5_gdb_dummy_fp_reg =
+{
+ "GDB dummy floating-point register", armv4_5_gdb_dummy_fp_value, 0, 1, 96, NULL, 0, NULL, 0
+};
+
+u8 armv4_5_gdb_dummy_fps_value[] = {0, 0, 0, 0};
+
+reg_t armv4_5_gdb_dummy_fps_reg =
+{
+ "GDB dummy floating-point status register", armv4_5_gdb_dummy_fps_value, 0, 1, 32, NULL, 0, NULL, 0
+};
+
+/* map psr mode bits to linear number */
+int armv4_5_mode_to_number(enum armv4_5_mode mode)
+{
+ switch (mode)
+ {
+ case 16: return 0; break;
+ case 17: return 1; break;
+ case 18: return 2; break;
+ case 19: return 3; break;
+ case 23: return 4; break;
+ case 27: return 5; break;
+ case 31: return 6; break;
+ case -1: return 0; break; /* map MODE_ANY to user mode */
+ default:
+ ERROR("invalid mode value encountered");
+ return -1;
+ }
+}
+
+/* map linear number to mode bits */
+enum armv4_5_mode armv4_5_number_to_mode(int number)
+{
+ switch(number)
+ {
+ case 0: return ARMV4_5_MODE_USR; break;
+ case 1: return ARMV4_5_MODE_FIQ; break;
+ case 2: return ARMV4_5_MODE_IRQ; break;
+ case 3: return ARMV4_5_MODE_SVC; break;
+ case 4: return ARMV4_5_MODE_ABT; break;
+ case 5: return ARMV4_5_MODE_UND; break;
+ case 6: return ARMV4_5_MODE_SYS; break;
+ default:
+ ERROR("mode index out of bounds");
+ return -1;
+ }
+};
+
+int armv4_5_get_core_reg(reg_t *reg)
+{
+ int retval;
+ armv4_5_core_reg_t *armv4_5 = reg->arch_info;
+ target_t *target = armv4_5->target;
+
+ if (target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ //retval = armv4_5->armv4_5_common->full_context(target);
+ retval = armv4_5->armv4_5_common->read_core_reg(target, armv4_5->num, armv4_5->mode);
+
+ return retval;
+}
+
+int armv4_5_set_core_reg(reg_t *reg, u32 value)
+{
+ armv4_5_core_reg_t *armv4_5 = reg->arch_info;
+ target_t *target = armv4_5->target;
+
+ if (target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ buf_set_u32(reg->value, 0, 32, value);
+ reg->dirty = 1;
+ reg->valid = 1;
+
+ return ERROR_OK;
+}
+
+int armv4_5_invalidate_core_regs(target_t *target)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ int i;
+
+ for (i = 0; i < 37; i++)
+ {
+ armv4_5->core_cache->reg_list[i].valid = 0;
+ armv4_5->core_cache->reg_list[i].dirty = 0;
+ }
+
+ return ERROR_OK;
+}
+
+reg_cache_t* armv4_5_build_reg_cache(target_t *target, armv4_5_common_t *armv4_5_common)
+{
+ int num_regs = 37;
+ reg_cache_t *cache = malloc(sizeof(reg_cache_t));
+ reg_t *reg_list = malloc(sizeof(reg_t) * num_regs);
+ armv4_5_core_reg_t *arch_info = malloc(sizeof(reg_t) * num_regs);
+ int i;
+
+ cache->name = "arm v4/5 registers";
+ cache->next = NULL;
+ cache->reg_list = reg_list;
+ cache->num_regs = num_regs;
+
+ if (armv4_5_core_reg_arch_type == -1)
+ armv4_5_core_reg_arch_type = register_reg_arch_type(armv4_5_get_core_reg, armv4_5_set_core_reg);
+
+ for (i = 0; i < 37; i++)
+ {
+ arch_info[i] = armv4_5_core_reg_list_arch_info[i];
+ arch_info[i].target = target;
+ arch_info[i].armv4_5_common = armv4_5_common;
+ reg_list[i].name = armv4_5_core_reg_list[i];
+ reg_list[i].size = 32;
+ reg_list[i].value = calloc(1, 4);
+ reg_list[i].dirty = 0;
+ reg_list[i].valid = 0;
+ reg_list[i].bitfield_desc = NULL;
+ reg_list[i].num_bitfields = 0;
+ reg_list[i].arch_type = armv4_5_core_reg_arch_type;
+ reg_list[i].arch_info = &arch_info[i];
+ }
+
+ return cache;
+}
+
+int armv4_5_arch_state(struct target_s *target, char *buf, int buf_size)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+
+ if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
+ {
+ ERROR("BUG: called for a non-ARMv4/5 target");
+ exit(-1);
+ }
+
+ snprintf(buf, buf_size,
+ "target halted in %s state due to %s, current mode: %s\ncpsr: 0x%8.8x pc: 0x%8.8x",
+ armv4_5_state_strings[armv4_5->core_state],
+ target_debug_reason_strings[target->debug_reason],
+ armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)],
+ buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
+ buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
+
+ return ERROR_OK;
+}
+
+int handle_armv4_5_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ char output[128];
+ int output_len;
+ int mode, num;
+ target_t *target = get_current_target(cmd_ctx);
+ armv4_5_common_t *armv4_5 = target->arch_info;
+
+ if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
+ {
+ command_print(cmd_ctx, "current target isn't an ARMV4/5 target");
+ return ERROR_OK;
+ }
+
+ if (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "error: target must be halted for register accesses");
+ return ERROR_OK;
+ }
+
+ for (num = 0; num <= 15; num++)
+ {
+ output_len = 0;
+ for (mode = 0; mode < 6; mode++)
+ {
+ if (!ARMV4_5_CORE_REG_MODENUM(armv4_5->core_cache, mode, num).valid)
+ {
+ armv4_5->full_context(target);
+ }
+ output_len += snprintf(output + output_len, 128 - output_len, "%8s: %8.8x ", ARMV4_5_CORE_REG_MODENUM(armv4_5->core_cache, mode, num).name,
+ buf_get_u32(ARMV4_5_CORE_REG_MODENUM(armv4_5->core_cache, mode, num).value, 0, 32));
+ }
+ command_print(cmd_ctx, output);
+ }
+ command_print(cmd_ctx, " cpsr: %8.8x spsr_fiq: %8.8x spsr_irq: %8.8x spsr_svc: %8.8x spsr_abt: %8.8x spsr_und: %8.8x",
+ buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
+ buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_FIQ].value, 0, 32),
+ buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_IRQ].value, 0, 32),
+ buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_SVC].value, 0, 32),
+ buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_ABT].value, 0, 32),
+ buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_SPSR_UND].value, 0, 32));
+
+ return ERROR_OK;
+}
+
+int handle_armv4_5_core_state_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 = target->arch_info;
+
+ if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
+ {
+ command_print(cmd_ctx, "current target isn't an ARMV4/5 target");
+ return ERROR_OK;
+ }
+
+ if (argc > 0)
+ {
+ if (strcmp(args[0], "arm") == 0)
+ {
+ armv4_5->core_state = ARMV4_5_STATE_ARM;
+ }
+ if (strcmp(args[0], "thumb") == 0)
+ {
+ armv4_5->core_state = ARMV4_5_STATE_THUMB;
+ }
+ }
+
+ command_print(cmd_ctx, "core state: %s", armv4_5_state_strings[armv4_5->core_state]);
+
+ return ERROR_OK;
+}
+
+int armv4_5_register_commands(struct command_context_s *cmd_ctx)
+{
+ command_t *armv4_5_cmd;
+
+ armv4_5_cmd = register_command(cmd_ctx, NULL, "armv4_5", NULL, COMMAND_ANY, NULL);
+
+ register_command(cmd_ctx, armv4_5_cmd, "reg", handle_armv4_5_reg_command, COMMAND_EXEC, "display ARM core registers");
+ register_command(cmd_ctx, armv4_5_cmd, "core_state", handle_armv4_5_core_state_command, COMMAND_EXEC, "display/change ARM core state <arm|thumb>");
+
+ return ERROR_OK;
+}
+
+int armv4_5_get_gdb_reg_list(target_t *target, reg_t **reg_list[], int *reg_list_size)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ int i;
+
+ if (target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ *reg_list_size = 26;
+ *reg_list = malloc(sizeof(reg_t*) * (*reg_list_size));
+
+ for (i = 0; i < 16; i++)
+ {
+ (*reg_list)[i] = &ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i);
+ }
+
+ for (i = 16; i < 24; i++)
+ {
+ (*reg_list)[i] = &armv4_5_gdb_dummy_fp_reg;
+ }
+
+ (*reg_list)[24] = &armv4_5_gdb_dummy_fps_reg;
+ (*reg_list)[25] = &armv4_5->core_cache->reg_list[ARMV4_5_CPSR];
+
+ return ERROR_OK;
+}
+
+int armv4_5_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_params, u32 entry_point, u32 exit_point, int timeout_ms, void *arch_info)
+{
+ armv4_5_common_t *armv4_5 = target->arch_info;
+ armv4_5_algorithm_t *armv4_5_algorithm_info = arch_info;
+ enum armv4_5_state core_state = armv4_5->core_state;
+ enum armv4_5_mode core_mode = armv4_5->core_mode;
+ u32 context[17];
+ u32 cpsr;
+ int exit_breakpoint_size = 0;
+ int i;
+ int retval = ERROR_OK;
+
+ if (armv4_5_algorithm_info->common_magic != ARMV4_5_COMMON_MAGIC)
+ {
+ ERROR("current target isn't an ARMV4/5 target");
+ return ERROR_TARGET_INVALID;
+ }
+
+ if (target->state != TARGET_HALTED)
+ {
+ WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ for (i = 0; i <= 16; i++)
+ {
+ if (!ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).valid)
+ armv4_5->read_core_reg(target, i, armv4_5_algorithm_info->core_mode);
+ context[i] = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).value, 0, 32);
+ }
+ cpsr = buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32);
+
+ for (i = 0; i < num_mem_params; i++)
+ {
+ target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value);
+ }
+
+ for (i = 0; i < num_reg_params; i++)
+ {
+ reg_t *reg = register_get_by_name(armv4_5->core_cache, reg_params[i].reg_name, 0);
+ if (!reg)
+ {
+ ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
+ exit(-1);
+ }
+
+ if (reg->size != reg_params[i].size)
+ {
+ ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name);
+ exit(-1);
+ }
+
+ armv4_5_set_core_reg(reg, buf_get_u32(reg_params[i].value, 0, 32));
+ }
+
+ armv4_5->core_state = armv4_5_algorithm_info->core_state;
+ if (armv4_5->core_state == ARMV4_5_STATE_ARM)
+ exit_breakpoint_size = 4;
+ else if (armv4_5->core_state == ARMV4_5_STATE_THUMB)
+ exit_breakpoint_size = 2;
+ else
+ {
+ ERROR("BUG: can't execute algorithms when not in ARM or Thumb state");
+ exit(-1);
+ }
+
+ if (armv4_5_algorithm_info->core_mode != ARMV4_5_MODE_ANY)
+ {
+ DEBUG("setting core_mode: 0x%2.2x", armv4_5_algorithm_info->core_mode);
+ buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 5, armv4_5_algorithm_info->core_mode);
+ armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
+ armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
+ }
+
+ if ((retval = breakpoint_add(target, exit_point, exit_breakpoint_size, BKPT_HARD)) != ERROR_OK)
+ {
+ ERROR("can't add breakpoint to finish algorithm execution");
+ return ERROR_TARGET_FAILURE;
+ }
+
+ target->type->resume(target, 0, entry_point, 1, 1);
+ target->type->poll(target);
+
+ while (target->state != TARGET_HALTED)
+ {
+ usleep(10000);
+ target->type->poll(target);
+ if ((timeout_ms -= 10) <= 0)
+ {
+ ERROR("timeout waiting for algorithm to complete, trying to halt target");
+ target->type->halt(target);
+ timeout_ms = 1000;
+ while (target->state != TARGET_HALTED)
+ {
+ usleep(10000);
+ target->type->poll(target);
+ if ((timeout_ms -= 10) <= 0)
+ {
+ ERROR("target didn't reenter debug state, exiting");
+ exit(-1);
+ }
+ }
+ retval = ERROR_TARGET_TIMEOUT;
+ }
+ }
+
+ breakpoint_remove(target, exit_point);
+
+ for (i = 0; i < num_mem_params; i++)
+ {
+ if (mem_params[i].direction != PARAM_OUT)
+ target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value);
+ }
+
+ for (i = 0; i < num_reg_params; i++)
+ {
+ if (reg_params[i].direction != PARAM_OUT)
+ {
+
+ reg_t *reg = register_get_by_name(armv4_5->core_cache, reg_params[i].reg_name, 0);
+ if (!reg)
+ {
+ ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
+ exit(-1);
+ }
+
+ if (reg->size != reg_params[i].size)
+ {
+ ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name);
+ exit(-1);
+ }
+
+ buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
+ }
+ }
+
+ for (i = 0; i <= 16; i++)
+ {
+ DEBUG("restoring register %s with value 0x%8.8x", ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).name, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).value, 0, 32));
+ buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).value, 0, 32, context[i]);
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).valid = 1;
+ ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).dirty = 1;
+ }
+ buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32, cpsr);
+ armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
+ armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
+
+ armv4_5->core_state = core_state;
+ armv4_5->core_mode = core_mode;
+
+ return retval;
+}
+
+int armv4_5_init_arch_info(target_t *target, armv4_5_common_t *armv4_5)
+{
+ target->arch_info = armv4_5;
+
+ armv4_5->common_magic = ARMV4_5_COMMON_MAGIC;
+ armv4_5->core_state = ARMV4_5_STATE_ARM;
+ armv4_5->core_mode = ARMV4_5_MODE_USR;
+
+ return ERROR_OK;
+}
diff --git a/src/target/armv4_5.h b/src/target/armv4_5.h
new file mode 100644
index 00000000..a28bfa12
--- /dev/null
+++ b/src/target/armv4_5.h
@@ -0,0 +1,237 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef ARMV4_5_H
+#define ARMV4_5_H
+
+#include "register.h"
+#include "target.h"
+
+enum armv4_5_mode
+{
+ ARMV4_5_MODE_USR = 16,
+ ARMV4_5_MODE_FIQ = 17,
+ ARMV4_5_MODE_IRQ = 18,
+ ARMV4_5_MODE_SVC = 19,
+ ARMV4_5_MODE_ABT = 23,
+ ARMV4_5_MODE_UND = 27,
+ ARMV4_5_MODE_SYS = 31,
+ ARMV4_5_MODE_ANY = -1
+};
+
+extern char* armv4_5_mode_strings[];
+
+enum armv4_5_state
+{
+ ARMV4_5_STATE_ARM,
+ ARMV4_5_STATE_THUMB,
+ ARMV4_5_STATE_JAZELLE,
+};
+
+extern char* armv4_5_state_strings[];
+
+extern int armv4_5_core_reg_map[7][17];
+
+#define ARMV4_5_CORE_REG_MODE(cache, mode, num) \
+ cache->reg_list[armv4_5_core_reg_map[armv4_5_mode_to_number(mode)][num]]
+#define ARMV4_5_CORE_REG_MODENUM(cache, mode, num) \
+ cache->reg_list[armv4_5_core_reg_map[mode][num]]
+
+/* offsets into armv4_5 core register cache */
+enum
+{
+ ARMV4_5_CPSR = 31,
+ ARMV4_5_SPSR_FIQ = 32,
+ ARMV4_5_SPSR_IRQ = 33,
+ ARMV4_5_SPSR_SVC = 34,
+ ARMV4_5_SPSR_ABT = 35,
+ ARMV4_5_SPSR_UND = 36
+};
+
+#define ARMV4_5_COMMON_MAGIC 0x0A450A45
+
+typedef struct armv4_5_common_s
+{
+ int common_magic;
+ reg_cache_t *core_cache;
+ enum armv4_5_mode core_mode;
+ enum armv4_5_state core_state;
+ int (*full_context)(struct target_s *target);
+ int (*read_core_reg)(struct target_s *target, int num, enum armv4_5_mode mode);
+ int (*write_core_reg)(struct target_s *target, int num, enum armv4_5_mode mode, u32 value);
+ void *arch_info;
+} armv4_5_common_t;
+
+typedef struct armv4_5_algorithm_s
+{
+ int common_magic;
+
+ enum armv4_5_mode core_mode;
+ enum armv4_5_state core_state;
+} armv4_5_algorithm_t;
+
+typedef struct armv4_5_core_reg_s
+{
+ int num;
+ enum armv4_5_mode mode;
+ target_t *target;
+ armv4_5_common_t *armv4_5_common;
+} armv4_5_core_reg_t;
+
+extern reg_cache_t* armv4_5_build_reg_cache(target_t *target, armv4_5_common_t *armv4_5_common);
+extern enum armv4_5_mode armv4_5_number_to_mode(int number);
+extern int armv4_5_mode_to_number(enum armv4_5_mode mode);
+
+extern int armv4_5_arch_state(struct target_s *target, char *buf, int buf_size);
+extern int armv4_5_get_gdb_reg_list(target_t *target, reg_t **reg_list[], int *reg_list_size);
+extern int armv4_5_invalidate_core_regs(target_t *target);
+
+extern int armv4_5_register_commands(struct command_context_s *cmd_ctx);
+extern int armv4_5_init_arch_info(target_t *target, armv4_5_common_t *armv4_5);
+
+extern int armv4_5_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_params, u32 entry_point, u32 exit_point, int timeout_ms, void *arch_info);
+
+extern int armv4_5_invalidate_core_regs(target_t *target);
+
+/* ARM mode instructions
+ */
+
+/* Store multiple increment after
+ * Rn: base register
+ * List: for each bit in list: store register
+ * S: in priviledged mode: store user-mode registers
+ * W=1: update the base register. W=0: leave the base register untouched
+ */
+#define ARMV4_5_STMIA(Rn, List, S, W) (0xe8800000 | (S << 22) | (W << 21) | (Rn << 16) | (List))
+
+/* Load multiple increment after
+ * Rn: base register
+ * List: for each bit in list: store register
+ * S: in priviledged mode: store user-mode registers
+ * W=1: update the base register. W=0: leave the base register untouched
+ */
+#define ARMV4_5_LDMIA(Rn, List, S, W) (0xe8900000 | (S << 22) | (W << 21) | (Rn << 16) | (List))
+
+/* MOV r8, r8 */
+#define ARMV4_5_NOP (0xe1a08008)
+
+/* Move PSR to general purpose register
+ * R=1: SPSR R=0: CPSR
+ * Rn: target register
+ */
+#define ARMV4_5_MRS(Rn, R) (0xe10f0000 | (R << 22) | (Rn << 12))
+
+/* Store register
+ * Rd: register to store
+ * Rn: base register
+ */
+#define ARMV4_5_STR(Rd, Rn) (0xe5800000 | (Rd << 12) | (Rn << 16))
+
+/* Load register
+ * Rd: register to load
+ * Rn: base register
+ */
+#define ARMV4_5_LDR(Rd, Rn) (0xe5900000 | (Rd << 12) | (Rn << 16))
+
+/* Move general purpose register to PSR
+ * R=1: SPSR R=0: CPSR
+ * Field: Field mask
+ * 1: control field 2: extension field 4: status field 8: flags field
+ * Rm: source register
+ */
+#define ARMV4_5_MSR_GP(Rm, Field, R) (0xe120f000 | Rm | (Field << 16) | (R << 22))
+#define ARMV4_5_MSR_IM(Im, Rotate, Field, R) (0xe320f000 | (Im) | (Rotate << 8) | (Field << 16) | (R << 22))
+
+/* Load Register Halfword Immediate Post-Index
+ * Rd: register to load
+ * Rn: base register
+ */
+#define ARMV4_5_LDRH_IP(Rd, Rn) (0xe0d000b2 | (Rd << 12) | (Rn << 16))
+
+/* Load Register Byte Immediate Post-Index
+ * Rd: register to load
+ * Rn: base register
+ */
+#define ARMV4_5_LDRB_IP(Rd, Rn) (0xe4d00001 | (Rd << 12) | (Rn << 16))
+
+/* Store register Halfword Immediate Post-Index
+ * Rd: register to store
+ * Rn: base register
+ */
+#define ARMV4_5_STRH_IP(Rd, Rn) (0xe0c000b2 | (Rd << 12) | (Rn << 16))
+
+/* Store register Byte Immediate Post-Index
+ * Rd: register to store
+ * Rn: base register
+ */
+#define ARMV4_5_STRB_IP(Rd, Rn) (0xe4c00001 | (Rd << 12) | (Rn << 16))
+
+/* Branch (and Link)
+ * Im: Branch target (left-shifted by 2 bits, added to PC)
+ * L: 1: branch and link 0: branch only
+ */
+#define ARMV4_5_B(Im, L) (0xea000000 | Im | (L << 24))
+
+/* Branch and exchange (ARM state)
+ * Rm: register holding branch target address
+ */
+#define ARMV4_5_BX(Rm) (0xe12fff10 | Rm)
+
+/* Thumb mode instructions
+ */
+
+/* Store register (Thumb mode)
+ * Rd: source register
+ * Rn: base register
+ */
+#define ARMV4_5_T_STR(Rd, Rn) ((0x6000 | Rd | (Rn << 3)) | ((0x6000 | Rd | (Rn << 3)) << 16))
+
+/* Load register (Thumb state)
+ * Rd: destination register
+ * Rn: base register
+ */
+#define ARMV4_5_T_LDR(Rd, Rn) ((0x6800 | (Rn << 3) | Rd) | ((0x6800 | (Rn << 3) | Rd) << 16))
+
+/* Move hi register (Thumb mode)
+ * Rd: destination register
+ * Rm: source register
+ */
+#define ARMV4_5_T_MOV(Rd, Rm) ((0x4600 | (Rd & 0x7) | ((Rd & 0x8) << 4) | ((Rm & 0x7) << 3) | ((Rm & 0x8) << 3)) | ((0x4600 | (Rd & 0x7) | ((Rd & 0x8) << 4) | ((Rm & 0x7) << 3) | ((Rm & 0x8) << 3)) << 16))
+
+/* No operation (Thumb mode)
+ */
+#define ARMV4_5_T_NOP (0x1c3f | (0x1c3f << 16))
+
+/* Move immediate to register (Thumb state)
+ * Rd: destination register
+ * Im: 8-bit immediate value
+ */
+#define ARMV4_5_T_MOV_IM(Rd, Im) ((0x2000 | (Rd << 8) | Im) | ((0x2000 | (Rd << 8) | Im) << 16))
+
+/* Branch and Exchange
+ * Rm: register containing branch target
+ */
+#define ARMV4_5_T_BX(Rm) ((0x4700 | (Rm << 3)) | ((0x4700 | (Rm << 3)) << 16))
+
+/* Branch (Thumb state)
+ * Imm: Branch target
+ */
+#define ARMV4_5_T_B(Imm) ((0xe000 | Imm) | ((0xe000 | Imm) << 16))
+
+#endif /* ARMV4_5_H */
diff --git a/src/target/armv4_5_cache.c b/src/target/armv4_5_cache.c
new file mode 100644
index 00000000..326f10ee
--- /dev/null
+++ b/src/target/armv4_5_cache.c
@@ -0,0 +1,112 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "armv4_5_cache.h"
+
+#include "log.h"
+#include "command.h"
+
+int armv4_5_identify_cache(u32 cache_type_reg, armv4_5_cache_common_t *cache)
+{
+ int size, assoc, M, len, multiplier;
+
+ cache->ctype = (cache_type_reg & 0x1e000000U) >> 25;
+ cache->separate = (cache_type_reg & 0x01000000U) >> 24;
+
+ size = (cache_type_reg & 0x1c0000) >> 18;
+ assoc = (cache_type_reg & 0x38000) >> 15;
+ M = (cache_type_reg & 0x4000) >> 14;
+ len = (cache_type_reg & 0x3000) >> 12;
+ multiplier = 2 + M;
+
+ if ((assoc != 0) || (M != 1)) /* assoc 0 and M 1 means cache absent */
+ {
+ /* cache is present */
+ cache->d_u_size.linelen = 1 << (len + 3);
+ cache->d_u_size.associativity = multiplier << (assoc - 1);
+ cache->d_u_size.nsets = 1 << (size + 6 - assoc - len);
+ cache->d_u_size.cachesize = multiplier << (size + 8);
+ }
+ else
+ {
+ /* cache is absent */
+ cache->d_u_size.linelen = -1;
+ cache->d_u_size.associativity = -1;
+ cache->d_u_size.nsets = -1;
+ cache->d_u_size.cachesize = -1;
+ }
+
+ if (cache->separate)
+ {
+ size = (cache_type_reg & 0x1c0) >> 6;
+ assoc = (cache_type_reg & 0x38) >> 3;
+ M = (cache_type_reg & 0x4) >> 2;
+ len = (cache_type_reg & 0x3);
+ multiplier = 2 + M;
+
+ if ((assoc != 0) || (M != 1)) /* assoc 0 and M 1 means cache absent */
+ {
+ /* cache is present */
+ cache->i_size.linelen = 1 << (len + 3);
+ cache->i_size.associativity = multiplier << (assoc - 1);
+ cache->i_size.nsets = 1 << (size + 6 - assoc - len);
+ cache->i_size.cachesize = multiplier << (size + 8);
+ }
+ else
+ {
+ /* cache is absent */
+ cache->i_size.linelen = -1;
+ cache->i_size.associativity = -1;
+ cache->i_size.nsets = -1;
+ cache->i_size.cachesize = -1;
+ }
+ }
+ else
+ {
+ cache->i_size = cache->d_u_size;
+ }
+
+ return ERROR_OK;
+}
+
+int armv4_5_handle_cache_info_command(struct command_context_s *cmd_ctx, armv4_5_cache_common_t *armv4_5_cache)
+{
+ if (armv4_5_cache->ctype == -1)
+ {
+ command_print(cmd_ctx, "cache not yet identified");
+ return ERROR_OK;
+ }
+
+ command_print(cmd_ctx, "cache type: 0x%1.1x, %s", armv4_5_cache->ctype,
+ (armv4_5_cache->separate) ? "separate caches" : "unified cache");
+
+ command_print(cmd_ctx, "D-Cache: linelen %i, associativity %i, nsets %i, cachesize 0x%x",
+ armv4_5_cache->d_u_size.linelen,
+ armv4_5_cache->d_u_size.associativity,
+ armv4_5_cache->d_u_size.nsets,
+ armv4_5_cache->d_u_size.cachesize);
+
+ command_print(cmd_ctx, "I-Cache: linelen %i, associativity %i, nsets %i, cachesize 0x%x",
+ armv4_5_cache->i_size.linelen,
+ armv4_5_cache->i_size.associativity,
+ armv4_5_cache->i_size.nsets,
+ armv4_5_cache->i_size.cachesize);
+
+ return ERROR_OK;
+}
diff --git a/src/target/armv4_5_cache.h b/src/target/armv4_5_cache.h
new file mode 100644
index 00000000..766718b6
--- /dev/null
+++ b/src/target/armv4_5_cache.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef ARMV4_5_CACHE_H
+#define ARMV4_5_CACHE_H
+
+#include "types.h"
+#include "command.h"
+
+typedef struct armv4_5_cachesize_s
+{
+ int linelen;
+ int associativity;
+ int nsets;
+ int cachesize;
+} armv4_5_cachesize_t;
+
+typedef struct armv4_5_cache_common_s
+{
+ int ctype; /* specify supported cache operations */
+ int separate; /* separate caches or unified cache */
+ armv4_5_cachesize_t d_u_size; /* data cache */
+ armv4_5_cachesize_t i_size; /* instruction cache */
+ int i_cache_enabled;
+ int d_u_cache_enabled;
+} armv4_5_cache_common_t;
+
+extern int armv4_5_identify_cache(u32 cache_type_reg, armv4_5_cache_common_t *cache);
+extern int armv4_5_cache_state(u32 cp15_control_reg, armv4_5_cache_common_t *cache);
+
+extern int armv4_5_handle_cache_info_command(struct command_context_s *cmd_ctx, armv4_5_cache_common_t *armv4_5_cache);
+
+#endif /* ARMV4_5_CACHE_H */
diff --git a/src/target/armv4_5_mmu.c b/src/target/armv4_5_mmu.c
new file mode 100644
index 00000000..c7dad3e2
--- /dev/null
+++ b/src/target/armv4_5_mmu.c
@@ -0,0 +1,358 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "arm7_9_common.h"
+#include "log.h"
+#include "command.h"
+#include "armv4_5_mmu.h"
+
+#include <stdlib.h>
+
+u32 armv4mmu_translate_va(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 va, int *type, u32 *cb, int *domain, u32 *ap);
+int armv4_5_mmu_read_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer);
+int armv4_5_mmu_write_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer);
+
+char* armv4_5_mmu_page_type_names[] =
+{
+ "section", "large page", "small page", "tiny page"
+};
+
+u32 armv4_5_mmu_translate_va(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 va, int *type, u32 *cb, int *domain, u32 *ap)
+{
+ u32 first_lvl_descriptor = 0x0;
+ u32 second_lvl_descriptor = 0x0;
+ u32 ttb = armv4_5_mmu->get_ttb(target);
+
+ armv4_5_mmu_read_physical(target, armv4_5_mmu,
+ (ttb & 0xffffc000) | ((va & 0xfff00000) >> 18),
+ 4, 1, (u8*)&first_lvl_descriptor);
+
+ DEBUG("1st lvl desc: %8.8x", first_lvl_descriptor);
+
+ if ((first_lvl_descriptor & 0x3) == 0)
+ {
+ *type = -1;
+ return ERROR_TARGET_TRANSLATION_FAULT;
+ }
+
+ if (!armv4_5_mmu->has_tiny_pages && ((first_lvl_descriptor & 0x3) == 3))
+ {
+ *type = -1;
+ return ERROR_TARGET_TRANSLATION_FAULT;
+ }
+
+ /* domain is always specified in bits 8-5 */
+ *domain = (first_lvl_descriptor & 0x1e0) >> 5;
+
+ if ((first_lvl_descriptor & 0x3) == 2)
+ {
+ /* section descriptor */
+ *type = ARMV4_5_SECTION;
+ *cb = (first_lvl_descriptor & 0xc) >> 2;
+ *ap = (first_lvl_descriptor & 0xc00) >> 10;
+ return (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
+ }
+
+ if ((first_lvl_descriptor & 0x3) == 1)
+ {
+ /* coarse page table */
+ armv4_5_mmu_read_physical(target, armv4_5_mmu,
+ (first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10),
+ 4, 1, (u8*)&second_lvl_descriptor);
+ }
+
+ if ((first_lvl_descriptor & 0x3) == 3)
+ {
+ /* fine page table */
+ armv4_5_mmu_read_physical(target, armv4_5_mmu,
+ (first_lvl_descriptor & 0xfffff000) | ((va & 0x000ffc00) >> 8),
+ 4, 1, (u8*)&second_lvl_descriptor);
+ }
+
+ DEBUG("2nd lvl desc: %8.8x", first_lvl_descriptor);
+
+ if ((second_lvl_descriptor & 0x3) == 0)
+ {
+ *type = -1;
+ return ERROR_TARGET_TRANSLATION_FAULT;
+ }
+
+ /* cacheable/bufferable is always specified in bits 3-2 */
+ *cb = (second_lvl_descriptor & 0xc) >> 2;
+
+ if ((second_lvl_descriptor & 0x3) == 1)
+ {
+ /* large page descriptor */
+ *type = ARMV4_5_LARGE_PAGE;
+ *ap = (second_lvl_descriptor & 0xff0) >> 4;
+ return (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff);
+ }
+
+ if ((second_lvl_descriptor & 0x3) == 2)
+ {
+ /* small page descriptor */
+ *type = ARMV4_5_SMALL_PAGE;
+ *ap = (second_lvl_descriptor & 0xff0) >> 4;
+ return (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff);
+ }
+
+ if ((second_lvl_descriptor & 0x3) == 3)
+ {
+ /* tiny page descriptor */
+ *type = ARMV4_5_TINY_PAGE;
+ *ap = (second_lvl_descriptor & 0x30) >> 4;
+ return (second_lvl_descriptor & 0xfffffc00) | (va & 0x000003ff);
+ }
+
+ /* should not happen */
+ *type = -1;
+ return ERROR_TARGET_TRANSLATION_FAULT;
+}
+
+int armv4_5_mmu_read_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer)
+{
+ int retval;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ /* disable MMU and data (or unified) cache */
+ armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0);
+
+ retval = armv4_5_mmu->read_memory(target, address, size, count, buffer);
+
+ /* reenable MMU / cache */
+ armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled,
+ armv4_5_mmu->armv4_5_cache.d_u_cache_enabled,
+ armv4_5_mmu->armv4_5_cache.i_cache_enabled);
+
+ return retval;
+}
+
+int armv4_5_mmu_write_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer)
+{
+ int retval;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ /* disable MMU and data (or unified) cache */
+ armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0);
+
+ retval = armv4_5_mmu->write_memory(target, address, size, count, buffer);
+
+ /* reenable MMU / cache */
+ armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled,
+ armv4_5_mmu->armv4_5_cache.d_u_cache_enabled,
+ armv4_5_mmu->armv4_5_cache.i_cache_enabled);
+
+ return retval;
+}
+
+int armv4_5_mmu_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu)
+{
+ u32 va;
+ u32 pa;
+ int type;
+ u32 cb;
+ int domain;
+ u32 ap;
+
+ if (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "target must be stopped for \"virt2phys\" command");
+ return ERROR_OK;
+ }
+
+ if (argc == 0)
+ {
+ command_print(cmd_ctx, "usage: virt2phys <virtual address>");
+ return ERROR_OK;
+ }
+
+ if (argc == 1)
+ {
+ va = strtoul(args[0], NULL, 0);
+ pa = armv4_5_mmu_translate_va(target, armv4_5_mmu, va, &type, &cb, &domain, &ap);
+ if (type == -1)
+ {
+ switch (pa)
+ {
+ case ERROR_TARGET_TRANSLATION_FAULT:
+ command_print(cmd_ctx, "no valid translation for 0x%8.8x", va);
+ break;
+ default:
+ command_print(cmd_ctx, "unknown translation error");
+ }
+ return ERROR_OK;
+ }
+
+ command_print(cmd_ctx, "0x%8.8x -> 0x%8.8x, type: %s, cb: %i, domain: %i, ap: %2.2x",
+ va, pa, armv4_5_mmu_page_type_names[type], cb, domain, ap);
+ }
+
+ return ERROR_OK;
+}
+
+int armv4_5_mmu_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu)
+{
+ int count = 1;
+ int size = 4;
+ u32 address = 0;
+ int i;
+
+ char output[128];
+ int output_len;
+
+ int retval;
+
+ u8 *buffer;
+
+ if (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+ return ERROR_OK;
+ }
+
+ if (argc < 1)
+ return ERROR_OK;
+
+ if (argc == 2)
+ count = strtoul(args[1], NULL, 0);
+
+ address = strtoul(args[0], NULL, 0);
+
+ switch (cmd[2])
+ {
+ case 'w':
+ size = 4;
+ break;
+ case 'h':
+ size = 2;
+ break;
+ case 'b':
+ size = 1;
+ break;
+ default:
+ return ERROR_OK;
+ }
+
+ buffer = calloc(count, size);
+ if ((retval = armv4_5_mmu_read_physical(target, armv4_5_mmu, address, size, count, buffer)) != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_TARGET_UNALIGNED_ACCESS:
+ command_print(cmd_ctx, "error: address not aligned");
+ break;
+ case ERROR_TARGET_NOT_HALTED:
+ command_print(cmd_ctx, "error: target must be halted for memory accesses");
+ break;
+ case ERROR_TARGET_DATA_ABORT:
+ command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted");
+ break;
+ default:
+ command_print(cmd_ctx, "error: unknown error");
+ }
+ }
+
+ output_len = 0;
+
+ for (i = 0; i < count; i++)
+ {
+ if (i%8 == 0)
+ output_len += snprintf(output + output_len, 128 - output_len, "0x%8.8x: ", address + (i*size));
+
+ switch (size)
+ {
+ case 4:
+ output_len += snprintf(output + output_len, 128 - output_len, "%8.8x ", ((u32*)buffer)[i]);
+ break;
+ case 2:
+ output_len += snprintf(output + output_len, 128 - output_len, "%4.4x ", ((u16*)buffer)[i]);
+ break;
+ case 1:
+ output_len += snprintf(output + output_len, 128 - output_len, "%2.2x ", ((u8*)buffer)[i]);
+ break;
+ }
+
+ if ((i%8 == 7) || (i == count - 1))
+ {
+ command_print(cmd_ctx, output);
+ output_len = 0;
+ }
+ }
+
+ free(buffer);
+
+ return ERROR_OK;
+}
+
+int armv4_5_mmu_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu)
+{
+ u32 address = 0;
+ u32 value = 0;
+ int retval;
+
+ if (target->state != TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
+ return ERROR_OK;
+ }
+
+ if (argc < 2)
+ return ERROR_OK;
+
+ address = strtoul(args[0], NULL, 0);
+ value = strtoul(args[1], NULL, 0);
+
+ switch (cmd[2])
+ {
+ case 'w':
+ retval = armv4_5_mmu_write_physical(target, armv4_5_mmu, address, 4, 1, (u8*)&value);
+ break;
+ case 'h':
+ retval = armv4_5_mmu_write_physical(target, armv4_5_mmu, address, 2, 1, (u8*)&value);
+ break;
+ case 'b':
+ retval = armv4_5_mmu_write_physical(target, armv4_5_mmu, address, 1, 1, (u8*)&value);
+ break;
+ default:
+ return ERROR_OK;
+ }
+
+ switch (retval)
+ {
+ case ERROR_TARGET_UNALIGNED_ACCESS:
+ command_print(cmd_ctx, "error: address not aligned");
+ break;
+ case ERROR_TARGET_DATA_ABORT:
+ command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted");
+ break;
+ case ERROR_TARGET_NOT_HALTED:
+ command_print(cmd_ctx, "error: target must be halted for memory accesses");
+ break;
+ case ERROR_OK:
+ break;
+ default:
+ command_print(cmd_ctx, "error: unknown error");
+ }
+
+ return ERROR_OK;
+}
diff --git a/src/target/armv4_5_mmu.h b/src/target/armv4_5_mmu.h
new file mode 100644
index 00000000..3adb30e2
--- /dev/null
+++ b/src/target/armv4_5_mmu.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef ARMV4_5_MMU_H
+#define ARMV4_5_MMU_H
+
+#include "armv4_5_cache.h"
+
+typedef struct armv4_5_mmu_common_s
+{
+ u32 (*get_ttb)(target_t *target);
+ int (*read_memory)(target_t *target, u32 address, u32 size, u32 count, u8 *buffer);
+ int (*write_memory)(target_t *target, u32 address, u32 size, u32 count, u8 *buffer);
+ void (*disable_mmu_caches)(target_t *target, int mmu, int d_u_cache, int i_cache);
+ void (*enable_mmu_caches)(target_t *target, int mmu, int d_u_cache, int i_cache);
+ armv4_5_cache_common_t armv4_5_cache;
+ int has_tiny_pages;
+ int mmu_enabled;
+} armv4_5_mmu_common_t;
+
+enum
+{
+ ARMV4_5_SECTION, ARMV4_5_LARGE_PAGE, ARMV4_5_SMALL_PAGE, ARMV4_5_TINY_PAGE
+};
+
+extern char* armv4_5_page_type_names[];
+
+extern u32 armv4_5_mmu_translate_va(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 va, int *type, u32 *cb, int *domain, u32 *ap);
+extern int armv4_5_mmu_read_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer);
+extern int armv4_5_mmu_write_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer);
+
+extern int armv4_5_mmu_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu);
+extern int armv4_5_mmu_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu);
+extern int armv4_5_mmu_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu);
+
+#endif /* ARMV4_5_MMU_H */
diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c
new file mode 100644
index 00000000..efba25c9
--- /dev/null
+++ b/src/target/breakpoints.c
@@ -0,0 +1,219 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "config.h"
+
+#include <stdlib.h>
+
+#include "binarybuffer.h"
+#include "target.h"
+#include "log.h"
+#include "types.h"
+
+#include "breakpoints.h"
+
+char *breakpoint_type_strings[] =
+{
+ "hardware",
+ "software"
+};
+
+char *watchpoint_rw_strings[] =
+{
+ "read",
+ "write",
+ "access"
+};
+
+int breakpoint_add(target_t *target, u32 address, u32 length, enum breakpoint_type type)
+{
+ breakpoint_t *breakpoint = target->breakpoints;
+ breakpoint_t **breakpoint_p = &target->breakpoints;
+ int retval;
+
+ while (breakpoint)
+ {
+ if (breakpoint->address == address)
+ return ERROR_OK;
+ breakpoint_p = &breakpoint->next;
+ breakpoint = breakpoint->next;
+ }
+
+ if ((retval = target->type->add_breakpoint(target, address, length, type)) != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
+ INFO("can't add %s breakpoint, resource not available", breakpoint_type_strings[type]);
+ return retval;
+ break;
+ case ERROR_TARGET_NOT_HALTED:
+ INFO("can't add breakpoint while target is running");
+ return retval;
+ break;
+ default:
+ ERROR("unknown error");
+ exit(-1);
+ break;
+ }
+ }
+
+ (*breakpoint_p) = malloc(sizeof(breakpoint_t));
+ (*breakpoint_p)->address = address;
+ (*breakpoint_p)->length = length;
+ (*breakpoint_p)->type = type;
+ (*breakpoint_p)->set = 0;
+ (*breakpoint_p)->orig_instr = malloc(CEIL(length, 8));
+ (*breakpoint_p)->next = NULL;
+
+ DEBUG("added %s breakpoint at 0x%8.8x of length 0x%8.8x", breakpoint_type_strings[type], address, length);
+
+ return ERROR_OK;
+}
+
+int breakpoint_remove(target_t *target, u32 address)
+{
+ breakpoint_t *breakpoint = target->breakpoints;
+ breakpoint_t **breakpoint_p = &target->breakpoints;
+ int retval;
+
+ while (breakpoint)
+ {
+ if (breakpoint->address == address)
+ break;
+ breakpoint_p = &breakpoint->next;
+ breakpoint = breakpoint->next;
+ }
+
+ if (breakpoint)
+ {
+ if ((retval = target->type->remove_breakpoint(target, breakpoint)) != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_TARGET_NOT_HALTED:
+ INFO("can't remove breakpoint while target is running");
+ return retval;
+ break;
+ default:
+ ERROR("unknown error");
+ exit(-1);
+ break;
+ }
+ }
+ (*breakpoint_p) = breakpoint->next;
+ free(breakpoint->orig_instr);
+ free(breakpoint);
+ }
+ else
+ {
+ ERROR("no breakpoint at address 0x%8.8x found", address);
+ }
+
+ return ERROR_OK;
+}
+
+breakpoint_t* breakpoint_find(target_t *target, u32 address)
+{
+ breakpoint_t *breakpoint = target->breakpoints;
+
+ while (breakpoint)
+ {
+ if (breakpoint->address == address)
+ return breakpoint;
+ breakpoint = breakpoint->next;
+ }
+
+ return NULL;
+}
+
+int watchpoint_add(target_t *target, u32 address, u32 length, enum watchpoint_rw rw, u32 value, u32 mask)
+{
+ watchpoint_t *watchpoint = target->watchpoints;
+ watchpoint_t **watchpoint_p = &target->watchpoints;
+ int retval;
+
+ while (watchpoint)
+ {
+ if (watchpoint->address == address)
+ return ERROR_OK;
+ watchpoint_p = &watchpoint->next;
+ watchpoint = watchpoint->next;
+ }
+
+ if ((retval = target->type->add_watchpoint(target, address, length, rw)) != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
+ INFO("can't add %s watchpoint, resource not available", watchpoint_rw_strings[rw]);
+ return retval;
+ break;
+ default:
+ ERROR("unknown error");
+ exit(-1);
+ break;
+ }
+ }
+
+ (*watchpoint_p) = malloc(sizeof(watchpoint_t));
+ (*watchpoint_p)->address = address;
+ (*watchpoint_p)->length = length;
+ (*watchpoint_p)->value = value;
+ (*watchpoint_p)->mask = mask;
+ (*watchpoint_p)->rw = rw;
+ (*watchpoint_p)->set = 0;
+ (*watchpoint_p)->next = NULL;
+
+ DEBUG("added %s watchpoint at 0x%8.8x of length 0x%8.8x", watchpoint_rw_strings[rw], address, length);
+
+ return ERROR_OK;
+}
+
+int watchpoint_remove(target_t *target, u32 address)
+{
+ watchpoint_t *watchpoint = target->watchpoints;
+ watchpoint_t **watchpoint_p = &target->watchpoints;
+ int retval;
+
+ while (watchpoint)
+ {
+ if (watchpoint->address == address)
+ break;
+ watchpoint_p = &watchpoint->next;
+ watchpoint = watchpoint->next;
+ }
+
+ if (watchpoint)
+ {
+ if ((retval = target->type->remove_watchpoint(target, watchpoint)) != ERROR_OK)
+ {
+ ERROR("BUG: can't remove watchpoint");
+ exit(-1);
+ }
+ (*watchpoint_p) = watchpoint->next;
+ free(watchpoint);
+ }
+ else
+ {
+ ERROR("no watchpoint at address 0x%8.8x found", address);
+ }
+
+ return ERROR_OK;
+}
diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h
new file mode 100644
index 00000000..7eba39aa
--- /dev/null
+++ b/src/target/breakpoints.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef BREAKPOINTS_H
+#define BREAKPOINTS_H
+
+#include "target.h"
+
+struct target_s;
+
+enum breakpoint_type
+{
+ BKPT_HARD,
+ BKPT_SOFT,
+};
+
+extern char *breakpoint_type_strings[];
+
+enum watchpoint_rw
+{
+ WPT_READ = 0, WPT_WRITE = 1, WPT_ACCESS = 2
+};
+
+extern char *watchpoint_rw_strings[];
+
+typedef struct breakpoint_s
+{
+ u32 address;
+ int length;
+ enum breakpoint_type type;
+ int set;
+ u8 *orig_instr;
+ struct breakpoint_s *next;
+} breakpoint_t;
+
+typedef struct watchpoint_s
+{
+ u32 address;
+ int length;
+ u32 mask;
+ u32 value;
+ enum watchpoint_rw rw;
+ int set;
+ struct watchpoint_s *next;
+} watchpoint_t;
+
+extern int breakpoint_add(struct target_s *target, u32 address, u32 length, enum breakpoint_type type);
+extern int breakpoint_remove(struct target_s *target, u32 address);
+extern breakpoint_t* breakpoint_find(struct target_s *target, u32 address);
+extern int watchpoint_add(struct target_s *target, u32 address, u32 length, enum watchpoint_rw rw, u32 value, u32 mask);
+extern int watchpoint_remove(struct target_s *target, u32 address);
+
+#endif /* BREAKPOINTS_H */
+
diff --git a/src/target/embeddedice.c b/src/target/embeddedice.c
new file mode 100644
index 00000000..e148b888
--- /dev/null
+++ b/src/target/embeddedice.c
@@ -0,0 +1,301 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "config.h"
+
+#include "embeddedice.h"
+
+#include "armv4_5.h"
+#include "arm7_9_common.h"
+
+#include "log.h"
+#include "arm_jtag.h"
+#include "types.h"
+#include "binarybuffer.h"
+#include "target.h"
+#include "register.h"
+#include "jtag.h"
+
+#include <stdlib.h>
+
+bitfield_desc_t embeddedice_comms_ctrl_bitfield_desc[] =
+{
+ {"R", 1},
+ {"W", 1},
+ {"reserved", 26},
+ {"version", 4}
+};
+
+int embeddedice_reg_arch_info[] =
+{
+ 0x0, 0x1, 0x4, 0x5,
+ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15
+};
+
+char* embeddedice_reg_list[] =
+{
+ "debug_ctrl",
+ "debug_status",
+
+ "comms_ctrl",
+ "comms_data",
+
+ "watch 0 addr value",
+ "watch 0 addr mask",
+ "watch 0 data value",
+ "watch 0 data mask",
+ "watch 0 control value",
+ "watch 0 control mask",
+
+ "watch 1 addr value",
+ "watch 1 addr mask",
+ "watch 1 data value",
+ "watch 1 data mask",
+ "watch 1 control value",
+ "watch 1 control mask"
+};
+
+int embeddedice_reg_arch_type = -1;
+
+int embeddedice_get_reg(reg_t *reg);
+int embeddedice_set_reg(reg_t *reg, u32 value);
+
+int embeddedice_write_reg(reg_t *reg, u32 value);
+int embeddedice_read_reg(reg_t *reg);
+
+reg_cache_t* embeddedice_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg)
+{
+ reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t));
+ reg_t *reg_list = NULL;
+ embeddedice_reg_t *arch_info = NULL;
+ int num_regs = 16 + extra_reg;
+ int i;
+
+ /* register a register arch-type for EmbeddedICE registers only once */
+ if (embeddedice_reg_arch_type == -1)
+ embeddedice_reg_arch_type = register_reg_arch_type(embeddedice_get_reg, embeddedice_set_reg_w_exec);
+
+ /* the actual registers are kept in two arrays */
+ reg_list = calloc(num_regs, sizeof(reg_t));
+ arch_info = calloc(num_regs, sizeof(embeddedice_reg_t));
+
+ /* fill in values for the reg cache */
+ reg_cache->name = "EmbeddedICE registers";
+ reg_cache->next = NULL;
+ reg_cache->reg_list = reg_list;
+ reg_cache->num_regs = num_regs;
+
+ /* set up registers */
+ for (i = 0; i < num_regs - extra_reg; i++)
+ {
+ reg_list[i].name = embeddedice_reg_list[i];
+ reg_list[i].size = 32;
+ reg_list[i].dirty = 0;
+ reg_list[i].valid = 0;
+ reg_list[i].bitfield_desc = NULL;
+ reg_list[i].num_bitfields = 0;
+ reg_list[i].value = calloc(1, 4);
+ reg_list[i].arch_info = &arch_info[i];
+ reg_list[i].arch_type = embeddedice_reg_arch_type;
+ arch_info[i].addr = embeddedice_reg_arch_info[i];
+ arch_info[i].jtag_info = jtag_info;
+ }
+
+ /* there may be one extra reg (Abort status (ARM7 rev4) or Vector catch (ARM9)) */
+ if (extra_reg)
+ {
+ reg_list[num_regs - 1].arch_info = &arch_info[num_regs - 1];
+ arch_info[num_regs - 1].jtag_info = jtag_info;
+ }
+
+ return reg_cache;
+}
+
+int embeddedice_get_reg(reg_t *reg)
+{
+ if (embeddedice_read_reg(reg) != ERROR_OK)
+ {
+ ERROR("BUG: error scheduling EmbeddedICE register read");
+ exit(-1);
+ }
+
+ if (jtag_execute_queue() != ERROR_OK)
+ {
+ ERROR("register read failed");
+ }
+
+ return ERROR_OK;
+}
+
+int embeddedice_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask)
+{
+ embeddedice_reg_t *ice_reg = reg->arch_info;
+ u8 reg_addr = ice_reg->addr & 0x1f;
+ scan_field_t fields[3];
+
+ DEBUG("%i", ice_reg->addr);
+
+ jtag_add_end_state(TAP_RTI);
+ arm_jtag_scann(ice_reg->jtag_info, 0x2);
+ arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr);
+
+ fields[0].device = ice_reg->jtag_info->chain_pos;
+ fields[0].num_bits = 32;
+ fields[0].out_value = reg->value;
+ 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 = ice_reg->jtag_info->chain_pos;
+ fields[1].num_bits = 5;
+ fields[1].out_value = malloc(1);
+ buf_set_u32(fields[1].out_value, 0, 5, reg_addr);
+ 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 = ice_reg->jtag_info->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);
+
+ fields[0].in_value = reg->value;
+ fields[0].in_check_value = check_value;
+ fields[0].in_check_mask = check_mask;
+
+ /* when reading the DCC data register, leaving the address field set to
+ * EICE_COMMS_DATA would read the register twice
+ * reading the control register is safe
+ */
+ buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]);
+
+ jtag_add_dr_scan(3, fields, -1);
+
+ free(fields[1].out_value);
+ free(fields[2].out_value);
+
+ return ERROR_OK;
+}
+
+int embeddedice_read_reg(reg_t *reg)
+{
+ return embeddedice_read_reg_w_check(reg, NULL, NULL);
+}
+
+int embeddedice_set_reg(reg_t *reg, u32 value)
+{
+ if (embeddedice_write_reg(reg, value) != ERROR_OK)
+ {
+ ERROR("BUG: error scheduling EmbeddedICE register write");
+ exit(-1);
+ }
+
+ buf_set_u32(reg->value, 0, reg->size, value);
+ reg->valid = 1;
+ reg->dirty = 0;
+
+ return ERROR_OK;
+}
+
+int embeddedice_set_reg_w_exec(reg_t *reg, u32 value)
+{
+ embeddedice_set_reg(reg, value);
+
+ if (jtag_execute_queue() != ERROR_OK)
+ {
+ ERROR("register write failed");
+ exit(-1);
+ }
+ return ERROR_OK;
+}
+
+int embeddedice_write_reg(reg_t *reg, u32 value)
+{
+ embeddedice_reg_t *ice_reg = reg->arch_info;
+ u8 reg_addr = ice_reg->addr & 0x1f;
+ scan_field_t fields[3];
+
+ DEBUG("%i: 0x%8.8x", ice_reg->addr, value);
+
+ jtag_add_end_state(TAP_RTI);
+ arm_jtag_scann(ice_reg->jtag_info, 0x2);
+ arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr);
+
+ fields[0].device = ice_reg->jtag_info->chain_pos;
+ fields[0].num_bits = 32;
+ fields[0].out_value = malloc(4);
+ buf_set_u32(fields[0].out_value, 0, 32, value);
+ 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 = ice_reg->jtag_info->chain_pos;
+ fields[1].num_bits = 5;
+ fields[1].out_value = malloc(1);
+ buf_set_u32(fields[1].out_value, 0, 5, reg_addr);
+ 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 = ice_reg->jtag_info->chain_pos;
+ fields[2].num_bits = 1;
+ fields[2].out_value = malloc(1);
+ buf_set_u32(fields[2].out_value, 0, 1, 1);
+ 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);
+
+ free(fields[0].out_value);
+ free(fields[1].out_value);
+ free(fields[2].out_value);
+
+ return ERROR_OK;
+}
+
+int embeddedice_store_reg(reg_t *reg)
+{
+ return embeddedice_write_reg(reg, buf_get_u32(reg->value, 0, reg->size));
+}
+
diff --git a/src/target/embeddedice.h b/src/target/embeddedice.h
new file mode 100644
index 00000000..0062153f
--- /dev/null
+++ b/src/target/embeddedice.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef EMBEDDED_ICE_H
+#define EMBEDDED_ICE_H
+
+#include "target.h"
+#include "register.h"
+#include "arm_jtag.h"
+
+enum
+{
+ EICE_DBG_CTRL = 0,
+ EICE_DBG_STAT = 1,
+ EICE_COMMS_CTRL = 2,
+ EICE_COMMS_DATA = 3,
+ EICE_W0_ADDR_VALUE = 4,
+ EICE_W0_ADDR_MASK = 5,
+ EICE_W0_DATA_VALUE = 6,
+ EICE_W0_DATA_MASK = 7,
+ EICE_W0_CONTROL_VALUE = 8,
+ EICE_W0_CONTROL_MASK = 9,
+ EICE_W1_ADDR_VALUE = 10,
+ EICE_W1_ADDR_MASK = 11,
+ EICE_W1_DATA_VALUE = 12,
+ EICE_W1_DATA_MASK = 13,
+ EICE_W1_CONTROL_VALUE = 14,
+ EICE_W1_CONTROL_MASK = 15
+};
+
+enum
+{
+ EICE_DBG_CONTROL_INTDIS = 2,
+ EICE_DBG_CONTROL_DBGRQ = 1,
+ EICE_DBG_CONTROL_DBGACK = 0,
+};
+
+enum
+{
+ EICE_DBG_STATUS_ITBIT = 4,
+ EICE_DBG_STATUS_SYSCOMP = 3,
+ EICE_DBG_STATUS_IFEN = 2,
+ EICE_DBG_STATUS_DBGRQ = 1,
+ EICE_DBG_STATUS_DBGACK = 0
+};
+
+enum
+{
+ EICE_W_CTRL_ENABLE = 0x100,
+ EICE_W_CTRL_RANGE = 0x80,
+ EICE_W_CTRL_CHAIN = 0x40,
+ EICE_W_CTRL_EXTERN = 0x20,
+ EICE_W_CTRL_nTRANS = 0x10,
+ EICE_W_CTRL_nOPC = 0x8,
+ EICE_W_CTRL_MAS = 0x6,
+ EICE_W_CTRL_ITBIT = 0x2,
+ EICE_W_CTRL_nRW = 0x1
+};
+
+typedef struct embeddedice_reg_s
+{
+ int addr;
+ arm_jtag_t *jtag_info;
+} embeddedice_reg_t;
+
+extern reg_cache_t* embeddedice_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg);
+extern int embeddedice_read_reg(reg_t *reg);
+extern int embeddedice_write_reg(reg_t *reg, u32 value);
+extern int embeddedice_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask);
+extern int embeddedice_store_reg(reg_t *reg);
+extern int embeddedice_set_reg(reg_t *reg, u32 value);
+extern int embeddedice_set_reg_w_exec(reg_t *reg, u32 value);
+
+#endif /* EMBEDDED_ICE_H */
diff --git a/src/target/etm.c b/src/target/etm.c
new file mode 100644
index 00000000..a84e2d67
--- /dev/null
+++ b/src/target/etm.c
@@ -0,0 +1,409 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "config.h"
+
+#include "etm.h"
+
+#include "armv4_5.h"
+#include "arm7_9_common.h"
+
+#include "log.h"
+#include "arm_jtag.h"
+#include "types.h"
+#include "binarybuffer.h"
+#include "target.h"
+#include "register.h"
+#include "jtag.h"
+
+#include <stdlib.h>
+
+bitfield_desc_t etm_comms_ctrl_bitfield_desc[] =
+{
+ {"R", 1},
+ {"W", 1},
+ {"reserved", 26},
+ {"version", 4}
+};
+
+int etm_reg_arch_info[] =
+{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+};
+
+int etm_reg_arch_size_info[] =
+{
+ 32, 32, 17, 8, 3, 9, 32, 17,
+ 26, 16, 25, 8, 17, 32, 32, 17,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 16, 16, 16, 16, 18, 18, 18, 18,
+ 17, 17, 17, 17, 16, 16, 16, 16,
+ 17, 17, 17, 17, 17, 17, 2,
+ 17, 17, 17, 17, 32, 32, 32, 32
+};
+
+char* etm_reg_list[] =
+{
+ "ETM_CTRL",
+ "ETM_CONFIG",
+ "ETM_TRIG_EVENT",
+ "ETM_MMD_CTRL",
+ "ETM_STATUS",
+ "ETM_SYS_CONFIG",
+ "ETM_TRACE_RESOURCE_CTRL",
+ "ETM_TRACE_EN_CTRL2",
+ "ETM_TRACE_EN_EVENT",
+ "ETM_TRACE_EN_CTRL1",
+ "ETM_FIFOFULL_REGION",
+ "ETM_FIFOFULL_LEVEL",
+ "ETM_VIEWDATA_EVENT",
+ "ETM_VIEWDATA_CTRL1",
+ "ETM_VIEWDATA_CTRL2",
+ "ETM_VIEWDATA_CTRL3",
+ "ETM_ADDR_COMPARATOR_VALUE1",
+ "ETM_ADDR_COMPARATOR_VALUE2",
+ "ETM_ADDR_COMPARATOR_VALUE3",
+ "ETM_ADDR_COMPARATOR_VALUE4",
+ "ETM_ADDR_COMPARATOR_VALUE5",
+ "ETM_ADDR_COMPARATOR_VALUE6",
+ "ETM_ADDR_COMPARATOR_VALUE7",
+ "ETM_ADDR_COMPARATOR_VALUE8",
+ "ETM_ADDR_COMPARATOR_VALUE9",
+ "ETM_ADDR_COMPARATOR_VALUE10",
+ "ETM_ADDR_COMPARATOR_VALUE11",
+ "ETM_ADDR_COMPARATOR_VALUE12",
+ "ETM_ADDR_COMPARATOR_VALUE13",
+ "ETM_ADDR_COMPARATOR_VALUE14",
+ "ETM_ADDR_COMPARATOR_VALUE15",
+ "ETM_ADDR_COMPARATOR_VALUE16",
+ "ETM_ADDR_ACCESS_TYPE1",
+ "ETM_ADDR_ACCESS_TYPE2",
+ "ETM_ADDR_ACCESS_TYPE3",
+ "ETM_ADDR_ACCESS_TYPE4",
+ "ETM_ADDR_ACCESS_TYPE5",
+ "ETM_ADDR_ACCESS_TYPE6",
+ "ETM_ADDR_ACCESS_TYPE7",
+ "ETM_ADDR_ACCESS_TYPE8",
+ "ETM_ADDR_ACCESS_TYPE9",
+ "ETM_ADDR_ACCESS_TYPE10",
+ "ETM_ADDR_ACCESS_TYPE11",
+ "ETM_ADDR_ACCESS_TYPE12",
+ "ETM_ADDR_ACCESS_TYPE13",
+ "ETM_ADDR_ACCESS_TYPE14",
+ "ETM_ADDR_ACCESS_TYPE15",
+ "ETM_ADDR_ACCESS_TYPE16",
+ "ETM_DATA_COMPARATOR_VALUE1",
+ "ETM_DATA_COMPARATOR_VALUE2",
+ "ETM_DATA_COMPARATOR_VALUE3",
+ "ETM_DATA_COMPARATOR_VALUE4",
+ "ETM_DATA_COMPARATOR_VALUE5",
+ "ETM_DATA_COMPARATOR_VALUE6",
+ "ETM_DATA_COMPARATOR_VALUE7",
+ "ETM_DATA_COMPARATOR_VALUE8",
+ "ETM_DATA_COMPARATOR_VALUE9",
+ "ETM_DATA_COMPARATOR_VALUE10",
+ "ETM_DATA_COMPARATOR_VALUE11",
+ "ETM_DATA_COMPARATOR_VALUE12",
+ "ETM_DATA_COMPARATOR_VALUE13",
+ "ETM_DATA_COMPARATOR_VALUE14",
+ "ETM_DATA_COMPARATOR_VALUE15",
+ "ETM_DATA_COMPARATOR_VALUE16",
+ "ETM_DATA_COMPARATOR_MASK1",
+ "ETM_DATA_COMPARATOR_MASK2",
+ "ETM_DATA_COMPARATOR_MASK3",
+ "ETM_DATA_COMPARATOR_MASK4",
+ "ETM_DATA_COMPARATOR_MASK5",
+ "ETM_DATA_COMPARATOR_MASK6",
+ "ETM_DATA_COMPARATOR_MASK7",
+ "ETM_DATA_COMPARATOR_MASK8",
+ "ETM_DATA_COMPARATOR_MASK9",
+ "ETM_DATA_COMPARATOR_MASK10",
+ "ETM_DATA_COMPARATOR_MASK11",
+ "ETM_DATA_COMPARATOR_MASK12",
+ "ETM_DATA_COMPARATOR_MASK13",
+ "ETM_DATA_COMPARATOR_MASK14",
+ "ETM_DATA_COMPARATOR_MASK15",
+ "ETM_DATA_COMPARATOR_MASK16",
+ "ETM_COUNTER_INITAL_VALUE1",
+ "ETM_COUNTER_INITAL_VALUE2",
+ "ETM_COUNTER_INITAL_VALUE3",
+ "ETM_COUNTER_INITAL_VALUE4",
+ "ETM_COUNTER_ENABLE1",
+ "ETM_COUNTER_ENABLE2",
+ "ETM_COUNTER_ENABLE3",
+ "ETM_COUNTER_ENABLE4",
+ "ETM_COUNTER_RELOAD_VALUE1",
+ "ETM_COUNTER_RELOAD_VALUE2",
+ "ETM_COUNTER_RELOAD_VALUE3",
+ "ETM_COUNTER_RELOAD_VALUE4",
+ "ETM_COUNTER_VALUE1",
+ "ETM_COUNTER_VALUE2",
+ "ETM_COUNTER_VALUE3",
+ "ETM_COUNTER_VALUE4",
+ "ETM_SEQUENCER_CTRL1",
+ "ETM_SEQUENCER_CTRL2",
+ "ETM_SEQUENCER_CTRL3",
+ "ETM_SEQUENCER_CTRL4",
+ "ETM_SEQUENCER_CTRL5",
+ "ETM_SEQUENCER_CTRL6",
+ "ETM_SEQUENCER_STATE",
+ "ETM_EXTERNAL_OUTPUT1",
+ "ETM_EXTERNAL_OUTPUT2",
+ "ETM_EXTERNAL_OUTPUT3",
+ "ETM_EXTERNAL_OUTPUT4",
+ "ETM_CONTEXTID_COMPARATOR_VALUE1",
+ "ETM_CONTEXTID_COMPARATOR_VALUE2",
+ "ETM_CONTEXTID_COMPARATOR_VALUE3",
+ "ETM_CONTEXTID_COMPARATOR_MASK"
+};
+
+int etm_reg_arch_type = -1;
+
+int etm_get_reg(reg_t *reg);
+int etm_set_reg(reg_t *reg, u32 value);
+
+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)
+{
+ 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;
+
+ /* register a register arch-type for etm registers only once */
+ if (etm_reg_arch_type == -1)
+ etm_reg_arch_type = register_reg_arch_type(etm_get_reg, etm_set_reg_w_exec);
+
+ /* the actual registers are kept in two arrays */
+ reg_list = calloc(num_regs, sizeof(reg_t));
+ arch_info = calloc(num_regs, sizeof(etm_reg_t));
+
+ /* fill in values for the reg cache */
+ reg_cache->name = "etm registers";
+ reg_cache->next = NULL;
+ reg_cache->reg_list = reg_list;
+ reg_cache->num_regs = num_regs;
+
+ /* set up registers */
+ for (i = 0; i < num_regs; i++)
+ {
+ reg_list[i].name = etm_reg_list[i];
+ reg_list[i].size = 32;
+ reg_list[i].dirty = 0;
+ reg_list[i].valid = 0;
+ reg_list[i].bitfield_desc = NULL;
+ reg_list[i].num_bitfields = 0;
+ reg_list[i].value = calloc(1, 4);
+ reg_list[i].arch_info = &arch_info[i];
+ reg_list[i].arch_type = etm_reg_arch_type;
+ reg_list[i].size = etm_reg_arch_size_info[i];
+ arch_info[i].addr = etm_reg_arch_info[i];
+ arch_info[i].jtag_info = jtag_info;
+ }
+ return reg_cache;
+}
+
+int etm_get_reg(reg_t *reg)
+{
+ if (etm_read_reg(reg) != ERROR_OK)
+ {
+ ERROR("BUG: error scheduling etm register read");
+ exit(-1);
+ }
+
+ if (jtag_execute_queue() != ERROR_OK)
+ {
+ ERROR("register read failed");
+ }
+
+ return ERROR_OK;
+}
+
+int etm_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask)
+{
+ etm_reg_t *etm_reg = reg->arch_info;
+ u8 reg_addr = etm_reg->addr & 0x7f;
+ scan_field_t fields[3];
+
+ DEBUG("%i", etm_reg->addr);
+
+ jtag_add_end_state(TAP_RTI);
+ arm_jtag_scann(etm_reg->jtag_info, 0x6);
+ arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr);
+
+ fields[0].device = etm_reg->jtag_info->chain_pos;
+ fields[0].num_bits = 32;
+ fields[0].out_value = reg->value;
+ 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 = etm_reg->jtag_info->chain_pos;
+ fields[1].num_bits = 7;
+ fields[1].out_value = malloc(1);
+ buf_set_u32(fields[1].out_value, 0, 7, reg_addr);
+ 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 = etm_reg->jtag_info->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);
+
+ fields[0].in_value = reg->value;
+ fields[0].in_check_value = check_value;
+ fields[0].in_check_mask = check_mask;
+
+ jtag_add_dr_scan(3, fields, -1);
+
+ free(fields[1].out_value);
+ free(fields[2].out_value);
+
+ return ERROR_OK;
+}
+
+int etm_read_reg(reg_t *reg)
+{
+ return etm_read_reg_w_check(reg, NULL, NULL);
+}
+
+int etm_set_reg(reg_t *reg, u32 value)
+{
+ if (etm_write_reg(reg, value) != ERROR_OK)
+ {
+ ERROR("BUG: error scheduling etm register write");
+ exit(-1);
+ }
+
+ buf_set_u32(reg->value, 0, reg->size, value);
+ reg->valid = 1;
+ reg->dirty = 0;
+
+ return ERROR_OK;
+}
+
+int etm_set_reg_w_exec(reg_t *reg, u32 value)
+{
+ etm_set_reg(reg, value);
+
+ if (jtag_execute_queue() != ERROR_OK)
+ {
+ ERROR("register write failed");
+ exit(-1);
+ }
+ return ERROR_OK;
+}
+
+int etm_write_reg(reg_t *reg, u32 value)
+{
+ etm_reg_t *etm_reg = reg->arch_info;
+ u8 reg_addr = etm_reg->addr & 0x7f;
+ scan_field_t fields[3];
+
+ DEBUG("%i: 0x%8.8x", etm_reg->addr, value);
+
+ jtag_add_end_state(TAP_RTI);
+ arm_jtag_scann(etm_reg->jtag_info, 0x6);
+ arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr);
+
+ fields[0].device = etm_reg->jtag_info->chain_pos;
+ fields[0].num_bits = 32;
+ fields[0].out_value = malloc(4);
+ buf_set_u32(fields[0].out_value, 0, 32, value);
+ 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 = etm_reg->jtag_info->chain_pos;
+ fields[1].num_bits = 7;
+ fields[1].out_value = malloc(1);
+ buf_set_u32(fields[1].out_value, 0, 7, reg_addr);
+ 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 = etm_reg->jtag_info->chain_pos;
+ fields[2].num_bits = 1;
+ fields[2].out_value = malloc(1);
+ buf_set_u32(fields[2].out_value, 0, 1, 1);
+ 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);
+
+ free(fields[0].out_value);
+ free(fields[1].out_value);
+ free(fields[2].out_value);
+
+ return ERROR_OK;
+}
+
+int etm_store_reg(reg_t *reg)
+{
+ return etm_write_reg(reg, buf_get_u32(reg->value, 0, reg->size));
+}
+
diff --git a/src/target/etm.h b/src/target/etm.h
new file mode 100644
index 00000000..dbe78f35
--- /dev/null
+++ b/src/target/etm.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef ETM_H
+#define ETM_H
+
+#include "target.h"
+#include "register.h"
+#include "arm_jtag.h"
+
+// ETM registers (V1.2 protocol)
+enum
+{
+ ETM_CTRL = 0x00,
+ ETM_CONFIG = 0x01,
+ ETM_TRIG_EVENT = 0x02,
+ ETM_MMD_CTRL = 0x03,
+ ETM_STATUS = 0x04,
+ ETM_SYS_CONFIG = 0x05,
+ ETM_TRACE_RESOURCE_CTRL = 0x06,
+ ETM_TRACE_EN_CTRL2 = 0x07,
+ ETM_TRACE_EN_EVENT = 0x08,
+ ETM_TRACE_EN_CTRL1 = 0x09,
+ ETM_FIFOFULL_REGION = 0x0a,
+ ETM_FIFOFULL_LEVEL = 0x0b,
+ ETM_VIEWDATA_EVENT = 0x0c,
+ ETM_VIEWDATA_CTRL1 = 0x0d,
+ ETM_VIEWDATA_CTRL2 = 0x0e,
+ ETM_VIEWDATA_CTRL3 = 0x0f,
+ ETM_ADDR_COMPARATOR_VALUE = 0x10,
+ ETM_ADDR_ACCESS_TYPE = 0x20,
+ ETM_DATA_COMPARATOR_VALUE = 0x30,
+ ETM_DATA_COMPARATOR_MASK = 0x40,
+ ETM_COUNTER_INITAL_VALUE = 0x50,
+ ETM_COUNTER_ENABLE = 0x54,
+ ETM_COUNTER_RELOAD_VALUE = 0x58,
+ ETM_COUNTER_VALUE = 0x5c,
+ ETM_SEQUENCER_CTRL = 0x60,
+ ETM_SEQUENCER_STATE = 0x67,
+ ETM_EXTERNAL_OUTPUT = 0x68,
+ ETM_CONTEXTID_COMPARATOR_VALUE = 0x6c,
+ 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);
+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);
+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, u32 value);
+
+#endif /* ETM_H */
diff --git a/src/target/register.c b/src/target/register.c
new file mode 100644
index 00000000..7b98cfcf
--- /dev/null
+++ b/src/target/register.c
@@ -0,0 +1,100 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "register.h"
+
+#include "log.h"
+#include "command.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+reg_arch_type_t *reg_arch_types = NULL;
+
+reg_t* register_get_by_name(reg_cache_t *first, char *name, int search_all)
+{
+ int i;
+ reg_cache_t *cache = first;
+
+ while (cache)
+ {
+ for (i = 0; i < cache->num_regs; i++)
+ {
+ if (strcmp(cache->reg_list[i].name, name) == 0)
+ return &(cache->reg_list[i]);
+ }
+
+ if (search_all)
+ cache = cache->next;
+ else
+ break;
+ }
+
+ return NULL;
+}
+
+reg_cache_t** register_get_last_cache_p(reg_cache_t **first)
+{
+ reg_cache_t **cache_p = first;
+
+ if (*cache_p)
+ while (*cache_p)
+ cache_p = &((*cache_p)->next);
+ else
+ return first;
+
+ return cache_p;
+}
+
+int register_reg_arch_type(int (*get)(reg_t *reg), int (*set)(reg_t *reg, u32 value))
+{
+ reg_arch_type_t** arch_type_p = &reg_arch_types;
+ int id = 0;
+
+ if (*arch_type_p)
+ {
+ while (*arch_type_p)
+ {
+ id = (*arch_type_p)->id;
+ arch_type_p = &((*arch_type_p)->next);
+ }
+ }
+
+ (*arch_type_p) = malloc(sizeof(reg_arch_type_t));
+ (*arch_type_p)->id = id + 1;
+ (*arch_type_p)->set = set;
+ (*arch_type_p)->get = get;
+ (*arch_type_p)->next = NULL;
+
+ return id + 1;
+}
+
+reg_arch_type_t* register_get_arch_type(int id)
+{
+ reg_arch_type_t *arch_type = reg_arch_types;
+
+ while (arch_type)
+ {
+ if (arch_type->id == id)
+ return arch_type;
+ arch_type = arch_type->next;
+ }
+
+ return NULL;
+}
diff --git a/src/target/register.h b/src/target/register.h
new file mode 100644
index 00000000..8a903edd
--- /dev/null
+++ b/src/target/register.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef REGISTER_H
+#define REGISTER_H
+
+#include "types.h"
+#include "target.h"
+
+struct target_s;
+
+typedef struct bitfield_desc_s
+{
+ char *name;
+ int num_bits;
+} bitfield_desc_t;
+
+typedef struct reg_s
+{
+ char *name;
+ u8 *value;
+ int dirty;
+ int valid;
+ int size;
+ bitfield_desc_t *bitfield_desc;
+ int num_bitfields;
+ void *arch_info;
+ int arch_type;
+} reg_t;
+
+typedef struct reg_cache_s
+{
+ char *name;
+ struct reg_cache_s *next;
+ reg_t *reg_list;
+ int num_regs;
+} reg_cache_t;
+
+typedef struct reg_arch_type_s
+{
+ int id;
+ int (*get)(reg_t *reg);
+ int (*set)(reg_t *reg, u32 value);
+ struct reg_arch_type_s *next;
+} reg_arch_type_t;
+
+extern reg_t* register_get_by_name(reg_cache_t *first, char *name, int search_all);
+extern reg_cache_t** register_get_last_cache_p(reg_cache_t **first);
+extern int register_reg_arch_type(int (*get)(reg_t *reg), int (*set)(reg_t *reg, u32 value));
+extern reg_arch_type_t* register_get_arch_type(int id);
+
+#endif /* REGISTER_H */
+
diff --git a/src/target/target.c b/src/target/target.c
new file mode 100644
index 00000000..98407afb
--- /dev/null
+++ b/src/target/target.c
@@ -0,0 +1,1701 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "config.h"
+#include "target.h"
+
+#include "log.h"
+#include "configuration.h"
+#include "binarybuffer.h"
+#include "jtag.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/time.h>
+#include <time.h>
+
+#include <time_support.h>
+
+int cli_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv);
+
+int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+int handle_target_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_run_and_halt_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_load_binary_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_dump_binary_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+/* targets
+ */
+extern target_type_t arm7tdmi_target;
+extern target_type_t arm720t_target;
+extern target_type_t arm9tdmi_target;
+extern target_type_t arm920t_target;
+
+target_type_t *target_types[] =
+{
+ &arm7tdmi_target,
+ &arm9tdmi_target,
+ &arm920t_target,
+ &arm720t_target,
+ NULL,
+};
+
+target_t *targets = NULL;
+target_event_callback_t *target_event_callbacks = NULL;
+target_timer_callback_t *target_timer_callbacks = NULL;
+
+char *target_state_strings[] =
+{
+ "unknown",
+ "running",
+ "halted",
+ "reset",
+ "debug_running",
+};
+
+char *target_debug_reason_strings[] =
+{
+ "debug request", "breakpoint", "watchpoint",
+ "watchpoint and breakpoint", "single step",
+ "target not halted"
+};
+
+char *target_endianess_strings[] =
+{
+ "big endian",
+ "little endian",
+};
+
+enum daemon_startup_mode startup_mode = DAEMON_ATTACH;
+
+static int target_continous_poll = 1;
+
+/* returns a pointer to the n-th configured target */
+target_t* get_target_by_num(int num)
+{
+ target_t *target = targets;
+ int i = 0;
+
+ while (target)
+ {
+ if (num == i)
+ return target;
+ target = target->next;
+ i++;
+ }
+
+ return NULL;
+}
+
+int get_num_by_target(target_t *query_target)
+{
+ target_t *target = targets;
+ int i = 0;
+
+ while (target)
+ {
+ if (target == query_target)
+ return i;
+ target = target->next;
+ i++;
+ }
+
+ return -1;
+}
+
+target_t* get_current_target(command_context_t *cmd_ctx)
+{
+ target_t *target = get_target_by_num(cmd_ctx->current_target);
+
+ if (target == NULL)
+ {
+ ERROR("BUG: current_target out of bounds");
+ exit(-1);
+ }
+
+ return target;
+}
+
+/* Process target initialization, when target entered debug out of reset
+ * the handler is unregistered at the end of this function, so it's only called once
+ */
+int target_init_handler(struct target_s *target, enum target_event event, void *priv)
+{
+ FILE *script;
+ struct command_context_s *cmd_ctx = priv;
+
+ if ((event == TARGET_EVENT_HALTED) && (target->reset_script))
+ {
+ script = fopen(target->reset_script, "r");
+ if (!script)
+ {
+ ERROR("couldn't open script file %s", target->reset_script);
+ return ERROR_OK;
+ }
+
+ INFO("executing reset script '%s'", target->reset_script);
+ command_run_file(cmd_ctx, script, COMMAND_EXEC);
+ fclose(script);
+
+ jtag_execute_queue();
+
+ target_unregister_event_callback(target_init_handler, priv);
+ }
+
+ return ERROR_OK;
+}
+
+int target_run_and_halt_handler(void *priv)
+{
+ target_t *target = priv;
+
+ target->type->halt(target);
+
+ return ERROR_OK;
+}
+
+int target_process_reset(struct command_context_s *cmd_ctx)
+{
+ int retval = ERROR_OK;
+ target_t *target;
+
+ target = targets;
+ while (target)
+ {
+ target->type->assert_reset(target);
+ target = target->next;
+ }
+ jtag_execute_queue();
+
+ /* request target halt if necessary, and schedule further action */
+ target = targets;
+ while (target)
+ {
+ switch (target->reset_mode)
+ {
+ case RESET_RUN:
+ /* nothing to do if target just wants to be run */
+ break;
+ case RESET_RUN_AND_HALT:
+ /* schedule halt */
+ target_register_timer_callback(target_run_and_halt_handler, target->run_and_halt_time, 0, target);
+ break;
+ case RESET_RUN_AND_INIT:
+ /* schedule halt */
+ target_register_timer_callback(target_run_and_halt_handler, target->run_and_halt_time, 0, target);
+ target_register_event_callback(target_init_handler, cmd_ctx);
+ break;
+ case RESET_HALT:
+ target->type->halt(target);
+ break;
+ case RESET_INIT:
+ target->type->halt(target);
+ target_register_event_callback(target_init_handler, cmd_ctx);
+ break;
+ default:
+ ERROR("BUG: unknown target->reset_mode");
+ }
+ target = target->next;
+ }
+
+ target = targets;
+ while (target)
+ {
+ target->type->deassert_reset(target);
+ target = target->next;
+ }
+ jtag_execute_queue();
+
+ return retval;
+}
+
+int target_init(struct command_context_s *cmd_ctx)
+{
+ target_t *target = targets;
+
+ while (target)
+ {
+ if (target->type->init_target(cmd_ctx, target) != ERROR_OK)
+ {
+ ERROR("target '%s' init failed", target->type->name);
+ exit(-1);
+ }
+ target = target->next;
+ }
+
+ if (targets)
+ {
+ target_register_user_commands(cmd_ctx);
+ target_register_timer_callback(handle_target, 100, 1, NULL);
+ }
+
+ if (startup_mode == DAEMON_RESET)
+ target_process_reset(cmd_ctx);
+
+ return ERROR_OK;
+}
+
+int target_register_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv)
+{
+ target_event_callback_t **callbacks_p = &target_event_callbacks;
+
+ if (callback == NULL)
+ {
+ return ERROR_INVALID_ARGUMENTS;
+ }
+
+ if (*callbacks_p)
+ {
+ while ((*callbacks_p)->next)
+ callbacks_p = &((*callbacks_p)->next);
+ callbacks_p = &((*callbacks_p)->next);
+ }
+
+ (*callbacks_p) = malloc(sizeof(target_event_callback_t));
+ (*callbacks_p)->callback = callback;
+ (*callbacks_p)->priv = priv;
+ (*callbacks_p)->next = NULL;
+
+ return ERROR_OK;
+}
+
+int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv)
+{
+ target_timer_callback_t **callbacks_p = &target_timer_callbacks;
+ struct timeval now;
+
+ if (callback == NULL)
+ {
+ return ERROR_INVALID_ARGUMENTS;
+ }
+
+ if (*callbacks_p)
+ {
+ while ((*callbacks_p)->next)
+ callbacks_p = &((*callbacks_p)->next);
+ callbacks_p = &((*callbacks_p)->next);
+ }
+
+ (*callbacks_p) = malloc(sizeof(target_timer_callback_t));
+ (*callbacks_p)->callback = callback;
+ (*callbacks_p)->periodic = periodic;
+ (*callbacks_p)->time_ms = time_ms;
+
+ gettimeofday(&now, NULL);
+ (*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000;
+ time_ms -= (time_ms % 1000);
+ (*callbacks_p)->when.tv_sec = now.tv_sec + (time_ms / 1000);
+ if ((*callbacks_p)->when.tv_usec > 1000000)
+ {
+ (*callbacks_p)->when.tv_usec = (*callbacks_p)->when.tv_usec - 1000000;
+ (*callbacks_p)->when.tv_sec += 1;
+ }
+
+ (*callbacks_p)->priv = priv;
+ (*callbacks_p)->next = NULL;
+
+ return ERROR_OK;
+}
+
+int target_unregister_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv)
+{
+ target_event_callback_t **p = &target_event_callbacks;
+ target_event_callback_t *c = target_event_callbacks;
+
+ if (callback == NULL)
+ {
+ return ERROR_INVALID_ARGUMENTS;
+ }
+
+ while (c)
+ {
+ target_event_callback_t *next = c->next;
+ if ((c->callback == callback) && (c->priv == priv))
+ {
+ *p = next;
+ free(c);
+ return ERROR_OK;
+ }
+ else
+ p = &(c->next);
+ c = next;
+ }
+
+ return ERROR_OK;
+}
+
+int target_unregister_timer_callback(int (*callback)(void *priv), void *priv)
+{
+ target_timer_callback_t **p = &target_timer_callbacks;
+ target_timer_callback_t *c = target_timer_callbacks;
+
+ if (callback == NULL)
+ {
+ return ERROR_INVALID_ARGUMENTS;
+ }
+
+ while (c)
+ {
+ target_timer_callback_t *next = c->next;
+ if ((c->callback == callback) && (c->priv == priv))
+ {
+ *p = next;
+ free(c);
+ return ERROR_OK;
+ }
+ else
+ p = &(c->next);
+ c = next;
+ }
+
+ return ERROR_OK;
+}
+
+int target_call_event_callbacks(target_t *target, enum target_event event)
+{
+ target_event_callback_t *callback = target_event_callbacks;
+ target_event_callback_t *next_callback;
+
+ DEBUG("target event %i", event);
+
+ while (callback)
+ {
+ next_callback = callback->next;
+ callback->callback(target, event, callback->priv);
+ callback = next_callback;
+ }
+
+ return ERROR_OK;
+}
+
+int target_call_timer_callbacks()
+{
+ target_timer_callback_t *callback = target_timer_callbacks;
+ target_timer_callback_t *next_callback;
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+
+ while (callback)
+ {
+ next_callback = callback->next;
+
+ if (((now.tv_sec >= callback->when.tv_sec) && (now.tv_usec >= callback->when.tv_usec))
+ || (now.tv_sec > callback->when.tv_sec))
+ {
+ callback->callback(callback->priv);
+ if (callback->periodic)
+ {
+ int time_ms = callback->time_ms;
+ callback->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000;
+ time_ms -= (time_ms % 1000);
+ callback->when.tv_sec = now.tv_sec + time_ms / 1000;
+ if (callback->when.tv_usec > 1000000)
+ {
+ callback->when.tv_usec = callback->when.tv_usec - 1000000;
+ callback->when.tv_sec += 1;
+ }
+ }
+ else
+ target_unregister_timer_callback(callback->callback, callback->priv);
+ }
+
+ callback = next_callback;
+ }
+
+ return ERROR_OK;
+}
+
+int target_alloc_working_area(struct target_s *target, u32 size, working_area_t **area)
+{
+ working_area_t *c = target->working_areas;
+ working_area_t *new_wa = NULL;
+
+ /* only allocate multiples of 4 byte */
+ if (size % 4)
+ {
+ ERROR("BUG: code tried to allocate unaligned number of bytes, padding");
+ size = CEIL(size, 4);
+ }
+
+ /* see if there's already a matching working area */
+ while (c)
+ {
+ if ((c->free) && (c->size == size))
+ {
+ new_wa = c;
+ break;
+ }
+ c = c->next;
+ }
+
+ /* if not, allocate a new one */
+ if (!new_wa)
+ {
+ working_area_t **p = &target->working_areas;
+ u32 first_free = target->working_area;
+ u32 free_size = target->working_area_size;
+
+ DEBUG("allocating new working area");
+
+ c = target->working_areas;
+ while (c)
+ {
+ first_free += c->size;
+ free_size -= c->size;
+ p = &c->next;
+ c = c->next;
+ }
+
+ if (free_size < size)
+ {
+ WARNING("not enough working area available");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ new_wa = malloc(sizeof(working_area_t));
+ new_wa->next = NULL;
+ new_wa->size = size;
+ new_wa->address = first_free;
+
+ if (target->backup_working_area)
+ {
+ new_wa->backup = malloc(new_wa->size);
+ target->type->read_memory(target, new_wa->address, 4, new_wa->size / 4, new_wa->backup);
+ }
+ else
+ {
+ new_wa->backup = NULL;
+ }
+
+ /* put new entry in list */
+ *p = new_wa;
+ }
+
+ /* mark as used, and return the new (reused) area */
+ new_wa->free = 0;
+ *area = new_wa;
+
+ /* user pointer */
+ new_wa->user = area;
+
+ return ERROR_OK;
+}
+
+int target_free_working_area(struct target_s *target, working_area_t *area)
+{
+ if (area->free)
+ return ERROR_OK;
+
+ if (target->backup_working_area)
+ target->type->write_memory(target, area->address, 4, area->size / 4, area->backup);
+
+ area->free = 1;
+
+ /* mark user pointer invalid */
+ *area->user = NULL;
+ area->user = NULL;
+
+ return ERROR_OK;
+}
+
+int target_free_all_working_areas(struct target_s *target)
+{
+ working_area_t *c = target->working_areas;
+
+ while (c)
+ {
+ working_area_t *next = c->next;
+ target_free_working_area(target, c);
+
+ if (c->backup)
+ free(c->backup);
+
+ free(c);
+
+ c = next;
+ }
+
+ target->working_areas = NULL;
+
+ return ERROR_OK;
+}
+
+int target_register_commands(struct command_context_s *cmd_ctx)
+{
+ register_command(cmd_ctx, NULL, "target", handle_target_command, COMMAND_CONFIG, NULL);
+ register_command(cmd_ctx, NULL, "targets", handle_targets_command, COMMAND_EXEC, NULL);
+ register_command(cmd_ctx, NULL, "daemon_startup", handle_daemon_startup_command, COMMAND_CONFIG, NULL);
+ register_command(cmd_ctx, NULL, "target_script", handle_target_script_command, COMMAND_CONFIG, NULL);
+ register_command(cmd_ctx, NULL, "run_and_halt_time", handle_run_and_halt_time_command, COMMAND_CONFIG, NULL);
+ register_command(cmd_ctx, NULL, "working_area", handle_working_area_command, COMMAND_CONFIG, NULL);
+
+ return ERROR_OK;
+}
+
+int target_write_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer)
+{
+ int retval;
+
+ DEBUG("writing buffer of %i byte at 0x%8.8x", size, address);
+
+ /* handle writes of less than 4 byte */
+ if (size < 4)
+ {
+ if ((retval = target->type->write_memory(target, address, 1, size, buffer)) != ERROR_OK)
+ return retval;
+ }
+
+ /* handle unaligned head bytes */
+ if (address % 4)
+ {
+ int unaligned = 4 - (address % 4);
+
+ if ((retval = target->type->write_memory(target, address, 1, unaligned, buffer)) != ERROR_OK)
+ return retval;
+
+ buffer += unaligned;
+ address += unaligned;
+ size -= unaligned;
+ }
+
+ /* handle aligned words */
+ if (size >= 4)
+ {
+ int aligned = size - (size % 4);
+
+ /* use bulk writes above a certain limit. This may have to be changed */
+ if (aligned > 128)
+ {
+ if ((retval = target->type->bulk_write_memory(target, address, aligned / 4, buffer)) != ERROR_OK)
+ return retval;
+ }
+ else
+ {
+ if ((retval = target->type->write_memory(target, address, 4, aligned / 4, buffer)) != ERROR_OK)
+ return retval;
+ }
+
+ buffer += aligned;
+ address += aligned;
+ size -= aligned;
+ }
+
+ /* handle tail writes of less than 4 bytes */
+ if (size > 0)
+ {
+ if ((retval = target->type->write_memory(target, address, 1, size, buffer)) != ERROR_OK)
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+int target_read_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer)
+{
+ int retval;
+
+ DEBUG("reading buffer of %i byte at 0x%8.8x", size, address);
+
+ /* handle reads of less than 4 byte */
+ if (size < 4)
+ {
+ if ((retval = target->type->read_memory(target, address, 1, size, buffer)) != ERROR_OK)
+ return retval;
+ }
+
+ /* handle unaligned head bytes */
+ if (address % 4)
+ {
+ int unaligned = 4 - (address % 4);
+
+ if ((retval = target->type->read_memory(target, address, 1, unaligned, buffer)) != ERROR_OK)
+ return retval;
+
+ address += unaligned;
+ size -= unaligned;
+ }
+
+ /* handle aligned words */
+ if (size >= 4)
+ {
+ int aligned = size - (size % 4);
+
+ if ((retval = target->type->read_memory(target, address, 4, aligned / 4, buffer)) != ERROR_OK)
+ return retval;
+
+ address += aligned;
+ size -= aligned;
+ }
+
+ /* handle tail writes of less than 4 bytes */
+ if (size > 0)
+ {
+ if ((retval = target->type->read_memory(target, address, 1, size, buffer)) != ERROR_OK)
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+int target_register_user_commands(struct command_context_s *cmd_ctx)
+{
+ register_command(cmd_ctx, NULL, "reg", handle_reg_command, COMMAND_EXEC, NULL);
+ register_command(cmd_ctx, NULL, "poll", handle_poll_command, COMMAND_EXEC, "poll target state");
+ register_command(cmd_ctx, NULL, "wait_halt", handle_wait_halt_command, COMMAND_EXEC, "wait for target halt");
+ register_command(cmd_ctx, NULL, "halt", handle_halt_command, COMMAND_EXEC, "halt target");
+ register_command(cmd_ctx, NULL, "resume", handle_resume_command, COMMAND_EXEC, "resume target [addr]");
+ register_command(cmd_ctx, NULL, "step", handle_step_command, COMMAND_EXEC, "step one instruction");
+ register_command(cmd_ctx, NULL, "reset", handle_reset_command, COMMAND_EXEC, "reset target [run|halt|init|run_and_halt|run_and_init]");
+ register_command(cmd_ctx, NULL, "soft_reset_halt", handle_soft_reset_halt_command, COMMAND_EXEC, "halt the target and do a soft reset");
+
+ register_command(cmd_ctx, NULL, "mdw", handle_md_command, COMMAND_EXEC, "display memory words <addr> [count]");
+ register_command(cmd_ctx, NULL, "mdh", handle_md_command, COMMAND_EXEC, "display memory half-words <addr> [count]");
+ register_command(cmd_ctx, NULL, "mdb", handle_md_command, COMMAND_EXEC, "display memory bytes <addr> [count]");
+
+ register_command(cmd_ctx, NULL, "mww", handle_mw_command, COMMAND_EXEC, "write memory word <addr> <value>");
+ register_command(cmd_ctx, NULL, "mwh", handle_mw_command, COMMAND_EXEC, "write memory half-word <addr> <value>");
+ register_command(cmd_ctx, NULL, "mwb", handle_mw_command, COMMAND_EXEC, "write memory byte <addr> <value>");
+
+ register_command(cmd_ctx, NULL, "bp", handle_bp_command, COMMAND_EXEC, "set breakpoint <address> <length> [hw]");
+ register_command(cmd_ctx, NULL, "rbp", handle_rbp_command, COMMAND_EXEC, "remove breakpoint <adress>");
+ register_command(cmd_ctx, NULL, "wp", handle_wp_command, COMMAND_EXEC, "set watchpoint <address> <length> <r/w/a> [value] [mask]");
+ register_command(cmd_ctx, NULL, "rwp", handle_rwp_command, COMMAND_EXEC, "remove watchpoint <adress>");
+
+ register_command(cmd_ctx, NULL, "load_binary", handle_load_binary_command, COMMAND_EXEC, "load binary <file> <address>");
+ register_command(cmd_ctx, NULL, "dump_binary", handle_dump_binary_command, COMMAND_EXEC, "dump binary <file> <address> <size>");
+
+ return ERROR_OK;
+}
+
+int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = targets;
+ int count = 0;
+
+ if (argc == 1)
+ {
+ int num = strtoul(args[0], NULL, 0);
+
+ while (target)
+ {
+ count++;
+ target = target->next;
+ }
+
+ if (num < count)
+ cmd_ctx->current_target = num;
+ else
+ command_print(cmd_ctx, "%i is out of bounds, only %i targets are configured", num, count);
+
+ return ERROR_OK;
+ }
+
+ while (target)
+ {
+ command_print(cmd_ctx, "%i: %s (%s), state: %s", count++, target->type->name, target_endianess_strings[target->endianness], target_state_strings[target->state]);
+ target = target->next;
+ }
+
+ return ERROR_OK;
+}
+
+int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ int i;
+ int found = 0;
+
+ if (argc < 3)
+ {
+ ERROR("target command requires at least three arguments: <type> <endianess> <reset_mode>");
+ exit(-1);
+ }
+
+ /* search for the specified target */
+ if (args[0] && (args[0][0] != 0))
+ {
+ for (i = 0; target_types[i]; i++)
+ {
+ if (strcmp(args[0], target_types[i]->name) == 0)
+ {
+ target_t **last_target_p = &targets;
+
+ /* register target specific commands */
+ if (target_types[i]->register_commands(cmd_ctx) != ERROR_OK)
+ {
+ ERROR("couldn't register '%s' commands", args[0]);
+ exit(-1);
+ }
+
+ if (*last_target_p)
+ {
+ while ((*last_target_p)->next)
+ last_target_p = &((*last_target_p)->next);
+ last_target_p = &((*last_target_p)->next);
+ }
+
+ *last_target_p = malloc(sizeof(target_t));
+
+ (*last_target_p)->type = target_types[i];
+
+ if (strcmp(args[1], "big") == 0)
+ (*last_target_p)->endianness = TARGET_BIG_ENDIAN;
+ else if (strcmp(args[1], "little") == 0)
+ (*last_target_p)->endianness = TARGET_LITTLE_ENDIAN;
+ else
+ {
+ ERROR("endianness must be either 'little' or 'big', not '%s'", args[1]);
+ exit(-1);
+ }
+
+ /* what to do on a target reset */
+ if (strcmp(args[2], "reset_halt") == 0)
+ (*last_target_p)->reset_mode = RESET_HALT;
+ else if (strcmp(args[2], "reset_run") == 0)
+ (*last_target_p)->reset_mode = RESET_RUN;
+ else if (strcmp(args[2], "reset_init") == 0)
+ (*last_target_p)->reset_mode = RESET_INIT;
+ else if (strcmp(args[2], "run_and_halt") == 0)
+ (*last_target_p)->reset_mode = RESET_RUN_AND_HALT;
+ else if (strcmp(args[2], "run_and_init") == 0)
+ (*last_target_p)->reset_mode = RESET_RUN_AND_INIT;
+ else
+ {
+ ERROR("unknown target startup mode %s", args[2]);
+ exit(-1);
+ }
+ (*last_target_p)->run_and_halt_time = 1000; /* default 1s */
+
+ (*last_target_p)->reset_script = NULL;
+ (*last_target_p)->post_halt_script = NULL;
+ (*last_target_p)->pre_resume_script = NULL;
+
+ (*last_target_p)->working_area = 0x0;
+ (*last_target_p)->working_area_size = 0x0;
+ (*last_target_p)->working_areas = NULL;
+ (*last_target_p)->backup_working_area = 0;
+
+ (*last_target_p)->endianness = TARGET_LITTLE_ENDIAN;
+ (*last_target_p)->state = TARGET_UNKNOWN;
+ (*last_target_p)->reg_cache = NULL;
+ (*last_target_p)->breakpoints = NULL;
+ (*last_target_p)->watchpoints = NULL;
+ (*last_target_p)->next = NULL;
+ (*last_target_p)->arch_info = NULL;
+
+ (*last_target_p)->type->target_command(cmd_ctx, cmd, args, argc, *last_target_p);
+
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ /* no matching target found */
+ if (!found)
+ {
+ ERROR("target '%s' not found", args[0]);
+ exit(-1);
+ }
+
+ return ERROR_OK;
+}
+
+/* usage: target_script <target#> <event> <script_file> */
+int handle_target_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = NULL;
+
+ if (argc < 3)
+ {
+ ERROR("incomplete target_script 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 (strcmp(args[1], "reset") == 0)
+ {
+ if (target->reset_script)
+ free(target->reset_script);
+ target->reset_script = strdup(args[2]);
+ }
+ else if (strcmp(args[1], "post_halt") == 0)
+ {
+ if (target->post_halt_script)
+ free(target->post_halt_script);
+ target->post_halt_script = strdup(args[2]);
+ }
+ else if (strcmp(args[1], "pre_resume") == 0)
+ {
+ if (target->pre_resume_script)
+ free(target->pre_resume_script);
+ target->pre_resume_script = strdup(args[2]);
+ }
+ else
+ {
+ ERROR("unknown event type: '%s", args[1]);
+ exit(-1);
+ }
+
+ return ERROR_OK;
+}
+
+int handle_run_and_halt_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = NULL;
+
+ if (argc < 2)
+ {
+ ERROR("incomplete run_and_halt_time 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);
+ }
+
+ target->run_and_halt_time = strtoul(args[1], NULL, 0);
+
+ return ERROR_OK;
+}
+
+int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = NULL;
+
+ if (argc < 4)
+ {
+ ERROR("incomplete working_area command. usage: working_area <target#> <address> <size> <'backup'|'nobackup'>");
+ exit(-1);
+ }
+
+ target = get_target_by_num(strtoul(args[0], NULL, 0));
+
+ if (!target)
+ {
+ ERROR("target number '%s' not defined", args[0]);
+ exit(-1);
+ }
+
+ target->working_area = strtoul(args[1], NULL, 0);
+ target->working_area_size = strtoul(args[2], NULL, 0);
+
+ if (strcmp(args[3], "backup") == 0)
+ {
+ target->backup_working_area = 1;
+ }
+ else if (strcmp(args[3], "nobackup") == 0)
+ {
+ target->backup_working_area = 0;
+ }
+ else
+ {
+ ERROR("unrecognized <backup|nobackup> argument (%s)", args[3]);
+ exit(-1);
+ }
+
+ return ERROR_OK;
+}
+
+
+/* process target state changes */
+int handle_target(void *priv)
+{
+ int retval;
+ target_t *target = targets;
+
+ while (target)
+ {
+ /* only poll if target isn't already halted */
+ if (target->state != TARGET_HALTED)
+ {
+ if (target_continous_poll)
+ if ((retval = target->type->poll(target)) < 0)
+ {
+ ERROR("couldn't poll target, exiting");
+ exit(-1);
+ }
+ }
+
+ target = target->next;
+ }
+
+ return ERROR_OK;
+}
+
+int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target;
+ reg_t *reg = NULL;
+ int count = 0;
+ char *value;
+
+ DEBUG("");
+
+ target = get_current_target(cmd_ctx);
+
+ /* list all available registers for the current target */
+ if (argc == 0)
+ {
+ reg_cache_t *cache = target->reg_cache;
+
+ count = 0;
+ while(cache)
+ {
+ int i;
+ for (i = 0; i < cache->num_regs; i++)
+ {
+ value = buf_to_char(cache->reg_list[i].value, cache->reg_list[i].size);
+ command_print(cmd_ctx, "(%i) %s (/%i): 0x%s (dirty: %i, valid: %i)", count++, cache->reg_list[i].name, cache->reg_list[i].size, value, cache->reg_list[i].dirty, cache->reg_list[i].valid);
+ free(value);
+ }
+ cache = cache->next;
+ }
+
+ return ERROR_OK;
+ }
+
+ /* access a single register by its ordinal number */
+ if ((args[0][0] >= '0') && (args[0][0] <= '9'))
+ {
+ int num = strtoul(args[0], NULL, 0);
+ reg_cache_t *cache = target->reg_cache;
+
+ count = 0;
+ while(cache)
+ {
+ int i;
+ for (i = 0; i < cache->num_regs; i++)
+ {
+ if (count++ == num)
+ {
+ reg = &cache->reg_list[i];
+ break;
+ }
+ }
+ if (reg)
+ break;
+ cache = cache->next;
+ }
+
+ if (!reg)
+ {
+ command_print(cmd_ctx, "%i is out of bounds, the current target has only %i registers (0 - %i)", num, count, count - 1);
+ return ERROR_OK;
+ }
+ } else /* access a single register by its name */
+ {
+ reg = register_get_by_name(target->reg_cache, args[0], 1);
+
+ if (!reg)
+ {
+ command_print(cmd_ctx, "register %s not found in current target", args[0]);
+ return ERROR_OK;
+ }
+ }
+
+ /* display a register */
+ if ((argc == 1) || ((argc == 2) && !((args[1][0] >= '0') && (args[1][0] <= '9'))))
+ {
+ if ((argc == 2) && (strcmp(args[1], "force") == 0))
+ reg->valid = 0;
+
+ if (reg->valid == 0)
+ {
+ reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type);
+ if (arch_type == NULL)
+ {
+ ERROR("BUG: encountered unregistered arch type");
+ return ERROR_OK;
+ }
+ arch_type->get(reg);
+ }
+ value = buf_to_char(reg->value, reg->size);
+ command_print(cmd_ctx, "%s (/%i): 0x%s", reg->name, reg->size, value);
+ free(value);
+ return ERROR_OK;
+ }
+
+ /* set register value */
+ if (argc == 2)
+ {
+ u32 new_value = strtoul(args[1], NULL, 0);
+ reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type);
+ if (arch_type == NULL)
+ {
+ ERROR("BUG: encountered unregistered arch type");
+ return ERROR_OK;
+ }
+
+ arch_type->set(reg, new_value);
+ value = buf_to_char(reg->value, reg->size);
+ command_print(cmd_ctx, "%s (/%i): 0x%s", reg->name, reg->size, value);
+ free(value);
+
+ return ERROR_OK;
+ }
+
+ command_print(cmd_ctx, "usage: reg <#|name> [value]");
+
+ return ERROR_OK;
+}
+
+int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = get_current_target(cmd_ctx);
+ char buffer[512];
+
+ if (argc == 0)
+ {
+ command_print(cmd_ctx, "target state: %s", target_state_strings[target->type->poll(target)]);
+ if (target->state == TARGET_HALTED)
+ {
+ target->type->arch_state(target, buffer, 512);
+ buffer[511] = 0;
+ command_print(cmd_ctx, "%s", buffer);
+ }
+ }
+ else
+ {
+ if (strcmp(args[0], "on") == 0)
+ {
+ target_continous_poll = 1;
+ }
+ else if (strcmp(args[0], "off") == 0)
+ {
+ target_continous_poll = 0;
+ }
+ }
+
+
+ return ERROR_OK;
+}
+
+int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = get_current_target(cmd_ctx);
+ struct timeval timeout, now;
+
+ gettimeofday(&timeout, NULL);
+ timeval_add_time(&timeout, 5, 0);
+
+ command_print(cmd_ctx, "waiting for target halted...");
+
+ while(target->type->poll(target))
+ {
+ if (target->state == TARGET_HALTED)
+ {
+ command_print(cmd_ctx, "target halted");
+ break;
+ }
+ target_call_timer_callbacks();
+
+ gettimeofday(&now, NULL);
+ if ((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))
+ {
+ command_print(cmd_ctx, "timed out while waiting for target halt");
+ ERROR("timed out while waiting for target halt");
+ break;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int handle_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ int retval;
+ target_t *target = get_current_target(cmd_ctx);
+
+ DEBUG("");
+
+ command_print(cmd_ctx, "requesting target halt...");
+
+ if ((retval = target->type->halt(target)) != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_TARGET_ALREADY_HALTED:
+ command_print(cmd_ctx, "target already halted");
+ break;
+ case ERROR_TARGET_TIMEOUT:
+ command_print(cmd_ctx, "target timed out... shutting down");
+ exit(-1);
+ default:
+ command_print(cmd_ctx, "unknown error... shutting down");
+ exit(-1);
+ }
+ }
+
+ return ERROR_OK;
+
+}
+
+/* what to do on daemon startup */
+int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc == 1)
+ {
+ if (strcmp(args[0], "attach") == 0)
+ {
+ startup_mode = DAEMON_ATTACH;
+ return ERROR_OK;
+ }
+ else if (strcmp(args[0], "reset") == 0)
+ {
+ startup_mode = DAEMON_RESET;
+ return ERROR_OK;
+ }
+ }
+
+ WARNING("invalid daemon_startup configuration directive: %s", args[0]);
+ return ERROR_OK;
+
+}
+
+int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = get_current_target(cmd_ctx);
+ int retval;
+
+ command_print(cmd_ctx, "requesting target halt and executing a soft reset");
+
+ if ((retval = target->type->soft_reset_halt(target)) != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_TARGET_TIMEOUT:
+ command_print(cmd_ctx, "target timed out... shutting down");
+ exit(-1);
+ default:
+ command_print(cmd_ctx, "unknown error... shutting down");
+ exit(-1);
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = get_current_target(cmd_ctx);
+ enum target_reset_mode reset_mode = RESET_RUN;
+
+ DEBUG("");
+
+ if (argc >= 1)
+ {
+ if (strcmp("run", args[0]) == 0)
+ reset_mode = RESET_RUN;
+ else if (strcmp("halt", args[0]) == 0)
+ reset_mode = RESET_HALT;
+ else if (strcmp("init", args[0]) == 0)
+ reset_mode = RESET_INIT;
+ else if (strcmp("run_and_halt", args[0]) == 0)
+ {
+ reset_mode = RESET_RUN_AND_HALT;
+ if (argc >= 2)
+ {
+ target->run_and_halt_time = strtoul(args[1], NULL, 0);
+ }
+ }
+ else if (strcmp("run_and_init", args[0]) == 0)
+ {
+ reset_mode = RESET_RUN_AND_INIT;
+ if (argc >= 2)
+ {
+ target->run_and_halt_time = strtoul(args[1], NULL, 0);
+ }
+ }
+ else
+ {
+ command_print(cmd_ctx, "usage: reset ['run', 'halt', 'init', 'run_and_halt', 'run_and_init]");
+ return ERROR_OK;
+ }
+ target->reset_mode = reset_mode;
+ }
+
+ target_process_reset(cmd_ctx);
+
+ return ERROR_OK;
+}
+
+int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ int retval;
+ target_t *target = get_current_target(cmd_ctx);
+
+ DEBUG("");
+
+ if (argc == 0)
+ retval = target->type->resume(target, 1, 0, 1, 0); /* current pc, addr = 0, handle breakpoints, not debugging */
+ else if (argc == 1)
+ retval = target->type->resume(target, 0, strtoul(args[0], NULL, 0), 1, 0); /* addr = args[0], handle breakpoints, not debugging */
+ else
+ {
+ command_print(cmd_ctx, "usage: resume [address]");
+ return ERROR_OK;
+ }
+
+ if (retval != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_TARGET_NOT_HALTED:
+ command_print(cmd_ctx, "target not halted");
+ break;
+ default:
+ command_print(cmd_ctx, "unknown error... shutting down");
+ exit(-1);
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = get_current_target(cmd_ctx);
+
+ DEBUG("");
+
+ if (argc == 0)
+ target->type->step(target, 1, 0, 1); /* current pc, addr = 0, handle breakpoints */
+
+ if (argc == 1)
+ target->type->step(target, 0, strtoul(args[0], NULL, 0), 1); /* addr = args[0], handle breakpoints */
+
+ return ERROR_OK;
+}
+
+int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ int count = 1;
+ int size = 4;
+ u32 address = 0;
+ int i;
+
+ char output[128];
+ int output_len;
+
+ int retval;
+
+ u8 *buffer;
+ target_t *target = get_current_target(cmd_ctx);
+
+ if (argc < 1)
+ return ERROR_OK;
+
+ if (argc == 2)
+ count = strtoul(args[1], NULL, 0);
+
+ address = strtoul(args[0], NULL, 0);
+
+
+ switch (cmd[2])
+ {
+ case 'w':
+ size = 4;
+ break;
+ case 'h':
+ size = 2;
+ break;
+ case 'b':
+ size = 1;
+ break;
+ default:
+ return ERROR_OK;
+ }
+
+ buffer = calloc(count, size);
+ if ((retval = target->type->read_memory(target, address, size, count, buffer)) != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_TARGET_UNALIGNED_ACCESS:
+ command_print(cmd_ctx, "error: address not aligned");
+ break;
+ case ERROR_TARGET_NOT_HALTED:
+ command_print(cmd_ctx, "error: target must be halted for memory accesses");
+ break;
+ case ERROR_TARGET_DATA_ABORT:
+ command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted");
+ break;
+ default:
+ command_print(cmd_ctx, "error: unknown error");
+ break;
+ }
+ }
+
+ output_len = 0;
+
+ for (i = 0; i < count; i++)
+ {
+ if (i%8 == 0)
+ output_len += snprintf(output + output_len, 128 - output_len, "0x%8.8x: ", address + (i*size));
+
+ switch (size)
+ {
+ case 4:
+ output_len += snprintf(output + output_len, 128 - output_len, "%8.8x ", ((u32*)buffer)[i]);
+ break;
+ case 2:
+ output_len += snprintf(output + output_len, 128 - output_len, "%4.4x ", ((u16*)buffer)[i]);
+ break;
+ case 1:
+ output_len += snprintf(output + output_len, 128 - output_len, "%2.2x ", ((u8*)buffer)[i]);
+ break;
+ }
+
+ if ((i%8 == 7) || (i == count - 1))
+ {
+ command_print(cmd_ctx, output);
+ output_len = 0;
+ }
+ }
+
+ free(buffer);
+
+ return ERROR_OK;
+}
+
+int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ u32 address = 0;
+ u32 value = 0;
+ int retval;
+ target_t *target = get_current_target(cmd_ctx);
+
+ if (argc < 2)
+ return ERROR_OK;
+
+ address = strtoul(args[0], NULL, 0);
+ value = strtoul(args[1], NULL, 0);
+
+ switch (cmd[2])
+ {
+ case 'w':
+ retval = target->type->write_memory(target, address, 4, 1, (u8*)&value);
+ break;
+ case 'h':
+ retval = target->type->write_memory(target, address, 2, 1, (u8*)&value);
+ break;
+ case 'b':
+ retval = target->type->write_memory(target, address, 1, 1, (u8*)&value);
+ break;
+ default:
+ return ERROR_OK;
+ }
+
+ switch (retval)
+ {
+ case ERROR_TARGET_UNALIGNED_ACCESS:
+ command_print(cmd_ctx, "error: address not aligned");
+ break;
+ case ERROR_TARGET_DATA_ABORT:
+ command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted");
+ break;
+ case ERROR_TARGET_NOT_HALTED:
+ command_print(cmd_ctx, "error: target must be halted for memory accesses");
+ break;
+ case ERROR_OK:
+ break;
+ default:
+ command_print(cmd_ctx, "error: unknown error");
+ break;
+ }
+
+ return ERROR_OK;
+
+}
+
+int handle_load_binary_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ FILE *binary;
+ u32 address;
+ struct stat binary_stat;
+ u32 binary_size;
+
+ u8 *buffer;
+ u32 buf_cnt;
+
+ struct timeval start, end;
+
+ target_t *target = get_current_target(cmd_ctx);
+
+ if (argc != 2)
+ {
+ command_print(cmd_ctx, "usage: load_binary <filename> <address>");
+ return ERROR_OK;
+ }
+
+ address = strtoul(args[1], NULL, 0);
+
+ if (stat(args[0], &binary_stat) == -1)
+ {
+ ERROR("couldn't stat() %s: %s", args[0], strerror(errno));
+ command_print(cmd_ctx, "error accessing file %s", args[0]);
+ return ERROR_OK;
+ }
+
+ if (!(binary = fopen(args[0], "r")))
+ {
+ ERROR("couldn't open %s: %s", args[0], strerror(errno));
+ command_print(cmd_ctx, "error accessing file %s", args[0]);
+ return ERROR_OK;
+ }
+
+ buffer = malloc(128 * 1024);
+
+ gettimeofday(&start, NULL);
+
+ binary_size = binary_stat.st_size;
+ while (binary_size > 0)
+ {
+ buf_cnt = fread(buffer, 1, 128*1024, binary);
+ target_write_buffer(target, address, buf_cnt, buffer);
+ address += buf_cnt;
+ binary_size -= buf_cnt;
+ }
+
+ gettimeofday(&end, NULL);
+
+ free(buffer);
+
+ command_print(cmd_ctx, "downloaded %lli byte in %is %ius", (long long) binary_stat.st_size, end.tv_sec - start.tv_sec, end.tv_usec - start.tv_usec);
+
+ fclose(binary);
+
+ return ERROR_OK;
+
+}
+
+int handle_dump_binary_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ FILE *binary;
+ u32 address;
+ u32 size;
+ u8 buffer[560];
+
+ target_t *target = get_current_target(cmd_ctx);
+
+ if (argc != 3)
+ {
+ command_print(cmd_ctx, "usage: dump_binary <filename> <address> <size>");
+ return ERROR_OK;
+ }
+
+ address = strtoul(args[1], NULL, 0);
+ size = strtoul(args[2], NULL, 0);
+
+ if (!(binary = fopen(args[0], "w")))
+ {
+ ERROR("couldn't open %s for writing: %s", args[0], strerror(errno));
+ command_print(cmd_ctx, "error accessing file %s", args[0]);
+ return ERROR_OK;
+ }
+
+ if ((address & 3) || (size & 3))
+ {
+ command_print(cmd_ctx, "only 32-bit aligned address and size are supported");
+ return ERROR_OK;
+ }
+
+ while (size > 0)
+ {
+ u32 this_run_size = (size > 560) ? 560 : size;
+ target->type->read_memory(target, address, 4, this_run_size / 4, buffer);
+ fwrite(buffer, 1, this_run_size, binary);
+ size -= this_run_size;
+ address += this_run_size;
+ }
+
+ fclose(binary);
+
+ return ERROR_OK;
+
+}
+
+int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ int retval;
+ target_t *target = get_current_target(cmd_ctx);
+
+ if (argc == 0)
+ {
+ breakpoint_t *breakpoint = target->breakpoints;
+
+ while (breakpoint)
+ {
+ if (breakpoint->type == BKPT_SOFT)
+ {
+ char* buf = buf_to_char(breakpoint->orig_instr, breakpoint->length);
+ command_print(cmd_ctx, "0x%8.8x, 0x%x, %i, 0x%s", breakpoint->address, breakpoint->length, breakpoint->set, buf);
+ free(buf);
+ }
+ else
+ {
+ command_print(cmd_ctx, "0x%8.8x, 0x%x, %i", breakpoint->address, breakpoint->length, breakpoint->set);
+ }
+ breakpoint = breakpoint->next;
+ }
+ }
+ else if (argc >= 2)
+ {
+ int hw = BKPT_SOFT;
+ u32 length = 0;
+
+ length = strtoul(args[1], NULL, 0);
+
+ if (argc >= 3)
+ if (strcmp(args[2], "hw") == 0)
+ hw = BKPT_HARD;
+
+ if ((retval = breakpoint_add(target, strtoul(args[0], NULL, 0), length, hw)) != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_TARGET_NOT_HALTED:
+ command_print(cmd_ctx, "target must be halted to set breakpoints");
+ break;
+ case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
+ command_print(cmd_ctx, "no more breakpoints available");
+ break;
+ default:
+ command_print(cmd_ctx, "unknown error, breakpoint not set");
+ break;
+ }
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = get_current_target(cmd_ctx);
+
+ if (argc > 0)
+ breakpoint_remove(target, strtoul(args[0], NULL, 0));
+
+ return ERROR_OK;
+}
+
+int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = get_current_target(cmd_ctx);
+
+ if (argc == 0)
+ {
+ watchpoint_t *watchpoint = target->watchpoints;
+
+ while (watchpoint)
+ {
+ command_print(cmd_ctx, "address: 0x%8.8x, mask: 0x%8.8x, r/w/a: %i, value: 0x%8.8x, mask: 0x%8.8x", watchpoint->address, watchpoint->length, watchpoint->rw, watchpoint->value, watchpoint->mask);
+ watchpoint = watchpoint->next;
+ }
+ }
+ else if (argc >= 2)
+ {
+ enum watchpoint_rw type = WPT_ACCESS;
+ u32 data_value = 0x0;
+ u32 data_mask = 0xffffffff;
+
+ if (argc >= 3)
+ {
+ switch(args[2][0])
+ {
+ case 'r':
+ type = WPT_READ;
+ break;
+ case 'w':
+ type = WPT_WRITE;
+ break;
+ case 'a':
+ type = WPT_ACCESS;
+ break;
+ default:
+ command_print(cmd_ctx, "usage: wp <address> <length> [r/w/a] [value] [mask]");
+ return ERROR_OK;
+ }
+ }
+ if (argc >= 4)
+ {
+ data_value = strtoul(args[3], NULL, 0);
+ }
+ if (argc >= 5)
+ {
+ data_mask = strtoul(args[4], NULL, 0);
+ }
+ watchpoint_add(target, strtoul(args[0], NULL, 0), strtoul(args[1], NULL, 0), type, data_value, data_mask);
+ }
+ else
+ {
+ command_print(cmd_ctx, "usage: wp <address> <length> [r/w/a] [value] [mask]");
+ }
+
+ return ERROR_OK;
+}
+
+int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target = get_current_target(cmd_ctx);
+
+ if (argc > 0)
+ watchpoint_remove(target, strtoul(args[0], NULL, 0));
+
+ return ERROR_OK;
+}
+
diff --git a/src/target/target.h b/src/target/target.h
new file mode 100644
index 00000000..6d3b6d17
--- /dev/null
+++ b/src/target/target.h
@@ -0,0 +1,231 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef TARGET_H
+#define TARGET_H
+
+#include "register.h"
+#include "breakpoints.h"
+#include "algorithm.h"
+
+#include "command.h"
+#include "types.h"
+
+#include <sys/time.h>
+#include <time.h>
+
+struct reg_s;
+struct command_context_s;
+
+enum target_state
+{
+ TARGET_UNKNOWN = 0,
+ TARGET_RUNNING = 1,
+ TARGET_HALTED = 2,
+ TARGET_RESET = 3,
+ TARGET_DEBUG_RUNNING = 4,
+};
+
+extern char *target_state_strings[];
+
+enum daemon_startup_mode
+{
+ DAEMON_ATTACH, /* simply attach to the target */
+ DAEMON_RESET, /* reset target (behaviour defined by reset_mode */
+};
+
+enum target_reset_mode
+{
+ RESET_RUN = 0, /* reset and let target run */
+ RESET_HALT = 1, /* reset and halt target out of reset */
+ RESET_INIT = 2, /* reset and halt target out of reset, then run init script */
+ RESET_RUN_AND_HALT = 3, /* reset and let target run, halt after n milliseconds */
+ RESET_RUN_AND_INIT = 4, /* reset and let target run, halt after n milliseconds, then run init script */
+};
+
+enum target_debug_reason
+{
+ DBG_REASON_DBGRQ = 0,
+ DBG_REASON_BREAKPOINT = 1,
+ DBG_REASON_WATCHPOINT = 2,
+ DBG_REASON_WPTANDBKPT = 3,
+ DBG_REASON_SINGLESTEP = 4,
+ DBG_REASON_NOTHALTED = 5
+};
+
+extern char *target_debug_reason_strings[];
+
+enum target_endianess
+{
+ TARGET_BIG_ENDIAN = 0, TARGET_LITTLE_ENDIAN = 1
+};
+
+extern char *target_endianess_strings[];
+
+struct target_s;
+
+typedef struct working_area_s
+{
+ u32 address;
+ u32 size;
+ int free;
+ u8 *backup;
+ struct working_area_s **user;
+ struct working_area_s *next;
+} working_area_t;
+
+typedef struct target_type_s
+{
+ char *name;
+
+ /* poll current target status */
+ enum target_state (*poll)(struct target_s *target);
+ /* architecture specific status reply */
+ int (*arch_state)(struct target_s *target, char *buf, int buf_size);
+
+ /* target execution control */
+ int (*halt)(struct target_s *target);
+ int (*resume)(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution);
+ int (*step)(struct target_s *target, int current, u32 address, int handle_breakpoints);
+
+ /* target reset control */
+ int (*assert_reset)(struct target_s *target);
+ int (*deassert_reset)(struct target_s *target);
+ int (*soft_reset_halt)(struct target_s *target);
+
+ /* target register access for gdb */
+ int (*get_gdb_reg_list)(struct target_s *target, struct reg_s **reg_list[], int *reg_list_size);
+
+ /* target memory access
+ * size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit)
+ * count: number of items of <size>
+ */
+ int (*read_memory)(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
+ int (*write_memory)(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
+
+ /* write target memory in multiples of 4 byte, optimized for writing large quantities of data */
+ int (*bulk_write_memory)(struct target_s *target, u32 address, u32 count, u8 *buffer);
+
+ /* target break-/watchpoint control
+ * rw: 0 = write, 1 = read, 2 = access
+ */
+ int (*add_breakpoint)(struct target_s *target, u32 address, u32 length, enum breakpoint_type type);
+ int (*remove_breakpoint)(struct target_s *target, breakpoint_t *breakpoint);
+ int (*add_watchpoint)(struct target_s *target, u32 address, u32 length, enum watchpoint_rw rw);
+ int (*remove_watchpoint)(struct target_s *target, watchpoint_t *watchpoint);
+
+ /* target algorithm support */
+ int (*run_algorithm)(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_param, u32 entry_point, u32 exit_point, int timeout_ms, void *arch_info);
+
+ int (*register_commands)(struct command_context_s *cmd_ctx);
+ int (*target_command)(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
+ int (*init_target)(struct command_context_s *cmd_ctx, struct target_s *target);
+ int (*quit)(void);
+
+} target_type_t;
+
+typedef struct target_s
+{
+ target_type_t *type; /* target type definition (name, access functions) */
+ enum target_reset_mode reset_mode; /* what to do after a reset */
+ int run_and_halt_time; /* how long the target should run after a run_and_halt reset */
+ char *reset_script; /* script file to initialize the target after a reset */
+ char *post_halt_script; /* script file to execute after the target halted */
+ char *pre_resume_script; /* script file to execute before the target resumed */
+ u32 working_area; /* working area (initialized RAM) */
+ u32 working_area_size; /* size in bytes */
+ u32 backup_working_area; /* whether the content of the working area has to be preserved */
+ struct working_area_s *working_areas;/* list of allocated working areas */
+ enum target_debug_reason debug_reason; /* reason why the target entered debug state */
+ enum target_endianess endianness; /* target endianess */
+ enum target_state state; /* the current backend-state (running, halted, ...) */
+ struct reg_cache_s *reg_cache; /* the first register cache of the target (core regs) */
+ struct breakpoint_s *breakpoints; /* list of breakpoints */
+ struct watchpoint_s *watchpoints; /* list of watchpoints */
+ void *arch_info; /* architecture specific information */
+ struct target_s *next; /* next target in list */
+} target_t;
+
+enum target_event
+{
+ TARGET_EVENT_HALTED, /* target entered debug state from normal execution or reset */
+ TARGET_EVENT_RESUMED, /* target resumed to normal execution */
+ TARGET_EVENT_RESET, /* target entered reset */
+ TARGET_EVENT_DEBUG_HALTED, /* target entered debug state, but was executing on behalf of the debugger */
+ TARGET_EVENT_DEBUG_RESUMED, /* target resumed to execute on behalf of the debugger */
+};
+
+typedef struct target_event_callback_s
+{
+ int (*callback)(struct target_s *target, enum target_event event, void *priv);
+ void *priv;
+ struct target_event_callback_s *next;
+} target_event_callback_t;
+
+typedef struct target_timer_callback_s
+{
+ int (*callback)(void *priv);
+ int time_ms;
+ int periodic;
+ struct timeval when;
+ void *priv;
+ struct target_timer_callback_s *next;
+} target_timer_callback_t;
+
+extern int target_register_commands(struct command_context_s *cmd_ctx);
+extern int target_register_user_commands(struct command_context_s *cmd_ctx);
+extern int target_init(struct command_context_s *cmd_ctx);
+extern int handle_target(void *priv);
+
+extern int target_register_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv);
+extern int target_unregister_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv);
+extern int target_call_event_callbacks(target_t *target, enum target_event event);
+
+extern int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv);
+extern int target_unregister_timer_callback(int (*callback)(void *priv), void *priv);
+extern int target_call_timer_callbacks();
+
+extern target_t* get_current_target(struct command_context_s *cmd_ctx);
+extern int get_num_by_target(target_t *query_target);
+extern target_t* get_target_by_num(int num);
+
+extern int target_write_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer);
+extern int target_read_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer);
+
+extern int target_alloc_working_area(struct target_s *target, u32 size, working_area_t **area);
+extern int target_free_working_area(struct target_s *target, working_area_t *area);
+extern int target_free_all_working_areas(struct target_s *target);
+
+extern target_t *targets;
+
+extern target_event_callback_t *target_event_callbacks;
+extern target_timer_callback_t *target_timer_callbacks;
+
+#define ERROR_TARGET_INVALID (-300)
+#define ERROR_TARGET_INIT_FAILED (-301)
+#define ERROR_TARGET_TIMEOUT (-302)
+#define ERROR_TARGET_ALREADY_HALTED (-303)
+#define ERROR_TARGET_NOT_HALTED (-304)
+#define ERROR_TARGET_FAILURE (-305)
+#define ERROR_TARGET_UNALIGNED_ACCESS (-306)
+#define ERROR_TARGET_DATA_ABORT (-307)
+#define ERROR_TARGET_RESOURCE_NOT_AVAILABLE (-308)
+#define ERROR_TARGET_TRANSLATION_FAULT (-309)
+
+#endif /* TARGET_H */