This is an automated email from Gerrit. "Walter Ji <walter...@oss.cipunited.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7866
-- gerrit commit 12ed00751bce9aa6a55eee1a0c201ba732ee1a41 Author: Walter Ji <walter...@oss.cipunited.com> Date: Fri Aug 25 17:34:31 2023 +0800 target/mips32: add fpu access support Add access to fpr and cp1 registers. Change-Id: I63896ab6f6737054d8108db105a13a58e1446fbc Signed-off-by: Walter Ji <walter...@oss.cipunited.com> diff --git a/src/target/mips32.c b/src/target/mips32.c index 755b958450..4a1338e40a 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -286,6 +286,28 @@ static int mips32_set_core_reg(struct reg *reg, uint8_t *buf) return ERROR_OK; } +static void mips32_set_fpr_width(struct mips32_common *mips32, bool fp64); + +static void mips32_detect_fpr_mode_change(struct mips32_common *mips32, uint32_t cp0_status) +{ + if (mips32->fp_imp) { + bool status_fr = (cp0_status >> MIPS32_CP0_STATUS_FR_SHIFT) & 0x1; + bool status_cu1 = (cp0_status >> MIPS32_CP0_STATUS_CU1_SHIFT) & 0x1; + + if (mips32->fpu_in_64bit != status_fr) { + mips32->fpu_in_64bit = status_fr; + mips32_set_fpr_width(mips32, status_fr); + LOG_WARNING("** FP mode changed to %sbit, you must reconnect GDB **", status_fr ? "64" : "32"); + } + + if (mips32->fpu_enabled != status_cu1) { + mips32->fpu_enabled = status_cu1; + const char *s = status_cu1 ? "enabled" : "disabled"; + LOG_WARNING("** FP is %s, register update %s **", s, s); + } + } +} + static int mips32_read_core_reg(struct target *target, unsigned int num) { unsigned int cnum; @@ -500,6 +522,18 @@ struct reg_cache *mips32_build_reg_cache(struct target *target) return cache; } +static void mips32_set_fpr_width(struct mips32_common *mips32, bool fp64) +{ + struct reg_cache *cache = mips32->core_cache; + struct reg *reg_list = cache->reg_list; + int i; + + for (i = MIPS32_REGLIST_FP_INDEX; i < (MIPS32_REGLIST_FP_INDEX + MIPS32_REG_FP_COUNT); i++) { + reg_list[i].size = fp64 ? 64 : 32; + reg_list[i].reg_data_type->type = fp64 ? REG_TYPE_IEEE_DOUBLE : REG_TYPE_IEEE_SINGLE; + } +} + int mips32_init_arch_info(struct target *target, struct mips32_common *mips32, struct jtag_tap *tap) { target->arch_info = mips32; @@ -1170,6 +1204,51 @@ int mips32_read_config_regs(struct target *target) LOG_USER("DSP implemented: %s", "no"); } + /* Retrieve if Float Point CoProcessor Implemented */ + mips32->fp_imp = (ejtag_info->config[1] & MIPS32_CONFIG1_FP_MASK) >> MIPS32_CONFIG1_FP_SHIFT; + if (mips32->fp_imp) { + uint32_t fir_value, status_value; + bool status_fr, status_cu1; + char buf[128] = {0}; + + retval = mips32_cp0_read(ejtag_info, &status_value, MIPS32_C0_STATUS, 0); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read cp0 status register"); + return retval; + } + + status_fr = (status_value >> MIPS32_CP0_STATUS_FR_SHIFT) & 0x1; + status_cu1 = (status_value >> MIPS32_CP0_STATUS_CU1_SHIFT) & 0x1; + if (status_cu1) { + retval = mips32_cp1_control_read(ejtag_info, &fir_value, 0); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read cp1 FIR register"); + return retval; + } + + if ((fir_value >> MIPS32_CP1_FIR_F64_SHIFT) & 0x1) + mips32->fp_imp++; + } else { + strcpy(buf, "yes, disabled"); + mips32->fp_imp = MIPS32_FP_IMP_UNKNOWN; + } + + mips32->fpu_in_64bit = status_fr; + mips32->fpu_enabled = status_cu1; + + mips32_set_fpr_width(mips32, status_fr); + + if (!buf[0]) + sprintf(buf, "yes, %sbit (%s, working in %sbit)", + mips32->fp_imp == MIPS32_FP_IMP_64 ? "64" : "32", + status_cu1 ? "enabled" : "disabled", + status_fr ? "64" : "32"); + + LOG_USER("FPU implemented: %s", buf); + } else { + LOG_USER("FPU implemented: %s", "no"); + } + /* Determine if FDC and CDMM are implemented for this core */ uint32_t dcr; @@ -1405,38 +1484,132 @@ COMMAND_HANDLER(mips32_handle_cp0_command) } /* two or more argument, access a single register/select (write if third argument is given) */ - if (CMD_ARGC < 2) - return ERROR_COMMAND_SYNTAX_ERROR; - else { - uint32_t cp0_reg, cp0_sel; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel); + if (CMD_ARGC < 2) { + uint32_t value; + + if (CMD_ARGC == 0) { + for (int i = 0; i < MIPS32NUMCP0REGS; i++) { + if (mips32_cp0_regs[i].core & mips32->cp0_mask) { + retval = mips32_cp0_read(ejtag_info, &value, mips32_cp0_regs[i].reg, mips32_cp0_regs[i].sel); + if (retval != ERROR_OK) { + command_print(CMD, "couldn't access reg %s", mips32_cp0_regs[i].name); + return ERROR_OK; + } + } else /* Register name not valid for this core */ + continue; + + command_print(CMD, "%*s: 0x%8.8x", 14, mips32_cp0_regs[i].name, value); + } + } else { + for (int i = 0; i < MIPS32NUMCP0REGS; i++) { + /* find register name */ + if (mips32_cp0_regs[i].core & mips32->cp0_mask) { + if (strcmp(mips32_cp0_regs[i].name, CMD_ARGV[0]) == 0) { + retval = mips32_cp0_read(ejtag_info, &value, mips32_cp0_regs[i].reg, mips32_cp0_regs[i].sel); + command_print(CMD, "0x%8.8x", value); + return ERROR_OK; + } + } else /* Register name not valid for this core */ + continue; + } + LOG_ERROR("BUG: register '%s' not found", CMD_ARGV[0]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + } else { if (CMD_ARGC == 2) { uint32_t value; - - retval = mips32_cp0_read(ejtag_info, &value, cp0_reg, cp0_sel); - if (retval != ERROR_OK) { - command_print(CMD, - "couldn't access reg %" PRIu32, + int tmp = *CMD_ARGV[0]; + + if (isdigit(tmp) == false) { + for (int i = 0; i < MIPS32NUMCP0REGS; i++) { + /* find register name */ + if (mips32_cp0_regs[i].core & mips32->cp0_mask) { + if (strcmp(mips32_cp0_regs[i].name, CMD_ARGV[0]) == 0) { + uint32_t cp0_reg = mips32_cp0_regs[i].reg; + uint32_t cp0_sel = mips32_cp0_regs[i].sel; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + + /* Check if user is writing to Status register */ + if ((cp0_reg == MIPS32_C0_STATUS) && (cp0_sel == 0)) { + mips32->core_regs.cp0[MIPS32_REG_C0_STATUS_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_STATUS_INDEX].dirty = 1; + } else if ((cp0_reg == MIPS32_C0_CAUSE) && (cp0_sel == 0)) { + /* Cause register ?? Update register cache with new value */ + mips32->core_regs.cp0[MIPS32_REG_C0_CAUSE_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_CAUSE_INDEX].dirty = 1; + } else if ((cp0_reg == MIPS32_C0_DEPC) && (cp0_sel == 0)) { + /* DEPC ? Update cached PC */ + mips32->core_regs.cp0[MIPS32_REG_C0_PC_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].dirty = 1; + } else if ((cp0_reg == MIPS32_C0_GUESTCTL1) && (cp0_sel == 4)) { + /* guestCtl1 ? Update it */ + mips32->core_regs.cp0[MIPS32_REG_C0_GUESTCTL1_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_GUESTCTL1_INDEX].dirty = 1; + } + + retval = mips32_cp0_write(ejtag_info, value, mips32_cp0_regs[i].reg, mips32_cp0_regs[i].sel); + return ERROR_OK; + } + } else /* Register name not valid for this core */ + continue; + } + + LOG_ERROR("BUG: register '%s' not found", CMD_ARGV[0]); + return ERROR_COMMAND_SYNTAX_ERROR; + } else { + uint32_t cp0_reg, cp0_sel; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel); + + retval = mips32_cp0_read(ejtag_info, &value, cp0_reg, cp0_sel); + if (retval != ERROR_OK) { + command_print(CMD, + "couldn't access reg %" PRIi32, cp0_reg); - return ERROR_OK; - } - command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32, - cp0_reg, cp0_sel, value); + return ERROR_OK; + } + command_print(CMD, "cp0 reg %" PRIi32 ", select %" PRIi32 ": %8.8" PRIx32, + cp0_reg, cp0_sel, value); + } } else if (CMD_ARGC == 3) { + uint32_t cp0_reg, cp0_sel; uint32_t value; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); + + /* Check if user is writing to Status register */ + if ((cp0_reg == MIPS32_C0_STATUS) && (cp0_sel == 0)) { + mips32->core_regs.cp0[MIPS32_REG_C0_STATUS_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_STATUS_INDEX].dirty = 1; + } else if ((cp0_reg == MIPS32_C0_CAUSE) && (cp0_sel == 0)) { + /* Cause register ?? Update register cache with new value */ + mips32->core_regs.cp0[MIPS32_REG_C0_CAUSE_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_CAUSE_INDEX].dirty = 1; + } else if ((cp0_reg == MIPS32_C0_DEPC) && (cp0_sel == 0)) { + /* DEPC ? Update cached PC */ + mips32->core_regs.cp0[MIPS32_REG_C0_PC_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].dirty = 1; + } else if ((cp0_reg == MIPS32_C0_GUESTCTL1) && (cp0_sel == 4)) { + /* guestCtl1 ? Update it */ + mips32->core_regs.cp0[MIPS32_REG_C0_GUESTCTL1_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_GUESTCTL1_INDEX].dirty = 1; + } + + retval = mips32_cp0_write(ejtag_info, value, cp0_reg, cp0_sel); if (retval != ERROR_OK) { command_print(CMD, - "couldn't access cp0 reg %" PRIu32 ", select %" PRIu32, - cp0_reg, cp0_sel); + "couldn't access cp0 reg %" PRIi32 ", select %" PRIi32, + cp0_reg, cp0_sel); return ERROR_OK; } - command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32, - cp0_reg, cp0_sel, value); + command_print(CMD, "cp0 reg %" PRIi32 ", select %" PRIi32 ": %8.8" PRIx32, + cp0_reg, cp0_sel, value); } } @@ -2176,7 +2349,7 @@ static const struct command_registration mips32_exec_command_handlers[] = { .name = "cp0", .handler = mips32_handle_cp0_command, .mode = COMMAND_EXEC, - .usage = "regnum select [value]", + .usage = "[[reg_name|regnum select] [value]]", .help = "display/modify cp0 register", }, { diff --git a/src/target/mips32_pracc.c b/src/target/mips32_pracc.c index 617c293bf0..43a87245cc 100644 --- a/src/target/mips32_pracc.c +++ b/src/target/mips32_pracc.c @@ -583,6 +583,26 @@ int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_r return ctx.retval; } +int mips32_cp1_control_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp1_c_reg) +{ + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; + pracc_queue_init(&ctx); + + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ + pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa)); + pracc_add(&ctx, 0, MIPS32_CFC1(ctx.isa, 8, cp1_c_reg)); /* move cp1c reg to $8 */ + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */ + pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ + pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */ + + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, val, 1); + pracc_queue_free(&ctx); + return ctx.retval; +} + /** * \b mips32_pracc_sync_cache * diff --git a/src/target/mips32_pracc.h b/src/target/mips32_pracc.h index 804de8ca84..463ee4f870 100644 --- a/src/target/mips32_pracc.h +++ b/src/target/mips32_pracc.h @@ -101,6 +101,21 @@ int mips32_cp0_read(struct mips_ejtag *ejtag_info, int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel); +/** + * \b mips32_cp1_control_read + * + * Simulates cfc1 ASM instruction (Move Control Word From Floating Point), + * i.e. implements copro C1 Control Register read. + * + * @param[in] ejtag_info + * @param[in] val Storage to hold read value + * @param[in] cp1_c_reg Number of copro C1 control register we want to read + * + * @return ERROR_OK on Success, ERROR_FAIL otherwise + */ +int mips32_cp1_control_read(struct mips_ejtag *ejtag_info, + uint32_t *val, uint32_t cp1_c_reg); + static inline void pracc_swap16_array(struct mips_ejtag *ejtag_info, uint32_t *buf, int count) { if (ejtag_info->isa && ejtag_info->endianness) --