target-mips: add Config5.FRE support allowing Status.FR=0 emulation

This relatively small architectural feature adds the following:

FIR.FREP: Read-only. If FREP=1, then Config5.FRE and Config5.UFE are
available.

Config5.FRE: When enabled all single-precision FP arithmetic instructions,
LWC1/LWXC1/MTC1, SWC1/SWXC1/MFC1 cause a Reserved Instructions
exception.

Config5.UFE: Allows user to write/read Config5.FRE using CTC1/CFC1
instructions.

Enable the feature in MIPS64R6-generic CPU.

Backports commit 7c979afd11b09a16634699dd6344e3ba10c9677e from qemu
This commit is contained in:
Leon Alrae 2018-02-13 12:53:12 -05:00 committed by Lioncash
parent 428ffed744
commit c54458b638
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
4 changed files with 80 additions and 24 deletions

View file

@ -101,6 +101,7 @@ struct CPUMIPSFPUContext {
float_status fp_status;
/* fpu implementation/revision register (fir) */
uint32_t fcr0;
#define FCR0_FREP 29
#define FCR0_UFRP 28
#define FCR0_F64 22
#define FCR0_L 21
@ -463,6 +464,8 @@ struct CPUMIPSState {
#define CP0C5_CV 29
#define CP0C5_EVA 28
#define CP0C5_MSAEn 27
#define CP0C5_UFE 9
#define CP0C5_FRE 8
#define CP0C5_SBRI 6
#define CP0C5_UFR 2
#define CP0C5_NFExists 0
@ -515,7 +518,7 @@ struct CPUMIPSState {
#define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */
uint32_t hflags; /* CPU State */
/* TMASK defines different execution modes */
#define MIPS_HFLAG_TMASK 0x15807FF
#define MIPS_HFLAG_TMASK 0x35807FF
#define MIPS_HFLAG_MODE 0x00007 /* execution modes */
/* The KSU flags must be the lowest bits in hflags. The flag order
must be the same as defined for CP0 Status. This allows to use
@ -561,7 +564,8 @@ struct CPUMIPSState {
#define MIPS_HFLAG_HWRENA_ULR 0x200000 /* ULR bit from HWREna is set. */
#define MIPS_HFLAG_SBRI 0x400000 /* R6 SDBBP causes RI excpt. in user mode */
#define MIPS_HFLAG_FBNSLOT 0x800000 /* Forbidden slot */
#define MIPS_HFLAG_MSA 0x1000000
#define MIPS_HFLAG_MSA 0x1000000 /* FRE enabled */
#define MIPS_HFLAG_FRE 0x2000000 /* FRE enabled */
target_ulong btarget; /* Jump / branch target */
target_ulong bcond; /* Branch condition (if needed) */
@ -847,7 +851,7 @@ static inline void compute_hflags(CPUMIPSState *env)
env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2 |
MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA);
MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA | MIPS_HFLAG_FRE);
if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
!(env->CP0_Status & (1 << CP0St_ERL)) &&
!(env->hflags & MIPS_HFLAG_DM)) {
@ -928,6 +932,11 @@ static inline void compute_hflags(CPUMIPSState *env)
env->hflags |= MIPS_HFLAG_MSA;
}
}
if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
if (env->CP0_Config5 & (1 << CP0C5_FRE)) {
env->hflags |= MIPS_HFLAG_FRE;
}
}
}
#ifndef CONFIG_USER_ONLY

View file

