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)

-- 

Reply via email to