uint64_t PAMask;
bool mvh;
int CP0_LLAddr_shift;
+ bool ps;
} DisasContext;
enum {
}
}
+/* This code generates a "reserved instruction" exception if the
+ CPU does not support 64-bit paired-single (PS) floating point data type */
+static inline void check_ps(DisasContext *ctx)
+{
+ if (unlikely(!ctx->ps)) {
+ generate_exception(ctx, EXCP_RI);
+ }
+ check_cp1_64bitmode(ctx);
+}
+
#ifdef TARGET_MIPS64
/* This code generates a "reserved instruction" exception if 64-bit
instructions are not enabled. */
TCGv_i##bits fp1 = tcg_temp_new_i##bits (); \
switch (ifmt) { \
case FMT_PS: \
- check_cp1_64bitmode(ctx); \
+ check_ps(ctx); \
break; \
case FMT_D: \
if (abs) { \
};
enum { BINOP, CMPOP, OTHEROP } optype = OTHEROP;
uint32_t func = ctx->opcode & 0x3f;
-
switch (op1) {
case OPC_ADD_S:
{
opn = "cvt.l.s";
break;
case OPC_CVT_PS_S:
- check_insn_opc_removed(ctx, ISA_MIPS32R6);
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp64 = tcg_temp_new_i64();
TCGv_i32 fp32_0 = tcg_temp_new_i32();
opn = "cvt.d.l";
break;
case OPC_CVT_PS_PW:
- check_insn_opc_removed(ctx, ISA_MIPS32R6);
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
opn = "cvt.ps.pw";
break;
case OPC_ADD_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
TCGv_i64 fp1 = tcg_temp_new_i64();
opn = "add.ps";
break;
case OPC_SUB_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
TCGv_i64 fp1 = tcg_temp_new_i64();
opn = "sub.ps";
break;
case OPC_MUL_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
TCGv_i64 fp1 = tcg_temp_new_i64();
opn = "mul.ps";
break;
case OPC_ABS_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
opn = "abs.ps";
break;
case OPC_MOV_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
opn = "mov.ps";
break;
case OPC_NEG_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
opn = "neg.ps";
break;
case OPC_MOVCF_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
gen_movcf_ps(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1);
opn = "movcf.ps";
break;
case OPC_MOVZ_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGLabel *l1 = gen_new_label();
TCGv_i64 fp0;
opn = "movz.ps";
break;
case OPC_MOVN_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGLabel *l1 = gen_new_label();
TCGv_i64 fp0;
opn = "movn.ps";
break;
case OPC_ADDR_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
TCGv_i64 fp1 = tcg_temp_new_i64();
opn = "addr.ps";
break;
case OPC_MULR_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
TCGv_i64 fp1 = tcg_temp_new_i64();
opn = "mulr.ps";
break;
case OPC_RECIP2_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
TCGv_i64 fp1 = tcg_temp_new_i64();
opn = "recip2.ps";
break;
case OPC_RECIP1_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
opn = "recip1.ps";
break;
case OPC_RSQRT1_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
opn = "rsqrt1.ps";
break;
case OPC_RSQRT2_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
TCGv_i64 fp1 = tcg_temp_new_i64();
opn = "cvt.s.pu";
break;
case OPC_CVT_PW_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
opn = "cvt.s.pl";
break;
case OPC_PLL_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
TCGv_i32 fp1 = tcg_temp_new_i32();
opn = "pll.ps";
break;
case OPC_PLU_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
TCGv_i32 fp1 = tcg_temp_new_i32();
opn = "plu.ps";
break;
case OPC_PUL_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
TCGv_i32 fp1 = tcg_temp_new_i32();
opn = "pul.ps";
break;
case OPC_PUU_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
TCGv_i32 fp1 = tcg_temp_new_i32();
switch (opc) {
case OPC_ALNV_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv t0 = tcg_temp_local_new();
TCGv_i32 fp = tcg_temp_new_i32();
opn = "madd.d";
break;
case OPC_MADD_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
TCGv_i64 fp1 = tcg_temp_new_i64();
opn = "msub.d";
break;
case OPC_MSUB_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
TCGv_i64 fp1 = tcg_temp_new_i64();
opn = "nmadd.d";
break;
case OPC_NMADD_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
TCGv_i64 fp1 = tcg_temp_new_i64();
opn = "nmsub.d";
break;
case OPC_NMSUB_PS:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
TCGv_i64 fp1 = tcg_temp_new_i64();
gen_movcf_d(ctx, rs, rt, cc, 0);
break;
case FMT_SDPS_PS:
+ check_ps(ctx);
gen_movcf_ps(ctx, rs, rt, cc, 0);
break;
default:
gen_movcf_d(ctx, rs, rt, cc, 1);
break;
case FMT_SDPS_PS:
+ check_ps(ctx);
gen_movcf_ps(ctx, rs, rt, cc, 1);
break;
default:
mips32_op = OPC_##prfx##_D; \
goto do_fpop; \
case FMT_SDPS_PS: \
+ check_ps(ctx); \
mips32_op = OPC_##prfx##_PS; \
goto do_fpop; \
default: \
(rt >> 2) & 0x7, imm << 2);
break;
case OPC_PS_FMT:
- check_cp1_enabled(ctx);
- check_insn_opc_removed(ctx, ISA_MIPS32R6);
+ check_ps(ctx);
/* fall through */
case OPC_S_FMT:
case OPC_D_FMT:
/* Restore delay slot state from the tb context. */
ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */
ctx.ulri = (env->CP0_Config3 >> CP0C3_ULRI) & 1;
+ ctx.ps = ((env->active_fpu.fcr0 >> FCR0_PS) & 1) ||
+ (env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F));
restore_cpu_state(env, &ctx);
#ifdef CONFIG_USER_ONLY
ctx.mem_idx = MIPS_HFLAG_UM;