David Brownell <david-b@pacbell.net>:
[fw/openocd] / src / target / armv7m.c
index b93dda3671f5282c16699a54e99ea9abe5a8f497..74c1ce43ab55fecbeb9b7fcf22081b70121b5322 100644 (file)
@@ -8,7 +8,7 @@
  *   Copyright (C) 2008 by Spencer Oliver                                  *
  *   spen@spen-soft.co.uk                                                  *
  *                                                                         *
- *   Copyright (C) 2007,2008 Øyvind Harboe                                 *
+ *   Copyright (C) 2007,2008 Øyvind Harboe                                 *
  *   oyvind.harboe@zylin.com                                               *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   along with this program; if not, write to the                         *
  *   Free Software Foundation, Inc.,                                       *
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *                                                                         *
+ *     ARMv7-M Architecture, Application Level Reference Manual           *
+ *              ARM DDI 0405C (September 2008)                             *
+ *                                                                         *
  ***************************************************************************/
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -32,6 +36,8 @@
 
 #include "armv7m.h"
 
+#define ARRAY_SIZE(x)  ((int)(sizeof(x)/sizeof((x)[0])))
+
 
 #if 0
 #define _DEBUG_INSTRUCTION_EXECUTION_
@@ -42,20 +48,12 @@ char* armv7m_mode_strings[] =
        "Thread", "Thread (User)", "Handler",
 };
 
-char* armv7m_exception_strings[] =
-{
-       "", "Reset", "NMI", "HardFault", "MemManage", "BusFault", "UsageFault", "RESERVED", "RESERVED", "RESERVED", "RESERVED",
-       "SVCall", "DebugMonitor", "RESERVED", "PendSV", "SysTick"
-};
-
-char* armv7m_core_reg_list[] =
+static char *armv7m_exception_strings[] =
 {
-       /* Registers accessed through core debug */
-       "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12",
-       "sp", "lr", "pc",
-       "xPSR", "msp", "psp",
-       /* Registers accessed through special reg 20 */
-       "primask", "basepri", "faultmask", "control"
+       "", "Reset", "NMI", "HardFault",
+       "MemManage", "BusFault", "UsageFault", "RESERVED",
+       "RESERVED", "RESERVED", "RESERVED", "SVCall",
+       "DebugMonitor", "RESERVED", "PendSV", "SysTick"
 };
 
 uint8_t armv7m_gdb_dummy_fp_value[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -81,37 +79,47 @@ reg_t armv7m_gdb_dummy_cpsr_reg =
 };
 #endif
 
