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 | 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: | ... | ... |