- explicitly disable monitor mode on ARM7/9 targets
[fw/openocd] / src / target / arm7_9_common.c
index b793ba51531a1b359b48bb58edcc178b4487b921..3a7c80a107244f7af29ee650861653a502c2f860 100644 (file)
@@ -54,6 +54,8 @@ int handle_arm7_9_force_hw_bkpts_command(struct command_context_s *cmd_ctx, char
 int handle_arm7_9_dbgrq_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 int handle_arm7_9_fast_memory_access_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 handle_arm7_9_etm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_arm7_9_etb_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 
 int arm7_9_reinit_embeddedice(target_t *target)
 {
@@ -253,7 +255,7 @@ int arm7_9_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
        return ERROR_OK;
 }
 
-int arm7_9_add_breakpoint(struct target_s *target, u32 address, u32 length, enum breakpoint_type type)
+int arm7_9_add_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;
@@ -266,30 +268,31 @@ int arm7_9_add_breakpoint(struct target_s *target, u32 address, u32 length, enum
        
        if (arm7_9->force_hw_bkpts)
        {
-               type = BKPT_HARD;
+               DEBUG("forcing use of hardware breakpoint at address 0x%8.8x", breakpoint->address);
+               breakpoint->type = BKPT_HARD;
        }
        
-       if ((type == BKPT_SOFT) && (arm7_9->sw_bkpts_enabled == 0))
+       if ((breakpoint->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))
+       if ((breakpoint->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))
+       if ((breakpoint->length != 2) && (breakpoint->length != 4))
        {
                INFO("only breakpoints of two (Thumb) or four (ARM) bytes length supported");
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        }
        
+       if (breakpoint->type == BKPT_HARD)
+               arm7_9->wp_available--;
+       
        return ERROR_OK;
 }
 
@@ -406,7 +409,7 @@ int arm7_9_unset_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
        return ERROR_OK;
 }
 
-int arm7_9_add_watchpoint(struct target_s *target, u32 address, u32 length, enum watchpoint_rw rw)
+int arm7_9_add_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;
@@ -422,7 +425,7 @@ int arm7_9_add_watchpoint(struct target_s *target, u32 address, u32 length, enum
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        }
        
-       if ((length != 1) && (length != 2) && (length != 4))
+       if ((watchpoint->length != 1) && (watchpoint->length != 2) && (watchpoint->length != 4))
        {
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        }
@@ -656,6 +659,9 @@ int arm7_9_assert_reset(target_t *target)
        
        if (target->state == TARGET_HALTED || target->state == TARGET_UNKNOWN)
        {
+               /* if the target wasn't running, there might be working areas allocated */
+               target_free_all_working_areas(target);
+               
                /* 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)
@@ -719,9 +725,52 @@ int arm7_9_deassert_reset(target_t *target)
        
        /* deassert reset lines */
        jtag_add_reset(0, 0);
-               
+       
        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];
+       
+       /* we used DBGRQ only if we didn't come out of reset */
+       if (!arm7_9->debug_entry_from_reset && 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
+       {
+               if (arm7_9->debug_entry_from_reset && arm7_9->has_vector_catch)
+               {
+                       /* if we came out of reset, and vector catch is supported, we used
+                        * vector catch to enter debug state
+                        * restore the register in that case
+                        */
+                       embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_VEC_CATCH]);
+               }
+               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_soft_reset_halt(struct target_s *target)
@@ -729,6 +778,7 @@ 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];
+       reg_t *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL];
        int i;
        
        if (target->state == TARGET_RUNNING)
@@ -743,6 +793,26 @@ int arm7_9_soft_reset_halt(struct target_s *target)
        }
        target->state = TARGET_HALTED;
        
+       /* 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 the target is in Thumb state, change to ARM state */
+       if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_ITBIT, 1))
+       {
+               u32 r0_thumb, pc_thumb;
+               DEBUG("target entered debug from Thumb state, changing to ARM");
+               /* Entered debug from Thumb mode */
+               armv4_5->core_state = ARMV4_5_STATE_THUMB;
+               arm7_9->change_to_arm(target, &r0_thumb, &pc_thumb);
+       }
+       
        /* all register content is now invalid */
        armv4_5_invalidate_core_regs(target);
        
@@ -772,6 +842,28 @@ int arm7_9_soft_reset_halt(struct target_s *target)
        return ERROR_OK;
 }
 
