target-ppc: add support for extended mtfsf/mtfsfi forms

Power ISA 2.05 adds support for extended mtfsf/mtfsfi form, with a new
W field to select the upper part of the FPCSR register.

For that the helper is changed to handle 64-bit input values and mask with
up to 16 bits. The mtfsf/mtfsfi instructions do not have the W bit
marked as invalid anymore. Instead this is checked in the helper, which
therefore needs to access to the insns/insns_flags2. They are added in
the DisasContext struct. Finally change all accesses to the opcode fields
through extract helpers, prefixed with FP for consistency.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
Aurelien Jarno 2013-04-20 08:56:22 +00:00 committed by Alexander Graf
parent 44bc0c4d3e
commit 7d08d85645
2 changed files with 41 additions and 22 deletions

View File

@ -430,20 +430,17 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask) void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
{ {
/* target_ulong prev, new;
* We use only the 32 LSB of the incoming fpr
*/
uint32_t prev, new;
int i; int i;
prev = env->fpscr; prev = env->fpscr;
new = (uint32_t)arg; new = (target_ulong)arg;
new &= ~0x60000000; new &= ~0x60000000LL;
new |= prev & 0x60000000; new |= prev & 0x60000000LL;
for (i = 0; i < 8; i++) { for (i = 0; i < sizeof(target_ulong) * 2; i++) {
if (mask & (1 << i)) { if (mask & (1 << i)) {
env->fpscr &= ~(0xF << (4 * i)); env->fpscr &= ~(0xFLL << (4 * i));
env->fpscr |= new & (0xF << (4 * i)); env->fpscr |= new & (0xFLL << (4 * i));
} }
} }
/* Update VX and FEX */ /* Update VX and FEX */

View File

@ -202,6 +202,8 @@ typedef struct DisasContext {
int spe_enabled; int spe_enabled;
ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
int singlestep_enabled; int singlestep_enabled;
uint64_t insns_flags;
uint64_t insns_flags2;
} DisasContext; } DisasContext;
/* True when active word size < size of target_long. */ /* True when active word size < size of target_long. */
@ -423,9 +425,14 @@ EXTRACT_HELPER(ME, 1, 5);
EXTRACT_HELPER(TO, 21, 5); EXTRACT_HELPER(TO, 21, 5);
EXTRACT_HELPER(CRM, 12, 8); EXTRACT_HELPER(CRM, 12, 8);
EXTRACT_HELPER(FM, 17, 8);
EXTRACT_HELPER(SR, 16, 4); EXTRACT_HELPER(SR, 16, 4);
/* mtfsf/mtfsfi */
EXTRACT_HELPER(FPBF, 19, 3);
EXTRACT_HELPER(FPIMM, 12, 4); EXTRACT_HELPER(FPIMM, 12, 4);
EXTRACT_HELPER(FPL, 21, 1);
EXTRACT_HELPER(FPFLM, 17, 8);
EXTRACT_HELPER(FPW, 16, 1);
/*** Jump target decoding ***/ /*** Jump target decoding ***/
/* Displacement */ /* Displacement */
@ -2360,19 +2367,27 @@ static void gen_mtfsb1(DisasContext *ctx)
static void gen_mtfsf(DisasContext *ctx) static void gen_mtfsf(DisasContext *ctx)
{ {
TCGv_i32 t0; TCGv_i32 t0;
int L = ctx->opcode & 0x02000000; int flm, l, w;
if (unlikely(!ctx->fpu_enabled)) { if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU); gen_exception(ctx, POWERPC_EXCP_FPU);
return; return;
} }
flm = FPFLM(ctx->opcode);
l = FPL(ctx->opcode);
w = FPW(ctx->opcode);
if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
return;
}
/* NIP cannot be restored if the memory exception comes from an helper */ /* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4); gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus(); gen_reset_fpstatus();
if (L) if (l) {
t0 = tcg_const_i32(0xff); t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff);
else } else {
t0 = tcg_const_i32(FM(ctx->opcode)); t0 = tcg_const_i32(flm << (w * 8));
}
gen_helper_store_fpscr(cpu_env, cpu_fpr[rB(ctx->opcode)], t0); gen_helper_store_fpscr(cpu_env, cpu_fpr[rB(ctx->opcode)], t0);
tcg_temp_free_i32(t0); tcg_temp_free_i32(t0);
if (unlikely(Rc(ctx->opcode) != 0)) { if (unlikely(Rc(ctx->opcode) != 0)) {
@ -2386,7 +2401,7 @@ static void gen_mtfsf(DisasContext *ctx)
/* mtfsfi */ /* mtfsfi */
static void gen_mtfsfi(DisasContext *ctx) static void gen_mtfsfi(DisasContext *ctx)
{ {
int bf, sh; int bf, sh, w;
TCGv_i64 t0; TCGv_i64 t0;
TCGv_i32 t1; TCGv_i32 t1;
@ -2394,12 +2409,17 @@ static void gen_mtfsfi(DisasContext *ctx)
gen_exception(ctx, POWERPC_EXCP_FPU); gen_exception(ctx, POWERPC_EXCP_FPU);
return; return;
} }
bf = crbD(ctx->opcode) >> 2; w = FPW(ctx->opcode);
sh = 7 - bf; bf = FPBF(ctx->opcode);
if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
return;
}
sh = (8 * w) + 7 - bf;
/* NIP cannot be restored if the memory exception comes from an helper */ /* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4); gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus(); gen_reset_fpstatus();
t0 = tcg_const_i64(FPIMM(ctx->opcode) << (4 * sh)); t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh));
t1 = tcg_const_i32(1 << sh); t1 = tcg_const_i32(1 << sh);
gen_helper_store_fpscr(cpu_env, t0, t1); gen_helper_store_fpscr(cpu_env, t0, t1);
tcg_temp_free_i64(t0); tcg_temp_free_i64(t0);
@ -8689,8 +8709,8 @@ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT),
GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT),
GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT),
GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT),
GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00010000, PPC_FLOAT), GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT),
GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT), GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006e0800, PPC_FLOAT),
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B), GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B),
GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX), GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX),
@ -9728,6 +9748,8 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env,
ctx.exception = POWERPC_EXCP_NONE; ctx.exception = POWERPC_EXCP_NONE;
ctx.spr_cb = env->spr_cb; ctx.spr_cb = env->spr_cb;
ctx.mem_idx = env->mmu_idx; ctx.mem_idx = env->mmu_idx;
ctx.insns_flags = env->insns_flags;
ctx.insns_flags2 = env->insns_flags2;
ctx.access_type = -1; ctx.access_type = -1;
ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0; ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0;
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)