mips32: add micromips isa handling

Read and save configuration registers, up to 4.
Config3 holds the micromips implementation info.
Added isa implementation info to mips32_common.
Added isa filter to avoid common mistakes, but only
if one isa mode is implemented.
When resuming the isa requested is set if more than
one isa mode is implemented.

Change-Id: I1d6526c5525bffac8d75e031b842b2edc6310e28
Signed-off-by: Salvador Arroyo <sarroyofdez@yahoo.es>
Reviewed-on: http://openocd.zylin.com/4123
Tested-by: jenkins
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
gitignore-build
Salvador Arroyo 2017-05-07 18:39:17 +02:00 committed by Freddie Chopin
parent f5151b6d46
commit 4831ce4433
5 changed files with 91 additions and 19 deletions

View File

@ -34,7 +34,7 @@
#include "register.h" #include "register.h"
static const char *mips_isa_strings[] = { static const char *mips_isa_strings[] = {
"MIPS32", "MIPS16" "MIPS32", "MIPS16", "", "MICRO MIPS32",
}; };
#define MIPS32_GDB_DUMMY_FP_REG 1 #define MIPS32_GDB_DUMMY_FP_REG 1
@ -375,6 +375,7 @@ int mips32_init_arch_info(struct target *target, struct mips32_common *mips32, s
target->arch_info = mips32; target->arch_info = mips32;
mips32->common_magic = MIPS32_COMMON_MAGIC; mips32->common_magic = MIPS32_COMMON_MAGIC;
mips32->fast_data_area = NULL; mips32->fast_data_area = NULL;
mips32->isa_imp = MIPS32_ONLY; /* default */
/* has breakpoint/watchpoint unit been scanned */ /* has breakpoint/watchpoint unit been scanned */
mips32->bp_scanned = 0; mips32->bp_scanned = 0;
@ -388,7 +389,7 @@ int mips32_init_arch_info(struct target *target, struct mips32_common *mips32, s
mips32->ejtag_info.scan_delay = MIPS32_SCAN_DELAY_LEGACY_MODE; mips32->ejtag_info.scan_delay = MIPS32_SCAN_DELAY_LEGACY_MODE;
mips32->ejtag_info.mode = 0; /* Initial default value */ mips32->ejtag_info.mode = 0; /* Initial default value */
mips32->ejtag_info.isa = 0; /* isa on debug mips32, updated by poll function */ mips32->ejtag_info.isa = 0; /* isa on debug mips32, updated by poll function */
mips32->ejtag_info.config_regs = 0; /* no config register read */
return ERROR_OK; return ERROR_OK;
} }
@ -698,6 +699,50 @@ int mips32_enable_interrupts(struct target *target, int enable)
return ERROR_OK; return ERROR_OK;
} }
/* read config to config3 cp0 registers and log isa implementation */
int mips32_read_config_regs(struct target *target)
{
struct mips32_common *mips32 = target_to_mips32(target);
struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
if (ejtag_info->config_regs == 0)
for (int i = 0; i != 4; i++) {
int retval = mips32_cp0_read(ejtag_info, &ejtag_info->config[i], 16, i);
if (retval != ERROR_OK) {
LOG_ERROR("isa info not available, failed to read cp0 config register: %" PRId32, i);
ejtag_info->config_regs = 0;
return retval;
}
ejtag_info->config_regs = i + 1;
if ((ejtag_info->config[i] & (1 << 31)) == 0)
break; /* no more config registers implemented */
}
else
return ERROR_OK; /* already succesfully read */
LOG_DEBUG("read %"PRId32" config registers", ejtag_info->config_regs);
if (ejtag_info->impcode & EJTAG_IMP_MIPS16) {
mips32->isa_imp = MIPS32_MIPS16;
LOG_USER("MIPS32 with MIPS16 support implemented");
} else if (ejtag_info->config_regs >= 4) { /* config3 implemented */
unsigned isa_imp = (ejtag_info->config[3] & MIPS32_CONFIG3_ISA_MASK) >> MIPS32_CONFIG3_ISA_SHIFT;
if (isa_imp == 1) {
mips32->isa_imp = MMIPS32_ONLY;
LOG_USER("MICRO MIPS32 only implemented");
} else if (isa_imp != 0) {
mips32->isa_imp = MIPS32_MMIPS32;
LOG_USER("MIPS32 and MICRO MIPS32 implemented");
}
}
if (mips32->isa_imp == MIPS32_ONLY) /* initial default value */
LOG_USER("MIPS32 only implemented");
return ERROR_OK;
}
int mips32_checksum_memory(struct target *target, target_addr_t address, int mips32_checksum_memory(struct target *target, target_addr_t address,
uint32_t count, uint32_t *checksum) uint32_t count, uint32_t *checksum)
{ {
@ -756,7 +801,7 @@ int mips32_checksum_memory(struct target *target, target_addr_t address,
return retval; return retval;
mips32_info.common_magic = MIPS32_COMMON_MAGIC; mips32_info.common_magic = MIPS32_COMMON_MAGIC;
mips32_info.isa_mode = MIPS32_ISA_MIPS32; mips32_info.isa_mode = isa ? MIPS32_ISA_MMIPS32 : MIPS32_ISA_MIPS32; /* run isa as in debug mode */
init_reg_param(&reg_params[0], "r4", 32, PARAM_IN_OUT); init_reg_param(&reg_params[0], "r4", 32, PARAM_IN_OUT);
buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[0].value, 0, 32, address);
@ -766,11 +811,8 @@ int mips32_checksum_memory(struct target *target, target_addr_t address,
int timeout = 20000 * (1 + (count / (1024 * 1024))); int timeout = 20000 * (1 + (count / (1024 * 1024)));
/* same isa as in debug mode */ retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address,
retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address + (sizeof(mips_crc_code) - 4), timeout, &mips32_info);
crc_algorithm->address | isa,
(crc_algorithm->address + (sizeof(mips_crc_code) - 4)) | isa,
timeout, &mips32_info);
if (retval == ERROR_OK) if (retval == ERROR_OK)
*checksum = buf_get_u32(reg_params[0].value, 0, 32); *checksum = buf_get_u32(reg_params[0].value, 0, 32);
@ -827,7 +869,7 @@ int mips32_blank_check_memory(struct target *target,
return retval; return retval;
mips32_info.common_magic = MIPS32_COMMON_MAGIC; mips32_info.common_magic = MIPS32_COMMON_MAGIC;
mips32_info.isa_mode = MIPS32_ISA_MIPS32; mips32_info.isa_mode = isa ? MIPS32_ISA_MMIPS32 : MIPS32_ISA_MIPS32;
init_reg_param(&reg_params[0], "r4", 32, PARAM_OUT); init_reg_param(&reg_params[0], "r4", 32, PARAM_OUT);
buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[0].value, 0, 32, address);
@ -838,11 +880,8 @@ int mips32_blank_check_memory(struct target *target,
init_reg_param(&reg_params[2], "r6", 32, PARAM_IN_OUT); init_reg_param(&reg_params[2], "r6", 32, PARAM_IN_OUT);
buf_set_u32(reg_params[2].value, 0, 32, erased_value); buf_set_u32(reg_params[2].value, 0, 32, erased_value);
/* same isa as in debug mode */ retval = target_run_algorithm(target, 0, NULL, 3, reg_params, erase_check_algorithm->address,
retval = target_run_algorithm(target, 0, NULL, 3, reg_params, erase_check_algorithm->address + (sizeof(erase_check_code) - 4), 10000, &mips32_info);
erase_check_algorithm->address | isa,
(erase_check_algorithm->address + (sizeof(erase_check_code) - 4)) | isa,
10000, &mips32_info);
if (retval == ERROR_OK) if (retval == ERROR_OK)
*blank = buf_get_u32(reg_params[2].value, 0, 32); *blank = buf_get_u32(reg_params[2].value, 0, 32);

View File

@ -58,6 +58,9 @@
#define MIPS32_CONFIG1_DL_SHIFT 10 #define MIPS32_CONFIG1_DL_SHIFT 10
#define MIPS32_CONFIG1_DL_MASK (0x7 << MIPS32_CONFIG1_DL_SHIFT) #define MIPS32_CONFIG1_DL_MASK (0x7 << MIPS32_CONFIG1_DL_SHIFT)
#define MIPS32_CONFIG3_ISA_SHIFT 14
#define MIPS32_CONFIG3_ISA_MASK (3 << MIPS32_CONFIG3_ISA_SHIFT)
#define MIPS32_ARCH_REL1 0x0 #define MIPS32_ARCH_REL1 0x0
#define MIPS32_ARCH_REL2 0x1 #define MIPS32_ARCH_REL2 0x1
@ -73,6 +76,14 @@ enum {
enum mips32_isa_mode { enum mips32_isa_mode {
MIPS32_ISA_MIPS32 = 0, MIPS32_ISA_MIPS32 = 0,
MIPS32_ISA_MIPS16E = 1, MIPS32_ISA_MIPS16E = 1,
MIPS32_ISA_MMIPS32 = 3,
};
enum mips32_isa_imp {
MIPS32_ONLY = 0,
MMIPS32_ONLY = 1,
MIPS32_MIPS16 = 2,
MIPS32_MMIPS32 = 3,
}; };
struct mips32_comparator { struct mips32_comparator {
@ -88,6 +99,7 @@ struct mips32_common {
struct mips_ejtag ejtag_info; struct mips_ejtag ejtag_info;
uint32_t core_regs[MIPS32NUMCOREREGS]; uint32_t core_regs[MIPS32NUMCOREREGS];
enum mips32_isa_mode isa_mode; enum mips32_isa_mode isa_mode;
enum mips32_isa_imp isa_imp;
/* working area for fastdata access */ /* working area for fastdata access */
struct working_area *fast_data_area; struct working_area *fast_data_area;
@ -406,6 +418,8 @@ int mips32_enable_interrupts(struct target *target, int enable);
int mips32_examine(struct target *target); int mips32_examine(struct target *target);
int mips32_read_config_regs(struct target *target);
int mips32_register_commands(struct command_context *cmd_ctx); int mips32_register_commands(struct command_context *cmd_ctx);
int mips32_get_gdb_reg_list(struct target *target, int mips32_get_gdb_reg_list(struct target *target,

View File

@ -183,6 +183,9 @@ struct mips_ejtag {
uint32_t idcode; uint32_t idcode;
uint32_t ejtag_ctrl; uint32_t ejtag_ctrl;
int fast_access_save; int fast_access_save;
uint32_t config_regs; /* number of config registers read */
uint32_t config[4]; /* cp0 config to config3 */
uint32_t reg8; uint32_t reg8;
uint32_t reg9; uint32_t reg9;
unsigned scan_delay; unsigned scan_delay;

View File

@ -41,7 +41,7 @@ static int mips_m4k_set_breakpoint(struct target *target,
static int mips_m4k_unset_breakpoint(struct target *target, static int mips_m4k_unset_breakpoint(struct target *target,
struct breakpoint *breakpoint); struct breakpoint *breakpoint);
static int mips_m4k_internal_restore(struct target *target, int current, static int mips_m4k_internal_restore(struct target *target, int current,
uint32_t address, int handle_breakpoints, target_addr_t address, int handle_breakpoints,
int debug_execution); int debug_execution);
static int mips_m4k_halt(struct target *target); static int mips_m4k_halt(struct target *target);
static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t address, static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t address,
@ -108,11 +108,14 @@ static int mips_m4k_debug_entry(struct target *target)
/* attempt to find halt reason */ /* attempt to find halt reason */
mips_m4k_examine_debug_reason(target); mips_m4k_examine_debug_reason(target);
mips32_read_config_regs(target);
/* default to mips32 isa, it will be changed below if required */ /* default to mips32 isa, it will be changed below if required */
mips32->isa_mode = MIPS32_ISA_MIPS32; mips32->isa_mode = MIPS32_ISA_MIPS32;
if (ejtag_info->impcode & EJTAG_IMP_MIPS16) /* other than mips32 only and isa bit set ? */
mips32->isa_mode = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1); if (mips32->isa_imp && buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1))
mips32->isa_mode = mips32->isa_imp == 2 ? MIPS32_ISA_MIPS16E : MIPS32_ISA_MMIPS32;
LOG_DEBUG("entered debug state at PC 0x%" PRIx32 ", target->state: %s", LOG_DEBUG("entered debug state at PC 0x%" PRIx32 ", target->state: %s",
buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32), buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32),
@ -431,7 +434,7 @@ static int mips_m4k_restore_smp(struct target *target, uint32_t address, int han
} }
static int mips_m4k_internal_restore(struct target *target, int current, static int mips_m4k_internal_restore(struct target *target, int current,
uint32_t address, int handle_breakpoints, int debug_execution) target_addr_t address, int handle_breakpoints, int debug_execution)
{ {
struct mips32_common *mips32 = target_to_mips32(target); struct mips32_common *mips32 = target_to_mips32(target);
struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
@ -451,12 +454,13 @@ static int mips_m4k_internal_restore(struct target *target, int current,
/* current = 1: continue on current pc, otherwise continue at <address> */ /* current = 1: continue on current pc, otherwise continue at <address> */
if (!current) { if (!current) {
mips_m4k_isa_filter(mips32->isa_imp, &address);
buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address); buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address);
mips32->core_cache->reg_list[MIPS32_PC].dirty = 1; mips32->core_cache->reg_list[MIPS32_PC].dirty = 1;
mips32->core_cache->reg_list[MIPS32_PC].valid = 1; mips32->core_cache->reg_list[MIPS32_PC].valid = 1;
} }
if (ejtag_info->impcode & EJTAG_IMP_MIPS16) if ((mips32->isa_imp > 1) && debug_execution) /* if more than one isa supported */
buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1, mips32->isa_mode); buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1, mips32->isa_mode);
if (!current) if (!current)
@ -544,6 +548,7 @@ static int mips_m4k_step(struct target *target, int current,
/* current = 1: continue on current pc, otherwise continue at <address> */ /* current = 1: continue on current pc, otherwise continue at <address> */
if (!current) { if (!current) {
mips_m4k_isa_filter(mips32->isa_imp, &address);
buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address); buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address);
mips32->core_cache->reg_list[MIPS32_PC].dirty = 1; mips32->core_cache->reg_list[MIPS32_PC].dirty = 1;
mips32->core_cache->reg_list[MIPS32_PC].valid = 1; mips32->core_cache->reg_list[MIPS32_PC].valid = 1;

View File

@ -41,6 +41,17 @@ target_to_m4k(struct target *target)
struct mips_m4k_common, mips32); struct mips_m4k_common, mips32);
} }
static inline void mips_m4k_isa_filter(enum mips32_isa_imp isa_imp, target_addr_t *addr)
{
if (isa_imp <= 1) { /* if only one isa implemented */
target_addr_t address = (*addr & ~1) | isa_imp;
if (address != *addr) {
LOG_USER("Warning: isa bit changed due to isa not implemented");
*addr = address;
}
}
}
extern const struct command_registration mips_m4k_command_handlers[]; extern const struct command_registration mips_m4k_command_handlers[];
#endif /* OPENOCD_TARGET_MIPS_M4K_H */ #endif /* OPENOCD_TARGET_MIPS_M4K_H */