Skip to content

Commit

Permalink
target-ppc: Extend FPU state for newer POWER CPUs
Browse files Browse the repository at this point in the history
This patch adds some extra FPU state to CPUPPCState.  Specifically,
fpscr is extended to a target_ulong bits, since some recent (64 bit)
CPUs now have more status bits than fit inside 32 bits.  Also, we add
the 32 VSR registers present on CPUs with VSX (these extend the
standard FP regs, which together with the Altivec/VMX registers form a
64 x 128bit register file for VSX).

We don't actually support the instructions using these extra registers
in TCG yet, but we still need a place to store the state so we can
sync it with KVM and savevm/loadvm it.  This patch updates the savevm
code to not fail on the extended state, but also does not actually
save it - that's a project for another patch.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
  • Loading branch information
dgibson authored and agraf committed Nov 1, 2012
1 parent ac7d12b commit 3030442
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 14 deletions.
4 changes: 3 additions & 1 deletion target-ppc/cpu.h
Expand Up @@ -963,7 +963,7 @@ struct CPUPPCState {
/* floating point registers */
float64 fpr[32];
/* floating point status and control register */
uint32_t fpscr;
target_ulong fpscr;

/* Next instruction pointer */
target_ulong nip;
Expand Down Expand Up @@ -1014,6 +1014,8 @@ struct CPUPPCState {
/* Altivec registers */
ppc_avr_t avr[32];
uint32_t vscr;
/* VSX registers */
uint64_t vsr[32];
/* SPE registers */
uint64_t spe_acc;
uint32_t spe_fscr;
Expand Down
8 changes: 6 additions & 2 deletions target-ppc/machine.c
Expand Up @@ -6,6 +6,7 @@ void cpu_save(QEMUFile *f, void *opaque)
{
CPUPPCState *env = (CPUPPCState *)opaque;
unsigned int i, j;
uint32_t fpscr;

for (i = 0; i < 32; i++)
qemu_put_betls(f, &env->gpr[i]);
Expand All @@ -30,7 +31,8 @@ void cpu_save(QEMUFile *f, void *opaque)
u.d = env->fpr[i];
qemu_put_be64(f, u.l);
}
qemu_put_be32s(f, &env->fpscr);
fpscr = env->fpscr;
qemu_put_be32s(f, &fpscr);
qemu_put_sbe32s(f, &env->access_type);
#if defined(TARGET_PPC64)
qemu_put_betls(f, &env->asr);
Expand Down Expand Up @@ -90,6 +92,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
CPUPPCState *env = (CPUPPCState *)opaque;
unsigned int i, j;
target_ulong sdr1;
uint32_t fpscr;

for (i = 0; i < 32; i++)
qemu_get_betls(f, &env->gpr[i]);
Expand All @@ -114,7 +117,8 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
u.l = qemu_get_be64(f);
env->fpr[i] = u.d;
}
qemu_get_be32s(f, &env->fpscr);
qemu_get_be32s(f, &fpscr);
env->fpscr = fpscr;
qemu_get_sbe32s(f, &env->access_type);
#if defined(TARGET_PPC64)
qemu_get_betls(f, &env->asr);
Expand Down
29 changes: 18 additions & 11 deletions target-ppc/translate.c
Expand Up @@ -68,7 +68,7 @@ static TCGv cpu_cfar;
#endif
static TCGv cpu_xer;
static TCGv cpu_reserve;
static TCGv_i32 cpu_fpscr;
static TCGv cpu_fpscr;
static TCGv_i32 cpu_access_type;

#include "gen-icount.h"
Expand Down Expand Up @@ -163,8 +163,8 @@ void ppc_translate_init(void)
offsetof(CPUPPCState, reserve_addr),
"reserve_addr");

cpu_fpscr = tcg_global_mem_new_i32(TCG_AREG0,
offsetof(CPUPPCState, fpscr), "fpscr");
cpu_fpscr = tcg_global_mem_new(TCG_AREG0,
offsetof(CPUPPCState, fpscr), "fpscr");

cpu_access_type = tcg_global_mem_new_i32(TCG_AREG0,
offsetof(CPUPPCState, access_type), "access_type");
Expand Down Expand Up @@ -2302,16 +2302,19 @@ GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT);
/* mcrfs */
static void gen_mcrfs(DisasContext *ctx)
{
TCGv tmp = tcg_temp_new();
int bfa;

if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
bfa = 4 * (7 - crfS(ctx->opcode));
tcg_gen_shri_i32(cpu_crf[crfD(ctx->opcode)], cpu_fpscr, bfa);
tcg_gen_shri_tl(tmp, cpu_fpscr, bfa);
tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], tmp);
tcg_temp_free(tmp);
tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], 0xf);
tcg_gen_andi_i32(cpu_fpscr, cpu_fpscr, ~(0xF << bfa));
tcg_gen_andi_tl(cpu_fpscr, cpu_fpscr, ~(0xF << bfa));
}

/* mffs */
Expand All @@ -2322,7 +2325,7 @@ static void gen_mffs(DisasContext *ctx)
return;
}
gen_reset_fpstatus();
tcg_gen_extu_i32_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpscr);
tcg_gen_extu_tl_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpscr);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0);
}

Expand All @@ -2346,7 +2349,8 @@ static void gen_mtfsb0(DisasContext *ctx)
tcg_temp_free_i32(t0);
}
if (unlikely(Rc(ctx->opcode) != 0)) {
tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
}
}

Expand All @@ -2371,7 +2375,8 @@ static void gen_mtfsb1(DisasContext *ctx)
tcg_temp_free_i32(t0);
}
if (unlikely(Rc(ctx->opcode) != 0)) {
tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
}
/* We can raise a differed exception */
gen_helper_float_check_status(cpu_env);
Expand All @@ -2397,7 +2402,8 @@ static void gen_mtfsf(DisasContext *ctx)
gen_helper_store_fpscr(cpu_env, cpu_fpr[rB(ctx->opcode)], t0);
tcg_temp_free_i32(t0);
if (unlikely(Rc(ctx->opcode) != 0)) {
tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
}
/* We can raise a differed exception */
gen_helper_float_check_status(cpu_env);
Expand Down Expand Up @@ -2425,7 +2431,8 @@ static void gen_mtfsfi(DisasContext *ctx)
tcg_temp_free_i64(t0);
tcg_temp_free_i32(t1);
if (unlikely(Rc(ctx->opcode) != 0)) {
tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
}
/* We can raise a differed exception */
gen_helper_float_check_status(cpu_env);
Expand Down Expand Up @@ -9463,7 +9470,7 @@ void cpu_dump_state (CPUPPCState *env, FILE *f, fprintf_function cpu_fprintf,
if ((i & (RFPL - 1)) == (RFPL - 1))
cpu_fprintf(f, "\n");
}
cpu_fprintf(f, "FPSCR %08x\n", env->fpscr);
cpu_fprintf(f, "FPSCR " TARGET_FMT_lx "\n", env->fpscr);
#if !defined(CONFIG_USER_ONLY)
cpu_fprintf(f, " SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx
" PVR " TARGET_FMT_lx " VRSAVE " TARGET_FMT_lx "\n",
Expand Down

0 comments on commit 3030442

Please sign in to comment.