Magnus Lundin <lundin@mlu.mine.nu>, Oyvind Harboe <oyvind.harboe@zylin.com>, David...
[openocd.git] / src / target / cortex_m3.c
index 9f4ef5232fb4543e1e98f27ab1618f9cefd163f8..8cb1bd4e7a69c5dd09527500cc48e4fcb44436fe 100644 (file)
@@ -24,7 +24,7 @@
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  *                                                                         *
  *                                                                         *
- *   Cortex-M3(tm) TRM, ARM DDI 0337C                                      *
+ *   Cortex-M3(tm) TRM, ARM DDI 0337E (r1p1) and 0337G (r2p0)              *
  *                                                                         *
  ***************************************************************************/
 #ifdef HAVE_CONFIG_H
@@ -34,6 +34,7 @@
 #include "cortex_m3.h"
 #include "target_request.h"
 #include "target_type.h"
+#include "arm_disassembler.h"
 
 
 /* cli handling */
@@ -109,11 +110,11 @@ int cortexm3_dap_read_coreregister_u32(swjdp_common_t *swjdp, uint32_t *value, i
 
        /* mem_ap_write_u32(swjdp, DCB_DCRSR, regnum); */
        dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0);
-       dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum );
+       dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum);
 
        /* mem_ap_read_u32(swjdp, DCB_DCRDR, value); */
        dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0);
-       dap_ap_read_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value );
+       dap_ap_read_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value);
 
        mem_ap_write_u32(swjdp, DCB_DCRDR, dcrdr);
        retval = swjdp_transaction_endcheck(swjdp);
@@ -134,11 +135,11 @@ int cortexm3_dap_write_coreregister_u32(swjdp_common_t *swjdp, uint32_t value, i
 
        /* mem_ap_write_u32(swjdp, DCB_DCRDR, core_regs[i]); */
        dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0);
-       dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value );
+       dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value);
 
-       /* mem_ap_write_u32(swjdp, DCB_DCRSR, i | DCRSR_WnR     ); */
+       /* mem_ap_write_u32(swjdp, DCB_DCRSR, i | DCRSR_WnR); */
        dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0);
-       dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum | DCRSR_WnR );
+       dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum | DCRSR_WnR);
 
        mem_ap_write_u32(swjdp, DCB_DCRDR, dcrdr);
        retval = swjdp_transaction_endcheck(swjdp);
@@ -204,7 +205,7 @@ int cortex_m3_single_step_core(target_t *target)
        return ERROR_OK;
 }
 
-int cortex_m3_exec_opcode(target_t *target,uint32_t opcode, int len /* MODE, r0_invalue, &r0_outvalue */ )
+int cortex_m3_exec_opcode(target_t *target,uint32_t opcode, int len /* MODE, r0_invalue, &r0_outvalue */)
 {
        /* get pointers to arch-specific information */
        armv7m_common_t *armv7m = target->arch_info;
@@ -394,7 +395,7 @@ int cortex_m3_debug_entry(target_t *target)
 
        /* Examine target state and mode */
        /* First load register acessible through core debug port*/
-       for (i = 0; i < ARMV7M_PRIMASK; i++)
+       for (i = 0; i < ARMV7NUMCOREREGS; i++)
        {
                if (!armv7m->core_cache->reg_list[i].valid)
                        armv7m->read_core_reg(target, i);
@@ -417,22 +418,19 @@ int cortex_m3_debug_entry(target_t *target)
                cortex_m3_store_core_reg_u32(target, ARMV7M_REGISTER_CORE_GP, 16, xPSR &~ 0xff);
        }
 
-       /* Now we can load SP core registers */
-       for (i = ARMV7M_PRIMASK; i < ARMV7NUMCOREREGS; i++)
-       {
-               if (!armv7m->core_cache->reg_list[i].valid)
-                       armv7m->read_core_reg(target, i);
-       }
-
        /* Are we in an exception handler */
        if (xPSR & 0x1FF)
        {
                armv7m->core_mode = ARMV7M_MODE_HANDLER;
                armv7m->exception_number = (xPSR & 0x1FF);
        }
-       else
+       else if (armv7m->has_spec20)
        {
-               armv7m->core_mode = buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 1);
+               /* NOTE:  CONTROL is bits 31:24 of SPEC20 register, holding
+                * a two-bit field.  Unavailable before r2p0...
+                */
+               armv7m->core_mode = buf_get_u32(
+                       armv7m->core_cache->reg_list[ARMV7M_SPEC20].value, 24, 2);
                armv7m->exception_number = 0;
        }
 
