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 832ff7390cc56d19cd46e73ecf6902d5d25e8051..acda72237085c0e116332507bbb3f4c412a9daac 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 d02518a2180c8a91f3a7efb41d3ca9d446e32422..905a5d77eda112297191ebf6e508db499e76235f 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 f2263b525d84e7fc306c826fa34a16ef1fd3af21..6e3b1d1536e304f4156fdadf1ab194cad0cc033f 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 d77c9535115ea2a0fae65c736b484d4f0f079c91..eed48bb3e07af993b968a55f63b328b7c0db6b5d 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 27df12fc33f42d34466c6f5ea6ad300ce90f822a..61fac56b23ae336021800bf834eae9e53c1c85b7 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,
 };
 

Linking to existing account procedure

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

SSH host keys fingerprints

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