Michael Bruck:
authoroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Fri, 29 Feb 2008 07:03:28 +0000 (07:03 +0000)
committeroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Fri, 29 Feb 2008 07:03:28 +0000 (07:03 +0000)
arm11

--- Added burst memory transfer mode

This does not explicitly query command execution but rather uses a small
delay produced by the FT2232 on certain TAP commands.

A potential failure of this process is detected afterwards and the
program terminates with an error.

'arm11 memwrite burst disable'
  can be used to switch this feature off.

'arm11 memwrite error_fatal disable'
  can be used to prevent the program to exit on an memory write error

--- Added support for interrupt breaking via VCR register

Use 'arm11 vcr' command to set.

--- Cleaned up the handling of

halt/resume/step/poll, target->state, target->debug_reason,
target_call_event_callbacks() at least as far as I could guess the
intended behaviour from other targets.

Did some overall positive tests with GDB.

--- Added support for breakpoints

Hardware breakpoints only. All breakpoints will be treated as hardware
breakpoints.

All ARM11's seem to have at least 6 hardware breakpoints.

--- Stepping over BKPT added

Modification to PC without touching the target.

--- Stepping over a B or BL to self will do nothing

git-svn-id: svn://svn.berlios.de/openocd/trunk@385 b42882b7-edfa-0310-969c-e2dbd0fdcd60

src/target/Makefile.am
src/target/arm11.c
src/target/arm11.h
src/target/arm11_dbgtap.c
src/target/target.c

index 832ff73..acda722 100644 (file)
@@ -5,6 +5,7 @@ else
 OOCD_TRACE_FILES =
 endif
 
+CFLAGS += -Wall
 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
 AM_CPPFLAGS = -DPKGLIBDIR=\"$(pkglibdir)\" @CPPFLAGS@
@@ -12,11 +13,11 @@ noinst_LIBRARIES = libtarget.a
 libtarget_a_SOURCES = target.c register.c breakpoints.c armv4_5.c embeddedice.c etm.c arm7tdmi.c arm9tdmi.c \
        arm_jtag.c arm7_9_common.c algorithm.c arm920t.c arm720t.c armv4_5_mmu.c armv4_5_cache.c arm_disassembler.c \
        arm966e.c arm926ejs.c feroceon.c etb.c xscale.c arm_simulator.c image.c armv7m.c cortex_m3.c cortex_swjdp.c \
-       etm_dummy.c $(OOCD_TRACE_FILES) target_request.c trace.c
+       etm_dummy.c $(OOCD_TRACE_FILES) target_request.c trace.c arm11.c arm11_dbgtap.c
 noinst_HEADERS = target.h trace.h register.h armv4_5.h embeddedice.h etm.h arm7tdmi.h arm9tdmi.h \
        arm_jtag.h arm7_9_common.h arm920t.h arm720t.h armv4_5_mmu.h armv4_5_cache.h breakpoints.h algorithm.h \
        arm_disassembler.h arm966e.h arm926ejs.h etb.h xscale.h arm_simulator.h image.h armv7m.h cortex_m3.h cortex_swjdp.h \
-       etm_dummy.h oocd_trace.h target_request.h trace.h
+       etm_dummy.h oocd_trace.h target_request.h trace.h arm11.h
 
 nobase_dist_pkglib_DATA = xscale/debug_handler.bin event/at91eb40a_reset.cfg target/at91eb40a.cfg
 
index d02518a..905a5d7 100644 (file)
 static void arm11_on_enter_debug_state(arm11_common_t * arm11);
 
 
+bool   arm11_config_memwrite_burst             = true;
+bool   arm11_config_memwrite_error_fatal       = true;
+u32    arm11_vcr                               = 0;
+
+
 #define ARM11_HANDLER(x)       \
     .x                         = arm11_##x
 
@@ -338,7 +343,7 @@ void arm11_check_init(arm11_common_t * arm11, u32 * dscr)
            arm11->target->debug_reason = DBG_REASON_NOTHALTED;
        }
 
-       arm11_sc7_clear_bw(arm11);
+       arm11_sc7_clear_vbw(arm11);
     }
 }
 
@@ -382,7 +387,7 @@ static void arm11_on_enter_debug_state(arm11_common_t * arm11)
        arm11_setup_field(arm11,  1, NULL, NULL,        chain5_fields + 1);
        arm11_setup_field(arm11,  1, NULL, NULL,        chain5_fields + 2);
 
-       jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD);
+       arm11_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD);
     }
     else
     {
@@ -501,7 +506,11 @@ static void arm11_on_enter_debug_state(arm11_common_t * arm11)
 
     arm11_run_instr_data_finish(arm11);
 
+    arm11_dump_reg_changes(arm11);
+}
 