@@ -444,7 +442,7 @@ int cortex_m3_debug_entry(target_t *target)
        LOG_DEBUG("entered debug state in core mode: %s at PC 0x%" PRIx32 ", target->state: %s",
                armv7m_mode_strings[armv7m->core_mode],
                *(uint32_t*)(armv7m->core_cache->reg_list[15].value),
-               Jim_Nvp_value2name_simple( nvp_target_state, target->state )->name);
+               target_state_name(target));
 
        if (armv7m->post_debug_entry)
                armv7m->post_debug_entry(target);
@@ -512,16 +510,19 @@ int cortex_m3_poll(target_t *target)
                }
        }
 
-       /*
-       if (cortex_m3->dcb_dhcsr & S_SLEEP)
-               target->state = TARGET_SLEEP;
-       */
+       /* REVISIT when S_SLEEP is set, it's in a Sleep or DeepSleep state.
+        * How best to model low power modes?
+        */
 
-#if 0
-       /* Read Debug Fault Status Register, added to figure out the lockup when running flashtest.script  */
-       mem_ap_read_atomic_u32(swjdp, NVIC_DFSR, &cortex_m3->nvic_dfsr);
-       LOG_DEBUG("dcb_dhcsr 0x%x, nvic_dfsr 0x%x, target->state: %s", cortex_m3->dcb_dhcsr, cortex_m3->nvic_dfsr, Jim_Nvp_value2name_simple( nvp_target_state, target->state )->name );
-#endif
+       if (target->state == TARGET_UNKNOWN)
+       {
+               /* check if processor is retiring instructions */
+               if (cortex_m3->dcb_dhcsr & S_RETIRE_ST)
+               {
+                       target->state = TARGET_RUNNING;
+                       return ERROR_OK;
+               }
+       }
 
        return ERROR_OK;
 }
@@ -529,7 +530,7 @@ int cortex_m3_poll(target_t *target)
 int cortex_m3_halt(target_t *target)
 {
        LOG_DEBUG("target->state: %s",
-               Jim_Nvp_value2name_simple(nvp_target_state, target->state )->name);
+               target_state_name(target));
 
        if (target->state == TARGET_HALTED)
        {
@@ -632,16 +633,26 @@ int cortex_m3_resume(struct target_s *target, int current, uint32_t address, int
        if (debug_execution)
        {
                /* Disable interrupts */
-               /* We disable interrupts in the PRIMASK register instead of masking with C_MASKINTS,
+               /* We disable interrupts in the PRIMASK register instead
+                * of masking with C_MASKINTS,
                 * This is probably the same issue as Cortex-M3 Errata  377493:
-                * C_MASKINTS in parallel with disabled interrupts can cause local faults to not be taken. */
-               buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_PRIMASK].value, 0, 32, 1);
-               armv7m->core_cache->reg_list[ARMV7M_PRIMASK].dirty = 1;
-               armv7m->core_cache->reg_list[ARMV7M_PRIMASK].valid = 1;
+                * C_MASKINTS in parallel with disabled interrupts can cause
+                * local faults to not be taken.  (FIXED in r1p0 and later.)
+                *
+                * NOTE:  PRIMASK is bits 7:0 of SPEC20 register, holding a
+                * one bit field.  Available this way for r2p0 and later...
+                */
+               if (armv7m->has_spec20) {
+                       buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_SPEC20]
+                                       .value, 0, 1, 1);
+                       armv7m->core_cache->reg_list[ARMV7M_SPEC20].dirty = 1;
+                       armv7m->core_cache->reg_list[ARMV7M_SPEC20].valid = 1;
+               }
 
                /* Make sure we are in Thumb mode */
                buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32,
-                       buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32) | (1 << 24));
+                       buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32)
+                       | (1 << 24));
                armv7m->core_cache->reg_list[ARMV7M_xPSR].dirty = 1;
                armv7m->core_cache->reg_list[ARMV7M_xPSR].valid = 1;
        }
@@ -664,7 +675,9 @@ int cortex_m3_resume(struct target_s *target, int current, uint32_t address, int
                /* Single step past breakpoint at current address */
                if ((breakpoint = breakpoint_find(target, resume_pc)))
                {
-                       LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address);
+                       LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 " (ID: %d)", 
+                                         breakpoint->address,
+                                         breakpoint->unique_id );
                        cortex_m3_unset_breakpoint(target, breakpoint);
                        cortex_m3_single_step_core(target);
                        cortex_m3_set_breakpoint(target, breakpoint);
@@ -751,7 +764,7 @@ int cortex_m3_assert_reset(target_t *target)
        int assert_srst = 1;
 
        LOG_DEBUG("target->state: %s",
-               Jim_Nvp_value2name_simple( nvp_target_state, target->state )->name );
+               target_state_name(target));
 
        enum reset_types jtag_reset_config = jtag_get_reset_config();
        if (!(jtag_reset_config & RESET_HAS_SRST))
@@ -765,7 +778,7 @@ int cortex_m3_assert_reset(target_t *target)
        if (!(cortex_m3->dcb_dhcsr & C_DEBUGEN))
                mem_ap_write_u32(swjdp, DCB_DHCSR, DBGKEY | C_DEBUGEN);
 
-       mem_ap_write_u32(swjdp, DCB_DCRDR, 0 );
+       mem_ap_write_u32(swjdp, DCB_DCRDR, 0);
 
        if (!target->reset_halt)
        {
@@ -862,7 +875,7 @@ int cortex_m3_assert_reset(target_t *target)
 int cortex_m3_deassert_reset(target_t *target)
 {
        LOG_DEBUG("target->state: %s",
-               Jim_Nvp_value2name_simple(nvp_target_state, target->state )->name);
+               target_state_name(target));
 
        /* deassert reset lines */
        jtag_add_reset(0, 0);
@@ -897,7 +910,7 @@ int cortex_m3_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
 
        if (breakpoint->set)
        {
-               LOG_WARNING("breakpoint already set");
+               LOG_WARNING("breakpoint (BPID: %d) already set", breakpoint->unique_id);
                return ERROR_OK;
        }
 
@@ -943,6 +956,13 @@ int cortex_m3_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
                breakpoint->set = 0x11; /* Any nice value but 0 */
        }
 
+       LOG_DEBUG("BPID: %d, Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)", 
+                         breakpoint->unique_id,
+                         (int)(breakpoint->type),
+                         breakpoint->address,
+                         breakpoint->length,
+                         breakpoint->set);
+
        return ERROR_OK;
 }
 
@@ -960,6 +980,13 @@ int cortex_m3_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint
                return ERROR_OK;
        }
 
+       LOG_DEBUG("BPID: %d, Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)", 
+                         breakpoint->unique_id,
+                         (int)(breakpoint->type),
+                         breakpoint->address,
+                         breakpoint->length,
+                         breakpoint->set);
+
        if (breakpoint->type == BKPT_HARD)
        {
                int fp_num = breakpoint->set - 1;
@@ -1085,7 +1112,7 @@ int cortex_m3_set_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
 
        if (watchpoint->set)
        {
-               LOG_WARNING("watchpoint already set");
+               LOG_WARNING("watchpoint (%d) already set", watchpoint->unique_id );
                return ERROR_OK;
        }
 
@@ -1118,10 +1145,13 @@ int cortex_m3_set_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
        }
        else
        {
-               LOG_WARNING("Cannot watch data values");  /* Move this test to add_watchpoint */
+               /* Move this test to add_watchpoint */
+               LOG_WARNING("Cannot watch data values (id: %d)",
+                                 watchpoint->unique_id );
                return ERROR_OK;
        }
-
+       LOG_DEBUG("Watchpoint (ID: %d) address: 0x%08" PRIx32 " set=%d ", 
+                         watchpoint->unique_id, watchpoint->address, watchpoint->set );
        return ERROR_OK;
 
 }
@@ -1136,10 +1166,13 @@ int cortex_m3_unset_watchpoint(struct target_s *target, watchpoint_t *watchpoint
 
        if (!watchpoint->set)
        {
-               LOG_WARNING("watchpoint not set");
+               LOG_WARNING("watchpoint (wpid: %d) not set", watchpoint->unique_id );
                return ERROR_OK;
        }
 
+       LOG_DEBUG("Watchpoint (ID: %d) address: 0x%08" PRIx32 " set=%d ", 
+                         watchpoint->unique_id, watchpoint->address,watchpoint->set );
+
        dwt_num = watchpoint->set - 1;
 
        if ((dwt_num < 0) || (dwt_num >= cortex_m3->dwt_num_comp))
@@ -1179,6 +1212,7 @@ int cortex_m3_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
        }
 
        cortex_m3->dwt_comp_available--;
+       LOG_DEBUG("dwt_comp_available: %d", cortex_m3->dwt_comp_available);
 
        return ERROR_OK;
 }
@@ -1201,6 +1235,7 @@ int cortex_m3_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoin
        }
 
        cortex_m3->dwt_comp_available++;
+       LOG_DEBUG("dwt_comp_available: %d", cortex_m3->dwt_comp_available);
 
        return ERROR_OK;
 }
@@ -1439,8 +1474,14 @@ int cortex_m3_examine(struct target_s *target)
                if ((retval = target_read_u32(target, CPUID, &cpuid)) != ERROR_OK)
                        return retval;
 