+int arm7_9_prepare_reset_halt(target_t *target)
+{
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       arm7_9_common_t *arm7_9 = armv4_5->arch_info;
+       
+       if (arm7_9->has_vector_catch)
+       {
+               /* program vector catch register to catch reset vector */
+               embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_VEC_CATCH], 0x1);
+       }
+       else
+       {
+               /* program watchpoint unit to match on reset vector address */
+               embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0x3);
+               embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0x0);
+               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);
+       }
+       
+       return ERROR_OK;
+}
+
 int arm7_9_halt(target_t *target)
 {
        armv4_5_common_t *armv4_5 = target->arch_info;
@@ -784,17 +876,29 @@ int arm7_9_halt(target_t *target)
        {
                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 ((target->state == TARGET_RESET) && (jtag_reset_config & RESET_SRST_PULLS_TRST) && (jtag_srst))
+       if (target->state == TARGET_RESET) 
        {
-               ERROR("can't request a halt while in reset if nSRST pulls nTRST");
-               return ERROR_TARGET_FAILURE;
+               if ((jtag_reset_config & RESET_SRST_PULLS_TRST) && jtag_srst)
+               {
+                       ERROR("can't request a halt while in reset if nSRST pulls nTRST");
+                       return ERROR_TARGET_FAILURE;
+               }
+               else
+               {
+                       /* we came here in a reset_halt or reset_init sequence
+                        * debug entry was already prepared in arm7_9_prepare_reset_halt()
+                        */
+                       target->debug_reason = DBG_REASON_DBGRQ;
+                       
+                       return ERROR_OK; 
+               }
        }
 
        if (arm7_9->use_dbgrq)
@@ -819,38 +923,6 @@ int arm7_9_halt(target_t *target)
        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;
@@ -866,7 +938,7 @@ int arm7_9_debug_entry(target_t *target)
        reg_t *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL];
 
 #ifdef _DEBUG_ARM7_9_
-       DEBUG("");
+       DEBUG("-");
 #endif
 
        if (arm7_9->pre_debug_entry)
@@ -1016,7 +1088,7 @@ int arm7_9_full_context(target_t *target)
        armv4_5_common_t *armv4_5 = target->arch_info;
        arm7_9_common_t *arm7_9 = armv4_5->arch_info;
 
-       DEBUG("");
+       DEBUG("-");
        
        if (target->state != TARGET_HALTED)
        {
@@ -1099,7 +1171,7 @@ int arm7_9_restore_context(target_t *target)
        int dirty;
        int mode_change;
        
-       DEBUG("");
+       DEBUG("-");
        
        if (target->state != TARGET_HALTED)
        {
@@ -1300,7 +1372,7 @@ int arm7_9_resume(struct target_s *target, int current, u32 address, int handle_
        breakpoint_t *breakpoint = target->breakpoints;
        reg_t *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL];
        
-       DEBUG("");
+       DEBUG("-");
        
        if (target->state != TARGET_HALTED)
        {
@@ -1448,7 +1520,7 @@ int arm7_9_step(struct target_s *target, int current, u32 address, int handle_br
 {
        armv4_5_common_t *armv4_5 = target->arch_info;
        arm7_9_common_t *arm7_9 = armv4_5->arch_info;
-       breakpoint_t *breakpoint = target->breakpoints;
+       breakpoint_t *breakpoint = NULL;
 
        if (target->state != TARGET_HALTED)
        {
@@ -2024,6 +2096,9 @@ 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, "arm7/9 specific commands");
+
+       register_command(cmd_ctx, arm7_9_cmd, "etm", handle_arm7_9_etm_command, COMMAND_CONFIG, NULL);
+       register_command(cmd_ctx, arm7_9_cmd, "etb", handle_arm7_9_etb_command, COMMAND_CONFIG, NULL);
        
        register_command(cmd_ctx, arm7_9_cmd, "write_xpsr", handle_arm7_9_write_xpsr_command, COMMAND_EXEC, "write program status register <value> <not cpsr|spsr>");
        register_command(cmd_ctx, arm7_9_cmd, "write_xpsr_im8", handle_arm7_9_write_xpsr_im8_command, COMMAND_EXEC, "write program status register <8bit immediate> <rotate> <not cpsr|spsr>");
@@ -2351,6 +2426,81 @@ int handle_arm7_9_dcc_downloads_command(struct command_context_s *cmd_ctx, char
        return ERROR_OK;
 }
 
+int handle_arm7_9_etm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target;
+       armv4_5_common_t *armv4_5;
+       arm7_9_common_t *arm7_9;
+       
+       if (argc != 1)
+       {
+               ERROR("incomplete 'arm7_9 etm <target>' command");
+               exit(-1);
+       }
+       
+       target = get_target_by_num(strtoul(args[0], NULL, 0));
+       
+       if (!target)
+       {
+               ERROR("target number '%s' not defined", args[0]);
+               exit(-1);
+       }
+       
+       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+               return ERROR_OK;
+       }
+       
+       arm7_9->has_etm = 1;
+       
+       return ERROR_OK;
+}
+
+int handle_arm7_9_etb_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target;
+       jtag_device_t *jtag_device;
+       armv4_5_common_t *armv4_5;
+       arm7_9_common_t *arm7_9;
+       
+       if (argc != 2)
+       {
+               ERROR("incomplete 'arm7_9 etb <target> <chain_pos>' command");
+               exit(-1);
+       }
+       
+       target = get_target_by_num(strtoul(args[0], NULL, 0));
+       
+       if (!target)
+       {
+               ERROR("target number '%s' not defined", args[0]);
+               exit(-1);
+       }
+       
+       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+               return ERROR_OK;
+       }
+       
+       jtag_device = jtag_get_device(strtoul(args[1], NULL, 0));
+       
+       if (!jtag_device)
+       {
+               ERROR("jtag device number '%s' not defined", args[1]);
+               exit(-1);
+       }
+
+       arm7_9->etb = malloc(sizeof(etb_t));
+       
+       arm7_9->etb->chain_pos = strtoul(args[1], NULL, 0);
+       arm7_9->etb->cur_scan_chain = -1;
+       arm7_9->etb->reg_cache = NULL;
+
+       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;
@@ -2363,10 +2513,17 @@ int arm7_9_init_arch_info(target_t *target, arm7_9_common_t *arm7_9)
        arm7_9->wp1_used = 0;
        arm7_9->force_hw_bkpts = 0;
        arm7_9->use_dbgrq = 0;
+       
        arm7_9->has_etm = 0;
+       arm7_9->etb = NULL;
+       arm7_9->has_single_step = 0;
+       arm7_9->has_monitor_mode = 0;
+       arm7_9->has_vector_catch = 0;
        
        arm7_9->reinit_embeddedice = 0;
        
+       arm7_9->debug_entry_from_reset = 0;
+       
        arm7_9->dcc_working_area = NULL;
        
        arm7_9->fast_memory_access = 0;