Commit b8aa4598e2cc109b0884740a42116acaab01e67d
1 parent
6341fdcb
MIPS COP1X (and related) instructions, by Richard Sandiford.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3877 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
74 additions
and
18 deletions
target-mips/cpu.h
| @@ -417,7 +417,7 @@ struct CPUMIPSState { | @@ -417,7 +417,7 @@ struct CPUMIPSState { | ||
| 417 | int user_mode_only; /* user mode only simulation */ | 417 | int user_mode_only; /* user mode only simulation */ |
| 418 | uint32_t hflags; /* CPU State */ | 418 | uint32_t hflags; /* CPU State */ |
| 419 | /* TMASK defines different execution modes */ | 419 | /* TMASK defines different execution modes */ |
| 420 | -#define MIPS_HFLAG_TMASK 0x00FF | 420 | +#define MIPS_HFLAG_TMASK 0x01FF |
| 421 | #define MIPS_HFLAG_MODE 0x0007 /* execution modes */ | 421 | #define MIPS_HFLAG_MODE 0x0007 /* execution modes */ |
| 422 | /* The KSU flags must be the lowest bits in hflags. The flag order | 422 | /* The KSU flags must be the lowest bits in hflags. The flag order |
| 423 | must be the same as defined for CP0 Status. This allows to use | 423 | must be the same as defined for CP0 Status. This allows to use |
| @@ -431,16 +431,20 @@ struct CPUMIPSState { | @@ -431,16 +431,20 @@ struct CPUMIPSState { | ||
| 431 | #define MIPS_HFLAG_CP0 0x0010 /* CP0 enabled */ | 431 | #define MIPS_HFLAG_CP0 0x0010 /* CP0 enabled */ |
| 432 | #define MIPS_HFLAG_FPU 0x0020 /* FPU enabled */ | 432 | #define MIPS_HFLAG_FPU 0x0020 /* FPU enabled */ |
| 433 | #define MIPS_HFLAG_F64 0x0040 /* 64-bit FPU enabled */ | 433 | #define MIPS_HFLAG_F64 0x0040 /* 64-bit FPU enabled */ |
| 434 | -#define MIPS_HFLAG_RE 0x0080 /* Reversed endianness */ | 434 | + /* True if the MIPS IV COP1X instructions can be used. This also |
| 435 | + controls the non-COP1X instructions RECIP.S, RECIP.D, RSQRT.S | ||
| 436 | + and RSQRT.D. */ | ||
| 437 | +#define MIPS_HFLAG_COP1X 0x0080 /* COP1X instructions enabled */ | ||
| 438 | +#define MIPS_HFLAG_RE 0x0100 /* Reversed endianness */ | ||
| 435 | /* If translation is interrupted between the branch instruction and | 439 | /* If translation is interrupted between the branch instruction and |
| 436 | * the delay slot, record what type of branch it is so that we can | 440 | * the delay slot, record what type of branch it is so that we can |
| 437 | * resume translation properly. It might be possible to reduce | 441 | * resume translation properly. It might be possible to reduce |
| 438 | * this from three bits to two. */ | 442 | * this from three bits to two. */ |
| 439 | -#define MIPS_HFLAG_BMASK 0x0700 | ||
| 440 | -#define MIPS_HFLAG_B 0x0100 /* Unconditional branch */ | ||
| 441 | -#define MIPS_HFLAG_BC 0x0200 /* Conditional branch */ | ||
| 442 | -#define MIPS_HFLAG_BL 0x0300 /* Likely branch */ | ||
| 443 | -#define MIPS_HFLAG_BR 0x0400 /* branch to register (can't link TB) */ | 443 | +#define MIPS_HFLAG_BMASK 0x0e00 |
| 444 | +#define MIPS_HFLAG_B 0x0200 /* Unconditional branch */ | ||
| 445 | +#define MIPS_HFLAG_BC 0x0400 /* Conditional branch */ | ||
| 446 | +#define MIPS_HFLAG_BL 0x0600 /* Likely branch */ | ||
| 447 | +#define MIPS_HFLAG_BR 0x0800 /* branch to register (can't link TB) */ | ||
| 444 | target_ulong btarget; /* Jump / branch target */ | 448 | target_ulong btarget; /* Jump / branch target */ |
| 445 | int bcond; /* Branch condition (if needed) */ | 449 | int bcond; /* Branch condition (if needed) */ |
| 446 | 450 |
target-mips/exec.h
| @@ -237,8 +237,8 @@ static always_inline int cpu_halted(CPUState *env) | @@ -237,8 +237,8 @@ static always_inline int cpu_halted(CPUState *env) | ||
| 237 | 237 | ||
| 238 | static always_inline void compute_hflags(CPUState *env) | 238 | static always_inline void compute_hflags(CPUState *env) |
| 239 | { | 239 | { |
| 240 | - env->hflags &= ~(MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 | | ||
| 241 | - MIPS_HFLAG_FPU | MIPS_HFLAG_KSU); | 240 | + env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | |
| 241 | + MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU); | ||
| 242 | if (!(env->CP0_Status & (1 << CP0St_EXL)) && | 242 | if (!(env->CP0_Status & (1 << CP0St_EXL)) && |
| 243 | !(env->CP0_Status & (1 << CP0St_ERL)) && | 243 | !(env->CP0_Status & (1 << CP0St_ERL)) && |
| 244 | !(env->hflags & MIPS_HFLAG_DM)) { | 244 | !(env->hflags & MIPS_HFLAG_DM)) { |
| @@ -257,6 +257,20 @@ static always_inline void compute_hflags(CPUState *env) | @@ -257,6 +257,20 @@ static always_inline void compute_hflags(CPUState *env) | ||
| 257 | env->hflags |= MIPS_HFLAG_FPU; | 257 | env->hflags |= MIPS_HFLAG_FPU; |
| 258 | if (env->CP0_Status & (1 << CP0St_FR)) | 258 | if (env->CP0_Status & (1 << CP0St_FR)) |
| 259 | env->hflags |= MIPS_HFLAG_F64; | 259 | env->hflags |= MIPS_HFLAG_F64; |
| 260 | + if (env->insn_flags & ISA_MIPS32R2) { | ||
| 261 | + if (env->fpu->fcr0 & FCR0_F64) | ||
| 262 | + env->hflags |= MIPS_HFLAG_COP1X; | ||
| 263 | + } else if (env->insn_flags & ISA_MIPS32) { | ||
| 264 | + if (env->hflags & MIPS_HFLAG_64) | ||
| 265 | + env->hflags |= MIPS_HFLAG_COP1X; | ||
| 266 | + } else if (env->insn_flags & ISA_MIPS4) { | ||
| 267 | + /* All supported MIPS IV CPUs use the XX (CU3) to enable | ||
| 268 | + and disable the MIPS IV extensions to the MIPS III ISA. | ||
| 269 | + Some other MIPS IV CPUs ignore the bit, so the check here | ||
| 270 | + would be too restrictive for them. */ | ||
| 271 | + if (env->CP0_Status & (1 << CP0St_CU3)) | ||
| 272 | + env->hflags |= MIPS_HFLAG_COP1X; | ||
| 273 | + } | ||
| 260 | } | 274 | } |
| 261 | 275 | ||
| 262 | #endif /* !defined(__QEMU_MIPS_EXEC_H__) */ | 276 | #endif /* !defined(__QEMU_MIPS_EXEC_H__) */ |
target-mips/translate.c
| @@ -794,9 +794,22 @@ static always_inline void check_cp1_enabled(DisasContext *ctx) | @@ -794,9 +794,22 @@ static always_inline void check_cp1_enabled(DisasContext *ctx) | ||
| 794 | generate_exception_err(ctx, EXCP_CpU, 1); | 794 | generate_exception_err(ctx, EXCP_CpU, 1); |
| 795 | } | 795 | } |
| 796 | 796 | ||
| 797 | +/* Verify that the processor is running with COP1X instructions enabled. | ||
| 798 | + This is associated with the nabla symbol in the MIPS32 and MIPS64 | ||
| 799 | + opcode tables. */ | ||
| 800 | + | ||
| 801 | +static always_inline void check_cop1x(DisasContext *ctx) | ||
| 802 | +{ | ||
| 803 | + if (unlikely(!(ctx->hflags & MIPS_HFLAG_COP1X))) | ||
| 804 | + generate_exception(ctx, EXCP_RI); | ||
| 805 | +} | ||
| 806 | + | ||
| 807 | +/* Verify that the processor is running with 64-bit floating-point | ||
| 808 | + operations enabled. */ | ||
| 809 | + | ||
| 797 | static always_inline void check_cp1_64bitmode(DisasContext *ctx) | 810 | static always_inline void check_cp1_64bitmode(DisasContext *ctx) |
| 798 | { | 811 | { |
| 799 | - if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64))) | 812 | + if (unlikely(~ctx->hflags & (MIPS_HFLAG_F64 | MIPS_HFLAG_COP1X))) |
| 800 | generate_exception(ctx, EXCP_RI); | 813 | generate_exception(ctx, EXCP_RI); |
| 801 | } | 814 | } |
| 802 | 815 | ||
| @@ -5178,12 +5191,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, | @@ -5178,12 +5191,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, | ||
| 5178 | opn = "movn.s"; | 5191 | opn = "movn.s"; |
| 5179 | break; | 5192 | break; |
| 5180 | case FOP(21, 16): | 5193 | case FOP(21, 16): |
| 5194 | + check_cop1x(ctx); | ||
| 5181 | GEN_LOAD_FREG_FTN(WT0, fs); | 5195 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 5182 | gen_op_float_recip_s(); | 5196 | gen_op_float_recip_s(); |
| 5183 | GEN_STORE_FTN_FREG(fd, WT2); | 5197 | GEN_STORE_FTN_FREG(fd, WT2); |
| 5184 | opn = "recip.s"; | 5198 | opn = "recip.s"; |
| 5185 | break; | 5199 | break; |
| 5186 | case FOP(22, 16): | 5200 | case FOP(22, 16): |
| 5201 | + check_cop1x(ctx); | ||
| 5187 | GEN_LOAD_FREG_FTN(WT0, fs); | 5202 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 5188 | gen_op_float_rsqrt_s(); | 5203 | gen_op_float_rsqrt_s(); |
| 5189 | GEN_STORE_FTN_FREG(fd, WT2); | 5204 | GEN_STORE_FTN_FREG(fd, WT2); |
| @@ -5266,7 +5281,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, | @@ -5266,7 +5281,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, | ||
| 5266 | GEN_LOAD_FREG_FTN(WT0, fs); | 5281 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 5267 | GEN_LOAD_FREG_FTN(WT1, ft); | 5282 | GEN_LOAD_FREG_FTN(WT1, ft); |
| 5268 | if (ctx->opcode & (1 << 6)) { | 5283 | if (ctx->opcode & (1 << 6)) { |
| 5269 | - check_cp1_64bitmode(ctx); | 5284 | + check_cop1x(ctx); |
| 5270 | gen_cmpabs_s(func-48, cc); | 5285 | gen_cmpabs_s(func-48, cc); |
| 5271 | opn = condnames_abs[func-48]; | 5286 | opn = condnames_abs[func-48]; |
| 5272 | } else { | 5287 | } else { |
| @@ -5419,14 +5434,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, | @@ -5419,14 +5434,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, | ||
| 5419 | opn = "movn.d"; | 5434 | opn = "movn.d"; |
| 5420 | break; | 5435 | break; |
| 5421 | case FOP(21, 17): | 5436 | case FOP(21, 17): |
| 5422 | - check_cp1_registers(ctx, fs | fd); | 5437 | + check_cp1_64bitmode(ctx); |
| 5423 | GEN_LOAD_FREG_FTN(DT0, fs); | 5438 | GEN_LOAD_FREG_FTN(DT0, fs); |
| 5424 | gen_op_float_recip_d(); | 5439 | gen_op_float_recip_d(); |
| 5425 | GEN_STORE_FTN_FREG(fd, DT2); | 5440 | GEN_STORE_FTN_FREG(fd, DT2); |
| 5426 | opn = "recip.d"; | 5441 | opn = "recip.d"; |
| 5427 | break; | 5442 | break; |
| 5428 | case FOP(22, 17): | 5443 | case FOP(22, 17): |
| 5429 | - check_cp1_registers(ctx, fs | fd); | 5444 | + check_cp1_64bitmode(ctx); |
| 5430 | GEN_LOAD_FREG_FTN(DT0, fs); | 5445 | GEN_LOAD_FREG_FTN(DT0, fs); |
| 5431 | gen_op_float_rsqrt_d(); | 5446 | gen_op_float_rsqrt_d(); |
| 5432 | GEN_STORE_FTN_FREG(fd, DT2); | 5447 | GEN_STORE_FTN_FREG(fd, DT2); |
| @@ -5481,7 +5496,8 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, | @@ -5481,7 +5496,8 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, | ||
| 5481 | GEN_LOAD_FREG_FTN(DT0, fs); | 5496 | GEN_LOAD_FREG_FTN(DT0, fs); |
| 5482 | GEN_LOAD_FREG_FTN(DT1, ft); | 5497 | GEN_LOAD_FREG_FTN(DT1, ft); |
| 5483 | if (ctx->opcode & (1 << 6)) { | 5498 | if (ctx->opcode & (1 << 6)) { |
| 5484 | - check_cp1_64bitmode(ctx); | 5499 | + check_cop1x(ctx); |
| 5500 | + check_cp1_registers(ctx, fs | ft); | ||
| 5485 | gen_cmpabs_d(func-48, cc); | 5501 | gen_cmpabs_d(func-48, cc); |
| 5486 | opn = condnames_abs[func-48]; | 5502 | opn = condnames_abs[func-48]; |
| 5487 | } else { | 5503 | } else { |
| @@ -5814,8 +5830,6 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, | @@ -5814,8 +5830,6 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, | ||
| 5814 | const char *opn = "extended float load/store"; | 5830 | const char *opn = "extended float load/store"; |
| 5815 | int store = 0; | 5831 | int store = 0; |
| 5816 | 5832 | ||
| 5817 | - /* All of those work only on 64bit FPUs. */ | ||
| 5818 | - check_cp1_64bitmode(ctx); | ||
| 5819 | if (base == 0) { | 5833 | if (base == 0) { |
| 5820 | if (index == 0) | 5834 | if (index == 0) |
| 5821 | gen_op_reset_T0(); | 5835 | gen_op_reset_T0(); |
| @@ -5832,33 +5846,41 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, | @@ -5832,33 +5846,41 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, | ||
| 5832 | memory access. */ | 5846 | memory access. */ |
| 5833 | switch (opc) { | 5847 | switch (opc) { |
| 5834 | case OPC_LWXC1: | 5848 | case OPC_LWXC1: |
| 5849 | + check_cop1x(ctx); | ||
| 5835 | op_ldst(lwc1); | 5850 | op_ldst(lwc1); |
| 5836 | GEN_STORE_FTN_FREG(fd, WT0); | 5851 | GEN_STORE_FTN_FREG(fd, WT0); |
| 5837 | opn = "lwxc1"; | 5852 | opn = "lwxc1"; |
| 5838 | break; | 5853 | break; |
| 5839 | case OPC_LDXC1: | 5854 | case OPC_LDXC1: |
| 5855 | + check_cop1x(ctx); | ||
| 5856 | + check_cp1_registers(ctx, fd); | ||
| 5840 | op_ldst(ldc1); | 5857 | op_ldst(ldc1); |
| 5841 | GEN_STORE_FTN_FREG(fd, DT0); | 5858 | GEN_STORE_FTN_FREG(fd, DT0); |
| 5842 | opn = "ldxc1"; | 5859 | opn = "ldxc1"; |
| 5843 | break; | 5860 | break; |
| 5844 | case OPC_LUXC1: | 5861 | case OPC_LUXC1: |
| 5862 | + check_cp1_64bitmode(ctx); | ||
| 5845 | op_ldst(luxc1); | 5863 | op_ldst(luxc1); |
| 5846 | GEN_STORE_FTN_FREG(fd, DT0); | 5864 | GEN_STORE_FTN_FREG(fd, DT0); |
| 5847 | opn = "luxc1"; | 5865 | opn = "luxc1"; |
| 5848 | break; | 5866 | break; |
| 5849 | case OPC_SWXC1: | 5867 | case OPC_SWXC1: |
| 5868 | + check_cop1x(ctx); | ||
| 5850 | GEN_LOAD_FREG_FTN(WT0, fs); | 5869 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 5851 | op_ldst(swc1); | 5870 | op_ldst(swc1); |
| 5852 | opn = "swxc1"; | 5871 | opn = "swxc1"; |
| 5853 | store = 1; | 5872 | store = 1; |
| 5854 | break; | 5873 | break; |
| 5855 | case OPC_SDXC1: | 5874 | case OPC_SDXC1: |
| 5875 | + check_cop1x(ctx); | ||
| 5876 | + check_cp1_registers(ctx, fs); | ||
| 5856 | GEN_LOAD_FREG_FTN(DT0, fs); | 5877 | GEN_LOAD_FREG_FTN(DT0, fs); |
| 5857 | op_ldst(sdc1); | 5878 | op_ldst(sdc1); |
| 5858 | opn = "sdxc1"; | 5879 | opn = "sdxc1"; |
| 5859 | store = 1; | 5880 | store = 1; |
| 5860 | break; | 5881 | break; |
| 5861 | case OPC_SUXC1: | 5882 | case OPC_SUXC1: |
| 5883 | + check_cp1_64bitmode(ctx); | ||
| 5862 | GEN_LOAD_FREG_FTN(DT0, fs); | 5884 | GEN_LOAD_FREG_FTN(DT0, fs); |
| 5863 | op_ldst(suxc1); | 5885 | op_ldst(suxc1); |
| 5864 | opn = "suxc1"; | 5886 | opn = "suxc1"; |
| @@ -5878,10 +5900,9 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | @@ -5878,10 +5900,9 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | ||
| 5878 | { | 5900 | { |
| 5879 | const char *opn = "flt3_arith"; | 5901 | const char *opn = "flt3_arith"; |
| 5880 | 5902 | ||
| 5881 | - /* All of those work only on 64bit FPUs. */ | ||
| 5882 | - check_cp1_64bitmode(ctx); | ||
| 5883 | switch (opc) { | 5903 | switch (opc) { |
| 5884 | case OPC_ALNV_PS: | 5904 | case OPC_ALNV_PS: |
| 5905 | + check_cp1_64bitmode(ctx); | ||
| 5885 | GEN_LOAD_REG_T0(fr); | 5906 | GEN_LOAD_REG_T0(fr); |
| 5886 | GEN_LOAD_FREG_FTN(DT0, fs); | 5907 | GEN_LOAD_FREG_FTN(DT0, fs); |
| 5887 | GEN_LOAD_FREG_FTN(DT1, ft); | 5908 | GEN_LOAD_FREG_FTN(DT1, ft); |
| @@ -5890,6 +5911,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | @@ -5890,6 +5911,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | ||
| 5890 | opn = "alnv.ps"; | 5911 | opn = "alnv.ps"; |
| 5891 | break; | 5912 | break; |
| 5892 | case OPC_MADD_S: | 5913 | case OPC_MADD_S: |
| 5914 | + check_cop1x(ctx); | ||
| 5893 | GEN_LOAD_FREG_FTN(WT0, fs); | 5915 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 5894 | GEN_LOAD_FREG_FTN(WT1, ft); | 5916 | GEN_LOAD_FREG_FTN(WT1, ft); |
| 5895 | GEN_LOAD_FREG_FTN(WT2, fr); | 5917 | GEN_LOAD_FREG_FTN(WT2, fr); |
| @@ -5898,6 +5920,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | @@ -5898,6 +5920,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | ||
| 5898 | opn = "madd.s"; | 5920 | opn = "madd.s"; |
| 5899 | break; | 5921 | break; |
| 5900 | case OPC_MADD_D: | 5922 | case OPC_MADD_D: |
| 5923 | + check_cop1x(ctx); | ||
| 5924 | + check_cp1_registers(ctx, fd | fs | ft | fr); | ||
| 5901 | GEN_LOAD_FREG_FTN(DT0, fs); | 5925 | GEN_LOAD_FREG_FTN(DT0, fs); |
| 5902 | GEN_LOAD_FREG_FTN(DT1, ft); | 5926 | GEN_LOAD_FREG_FTN(DT1, ft); |
| 5903 | GEN_LOAD_FREG_FTN(DT2, fr); | 5927 | GEN_LOAD_FREG_FTN(DT2, fr); |
| @@ -5906,6 +5930,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | @@ -5906,6 +5930,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | ||
| 5906 | opn = "madd.d"; | 5930 | opn = "madd.d"; |
| 5907 | break; | 5931 | break; |
| 5908 | case OPC_MADD_PS: | 5932 | case OPC_MADD_PS: |
| 5933 | + check_cp1_64bitmode(ctx); | ||
| 5909 | GEN_LOAD_FREG_FTN(WT0, fs); | 5934 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 5910 | GEN_LOAD_FREG_FTN(WTH0, fs); | 5935 | GEN_LOAD_FREG_FTN(WTH0, fs); |
| 5911 | GEN_LOAD_FREG_FTN(WT1, ft); | 5936 | GEN_LOAD_FREG_FTN(WT1, ft); |
| @@ -5918,6 +5943,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | @@ -5918,6 +5943,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | ||
| 5918 | opn = "madd.ps"; | 5943 | opn = "madd.ps"; |
| 5919 | break; | 5944 | break; |
| 5920 | case OPC_MSUB_S: | 5945 | case OPC_MSUB_S: |
| 5946 | + check_cop1x(ctx); | ||
| 5921 | GEN_LOAD_FREG_FTN(WT0, fs); | 5947 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 5922 | GEN_LOAD_FREG_FTN(WT1, ft); | 5948 | GEN_LOAD_FREG_FTN(WT1, ft); |
| 5923 | GEN_LOAD_FREG_FTN(WT2, fr); | 5949 | GEN_LOAD_FREG_FTN(WT2, fr); |
| @@ -5926,6 +5952,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | @@ -5926,6 +5952,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | ||
| 5926 | opn = "msub.s"; | 5952 | opn = "msub.s"; |
| 5927 | break; | 5953 | break; |
| 5928 | case OPC_MSUB_D: | 5954 | case OPC_MSUB_D: |
| 5955 | + check_cop1x(ctx); | ||
| 5956 | + check_cp1_registers(ctx, fd | fs | ft | fr); | ||
| 5929 | GEN_LOAD_FREG_FTN(DT0, fs); | 5957 | GEN_LOAD_FREG_FTN(DT0, fs); |
| 5930 | GEN_LOAD_FREG_FTN(DT1, ft); | 5958 | GEN_LOAD_FREG_FTN(DT1, ft); |
| 5931 | GEN_LOAD_FREG_FTN(DT2, fr); | 5959 | GEN_LOAD_FREG_FTN(DT2, fr); |
| @@ -5934,6 +5962,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | @@ -5934,6 +5962,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | ||
| 5934 | opn = "msub.d"; | 5962 | opn = "msub.d"; |
| 5935 | break; | 5963 | break; |
| 5936 | case OPC_MSUB_PS: | 5964 | case OPC_MSUB_PS: |
| 5965 | + check_cp1_64bitmode(ctx); | ||
| 5937 | GEN_LOAD_FREG_FTN(WT0, fs); | 5966 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 5938 | GEN_LOAD_FREG_FTN(WTH0, fs); | 5967 | GEN_LOAD_FREG_FTN(WTH0, fs); |
| 5939 | GEN_LOAD_FREG_FTN(WT1, ft); | 5968 | GEN_LOAD_FREG_FTN(WT1, ft); |
| @@ -5946,6 +5975,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | @@ -5946,6 +5975,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | ||
| 5946 | opn = "msub.ps"; | 5975 | opn = "msub.ps"; |
| 5947 | break; | 5976 | break; |
| 5948 | case OPC_NMADD_S: | 5977 | case OPC_NMADD_S: |
| 5978 | + check_cop1x(ctx); | ||
| 5949 | GEN_LOAD_FREG_FTN(WT0, fs); | 5979 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 5950 | GEN_LOAD_FREG_FTN(WT1, ft); | 5980 | GEN_LOAD_FREG_FTN(WT1, ft); |
| 5951 | GEN_LOAD_FREG_FTN(WT2, fr); | 5981 | GEN_LOAD_FREG_FTN(WT2, fr); |
| @@ -5954,6 +5984,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | @@ -5954,6 +5984,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | ||
| 5954 | opn = "nmadd.s"; | 5984 | opn = "nmadd.s"; |
| 5955 | break; | 5985 | break; |
| 5956 | case OPC_NMADD_D: | 5986 | case OPC_NMADD_D: |
| 5987 | + check_cop1x(ctx); | ||
| 5988 | + check_cp1_registers(ctx, fd | fs | ft | fr); | ||
| 5957 | GEN_LOAD_FREG_FTN(DT0, fs); | 5989 | GEN_LOAD_FREG_FTN(DT0, fs); |
| 5958 | GEN_LOAD_FREG_FTN(DT1, ft); | 5990 | GEN_LOAD_FREG_FTN(DT1, ft); |
| 5959 | GEN_LOAD_FREG_FTN(DT2, fr); | 5991 | GEN_LOAD_FREG_FTN(DT2, fr); |
| @@ -5962,6 +5994,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | @@ -5962,6 +5994,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | ||
| 5962 | opn = "nmadd.d"; | 5994 | opn = "nmadd.d"; |
| 5963 | break; | 5995 | break; |
| 5964 | case OPC_NMADD_PS: | 5996 | case OPC_NMADD_PS: |
| 5997 | + check_cp1_64bitmode(ctx); | ||
| 5965 | GEN_LOAD_FREG_FTN(WT0, fs); | 5998 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 5966 | GEN_LOAD_FREG_FTN(WTH0, fs); | 5999 | GEN_LOAD_FREG_FTN(WTH0, fs); |
| 5967 | GEN_LOAD_FREG_FTN(WT1, ft); | 6000 | GEN_LOAD_FREG_FTN(WT1, ft); |
| @@ -5974,6 +6007,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | @@ -5974,6 +6007,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | ||
| 5974 | opn = "nmadd.ps"; | 6007 | opn = "nmadd.ps"; |
| 5975 | break; | 6008 | break; |
| 5976 | case OPC_NMSUB_S: | 6009 | case OPC_NMSUB_S: |
| 6010 | + check_cop1x(ctx); | ||
| 5977 | GEN_LOAD_FREG_FTN(WT0, fs); | 6011 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 5978 | GEN_LOAD_FREG_FTN(WT1, ft); | 6012 | GEN_LOAD_FREG_FTN(WT1, ft); |
| 5979 | GEN_LOAD_FREG_FTN(WT2, fr); | 6013 | GEN_LOAD_FREG_FTN(WT2, fr); |
| @@ -5982,6 +6016,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | @@ -5982,6 +6016,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | ||
| 5982 | opn = "nmsub.s"; | 6016 | opn = "nmsub.s"; |
| 5983 | break; | 6017 | break; |
| 5984 | case OPC_NMSUB_D: | 6018 | case OPC_NMSUB_D: |
| 6019 | + check_cop1x(ctx); | ||
| 6020 | + check_cp1_registers(ctx, fd | fs | ft | fr); | ||
| 5985 | GEN_LOAD_FREG_FTN(DT0, fs); | 6021 | GEN_LOAD_FREG_FTN(DT0, fs); |
| 5986 | GEN_LOAD_FREG_FTN(DT1, ft); | 6022 | GEN_LOAD_FREG_FTN(DT1, ft); |
| 5987 | GEN_LOAD_FREG_FTN(DT2, fr); | 6023 | GEN_LOAD_FREG_FTN(DT2, fr); |
| @@ -5990,6 +6026,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | @@ -5990,6 +6026,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, | ||
| 5990 | opn = "nmsub.d"; | 6026 | opn = "nmsub.d"; |
| 5991 | break; | 6027 | break; |
| 5992 | case OPC_NMSUB_PS: | 6028 | case OPC_NMSUB_PS: |
| 6029 | + check_cp1_64bitmode(ctx); | ||
| 5993 | GEN_LOAD_FREG_FTN(WT0, fs); | 6030 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 5994 | GEN_LOAD_FREG_FTN(WTH0, fs); | 6031 | GEN_LOAD_FREG_FTN(WTH0, fs); |
| 5995 | GEN_LOAD_FREG_FTN(WT1, ft); | 6032 | GEN_LOAD_FREG_FTN(WT1, ft); |
| @@ -6465,6 +6502,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | @@ -6465,6 +6502,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | ||
| 6465 | #endif | 6502 | #endif |
| 6466 | case OPC_BC1ANY2: | 6503 | case OPC_BC1ANY2: |
| 6467 | case OPC_BC1ANY4: | 6504 | case OPC_BC1ANY4: |
| 6505 | + check_cop1x(ctx); | ||
| 6468 | check_insn(env, ctx, ASE_MIPS3D); | 6506 | check_insn(env, ctx, ASE_MIPS3D); |
| 6469 | /* fall through */ | 6507 | /* fall through */ |
| 6470 | case OPC_BC1: | 6508 | case OPC_BC1: |