-armv7m_core_reg_t armv7m_core_reg_list_arch_info[] =
-{
-       /*  CORE_GP are accesible using the core debug registers */
-       {0, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-       {1, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-       {2, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-       {3, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-       {4, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-       {5, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-       {6, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-       {7, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-       {8, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-       {9, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-       {10, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-       {11, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-       {12, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-       {13, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-       {14, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-       {15, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
-
-       {16, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL}, /* xPSR */
-       {17, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL}, /* MSP */
-       {18, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL}, /* PSP */
-
-       /*  CORE_SP are accesible using coreregister 20 */
-       {19, ARMV7M_REGISTER_CORE_SP, ARMV7M_MODE_ANY, NULL, NULL}, /* PRIMASK */
-       {20, ARMV7M_REGISTER_CORE_SP, ARMV7M_MODE_ANY, NULL, NULL}, /* BASEPRI */
-       {21, ARMV7M_REGISTER_CORE_SP, ARMV7M_MODE_ANY, NULL, NULL}, /* FAULTMASK */
-       {22, ARMV7M_REGISTER_CORE_SP, ARMV7M_MODE_ANY, NULL, NULL}  /* CONTROL */
+/*
+ * These registers are not memory-mapped.  The ARMv7-M profile includes
+ * memory mapped registers too, such as for the NVIC (interrupt controller)
+ * and SysTick (timer) modules; those can mostly be treated as peripherals.
+ */
+static const struct {
+       unsigned id;
+       char *name;
+} armv7m_regs[] = {
+       { ARMV7M_R0, "r0" },
+       { ARMV7M_R1, "r1" },
+       { ARMV7M_R2, "r2" },
+       { ARMV7M_R3, "r3" },
+
+       { ARMV7M_R4, "r4" },
+       { ARMV7M_R5, "r5" },
+       { ARMV7M_R6, "r6" },
+       { ARMV7M_R7, "r7" },
+
+       { ARMV7M_R8, "r8" },
+       { ARMV7M_R9, "r9" },
+       { ARMV7M_R10, "r10" },
+       { ARMV7M_R11, "r11" },
+
+       { ARMV7M_R12, "r12" },
+       { ARMV7M_R13, "sp" },
+       { ARMV7M_R14, "lr" },
+       { ARMV7M_PC, "pc" },
+
+       { ARMV7M_xPSR, "xPSR" },
+       { ARMV7M_MSP, "msp" },
+       { ARMV7M_PSP, "psp" },
+
+       { ARMV7M_PRIMASK, "primask" },
+       { ARMV7M_BASEPRI, "basepri" },
+       { ARMV7M_FAULTMASK, "faultmask" },
+       { ARMV7M_CONTROL, "control" },
 };
 
+#define ARMV7M_NUM_REGS        ARRAY_SIZE(armv7m_regs)
+
 int armv7m_core_reg_arch_type = -1;
 int armv7m_dummy_core_reg_arch_type = -1;
 
@@ -127,7 +135,7 @@ int armv7m_restore_context(target_t *target)
        if (armv7m->pre_restore_context)
                armv7m->pre_restore_context(target);
 
-       for (i = ARMV7NUMCOREREGS-1; i >= 0; i--)
+       for (i = ARMV7M_NUM_REGS - 1; i >= 0; i--)
        {
                if (armv7m->core_cache->reg_list[i].dirty)
                {
@@ -198,7 +206,7 @@ int armv7m_read_core_reg(struct target_s *target, int num)
        /* get pointers to arch-specific information */
        armv7m_common_t *armv7m = target->arch_info;
 
-       if ((num < 0) || (num >= ARMV7NUMCOREREGS))
+       if ((num < 0) || (num >= ARMV7M_NUM_REGS))
                return ERROR_INVALID_ARGUMENTS;
 
        armv7m_core_reg = armv7m->core_cache->reg_list[num].arch_info;
@@ -219,7 +227,7 @@ int armv7m_write_core_reg(struct target_s *target, int num)
        /* get pointers to arch-specific information */
        armv7m_common_t *armv7m = target->arch_info;
 
-       if ((num < 0) || (num >= ARMV7NUMCOREREGS))
+       if ((num < 0) || (num >= ARMV7M_NUM_REGS))
                return ERROR_INVALID_ARGUMENTS;
 
        reg_value = buf_get_u32(armv7m->core_cache->reg_list[num].value, 0, 32);
@@ -262,6 +270,13 @@ int armv7m_get_gdb_reg_list(target_t *target, reg_t **reg_list[], int *reg_list_
        *reg_list_size = 26;
        *reg_list = malloc(sizeof(reg_t*) * (*reg_list_size));
 
+       /*
+        * GDB register packet format for ARM:
+        *  - the first 16 registers are r0..r15
+        *  - (obsolete) 8 FPA registers
+        *  - (obsolete) FPA status
+        *  - CPSR
+        */
        for (i = 0; i < 16; i++)
        {
                (*reg_list)[i] = &armv7m->core_cache->reg_list[i];
@@ -331,7 +346,7 @@ int armv7m_run_algorithm(struct target_s *target, int num_mem_params, mem_param_
        enum armv7m_mode core_mode = armv7m->core_mode;
        int retval = ERROR_OK;
        int i;
-       uint32_t context[ARMV7NUMCOREREGS];
+       uint32_t context[ARMV7M_NUM_REGS];
 
        if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC)
        {
@@ -347,7 +362,7 @@ int armv7m_run_algorithm(struct target_s *target, int num_mem_params, mem_param_
 
        /* refresh core register cache */
        /* Not needed if core register cache is always consistent with target process state */
-       for (i = 0; i < ARMV7NUMCOREREGS; i++)
+       for (i = 0; i < ARMV7M_NUM_REGS; i++)
        {
                if (!armv7m->core_cache->reg_list[i].valid)
                        armv7m->read_core_reg(target, i);
@@ -384,7 +399,8 @@ int armv7m_run_algorithm(struct target_s *target, int num_mem_params, mem_param_
        if (armv7m_algorithm_info->core_mode != ARMV7M_MODE_ANY)
        {
                LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
-               buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 1, armv7m_algorithm_info->core_mode);
+               buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_CONTROL].value,
+                               0, 1, armv7m_algorithm_info->core_mode);
                armv7m->core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
                armv7m->core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
        }
@@ -438,14 +454,16 @@ int armv7m_run_algorithm(struct target_s *target, int num_mem_params, mem_param_
                }
        }
 
-       for (i = ARMV7NUMCOREREGS-1; i >= 0; i--)
+       for (i = ARMV7M_NUM_REGS; i >= 0; i--)
        {
                uint32_t regvalue;
                regvalue = buf_get_u32(armv7m->core_cache->reg_list[i].value, 0, 32);
                if (regvalue != context[i])
                {
-                       LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32 "", armv7m->core_cache->reg_list[i].name, context[i]);
-                       buf_set_u32(armv7m->core_cache->reg_list[i].value, 0, 32, context[i]);
+                       LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32,
+                               armv7m->core_cache->reg_list[i].name, context[i]);
+                       buf_set_u32(armv7m->core_cache->reg_list[i].value,
+                                       0, 32, context[i]);
                        armv7m->core_cache->reg_list[i].valid = 1;
                        armv7m->core_cache->reg_list[i].dirty = 1;
                }
@@ -461,12 +479,13 @@ int armv7m_arch_state(struct target_s *target)
        /* get pointers to arch-specific information */
        armv7m_common_t *armv7m = target->arch_info;
 
-       LOG_USER("target halted due to %s, current mode: %s %s\nxPSR: 0x%8.8" PRIx32 " pc: 0x%8.8" PRIx32 "",
+       LOG_USER("target halted due to %s, current mode: %s %s\n"
+               "xPSR: 0x%8.8" PRIx32 " pc: 0x%8.8" PRIx32,
                 Jim_Nvp_value2name_simple(nvp_target_debug_reason,target->debug_reason)->name,
                armv7m_mode_strings[armv7m->core_mode],
                armv7m_exception_string(armv7m->exception_number),
                buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32),
-               buf_get_u32(armv7m->core_cache->reg_list[15].value, 0, 32));
+               buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_PC].value, 0, 32));
 
        return ERROR_OK;
 }
@@ -476,11 +495,11 @@ reg_cache_t *armv7m_build_reg_cache(target_t *target)
        /* get pointers to arch-specific information */
        armv7m_common_t *armv7m = target->arch_info;
 
-       int num_regs = ARMV7NUMCOREREGS;
+       int num_regs = ARMV7M_NUM_REGS;
        reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
        reg_cache_t *cache = malloc(sizeof(reg_cache_t));
-       reg_t *reg_list = malloc(sizeof(reg_t) * num_regs);
-       armv7m_core_reg_t *arch_info = malloc(sizeof(armv7m_core_reg_t) * num_regs);
+       reg_t *reg_list = calloc(num_regs, sizeof(reg_t));
+       armv7m_core_reg_t *arch_info = calloc(num_regs, sizeof(armv7m_core_reg_t));
        int i;
 
        if (armv7m_core_reg_arch_type == -1)
@@ -504,10 +523,10 @@ reg_cache_t *armv7m_build_reg_cache(target_t *target)
 
        for (i = 0; i < num_regs; i++)
        {
-               arch_info[i] = armv7m_core_reg_list_arch_info[i];
+               arch_info[i].num = armv7m_regs[i].id;
                arch_info[i].target = target;
                arch_info[i].armv7m_common = armv7m;
-               reg_list[i].name = armv7m_core_reg_list[i];
+               reg_list[i].name = armv7m_regs[i].name;
                reg_list[i].size = 32;
                reg_list[i].value = calloc(1, 4);
                reg_list[i].dirty = 0;
@@ -539,20 +558,6 @@ int armv7m_init_arch_info(target_t *target, armv7m_common_t *armv7m)
        return ERROR_OK;
 }
 
-int armv7m_register_commands(struct command_context_s *cmd_ctx)
-{
-       command_t *arm_adi_v5_dap_cmd;
-
-       arm_adi_v5_dap_cmd = register_command(cmd_ctx, NULL, "dap", NULL, COMMAND_ANY, "cortex dap specific commands");         
-       register_command(cmd_ctx, arm_adi_v5_dap_cmd, "info", handle_dap_info_command, COMMAND_EXEC, "Displays dap info for ap [num], default currently selected AP");
-       register_command(cmd_ctx, arm_adi_v5_dap_cmd, "apsel", handle_dap_apsel_command, COMMAND_EXEC, "Select a different AP [num] (default 0)");
-       register_command(cmd_ctx, arm_adi_v5_dap_cmd, "apid", handle_dap_apid_command, COMMAND_EXEC, "Displays id reg from AP [num], default currently selected AP");
-       register_command(cmd_ctx, arm_adi_v5_dap_cmd, "baseaddr", handle_dap_baseaddr_command, COMMAND_EXEC, "Displays debug base address from AP [num], default currently selected AP");
-       register_command(cmd_ctx, arm_adi_v5_dap_cmd, "memaccess", handle_dap_memaccess_command, COMMAND_EXEC, "set/get number of extra tck for mem-ap memory bus access [0-255]");
-
-       return ERROR_OK;
-}
-
 int armv7m_checksum_memory(struct target_s *target, uint32_t address, uint32_t count, uint32_t* checksum)
 {
        working_area_t *crc_algorithm;
@@ -696,10 +701,12 @@ int armv7m_blank_check_memory(struct target_s *target, uint32_t address, uint32_
        return ERROR_OK;
 }
 
-/********************************************************************************************************************
-* Return the debug ap baseaddress in hexadecimal, no extra output to simplify script processing
-*********************************************************************************************************************/
-int handle_dap_baseaddr_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+/*
+ * Return the debug ap baseaddress in hexadecimal;
+ * no extra output to simplify script processing
+ */
+static int handle_dap_baseaddr_command(struct command_context_s *cmd_ctx,
+               char *cmd, char **args, int argc)
 {
        target_t *target = get_current_target(cmd_ctx);
        armv7m_common_t *armv7m = target->arch_info;
@@ -710,7 +717,7 @@ int handle_dap_baseaddr_command(struct command_context_s *cmd_ctx, char *cmd, ch
        apsel = swjdp->apsel;
        apselsave = swjdp->apsel;
        if (argc > 0)
-       {       
+       {
                apsel = strtoul(args[0], NULL, 0);
        }
        if (apselsave != apsel)
@@ -731,97 +738,83 @@ int handle_dap_baseaddr_command(struct command_context_s *cmd_ctx, char *cmd, ch
 }
 
 
-/********************************************************************************************************************
-* Return the debug ap id in hexadecimal, no extra output to simplify script processing
-*********************************************************************************************************************/
-extern int handle_dap_apid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+/*
+ * Return the debug ap id in hexadecimal;
+ * no extra output to simplify script processing
+ */
+extern int handle_dap_apid_command(struct command_context_s *cmd_ctx,
+               char *cmd, char **args, int argc)
 {
        target_t *target = get_current_target(cmd_ctx);
        armv7m_common_t *armv7m = target->arch_info;
        swjdp_common_t *swjdp = &armv7m->swjdp_info;
-       uint32_t apsel, apselsave, apid;
-       int retval;
-
-       apsel = swjdp->apsel;
-       apselsave = swjdp->apsel;
-       if (argc > 0)
-       {       
-               apsel = strtoul(args[0], NULL, 0);
-       }
-
-       if (apselsave != apsel)
-       {
-               dap_ap_select(swjdp, apsel);
-       }
-
-       dap_ap_read_reg_u32(swjdp, 0xFC, &apid);
-       retval = swjdp_transaction_endcheck(swjdp);
-       command_print(cmd_ctx, "0x%8.8" PRIx32 "", apid);
-       if (apselsave != apsel)
-       {
-               dap_ap_select(swjdp, apselsave);
-       }
 
-       return retval;
+       return dap_apid_command(cmd_ctx, swjdp, args, argc);
 }
 
-int handle_dap_apsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+static int handle_dap_apsel_command(struct command_context_s *cmd_ctx,
+               char *cmd, char **args, int argc)
 {
        target_t *target = get_current_target(cmd_ctx);
        armv7m_common_t *armv7m = target->arch_info;
        swjdp_common_t *swjdp = &armv7m->swjdp_info;
-       uint32_t apsel, apid;
-       int retval;
 
-       apsel = 0;
-       if (argc > 0)
-       {       
-               apsel = strtoul(args[0], NULL, 0);
-       }
-
-       dap_ap_select(swjdp, apsel);
-       dap_ap_read_reg_u32(swjdp, 0xFC, &apid);
-       retval = swjdp_transaction_endcheck(swjdp);
-       command_print(cmd_ctx, "ap %i selected, identification register 0x%8.8" PRIx32 "", (int)apsel, apid);
-
-       return retval;
+       return dap_apsel_command(cmd_ctx, swjdp, args, argc);
 }
 
-int handle_dap_memaccess_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+static int handle_dap_memaccess_command(struct command_context_s *cmd_ctx,
+               char *cmd, char **args, int argc)
 {
        target_t *target = get_current_target(cmd_ctx);
        armv7m_common_t *armv7m = target->arch_info;
        swjdp_common_t *swjdp = &armv7m->swjdp_info;
-       uint32_t memaccess_tck;
-
-       memaccess_tck = swjdp->memaccess_tck;
-       if (argc > 0)
-       {       
-               memaccess_tck = strtoul(args[0], NULL, 0);
-       }
 
-       swjdp->memaccess_tck = memaccess_tck;
-       command_print(cmd_ctx, "memory bus access delay set to %i tck", (int)(swjdp->memaccess_tck));
-
-       return ERROR_OK;
+       return dap_memaccess_command(cmd_ctx, swjdp, args, argc);
 }
 
-int handle_dap_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+
+static int handle_dap_info_command(struct command_context_s *cmd_ctx,
+               char *cmd, char **args, int argc)
 {
        target_t *target = get_current_target(cmd_ctx);
        armv7m_common_t *armv7m = target->arch_info;
        swjdp_common_t *swjdp = &armv7m->swjdp_info;
-       int retval;
        uint32_t apsel;
 
        apsel =  swjdp->apsel;
        if (argc > 0)
-       {       
                apsel = strtoul(args[0], NULL, 0);
-       }
-       
-       retval = dap_info_command(cmd_ctx, swjdp, apsel);
 
-       return retval;
+       return dap_info_command(cmd_ctx, swjdp, apsel);
 }
 
+int armv7m_register_commands(struct command_context_s *cmd_ctx)
+{
+       command_t *arm_adi_v5_dap_cmd;
+
+       arm_adi_v5_dap_cmd = register_command(cmd_ctx, NULL, "dap",
+                       NULL, COMMAND_ANY,
+                       "cortex dap specific commands");
+
+       register_command(cmd_ctx, arm_adi_v5_dap_cmd, "info",
+                       handle_dap_info_command, COMMAND_EXEC,
+                       "Displays dap info for ap [num],"
+                       "default currently selected AP");
+       register_command(cmd_ctx, arm_adi_v5_dap_cmd, "apsel",
+                       handle_dap_apsel_command, COMMAND_EXEC,
+                       "Select a different AP [num] (default 0)");
+       register_command(cmd_ctx, arm_adi_v5_dap_cmd, "apid",
+                       handle_dap_apid_command, COMMAND_EXEC,
+                       "Displays id reg from AP [num], "
+                       "default currently selected AP");
+       register_command(cmd_ctx, arm_adi_v5_dap_cmd, "baseaddr",
+                       handle_dap_baseaddr_command, COMMAND_EXEC,
+                       "Displays debug base address from AP [num],"
+                       "default currently selected AP");
+       register_command(cmd_ctx, arm_adi_v5_dap_cmd, "memaccess",
+                       handle_dap_memaccess_command, COMMAND_EXEC,
+                       "set/get number of extra tck for mem-ap "
+                       "memory bus access [0-255]");
+
+       return ERROR_OK;
+}