mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-23 10:55:34 +00:00
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:
parent
428ffed744
commit
c54458b638
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue