Commit b8aa4598e2cc109b0884740a42116acaab01e67d

Authored by ths
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
target-mips/cpu.h
... ... @@ -417,7 +417,7 @@ struct CPUMIPSState {
417 417 int user_mode_only; /* user mode only simulation */
418 418 uint32_t hflags; /* CPU State */
419 419 /* TMASK defines different execution modes */
420   -#define MIPS_HFLAG_TMASK 0x00FF
  420 +#define MIPS_HFLAG_TMASK 0x01FF
421 421 #define MIPS_HFLAG_MODE 0x0007 /* execution modes */
422 422 /* The KSU flags must be the lowest bits in hflags. The flag order
423 423 must be the same as defined for CP0 Status. This allows to use
... ... @@ -431,16 +431,20 @@ struct CPUMIPSState {
431 431 #define MIPS_HFLAG_CP0 0x0010 /* CP0 enabled */
432 432 #define MIPS_HFLAG_FPU 0x0020 /* FPU enabled */
433 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 439 /* If translation is interrupted between the branch instruction and
436 440 * the delay slot, record what type of branch it is so that we can
437 441 * resume translation properly. It might be possible to reduce
438 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 448 target_ulong btarget; /* Jump / branch target */
445 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 237  
238 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 242 if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
243 243 !(env->CP0_Status & (1 << CP0St_ERL)) &&
244 244 !(env->hflags & MIPS_HFLAG_DM)) {
... ... @@ -257,6 +257,20 @@ static always_inline void compute_hflags(CPUState *env)
257 257 env->hflags |= MIPS_HFLAG_FPU;
258 258 if (env->CP0_Status & (1 << CP0St_FR))
259 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 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 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 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 813 generate_exception(ctx, EXCP_RI);
801 814 }
802 815  
... ... @@ -5178,12 +5191,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
5178 5191 opn = "movn.s";
5179 5192 break;
5180 5193 case FOP(21, 16):
  5194 + check_cop1x(ctx);
5181 5195 GEN_LOAD_FREG_FTN(WT0, fs);
5182 5196 gen_op_float_recip_s();
5183 5197 GEN_STORE_FTN_FREG(fd, WT2);
5184 5198 opn = "recip.s";
5185 5199 break;
5186 5200 case FOP(22, 16):
  5201 + check_cop1x(ctx);
