target/mips32: add fpu access support

Add access to fpr and cp1 registers.
GDB can now check the FPRs with `info reg f` and change them.
Checkpatch-ignore: MACRO_ARG_REUSE

Change-Id: I63896ab6f6737054d8108db105a13a58e1446fbc
Signed-off-by: Walter Ji <walter.ji@oss.cipunited.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/7866
Tested-by: jenkins
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
Walter Ji
2023-11-17 16:46:55 +08:00
committed by Antonio Borneo
parent a88db9b121
commit 01a797af14
4 changed files with 245 additions and 12 deletions

View File

@@ -588,6 +588,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
*
@@ -856,6 +876,9 @@ int mips32_pracc_write_regs(struct mips32_common *mips32)
struct pracc_queue_info ctx = {.ejtag_info = ejtag_info};
uint32_t *gprs = mips32->core_regs.gpr;
uint32_t *c0rs = mips32->core_regs.cp0;
bool fpu_in_64bit = ((c0rs[0] & BIT(MIPS32_CP0_STATUS_FR_SHIFT)) != 0);
bool fp_enabled = ((c0rs[0] & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0);
uint32_t rel = (ejtag_info->config[0] & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT;
pracc_queue_init(&ctx);
@@ -895,6 +918,31 @@ int mips32_pracc_write_regs(struct mips32_common *mips32)
if (mips32_cpu_support_hazard_barrier(ejtag_info))
pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa));
/* store FPRs */
if (mips32->fp_imp && fp_enabled) {
uint64_t *fprs = mips32->core_regs.fpr;
if (fpu_in_64bit) {
for (int i = 0; i != MIPS32_REG_FP_COUNT; i++) {
uint32_t fp_lo = fprs[i] & 0xffffffff;
uint32_t fp_hi = (fprs[i] >> 32) & 0xffffffff;
pracc_add_li32(&ctx, 2, fp_lo, 0);
pracc_add_li32(&ctx, 3, fp_hi, 0);
pracc_add(&ctx, 0, MIPS32_MTC1(ctx.isa, 2, i));
pracc_add(&ctx, 0, MIPS32_MTHC1(ctx.isa, 3, i));
}
} else {
for (int i = 0; i != MIPS32_REG_FP_COUNT; i++) {
uint32_t fp_lo = fprs[i] & 0xffffffff;
pracc_add_li32(&ctx, 2, fp_lo, 0);
pracc_add(&ctx, 0, MIPS32_MTC1(ctx.isa, 2, i));
}
}
if (rel > MIPS32_RELEASE_1)
pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa));
}
/* load registers 2 to 31 with li32, optimize */
for (int i = 2; i < 32; i++)
pracc_add_li32(&ctx, i, gprs[i], 1);
@@ -1014,6 +1062,9 @@ int mips32_pracc_read_regs(struct mips32_common *mips32)
struct mips32_core_regs *core_regs = &mips32->core_regs;
unsigned int offset_gpr = ((uint8_t *)&core_regs->gpr[0]) - (uint8_t *)core_regs;
unsigned int offset_cp0 = ((uint8_t *)&core_regs->cp0[0]) - (uint8_t *)core_regs;
unsigned int offset_fpr = ((uint8_t *)&core_regs->fpr[0]) - (uint8_t *)core_regs;
unsigned int offset_fpcr = ((uint8_t *)&core_regs->fpcr[0]) - (uint8_t *)core_regs;
bool fp_enabled;
/*
* This procedure has to be in 2 distinctive steps, because we can
@@ -1040,11 +1091,64 @@ int mips32_pracc_read_regs(struct mips32_common *mips32)
ejtag_info->reg8 = mips32->core_regs.gpr[8];
ejtag_info->reg9 = mips32->core_regs.gpr[9];
if (ctx.retval != ERROR_OK)
return ctx.retval;
/* we only care if FP is actually impl'd and if cp1 is enabled */
/* since we already read cp0 in the prev step */
/* now we know what's in cp0.status */
/* TODO: Read FPRs */
fp_enabled = (mips32->core_regs.cp0[0] & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0;
if (mips32->fp_imp && fp_enabled) {
pracc_queue_init(&ctx);
mips32_pracc_store_regs_set_base_addr(&ctx);
/* FCSR */
pracc_add(&ctx, 0, MIPS32_CFC1(ctx.isa, 8, 31));
pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset_fpcr,
MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset_fpcr, 1));
/* FIR */
pracc_add(&ctx, 0, MIPS32_CFC1(ctx.isa, 8, 0));
pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset_fpcr + 4,
MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset_fpcr + 4, 1));
/* f0 to f31 */
if (mips32->fpu_in_64bit) {
for (int i = 0; i != 32; i++) {
size_t offset = offset_fpr + (i * 8);
/* current pracc implementation (or EJTAG itself) only supports 32b access */
/* so there is no way to use SDC1 */
/* lower half */
pracc_add(&ctx, 0, MIPS32_MFC1(ctx.isa, 8, i));
pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset,
MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset, 1));
/* upper half */
pracc_add(&ctx, 0, MIPS32_MFHC1(ctx.isa, 8, i));
pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset + 4,
MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset + 4, 1));
}
} else {
for (int i = 0; i != 32; i++) {
size_t offset = offset_fpr + (i * 8);
pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset,
MIPS32_SWC1(ctx.isa, i, PRACC_OUT_OFFSET + offset, 1));
}
}
mips32_pracc_store_regs_restore(&ctx);
/* jump to start */
pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa)));
/* load $15 in DeSave */
pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0));
ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, (uint32_t *)&mips32->core_regs, 1);
pracc_queue_free(&ctx);
}
return ctx.retval;
}