-               if (((cpuid >> 4) & 0xc3f) == 0xc23)
+               if (((cpuid >> 4) & 0xc3f) == 0xc23) {
                        LOG_DEBUG("CORTEX-M3 processor detected");
+                       if (((cpuid >> 20) & 0xf) >= 2) {
+                               armv7m->has_spec20 = true;
+                               LOG_DEBUG("r2p0 or later detected");
+                       }
+               } else
+                       LOG_WARNING("not a CORTEX-M3 processor?");
                LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid);
 
                target_read_u32(target, NVIC_ICTR, &ictr);
@@ -1491,7 +1532,7 @@ int cortex_m3_dcc_read(swjdp_common_t *swjdp, uint8_t *value, uint8_t *ctrl)
 {
        uint16_t dcrdr;
 
-       mem_ap_read_buf_u16( swjdp, (uint8_t*)&dcrdr, 1, DCB_DCRDR);
+       mem_ap_read_buf_u16(swjdp, (uint8_t*)&dcrdr, 1, DCB_DCRDR);
        *ctrl = (uint8_t)dcrdr;
        *value = (uint8_t)(dcrdr >> 8);
 
@@ -1502,7 +1543,7 @@ int cortex_m3_dcc_read(swjdp_common_t *swjdp, uint8_t *value, uint8_t *ctrl)
        if (dcrdr & (1 << 0))
        {
                dcrdr = 0;
-               mem_ap_write_buf_u16( swjdp, (uint8_t*)&dcrdr, 1, DCB_DCRDR);
+               mem_ap_write_buf_u16(swjdp, (uint8_t*)&dcrdr, 1, DCB_DCRDR);
        }
 
        return ERROR_OK;
@@ -1619,6 +1660,47 @@ int cortex_m3_target_create(struct target_s *target, Jim_Interp *interp)
        return ERROR_OK;
 }
 
+/*
+ * REVISIT Thumb2 disassembly should work for all ARMv7 cores, as well
+ * as at least ARM-1156T2.  The interesting thing about Cortex-M is
+ * that *only* Thumb2 disassembly matters.  There are also some small
+ * additions to Thumb2 that are specific to ARMv7-M.
+ */
+static int
+handle_cortex_m3_disassemble_command(struct command_context_s *cmd_ctx,
+               char *cmd, char **args, int argc)
+{
+       int retval = ERROR_OK;
+       target_t *target = get_current_target(cmd_ctx);
+       uint32_t address;
+       unsigned long count;
+       arm_instruction_t cur_instruction;
+
+       if (argc != 2) {
+               command_print(cmd_ctx,
+                       "usage: cortex_m3 disassemble <address> <count>");
+               return ERROR_OK;
+       }
+
+       errno = 0;
+       address = strtoul(args[0], NULL, 0);
+       if (errno)
+               return ERROR_FAIL;
+       count = strtoul(args[1], NULL, 0);
+       if (errno)
+               return ERROR_FAIL;
+
+       while (count--) {
+               retval = thumb2_opcode(target, address, &cur_instruction);
+               if (retval != ERROR_OK)
+                       return retval;
+               command_print(cmd_ctx, "%s", cur_instruction.text);
+               address += cur_instruction.instruction_size;
+       }
+
+       return ERROR_OK;
+}
+
 int cortex_m3_register_commands(struct command_context_s *cmd_ctx)
 {
        int retval;
@@ -1626,8 +1708,15 @@ int cortex_m3_register_commands(struct command_context_s *cmd_ctx)
 
        retval = armv7m_register_commands(cmd_ctx);
 
-       cortex_m3_cmd = register_command(cmd_ctx, NULL, "cortex_m3", NULL, COMMAND_ANY, "cortex_m3 specific commands");
-       register_command(cmd_ctx, cortex_m3_cmd, "maskisr", handle_cortex_m3_mask_interrupts_command, COMMAND_EXEC, "mask cortex_m3 interrupts ['on'|'off']");
+       cortex_m3_cmd = register_command(cmd_ctx, NULL, "cortex_m3",
+                       NULL, COMMAND_ANY, "cortex_m3 specific commands");
+
+       register_command(cmd_ctx, cortex_m3_cmd, "disassemble",
+                       handle_cortex_m3_disassemble_command, COMMAND_EXEC,
+                       "disassemble Thumb2 instructions <address> <count>");
+       register_command(cmd_ctx, cortex_m3_cmd, "maskisr",
+                       handle_cortex_m3_mask_interrupts_command, COMMAND_EXEC,
+                       "mask cortex_m3 interrupts ['on'|'off']");
 
        return retval;
 }

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)