5187 5202 GEN_LOAD_FREG_FTN(WT0, fs);
5188 5203 gen_op_float_rsqrt_s();
5189 5204 GEN_STORE_FTN_FREG(fd, WT2);
... ... @@ -5266,7 +5281,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
5266 5281 GEN_LOAD_FREG_FTN(WT0, fs);
5267 5282 GEN_LOAD_FREG_FTN(WT1, ft);
5268 5283 if (ctx->opcode & (1 << 6)) {
5269   - check_cp1_64bitmode(ctx);
  5284 + check_cop1x(ctx);
5270 5285 gen_cmpabs_s(func-48, cc);
5271 5286 opn = condnames_abs[func-48];
5272 5287 } else {
... ... @@ -5419,14 +5434,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
5419 5434 opn = "movn.d";
5420 5435 break;
5421 5436 case FOP(21, 17):
5422   - check_cp1_registers(ctx, fs | fd);
  5437 + check_cp1_64bitmode(ctx);
5423 5438 GEN_LOAD_FREG_FTN(DT0, fs);
5424 5439 gen_op_float_recip_d();
5425 5440 GEN_STORE_FTN_FREG(fd, DT2);
5426 5441 opn = "recip.d";
5427 5442 break;
5428 5443 case FOP(22, 17):
5429   - check_cp1_registers(ctx, fs | fd);
  5444 + check_cp1_64bitmode(ctx);
5430 5445 GEN_LOAD_FREG_FTN(DT0, fs);
5431 5446 gen_op_float_rsqrt_d();
5432 5447 GEN_STORE_FTN_FREG(fd, DT2);
... ... @@ -5481,7 +5496,8 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
5481 5496 GEN_LOAD_FREG_FTN(DT0, fs);
5482 5497 GEN_LOAD_FREG_FTN(DT1, ft);
5483 5498 if (ctx->opcode & (1 << 6)) {
5484   - check_cp1_64bitmode(ctx);
  5499 + check_cop1x(ctx);
  5500 + check_cp1_registers(ctx, fs | ft);
5485 5501 gen_cmpabs_d(func-48, cc);
5486 5502 opn = condnames_abs[func-48];
5487 5503 } else {
... ... @@ -5814,8 +5830,6 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc,
5814 5830 const char *opn = "extended float load/store";
5815 5831 int store = 0;
5816 5832  
5817   - /* All of those work only on 64bit FPUs. */
5818   - check_cp1_64bitmode(ctx);
5819 5833 if (base == 0) {
5820 5834 if (index == 0)
5821 5835 gen_op_reset_T0();
... ... @@ -5832,33 +5846,41 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc,
5832 5846 memory access. */
5833 5847 switch (opc) {
5834 5848 case OPC_LWXC1:
  5849 + check_cop1x(ctx);
5835 5850 op_ldst(lwc1);
5836 5851 GEN_STORE_FTN_FREG(fd, WT0);
5837 5852 opn = "lwxc1";
5838 5853 break;
5839 5854 case OPC_LDXC1:
  5855 + check_cop1x(ctx);
  5856 + check_cp1_registers(ctx, fd);
5840 5857 op_ldst(ldc1);
5841 5858 GEN_STORE_FTN_FREG(fd, DT0);
5842 5859 opn = "ldxc1";
5843 5860 break;
5844 5861 case OPC_LUXC1:
  5862 + check_cp1_64bitmode(ctx);
5845 5863 op_ldst(luxc1);
5846 5864 GEN_STORE_FTN_FREG(fd, DT0);
5847 5865 opn = "luxc1";
5848 5866 break;
5849 5867 case OPC_SWXC1:
  5868 + check_cop1x(ctx);
5850 5869 GEN_LOAD_FREG_FTN(WT0, fs);
5851 5870 op_ldst(swc1);
5852 5871 opn = "swxc1";
5853 5872 store = 1;
5854 5873 break;
5855 5874 case OPC_SDXC1:
  5875 + check_cop1x(ctx);
  5876 + check_cp1_registers(ctx, fs);
5856 5877 GEN_LOAD_FREG_FTN(DT0, fs);
5857 5878 op_ldst(sdc1);
5858 5879 opn = "sdxc1";
5859 5880 store = 1;
5860 5881 break;
5861 5882 case OPC_SUXC1:
  5883 + check_cp1_64bitmode(ctx);
5862 5884 GEN_LOAD_FREG_FTN(DT0, fs);
5863 5885 op_ldst(suxc1);
5864 5886 opn = "suxc1";
... ... @@ -5878,10 +5900,9 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
5878 5900 {
5879 5901 const char *opn = "flt3_arith";
5880 5902  
5881   - /* All of those work only on 64bit FPUs. */
5882   - check_cp1_64bitmode(ctx);
5883 5903 switch (opc) {
5884 5904 case OPC_ALNV_PS:
  5905 + check_cp1_64bitmode(ctx);
5885 5906 GEN_LOAD_REG_T0(fr);
5886 5907 GEN_LOAD_FREG_FTN(DT0, fs);
5887 5908 GEN_LOAD_FREG_FTN(DT1, ft);
... ... @@ -5890,6 +5911,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
5890 5911 opn = "alnv.ps";
5891 5912 break;
5892 5913 case OPC_MADD_S:
  5914 + check_cop1x(ctx);
5893 5915 GEN_LOAD_FREG_FTN(WT0, fs);
5894 5916 GEN_LOAD_FREG_FTN(WT1, ft);
5895 5917 GEN_LOAD_FREG_FTN(WT2, fr);
... ... @@ -5898,6 +5920,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
5898 5920 opn = "madd.s";
5899 5921 break;
5900 5922 case OPC_MADD_D:
  5923 + check_cop1x(ctx);
  5924 + check_cp1_registers(ctx, fd | fs | ft | fr);
5901 5925 GEN_LOAD_FREG_FTN(DT0, fs);
5902 5926 GEN_LOAD_FREG_FTN(DT1, ft);
5903 5927 GEN_LOAD_FREG_FTN(DT2, fr);
... ... @@ -5906,6 +5930,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
5906 5930 opn = "madd.d";
5907 5931 break;
5908 5932 case OPC_MADD_PS:
  5933 + check_cp1_64bitmode(ctx);
5909 5934 GEN_LOAD_FREG_FTN(WT0, fs);
5910 5935 GEN_LOAD_FREG_FTN(WTH0, fs);
5911 5936 GEN_LOAD_FREG_FTN(WT1, ft);
... ... @@ -5918,6 +5943,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
5918 5943 opn = "madd.ps";
5919 5944 break;
5920 5945 case OPC_MSUB_S:
  5946 + check_cop1x(ctx);
5921 5947 GEN_LOAD_FREG_FTN(WT0, fs);
5922 5948 GEN_LOAD_FREG_FTN(WT1, ft);
5923 5949 GEN_LOAD_FREG_FTN(WT2, fr);
... ... @@ -5926,6 +5952,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
5926 5952 opn = "msub.s";
5927 5953 break;
5928 5954 case OPC_MSUB_D:
  5955 + check_cop1x(ctx);
  5956 + check_cp1_registers(ctx, fd | fs | ft | fr);
5929 5957 GEN_LOAD_FREG_FTN(DT0, fs);
5930 5958 GEN_LOAD_FREG_FTN(DT1, ft);
5931 5959 GEN_LOAD_FREG_FTN(DT2, fr);
... ... @@ -5934,6 +5962,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
5934 5962 opn = "msub.d";
5935 5963 break;
5936 5964 case OPC_MSUB_PS:
  5965 + check_cp1_64bitmode(ctx);
5937 5966 GEN_LOAD_FREG_FTN(WT0, fs);
5938 5967 GEN_LOAD_FREG_FTN(WTH0, fs);
5939 5968 GEN_LOAD_FREG_FTN(WT1, ft);
... ... @@ -5946,6 +5975,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
5946 5975 opn = "msub.ps";
5947 5976 break;
5948 5977 case OPC_NMADD_S:
  5978 + check_cop1x(ctx);
5949 5979 GEN_LOAD_FREG_FTN(WT0, fs);
5950 5980 GEN_LOAD_FREG_FTN(WT1, ft);
5951 5981 GEN_LOAD_FREG_FTN(WT2, fr);
... ... @@ -5954,6 +5984,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
5954 5984 opn = "nmadd.s";
5955 5985 break;
5956 5986 case OPC_NMADD_D:
  5987 + check_cop1x(ctx);
  5988 + check_cp1_registers(ctx, fd | fs | ft | fr);
5957 5989 GEN_LOAD_FREG_FTN(DT0, fs);
5958 5990 GEN_LOAD_FREG_FTN(DT1, ft);
5959 5991 GEN_LOAD_FREG_FTN(DT2, fr);
... ... @@ -5962,6 +5994,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
5962 5994 opn = "nmadd.d";
5963 5995 break;
5964 5996 case OPC_NMADD_PS:
  5997 + check_cp1_64bitmode(ctx);
5965 5998 GEN_LOAD_FREG_FTN(WT0, fs);
5966 5999 GEN_LOAD_FREG_FTN(WTH0, fs);
5967 6000 GEN_LOAD_FREG_FTN(WT1, ft);
... ... @@ -5974,6 +6007,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
5974 6007 opn = "nmadd.ps";
5975 6008 break;
5976 6009 case OPC_NMSUB_S:
  6010 + check_cop1x(ctx);
5977 6011 GEN_LOAD_FREG_FTN(WT0, fs);
5978 6012 GEN_LOAD_FREG_FTN(WT1, ft);
5979 6013 GEN_LOAD_FREG_FTN(WT2, fr);
... ... @@ -5982,6 +6016,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
5982 6016 opn = "nmsub.s";
5983 6017 break;
5984 6018 case OPC_NMSUB_D:
  6019 + check_cop1x(ctx);
  6020 + check_cp1_registers(ctx, fd | fs | ft | fr);
5985 6021 GEN_LOAD_FREG_FTN(DT0, fs);
5986 6022 GEN_LOAD_FREG_FTN(DT1, ft);
5987 6023 GEN_LOAD_FREG_FTN(DT2, fr);
... ... @@ -5990,6 +6026,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
5990 6026 opn = "nmsub.d";
5991 6027 break;
5992 6028 case OPC_NMSUB_PS:
  6029 + check_cp1_64bitmode(ctx);
5993 6030 GEN_LOAD_FREG_FTN(WT0, fs);
5994 6031 GEN_LOAD_FREG_FTN(WTH0, fs);
5995 6032 GEN_LOAD_FREG_FTN(WT1, ft);
... ... @@ -6465,6 +6502,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
6465 6502 #endif
6466 6503 case OPC_BC1ANY2:
6467 6504 case OPC_BC1ANY4:
  6505 + check_cop1x(ctx);
6468 6506 check_insn(env, ctx, ASE_MIPS3D);
6469 6507 /* fall through */
6470 6508 case OPC_BC1:
... ...