Commit b8aa4598 authored by Thiemo Seufer's avatar Thiemo Seufer
Browse files

MIPS COP1X (and related) instructions, by Richard Sandiford.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3877 c046a42c-6fe2-441c-8c8c-71466251a162
parent 6341fdcb
Loading
Loading
Loading
Loading
+11 −7
Original line number Diff line number Diff line
@@ -417,7 +417,7 @@ struct CPUMIPSState {
    int user_mode_only; /* user mode only simulation */
    uint32_t hflags;    /* CPU State */
    /* TMASK defines different execution modes */
#define MIPS_HFLAG_TMASK  0x00FF
#define MIPS_HFLAG_TMASK  0x01FF
#define MIPS_HFLAG_MODE   0x0007 /* 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
@@ -431,16 +431,20 @@ struct CPUMIPSState {
#define MIPS_HFLAG_CP0    0x0010 /* CP0 enabled                        */
#define MIPS_HFLAG_FPU    0x0020 /* FPU enabled                        */
#define MIPS_HFLAG_F64    0x0040 /* 64-bit FPU enabled                 */
#define MIPS_HFLAG_RE     0x0080 /* Reversed endianness                */
    /* True if the MIPS IV COP1X instructions can be used.  This also
       controls the non-COP1X instructions RECIP.S, RECIP.D, RSQRT.S
       and RSQRT.D.  */
#define MIPS_HFLAG_COP1X  0x0080 /* COP1X instructions enabled         */
#define MIPS_HFLAG_RE     0x0100 /* Reversed endianness                */
    /* If translation is interrupted between the branch instruction and
     * the delay slot, record what type of branch it is so that we can
     * resume translation properly.  It might be possible to reduce
     * this from three bits to two.  */
#define MIPS_HFLAG_BMASK  0x0700
#define MIPS_HFLAG_B      0x0100 /* Unconditional branch               */
#define MIPS_HFLAG_BC     0x0200 /* Conditional branch                 */
#define MIPS_HFLAG_BL     0x0300 /* Likely branch                      */
#define MIPS_HFLAG_BR     0x0400 /* branch to register (can't link TB) */
#define MIPS_HFLAG_BMASK  0x0e00
#define MIPS_HFLAG_B      0x0200 /* Unconditional branch               */
#define MIPS_HFLAG_BC     0x0400 /* Conditional branch                 */
#define MIPS_HFLAG_BL     0x0600 /* Likely branch                      */
#define MIPS_HFLAG_BR     0x0800 /* branch to register (can't link TB) */
    target_ulong btarget;        /* Jump / branch target               */
    int bcond;                   /* Branch condition (if needed)       */

+16 −2
Original line number Diff line number Diff line
@@ -237,8 +237,8 @@ static always_inline int cpu_halted(CPUState *env)

static always_inline void compute_hflags(CPUState *env)
{
    env->hflags &= ~(MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 |
                     MIPS_HFLAG_FPU | MIPS_HFLAG_KSU);
    env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
                     MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU);
    if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
        !(env->CP0_Status & (1 << CP0St_ERL)) &&
        !(env->hflags & MIPS_HFLAG_DM)) {
@@ -257,6 +257,20 @@ static always_inline void compute_hflags(CPUState *env)
        env->hflags |= MIPS_HFLAG_FPU;
    if (env->CP0_Status & (1 << CP0St_FR))
        env->hflags |= MIPS_HFLAG_F64;
    if (env->insn_flags & ISA_MIPS32R2) {
        if (env->fpu->fcr0 & FCR0_F64)
            env->hflags |= MIPS_HFLAG_COP1X;
    } else if (env->insn_flags & ISA_MIPS32) {
        if (env->hflags & MIPS_HFLAG_64)
            env->hflags |= MIPS_HFLAG_COP1X;
    } else if (env->insn_flags & ISA_MIPS4) {
        /* All supported MIPS IV CPUs use the XX (CU3) to enable
           and disable the MIPS IV extensions to the MIPS III ISA.
           Some other MIPS IV CPUs ignore the bit, so the check here
           would be too restrictive for them.  */
        if (env->CP0_Status & (1 << CP0St_CU3))
            env->hflags |= MIPS_HFLAG_COP1X;
    }
}

#endif /* !defined(__QEMU_MIPS_EXEC_H__) */
+47 −9
Original line number Diff line number Diff line
@@ -794,9 +794,22 @@ static always_inline void check_cp1_enabled(DisasContext *ctx)
        generate_exception_err(ctx, EXCP_CpU, 1);
}

/* Verify that the processor is running with COP1X instructions enabled.
   This is associated with the nabla symbol in the MIPS32 and MIPS64
   opcode tables.  */

static always_inline void check_cop1x(DisasContext *ctx)
{
    if (unlikely(!(ctx->hflags & MIPS_HFLAG_COP1X)))
        generate_exception(ctx, EXCP_RI);
}

/* Verify that the processor is running with 64-bit floating-point
   operations enabled.  */

static always_inline void check_cp1_64bitmode(DisasContext *ctx)
{
    if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64)))
    if (unlikely(~ctx->hflags & (MIPS_HFLAG_F64 | MIPS_HFLAG_COP1X)))
        generate_exception(ctx, EXCP_RI);
}

@@ -5178,12 +5191,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
        opn = "movn.s";
        break;
    case FOP(21, 16):
        check_cop1x(ctx);
        GEN_LOAD_FREG_FTN(WT0, fs);
        gen_op_float_recip_s();
        GEN_STORE_FTN_FREG(fd, WT2);
        opn = "recip.s";
        break;
    case FOP(22, 16):
        check_cop1x(ctx);
        GEN_LOAD_FREG_FTN(WT0, fs);
        gen_op_float_rsqrt_s();
        GEN_STORE_FTN_FREG(fd, WT2);
@@ -5266,7 +5281,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
        GEN_LOAD_FREG_FTN(WT0, fs);
        GEN_LOAD_FREG_FTN(WT1, ft);
        if (ctx->opcode & (1 << 6)) {
            check_cp1_64bitmode(ctx);
            check_cop1x(ctx);
            gen_cmpabs_s(func-48, cc);
            opn = condnames_abs[func-48];
        } else {
@@ -5419,14 +5434,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
        opn = "movn.d";
        break;
    case FOP(21, 17):
        check_cp1_registers(ctx, fs | fd);
        check_cp1_64bitmode(ctx);
        GEN_LOAD_FREG_FTN(DT0, fs);
        gen_op_float_recip_d();
        GEN_STORE_FTN_FREG(fd, DT2);
        opn = "recip.d";
        break;
    case FOP(22, 17):
        check_cp1_registers(ctx, fs | fd);
        check_cp1_64bitmode(ctx);
        GEN_LOAD_FREG_FTN(DT0, fs);
        gen_op_float_rsqrt_d();
        GEN_STORE_FTN_FREG(fd, DT2);
@@ -5481,7 +5496,8 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
        GEN_LOAD_FREG_FTN(DT0, fs);
        GEN_LOAD_FREG_FTN(DT1, ft);
        if (ctx->opcode & (1 << 6)) {
            check_cp1_64bitmode(ctx);
            check_cop1x(ctx);
            check_cp1_registers(ctx, fs | ft);
            gen_cmpabs_d(func-48, cc);
            opn = condnames_abs[func-48];
        } else {
@@ -5814,8 +5830,6 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc,
    const char *opn = "extended float load/store";
    int store = 0;

    /* All of those work only on 64bit FPUs. */
    check_cp1_64bitmode(ctx);
    if (base == 0) {
        if (index == 0)
            gen_op_reset_T0();
@@ -5832,33 +5846,41 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc,
       memory access. */
    switch (opc) {
    case OPC_LWXC1:
        check_cop1x(ctx);
        op_ldst(lwc1);
        GEN_STORE_FTN_FREG(fd, WT0);
        opn = "lwxc1";
        break;
    case OPC_LDXC1:
        check_cop1x(ctx);
        check_cp1_registers(ctx, fd);
        op_ldst(ldc1);
        GEN_STORE_FTN_FREG(fd, DT0);
        opn = "ldxc1";
        break;
    case OPC_LUXC1:
        check_cp1_64bitmode(ctx);
        op_ldst(luxc1);
        GEN_STORE_FTN_FREG(fd, DT0);
        opn = "luxc1";
        break;
    case OPC_SWXC1:
        check_cop1x(ctx);
        GEN_LOAD_FREG_FTN(WT0, fs);
        op_ldst(swc1);
        opn = "swxc1";
        store = 1;
        break;
    case OPC_SDXC1:
        check_cop1x(ctx);
        check_cp1_registers(ctx, fs);
        GEN_LOAD_FREG_FTN(DT0, fs);
        op_ldst(sdc1);
        opn = "sdxc1";
        store = 1;
        break;
    case OPC_SUXC1:
        check_cp1_64bitmode(ctx);
        GEN_LOAD_FREG_FTN(DT0, fs);
        op_ldst(suxc1);
        opn = "suxc1";
@@ -5878,10 +5900,9 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
{
    const char *opn = "flt3_arith";

    /* All of those work only on 64bit FPUs. */
    check_cp1_64bitmode(ctx);
    switch (opc) {
    case OPC_ALNV_PS:
        check_cp1_64bitmode(ctx);
        GEN_LOAD_REG_T0(fr);
        GEN_LOAD_FREG_FTN(DT0, fs);
        GEN_LOAD_FREG_FTN(DT1, ft);
@@ -5890,6 +5911,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
        opn = "alnv.ps";
        break;
    case OPC_MADD_S:
        check_cop1x(ctx);
        GEN_LOAD_FREG_FTN(WT0, fs);
        GEN_LOAD_FREG_FTN(WT1, ft);
        GEN_LOAD_FREG_FTN(WT2, fr);
@@ -5898,6 +5920,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
        opn = "madd.s";
        break;
    case OPC_MADD_D:
        check_cop1x(ctx);
        check_cp1_registers(ctx, fd | fs | ft | fr);
        GEN_LOAD_FREG_FTN(DT0, fs);
        GEN_LOAD_FREG_FTN(DT1, ft);
        GEN_LOAD_FREG_FTN(DT2, fr);
@@ -5906,6 +5930,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
        opn = "madd.d";
        break;
    case OPC_MADD_PS:
        check_cp1_64bitmode(ctx);
        GEN_LOAD_FREG_FTN(WT0, fs);
        GEN_LOAD_FREG_FTN(WTH0, fs);
        GEN_LOAD_FREG_FTN(WT1, ft);
@@ -5918,6 +5943,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
        opn = "madd.ps";
        break;
    case OPC_MSUB_S:
        check_cop1x(ctx);
        GEN_LOAD_FREG_FTN(WT0, fs);
        GEN_LOAD_FREG_FTN(WT1, ft);
        GEN_LOAD_FREG_FTN(WT2, fr);
@@ -5926,6 +5952,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
        opn = "msub.s";
        break;
    case OPC_MSUB_D:
        check_cop1x(ctx);
        check_cp1_registers(ctx, fd | fs | ft | fr);
        GEN_LOAD_FREG_FTN(DT0, fs);
        GEN_LOAD_FREG_FTN(DT1, ft);
        GEN_LOAD_FREG_FTN(DT2, fr);
@@ -5934,6 +5962,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
        opn = "msub.d";
        break;
    case OPC_MSUB_PS:
        check_cp1_64bitmode(ctx);
        GEN_LOAD_FREG_FTN(WT0, fs);
        GEN_LOAD_FREG_FTN(WTH0, fs);
        GEN_LOAD_FREG_FTN(WT1, ft);
@@ -5946,6 +5975,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
        opn = "msub.ps";
        break;
    case OPC_NMADD_S:
        check_cop1x(ctx);
        GEN_LOAD_FREG_FTN(WT0, fs);
        GEN_LOAD_FREG_FTN(WT1, ft);
        GEN_LOAD_FREG_FTN(WT2, fr);
@@ -5954,6 +5984,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
        opn = "nmadd.s";
        break;
    case OPC_NMADD_D:
        check_cop1x(ctx);
        check_cp1_registers(ctx, fd | fs | ft | fr);
        GEN_LOAD_FREG_FTN(DT0, fs);
        GEN_LOAD_FREG_FTN(DT1, ft);
        GEN_LOAD_FREG_FTN(DT2, fr);
@@ -5962,6 +5994,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
        opn = "nmadd.d";
        break;
    case OPC_NMADD_PS:
        check_cp1_64bitmode(ctx);
        GEN_LOAD_FREG_FTN(WT0, fs);
        GEN_LOAD_FREG_FTN(WTH0, fs);
        GEN_LOAD_FREG_FTN(WT1, ft);
@@ -5974,6 +6007,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
        opn = "nmadd.ps";
        break;
    case OPC_NMSUB_S:
        check_cop1x(ctx);
        GEN_LOAD_FREG_FTN(WT0, fs);
        GEN_LOAD_FREG_FTN(WT1, ft);
        GEN_LOAD_FREG_FTN(WT2, fr);
@@ -5982,6 +6016,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
        opn = "nmsub.s";
        break;
    case OPC_NMSUB_D:
        check_cop1x(ctx);
        check_cp1_registers(ctx, fd | fs | ft | fr);
        GEN_LOAD_FREG_FTN(DT0, fs);
        GEN_LOAD_FREG_FTN(DT1, ft);
        GEN_LOAD_FREG_FTN(DT2, fr);
@@ -5990,6 +6026,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
        opn = "nmsub.d";
        break;
    case OPC_NMSUB_PS:
        check_cp1_64bitmode(ctx);
        GEN_LOAD_FREG_FTN(WT0, fs);
        GEN_LOAD_FREG_FTN(WTH0, fs);
        GEN_LOAD_FREG_FTN(WT1, ft);
@@ -6465,6 +6502,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
#endif
            case OPC_BC1ANY2:
            case OPC_BC1ANY4:
                check_cop1x(ctx);
                check_insn(env, ctx, ASE_MIPS3D);
                /* fall through */
            case OPC_BC1: