From 4da019edeb62154978dfac6a37e738814b2f2724 Mon Sep 17 00:00:00 2001 From: ntfreak Date: Tue, 21 Jul 2009 20:15:11 +0000 Subject: [PATCH] David Brownell : Clean up treatment of registers in ARMv7-M and Cortex-M3. - At the arch level: * Just list registers and names; don't impose core-specific policy about how they are accessed. * Each register has a symbol. * Remove the register mode field (irrelevant to debugger) - At the core/implementation level: * Just map the registers to their relevant access methods; don't require the arch level to say how that should work (cores other than Cortex-M3 could do it differently). * Don't use undefined bits from register 20. * Use register IDs that are part of the ARMv7-M interface. In short, there's now a real distinction between the arch and core layers. git-svn-id: svn://svn.berlios.de/openocd/trunk@2554 b42882b7-edfa-0310-969c-e2dbd0fdcd60 --- src/target/armv7m.c | 125 +++++++++++++++++++++++------------------ src/target/armv7m.h | 28 +++++++-- src/target/cortex_m3.c | 103 ++++++++++++++++++--------------- 3 files changed, 152 insertions(+), 104 deletions(-) diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 5849443018..74c1ce43ab 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -36,6 +36,8 @@ #include "armv7m.h" +#define ARRAY_SIZE(x) ((int)(sizeof(x)/sizeof((x)[0]))) + #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ @@ -46,7 +48,7 @@ char* armv7m_mode_strings[] = "Thread", "Thread (User)", "Handler", }; -char* armv7m_exception_strings[] = +static char *armv7m_exception_strings[] = { "", "Reset", "NMI", "HardFault", "MemManage", "BusFault", "UsageFault", "RESERVED", @@ -54,16 +56,6 @@ char* armv7m_exception_strings[] = "DebugMonitor", "RESERVED", "PendSV", "SysTick" }; -char* armv7m_core_reg_list[] = -{ - /* 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" -}; - uint8_t armv7m_gdb_dummy_fp_value[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; reg_t armv7m_gdb_dummy_fp_reg = @@ -87,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; @@ -133,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) { @@ -204,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; @@ -225,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); @@ -268,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]; @@ -337,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) { @@ -353,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); @@ -390,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; } @@ -444,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; } @@ -467,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; } @@ -482,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) @@ -510,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; diff --git a/src/target/armv7m.h b/src/target/armv7m.h index ec90b7150d..f3a74221ce 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -50,22 +50,43 @@ enum armv7m_regtype ARMV7M_REGISTER_MEMMAP }; -extern char* armv7m_exception_strings[]; - extern char *armv7m_exception_string(int number); /* offsets into armv7m core register cache */ enum { + /* for convenience, the first set of indices match + * the Cortex-M3 DCRSR selectors + */ + ARMV7M_R0, + ARMV7M_R1, + ARMV7M_R2, + ARMV7M_R3, + + ARMV7M_R4, + ARMV7M_R5, + ARMV7M_R6, + ARMV7M_R7, + + ARMV7M_R8, + ARMV7M_R9, + ARMV7M_R10, + ARMV7M_R11, + + ARMV7M_R12, + ARMV7M_R13, + ARMV7M_R14, ARMV7M_PC = 15, + ARMV7M_xPSR = 16, ARMV7M_MSP, ARMV7M_PSP, + + /* this next set of indices is arbitrary */ ARMV7M_PRIMASK, ARMV7M_BASEPRI, ARMV7M_FAULTMASK, ARMV7M_CONTROL, - ARMV7NUMCOREREGS }; #define ARMV7M_COMMON_MAGIC 0x2A452A45 @@ -107,7 +128,6 @@ typedef struct armv7m_core_reg_s { uint32_t num; enum armv7m_regtype type; - enum armv7m_mode mode; target_t *target; armv7m_common_t *armv7m_common; } armv7m_core_reg_t; diff --git a/src/target/cortex_m3.c b/src/target/cortex_m3.c index 94d420468e..8875dddc68 100644 --- a/src/target/cortex_m3.c +++ b/src/target/cortex_m3.c @@ -395,7 +395,9 @@ 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++) + int num_regs = armv7m->core_cache->num_regs; + + for (i = 0; i < num_regs; i++) { if (!armv7m->core_cache->reg_list[i].valid) armv7m->read_core_reg(target, i); @@ -418,13 +420,6 @@ 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) { @@ -1253,8 +1248,12 @@ int cortex_m3_load_core_reg_u32(struct target_s *target, enum armv7m_regtype typ armv7m_common_t *armv7m = target->arch_info; swjdp_common_t *swjdp = &armv7m->swjdp_info; - if ((type == ARMV7M_REGISTER_CORE_GP) && (num <= ARMV7M_PSP)) - { + /* NOTE: we "know" here that the register identifiers used + * in the v7m header match the Cortex-M3 Debug Core Register + * Selector values for R0..R15, xPSR, MSP, and PSP. + */ + switch (num) { + case 0 ... 18: /* read a normal core register */ retval = cortexm3_dap_read_coreregister_u32(swjdp, value, num); @@ -1264,35 +1263,41 @@ int cortex_m3_load_core_reg_u32(struct target_s *target, enum armv7m_regtype typ return ERROR_JTAG_DEVICE_ERROR; } LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "",(int)num,*value); - } - else if (type == ARMV7M_REGISTER_CORE_SP) /* Special purpose core register */ - { - /* read other registers */ + break; + + case ARMV7M_PRIMASK: + case ARMV7M_BASEPRI: + case ARMV7M_FAULTMASK: + case ARMV7M_CONTROL: + /* Cortex-M3 packages these four registers as bitfields + * in one Debug Core register. So say r0 and r2 docs; + * it was removed from r1 docs, but still works. + */ cortexm3_dap_read_coreregister_u32(swjdp, value, 20); switch (num) { - case 19: - *value = buf_get_u32((uint8_t*)value, 0, 8); + case ARMV7M_PRIMASK: + *value = buf_get_u32((uint8_t*)value, 0, 1); break; - case 20: + case ARMV7M_BASEPRI: *value = buf_get_u32((uint8_t*)value, 8, 8); break; - case 21: - *value = buf_get_u32((uint8_t*)value, 16, 8); + case ARMV7M_FAULTMASK: + *value = buf_get_u32((uint8_t*)value, 16, 1); break; - case 22: - *value = buf_get_u32((uint8_t*)value, 24, 8); + case ARMV7M_CONTROL: + *value = buf_get_u32((uint8_t*)value, 24, 2); break; } LOG_DEBUG("load from special reg %i value 0x%" PRIx32 "", (int)num, *value); - } - else - { + break; + + default: return ERROR_INVALID_ARGUMENTS; } @@ -1313,14 +1318,19 @@ int cortex_m3_store_core_reg_u32(struct target_s *target, enum armv7m_regtype ty * in "thumb" mode, or an INVSTATE exception will occur. This is a * hack to deal with the fact that gdb will sometimes "forge" * return addresses, and doesn't set the LSB correctly (i.e., when - * printing expressions containing function calls, it sets LR = 0.) */ - - if (num == 14) + * printing expressions containing function calls, it sets LR = 0.) + * Valid exception return codes have bit 0 set too. + */ + if (num == ARMV7M_R14) value |= 0x01; #endif - if ((type == ARMV7M_REGISTER_CORE_GP) && (num <= ARMV7M_PSP)) - { + /* NOTE: we "know" here that the register identifiers used + * in the v7m header match the Cortex-M3 Debug Core Register + * Selector values for R0..R15, xPSR, MSP, and PSP. + */ + switch (num) { + case 0 ... 18: retval = cortexm3_dap_write_coreregister_u32(swjdp, value, num); if (retval != ERROR_OK) { @@ -1329,38 +1339,43 @@ int cortex_m3_store_core_reg_u32(struct target_s *target, enum armv7m_regtype ty return ERROR_JTAG_DEVICE_ERROR; } LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value); - } - else if (type == ARMV7M_REGISTER_CORE_SP) /* Special purpose core register */ - { - /* write other registers */ - + break; + + case ARMV7M_PRIMASK: + case ARMV7M_BASEPRI: + case ARMV7M_FAULTMASK: + case ARMV7M_CONTROL: + /* Cortex-M3 packages these four registers as bitfields + * in one Debug Core register. So say r0 and r2 docs; + * it was removed from r1 docs, but still works. + */ cortexm3_dap_read_coreregister_u32(swjdp, ®, 20); switch (num) { - case 19: - buf_set_u32((uint8_t*)®, 0, 8, value); + case ARMV7M_PRIMASK: + buf_set_u32((uint8_t*)®, 0, 1, value); break; - case 20: + case ARMV7M_BASEPRI: buf_set_u32((uint8_t*)®, 8, 8, value); break; - case 21: - buf_set_u32((uint8_t*)®, 16, 8, value); + case ARMV7M_FAULTMASK: + buf_set_u32((uint8_t*)®, 16, 1, value); break; - case 22: - buf_set_u32((uint8_t*)®, 24, 8, value); + case ARMV7M_CONTROL: + buf_set_u32((uint8_t*)®, 24, 2, value); break; } cortexm3_dap_write_coreregister_u32(swjdp, reg, 20); LOG_DEBUG("write special reg %i value 0x%" PRIx32 " ", (int)num, value); - } - else - { + break; + + default: return ERROR_INVALID_ARGUMENTS; } -- 2.30.2