+void arm11_dump_reg_changes(arm11_common_t * arm11)
+{
     {size_t i;
     for(i = 0; i < ARM11_REGCACHE_COUNT; i++)
     {
@@ -556,7 +565,7 @@ void arm11_leave_debug_state(arm11_common_t * arm11)
 
 
     /* spec says clear wDTR and rDTR; we assume they are clear as
-       otherwide out programming would be sloppy */
+       otherwise our programming would be sloppy */
 
     {
        u32 DSCR = arm11_read_DSCR(arm11);
@@ -619,10 +628,14 @@ void arm11_leave_debug_state(arm11_common_t * arm11)
        arm11_setup_field(arm11,  1, &Ready,    NULL, chain5_fields + 1);
        arm11_setup_field(arm11,  1, &Valid,    NULL, chain5_fields + 2);
 
-       jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD);
+       arm11_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD);
     }
 
+    arm11_record_register_history(arm11);
+}
 
+void arm11_record_register_history(arm11_common_t * arm11)
+{
     {size_t i;
     for(i = 0; i < ARM11_REGCACHE_COUNT; i++)
     {
@@ -653,21 +666,22 @@ int arm11_poll(struct target_s *target)
 
     if (dscr & ARM11_DSCR_CORE_HALTED)
     {
-//     DEBUG("CH %d", target->state);
-
        if (target->state != TARGET_HALTED)
        {
+           enum target_state old_state = target->state;
+
            DEBUG("enter TARGET_HALTED");
            target->state               = TARGET_HALTED;
            target->debug_reason        = arm11_get_DSCR_debug_reason(dscr);
            arm11_on_enter_debug_state(arm11);
+
+           target_call_event_callbacks(target,
+               old_state == TARGET_DEBUG_RUNNING ? TARGET_EVENT_DEBUG_HALTED : TARGET_EVENT_HALTED);
        }
     }
     else
     {
-//     DEBUG("CR %d", target->state);
-
-       if (target->state != TARGET_RUNNING)
+       if (target->state != TARGET_RUNNING && target->state != TARGET_DEBUG_RUNNING)
        {
            DEBUG("enter TARGET_RUNNING");
            target->state               = TARGET_RUNNING;
@@ -733,9 +747,14 @@ int arm11_halt(struct target_s *target)
 
     arm11_on_enter_debug_state(arm11);
 
+    enum target_state old_state        = target->state;
+
     target->state              = TARGET_HALTED;
     target->debug_reason       = arm11_get_DSCR_debug_reason(dscr);
-    
+
+    target_call_event_callbacks(target,
+       old_state == TARGET_DEBUG_RUNNING ? TARGET_EVENT_DEBUG_HALTED : TARGET_EVENT_HALTED);
+
     return ERROR_OK;
 }
 
@@ -744,6 +763,9 @@ int arm11_resume(struct target_s *target, int current, u32 address, int handle_b
 {
     FNC_INFO;
 
+//    DEBUG("current %d  address %08x  handle_breakpoints %d  debug_execution %d",
+//     current, address, handle_breakpoints, debug_execution);
+
     arm11_common_t * arm11 = target->arch_info;
 
     DEBUG("target->state: %s", target_state_strings[target->state]);
@@ -757,8 +779,53 @@ int arm11_resume(struct target_s *target, int current, u32 address, int handle_b
     if (!current)
        R(PC) = address;
 
-    target->state              = TARGET_RUNNING;
-    target->debug_reason       = DBG_REASON_NOTHALTED;
+    INFO("RESUME PC %08x", R(PC));
+
+    /* clear breakpoints/watchpoints and VCR*/
+    arm11_sc7_clear_vbw(arm11);
+
+    /* Set up breakpoints */
+    if (!debug_execution)
+    {
+       /* check if one matches PC and step over it if necessary */
+
+       breakpoint_t *  bp;
+
+       for (bp = target->breakpoints; bp; bp = bp->next)
+       {
+           if (bp->address == R(PC))
+           {
+               DEBUG("must step over %08x", bp->address);
+               arm11_step(target, 1, 0, 0);
+               break;
+           }
+       }
+
+       /* set all breakpoints */
+
+       size_t          brp_num = 0;
+       
+       for (bp = target->breakpoints; bp; bp = bp->next)
+       {
+           arm11_sc7_action_t  brp[2];
+
+           brp[0].write        = 1;
+           brp[0].address      = ARM11_SC7_BVR0 + brp_num;
+           brp[0].value        = bp->address;
+           brp[1].write        = 1;
+           brp[1].address      = ARM11_SC7_BCR0 + brp_num;
+           brp[1].value        = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (0 << 21);
+    
+           arm11_sc7_run(arm11, brp, asizeof(brp));
+
+           DEBUG("Add BP %d at %08x", brp_num, bp->address);
+
+           brp_num++;
+       }
+
+       arm11_sc7_set_vcr(arm11, arm11_vcr);
+    }
+
 
     arm11_leave_debug_state(arm11);
 
@@ -776,7 +843,18 @@ int arm11_resume(struct target_s *target, int current, u32 address, int handle_b
            break;
     }
 
-    DEBUG("RES %d", target->state);
+    if (!debug_execution)
+    {
+       target->state           = TARGET_RUNNING;
+       target->debug_reason    = DBG_REASON_NOTHALTED;
+       target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+    }
+    else
+    {
+       target->state           = TARGET_DEBUG_RUNNING;
+       target->debug_reason    = DBG_REASON_NOTHALTED;
+       target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
+    }
 
     return ERROR_OK;
 }
@@ -795,61 +873,87 @@ int arm11_step(struct target_s *target, int current, u32 address, int handle_bre
 
     arm11_common_t * arm11 = target->arch_info;
 
-    /** \todo TODO: check if break-/watchpoints make any sense at all in combination
-      * with this. */
+    if (!current)
+       R(PC) = address;
+
+    INFO("STEP PC %08x", R(PC));
 
-    /** \todo TODO: check if disabling IRQs might be a good idea here. Alternatively
-        the VCR might be something worth looking into. */
+    /** \todo TODO: Thumb not supported here */
 
-    /* Set up breakpoint for stepping */
+    u32        next_instruction;
 
-    arm11_sc7_action_t brp[2];
+    arm11_read_memory_word(arm11, R(PC), &next_instruction);
 
-    brp[0].write       = 1;
-    brp[0].address     = ARM11_SC7_BVR0;
-    brp[0].value       = R(PC);
-    brp[1].write       = 1;
-    brp[1].address     = ARM11_SC7_BCR0;
-    brp[1].value       = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (2 << 21);
+    /** skip over BKPT */
+    if ((next_instruction & 0xFFF00070) == 0xe1200070)
+    {
+       R(PC) += 4;
+       arm11->reg_list[ARM11_RC_PC].valid = 1;
+       arm11->reg_list[ARM11_RC_PC].dirty = 0;
+       INFO("Skipping BKPT");
+    }
+    /* ignore B to self */
+    else if ((next_instruction & 0xFEFFFFFF) == 0xeafffffe)
+    {
+       INFO("Not stepping jump to self");
+    }
+    else
+    {
+       /** \todo TODO: check if break-/watchpoints make any sense at all in combination
+         * with this. */
 
-    arm11_sc7_run(arm11, brp, asizeof(brp));
+       /** \todo TODO: check if disabling IRQs might be a good idea here. Alternatively
+         * the VCR might be something worth looking into. */
 
-    /* resume */
 
-    arm11_leave_debug_state(arm11);
+       /* Set up breakpoint for stepping */
 
-    arm11_add_IR(arm11, ARM11_RESTART, TAP_RTI);
+       arm11_sc7_action_t      brp[2];
 
-    jtag_execute_queue();
+       brp[0].write    = 1;
+       brp[0].address  = ARM11_SC7_BVR0;
+       brp[0].value    = R(PC);
+       brp[1].write    = 1;
+       brp[1].address  = ARM11_SC7_BCR0;
+       brp[1].value    = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (2 << 21);
 
-    /** \todo TODO: add a timeout */
+       arm11_sc7_run(arm11, brp, asizeof(brp));
 
-    /* wait for halt */
+       /* resume */
 
-    while (1)
-    {
-       u32 dscr = arm11_read_DSCR(arm11);
+       arm11_leave_debug_state(arm11);
 
-       DEBUG("DSCR %08x", dscr);
+       arm11_add_IR(arm11, ARM11_RESTART, TAP_RTI);
 
-        if ((dscr & (ARM11_DSCR_CORE_RESTARTED | ARM11_DSCR_CORE_HALTED)) ==
-           (ARM11_DSCR_CORE_RESTARTED | ARM11_DSCR_CORE_HALTED))
-           break;
-    }
+       jtag_execute_queue();
 
+       /** \todo TODO: add a timeout */
 
-    /* clear breakpoint */
+       /* wait for halt */
 
-    arm11_sc7_clear_bw(arm11);
+       while (1)
+       {
+           u32 dscr = arm11_read_DSCR(arm11);
 
+           DEBUG("DSCR %08x", dscr);
 
-    /* save state */
+           if ((dscr & (ARM11_DSCR_CORE_RESTARTED | ARM11_DSCR_CORE_HALTED)) ==
+               (ARM11_DSCR_CORE_RESTARTED | ARM11_DSCR_CORE_HALTED))
+               break;
+       }
 
-    arm11_on_enter_debug_state(arm11);
+       /* clear breakpoint */
+       arm11_sc7_clear_vbw(arm11);
+
+       /* save state */
+       arm11_on_enter_debug_state(arm11);
+    }
 
 //    target->state            = TARGET_HALTED;
     target->debug_reason       = DBG_REASON_SINGLESTEP;
 
+    target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+
     return ERROR_OK;
 }
 
@@ -1064,13 +1168,47 @@ int arm11_write_memory(struct target_s *target, u32 address, u32 size, u32 count
     case 4:
        /** \todo TODO: check if buffer cast to u32* might cause alignment problems */
 
-       /* STC p14,c5,[R0],#4 */
-       arm11_run_instr_data_to_core(arm11, 0xeca05e01, (u32 *)buffer, count);
+       if (!arm11_config_memwrite_burst)
+       {
+           /* STC p14,c5,[R0],#4 */
+           arm11_run_instr_data_to_core(arm11, 0xeca05e01, (u32 *)buffer, count);
+       }
+       else
+       {
+           /* STC p14,c5,[R0],#4 */
+           arm11_run_instr_data_to_core_noack(arm11, 0xeca05e01, (u32 *)buffer, count);
+       }
+
        break;
     }
 
+#if 1
+    /* r0 verification */
+    {
+       u32 r0;
+
+       /* MCR p14,0,R0,c0,c5,0 */
+       arm11_run_instr_data_from_core(arm11, 0xEE000E15, &r0, 1);
+
+       if (address + size * count != r0)
+       {
+           ERROR("Data transfer failed. (%d)", (r0 - address) - size * count);
+
+           if (arm11_config_memwrite_burst)
+               ERROR("use 'arm11 memwrite burst disable' to disable fast burst mode");
+
+           if (arm11_config_memwrite_error_fatal)
+               exit(-1);
+       }
+    }
+#endif
+
+
     arm11_run_instr_data_finish(arm11);
 
+
+
+
     return ERROR_OK;
 }
 
@@ -1097,14 +1235,42 @@ int arm11_checksum_memory(struct target_s *target, u32 address, u32 count, u32*
 */
 int arm11_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
 {
-    FNC_INFO_NOTIMPLEMENTED;
+    FNC_INFO;
+
+    arm11_common_t * arm11 = target->arch_info;
+
+#if 0
+    if (breakpoint->type == BKPT_SOFT)
+    {
+       INFO("sw breakpoint requested, but software breakpoints not enabled");
+       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+    }
+#endif
+
+    if (!arm11->free_brps)
+    {
+       INFO("no breakpoint unit available for hardware breakpoint");
+       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+    }
+
+    if (breakpoint->length != 4)
+    {
+       INFO("only breakpoints of four bytes length supported");
+       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+    }
+
+    arm11->free_brps--;
 
     return ERROR_OK;
 }
 
 int arm11_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
 {
-    FNC_INFO_NOTIMPLEMENTED;
+    FNC_INFO;
+
+    arm11_common_t * arm11 = target->arch_info;
+       
+    arm11->free_brps++;
 
     return ERROR_OK;
 }
@@ -1132,14 +1298,6 @@ int arm11_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t
     return ERROR_OK;
 }
 
-
-int arm11_register_commands(struct command_context_s *cmd_ctx)
-{
-    FNC_INFO;
-
-    return ERROR_OK;
-}
-
 int arm11_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
 {
     FNC_INFO;
@@ -1189,7 +1347,7 @@ int arm11_init_target(struct command_context_s *cmd_ctx, struct target_s *target
 
     arm11_setup_field(arm11, 32, NULL, &arm11->device_id, &idcode_field);
 
-    jtag_add_dr_scan_vc(1, &idcode_field, TAP_PD);
+    arm11_add_dr_scan_vc(1, &idcode_field, TAP_PD);
 
     /* check DIDR */
 
@@ -1202,7 +1360,7 @@ int arm11_init_target(struct command_context_s *cmd_ctx, struct target_s *target
     arm11_setup_field(arm11, 32, NULL, &arm11->didr,           chain0_fields + 0);
     arm11_setup_field(arm11,  8, NULL, &arm11->implementor,    chain0_fields + 1);
 
-    jtag_add_dr_scan_vc(asizeof(chain0_fields), chain0_fields, TAP_RTI);
+    arm11_add_dr_scan_vc(asizeof(chain0_fields), chain0_fields, TAP_RTI);
 
     jtag_execute_queue();
 
@@ -1219,9 +1377,22 @@ int arm11_init_target(struct command_context_s *cmd_ctx, struct target_s *target
     }
     }
 
+    arm11->debug_version = (arm11->didr >> 16) & 0x0F;
+
+    if (arm11->debug_version != ARM11_DEBUG_V6 &&
+       arm11->debug_version != ARM11_DEBUG_V61)
+    {
+       ERROR("Only ARMv6 v6 and v6.1 architectures supported.");
+       exit(-1);
+    }
+
+
     arm11->brp = ((arm11->didr >> 24) & 0x0F) + 1;
     arm11->wrp = ((arm11->didr >> 28) & 0x0F) + 1;
 
+    /** \todo TODO: reserve one brp slot if we allow breakpoints during step */
+    arm11->free_brps = arm11->brp;
+    arm11->free_wrps = arm11->wrp;
 
     DEBUG("IDCODE %08x IMPLEMENTOR %02x DIDR %08x",
        arm11->device_id,
@@ -1260,7 +1431,7 @@ int arm11_get_reg(reg_t *reg)
        return ERROR_TARGET_NOT_HALTED;
     }
 
-    /** \todo TODO: Check this. We assume that all registers are fetched debug entry. */
+    /** \todo TODO: Check this. We assume that all registers are fetched at debug entry. */
 
 #if 0
     arm11_common_t *arm11 = target->arch_info;
@@ -1344,15 +1515,105 @@ void arm11_build_reg_cache(target_t *target)
     }
 }
 
-#if 0
-    arm11_run_instr_data_prepare(arm11);
 
-    /* MRC p14,0,r0,c0,c5,0 */
-    arm11_run_instr_data_to_core(arm11, 0xee100e15, 0xCA00003C);
-    /* MRC p14,0,r1,c0,c5,0 */
-    arm11_run_instr_data_to_core(arm11, 0xee101e15, 0xFFFFFFFF);
 
-    arm11_run_instr_data_finish(arm11);
-#endif
+int arm11_handle_bool(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, bool * var, char * name)
+{
+    if (argc == 0)
+    {
+       INFO("%s is %s.", name, *var ? "enabled" : "disabled");
+       return ERROR_OK;
+    }
+
+    if (argc != 1)
+       return ERROR_COMMAND_SYNTAX_ERROR;
+
+    switch (args[0][0])
+    {
+    case '0':  /* 0 */
+    case 'f':  /* false */
+    case 'F':
+    case 'd':  /* disable */
+    case 'D':
+       *var = false;
+       break;
+
+    case '1':  /* 1 */
+    case 't':  /* true */
+    case 'T':
+    case 'e':  /* enable */
+    case 'E':
+       *var = true;
+       break;
+    }
+
+    INFO("%s %s.", *var ? "Enabled" : "Disabled", name);
+
+    return ERROR_OK;
+}
+
+
+#define BOOL_WRAPPER(name, print_name)  \
+int arm11_handle_bool_##name(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) \
+{ \
+    return arm11_handle_bool(cmd_ctx, cmd, args, argc, &arm11_config_##name, print_name); \
+}
+
+#define RC_TOP(name, descr, more)  \
+{ \
+    command_t * new_cmd = register_command(cmd_ctx, top_cmd, name, NULL, COMMAND_ANY, descr);  \
+    command_t * top_cmd = new_cmd; \
+    more \
+}
 
+#define RC_FINAL(name, descr, handler)  \
+    register_command(cmd_ctx, top_cmd, name, handler, COMMAND_ANY, descr);
 
+#define RC_FINAL_BOOL(name, descr, var)  \
+    register_command(cmd_ctx, top_cmd, name, arm11_handle_bool_##var, COMMAND_ANY, descr);
+
+
+BOOL_WRAPPER(memwrite_burst,           "memory write burst mode")
+BOOL_WRAPPER(memwrite_error_fatal,     "fatal error mode for memory writes")
+
+
+int arm11_handle_vcr(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+    if (argc == 1)
+    {
+       arm11_vcr = strtoul(args[0], NULL, 0);
+    }
+    else if (argc != 0)
+    {
+       return ERROR_COMMAND_SYNTAX_ERROR;
+    }
+
+    INFO("VCR 0x%08X", arm11_vcr);
+    return ERROR_OK;
+}
+
+
+int arm11_register_commands(struct command_context_s *cmd_ctx)
+{
+    FNC_INFO;
+
+    command_t * top_cmd = NULL;
+
+    RC_TOP(                    "arm11",        "arm11 specific commands",
+
+       RC_TOP(                 "memwrite",     "Control memory write transfer mode",
+
+           RC_FINAL_BOOL(      "burst",        "Enable/Disable non-standard but fast burst mode (default: enabled)",
+                                               memwrite_burst)
+
+           RC_FINAL_BOOL(      "error_fatal",
+                                               "Terminate program if transfer error was found (default: enabled)",
+                                               memwrite_error_fatal)
+       )
+
+       RC_FINAL(               "vcr",          "Control (Interrupt) Vector Catch Register",
+                                               arm11_handle_vcr)
+    )
+
+    return ERROR_OK;
+}
index f2263b5..6e3b1d1 100644 (file)
@@ -50,7 +50,13 @@ typedef struct arm11_register_history_s
     u8     valid;
 }arm11_register_history_t;
 
-
+enum arm11_debug_version
+{
+    ARM11_DEBUG_V6     = 0x01,
+    ARM11_DEBUG_V61    = 0x02,
+    ARM11_DEBUG_V7     = 0x03,
+    ARM11_DEBUG_V7_CP14        = 0x04,
+};
 
 typedef struct arm11_common_s
 {
@@ -65,9 +71,11 @@ typedef struct arm11_common_s
     u32                didr;               /**< DIDR readout (debug capabilities)      */
     u8         implementor;        /**< DIDR Implementor readout               */
 
-    size_t     brp;                /**< Number of Breakpoint Register Pairs    */
-    size_t     wrp;                /**< Number of Watchpoint Register Pairs    */
+    size_t     brp;                /**< Number of Breakpoint Register Pairs from DIDR  */
+    size_t     wrp;                /**< Number of Watchpoint Register Pairs from DIDR  */
 
+    enum arm11_debug_version
+               debug_version;      /**< ARM debug architecture from DIDR       */
     /*@}*/
 
 
@@ -89,6 +97,9 @@ typedef struct arm11_common_s
                reg_history[ARM11_REGCACHE_COUNT];      /**< register state before last resume */
 
 
+    size_t     free_brps;                              /**< keep track of breakpoints allocated by arm11_add_breakpoint() */
+    size_t     free_wrps;                              /**< keep track of breakpoints allocated by arm11_add_watchpoint() */
+
 } arm11_common_t;
 
 
@@ -212,6 +223,9 @@ int arm11_quit(void);
 /* helpers */
 void arm11_build_reg_cache(target_t *target);
 
+void arm11_record_register_history(arm11_common_t * arm11);
+void arm11_dump_reg_changes(arm11_common_t * arm11);
+
 
 /* internals */
 
@@ -229,21 +243,36 @@ void arm11_run_instr_data_finish          (arm11_common_t * arm11);
 void arm11_run_instr_no_data                   (arm11_common_t * arm11, u32 * opcode, size_t count);
 void arm11_run_instr_no_data1                  (arm11_common_t * arm11, u32 opcode);
 void arm11_run_instr_data_to_core              (arm11_common_t * arm11, u32 opcode, u32 * data, size_t count);
+void arm11_run_instr_data_to_core_noack                (arm11_common_t * arm11, u32 opcode, u32 * data, size_t count);
 void arm11_run_instr_data_to_core1             (arm11_common_t * arm11, u32 opcode, u32 data);
 void arm11_run_instr_data_from_core            (arm11_common_t * arm11, u32 opcode, u32 * data, size_t count);
 void arm11_run_instr_data_from_core_via_r0     (arm11_common_t * arm11, u32 opcode, u32 * data);
 void arm11_run_instr_data_to_core_via_r0       (arm11_common_t * arm11, u32 opcode, u32 data);
 
+int arm11_add_dr_scan_vc(int num_fields, scan_field_t *fields, enum tap_state state);
+int arm11_add_ir_scan_vc(int num_fields, scan_field_t *fields, enum tap_state state);
 
+
+/** Used to make a list of read/write commands for scan chain 7
+ *
+ *  Use with arm11_sc7_run()
+ */
 typedef struct arm11_sc7_action_s
 {
-    bool    write;
-    u8     address;
-    u32            value;
+    bool    write;                             /**< Access mode: true for write, false for read.       */
+    u8     address;                            /**< Register address mode. Use enum #arm11_sc7         */
+    u32            value;                              /**< If write then set this to value to be written.
+                                                    In read mode this receives the read value when the
+                                                    function returns.                                  */
 } arm11_sc7_action_t;
 
 void arm11_sc7_run(arm11_common_t * arm11, arm11_sc7_action_t * actions, size_t count);
-void arm11_sc7_clear_bw(arm11_common_t * arm11);
+
+/* Mid-level helper functions */
+void arm11_sc7_clear_vbw(arm11_common_t * arm11);
+void arm11_sc7_set_vcr(arm11_common_t * arm11, u32 value);
+
+void arm11_read_memory_word(arm11_common_t * arm11, u32 address, u32 * result);
 
 
 
index d77c953..eed48bb 100644 (file)
        do {} while(0)
 #endif
 
+enum tap_state arm11_move_pi_to_si_via_ci[] =
+{
+    TAP_E2I, TAP_UI, TAP_SDS, TAP_SIS, TAP_CI, TAP_SI
+};
+
+
+int arm11_add_ir_scan_vc(int num_fields, scan_field_t *fields, enum tap_state state)
+{
+    if (cmd_queue_cur_state == TAP_PI)
+       jtag_add_pathmove(asizeof(arm11_move_pi_to_si_via_ci), arm11_move_pi_to_si_via_ci);
+
+    return jtag_add_ir_scan(num_fields, fields, state);
+}
+
+enum tap_state arm11_move_pd_to_sd_via_cd[] =
+{
+    TAP_E2D, TAP_UD, TAP_SDS, TAP_CD, TAP_SD
+};
+
+int arm11_add_dr_scan_vc(int num_fields, scan_field_t *fields, enum tap_state state)
+{
+    if (cmd_queue_cur_state == TAP_PD)
+       jtag_add_pathmove(asizeof(arm11_move_pd_to_sd_via_cd), arm11_move_pd_to_sd_via_cd);
+
+    return jtag_add_dr_scan(num_fields, fields, state);
+}
+
+
 /** Code de-clutter: Construct scan_field_t to write out a value
  *
  * \param arm11                Target state variable.
@@ -87,7 +115,7 @@ void arm11_add_IR(arm11_common_t * arm11, u8 instr, enum tap_state state)
 
     arm11_setup_field(arm11, 5, &instr, NULL, &field);
 
-    jtag_add_ir_scan_vc(1, &field, state == -1 ? TAP_PI : state);
+    arm11_add_ir_scan_vc(1, &field, state == -1 ? TAP_PI : state);
 }
 
 /** Verify shifted out data from Scan Chain Register (SCREG)
@@ -146,7 +174,7 @@ void arm11_add_debug_SCAN_N(arm11_common_t * arm11, u8 chain, enum tap_state sta
 
     field.in_handler = arm11_in_handler_SCAN_N;
 
-    jtag_add_dr_scan_vc(1, &field, state == -1 ? TAP_PD : state);
+    arm11_add_dr_scan_vc(1, &field, state == -1 ? TAP_PD : state);
 }
 
 /** Write an instruction into the ITR register
@@ -175,7 +203,7 @@ void arm11_add_debug_INST(arm11_common_t * arm11, u32 inst, u8 * flag, enum tap_
     arm11_setup_field(arm11, 32,    &inst,     NULL, itr + 0);
     arm11_setup_field(arm11, 1,            NULL,       flag, itr + 1);
 
-    jtag_add_dr_scan_vc(asizeof(itr), itr, state == -1 ? TAP_RTI : state);
+    arm11_add_dr_scan_vc(asizeof(itr), itr, state == -1 ? TAP_RTI : state);
 }
 
 /** Read the Debug Status and Control Register (DSCR)
@@ -198,7 +226,7 @@ u32 arm11_read_DSCR(arm11_common_t * arm11)
 
     arm11_setup_field(arm11, 32, NULL, &dscr, &chain1_field);
 
-    jtag_add_dr_scan_vc(1, &chain1_field, TAP_PD);
+    arm11_add_dr_scan_vc(1, &chain1_field, TAP_PD);
 
     jtag_execute_queue();
 
@@ -229,7 +257,7 @@ void arm11_write_DSCR(arm11_common_t * arm11, u32 dscr)
 
     arm11_setup_field(arm11, 32, &dscr, NULL, &chain1_field);
 
-    jtag_add_dr_scan_vc(1, &chain1_field, TAP_PD);
+    arm11_add_dr_scan_vc(1, &chain1_field, TAP_PD);
 
     jtag_execute_queue();
 
@@ -385,7 +413,7 @@ void arm11_run_instr_data_to_core(arm11_common_t * arm11, u32 opcode, u32 * data
        {
            Data            = *data;
 
-           jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_RTI);
+           arm11_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_RTI);
            jtag_execute_queue();
 
            JTAG_DEBUG("DTR  Ready %d  nRetry %d", Ready, nRetry);
@@ -401,16 +429,106 @@ void arm11_run_instr_data_to_core(arm11_common_t * arm11, u32 opcode, u32 * data
     {
        Data        = 0;
 
-       jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD);
+       arm11_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD);
        jtag_execute_queue();
 
        JTAG_DEBUG("DTR  Data %08x  Ready %d  nRetry %d", Data, Ready, nRetry);
     }
     while (!Ready);
+}
+
+/** JTAG path for arm11_run_instr_data_to_core_noack
+ *
+ *  The repeated TAP_RTI's do not cause a repeated execution
+ *  if passed without leaving the state.
+ *
+ *  Since this is more than 7 bits (adjustable via adding more
+ *  TAP_RTI's) it produces an artificial delay in the lower
+ *  layer (FT2232) that is long enough to finish execution on
+ *  the core but still shorter than any manually inducible delays.
+ *
+ */
+enum tap_state arm11_MOVE_PD_RTI_PD_with_delay[] =
+{
+    TAP_E2D, TAP_UD, TAP_RTI, TAP_RTI, TAP_RTI, TAP_SDS, TAP_CD, TAP_SD
+};
 
 
+
+/** Execute one instruction via ITR repeatedly while
+ *  passing data to the core via DTR on each execution.
+ *
+ *  No Ready check during transmission.
+ *
+ *  The executed instruction \em must read data from DTR.
+ *
+ * \pre arm11_run_instr_data_prepare() /  arm11_run_instr_data_finish() block
+ *
+ * \param arm11                Target state variable.
+ * \param opcode       ARM opcode
+ * \param data         Pointer to the data words to be passed to the core
+ * \param count                Number of data words and instruction repetitions
+ *
+ */
+void arm11_run_instr_data_to_core_noack(arm11_common_t * arm11, u32 opcode, u32 * data, size_t count)
+{
+    arm11_add_IR(arm11, ARM11_ITRSEL, -1);
+
+    arm11_add_debug_INST(arm11, opcode, NULL, TAP_PD);
+
+    arm11_add_IR(arm11, ARM11_EXTEST, -1);
+
+    scan_field_t       chain5_fields[3];
+
+    arm11_setup_field(arm11, 32,    NULL/*&Data*/,  NULL,      chain5_fields + 0);
+    arm11_setup_field(arm11,  1,    NULL,   NULL /*&Ready*/,   chain5_fields + 1);
+    arm11_setup_field(arm11,  1,    NULL,   NULL,      chain5_fields + 2);
+
+    u8                 Readies[count + 1];
+    u8 *               ReadyPos            = Readies;
+
+    while (count--)
+    {
+       chain5_fields[0].out_value      = (void *)(data++);
+       chain5_fields[1].in_value       = ReadyPos++;
+
+       if (count)
+       {
+           jtag_add_dr_scan(asizeof(chain5_fields), chain5_fields, TAP_PD);
+           jtag_add_pathmove(asizeof(arm11_MOVE_PD_RTI_PD_with_delay),
+               arm11_MOVE_PD_RTI_PD_with_delay); 
+       }
+       else
+       {
+           jtag_add_dr_scan(asizeof(chain5_fields), chain5_fields, TAP_RTI);
+       }
+    }
+
+    arm11_add_IR(arm11, ARM11_INTEST, -1);
+
+    chain5_fields[0].out_value = 0;
+    chain5_fields[1].in_value   = ReadyPos++;
+
+    arm11_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD);
+
+    jtag_execute_queue();
+
+    size_t error_count = 0;
+
+    {size_t i;
+    for (i = 0; i < asizeof(Readies); i++)
+    {
+       if (Readies[i] != 1)
+       {
+           error_count++;
+       }
+    }}
+
+    if (error_count)
+       ERROR("Transfer errors %d", error_count);
 }
 
+
 /** Execute an instruction via ITR while handing data into the core via DTR.
  *
  *  The executed instruction \em must read data from DTR.
@@ -463,7 +581,7 @@ void arm11_run_instr_data_from_core(arm11_common_t * arm11, u32 opcode, u32 * da
     {
        do
        {
-           jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, count ? TAP_RTI : TAP_PD);
+           arm11_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, count ? TAP_RTI : TAP_PD);
            jtag_execute_queue();
 
            JTAG_DEBUG("DTR  Data %08x  Ready %d  nRetry %d", Data, Ready, nRetry);
@@ -514,7 +632,15 @@ void arm11_run_instr_data_to_core_via_r0(arm11_common_t * arm11, u32 opcode, u32
     arm11_run_instr_no_data1(arm11, opcode);
 }
 
-
+/** Apply reads and writes to scan chain 7
+ *
+ * \see arm11_sc7_action_t
+ *
+ * \param arm11                Target state variable.
+ * \param actions      A list of read and/or write instructions
+ * \param count                Number of instructions in the list.
+ *
+ */
 void arm11_sc7_run(arm11_common_t * arm11, arm11_sc7_action_t * actions, size_t count)
 {
     arm11_add_debug_SCAN_N(arm11, 0x07, -1);
@@ -554,7 +680,7 @@ void arm11_sc7_run(arm11_common_t * arm11, arm11_sc7_action_t * actions, size_t
        {
            JTAG_DEBUG("SC7 <= Address %02x  Data %08x    nRW %d", AddressOut, DataOut, nRW);
 
-           jtag_add_dr_scan_vc(asizeof(chain7_fields), chain7_fields, TAP_PD);
+           arm11_add_dr_scan_vc(asizeof(chain7_fields), chain7_fields, TAP_PD);
            jtag_execute_queue();
 
            JTAG_DEBUG("SC7 => Address %02x  Data %08x  Ready %d", AddressIn, DataIn, Ready);
@@ -589,23 +715,73 @@ void arm11_sc7_run(arm11_common_t * arm11, arm11_sc7_action_t * actions, size_t
     }}
 }
 
-void arm11_sc7_clear_bw(arm11_common_t * arm11)
+/** Clear VCR and all breakpoints and watchpoints via scan chain 7
+ *
+ * \param arm11                Target state variable.
+ *
+ */
+void arm11_sc7_clear_vbw(arm11_common_t * arm11)
 {
-    size_t actions = arm11->brp + arm11->wrp;
-
-    arm11_sc7_action_t         clear_bw[actions];
+    arm11_sc7_action_t         clear_bw[arm11->brp + arm11->wrp + 1];
+    arm11_sc7_action_t *       pos = clear_bw;
 
     {size_t i;
-    for (i = 0; i < actions; i++)
+    for (i = 0; i < asizeof(clear_bw); i++)
     {
        clear_bw[i].write       = true;
        clear_bw[i].value       = 0;
-       clear_bw[i].address     =
-           i < arm11->brp ?
-               ARM11_SC7_BCR0 + i :
-               ARM11_SC7_WCR0 + i - arm11->brp;
     }}
 
-    arm11_sc7_run(arm11, clear_bw, actions);
+    {size_t i;
+    for (i = 0; i < arm11->brp; i++)
+       (pos++)->address = ARM11_SC7_BCR0 + i;
+    }
+
+    {size_t i;
+    for (i = 0; i < arm11->wrp; i++)
+       (pos++)->address = ARM11_SC7_WCR0 + i;
+    }
+
+    (pos++)->address = ARM11_SC7_VCR;
+}
+
+/** Write VCR register
+ *
+ * \param arm11                Target state variable.
+ * \param value                Value to be written
+ */
+void arm11_sc7_set_vcr(arm11_common_t * arm11, u32 value)
+{
+    arm11_sc7_action_t         set_vcr;
+
+    set_vcr.write              = 0;
+    set_vcr.address            = ARM11_SC7_VCR;
+    set_vcr.value              = value;
+
+
+    arm11_sc7_run(arm11, &set_vcr, 1);
+}
+
+
+
+/** Read word from address
+ *
+ * \param arm11                Target state variable.
+ * \param address      Memory address to be read
+ * \param result       Pointer where to store result
+ *
+ */
+void arm11_read_memory_word(arm11_common_t * arm11, u32 address, u32 * result)
+{
+    arm11_run_instr_data_prepare(arm11);
+
+    /* MRC p14,0,r0,c0,c5,0 (r0 = address) */
+    arm11_run_instr_data_to_core1(arm11, 0xee100e15, address);
+
+    /* LDC p14,c5,[R0],#4 (DTR = [r0]) */
+    arm11_run_instr_data_from_core(arm11, 0xecb05e01, result, 1);
+
+    arm11_run_instr_data_finish(arm11);
 }
 
+
index 27df12f..61fac56 100644 (file)
@@ -88,6 +88,7 @@ extern target_type_t arm926ejs_target;
 extern target_type_t feroceon_target;
 extern target_type_t xscale_target;
 extern target_type_t cortexm3_target;
+extern target_type_t arm11_target;
 
 target_type_t *target_types[] =
 {
@@ -100,6 +101,7 @@ target_type_t *target_types[] =
        &feroceon_target,
        &xscale_target,
        &cortexm3_target,
+       &arm11_target,
        NULL,
 };