@ -2306,6 +2306,16 @@ target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
}
}
break;
case 5:
/* FRE Support - read Config5.FRE bit */
if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
arg1 = (env->CP0_Config5 >> CP0C5_FRE) & 1;
} else {
helper_raise_exception(env, EXCP_RI);
}
}
break;
case 25:
arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
break;
@ -2350,6 +2360,30 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
helper_raise_exception(env, EXCP_RI);
}
break;
case 5:
/* FRE Support - clear Config5.FRE bit */
if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
return;
}
if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
env->CP0_Config5 &= ~(1 << CP0C5_FRE);
compute_hflags(env);
} else {
helper_raise_exception(env, EXCP_RI);
}
break;
case 6:
/* FRE Support - set Config5.FRE bit */
if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
return;
}
if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
env->CP0_Config5 |= (1 << CP0C5_FRE);
compute_hflags(env);
} else {
helper_raise_exception(env, EXCP_RI);
}
break;
case 25:
if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) {
return;

View file

@ -1548,20 +1548,22 @@ static inline void gen_store_srsgpr (DisasContext *s, int from, int to)
}
/* Tests */
static inline void gen_save_pc(target_ulong pc)
static inline void gen_save_pc(DisasContext *ctx, target_ulong pc)
{
tcg_gen_movi_tl(cpu_PC, pc);
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
tcg_gen_movi_tl(tcg_ctx, *(TCGv *)tcg_ctx->cpu_PC, pc);
}
static inline void save_cpu_state(DisasContext *ctx, int do_save_pc)
{
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
LOG_DISAS("hflags %08x saved %08x\n", ctx->hflags, ctx->saved_hflags);
if (do_save_pc && ctx->pc != ctx->saved_pc) {
gen_save_pc(ctx->pc);
gen_save_pc(ctx, ctx->pc);
ctx->saved_pc = ctx->pc;
}
if (ctx->hflags != ctx->saved_hflags) {
tcg_gen_movi_i32(hflags, ctx->hflags);
tcg_gen_movi_i32(tcg_ctx, tcg_ctx->hflags, ctx->hflags);
ctx->saved_hflags = ctx->hflags;
switch (ctx->hflags & MIPS_HFLAG_BMASK_BASE) {
case MIPS_HFLAG_BR:
@ -1569,7 +1571,7 @@ static inline void save_cpu_state(DisasContext *ctx, int do_save_pc)
case MIPS_HFLAG_BC:
case MIPS_HFLAG_BL:
case MIPS_HFLAG_B:
tcg_gen_movi_tl(btarget, ctx->btarget);
tcg_gen_movi_tl(tcg_ctx, *(TCGv *)tcg_ctx->btarget, ctx->btarget);
break;
}
}
@ -1591,31 +1593,41 @@ static inline void restore_cpu_state(CPUMIPSState *env, DisasContext *ctx)
static inline void generate_exception_err(DisasContext *ctx, int excp, int err)
{
TCGv_i32 texcp = tcg_const_i32(excp);
TCGv_i32 terr = tcg_const_i32(err);
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
TCGv_i32 texcp = tcg_const_i32(tcg_ctx, excp);
TCGv_i32 terr = tcg_const_i32(tcg_ctx, err);
save_cpu_state(ctx, 1);
gen_helper_raise_exception_err(cpu_env, texcp, terr);
tcg_temp_free_i32(terr);
tcg_temp_free_i32(texcp);
gen_helper_raise_exception_err(tcg_ctx, tcg_ctx->cpu_env, texcp, terr);
tcg_temp_free_i32(tcg_ctx, terr);
tcg_temp_free_i32(tcg_ctx, texcp);
}
static inline void generate_exception(DisasContext *ctx, int excp)
{
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
save_cpu_state(ctx, 1);
gen_helper_0e0i(raise_exception, excp);
gen_helper_0e0i(tcg_ctx, raise_exception, excp);
}
/* Floating point register moves. */
static void gen_load_fpr32(DisasContext *s, TCGv_i32 t, int reg)
static void gen_load_fpr32(DisasContext *ctx, TCGv_i32 t, int reg)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
if (ctx->hflags & MIPS_HFLAG_FRE) {
generate_exception(ctx, EXCP_RI);
}
tcg_gen_extrl_i64_i32(tcg_ctx, t, tcg_ctx->fpu_f64[reg]);
}
static void gen_store_fpr32(DisasContext *s, TCGv_i32 t, int reg)
static void gen_store_fpr32(DisasContext *ctx, TCGv_i32 t, int reg)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
TCGv_i64 t64 = tcg_temp_new_i64(tcg_ctx);
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
TCGv_i64 t64;
if (ctx->hflags & MIPS_HFLAG_FRE) {
generate_exception(ctx, EXCP_RI);
}
t64 = tcg_temp_new_i64(tcg_ctx);
tcg_gen_extu_i32_i64(tcg_ctx, t64, t);
tcg_gen_deposit_i64(tcg_ctx, tcg_ctx->fpu_f64[reg], tcg_ctx->fpu_f64[reg], t64, 0, 32);
tcg_temp_free_i64(tcg_ctx, t64);
@ -8523,7 +8535,8 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
gen_set_label(tcg_ctx, l1);
}
static inline void gen_movcf_s (DisasContext *ctx, int fs, int fd, int cc, int tf)
static inline void gen_movcf_s(DisasContext *ctx, int fs, int fd, int cc,
int tf)
{
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
int cond;

View file

@ -739,7 +739,7 @@ static const mips_def_t mips_defs[] =
(3 << CP0C4_IE) | (1 << CP0C4_M),
0,
0,
(1 << CP0C5_SBRI),
(1 << CP0C5_SBRI) | (1 << CP0C5_FRE) | (1 << CP0C5_UFE),
0,
0,
0,
@ -749,9 +749,9 @@ static const mips_def_t mips_defs[] =
0x30D8FFFF,
0,
0,
(1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
(1 << FCR0_D) | (1 << FCR0_S) | (0x00 << FCR0_PRID) |
(0x0 << FCR0_REV),
(1 << FCR0_FREP) | (1 << FCR0_F64) | (1 << FCR0_L) |
(1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) |
(0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
0,
42,
/* The architectural limit is 59, but we have hardcoded 36 bit