Commit 5a5012ecbdcd341bb1d2e8200db91f6212aa44df
1 parent
8b4af705
MIPS 64-bit FPU support, plus some collateral bugfixes in the
conditional branch handling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2779 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
11 changed files
with
1703 additions
and
520 deletions
Changelog
| @@ -4,6 +4,7 @@ | @@ -4,6 +4,7 @@ | ||
| 4 | - ds1225y nvram support (Herve Poussineau) | 4 | - ds1225y nvram support (Herve Poussineau) |
| 5 | - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau) | 5 | - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau) |
| 6 | - Several Sparc fixes (Aurelien Jarno, Blue Swirl) | 6 | - Several Sparc fixes (Aurelien Jarno, Blue Swirl) |
| 7 | + - MIPS 64-bit FPU support (Thiemo Seufer) | ||
| 7 | 8 | ||
| 8 | version 0.9.0: | 9 | version 0.9.0: |
| 9 | 10 |
gdbstub.c
| @@ -575,7 +575,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) | @@ -575,7 +575,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) | ||
| 575 | { | 575 | { |
| 576 | for (i = 0; i < 32; i++) | 576 | for (i = 0; i < 32; i++) |
| 577 | { | 577 | { |
| 578 | - *(uint32_t *)ptr = tswapl(FPR_W (env, i)); | 578 | + *(uint32_t *)ptr = tswapl(env->fpr[i].fs[FP_ENDIAN_IDX]); |
| 579 | ptr += 4; | 579 | ptr += 4; |
| 580 | } | 580 | } |
| 581 | 581 | ||
| @@ -637,7 +637,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) | @@ -637,7 +637,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) | ||
| 637 | { | 637 | { |
| 638 | for (i = 0; i < 32; i++) | 638 | for (i = 0; i < 32; i++) |
| 639 | { | 639 | { |
| 640 | - FPR_W (env, i) = tswapl(*(uint32_t *)ptr); | 640 | + env->fpr[i].fs[FP_ENDIAN_IDX] = tswapl(*(uint32_t *)ptr); |
| 641 | ptr += 4; | 641 | ptr += 4; |
| 642 | } | 642 | } |
| 643 | 643 |
target-mips/TODO
| @@ -10,11 +10,12 @@ General | @@ -10,11 +10,12 @@ General | ||
| 10 | when the Qemu FPU emulation is disabled. Also gdb inside the emulated | 10 | when the Qemu FPU emulation is disabled. Also gdb inside the emulated |
| 11 | system does not work. Both problems are caused by insufficient | 11 | system does not work. Both problems are caused by insufficient |
| 12 | handling of self-modifying code. | 12 | handling of self-modifying code. |
| 13 | +- Floating point exception emulation is incomplete. | ||
| 13 | 14 | ||
| 14 | MIPS64 | 15 | MIPS64 |
| 15 | ------ | 16 | ------ |
| 16 | - No 64bit TLB support | 17 | - No 64bit TLB support |
| 17 | -- no 64bit wide registers for FPU | 18 | +- 64bit FPU not fully implemented |
| 18 | - 64bit mul/div handling broken | 19 | - 64bit mul/div handling broken |
| 19 | 20 | ||
| 20 | "Generic" 4Kc system emulation | 21 | "Generic" 4Kc system emulation |
target-mips/cpu.h
| @@ -21,7 +21,7 @@ typedef union fpr_t fpr_t; | @@ -21,7 +21,7 @@ typedef union fpr_t fpr_t; | ||
| 21 | union fpr_t { | 21 | union fpr_t { |
| 22 | float64 fd; /* ieee double precision */ | 22 | float64 fd; /* ieee double precision */ |
| 23 | float32 fs[2];/* ieee single precision */ | 23 | float32 fs[2];/* ieee single precision */ |
| 24 | - uint64_t d; /* binary single fixed-point */ | 24 | + uint64_t d; /* binary double fixed-point */ |
| 25 | uint32_t w[2]; /* binary single fixed-point */ | 25 | uint32_t w[2]; /* binary single fixed-point */ |
| 26 | }; | 26 | }; |
| 27 | /* define FP_ENDIAN_IDX to access the same location | 27 | /* define FP_ENDIAN_IDX to access the same location |
| @@ -64,31 +64,35 @@ struct CPUMIPSState { | @@ -64,31 +64,35 @@ struct CPUMIPSState { | ||
| 64 | target_ulong HI, LO; | 64 | target_ulong HI, LO; |
| 65 | /* Floating point registers */ | 65 | /* Floating point registers */ |
| 66 | fpr_t fpr[32]; | 66 | fpr_t fpr[32]; |
| 67 | -#define FPR(cpu, n) ((fpr_t*)&(cpu)->fpr[(n) / 2]) | ||
| 68 | -#define FPR_FD(cpu, n) (FPR(cpu, n)->fd) | ||
| 69 | -#define FPR_FS(cpu, n) (FPR(cpu, n)->fs[((n) & 1) ^ FP_ENDIAN_IDX]) | ||
| 70 | -#define FPR_D(cpu, n) (FPR(cpu, n)->d) | ||
| 71 | -#define FPR_W(cpu, n) (FPR(cpu, n)->w[((n) & 1) ^ FP_ENDIAN_IDX]) | ||
| 72 | - | ||
| 73 | #ifndef USE_HOST_FLOAT_REGS | 67 | #ifndef USE_HOST_FLOAT_REGS |
| 74 | fpr_t ft0; | 68 | fpr_t ft0; |
| 75 | fpr_t ft1; | 69 | fpr_t ft1; |
| 76 | fpr_t ft2; | 70 | fpr_t ft2; |
| 77 | #endif | 71 | #endif |
| 78 | float_status fp_status; | 72 | float_status fp_status; |
| 79 | - /* fpu implementation/revision register */ | 73 | + /* fpu implementation/revision register (fir) */ |
| 80 | uint32_t fcr0; | 74 | uint32_t fcr0; |
| 75 | +#define FCR0_F64 22 | ||
| 76 | +#define FCR0_L 21 | ||
| 77 | +#define FCR0_W 20 | ||
| 78 | +#define FCR0_3D 19 | ||
| 79 | +#define FCR0_PS 18 | ||
| 80 | +#define FCR0_D 17 | ||
| 81 | +#define FCR0_S 16 | ||
| 82 | +#define FCR0_PRID 8 | ||
| 83 | +#define FCR0_REV 0 | ||
| 81 | /* fcsr */ | 84 | /* fcsr */ |
| 82 | uint32_t fcr31; | 85 | uint32_t fcr31; |
| 83 | -#define SET_FP_COND(reg) do { (reg) |= (1<<23); } while(0) | ||
| 84 | -#define CLEAR_FP_COND(reg) do { (reg) &= ~(1<<23); } while(0) | ||
| 85 | -#define IS_FP_COND_SET(reg) (((reg) & (1<<23)) != 0) | ||
| 86 | -#define GET_FP_CAUSE(reg) (((reg) >> 12) & 0x3f) | ||
| 87 | -#define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f) | ||
| 88 | -#define GET_FP_FLAGS(reg) (((reg) >> 2) & 0x1f) | ||
| 89 | -#define SET_FP_CAUSE(reg,v) do { (reg) = ((reg) & ~(0x3f << 12)) | ((v) << 12); } while(0) | ||
| 90 | -#define SET_FP_ENABLE(reg,v) do { (reg) = ((reg) & ~(0x1f << 7)) | ((v) << 7); } while(0) | ||
| 91 | -#define SET_FP_FLAGS(reg,v) do { (reg) = ((reg) & ~(0x1f << 2)) | ((v) << 2); } while(0) | 86 | +#define SET_FP_COND(num,env) do { (env->fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23))); } while(0) |
| 87 | +#define CLEAR_FP_COND(num,env) do { (env->fcr31) &= ~((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23))); } while(0) | ||
| 88 | +#define IS_FP_COND_SET(num,env) (((env->fcr31) & ((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23)))) != 0) | ||
| 89 | +#define GET_FP_CAUSE(reg) (((reg) >> 12) & 0x3f) | ||
| 90 | +#define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f) | ||
| 91 | +#define GET_FP_FLAGS(reg) (((reg) >> 2) & 0x1f) | ||
| 92 | +#define SET_FP_CAUSE(reg,v) do { (reg) = ((reg) & ~(0x3f << 12)) | ((v & 0x3f) << 12); } while(0) | ||
| 93 | +#define SET_FP_ENABLE(reg,v) do { (reg) = ((reg) & ~(0x1f << 7)) | ((v & 0x1f) << 7); } while(0) | ||
| 94 | +#define SET_FP_FLAGS(reg,v) do { (reg) = ((reg) & ~(0x1f << 2)) | ((v & 0x1f) << 2); } while(0) | ||
| 95 | +#define UPDATE_FP_FLAGS(reg,v) do { (reg) |= ((v & 0x1f) << 2); } while(0) | ||
| 92 | #define FP_INEXACT 1 | 96 | #define FP_INEXACT 1 |
| 93 | #define FP_UNDERFLOW 2 | 97 | #define FP_UNDERFLOW 2 |
| 94 | #define FP_OVERFLOW 4 | 98 | #define FP_OVERFLOW 4 |
| @@ -267,6 +271,7 @@ struct CPUMIPSState { | @@ -267,6 +271,7 @@ struct CPUMIPSState { | ||
| 267 | 271 | ||
| 268 | int SYNCI_Step; /* Address step size for SYNCI */ | 272 | int SYNCI_Step; /* Address step size for SYNCI */ |
| 269 | int CCRes; /* Cycle count resolution/divisor */ | 273 | int CCRes; /* Cycle count resolution/divisor */ |
| 274 | + int Status_rw_bitmask; /* Read/write bits in CP0_Status */ | ||
| 270 | 275 | ||
| 271 | #if defined(CONFIG_USER_ONLY) | 276 | #if defined(CONFIG_USER_ONLY) |
| 272 | target_ulong tls_value; | 277 | target_ulong tls_value; |
| @@ -330,10 +335,11 @@ enum { | @@ -330,10 +335,11 @@ enum { | ||
| 330 | EXCP_RI, | 335 | EXCP_RI, |
| 331 | EXCP_OVERFLOW, | 336 | EXCP_OVERFLOW, |
| 332 | EXCP_TRAP, | 337 | EXCP_TRAP, |
| 338 | + EXCP_FPE, | ||
| 333 | EXCP_DDBS, | 339 | EXCP_DDBS, |
| 334 | EXCP_DWATCH, | 340 | EXCP_DWATCH, |
| 335 | - EXCP_LAE, | ||
| 336 | - EXCP_SAE, /* 24 */ | 341 | + EXCP_LAE, /* 24 */ |
| 342 | + EXCP_SAE, | ||
| 337 | EXCP_LTLBL, | 343 | EXCP_LTLBL, |
| 338 | EXCP_TLBL, | 344 | EXCP_TLBL, |
| 339 | EXCP_TLBS, | 345 | EXCP_TLBS, |
target-mips/exec.h
| @@ -29,12 +29,18 @@ register target_ulong T2 asm(AREG3); | @@ -29,12 +29,18 @@ register target_ulong T2 asm(AREG3); | ||
| 29 | #define FST0 (env->ft0.fs[FP_ENDIAN_IDX]) | 29 | #define FST0 (env->ft0.fs[FP_ENDIAN_IDX]) |
| 30 | #define FST1 (env->ft1.fs[FP_ENDIAN_IDX]) | 30 | #define FST1 (env->ft1.fs[FP_ENDIAN_IDX]) |
| 31 | #define FST2 (env->ft2.fs[FP_ENDIAN_IDX]) | 31 | #define FST2 (env->ft2.fs[FP_ENDIAN_IDX]) |
| 32 | +#define FSTH0 (env->ft0.fs[!FP_ENDIAN_IDX]) | ||
| 33 | +#define FSTH1 (env->ft1.fs[!FP_ENDIAN_IDX]) | ||
| 34 | +#define FSTH2 (env->ft2.fs[!FP_ENDIAN_IDX]) | ||
| 32 | #define DT0 (env->ft0.d) | 35 | #define DT0 (env->ft0.d) |
| 33 | #define DT1 (env->ft1.d) | 36 | #define DT1 (env->ft1.d) |
| 34 | #define DT2 (env->ft2.d) | 37 | #define DT2 (env->ft2.d) |
| 35 | #define WT0 (env->ft0.w[FP_ENDIAN_IDX]) | 38 | #define WT0 (env->ft0.w[FP_ENDIAN_IDX]) |
| 36 | #define WT1 (env->ft1.w[FP_ENDIAN_IDX]) | 39 | #define WT1 (env->ft1.w[FP_ENDIAN_IDX]) |
| 37 | #define WT2 (env->ft2.w[FP_ENDIAN_IDX]) | 40 | #define WT2 (env->ft2.w[FP_ENDIAN_IDX]) |
| 41 | +#define WTH0 (env->ft0.w[!FP_ENDIAN_IDX]) | ||
| 42 | +#define WTH1 (env->ft1.w[!FP_ENDIAN_IDX]) | ||
| 43 | +#define WTH2 (env->ft2.w[!FP_ENDIAN_IDX]) | ||
| 38 | #endif | 44 | #endif |
| 39 | 45 | ||
| 40 | #if defined (DEBUG_OP) | 46 | #if defined (DEBUG_OP) |
target-mips/fop_template.c
| @@ -19,75 +19,103 @@ | @@ -19,75 +19,103 @@ | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | -#if defined(SFREG) | 22 | +#if defined(FREG) |
| 23 | 23 | ||
| 24 | -#define OP_WLOAD_FREG(treg, tregname, SFREG) \ | ||
| 25 | - void glue(glue(op_load_fpr_,tregname), SFREG) (void) \ | ||
| 26 | - { \ | ||
| 27 | - treg = FPR_W(env, SFREG); \ | ||
| 28 | - RETURN(); \ | 24 | +#define OP_WLOAD_FREG(treg, tregname, FREG) \ |
| 25 | + void glue(glue(op_load_fpr_,tregname), FREG) (void) \ | ||
| 26 | + { \ | ||
| 27 | + treg = env->fpr[FREG].fs[FP_ENDIAN_IDX]; \ | ||
| 28 | + RETURN(); \ | ||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | -#define OP_WSTORE_FREG(treg, tregname, SFREG) \ | ||
| 32 | - void glue(glue(op_store_fpr_,tregname), SFREG) (void)\ | ||
| 33 | - { \ | ||
| 34 | - FPR_W(env, SFREG) = treg; \ | ||
| 35 | - RETURN(); \ | 31 | +#define OP_WSTORE_FREG(treg, tregname, FREG) \ |
| 32 | + void glue(glue(op_store_fpr_,tregname), FREG) (void) \ | ||
| 33 | + { \ | ||
| 34 | + env->fpr[FREG].fs[FP_ENDIAN_IDX] = treg; \ | ||
| 35 | + RETURN(); \ | ||
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | -/* WT0 = SFREG.w: op_load_fpr_WT0_fprSFREG */ | ||
| 39 | -OP_WLOAD_FREG(WT0, WT0_fpr, SFREG) | ||
| 40 | -/* SFREG.w = WT0: op_store_fpr_WT0_fprSFREG */ | ||
| 41 | -OP_WSTORE_FREG(WT0, WT0_fpr, SFREG) | 38 | +/* WT0 = FREG.w: op_load_fpr_WT0_fprFREG */ |
| 39 | +OP_WLOAD_FREG(WT0, WT0_fpr, FREG) | ||
| 40 | +/* FREG.w = WT0: op_store_fpr_WT0_fprFREG */ | ||
| 41 | +OP_WSTORE_FREG(WT0, WT0_fpr, FREG) | ||
| 42 | + | ||
| 43 | +OP_WLOAD_FREG(WT1, WT1_fpr, FREG) | ||
| 44 | +OP_WSTORE_FREG(WT1, WT1_fpr, FREG) | ||
| 45 | + | ||
| 46 | +OP_WLOAD_FREG(WT2, WT2_fpr, FREG) | ||
| 47 | +OP_WSTORE_FREG(WT2, WT2_fpr, FREG) | ||
| 48 | + | ||
| 49 | +#define OP_DLOAD_FREG(treg, tregname, FREG) \ | ||
| 50 | + void glue(glue(op_load_fpr_,tregname), FREG) (void) \ | ||
| 51 | + { \ | ||
| 52 | + if (env->CP0_Status & (1 << CP0St_FR)) \ | ||
| 53 | + treg = env->fpr[FREG].fd; \ | ||
| 54 | + else \ | ||
| 55 | + treg = (uint64_t)(env->fpr[FREG | 1].fs[FP_ENDIAN_IDX]) << 32 | \ | ||
| 56 | + env->fpr[FREG & ~1].fs[FP_ENDIAN_IDX]; \ | ||
| 57 | + RETURN(); \ | ||
| 58 | + } | ||
| 42 | 59 | ||
| 43 | -OP_WLOAD_FREG(WT1, WT1_fpr, SFREG) | ||
| 44 | -OP_WSTORE_FREG(WT1, WT1_fpr, SFREG) | 60 | +#define OP_DSTORE_FREG(treg, tregname, FREG) \ |
| 61 | + void glue(glue(op_store_fpr_,tregname), FREG) (void) \ | ||
| 62 | + { \ | ||
| 63 | + if (env->CP0_Status & (1 << CP0St_FR)) \ | ||
| 64 | + env->fpr[FREG].fd = treg; \ | ||
| 65 | + else { \ | ||
| 66 | + env->fpr[FREG | 1].fs[FP_ENDIAN_IDX] = treg >> 32; \ | ||
| 67 | + env->fpr[FREG & ~1].fs[FP_ENDIAN_IDX] = treg; \ | ||
| 68 | + } \ | ||
| 69 | + RETURN(); \ | ||
| 70 | + } | ||
| 45 | 71 | ||
| 46 | -OP_WLOAD_FREG(WT2, WT2_fpr, SFREG) | ||
| 47 | -OP_WSTORE_FREG(WT2, WT2_fpr, SFREG) | 72 | +OP_DLOAD_FREG(DT0, DT0_fpr, FREG) |
| 73 | +OP_DSTORE_FREG(DT0, DT0_fpr, FREG) | ||
| 48 | 74 | ||
| 49 | -#endif | 75 | +OP_DLOAD_FREG(DT1, DT1_fpr, FREG) |
| 76 | +OP_DSTORE_FREG(DT1, DT1_fpr, FREG) | ||
| 50 | 77 | ||
| 51 | -#if defined(DFREG) | 78 | +OP_DLOAD_FREG(DT2, DT2_fpr, FREG) |
| 79 | +OP_DSTORE_FREG(DT2, DT2_fpr, FREG) | ||
| 52 | 80 | ||
| 53 | -#define OP_DLOAD_FREG(treg, tregname, DFREG) \ | ||
| 54 | - void glue(glue(op_load_fpr_,tregname), DFREG) (void) \ | ||
| 55 | - { \ | ||
| 56 | - treg = FPR_D(env, DFREG); \ | ||
| 57 | - RETURN(); \ | 81 | +#define OP_PSLOAD_FREG(treg, tregname, FREG) \ |
| 82 | + void glue(glue(op_load_fpr_,tregname), FREG) (void) \ | ||
| 83 | + { \ | ||
| 84 | + treg = env->fpr[FREG].fs[!FP_ENDIAN_IDX]; \ | ||
| 85 | + RETURN(); \ | ||
| 58 | } | 86 | } |
| 59 | 87 | ||
| 60 | -#define OP_DSTORE_FREG(treg, tregname, DFREG) \ | ||
| 61 | - void glue(glue(op_store_fpr_,tregname), DFREG) (void)\ | ||
| 62 | - { \ | ||
| 63 | - FPR_D(env, DFREG) = treg; \ | ||
| 64 | - RETURN(); \ | 88 | +#define OP_PSSTORE_FREG(treg, tregname, FREG) \ |
| 89 | + void glue(glue(op_store_fpr_,tregname), FREG) (void) \ | ||
| 90 | + { \ | ||
| 91 | + env->fpr[FREG].fs[!FP_ENDIAN_IDX] = treg; \ | ||
| 92 | + RETURN(); \ | ||
| 65 | } | 93 | } |
| 66 | 94 | ||
| 67 | -OP_DLOAD_FREG(DT0, DT0_fpr, DFREG) | ||
| 68 | -OP_DSTORE_FREG(DT0, DT0_fpr, DFREG) | 95 | +OP_PSLOAD_FREG(WTH0, WTH0_fpr, FREG) |
| 96 | +OP_PSSTORE_FREG(WTH0, WTH0_fpr, FREG) | ||
| 69 | 97 | ||
| 70 | -OP_DLOAD_FREG(DT1, DT1_fpr, DFREG) | ||
| 71 | -OP_DSTORE_FREG(DT1, DT1_fpr, DFREG) | 98 | +OP_PSLOAD_FREG(WTH1, WTH1_fpr, FREG) |
| 99 | +OP_PSSTORE_FREG(WTH1, WTH1_fpr, FREG) | ||
| 72 | 100 | ||
| 73 | -OP_DLOAD_FREG(DT2, DT2_fpr, DFREG) | ||
| 74 | -OP_DSTORE_FREG(DT2, DT2_fpr, DFREG) | 101 | +OP_PSLOAD_FREG(WTH2, WTH2_fpr, FREG) |
| 102 | +OP_PSSTORE_FREG(WTH2, WTH2_fpr, FREG) | ||
| 75 | 103 | ||
| 76 | #endif | 104 | #endif |
| 77 | 105 | ||
| 78 | #if defined (FTN) | 106 | #if defined (FTN) |
| 79 | 107 | ||
| 80 | -#define SET_RESET(treg, tregname) \ | 108 | +#define SET_RESET(treg, tregname) \ |
| 81 | void glue(op_set, tregname)(void) \ | 109 | void glue(op_set, tregname)(void) \ |
| 82 | - { \ | ||
| 83 | - treg = PARAM1; \ | ||
| 84 | - RETURN(); \ | ||
| 85 | - } \ | 110 | + { \ |
| 111 | + treg = PARAM1; \ | ||
| 112 | + RETURN(); \ | ||
| 113 | + } \ | ||
| 86 | void glue(op_reset, tregname)(void) \ | 114 | void glue(op_reset, tregname)(void) \ |
| 87 | - { \ | ||
| 88 | - treg = 0; \ | ||
| 89 | - RETURN(); \ | ||
| 90 | - } \ | 115 | + { \ |
| 116 | + treg = 0; \ | ||
| 117 | + RETURN(); \ | ||
| 118 | + } | ||
| 91 | 119 | ||
| 92 | SET_RESET(WT0, _WT0) | 120 | SET_RESET(WT0, _WT0) |
| 93 | SET_RESET(WT1, _WT1) | 121 | SET_RESET(WT1, _WT1) |
| @@ -95,6 +123,9 @@ SET_RESET(WT2, _WT2) | @@ -95,6 +123,9 @@ SET_RESET(WT2, _WT2) | ||
| 95 | SET_RESET(DT0, _DT0) | 123 | SET_RESET(DT0, _DT0) |
| 96 | SET_RESET(DT1, _DT1) | 124 | SET_RESET(DT1, _DT1) |
| 97 | SET_RESET(DT2, _DT2) | 125 | SET_RESET(DT2, _DT2) |
| 126 | +SET_RESET(WTH0, _WTH0) | ||
| 127 | +SET_RESET(WTH1, _WTH1) | ||
| 128 | +SET_RESET(WTH2, _WTH2) | ||
| 98 | 129 | ||
| 99 | #undef SET_RESET | 130 | #undef SET_RESET |
| 100 | #endif | 131 | #endif |
target-mips/helper.c
| @@ -379,6 +379,9 @@ void do_interrupt (CPUState *env) | @@ -379,6 +379,9 @@ void do_interrupt (CPUState *env) | ||
| 379 | case EXCP_TRAP: | 379 | case EXCP_TRAP: |
| 380 | cause = 13; | 380 | cause = 13; |
| 381 | goto set_EPC; | 381 | goto set_EPC; |
| 382 | + case EXCP_FPE: | ||
| 383 | + cause = 15; | ||
| 384 | + goto set_EPC; | ||
| 382 | case EXCP_LTLBL: | 385 | case EXCP_LTLBL: |
| 383 | cause = 1; | 386 | cause = 1; |
| 384 | goto set_EPC; | 387 | goto set_EPC; |
target-mips/op.c
| @@ -23,27 +23,27 @@ | @@ -23,27 +23,27 @@ | ||
| 23 | #include "exec.h" | 23 | #include "exec.h" |
| 24 | 24 | ||
| 25 | #ifndef CALL_FROM_TB0 | 25 | #ifndef CALL_FROM_TB0 |
| 26 | -#define CALL_FROM_TB0(func) func(); | 26 | +#define CALL_FROM_TB0(func) func() |
| 27 | #endif | 27 | #endif |
| 28 | #ifndef CALL_FROM_TB1 | 28 | #ifndef CALL_FROM_TB1 |
| 29 | -#define CALL_FROM_TB1(func, arg0) func(arg0); | 29 | +#define CALL_FROM_TB1(func, arg0) func(arg0) |
| 30 | #endif | 30 | #endif |
| 31 | #ifndef CALL_FROM_TB1_CONST16 | 31 | #ifndef CALL_FROM_TB1_CONST16 |
| 32 | -#define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0); | 32 | +#define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0) |
| 33 | #endif | 33 | #endif |
| 34 | #ifndef CALL_FROM_TB2 | 34 | #ifndef CALL_FROM_TB2 |
| 35 | -#define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1); | 35 | +#define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1) |
| 36 | #endif | 36 | #endif |
| 37 | #ifndef CALL_FROM_TB2_CONST16 | 37 | #ifndef CALL_FROM_TB2_CONST16 |
| 38 | #define CALL_FROM_TB2_CONST16(func, arg0, arg1) \ | 38 | #define CALL_FROM_TB2_CONST16(func, arg0, arg1) \ |
| 39 | -CALL_FROM_TB2(func, arg0, arg1); | 39 | + CALL_FROM_TB2(func, arg0, arg1) |
| 40 | #endif | 40 | #endif |
| 41 | #ifndef CALL_FROM_TB3 | 41 | #ifndef CALL_FROM_TB3 |
| 42 | -#define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2); | 42 | +#define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2) |
| 43 | #endif | 43 | #endif |
| 44 | #ifndef CALL_FROM_TB4 | 44 | #ifndef CALL_FROM_TB4 |
| 45 | #define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \ | 45 | #define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \ |
| 46 | - func(arg0, arg1, arg2, arg3); | 46 | + func(arg0, arg1, arg2, arg3) |
| 47 | #endif | 47 | #endif |
| 48 | 48 | ||
| 49 | #define REG 1 | 49 | #define REG 1 |
| @@ -144,134 +144,102 @@ CALL_FROM_TB2(func, arg0, arg1); | @@ -144,134 +144,102 @@ CALL_FROM_TB2(func, arg0, arg1); | ||
| 144 | #include "op_template.c" | 144 | #include "op_template.c" |
| 145 | #undef TN | 145 | #undef TN |
| 146 | 146 | ||
| 147 | -#define SFREG 0 | ||
| 148 | -#define DFREG 0 | 147 | +#define FREG 0 |
| 149 | #include "fop_template.c" | 148 | #include "fop_template.c" |
| 150 | -#undef SFREG | ||
| 151 | -#undef DFREG | ||
| 152 | -#define SFREG 1 | 149 | +#undef FREG |
| 150 | +#define FREG 1 | ||
| 153 | #include "fop_template.c" | 151 | #include "fop_template.c" |
| 154 | -#undef SFREG | ||
| 155 | -#define SFREG 2 | ||
| 156 | -#define DFREG 2 | 152 | +#undef FREG |
| 153 | +#define FREG 2 | ||
| 157 | #include "fop_template.c" | 154 | #include "fop_template.c" |
| 158 | -#undef SFREG | ||
| 159 | -#undef DFREG | ||
| 160 | -#define SFREG 3 | 155 | +#undef FREG |
| 156 | +#define FREG 3 | ||
| 161 | #include "fop_template.c" | 157 | #include "fop_template.c" |
| 162 | -#undef SFREG | ||
| 163 | -#define SFREG 4 | ||
| 164 | -#define DFREG 4 | 158 | +#undef FREG |
| 159 | +#define FREG 4 | ||
| 165 | #include "fop_template.c" | 160 | #include "fop_template.c" |
| 166 | -#undef SFREG | ||
| 167 | -#undef DFREG | ||
| 168 | -#define SFREG 5 | 161 | +#undef FREG |
| 162 | +#define FREG 5 | ||
| 169 | #include "fop_template.c" | 163 | #include "fop_template.c" |
| 170 | -#undef SFREG | ||
| 171 | -#define SFREG 6 | ||
| 172 | -#define DFREG 6 | 164 | +#undef FREG |
| 165 | +#define FREG 6 | ||
| 173 | #include "fop_template.c" | 166 | #include "fop_template.c" |
| 174 | -#undef SFREG | ||
| 175 | -#undef DFREG | ||
| 176 | -#define SFREG 7 | 167 | +#undef FREG |
| 168 | +#define FREG 7 | ||
| 177 | #include "fop_template.c" | 169 | #include "fop_template.c" |
| 178 | -#undef SFREG | ||
| 179 | -#define SFREG 8 | ||
| 180 | -#define DFREG 8 | 170 | +#undef FREG |
| 171 | +#define FREG 8 | ||
| 181 | #include "fop_template.c" | 172 | #include "fop_template.c" |
| 182 | -#undef SFREG | ||
| 183 | -#undef DFREG | ||
| 184 | -#define SFREG 9 | 173 | +#undef FREG |
| 174 | +#define FREG 9 | ||
| 185 | #include "fop_template.c" | 175 | #include "fop_template.c" |
| 186 | -#undef SFREG | ||
| 187 | -#define SFREG 10 | ||
| 188 | -#define DFREG 10 | 176 | +#undef FREG |
| 177 | +#define FREG 10 | ||
| 189 | #include "fop_template.c" | 178 | #include "fop_template.c" |
| 190 | -#undef SFREG | ||
| 191 | -#undef DFREG | ||
| 192 | -#define SFREG 11 | 179 | +#undef FREG |
| 180 | +#define FREG 11 | ||
| 193 | #include "fop_template.c" | 181 | #include "fop_template.c" |
| 194 | -#undef SFREG | ||
| 195 | -#define SFREG 12 | ||
| 196 | -#define DFREG 12 | 182 | +#undef FREG |
| 183 | +#define FREG 12 | ||
| 197 | #include "fop_template.c" | 184 | #include "fop_template.c" |
| 198 | -#undef SFREG | ||
| 199 | -#undef DFREG | ||
| 200 | -#define SFREG 13 | 185 | +#undef FREG |
| 186 | +#define FREG 13 | ||
| 201 | #include "fop_template.c" | 187 | #include "fop_template.c" |
| 202 | -#undef SFREG | ||
| 203 | -#define SFREG 14 | ||
| 204 | -#define DFREG 14 | 188 | +#undef FREG |
| 189 | +#define FREG 14 | ||
| 205 | #include "fop_template.c" | 190 | #include "fop_template.c" |
| 206 | -#undef SFREG | ||
| 207 | -#undef DFREG | ||
| 208 | -#define SFREG 15 | 191 | +#undef FREG |
| 192 | +#define FREG 15 | ||
| 209 | #include "fop_template.c" | 193 | #include "fop_template.c" |
| 210 | -#undef SFREG | ||
| 211 | -#define SFREG 16 | ||
| 212 | -#define DFREG 16 | 194 | +#undef FREG |
| 195 | +#define FREG 16 | ||
| 213 | #include "fop_template.c" | 196 | #include "fop_template.c" |
| 214 | -#undef SFREG | ||
| 215 | -#undef DFREG | ||
| 216 | -#define SFREG 17 | 197 | +#undef FREG |
| 198 | +#define FREG 17 | ||
| 217 | #include "fop_template.c" | 199 | #include "fop_template.c" |
| 218 | -#undef SFREG | ||
| 219 | -#define SFREG 18 | ||
| 220 | -#define DFREG 18 | 200 | +#undef FREG |
| 201 | +#define FREG 18 | ||
| 221 | #include "fop_template.c" | 202 | #include "fop_template.c" |
| 222 | -#undef SFREG | ||
| 223 | -#undef DFREG | ||
| 224 | -#define SFREG 19 | 203 | +#undef FREG |
| 204 | +#define FREG 19 | ||
| 225 | #include "fop_template.c" | 205 | #include "fop_template.c" |
| 226 | -#undef SFREG | ||
| 227 | -#define SFREG 20 | ||
| 228 | -#define DFREG 20 | 206 | +#undef FREG |
| 207 | +#define FREG 20 | ||
| 229 | #include "fop_template.c" | 208 | #include "fop_template.c" |
| 230 | -#undef SFREG | ||
| 231 | -#undef DFREG | ||
| 232 | -#define SFREG 21 | 209 | +#undef FREG |
| 210 | +#define FREG 21 | ||
| 233 | #include "fop_template.c" | 211 | #include "fop_template.c" |
| 234 | -#undef SFREG | ||
| 235 | -#define SFREG 22 | ||
| 236 | -#define DFREG 22 | 212 | +#undef FREG |
| 213 | +#define FREG 22 | ||
| 237 | #include "fop_template.c" | 214 | #include "fop_template.c" |
| 238 | -#undef SFREG | ||
| 239 | -#undef DFREG | ||
| 240 | -#define SFREG 23 | 215 | +#undef FREG |
| 216 | +#define FREG 23 | ||
| 241 | #include "fop_template.c" | 217 | #include "fop_template.c" |
| 242 | -#undef SFREG | ||
| 243 | -#define SFREG 24 | ||
| 244 | -#define DFREG 24 | 218 | +#undef FREG |
| 219 | +#define FREG 24 | ||
| 245 | #include "fop_template.c" | 220 | #include "fop_template.c" |
| 246 | -#undef SFREG | ||
| 247 | -#undef DFREG | ||
| 248 | -#define SFREG 25 | 221 | +#undef FREG |
| 222 | +#define FREG 25 | ||
| 249 | #include "fop_template.c" | 223 | #include "fop_template.c" |
| 250 | -#undef SFREG | ||
| 251 | -#define SFREG 26 | ||
| 252 | -#define DFREG 26 | 224 | +#undef FREG |
| 225 | +#define FREG 26 | ||
| 253 | #include "fop_template.c" | 226 | #include "fop_template.c" |
| 254 | -#undef SFREG | ||
| 255 | -#undef DFREG | ||
| 256 | -#define SFREG 27 | 227 | +#undef FREG |
| 228 | +#define FREG 27 | ||
| 257 | #include "fop_template.c" | 229 | #include "fop_template.c" |
| 258 | -#undef SFREG | ||
| 259 | -#define SFREG 28 | ||
| 260 | -#define DFREG 28 | 230 | +#undef FREG |
| 231 | +#define FREG 28 | ||
| 261 | #include "fop_template.c" | 232 | #include "fop_template.c" |
| 262 | -#undef SFREG | ||
| 263 | -#undef DFREG | ||
| 264 | -#define SFREG 29 | 233 | +#undef FREG |
| 234 | +#define FREG 29 | ||
| 265 | #include "fop_template.c" | 235 | #include "fop_template.c" |
| 266 | -#undef SFREG | ||
| 267 | -#define SFREG 30 | ||
| 268 | -#define DFREG 30 | 236 | +#undef FREG |
| 237 | +#define FREG 30 | ||
| 269 | #include "fop_template.c" | 238 | #include "fop_template.c" |
| 270 | -#undef SFREG | ||
| 271 | -#undef DFREG | ||
| 272 | -#define SFREG 31 | 239 | +#undef FREG |
| 240 | +#define FREG 31 | ||
| 273 | #include "fop_template.c" | 241 | #include "fop_template.c" |
| 274 | -#undef SFREG | 242 | +#undef FREG |
| 275 | 243 | ||
| 276 | #define FTN | 244 | #define FTN |
| 277 | #include "fop_template.c" | 245 | #include "fop_template.c" |
| @@ -919,14 +887,14 @@ void op_movz (void) | @@ -919,14 +887,14 @@ void op_movz (void) | ||
| 919 | void op_movf (void) | 887 | void op_movf (void) |
| 920 | { | 888 | { |
| 921 | if (!(env->fcr31 & PARAM1)) | 889 | if (!(env->fcr31 & PARAM1)) |
| 922 | - env->gpr[PARAM2] = env->gpr[PARAM3]; | 890 | + T0 = T1; |
| 923 | RETURN(); | 891 | RETURN(); |
| 924 | } | 892 | } |
| 925 | 893 | ||
| 926 | void op_movt (void) | 894 | void op_movt (void) |
| 927 | { | 895 | { |
| 928 | if (env->fcr31 & PARAM1) | 896 | if (env->fcr31 & PARAM1) |
| 929 | - env->gpr[PARAM2] = env->gpr[PARAM3]; | 897 | + T0 = T1; |
| 930 | RETURN(); | 898 | RETURN(); |
| 931 | } | 899 | } |
| 932 | 900 | ||
| @@ -1354,17 +1322,18 @@ void op_mtc0_compare (void) | @@ -1354,17 +1322,18 @@ void op_mtc0_compare (void) | ||
| 1354 | void op_mtc0_status (void) | 1322 | void op_mtc0_status (void) |
| 1355 | { | 1323 | { |
| 1356 | uint32_t val, old; | 1324 | uint32_t val, old; |
| 1325 | + uint32_t mask = env->Status_rw_bitmask; | ||
| 1357 | 1326 | ||
| 1358 | - /* No 64bit FPU, no reverse endianness, no MDMX/DSP, no 64bit ops, | 1327 | + /* No reverse endianness, no MDMX/DSP, no 64bit ops, |
| 1359 | no 64bit addressing implemented. */ | 1328 | no 64bit addressing implemented. */ |
| 1360 | - val = (int32_t)T0 & 0xF878FF17; | 1329 | + val = (int32_t)T0 & mask; |
| 1361 | old = env->CP0_Status; | 1330 | old = env->CP0_Status; |
| 1362 | if (!(val & (1 << CP0St_EXL)) && | 1331 | if (!(val & (1 << CP0St_EXL)) && |
| 1363 | !(val & (1 << CP0St_ERL)) && | 1332 | !(val & (1 << CP0St_ERL)) && |
| 1364 | !(env->hflags & MIPS_HFLAG_DM) && | 1333 | !(env->hflags & MIPS_HFLAG_DM) && |
| 1365 | (val & (1 << CP0St_UM))) | 1334 | (val & (1 << CP0St_UM))) |
| 1366 | env->hflags |= MIPS_HFLAG_UM; | 1335 | env->hflags |= MIPS_HFLAG_UM; |
| 1367 | - env->CP0_Status = (env->CP0_Status & ~0xF878FF17) | val; | 1336 | + env->CP0_Status = (env->CP0_Status & ~mask) | val; |
| 1368 | if (loglevel & CPU_LOG_EXEC) | 1337 | if (loglevel & CPU_LOG_EXEC) |
| 1369 | CALL_FROM_TB2(do_mtc0_status_debug, old, val); | 1338 | CALL_FROM_TB2(do_mtc0_status_debug, old, val); |
| 1370 | CALL_FROM_TB1(cpu_mips_update_irq, env); | 1339 | CALL_FROM_TB1(cpu_mips_update_irq, env); |
| @@ -1643,6 +1612,7 @@ void op_dmtc0_errorepc (void) | @@ -1643,6 +1612,7 @@ void op_dmtc0_errorepc (void) | ||
| 1643 | } | 1612 | } |
| 1644 | #endif /* TARGET_MIPS64 */ | 1613 | #endif /* TARGET_MIPS64 */ |
| 1645 | 1614 | ||
| 1615 | +/* CP1 functions */ | ||
| 1646 | #if 0 | 1616 | #if 0 |
| 1647 | # define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env) | 1617 | # define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env) |
| 1648 | #else | 1618 | #else |
| @@ -1666,20 +1636,6 @@ void op_cp1_enabled(void) | @@ -1666,20 +1636,6 @@ void op_cp1_enabled(void) | ||
| 1666 | RETURN(); | 1636 | RETURN(); |
| 1667 | } | 1637 | } |
| 1668 | 1638 | ||
| 1669 | -/* CP1 functions */ | ||
| 1670 | -void op_cfc1 (void) | ||
| 1671 | -{ | ||
| 1672 | - if (T1 == 0) { | ||
| 1673 | - T0 = env->fcr0; | ||
| 1674 | - } | ||
| 1675 | - else { | ||
| 1676 | - /* fetch fcr31, masking unused bits */ | ||
| 1677 | - T0 = env->fcr31 & 0x0183FFFF; | ||
| 1678 | - } | ||
| 1679 | - DEBUG_FPU_STATE(); | ||
| 1680 | - RETURN(); | ||
| 1681 | -} | ||
| 1682 | - | ||
| 1683 | /* convert MIPS rounding mode in FCR31 to IEEE library */ | 1639 | /* convert MIPS rounding mode in FCR31 to IEEE library */ |
| 1684 | unsigned int ieee_rm[] = { | 1640 | unsigned int ieee_rm[] = { |
| 1685 | float_round_nearest_even, | 1641 | float_round_nearest_even, |
| @@ -1691,26 +1647,93 @@ unsigned int ieee_rm[] = { | @@ -1691,26 +1647,93 @@ unsigned int ieee_rm[] = { | ||
| 1691 | #define RESTORE_ROUNDING_MODE \ | 1647 | #define RESTORE_ROUNDING_MODE \ |
| 1692 | set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status) | 1648 | set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status) |
| 1693 | 1649 | ||
| 1694 | -void op_ctc1 (void) | 1650 | +inline char ieee_ex_to_mips(char ieee) |
| 1695 | { | 1651 | { |
| 1696 | - if (T1 == 0) { | ||
| 1697 | - /* XXX should this throw an exception? | ||
| 1698 | - * don't write to FCR0. | ||
| 1699 | - * env->fcr0 = T0; | ||
| 1700 | - */ | ||
| 1701 | - } | ||
| 1702 | - else { | ||
| 1703 | - /* store new fcr31, masking unused bits */ | ||
| 1704 | - env->fcr31 = T0 & 0x0183FFFF; | 1652 | + return (ieee & float_flag_inexact) >> 5 | |
| 1653 | + (ieee & float_flag_underflow) >> 3 | | ||
| 1654 | + (ieee & float_flag_overflow) >> 1 | | ||
| 1655 | + (ieee & float_flag_divbyzero) << 1 | | ||
| 1656 | + (ieee & float_flag_invalid) << 4; | ||
| 1657 | +} | ||
| 1705 | 1658 | ||
| 1706 | - /* set rounding mode */ | ||
| 1707 | - RESTORE_ROUNDING_MODE; | 1659 | +inline char mips_ex_to_ieee(char mips) |
| 1660 | +{ | ||
| 1661 | + return (mips & FP_INEXACT) << 5 | | ||
| 1662 | + (mips & FP_UNDERFLOW) << 3 | | ||
| 1663 | + (mips & FP_OVERFLOW) << 1 | | ||
| 1664 | + (mips & FP_DIV0) >> 1 | | ||
| 1665 | + (mips & FP_INVALID) >> 4; | ||
| 1666 | +} | ||
| 1708 | 1667 | ||
| 1709 | -#ifndef CONFIG_SOFTFLOAT | ||
| 1710 | - /* no floating point exception for native float */ | ||
| 1711 | - SET_FP_ENABLE(env->fcr31, 0); | ||
| 1712 | -#endif | 1668 | +inline void update_fcr31(void) |
| 1669 | +{ | ||
| 1670 | + int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fp_status)); | ||
| 1671 | + | ||
| 1672 | + SET_FP_CAUSE(env->fcr31, tmp); | ||
| 1673 | + if (GET_FP_ENABLE(env->fcr31) & tmp) | ||
| 1674 | + CALL_FROM_TB1(do_raise_exception, EXCP_FPE); | ||
| 1675 | + else | ||
| 1676 | + UPDATE_FP_FLAGS(env->fcr31, tmp); | ||
| 1677 | +} | ||
| 1678 | + | ||
| 1679 | + | ||
| 1680 | +void op_cfc1 (void) | ||
| 1681 | +{ | ||
| 1682 | + switch (T1) { | ||
| 1683 | + case 0: | ||
| 1684 | + T0 = (int32_t)env->fcr0; | ||
| 1685 | + break; | ||
| 1686 | + case 25: | ||
| 1687 | + T0 = ((env->fcr31 >> 24) & 0xfe) | ((env->fcr31 >> 23) & 0x1); | ||
| 1688 | + break; | ||
| 1689 | + case 26: | ||
| 1690 | + T0 = env->fcr31 & 0x0003f07c; | ||
| 1691 | + break; | ||
| 1692 | + case 28: | ||
| 1693 | + T0 = (env->fcr31 & 0x00000f83) | ((env->fcr31 >> 22) & 0x4); | ||
| 1694 | + break; | ||
| 1695 | + default: | ||
| 1696 | + T0 = (int32_t)env->fcr31; | ||
| 1697 | + break; | ||
| 1698 | + } | ||
| 1699 | + DEBUG_FPU_STATE(); | ||
| 1700 | + RETURN(); | ||
| 1701 | +} | ||
| 1702 | + | ||
| 1703 | +void op_ctc1 (void) | ||
| 1704 | +{ | ||
| 1705 | + switch(T1) { | ||
| 1706 | + case 25: | ||
| 1707 | + if (T0 & 0xffffff00) | ||
| 1708 | + goto leave; | ||
| 1709 | + env->fcr31 = (env->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) | | ||
| 1710 | + ((T0 & 0x1) << 23); | ||
| 1711 | + break; | ||
| 1712 | + case 26: | ||
| 1713 | + if (T0 & 0x007c0000) | ||
| 1714 | + goto leave; | ||
| 1715 | + env->fcr31 = (env->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c); | ||
| 1716 | + break; | ||
| 1717 | + case 28: | ||
| 1718 | + if (T0 & 0x007c0000) | ||
| 1719 | + goto leave; | ||
| 1720 | + env->fcr31 = (env->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) | | ||
| 1721 | + ((T0 & 0x4) << 22); | ||
| 1722 | + break; | ||
| 1723 | + case 31: | ||
| 1724 | + if (T0 & 0x007c0000) | ||
| 1725 | + goto leave; | ||
| 1726 | + env->fcr31 = T0; | ||
| 1727 | + break; | ||
| 1728 | + default: | ||
| 1729 | + goto leave; | ||
| 1713 | } | 1730 | } |
| 1731 | + /* set rounding mode */ | ||
| 1732 | + RESTORE_ROUNDING_MODE; | ||
| 1733 | + set_float_exception_flags(0, &env->fp_status); | ||
| 1734 | + if ((GET_FP_ENABLE(env->fcr31) | 0x20) & GET_FP_CAUSE(env->fcr31)) | ||
| 1735 | + CALL_FROM_TB1(do_raise_exception, EXCP_FPE); | ||
| 1736 | + leave: | ||
| 1714 | DEBUG_FPU_STATE(); | 1737 | DEBUG_FPU_STATE(); |
| 1715 | RETURN(); | 1738 | RETURN(); |
| 1716 | } | 1739 | } |
| @@ -1729,55 +1752,219 @@ void op_mtc1 (void) | @@ -1729,55 +1752,219 @@ void op_mtc1 (void) | ||
| 1729 | RETURN(); | 1752 | RETURN(); |
| 1730 | } | 1753 | } |
| 1731 | 1754 | ||
| 1755 | +void op_dmfc1 (void) | ||
| 1756 | +{ | ||
| 1757 | + T0 = DT0; | ||
| 1758 | + DEBUG_FPU_STATE(); | ||
| 1759 | + RETURN(); | ||
| 1760 | +} | ||
| 1761 | + | ||
| 1762 | +void op_dmtc1 (void) | ||
| 1763 | +{ | ||
| 1764 | + DT0 = T0; | ||
| 1765 | + DEBUG_FPU_STATE(); | ||
| 1766 | + RETURN(); | ||
| 1767 | +} | ||
| 1768 | + | ||
| 1769 | +void op_mfhc1 (void) | ||
| 1770 | +{ | ||
| 1771 | + T0 = WTH0; | ||
| 1772 | + DEBUG_FPU_STATE(); | ||
| 1773 | + RETURN(); | ||
| 1774 | +} | ||
| 1775 | + | ||
| 1776 | +void op_mthc1 (void) | ||
| 1777 | +{ | ||
| 1778 | + WTH0 = T0; | ||
| 1779 | + DEBUG_FPU_STATE(); | ||
| 1780 | + RETURN(); | ||
| 1781 | +} | ||
| 1782 | + | ||
| 1732 | /* Float support. | 1783 | /* Float support. |
| 1733 | Single precition routines have a "s" suffix, double precision a | 1784 | Single precition routines have a "s" suffix, double precision a |
| 1734 | - "d" suffix. */ | 1785 | + "d" suffix, 32bit integer "w", 64bit integer "l", paired singe "ps", |
| 1786 | + paired single lowwer "pl", paired single upper "pu". */ | ||
| 1735 | 1787 | ||
| 1736 | #define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void) | 1788 | #define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void) |
| 1737 | 1789 | ||
| 1738 | FLOAT_OP(cvtd, s) | 1790 | FLOAT_OP(cvtd, s) |
| 1739 | { | 1791 | { |
| 1792 | + set_float_exception_flags(0, &env->fp_status); | ||
| 1740 | FDT2 = float32_to_float64(FST0, &env->fp_status); | 1793 | FDT2 = float32_to_float64(FST0, &env->fp_status); |
| 1794 | + update_fcr31(); | ||
| 1741 | DEBUG_FPU_STATE(); | 1795 | DEBUG_FPU_STATE(); |
| 1742 | RETURN(); | 1796 | RETURN(); |
| 1743 | } | 1797 | } |
| 1744 | FLOAT_OP(cvtd, w) | 1798 | FLOAT_OP(cvtd, w) |
| 1745 | { | 1799 | { |
| 1800 | + set_float_exception_flags(0, &env->fp_status); | ||
| 1746 | FDT2 = int32_to_float64(WT0, &env->fp_status); | 1801 | FDT2 = int32_to_float64(WT0, &env->fp_status); |
| 1802 | + update_fcr31(); | ||
| 1803 | + DEBUG_FPU_STATE(); | ||
| 1804 | + RETURN(); | ||
| 1805 | +} | ||
| 1806 | +FLOAT_OP(cvtd, l) | ||
| 1807 | +{ | ||
| 1808 | + set_float_exception_flags(0, &env->fp_status); | ||
| 1809 | + FDT2 = int64_to_float64(DT0, &env->fp_status); | ||
| 1810 | + update_fcr31(); | ||
| 1811 | + DEBUG_FPU_STATE(); | ||
| 1812 | + RETURN(); | ||
| 1813 | +} | ||
| 1814 | +FLOAT_OP(cvtl, d) | ||
| 1815 | +{ | ||
| 1816 | + set_float_exception_flags(0, &env->fp_status); | ||
| 1817 | + DT2 = float64_to_int64(FDT0, &env->fp_status); | ||
| 1818 | + update_fcr31(); | ||
| 1819 | + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) | ||
| 1820 | + DT2 = 0x7fffffffffffffffULL; | ||
| 1821 | + DEBUG_FPU_STATE(); | ||
| 1822 | + RETURN(); | ||
| 1823 | +} | ||
| 1824 | +FLOAT_OP(cvtl, s) | ||
| 1825 | +{ | ||
| 1826 | + set_float_exception_flags(0, &env->fp_status); | ||
| 1827 | + DT2 = float32_to_int64(FST0, &env->fp_status); | ||
| 1828 | + update_fcr31(); | ||
| 1829 | + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) | ||
| 1830 | + DT2 = 0x7fffffffffffffffULL; | ||
| 1831 | + DEBUG_FPU_STATE(); | ||
| 1832 | + RETURN(); | ||
| 1833 | +} | ||
| 1834 | +FLOAT_OP(cvtps, s) | ||
| 1835 | +{ | ||
| 1836 | + WT2 = WT0; | ||
| 1837 | + WTH2 = WT1; | ||
| 1838 | + DEBUG_FPU_STATE(); | ||
| 1839 | + RETURN(); | ||
| 1840 | +} | ||
| 1841 | +FLOAT_OP(cvtps, pw) | ||
| 1842 | +{ | ||
| 1843 | + set_float_exception_flags(0, &env->fp_status); | ||
| 1844 | + FST2 = int32_to_float32(WT0, &env->fp_status); | ||
| 1845 | + FSTH2 = int32_to_float32(WTH0, &env->fp_status); | ||
| 1846 | + update_fcr31(); | ||
| 1847 | + DEBUG_FPU_STATE(); | ||
| 1848 | + RETURN(); | ||
| 1849 | +} | ||
| 1850 | +FLOAT_OP(cvtpw, ps) | ||
| 1851 | +{ | ||
| 1852 | + set_float_exception_flags(0, &env->fp_status); | ||
| 1853 | + WT2 = float32_to_int32(FST0, &env->fp_status); | ||
| 1854 | + WTH2 = float32_to_int32(FSTH0, &env->fp_status); | ||
| 1855 | + update_fcr31(); | ||
| 1856 | + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) | ||
| 1857 | + WT2 = 0x7fffffff; | ||
| 1747 | DEBUG_FPU_STATE(); | 1858 | DEBUG_FPU_STATE(); |
| 1748 | RETURN(); | 1859 | RETURN(); |
| 1749 | } | 1860 | } |
| 1750 | FLOAT_OP(cvts, d) | 1861 | FLOAT_OP(cvts, d) |
| 1751 | { | 1862 | { |
| 1863 | + set_float_exception_flags(0, &env->fp_status); | ||
| 1752 | FST2 = float64_to_float32(FDT0, &env->fp_status); | 1864 | FST2 = float64_to_float32(FDT0, &env->fp_status); |
| 1865 | + update_fcr31(); | ||
| 1753 | DEBUG_FPU_STATE(); | 1866 | DEBUG_FPU_STATE(); |
| 1754 | RETURN(); | 1867 | RETURN(); |
| 1755 | } | 1868 | } |
| 1756 | FLOAT_OP(cvts, w) | 1869 | FLOAT_OP(cvts, w) |
| 1757 | { | 1870 | { |
| 1871 | + set_float_exception_flags(0, &env->fp_status); | ||
| 1758 | FST2 = int32_to_float32(WT0, &env->fp_status); | 1872 | FST2 = int32_to_float32(WT0, &env->fp_status); |
| 1873 | + update_fcr31(); | ||
| 1874 | + DEBUG_FPU_STATE(); | ||
| 1875 | + RETURN(); | ||
| 1876 | +} | ||
| 1877 | +FLOAT_OP(cvts, l) | ||
| 1878 | +{ | ||
| 1879 | + set_float_exception_flags(0, &env->fp_status); | ||
| 1880 | + FST2 = int64_to_float32(DT0, &env->fp_status); | ||
| 1881 | + update_fcr31(); | ||
| 1882 | + DEBUG_FPU_STATE(); | ||
| 1883 | + RETURN(); | ||
| 1884 | +} | ||
| 1885 | +FLOAT_OP(cvts, pl) | ||
| 1886 | +{ | ||
| 1887 | + set_float_exception_flags(0, &env->fp_status); | ||
| 1888 | + WT2 = WT0; | ||
| 1889 | + update_fcr31(); | ||
| 1890 | + DEBUG_FPU_STATE(); | ||
| 1891 | + RETURN(); | ||
| 1892 | +} | ||
| 1893 | +FLOAT_OP(cvts, pu) | ||
| 1894 | +{ | ||
| 1895 | + set_float_exception_flags(0, &env->fp_status); | ||
| 1896 | + WT2 = WTH0; | ||
| 1897 | + update_fcr31(); | ||
| 1759 | DEBUG_FPU_STATE(); | 1898 | DEBUG_FPU_STATE(); |
| 1760 | RETURN(); | 1899 | RETURN(); |
| 1761 | } | 1900 | } |
| 1762 | FLOAT_OP(cvtw, s) | 1901 | FLOAT_OP(cvtw, s) |
| 1763 | { | 1902 | { |
| 1903 | + set_float_exception_flags(0, &env->fp_status); | ||
| 1764 | WT2 = float32_to_int32(FST0, &env->fp_status); | 1904 | WT2 = float32_to_int32(FST0, &env->fp_status); |
| 1905 | + update_fcr31(); | ||
| 1906 | + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) | ||
| 1907 | + WT2 = 0x7fffffff; | ||
| 1765 | DEBUG_FPU_STATE(); | 1908 | DEBUG_FPU_STATE(); |
| 1766 | RETURN(); | 1909 | RETURN(); |
| 1767 | } | 1910 | } |
| 1768 | FLOAT_OP(cvtw, d) | 1911 | FLOAT_OP(cvtw, d) |
| 1769 | { | 1912 | { |
| 1913 | + set_float_exception_flags(0, &env->fp_status); | ||
| 1770 | WT2 = float64_to_int32(FDT0, &env->fp_status); | 1914 | WT2 = float64_to_int32(FDT0, &env->fp_status); |
| 1915 | + update_fcr31(); | ||
| 1916 | + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) | ||
| 1917 | + WT2 = 0x7fffffff; | ||
| 1918 | + DEBUG_FPU_STATE(); | ||
| 1919 | + RETURN(); | ||
| 1920 | +} | ||
| 1921 | + | ||
| 1922 | +FLOAT_OP(pll, ps) | ||
| 1923 | +{ | ||
| 1924 | + DT2 = ((uint64_t)WT0 << 32) | WT1; | ||
| 1925 | + DEBUG_FPU_STATE(); | ||
| 1926 | + RETURN(); | ||
| 1927 | +} | ||
| 1928 | +FLOAT_OP(plu, ps) | ||
| 1929 | +{ | ||
| 1930 | + DT2 = ((uint64_t)WT0 << 32) | WTH1; | ||
| 1931 | + DEBUG_FPU_STATE(); | ||
| 1932 | + RETURN(); | ||
| 1933 | +} | ||
| 1934 | +FLOAT_OP(pul, ps) | ||
| 1935 | +{ | ||
| 1936 | + DT2 = ((uint64_t)WTH0 << 32) | WT1; | ||
| 1937 | + DEBUG_FPU_STATE(); | ||
| 1938 | + RETURN(); | ||
| 1939 | +} | ||
| 1940 | +FLOAT_OP(puu, ps) | ||
| 1941 | +{ | ||
| 1942 | + DT2 = ((uint64_t)WTH0 << 32) | WTH1; | ||
| 1771 | DEBUG_FPU_STATE(); | 1943 | DEBUG_FPU_STATE(); |
| 1772 | RETURN(); | 1944 | RETURN(); |
| 1773 | } | 1945 | } |
| 1774 | 1946 | ||
| 1947 | +FLOAT_OP(roundl, d) | ||
| 1948 | +{ | ||
| 1949 | + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); | ||
| 1950 | + DT2 = float64_round_to_int(FDT0, &env->fp_status); | ||
| 1951 | + RESTORE_ROUNDING_MODE; | ||
| 1952 | + DEBUG_FPU_STATE(); | ||
| 1953 | + RETURN(); | ||
| 1954 | +} | ||
| 1955 | +FLOAT_OP(roundl, s) | ||
| 1956 | +{ | ||
| 1957 | + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); | ||
| 1958 | + DT2 = float32_round_to_int(FST0, &env->fp_status); | ||
| 1959 | + RESTORE_ROUNDING_MODE; | ||
| 1960 | + DEBUG_FPU_STATE(); | ||
| 1961 | + RETURN(); | ||
| 1962 | +} | ||
| 1775 | FLOAT_OP(roundw, d) | 1963 | FLOAT_OP(roundw, d) |
| 1776 | { | 1964 | { |
| 1777 | set_float_rounding_mode(float_round_nearest_even, &env->fp_status); | 1965 | set_float_rounding_mode(float_round_nearest_even, &env->fp_status); |
| 1778 | WT2 = float64_round_to_int(FDT0, &env->fp_status); | 1966 | WT2 = float64_round_to_int(FDT0, &env->fp_status); |
| 1779 | RESTORE_ROUNDING_MODE; | 1967 | RESTORE_ROUNDING_MODE; |
| 1780 | - | ||
| 1781 | DEBUG_FPU_STATE(); | 1968 | DEBUG_FPU_STATE(); |
| 1782 | RETURN(); | 1969 | RETURN(); |
| 1783 | } | 1970 | } |
| @@ -1790,6 +1977,18 @@ FLOAT_OP(roundw, s) | @@ -1790,6 +1977,18 @@ FLOAT_OP(roundw, s) | ||
| 1790 | RETURN(); | 1977 | RETURN(); |
| 1791 | } | 1978 | } |
| 1792 | 1979 | ||
| 1980 | +FLOAT_OP(truncl, d) | ||
| 1981 | +{ | ||
| 1982 | + DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status); | ||
| 1983 | + DEBUG_FPU_STATE(); | ||
| 1984 | + RETURN(); | ||
| 1985 | +} | ||
| 1986 | +FLOAT_OP(truncl, s) | ||
| 1987 | +{ | ||
| 1988 | + DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status); | ||
| 1989 | + DEBUG_FPU_STATE(); | ||
| 1990 | + RETURN(); | ||
| 1991 | +} | ||
| 1793 | FLOAT_OP(truncw, d) | 1992 | FLOAT_OP(truncw, d) |
| 1794 | { | 1993 | { |
| 1795 | WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status); | 1994 | WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status); |
| @@ -1803,12 +2002,27 @@ FLOAT_OP(truncw, s) | @@ -1803,12 +2002,27 @@ FLOAT_OP(truncw, s) | ||
| 1803 | RETURN(); | 2002 | RETURN(); |
| 1804 | } | 2003 | } |
| 1805 | 2004 | ||
| 2005 | +FLOAT_OP(ceill, d) | ||
| 2006 | +{ | ||
| 2007 | + set_float_rounding_mode(float_round_up, &env->fp_status); | ||
| 2008 | + DT2 = float64_round_to_int(FDT0, &env->fp_status); | ||
| 2009 | + RESTORE_ROUNDING_MODE; | ||
| 2010 | + DEBUG_FPU_STATE(); | ||
| 2011 | + RETURN(); | ||
| 2012 | +} | ||
| 2013 | +FLOAT_OP(ceill, s) | ||
| 2014 | +{ | ||
| 2015 | + set_float_rounding_mode(float_round_up, &env->fp_status); | ||
| 2016 | + DT2 = float32_round_to_int(FST0, &env->fp_status); | ||
| 2017 | + RESTORE_ROUNDING_MODE; | ||
| 2018 | + DEBUG_FPU_STATE(); | ||
| 2019 | + RETURN(); | ||
| 2020 | +} | ||
| 1806 | FLOAT_OP(ceilw, d) | 2021 | FLOAT_OP(ceilw, d) |
| 1807 | { | 2022 | { |
| 1808 | set_float_rounding_mode(float_round_up, &env->fp_status); | 2023 | set_float_rounding_mode(float_round_up, &env->fp_status); |
| 1809 | WT2 = float64_round_to_int(FDT0, &env->fp_status); | 2024 | WT2 = float64_round_to_int(FDT0, &env->fp_status); |
| 1810 | RESTORE_ROUNDING_MODE; | 2025 | RESTORE_ROUNDING_MODE; |
| 1811 | - | ||
| 1812 | DEBUG_FPU_STATE(); | 2026 | DEBUG_FPU_STATE(); |
| 1813 | RETURN(); | 2027 | RETURN(); |
| 1814 | } | 2028 | } |
| @@ -1821,12 +2035,27 @@ FLOAT_OP(ceilw, s) | @@ -1821,12 +2035,27 @@ FLOAT_OP(ceilw, s) | ||
| 1821 | RETURN(); | 2035 | RETURN(); |
| 1822 | } | 2036 | } |
| 1823 | 2037 | ||
| 2038 | +FLOAT_OP(floorl, d) | ||
| 2039 | +{ | ||
| 2040 | + set_float_rounding_mode(float_round_down, &env->fp_status); | ||
| 2041 | + DT2 = float64_round_to_int(FDT0, &env->fp_status); | ||
| 2042 | + RESTORE_ROUNDING_MODE; | ||
| 2043 | + DEBUG_FPU_STATE(); | ||
| 2044 | + RETURN(); | ||
| 2045 | +} | ||
| 2046 | +FLOAT_OP(floorl, s) | ||
| 2047 | +{ | ||
| 2048 | + set_float_rounding_mode(float_round_down, &env->fp_status); | ||
| 2049 | + DT2 = float32_round_to_int(FST0, &env->fp_status); | ||
| 2050 | + RESTORE_ROUNDING_MODE; | ||
| 2051 | + DEBUG_FPU_STATE(); | ||
| 2052 | + RETURN(); | ||
| 2053 | +} | ||
| 1824 | FLOAT_OP(floorw, d) | 2054 | FLOAT_OP(floorw, d) |
| 1825 | { | 2055 | { |
| 1826 | set_float_rounding_mode(float_round_down, &env->fp_status); | 2056 | set_float_rounding_mode(float_round_down, &env->fp_status); |
| 1827 | WT2 = float64_round_to_int(FDT0, &env->fp_status); | 2057 | WT2 = float64_round_to_int(FDT0, &env->fp_status); |
| 1828 | RESTORE_ROUNDING_MODE; | 2058 | RESTORE_ROUNDING_MODE; |
| 1829 | - | ||
| 1830 | DEBUG_FPU_STATE(); | 2059 | DEBUG_FPU_STATE(); |
| 1831 | RETURN(); | 2060 | RETURN(); |
| 1832 | } | 2061 | } |
| @@ -1839,16 +2068,121 @@ FLOAT_OP(floorw, s) | @@ -1839,16 +2068,121 @@ FLOAT_OP(floorw, s) | ||
| 1839 | RETURN(); | 2068 | RETURN(); |
| 1840 | } | 2069 | } |
| 1841 | 2070 | ||
| 2071 | +FLOAT_OP(movf, d) | ||
| 2072 | +{ | ||
| 2073 | + if (!(env->fcr31 & PARAM1)) | ||
| 2074 | + DT2 = DT0; | ||
| 2075 | + DEBUG_FPU_STATE(); | ||
| 2076 | + RETURN(); | ||
| 2077 | +} | ||
| 2078 | +FLOAT_OP(movf, s) | ||
| 2079 | +{ | ||
| 2080 | + if (!(env->fcr31 & PARAM1)) | ||
| 2081 | + WT2 = WT0; | ||
| 2082 | + DEBUG_FPU_STATE(); | ||
| 2083 | + RETURN(); | ||
| 2084 | +} | ||
| 2085 | +FLOAT_OP(movf, ps) | ||
| 2086 | +{ | ||
| 2087 | + if (!(env->fcr31 & PARAM1)) { | ||
| 2088 | + WT2 = WT0; | ||
| 2089 | + WTH2 = WTH0; | ||
| 2090 | + } | ||
| 2091 | + DEBUG_FPU_STATE(); | ||
| 2092 | + RETURN(); | ||
| 2093 | +} | ||
| 2094 | +FLOAT_OP(movt, d) | ||
| 2095 | +{ | ||
| 2096 | + if (env->fcr31 & PARAM1) | ||
| 2097 | + DT2 = DT0; | ||
| 2098 | + DEBUG_FPU_STATE(); | ||
| 2099 | + RETURN(); | ||
| 2100 | +} | ||
| 2101 | +FLOAT_OP(movt, s) | ||
| 2102 | +{ | ||
| 2103 | + if (env->fcr31 & PARAM1) | ||
| 2104 | + WT2 = WT0; | ||
| 2105 | + DEBUG_FPU_STATE(); | ||
| 2106 | + RETURN(); | ||
| 2107 | +} | ||
| 2108 | +FLOAT_OP(movt, ps) | ||
| 2109 | +{ | ||
| 2110 | + if (env->fcr31 & PARAM1) { | ||
| 2111 | + WT2 = WT0; | ||
| 2112 | + WTH2 = WTH0; | ||
| 2113 | + } | ||
| 2114 | + DEBUG_FPU_STATE(); | ||
| 2115 | + RETURN(); | ||
| 2116 | +} | ||
| 2117 | +FLOAT_OP(movz, d) | ||
| 2118 | +{ | ||
| 2119 | + if (!T0) | ||
| 2120 | + DT2 = DT0; | ||
| 2121 | + DEBUG_FPU_STATE(); | ||
| 2122 | + RETURN(); | ||
| 2123 | +} | ||
| 2124 | +FLOAT_OP(movz, s) | ||
| 2125 | +{ | ||
| 2126 | + if (!T0) | ||
| 2127 | + WT2 = WT0; | ||
| 2128 | + DEBUG_FPU_STATE(); | ||
| 2129 | + RETURN(); | ||
| 2130 | +} | ||
| 2131 | +FLOAT_OP(movz, ps) | ||
| 2132 | +{ | ||
| 2133 | + if (!T0) { | ||
| 2134 | + WT2 = WT0; | ||
| 2135 | + WTH2 = WTH0; | ||
| 2136 | + } | ||
| 2137 | + DEBUG_FPU_STATE(); | ||
| 2138 | + RETURN(); | ||
| 2139 | +} | ||
| 2140 | +FLOAT_OP(movn, d) | ||
| 2141 | +{ | ||
| 2142 | + if (T0) | ||
| 2143 | + DT2 = DT0; | ||
| 2144 | + DEBUG_FPU_STATE(); | ||
| 2145 | + RETURN(); | ||
| 2146 | +} | ||
| 2147 | +FLOAT_OP(movn, s) | ||
| 2148 | +{ | ||
| 2149 | + if (T0) | ||
| 2150 | + WT2 = WT0; | ||
| 2151 | + DEBUG_FPU_STATE(); | ||
| 2152 | + RETURN(); | ||
| 2153 | +} | ||
| 2154 | +FLOAT_OP(movn, ps) | ||
| 2155 | +{ | ||
| 2156 | + if (T0) { | ||
| 2157 | + WT2 = WT0; | ||
| 2158 | + WTH2 = WTH0; | ||
| 2159 | + } | ||
| 2160 | + DEBUG_FPU_STATE(); | ||
| 2161 | + RETURN(); | ||
| 2162 | +} | ||
| 2163 | + | ||
| 1842 | /* binary operations */ | 2164 | /* binary operations */ |
| 1843 | #define FLOAT_BINOP(name) \ | 2165 | #define FLOAT_BINOP(name) \ |
| 1844 | FLOAT_OP(name, d) \ | 2166 | FLOAT_OP(name, d) \ |
| 1845 | { \ | 2167 | { \ |
| 2168 | + set_float_exception_flags(0, &env->fp_status); \ | ||
| 1846 | FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \ | 2169 | FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \ |
| 2170 | + update_fcr31(); \ | ||
| 1847 | DEBUG_FPU_STATE(); \ | 2171 | DEBUG_FPU_STATE(); \ |
| 1848 | } \ | 2172 | } \ |
| 1849 | FLOAT_OP(name, s) \ | 2173 | FLOAT_OP(name, s) \ |
| 1850 | { \ | 2174 | { \ |
| 2175 | + set_float_exception_flags(0, &env->fp_status); \ | ||
| 1851 | FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ | 2176 | FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ |
| 2177 | + update_fcr31(); \ | ||
| 2178 | + DEBUG_FPU_STATE(); \ | ||
| 2179 | +} \ | ||
| 2180 | +FLOAT_OP(name, ps) \ | ||
| 2181 | +{ \ | ||
| 2182 | + set_float_exception_flags(0, &env->fp_status); \ | ||
| 2183 | + FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ | ||
| 2184 | + FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \ | ||
| 2185 | + update_fcr31(); \ | ||
| 1852 | DEBUG_FPU_STATE(); \ | 2186 | DEBUG_FPU_STATE(); \ |
| 1853 | } | 2187 | } |
| 1854 | FLOAT_BINOP(add) | 2188 | FLOAT_BINOP(add) |
| @@ -1857,6 +2191,32 @@ FLOAT_BINOP(mul) | @@ -1857,6 +2191,32 @@ FLOAT_BINOP(mul) | ||
| 1857 | FLOAT_BINOP(div) | 2191 | FLOAT_BINOP(div) |
| 1858 | #undef FLOAT_BINOP | 2192 | #undef FLOAT_BINOP |
| 1859 | 2193 | ||
| 2194 | +/* ternary operations */ | ||
| 2195 | +#define FLOAT_TERNOP(name1, name2) \ | ||
| 2196 | +FLOAT_OP(name1 ## name2, d) \ | ||
| 2197 | +{ \ | ||
| 2198 | + FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fp_status); \ | ||
| 2199 | + FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fp_status); \ | ||
| 2200 | + DEBUG_FPU_STATE(); \ | ||
| 2201 | +} \ | ||
| 2202 | +FLOAT_OP(name1 ## name2, s) \ | ||
| 2203 | +{ \ | ||
| 2204 | + FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \ | ||
| 2205 | + FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ | ||
| 2206 | + DEBUG_FPU_STATE(); \ | ||
| 2207 | +} \ | ||
| 2208 | +FLOAT_OP(name1 ## name2, ps) \ | ||
| 2209 | +{ \ | ||
| 2210 | + FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \ | ||
| 2211 | + FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fp_status); \ | ||
| 2212 | + FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ | ||
| 2213 | + FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fp_status); \ | ||
| 2214 | + DEBUG_FPU_STATE(); \ | ||
| 2215 | +} | ||
| 2216 | +FLOAT_TERNOP(mul, add) | ||
| 2217 | +FLOAT_TERNOP(mul, sub) | ||
| 2218 | +#undef FLOAT_TERNOP | ||
| 2219 | + | ||
| 1860 | /* unary operations, modifying fp status */ | 2220 | /* unary operations, modifying fp status */ |
| 1861 | #define FLOAT_UNOP(name) \ | 2221 | #define FLOAT_UNOP(name) \ |
| 1862 | FLOAT_OP(name, d) \ | 2222 | FLOAT_OP(name, d) \ |
| @@ -1868,6 +2228,12 @@ FLOAT_OP(name, s) \ | @@ -1868,6 +2228,12 @@ FLOAT_OP(name, s) \ | ||
| 1868 | { \ | 2228 | { \ |
| 1869 | FST2 = float32_ ## name(FST0, &env->fp_status); \ | 2229 | FST2 = float32_ ## name(FST0, &env->fp_status); \ |
| 1870 | DEBUG_FPU_STATE(); \ | 2230 | DEBUG_FPU_STATE(); \ |
| 2231 | +} \ | ||
| 2232 | +FLOAT_OP(name, ps) \ | ||
| 2233 | +{ \ | ||
| 2234 | + FST2 = float32_ ## name(FST0, &env->fp_status); \ | ||
| 2235 | + FSTH2 = float32_ ## name(FSTH0, &env->fp_status); \ | ||
| 2236 | + DEBUG_FPU_STATE(); \ | ||
| 1871 | } | 2237 | } |
| 1872 | FLOAT_UNOP(sqrt) | 2238 | FLOAT_UNOP(sqrt) |
| 1873 | #undef FLOAT_UNOP | 2239 | #undef FLOAT_UNOP |
| @@ -1883,6 +2249,12 @@ FLOAT_OP(name, s) \ | @@ -1883,6 +2249,12 @@ FLOAT_OP(name, s) \ | ||
| 1883 | { \ | 2249 | { \ |
| 1884 | FST2 = float32_ ## name(FST0); \ | 2250 | FST2 = float32_ ## name(FST0); \ |
| 1885 | DEBUG_FPU_STATE(); \ | 2251 | DEBUG_FPU_STATE(); \ |
| 2252 | +} \ | ||
| 2253 | +FLOAT_OP(name, ps) \ | ||
| 2254 | +{ \ | ||
| 2255 | + FST2 = float32_ ## name(FST0); \ | ||
| 2256 | + FSTH2 = float32_ ## name(FSTH0); \ | ||
| 2257 | + DEBUG_FPU_STATE(); \ | ||
| 1886 | } | 2258 | } |
| 1887 | FLOAT_UNOP(abs) | 2259 | FLOAT_UNOP(abs) |
| 1888 | FLOAT_UNOP(chs) | 2260 | FLOAT_UNOP(chs) |
| @@ -1900,6 +2272,35 @@ FLOAT_OP(mov, s) | @@ -1900,6 +2272,35 @@ FLOAT_OP(mov, s) | ||
| 1900 | DEBUG_FPU_STATE(); | 2272 | DEBUG_FPU_STATE(); |
| 1901 | RETURN(); | 2273 | RETURN(); |
| 1902 | } | 2274 | } |
| 2275 | +FLOAT_OP(mov, ps) | ||
| 2276 | +{ | ||
| 2277 | + FST2 = FST0; | ||
| 2278 | + FSTH2 = FSTH0; | ||
| 2279 | + DEBUG_FPU_STATE(); | ||
| 2280 | + RETURN(); | ||
| 2281 | +} | ||
| 2282 | +FLOAT_OP(alnv, ps) | ||
| 2283 | +{ | ||
| 2284 | + switch (T0 & 0x7) { | ||
| 2285 | + case 0: | ||
| 2286 | + FST2 = FST0; | ||
| 2287 | + FSTH2 = FSTH0; | ||
| 2288 | + break; | ||
| 2289 | + case 4: | ||
| 2290 | +#ifdef TARGET_WORDS_BIGENDIAN | ||
| 2291 | + FSTH2 = FST0; | ||
| 2292 | + FST2 = FSTH1; | ||
| 2293 | +#else | ||
| 2294 | + FSTH2 = FST1; | ||
| 2295 | + FST2 = FSTH0; | ||
| 2296 | +#endif | ||
| 2297 | + break; | ||
| 2298 | + default: /* unpredictable */ | ||
| 2299 | + break; | ||
| 2300 | + } | ||
| 2301 | + DEBUG_FPU_STATE(); | ||
| 2302 | + RETURN(); | ||
| 2303 | +} | ||
| 1903 | 2304 | ||
| 1904 | #ifdef CONFIG_SOFTFLOAT | 2305 | #ifdef CONFIG_SOFTFLOAT |
| 1905 | #define clear_invalid() do { \ | 2306 | #define clear_invalid() do { \ |
| @@ -1913,96 +2314,200 @@ FLOAT_OP(mov, s) | @@ -1913,96 +2314,200 @@ FLOAT_OP(mov, s) | ||
| 1913 | 2314 | ||
| 1914 | extern void dump_fpu_s(CPUState *env); | 2315 | extern void dump_fpu_s(CPUState *env); |
| 1915 | 2316 | ||
| 1916 | -#define FOP_COND(fmt, op, sig, cond) \ | ||
| 1917 | -void op_cmp_ ## fmt ## _ ## op (void) \ | 2317 | +#define FOP_COND_D(op, cond) \ |
| 2318 | +void op_cmp_d_ ## op (void) \ | ||
| 1918 | { \ | 2319 | { \ |
| 1919 | - if (cond) \ | ||
| 1920 | - SET_FP_COND(env->fcr31); \ | 2320 | + int c = cond; \ |
| 2321 | + update_fcr31(); \ | ||
| 2322 | + if (c) \ | ||
| 2323 | + SET_FP_COND(PARAM1, env); \ | ||
| 1921 | else \ | 2324 | else \ |
| 1922 | - CLEAR_FP_COND(env->fcr31); \ | ||
| 1923 | - if (!sig) \ | ||
| 1924 | - clear_invalid(); \ | ||
| 1925 | - /*CALL_FROM_TB1(dump_fpu_s, env);*/ \ | 2325 | + CLEAR_FP_COND(PARAM1, env); \ |
| 1926 | DEBUG_FPU_STATE(); \ | 2326 | DEBUG_FPU_STATE(); \ |
| 1927 | RETURN(); \ | 2327 | RETURN(); \ |
| 1928 | } | 2328 | } |
| 1929 | 2329 | ||
| 1930 | -int float64_is_unordered(float64 a, float64 b STATUS_PARAM) | 2330 | +int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) |
| 1931 | { | 2331 | { |
| 1932 | - if (float64_is_nan(a) || float64_is_nan(b)) { | 2332 | + if (float64_is_signaling_nan(a) || |
| 2333 | + float64_is_signaling_nan(b) || | ||
| 2334 | + (sig && (float64_is_nan(a) || float64_is_nan(b)))) { | ||
| 1933 | float_raise(float_flag_invalid, status); | 2335 | float_raise(float_flag_invalid, status); |
| 1934 | return 1; | 2336 | return 1; |
| 1935 | - } | ||
| 1936 | - else { | 2337 | + } else if (float64_is_nan(a) || float64_is_nan(b)) { |
| 2338 | + return 1; | ||
| 2339 | + } else { | ||
| 1937 | return 0; | 2340 | return 0; |
| 1938 | } | 2341 | } |
| 1939 | } | 2342 | } |
| 1940 | 2343 | ||
| 1941 | -FOP_COND(d, f, 0, 0) | ||
| 1942 | -FOP_COND(d, un, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status)) | ||
| 1943 | -FOP_COND(d, eq, 0, float64_eq(FDT0, FDT1, &env->fp_status)) | ||
| 1944 | -FOP_COND(d, ueq, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) | ||
| 1945 | -FOP_COND(d, olt, 0, float64_lt(FDT0, FDT1, &env->fp_status)) | ||
| 1946 | -FOP_COND(d, ult, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) | ||
| 1947 | -FOP_COND(d, ole, 0, float64_le(FDT0, FDT1, &env->fp_status)) | ||
| 1948 | -FOP_COND(d, ule, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) | ||
| 1949 | /* NOTE: the comma operator will make "cond" to eval to false, | 2344 | /* NOTE: the comma operator will make "cond" to eval to false, |
| 1950 | - * but float*_is_unordered() is still called | ||
| 1951 | - */ | ||
| 1952 | -FOP_COND(d, sf, 1, (float64_is_unordered(FDT0, FDT1, &env->fp_status), 0)) | ||
| 1953 | -FOP_COND(d, ngle,1, float64_is_unordered(FDT1, FDT0, &env->fp_status)) | ||
| 1954 | -FOP_COND(d, seq, 1, float64_eq(FDT0, FDT1, &env->fp_status)) | ||
| 1955 | -FOP_COND(d, ngl, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) | ||
| 1956 | -FOP_COND(d, lt, 1, float64_lt(FDT0, FDT1, &env->fp_status)) | ||
| 1957 | -FOP_COND(d, nge, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) | ||
| 1958 | -FOP_COND(d, le, 1, float64_le(FDT0, FDT1, &env->fp_status)) | ||
| 1959 | -FOP_COND(d, ngt, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) | ||
| 1960 | - | ||
| 1961 | -flag float32_is_unordered(float32 a, float32 b STATUS_PARAM) | ||
| 1962 | -{ | ||
| 1963 | - extern flag float32_is_nan( float32 a ); | ||
| 1964 | - if (float32_is_nan(a) || float32_is_nan(b)) { | 2345 | + * but float*_is_unordered() is still called. */ |
| 2346 | +FOP_COND_D(f, (float64_is_unordered(0, FDT1, FDT0, &env->fp_status), 0)) | ||
| 2347 | +FOP_COND_D(un, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)) | ||
| 2348 | +FOP_COND_D(eq, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) | ||
| 2349 | +FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) | ||
| 2350 | +FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) | ||
| 2351 | +FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) | ||
| 2352 | +FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) | ||
| 2353 | +FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) | ||
| 2354 | +/* NOTE: the comma operator will make "cond" to eval to false, | ||
| 2355 | + * but float*_is_unordered() is still called. */ | ||
| 2356 | +FOP_COND_D(sf, (float64_is_unordered(1, FDT1, FDT0, &env->fp_status), 0)) | ||
| 2357 | +FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fp_status)) | ||
| 2358 | +FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) | ||
| 2359 | +FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) | ||
| 2360 | +FOP_COND_D(lt, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) | ||
| 2361 | +FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) | ||
| 2362 | +FOP_COND_D(le, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) | ||
| 2363 | +FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) | ||
| 2364 | + | ||
| 2365 | +#define FOP_COND_S(op, cond) \ | ||
| 2366 | +void op_cmp_s_ ## op (void) \ | ||
| 2367 | +{ \ | ||
| 2368 | + int c = cond; \ | ||
| 2369 | + update_fcr31(); \ | ||
| 2370 | + if (c) \ | ||
| 2371 | + SET_FP_COND(PARAM1, env); \ | ||
| 2372 | + else \ | ||
| 2373 | + CLEAR_FP_COND(PARAM1, env); \ | ||
| 2374 | + DEBUG_FPU_STATE(); \ | ||
| 2375 | + RETURN(); \ | ||
| 2376 | +} | ||
| 2377 | + | ||
| 2378 | +flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) | ||
| 2379 | +{ | ||
| 2380 | + extern flag float32_is_nan(float32 a); | ||
| 2381 | + if (float32_is_signaling_nan(a) || | ||
| 2382 | + float32_is_signaling_nan(b) || | ||
| 2383 | + (sig && (float32_is_nan(a) || float32_is_nan(b)))) { | ||
| 1965 | float_raise(float_flag_invalid, status); | 2384 | float_raise(float_flag_invalid, status); |
| 1966 | return 1; | 2385 | return 1; |
| 1967 | - } | ||
| 1968 | - else { | 2386 | + } else if (float32_is_nan(a) || float32_is_nan(b)) { |
| 2387 | + return 1; | ||
| 2388 | + } else { | ||
| 1969 | return 0; | 2389 | return 0; |
| 1970 | } | 2390 | } |
| 1971 | } | 2391 | } |
| 1972 | 2392 | ||
| 1973 | /* NOTE: the comma operator will make "cond" to eval to false, | 2393 | /* NOTE: the comma operator will make "cond" to eval to false, |
| 1974 | - * but float*_is_unordered() is still called | ||
| 1975 | - */ | ||
| 1976 | -FOP_COND(s, f, 0, 0) | ||
| 1977 | -FOP_COND(s, un, 0, float32_is_unordered(FST1, FST0, &env->fp_status)) | ||
| 1978 | -FOP_COND(s, eq, 0, float32_eq(FST0, FST1, &env->fp_status)) | ||
| 1979 | -FOP_COND(s, ueq, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) | ||
| 1980 | -FOP_COND(s, olt, 0, float32_lt(FST0, FST1, &env->fp_status)) | ||
| 1981 | -FOP_COND(s, ult, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) | ||
| 1982 | -FOP_COND(s, ole, 0, float32_le(FST0, FST1, &env->fp_status)) | ||
| 1983 | -FOP_COND(s, ule, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) | 2394 | + * but float*_is_unordered() is still called. */ |
| 2395 | +FOP_COND_S(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0)) | ||
| 2396 | +FOP_COND_S(un, float32_is_unordered(0, FST1, FST0, &env->fp_status)) | ||
| 2397 | +FOP_COND_S(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) | ||
| 2398 | +FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) | ||
| 2399 | +FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) | ||
| 2400 | +FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) | ||
| 2401 | +FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) | ||
| 2402 | +FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) | ||
| 1984 | /* NOTE: the comma operator will make "cond" to eval to false, | 2403 | /* NOTE: the comma operator will make "cond" to eval to false, |
| 1985 | - * but float*_is_unordered() is still called | ||
| 1986 | - */ | ||
| 1987 | -FOP_COND(s, sf, 1, (float32_is_unordered(FST0, FST1, &env->fp_status), 0)) | ||
| 1988 | -FOP_COND(s, ngle,1, float32_is_unordered(FST1, FST0, &env->fp_status)) | ||
| 1989 | -FOP_COND(s, seq, 1, float32_eq(FST0, FST1, &env->fp_status)) | ||
| 1990 | -FOP_COND(s, ngl, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) | ||
| 1991 | -FOP_COND(s, lt, 1, float32_lt(FST0, FST1, &env->fp_status)) | ||
| 1992 | -FOP_COND(s, nge, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) | ||
| 1993 | -FOP_COND(s, le, 1, float32_le(FST0, FST1, &env->fp_status)) | ||
| 1994 | -FOP_COND(s, ngt, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) | 2404 | + * but float*_is_unordered() is still called. */ |
| 2405 | +FOP_COND_S(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0)) | ||
| 2406 | +FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status)) | ||
| 2407 | +FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) | ||
| 2408 | +FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) | ||
| 2409 | +FOP_COND_S(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) | ||
| 2410 | +FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) | ||
| 2411 | +FOP_COND_S(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) | ||
| 2412 | +FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) | ||
| 2413 | + | ||
| 2414 | +#define FOP_COND_PS(op, condl, condh) \ | ||
| 2415 | +void op_cmp_ps_ ## op (void) \ | ||
| 2416 | +{ \ | ||
| 2417 | + int cl = condl; \ | ||
| 2418 | + int ch = condh; \ | ||
| 2419 | + update_fcr31(); \ | ||
| 2420 | + if (cl) \ | ||
| 2421 | + SET_FP_COND(PARAM1, env); \ | ||
| 2422 | + else \ | ||
| 2423 | + CLEAR_FP_COND(PARAM1, env); \ | ||
| 2424 | + if (ch) \ | ||
| 2425 | + SET_FP_COND(PARAM1 + 1, env); \ | ||
| 2426 | + else \ | ||
| 2427 | + CLEAR_FP_COND(PARAM1 + 1, env); \ | ||
| 2428 | + DEBUG_FPU_STATE(); \ | ||
| 2429 | + RETURN(); \ | ||
| 2430 | +} | ||
| 2431 | + | ||
| 2432 | +/* NOTE: the comma operator will make "cond" to eval to false, | ||
| 2433 | + * but float*_is_unordered() is still called. */ | ||
| 2434 | +FOP_COND_PS(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0), | ||
| 2435 | + (float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status), 0)) | ||
| 2436 | +FOP_COND_PS(un, float32_is_unordered(0, FST1, FST0, &env->fp_status), | ||
| 2437 | + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)) | ||
| 2438 | +FOP_COND_PS(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), | ||
| 2439 | + !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) | ||
| 2440 | +FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), | ||
| 2441 | + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) | ||
| 2442 | +FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), | ||
| 2443 | + !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) | ||
| 2444 | +FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), | ||
| 2445 | + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) | ||
| 2446 | +FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), | ||
| 2447 | + !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) | ||
| 2448 | +FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), | ||
| 2449 | + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) | ||
| 2450 | +/* NOTE: the comma operator will make "cond" to eval to false, | ||
| 2451 | + * but float*_is_unordered() is still called. */ | ||
| 2452 | +FOP_COND_PS(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0), | ||
| 2453 | + (float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status), 0)) | ||
| 2454 | +FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status), | ||
| 2455 | + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)) | ||
| 2456 | +FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), | ||
| 2457 | + !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) | ||
| 2458 | +FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), | ||
| 2459 | + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) | ||
| 2460 | +FOP_COND_PS(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), | ||
| 2461 | + !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) | ||
| 2462 | +FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), | ||
| 2463 | + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) | ||
| 2464 | +FOP_COND_PS(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), | ||
| 2465 | + !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) | ||
| 2466 | +FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), | ||
| 2467 | + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) | ||
| 1995 | 2468 | ||
| 1996 | void op_bc1f (void) | 2469 | void op_bc1f (void) |
| 1997 | { | 2470 | { |
| 1998 | - T0 = ! IS_FP_COND_SET(env->fcr31); | 2471 | + T0 = !IS_FP_COND_SET(PARAM1, env); |
| 2472 | + DEBUG_FPU_STATE(); | ||
| 2473 | + RETURN(); | ||
| 2474 | +} | ||
| 2475 | +void op_bc1fany2 (void) | ||
| 2476 | +{ | ||
| 2477 | + T0 = (!IS_FP_COND_SET(PARAM1, env) || | ||
| 2478 | + !IS_FP_COND_SET(PARAM1 + 1, env)); | ||
| 2479 | + DEBUG_FPU_STATE(); | ||
| 2480 | + RETURN(); | ||
| 2481 | +} | ||
| 2482 | +void op_bc1fany4 (void) | ||
| 2483 | +{ | ||
| 2484 | + T0 = (!IS_FP_COND_SET(PARAM1, env) || | ||
| 2485 | + !IS_FP_COND_SET(PARAM1 + 1, env) || | ||
| 2486 | + !IS_FP_COND_SET(PARAM1 + 2, env) || | ||
| 2487 | + !IS_FP_COND_SET(PARAM1 + 3, env)); | ||
| 1999 | DEBUG_FPU_STATE(); | 2488 | DEBUG_FPU_STATE(); |
| 2000 | RETURN(); | 2489 | RETURN(); |
| 2001 | } | 2490 | } |
| 2002 | 2491 | ||
| 2003 | void op_bc1t (void) | 2492 | void op_bc1t (void) |
| 2004 | { | 2493 | { |
| 2005 | - T0 = IS_FP_COND_SET(env->fcr31); | 2494 | + T0 = IS_FP_COND_SET(PARAM1, env); |
| 2495 | + DEBUG_FPU_STATE(); | ||
| 2496 | + RETURN(); | ||
| 2497 | +} | ||
| 2498 | +void op_bc1tany2 (void) | ||
| 2499 | +{ | ||
| 2500 | + T0 = (IS_FP_COND_SET(PARAM1, env) || | ||
| 2501 | + IS_FP_COND_SET(PARAM1 + 1, env)); | ||
| 2502 | + DEBUG_FPU_STATE(); | ||
| 2503 | + RETURN(); | ||
| 2504 | +} | ||
| 2505 | +void op_bc1tany4 (void) | ||
| 2506 | +{ | ||
| 2507 | + T0 = (IS_FP_COND_SET(PARAM1, env) || | ||
| 2508 | + IS_FP_COND_SET(PARAM1 + 1, env) || | ||
| 2509 | + IS_FP_COND_SET(PARAM1 + 2, env) || | ||
| 2510 | + IS_FP_COND_SET(PARAM1 + 3, env)); | ||
| 2006 | DEBUG_FPU_STATE(); | 2511 | DEBUG_FPU_STATE(); |
| 2007 | RETURN(); | 2512 | RETURN(); |
| 2008 | } | 2513 | } |
| @@ -2037,7 +2542,7 @@ void op_tlbr (void) | @@ -2037,7 +2542,7 @@ void op_tlbr (void) | ||
| 2037 | #if defined (CONFIG_USER_ONLY) | 2542 | #if defined (CONFIG_USER_ONLY) |
| 2038 | void op_tls_value (void) | 2543 | void op_tls_value (void) |
| 2039 | { | 2544 | { |
| 2040 | - T0 = env->tls_value; | 2545 | + T0 = env->tls_value; |
| 2041 | } | 2546 | } |
| 2042 | #endif | 2547 | #endif |
| 2043 | 2548 | ||
| @@ -2180,6 +2685,17 @@ void op_save_pc (void) | @@ -2180,6 +2685,17 @@ void op_save_pc (void) | ||
| 2180 | RETURN(); | 2685 | RETURN(); |
| 2181 | } | 2686 | } |
| 2182 | 2687 | ||
| 2688 | +void op_save_fp_status (void) | ||
| 2689 | +{ | ||
| 2690 | + union fps { | ||
| 2691 | + uint32_t i; | ||
| 2692 | + float_status f; | ||
| 2693 | + } fps; | ||
| 2694 | + fps.i = PARAM1; | ||
| 2695 | + env->fp_status = fps.f; | ||
| 2696 | + RETURN(); | ||
| 2697 | +} | ||
| 2698 | + | ||
| 2183 | void op_interrupt_restart (void) | 2699 | void op_interrupt_restart (void) |
| 2184 | { | 2700 | { |
| 2185 | if (!(env->CP0_Status & (1 << CP0St_EXL)) && | 2701 | if (!(env->CP0_Status & (1 << CP0St_EXL)) && |
target-mips/op_mem.c
| @@ -220,3 +220,35 @@ void glue(op_sdc1, MEMSUFFIX) (void) | @@ -220,3 +220,35 @@ void glue(op_sdc1, MEMSUFFIX) (void) | ||
| 220 | glue(stq, MEMSUFFIX)(T0, DT0); | 220 | glue(stq, MEMSUFFIX)(T0, DT0); |
| 221 | RETURN(); | 221 | RETURN(); |
| 222 | } | 222 | } |
| 223 | +void glue(op_lwxc1, MEMSUFFIX) (void) | ||
| 224 | +{ | ||
| 225 | + WT0 = glue(ldl, MEMSUFFIX)(T0 + T1); | ||
| 226 | + RETURN(); | ||
| 227 | +} | ||
| 228 | +void glue(op_swxc1, MEMSUFFIX) (void) | ||
| 229 | +{ | ||
| 230 | + glue(stl, MEMSUFFIX)(T0 + T1, WT0); | ||
| 231 | + RETURN(); | ||
| 232 | +} | ||
| 233 | +void glue(op_ldxc1, MEMSUFFIX) (void) | ||
| 234 | +{ | ||
| 235 | + DT0 = glue(ldq, MEMSUFFIX)(T0 + T1); | ||
| 236 | + RETURN(); | ||
| 237 | +} | ||
| 238 | +void glue(op_sdxc1, MEMSUFFIX) (void) | ||
| 239 | +{ | ||
| 240 | + glue(stq, MEMSUFFIX)(T0 + T1, DT0); | ||
| 241 | + RETURN(); | ||
| 242 | +} | ||
| 243 | +void glue(op_luxc1, MEMSUFFIX) (void) | ||
| 244 | +{ | ||
| 245 | + /* XXX: is defined as unaligned */ | ||
| 246 | + DT0 = glue(ldq, MEMSUFFIX)(T0 + T1); | ||
| 247 | + RETURN(); | ||
| 248 | +} | ||
| 249 | +void glue(op_suxc1, MEMSUFFIX) (void) | ||
| 250 | +{ | ||
| 251 | + /* XXX: is defined as unaligned */ | ||
| 252 | + glue(stq, MEMSUFFIX)(T0 + T1, DT0); | ||
| 253 | + RETURN(); | ||
| 254 | +} |
target-mips/translate.c
| @@ -333,20 +333,26 @@ enum { | @@ -333,20 +333,26 @@ enum { | ||
| 333 | OPC_MFC1 = (0x00 << 21) | OPC_CP1, | 333 | OPC_MFC1 = (0x00 << 21) | OPC_CP1, |
| 334 | OPC_DMFC1 = (0x01 << 21) | OPC_CP1, | 334 | OPC_DMFC1 = (0x01 << 21) | OPC_CP1, |
| 335 | OPC_CFC1 = (0x02 << 21) | OPC_CP1, | 335 | OPC_CFC1 = (0x02 << 21) | OPC_CP1, |
| 336 | - OPC_MFHCI = (0x03 << 21) | OPC_CP1, | 336 | + OPC_MFHC1 = (0x03 << 21) | OPC_CP1, |
| 337 | OPC_MTC1 = (0x04 << 21) | OPC_CP1, | 337 | OPC_MTC1 = (0x04 << 21) | OPC_CP1, |
| 338 | OPC_DMTC1 = (0x05 << 21) | OPC_CP1, | 338 | OPC_DMTC1 = (0x05 << 21) | OPC_CP1, |
| 339 | OPC_CTC1 = (0x06 << 21) | OPC_CP1, | 339 | OPC_CTC1 = (0x06 << 21) | OPC_CP1, |
| 340 | - OPC_MTHCI = (0x07 << 21) | OPC_CP1, | 340 | + OPC_MTHC1 = (0x07 << 21) | OPC_CP1, |
| 341 | OPC_BC1 = (0x08 << 21) | OPC_CP1, /* bc */ | 341 | OPC_BC1 = (0x08 << 21) | OPC_CP1, /* bc */ |
| 342 | + OPC_BC1ANY2 = (0x09 << 21) | OPC_CP1, | ||
| 343 | + OPC_BC1ANY4 = (0x0A << 21) | OPC_CP1, | ||
| 342 | OPC_S_FMT = (0x10 << 21) | OPC_CP1, /* 16: fmt=single fp */ | 344 | OPC_S_FMT = (0x10 << 21) | OPC_CP1, /* 16: fmt=single fp */ |
| 343 | OPC_D_FMT = (0x11 << 21) | OPC_CP1, /* 17: fmt=double fp */ | 345 | OPC_D_FMT = (0x11 << 21) | OPC_CP1, /* 17: fmt=double fp */ |
| 344 | OPC_E_FMT = (0x12 << 21) | OPC_CP1, /* 18: fmt=extended fp */ | 346 | OPC_E_FMT = (0x12 << 21) | OPC_CP1, /* 18: fmt=extended fp */ |
| 345 | OPC_Q_FMT = (0x13 << 21) | OPC_CP1, /* 19: fmt=quad fp */ | 347 | OPC_Q_FMT = (0x13 << 21) | OPC_CP1, /* 19: fmt=quad fp */ |
| 346 | OPC_W_FMT = (0x14 << 21) | OPC_CP1, /* 20: fmt=32bit fixed */ | 348 | OPC_W_FMT = (0x14 << 21) | OPC_CP1, /* 20: fmt=32bit fixed */ |
| 347 | OPC_L_FMT = (0x15 << 21) | OPC_CP1, /* 21: fmt=64bit fixed */ | 349 | OPC_L_FMT = (0x15 << 21) | OPC_CP1, /* 21: fmt=64bit fixed */ |
| 350 | + OPC_PS_FMT = (0x16 << 21) | OPC_CP1, /* 22: fmt=paired single fp */ | ||
| 348 | }; | 351 | }; |
| 349 | 352 | ||
| 353 | +#define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F) | ||
| 354 | +#define MASK_BC1(op) MASK_CP1(op) | (op & (0x3 << 16)) | ||
| 355 | + | ||
| 350 | enum { | 356 | enum { |
| 351 | OPC_BC1F = (0x00 << 16) | OPC_BC1, | 357 | OPC_BC1F = (0x00 << 16) | OPC_BC1, |
| 352 | OPC_BC1T = (0x01 << 16) | OPC_BC1, | 358 | OPC_BC1T = (0x01 << 16) | OPC_BC1, |
| @@ -354,8 +360,15 @@ enum { | @@ -354,8 +360,15 @@ enum { | ||
| 354 | OPC_BC1TL = (0x03 << 16) | OPC_BC1, | 360 | OPC_BC1TL = (0x03 << 16) | OPC_BC1, |
| 355 | }; | 361 | }; |
| 356 | 362 | ||
| 357 | -#define MASK_CP1_BCOND(op) MASK_CP1(op) | (op & (0x3 << 16)) | ||
| 358 | -#define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F) | 363 | +enum { |
| 364 | + OPC_BC1FANY2 = (0x00 << 16) | OPC_BC1ANY2, | ||
| 365 | + OPC_BC1TANY2 = (0x01 << 16) | OPC_BC1ANY2, | ||
| 366 | +}; | ||
| 367 | + | ||
| 368 | +enum { | ||
| 369 | + OPC_BC1FANY4 = (0x00 << 16) | OPC_BC1ANY4, | ||
| 370 | + OPC_BC1TANY4 = (0x01 << 16) | OPC_BC1ANY4, | ||
| 371 | +}; | ||
| 359 | 372 | ||
| 360 | #define MASK_CP2(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) | 373 | #define MASK_CP2(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) |
| 361 | 374 | ||
| @@ -404,20 +417,20 @@ const unsigned char *regnames[] = | @@ -404,20 +417,20 @@ const unsigned char *regnames[] = | ||
| 404 | "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", }; | 417 | "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", }; |
| 405 | 418 | ||
| 406 | /* Warning: no function for r0 register (hard wired to zero) */ | 419 | /* Warning: no function for r0 register (hard wired to zero) */ |
| 407 | -#define GEN32(func, NAME) \ | ||
| 408 | -static GenOpFunc *NAME ## _table [32] = { \ | ||
| 409 | -NULL, NAME ## 1, NAME ## 2, NAME ## 3, \ | ||
| 410 | -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ | ||
| 411 | -NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ | ||
| 412 | -NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ | ||
| 413 | -NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ | ||
| 414 | -NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ | ||
| 415 | -NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ | ||
| 416 | -NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ | ||
| 417 | -}; \ | ||
| 418 | -static inline void func(int n) \ | ||
| 419 | -{ \ | ||
| 420 | - NAME ## _table[n](); \ | 420 | +#define GEN32(func, NAME) \ |
| 421 | +static GenOpFunc *NAME ## _table [32] = { \ | ||
| 422 | +NULL, NAME ## 1, NAME ## 2, NAME ## 3, \ | ||
| 423 | +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ | ||
| 424 | +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ | ||
| 425 | +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ | ||
| 426 | +NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ | ||
| 427 | +NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ | ||
| 428 | +NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ | ||
| 429 | +NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ | ||
| 430 | +}; \ | ||
| 431 | +static inline void func(int n) \ | ||
| 432 | +{ \ | ||
| 433 | + NAME ## _table[n](); \ | ||
| 421 | } | 434 | } |
| 422 | 435 | ||
| 423 | /* General purpose registers moves */ | 436 | /* General purpose registers moves */ |
| @@ -434,58 +447,51 @@ static const char *fregnames[] = | @@ -434,58 +447,51 @@ static const char *fregnames[] = | ||
| 434 | "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", | 447 | "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", |
| 435 | "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; | 448 | "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; |
| 436 | 449 | ||
| 437 | -# define SFGEN32(func, NAME) \ | ||
| 438 | -static GenOpFunc *NAME ## _table [32] = { \ | ||
| 439 | -NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ | ||
| 440 | -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ | ||
| 441 | -NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ | ||
| 442 | -NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ | ||
| 443 | -NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ | ||
| 444 | -NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ | ||
| 445 | -NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ | ||
| 446 | -NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ | ||
| 447 | -}; \ | ||
| 448 | -static inline void func(int n) \ | ||
| 449 | -{ \ | ||
| 450 | - NAME ## _table[n](); \ | 450 | +#define FGEN32(func, NAME) \ |
| 451 | +static GenOpFunc *NAME ## _table [32] = { \ | ||
| 452 | +NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ | ||
| 453 | +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ | ||
| 454 | +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ | ||
| 455 | +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ | ||
| 456 | +NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ | ||
| 457 | +NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ | ||
| 458 | +NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ | ||
| 459 | +NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ | ||
| 460 | +}; \ | ||
| 461 | +static inline void func(int n) \ | ||
| 462 | +{ \ | ||
| 463 | + NAME ## _table[n](); \ | ||
| 451 | } | 464 | } |
| 452 | 465 | ||
| 453 | -# define DFGEN32(func, NAME) \ | ||
| 454 | -static GenOpFunc *NAME ## _table [32] = { \ | ||
| 455 | -NAME ## 0, 0, NAME ## 2, 0, \ | ||
| 456 | -NAME ## 4, 0, NAME ## 6, 0, \ | ||
| 457 | -NAME ## 8, 0, NAME ## 10, 0, \ | ||
| 458 | -NAME ## 12, 0, NAME ## 14, 0, \ | ||
| 459 | -NAME ## 16, 0, NAME ## 18, 0, \ | ||
| 460 | -NAME ## 20, 0, NAME ## 22, 0, \ | ||
| 461 | -NAME ## 24, 0, NAME ## 26, 0, \ | ||
| 462 | -NAME ## 28, 0, NAME ## 30, 0, \ | ||
| 463 | -}; \ | ||
| 464 | -static inline void func(int n) \ | ||
| 465 | -{ \ | ||
| 466 | - NAME ## _table[n](); \ | ||
| 467 | -} | 466 | +FGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr); |
| 467 | +FGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr); | ||
| 468 | + | ||
| 469 | +FGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr); | ||
| 470 | +FGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr); | ||
| 468 | 471 | ||
| 469 | -SFGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr); | ||
| 470 | -SFGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr); | 472 | +FGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr); |
| 473 | +FGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr); | ||
| 471 | 474 | ||
| 472 | -SFGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr); | ||
| 473 | -SFGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr); | 475 | +FGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr); |
| 476 | +FGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr); | ||
| 474 | 477 | ||
| 475 | -SFGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr); | ||
| 476 | -SFGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr); | 478 | +FGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr); |
| 479 | +FGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr); | ||
| 477 | 480 | ||
| 478 | -DFGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr); | ||
| 479 | -DFGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr); | 481 | +FGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr); |
| 482 | +FGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr); | ||
| 480 | 483 | ||
| 481 | -DFGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr); | ||
| 482 | -DFGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr); | 484 | +FGEN32(gen_op_load_fpr_WTH0, gen_op_load_fpr_WTH0_fpr); |
| 485 | +FGEN32(gen_op_store_fpr_WTH0, gen_op_store_fpr_WTH0_fpr); | ||
| 483 | 486 | ||
| 484 | -DFGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr); | ||
| 485 | -DFGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr); | 487 | +FGEN32(gen_op_load_fpr_WTH1, gen_op_load_fpr_WTH1_fpr); |
| 488 | +FGEN32(gen_op_store_fpr_WTH1, gen_op_store_fpr_WTH1_fpr); | ||
| 489 | + | ||
| 490 | +FGEN32(gen_op_load_fpr_WTH2, gen_op_load_fpr_WTH2_fpr); | ||
| 491 | +FGEN32(gen_op_store_fpr_WTH2, gen_op_store_fpr_WTH2_fpr); | ||
| 486 | 492 | ||
| 487 | #define FOP_CONDS(fmt) \ | 493 | #define FOP_CONDS(fmt) \ |
| 488 | -static GenOpFunc * cond_ ## fmt ## _table[16] = { \ | 494 | +static GenOpFunc1 * cond_ ## fmt ## _table[16] = { \ |
| 489 | gen_op_cmp_ ## fmt ## _f, \ | 495 | gen_op_cmp_ ## fmt ## _f, \ |
| 490 | gen_op_cmp_ ## fmt ## _un, \ | 496 | gen_op_cmp_ ## fmt ## _un, \ |
| 491 | gen_op_cmp_ ## fmt ## _eq, \ | 497 | gen_op_cmp_ ## fmt ## _eq, \ |
| @@ -503,18 +509,20 @@ static GenOpFunc * cond_ ## fmt ## _table[16] = { \ | @@ -503,18 +509,20 @@ static GenOpFunc * cond_ ## fmt ## _table[16] = { \ | ||
| 503 | gen_op_cmp_ ## fmt ## _le, \ | 509 | gen_op_cmp_ ## fmt ## _le, \ |
| 504 | gen_op_cmp_ ## fmt ## _ngt, \ | 510 | gen_op_cmp_ ## fmt ## _ngt, \ |
| 505 | }; \ | 511 | }; \ |
| 506 | -static inline void gen_cmp_ ## fmt(int n) \ | 512 | +static inline void gen_cmp_ ## fmt(int n, long cc) \ |
| 507 | { \ | 513 | { \ |
| 508 | - cond_ ## fmt ## _table[n](); \ | 514 | + cond_ ## fmt ## _table[n](cc); \ |
| 509 | } | 515 | } |
| 510 | 516 | ||
| 511 | FOP_CONDS(d) | 517 | FOP_CONDS(d) |
| 512 | FOP_CONDS(s) | 518 | FOP_CONDS(s) |
| 519 | +FOP_CONDS(ps) | ||
| 513 | 520 | ||
| 514 | typedef struct DisasContext { | 521 | typedef struct DisasContext { |
| 515 | struct TranslationBlock *tb; | 522 | struct TranslationBlock *tb; |
| 516 | target_ulong pc, saved_pc; | 523 | target_ulong pc, saved_pc; |
| 517 | uint32_t opcode; | 524 | uint32_t opcode; |
| 525 | + uint32_t fp_status, saved_fp_status; | ||
| 518 | /* Routine used to access memory */ | 526 | /* Routine used to access memory */ |
| 519 | int mem_idx; | 527 | int mem_idx; |
| 520 | uint32_t hflags, saved_hflags; | 528 | uint32_t hflags, saved_hflags; |
| @@ -600,17 +608,31 @@ static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) | @@ -600,17 +608,31 @@ static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) | ||
| 600 | if (ctx->hflags != ctx->saved_hflags) { | 608 | if (ctx->hflags != ctx->saved_hflags) { |
| 601 | gen_op_save_state(ctx->hflags); | 609 | gen_op_save_state(ctx->hflags); |
| 602 | ctx->saved_hflags = ctx->hflags; | 610 | ctx->saved_hflags = ctx->hflags; |
| 603 | - if (ctx->hflags & MIPS_HFLAG_BR) { | 611 | + switch (ctx->hflags & MIPS_HFLAG_BMASK) { |
| 612 | + case MIPS_HFLAG_BR: | ||
| 604 | gen_op_save_breg_target(); | 613 | gen_op_save_breg_target(); |
| 605 | - } else if (ctx->hflags & MIPS_HFLAG_B) { | ||
| 606 | - gen_op_save_btarget(ctx->btarget); | ||
| 607 | - } else if (ctx->hflags & MIPS_HFLAG_BMASK) { | 614 | + break; |
| 615 | + case MIPS_HFLAG_BC: | ||
| 608 | gen_op_save_bcond(); | 616 | gen_op_save_bcond(); |
| 617 | + /* fall through */ | ||
| 618 | + case MIPS_HFLAG_BL: | ||
| 619 | + /* bcond was already saved by the BL insn */ | ||
| 620 | + /* fall through */ | ||
| 621 | + case MIPS_HFLAG_B: | ||
| 609 | gen_op_save_btarget(ctx->btarget); | 622 | gen_op_save_btarget(ctx->btarget); |
| 623 | + break; | ||
| 610 | } | 624 | } |
| 611 | } | 625 | } |
| 612 | } | 626 | } |
| 613 | 627 | ||
| 628 | +static inline void save_fpu_state (DisasContext *ctx) | ||
| 629 | +{ | ||
| 630 | + if (ctx->fp_status != ctx->saved_fp_status) { | ||
| 631 | + gen_op_save_fp_status(ctx->fp_status); | ||
| 632 | + ctx->saved_fp_status = ctx->fp_status; | ||
| 633 | + } | ||
| 634 | +} | ||
| 635 | + | ||
| 614 | static inline void generate_exception_err (DisasContext *ctx, int excp, int err) | 636 | static inline void generate_exception_err (DisasContext *ctx, int excp, int err) |
| 615 | { | 637 | { |
| 616 | #if defined MIPS_DEBUG_DISAS | 638 | #if defined MIPS_DEBUG_DISAS |
| @@ -677,6 +699,12 @@ OP_LD_TABLE(wc1); | @@ -677,6 +699,12 @@ OP_LD_TABLE(wc1); | ||
| 677 | OP_ST_TABLE(wc1); | 699 | OP_ST_TABLE(wc1); |
| 678 | OP_LD_TABLE(dc1); | 700 | OP_LD_TABLE(dc1); |
| 679 | OP_ST_TABLE(dc1); | 701 | OP_ST_TABLE(dc1); |
| 702 | +OP_LD_TABLE(wxc1); | ||
| 703 | +OP_ST_TABLE(wxc1); | ||
| 704 | +OP_LD_TABLE(dxc1); | ||
| 705 | +OP_ST_TABLE(dxc1); | ||
| 706 | +OP_LD_TABLE(uxc1); | ||
| 707 | +OP_ST_TABLE(uxc1); | ||
| 680 | 708 | ||
| 681 | /* Load and store */ | 709 | /* Load and store */ |
| 682 | static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, | 710 | static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, |
| @@ -1472,7 +1500,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, | @@ -1472,7 +1500,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, | ||
| 1472 | if (ctx->hflags & MIPS_HFLAG_BMASK) { | 1500 | if (ctx->hflags & MIPS_HFLAG_BMASK) { |
| 1473 | if (loglevel & CPU_LOG_TB_IN_ASM) { | 1501 | if (loglevel & CPU_LOG_TB_IN_ASM) { |
| 1474 | fprintf(logfile, | 1502 | fprintf(logfile, |
| 1475 | - "undefined branch in delay slot at PC " TARGET_FMT_lx "\n", | 1503 | + "Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", |
| 1476 | ctx->pc); | 1504 | ctx->pc); |
| 1477 | } | 1505 | } |
| 1478 | MIPS_INVAL("branch/jump in bdelay slot"); | 1506 | MIPS_INVAL("branch/jump in bdelay slot"); |
| @@ -1672,6 +1700,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, | @@ -1672,6 +1700,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, | ||
| 1672 | MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget); | 1700 | MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget); |
| 1673 | not_likely: | 1701 | not_likely: |
| 1674 | ctx->hflags |= MIPS_HFLAG_BC; | 1702 | ctx->hflags |= MIPS_HFLAG_BC; |
| 1703 | + gen_op_set_bcond(); | ||
| 1675 | break; | 1704 | break; |
| 1676 | case OPC_BLTZALL: | 1705 | case OPC_BLTZALL: |
| 1677 | gen_op_ltz(); | 1706 | gen_op_ltz(); |
| @@ -1679,13 +1708,14 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, | @@ -1679,13 +1708,14 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, | ||
| 1679 | MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget); | 1708 | MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget); |
| 1680 | likely: | 1709 | likely: |
| 1681 | ctx->hflags |= MIPS_HFLAG_BL; | 1710 | ctx->hflags |= MIPS_HFLAG_BL; |
| 1711 | + gen_op_set_bcond(); | ||
| 1712 | + gen_op_save_bcond(); | ||
| 1682 | break; | 1713 | break; |
| 1683 | default: | 1714 | default: |
| 1684 | MIPS_INVAL("conditional branch/jump"); | 1715 | MIPS_INVAL("conditional branch/jump"); |
| 1685 | generate_exception(ctx, EXCP_RI); | 1716 | generate_exception(ctx, EXCP_RI); |
| 1686 | return; | 1717 | return; |
| 1687 | } | 1718 | } |
| 1688 | - gen_op_set_bcond(); | ||
| 1689 | } | 1719 | } |
| 1690 | MIPS_DEBUG("enter ds: link %d cond %02x target %08x", | 1720 | MIPS_DEBUG("enter ds: link %d cond %02x target %08x", |
| 1691 | blink, ctx->hflags, btarget); | 1721 | blink, ctx->hflags, btarget); |
| @@ -4220,7 +4250,7 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) | @@ -4220,7 +4250,7 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) | ||
| 4220 | 4250 | ||
| 4221 | /* CP1 Branches (before delay slot) */ | 4251 | /* CP1 Branches (before delay slot) */ |
| 4222 | static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, | 4252 | static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, |
| 4223 | - int32_t offset) | 4253 | + int32_t cc, int32_t offset) |
| 4224 | { | 4254 | { |
| 4225 | target_ulong btarget; | 4255 | target_ulong btarget; |
| 4226 | 4256 | ||
| @@ -4228,31 +4258,49 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, | @@ -4228,31 +4258,49 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, | ||
| 4228 | 4258 | ||
| 4229 | switch (op) { | 4259 | switch (op) { |
| 4230 | case OPC_BC1F: | 4260 | case OPC_BC1F: |
| 4231 | - gen_op_bc1f(); | 4261 | + gen_op_bc1f(cc); |
| 4232 | MIPS_DEBUG("bc1f " TARGET_FMT_lx, btarget); | 4262 | MIPS_DEBUG("bc1f " TARGET_FMT_lx, btarget); |
| 4233 | goto not_likely; | 4263 | goto not_likely; |
| 4234 | case OPC_BC1FL: | 4264 | case OPC_BC1FL: |
| 4235 | - gen_op_bc1f(); | 4265 | + gen_op_bc1f(cc); |
| 4236 | MIPS_DEBUG("bc1fl " TARGET_FMT_lx, btarget); | 4266 | MIPS_DEBUG("bc1fl " TARGET_FMT_lx, btarget); |
| 4237 | goto likely; | 4267 | goto likely; |
| 4238 | case OPC_BC1T: | 4268 | case OPC_BC1T: |
| 4239 | - gen_op_bc1t(); | 4269 | + gen_op_bc1t(cc); |
| 4240 | MIPS_DEBUG("bc1t " TARGET_FMT_lx, btarget); | 4270 | MIPS_DEBUG("bc1t " TARGET_FMT_lx, btarget); |
| 4241 | - not_likely: | ||
| 4242 | - ctx->hflags |= MIPS_HFLAG_BC; | ||
| 4243 | - break; | 4271 | + goto not_likely; |
| 4244 | case OPC_BC1TL: | 4272 | case OPC_BC1TL: |
| 4245 | - gen_op_bc1t(); | 4273 | + gen_op_bc1t(cc); |
| 4246 | MIPS_DEBUG("bc1tl " TARGET_FMT_lx, btarget); | 4274 | MIPS_DEBUG("bc1tl " TARGET_FMT_lx, btarget); |
| 4247 | likely: | 4275 | likely: |
| 4248 | ctx->hflags |= MIPS_HFLAG_BL; | 4276 | ctx->hflags |= MIPS_HFLAG_BL; |
| 4277 | + gen_op_set_bcond(); | ||
| 4278 | + gen_op_save_bcond(); | ||
| 4249 | break; | 4279 | break; |
| 4250 | - default: | ||
| 4251 | - MIPS_INVAL("cp1 branch/jump"); | 4280 | + case OPC_BC1FANY2: |
| 4281 | + gen_op_bc1fany2(cc); | ||
| 4282 | + MIPS_DEBUG("bc1fany2 " TARGET_FMT_lx, btarget); | ||
| 4283 | + goto not_likely; | ||
| 4284 | + case OPC_BC1TANY2: | ||
| 4285 | + gen_op_bc1tany2(cc); | ||
| 4286 | + MIPS_DEBUG("bc1tany2 " TARGET_FMT_lx, btarget); | ||
| 4287 | + goto not_likely; | ||
| 4288 | + case OPC_BC1FANY4: | ||
| 4289 | + gen_op_bc1fany4(cc); | ||
| 4290 | + MIPS_DEBUG("bc1fany4 " TARGET_FMT_lx, btarget); | ||
| 4291 | + goto not_likely; | ||
| 4292 | + case OPC_BC1TANY4: | ||
| 4293 | + gen_op_bc1tany4(cc); | ||
| 4294 | + MIPS_DEBUG("bc1tany4 " TARGET_FMT_lx, btarget); | ||
| 4295 | + not_likely: | ||
| 4296 | + ctx->hflags |= MIPS_HFLAG_BC; | ||
| 4297 | + gen_op_set_bcond(); | ||
| 4298 | + break; | ||
| 4299 | + default: | ||
| 4300 | + MIPS_INVAL("cp1 branch"); | ||
| 4252 | generate_exception (ctx, EXCP_RI); | 4301 | generate_exception (ctx, EXCP_RI); |
| 4253 | return; | 4302 | return; |
| 4254 | } | 4303 | } |
| 4255 | - gen_op_set_bcond(); | ||
| 4256 | 4304 | ||
| 4257 | MIPS_DEBUG("enter ds: cond %02x target " TARGET_FMT_lx, | 4305 | MIPS_DEBUG("enter ds: cond %02x target " TARGET_FMT_lx, |
| 4258 | ctx->hflags, btarget); | 4306 | ctx->hflags, btarget); |
| @@ -4262,6 +4310,29 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, | @@ -4262,6 +4310,29 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, | ||
| 4262 | } | 4310 | } |
| 4263 | 4311 | ||
| 4264 | /* Coprocessor 1 (FPU) */ | 4312 | /* Coprocessor 1 (FPU) */ |
| 4313 | + | ||
| 4314 | +/* verify if floating point register is valid; an operation is not defined | ||
| 4315 | + * if bit 0 of any register specification is set and the FR bit in the | ||
| 4316 | + * Status register equals zero, since the register numbers specify an | ||
| 4317 | + * even-odd pair of adjacent coprocessor general registers. When the FR bit | ||
| 4318 | + * in the Status register equals one, both even and odd register numbers | ||
| 4319 | + * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers. | ||
| 4320 | + * | ||
| 4321 | + * Multiple 64 bit wide registers can be checked by calling | ||
| 4322 | + * CHECK_FR(ctx, freg1 | freg2 | ... | fregN); | ||
| 4323 | + * | ||
| 4324 | + * FIXME: This is broken for R2, it needs to be checked at runtime, not | ||
| 4325 | + * at translation time. | ||
| 4326 | + */ | ||
| 4327 | +#define CHECK_FR(ctx, freg) do { \ | ||
| 4328 | + if (!((ctx)->CP0_Status & (1 << CP0St_FR)) && ((freg) & 1)) { \ | ||
| 4329 | + generate_exception (ctx, EXCP_RI); \ | ||
| 4330 | + return; \ | ||
| 4331 | + } \ | ||
| 4332 | + } while(0) | ||
| 4333 | + | ||
| 4334 | +#define FOP(func, fmt) (((fmt) << 21) | (func)) | ||
| 4335 | + | ||
| 4265 | static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) | 4336 | static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) |
| 4266 | { | 4337 | { |
| 4267 | const char *opn = "unk"; | 4338 | const char *opn = "unk"; |
| @@ -4280,30 +4351,43 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) | @@ -4280,30 +4351,43 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) | ||
| 4280 | opn = "mtc1"; | 4351 | opn = "mtc1"; |
| 4281 | break; | 4352 | break; |
| 4282 | case OPC_CFC1: | 4353 | case OPC_CFC1: |
| 4283 | - if (fs != 0 && fs != 31) { | ||
| 4284 | - MIPS_INVAL("cfc1 freg"); | ||
| 4285 | - generate_exception (ctx, EXCP_RI); | ||
| 4286 | - return; | ||
| 4287 | - } | ||
| 4288 | GEN_LOAD_IMM_TN(T1, fs); | 4354 | GEN_LOAD_IMM_TN(T1, fs); |
| 4289 | gen_op_cfc1(); | 4355 | gen_op_cfc1(); |
| 4290 | GEN_STORE_TN_REG(rt, T0); | 4356 | GEN_STORE_TN_REG(rt, T0); |
| 4291 | opn = "cfc1"; | 4357 | opn = "cfc1"; |
| 4292 | break; | 4358 | break; |
| 4293 | case OPC_CTC1: | 4359 | case OPC_CTC1: |
| 4294 | - if (fs != 0 && fs != 31) { | ||
| 4295 | - MIPS_INVAL("ctc1 freg"); | ||
| 4296 | - generate_exception (ctx, EXCP_RI); | ||
| 4297 | - return; | ||
| 4298 | - } | ||
| 4299 | GEN_LOAD_IMM_TN(T1, fs); | 4360 | GEN_LOAD_IMM_TN(T1, fs); |
| 4300 | GEN_LOAD_REG_TN(T0, rt); | 4361 | GEN_LOAD_REG_TN(T0, rt); |
| 4301 | gen_op_ctc1(); | 4362 | gen_op_ctc1(); |
| 4302 | opn = "ctc1"; | 4363 | opn = "ctc1"; |
| 4303 | break; | 4364 | break; |
| 4304 | case OPC_DMFC1: | 4365 | case OPC_DMFC1: |
| 4366 | + GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 4367 | + gen_op_dmfc1(); | ||
| 4368 | + GEN_STORE_TN_REG(rt, T0); | ||
| 4369 | + opn = "dmfc1"; | ||
| 4370 | + break; | ||
| 4305 | case OPC_DMTC1: | 4371 | case OPC_DMTC1: |
| 4306 | - /* Not implemented, fallthrough. */ | 4372 | + GEN_LOAD_REG_TN(T0, rt); |
| 4373 | + gen_op_dmtc1(); | ||
| 4374 | + GEN_STORE_FTN_FREG(fs, DT0); | ||
| 4375 | + opn = "dmtc1"; | ||
| 4376 | + break; | ||
| 4377 | + case OPC_MFHC1: | ||
| 4378 | + CHECK_FR(ctx, fs); | ||
| 4379 | + GEN_LOAD_FREG_FTN(WTH0, fs); | ||
| 4380 | + gen_op_mfhc1(); | ||
| 4381 | + GEN_STORE_TN_REG(rt, T0); | ||
| 4382 | + opn = "mfhc1"; | ||
| 4383 | + break; | ||
| 4384 | + case OPC_MTHC1: | ||
| 4385 | + CHECK_FR(ctx, fs); | ||
| 4386 | + GEN_LOAD_REG_TN(T0, rt); | ||
| 4387 | + gen_op_mthc1(); | ||
| 4388 | + GEN_STORE_FTN_FREG(fs, WTH0); | ||
| 4389 | + opn = "mthc1"; | ||
| 4390 | + break; | ||
| 4307 | default: | 4391 | default: |
| 4308 | if (loglevel & CPU_LOG_TB_IN_ASM) { | 4392 | if (loglevel & CPU_LOG_TB_IN_ASM) { |
| 4309 | fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n", | 4393 | fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n", |
| @@ -4316,26 +4400,44 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) | @@ -4316,26 +4400,44 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) | ||
| 4316 | MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]); | 4400 | MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]); |
| 4317 | } | 4401 | } |
| 4318 | 4402 | ||
| 4319 | -/* verify if floating point register is valid; an operation is not defined | ||
| 4320 | - * if bit 0 of any register specification is set and the FR bit in the | ||
| 4321 | - * Status register equals zero, since the register numbers specify an | ||
| 4322 | - * even-odd pair of adjacent coprocessor general registers. When the FR bit | ||
| 4323 | - * in the Status register equals one, both even and odd register numbers | ||
| 4324 | - * are valid. This limitation exists only for 64 bit wide (d,l) registers. | ||
| 4325 | - * | ||
| 4326 | - * Multiple 64 bit wide registers can be checked by calling | ||
| 4327 | - * CHECK_FR(ctx, freg1 | freg2 | ... | fregN); | ||
| 4328 | - */ | ||
| 4329 | -#define CHECK_FR(ctx, freg) do { \ | ||
| 4330 | - if (!((ctx)->CP0_Status & (1<<CP0St_FR)) && ((freg) & 1)) { \ | ||
| 4331 | - generate_exception (ctx, EXCP_RI); \ | ||
| 4332 | - return; \ | ||
| 4333 | - } \ | ||
| 4334 | - } while(0) | 4403 | +static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) |
| 4404 | +{ | ||
| 4405 | + uint32_t ccbit; | ||
| 4335 | 4406 | ||
| 4336 | -#define FOP(func, fmt) (((fmt) << 21) | (func)) | 4407 | + GEN_LOAD_REG_TN(T0, rd); |
| 4408 | + GEN_LOAD_REG_TN(T1, rs); | ||
| 4409 | + if (cc) | ||
| 4410 | + ccbit = 1 << (24 + cc); | ||
| 4411 | + else | ||
| 4412 | + ccbit = 1 << 23; | ||
| 4413 | + if (!tf) | ||
| 4414 | + gen_op_movf(ccbit); | ||
| 4415 | + else | ||
| 4416 | + gen_op_movt(ccbit); | ||
| 4417 | + GEN_STORE_TN_REG(rd, T0); | ||
| 4418 | +} | ||
| 4419 | + | ||
| 4420 | +#define GEN_MOVCF(fmt) \ | ||
| 4421 | +static void glue(gen_movcf_, fmt) (DisasContext *ctx, int cc, int tf) \ | ||
| 4422 | +{ \ | ||
| 4423 | + uint32_t ccbit; \ | ||
| 4424 | + \ | ||
| 4425 | + if (cc) \ | ||
| 4426 | + ccbit = 1 << (24 + cc); \ | ||
| 4427 | + else \ | ||
| 4428 | + ccbit = 1 << 23; \ | ||
| 4429 | + if (!tf) \ | ||
| 4430 | + glue(gen_op_float_movf_, fmt)(ccbit); \ | ||
| 4431 | + else \ | ||
| 4432 | + glue(gen_op_float_movt_, fmt)(ccbit); \ | ||
| 4433 | +} | ||
| 4434 | +GEN_MOVCF(d); | ||
| 4435 | +GEN_MOVCF(s); | ||
| 4436 | +GEN_MOVCF(ps); | ||
| 4437 | +#undef GEN_MOVCF | ||
| 4337 | 4438 | ||
| 4338 | -static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) | 4439 | +static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, |
| 4440 | + int fs, int fd, int cc) | ||
| 4339 | { | 4441 | { |
| 4340 | const char *opn = "unk"; | 4442 | const char *opn = "unk"; |
| 4341 | const char *condnames[] = { | 4443 | const char *condnames[] = { |
| @@ -4360,6 +4462,187 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) | @@ -4360,6 +4462,187 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) | ||
| 4360 | uint32_t func = ctx->opcode & 0x3f; | 4462 | uint32_t func = ctx->opcode & 0x3f; |
| 4361 | 4463 | ||
| 4362 | switch (ctx->opcode & FOP(0x3f, 0x1f)) { | 4464 | switch (ctx->opcode & FOP(0x3f, 0x1f)) { |
| 4465 | + case FOP(0, 16): | ||
| 4466 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4467 | + GEN_LOAD_FREG_FTN(WT1, ft); | ||
| 4468 | + gen_op_float_add_s(); | ||
| 4469 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4470 | + opn = "add.s"; | ||
| 4471 | + binary = 1; | ||
| 4472 | + break; | ||
| 4473 | + case FOP(1, 16): | ||
| 4474 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4475 | + GEN_LOAD_FREG_FTN(WT1, ft); | ||
| 4476 | + gen_op_float_sub_s(); | ||
| 4477 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4478 | + opn = "sub.s"; | ||
| 4479 | + binary = 1; | ||
| 4480 | + break; | ||
| 4481 | + case FOP(2, 16): | ||
| 4482 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4483 | + GEN_LOAD_FREG_FTN(WT1, ft); | ||
| 4484 | + gen_op_float_mul_s(); | ||
| 4485 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4486 | + opn = "mul.s"; | ||
| 4487 | + binary = 1; | ||
| 4488 | + break; | ||
| 4489 | + case FOP(3, 16): | ||
| 4490 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4491 | + GEN_LOAD_FREG_FTN(WT1, ft); | ||
| 4492 | + gen_op_float_div_s(); | ||
| 4493 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4494 | + opn = "div.s"; | ||
| 4495 | + binary = 1; | ||
| 4496 | + break; | ||
| 4497 | + case FOP(4, 16): | ||
| 4498 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4499 | + gen_op_float_sqrt_s(); | ||
| 4500 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4501 | + opn = "sqrt.s"; | ||
| 4502 | + break; | ||
| 4503 | + case FOP(5, 16): | ||
| 4504 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4505 | + gen_op_float_abs_s(); | ||
| 4506 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4507 | + opn = "abs.s"; | ||
| 4508 | + break; | ||
| 4509 | + case FOP(6, 16): | ||
| 4510 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4511 | + gen_op_float_mov_s(); | ||
| 4512 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4513 | + opn = "mov.s"; | ||
| 4514 | + break; | ||
| 4515 | + case FOP(7, 16): | ||
| 4516 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4517 | + gen_op_float_chs_s(); | ||
| 4518 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4519 | + opn = "neg.s"; | ||
| 4520 | + break; | ||
| 4521 | + case FOP(8, 16): | ||
| 4522 | + CHECK_FR(ctx, fs); | ||
| 4523 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4524 | + gen_op_float_roundl_s(); | ||
| 4525 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4526 | + opn = "round.l.s"; | ||
| 4527 | + break; | ||
| 4528 | + case FOP(9, 16): | ||
| 4529 | + CHECK_FR(ctx, fs); | ||
| 4530 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4531 | + gen_op_float_truncl_s(); | ||
| 4532 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4533 | + opn = "trunc.l.s"; | ||
| 4534 | + break; | ||
| 4535 | + case FOP(10, 16): | ||
| 4536 | + CHECK_FR(ctx, fs); | ||
| 4537 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4538 | + gen_op_float_ceill_s(); | ||
| 4539 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4540 | + opn = "ceil.l.s"; | ||
| 4541 | + break; | ||
| 4542 | + case FOP(11, 16): | ||
| 4543 | + CHECK_FR(ctx, fs); | ||
| 4544 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4545 | + gen_op_float_floorl_s(); | ||
| 4546 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4547 | + opn = "floor.l.s"; | ||
| 4548 | + break; | ||
| 4549 | + case FOP(12, 16): | ||
| 4550 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4551 | + gen_op_float_roundw_s(); | ||
| 4552 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4553 | + opn = "round.w.s"; | ||
| 4554 | + break; | ||
| 4555 | + case FOP(13, 16): | ||
| 4556 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4557 | + gen_op_float_truncw_s(); | ||
| 4558 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4559 | + opn = "trunc.w.s"; | ||
| 4560 | + break; | ||
| 4561 | + case FOP(14, 16): | ||
| 4562 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4563 | + gen_op_float_ceilw_s(); | ||
| 4564 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4565 | + opn = "ceil.w.s"; | ||
| 4566 | + break; | ||
| 4567 | + case FOP(15, 16): | ||
| 4568 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4569 | + gen_op_float_floorw_s(); | ||
| 4570 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4571 | + opn = "floor.w.s"; | ||
| 4572 | + break; | ||
| 4573 | + case FOP(17, 16): | ||
| 4574 | + GEN_LOAD_REG_TN(T0, ft); | ||
| 4575 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4576 | + GEN_LOAD_FREG_FTN(WT2, fd); | ||
| 4577 | + gen_movcf_s(ctx, (ft >> 2) & 0x7, ft & 0x1); | ||
| 4578 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4579 | + opn = "movcf.s"; | ||
| 4580 | + break; | ||
| 4581 | + case FOP(18, 16): | ||
| 4582 | + GEN_LOAD_REG_TN(T0, ft); | ||
| 4583 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4584 | + GEN_LOAD_FREG_FTN(WT2, fd); | ||
| 4585 | + gen_op_float_movz_s(); | ||
| 4586 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4587 | + opn = "movz.s"; | ||
| 4588 | + break; | ||
| 4589 | + case FOP(19, 16): | ||
| 4590 | + GEN_LOAD_REG_TN(T0, ft); | ||
| 4591 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4592 | + GEN_LOAD_FREG_FTN(WT2, fd); | ||
| 4593 | + gen_op_float_movn_s(); | ||
| 4594 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4595 | + opn = "movn.s"; | ||
| 4596 | + break; | ||
| 4597 | + case FOP(33, 16): | ||
| 4598 | + CHECK_FR(ctx, fd); | ||
| 4599 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4600 | + gen_op_float_cvtd_s(); | ||
| 4601 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4602 | + opn = "cvt.d.s"; | ||
| 4603 | + break; | ||
| 4604 | + case FOP(36, 16): | ||
| 4605 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4606 | + gen_op_float_cvtw_s(); | ||
| 4607 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4608 | + opn = "cvt.w.s"; | ||
| 4609 | + break; | ||
| 4610 | + case FOP(37, 16): | ||
| 4611 | + CHECK_FR(ctx, fs | fd); | ||
| 4612 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4613 | + gen_op_float_cvtl_s(); | ||
| 4614 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4615 | + opn = "cvt.l.s"; | ||
| 4616 | + break; | ||
| 4617 | + case FOP(38, 16): | ||
| 4618 | + CHECK_FR(ctx, fs | ft | fd); | ||
| 4619 | + GEN_LOAD_FREG_FTN(WT1, fs); | ||
| 4620 | + GEN_LOAD_FREG_FTN(WT0, ft); | ||
| 4621 | + gen_op_float_cvtps_s(); | ||
| 4622 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4623 | + opn = "cvt.ps.s"; | ||
| 4624 | + break; | ||
| 4625 | + case FOP(48, 16): | ||
| 4626 | + case FOP(49, 16): | ||
| 4627 | + case FOP(50, 16): | ||
| 4628 | + case FOP(51, 16): | ||
| 4629 | + case FOP(52, 16): | ||
| 4630 | + case FOP(53, 16): | ||
| 4631 | + case FOP(54, 16): | ||
| 4632 | + case FOP(55, 16): | ||
| 4633 | + case FOP(56, 16): | ||
| 4634 | + case FOP(57, 16): | ||
| 4635 | + case FOP(58, 16): | ||
| 4636 | + case FOP(59, 16): | ||
| 4637 | + case FOP(60, 16): | ||
| 4638 | + case FOP(61, 16): | ||
| 4639 | + case FOP(62, 16): | ||
| 4640 | + case FOP(63, 16): | ||
| 4641 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4642 | + GEN_LOAD_FREG_FTN(WT1, ft); | ||
| 4643 | + gen_cmp_s(func-48, cc); | ||
| 4644 | + opn = condnames[func-48]; | ||
| 4645 | + break; | ||
| 4363 | case FOP(0, 17): | 4646 | case FOP(0, 17): |
| 4364 | CHECK_FR(ctx, fs | ft | fd); | 4647 | CHECK_FR(ctx, fs | ft | fd); |
| 4365 | GEN_LOAD_FREG_FTN(DT0, fs); | 4648 | GEN_LOAD_FREG_FTN(DT0, fs); |
| @@ -4424,10 +4707,34 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) | @@ -4424,10 +4707,34 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) | ||
| 4424 | GEN_STORE_FTN_FREG(fd, DT2); | 4707 | GEN_STORE_FTN_FREG(fd, DT2); |
| 4425 | opn = "neg.d"; | 4708 | opn = "neg.d"; |
| 4426 | break; | 4709 | break; |
| 4427 | - /* 8 - round.l */ | ||
| 4428 | - /* 9 - trunc.l */ | ||
| 4429 | - /* 10 - ceil.l */ | ||
| 4430 | - /* 11 - floor.l */ | 4710 | + case FOP(8, 17): |
| 4711 | + CHECK_FR(ctx, fs); | ||
| 4712 | + GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 4713 | + gen_op_float_roundl_d(); | ||
| 4714 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4715 | + opn = "round.l.d"; | ||
| 4716 | + break; | ||
| 4717 | + case FOP(9, 17): | ||
| 4718 | + CHECK_FR(ctx, fs); | ||
| 4719 | + GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 4720 | + gen_op_float_truncl_d(); | ||
| 4721 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4722 | + opn = "trunc.l.d"; | ||
| 4723 | + break; | ||
| 4724 | + case FOP(10, 17): | ||
| 4725 | + CHECK_FR(ctx, fs); | ||
| 4726 | + GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 4727 | + gen_op_float_ceill_d(); | ||
| 4728 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4729 | + opn = "ceil.l.d"; | ||
| 4730 | + break; | ||
| 4731 | + case FOP(11, 17): | ||
| 4732 | + CHECK_FR(ctx, fs); | ||
| 4733 | + GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 4734 | + gen_op_float_floorl_d(); | ||
| 4735 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4736 | + opn = "floor.l.d"; | ||
| 4737 | + break; | ||
| 4431 | case FOP(12, 17): | 4738 | case FOP(12, 17): |
| 4432 | CHECK_FR(ctx, fs); | 4739 | CHECK_FR(ctx, fs); |
| 4433 | GEN_LOAD_FREG_FTN(DT0, fs); | 4740 | GEN_LOAD_FREG_FTN(DT0, fs); |
| @@ -4456,19 +4763,29 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) | @@ -4456,19 +4763,29 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) | ||
| 4456 | GEN_STORE_FTN_FREG(fd, WT2); | 4763 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4457 | opn = "floor.w.d"; | 4764 | opn = "floor.w.d"; |
| 4458 | break; | 4765 | break; |
| 4459 | - case FOP(33, 16): | ||
| 4460 | - CHECK_FR(ctx, fd); | ||
| 4461 | - GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4462 | - gen_op_float_cvtd_s(); | 4766 | + case FOP(17, 17): |
| 4767 | + GEN_LOAD_REG_TN(T0, ft); | ||
| 4768 | + GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 4769 | + GEN_LOAD_FREG_FTN(DT2, fd); | ||
| 4770 | + gen_movcf_d(ctx, (ft >> 2) & 0x7, ft & 0x1); | ||
| 4463 | GEN_STORE_FTN_FREG(fd, DT2); | 4771 | GEN_STORE_FTN_FREG(fd, DT2); |
| 4464 | - opn = "cvt.d.s"; | 4772 | + opn = "movcf.d"; |
| 4465 | break; | 4773 | break; |
| 4466 | - case FOP(33, 20): | ||
| 4467 | - CHECK_FR(ctx, fd); | ||
| 4468 | - GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4469 | - gen_op_float_cvtd_w(); | 4774 | + case FOP(18, 17): |
| 4775 | + GEN_LOAD_REG_TN(T0, ft); | ||
| 4776 | + GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 4777 | + GEN_LOAD_FREG_FTN(DT2, fd); | ||
| 4778 | + gen_op_float_movz_d(); | ||
| 4470 | GEN_STORE_FTN_FREG(fd, DT2); | 4779 | GEN_STORE_FTN_FREG(fd, DT2); |
| 4471 | - opn = "cvt.d.w"; | 4780 | + opn = "movz.d"; |
| 4781 | + break; | ||
| 4782 | + case FOP(19, 17): | ||
| 4783 | + GEN_LOAD_REG_TN(T0, ft); | ||
| 4784 | + GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 4785 | + GEN_LOAD_FREG_FTN(DT2, fd); | ||
| 4786 | + gen_op_float_movn_d(); | ||
| 4787 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4788 | + opn = "movn.d"; | ||
| 4472 | break; | 4789 | break; |
| 4473 | case FOP(48, 17): | 4790 | case FOP(48, 17): |
| 4474 | case FOP(49, 17): | 4791 | case FOP(49, 17): |
| @@ -4489,125 +4806,240 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) | @@ -4489,125 +4806,240 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) | ||
| 4489 | CHECK_FR(ctx, fs | ft); | 4806 | CHECK_FR(ctx, fs | ft); |
| 4490 | GEN_LOAD_FREG_FTN(DT0, fs); | 4807 | GEN_LOAD_FREG_FTN(DT0, fs); |
| 4491 | GEN_LOAD_FREG_FTN(DT1, ft); | 4808 | GEN_LOAD_FREG_FTN(DT1, ft); |
| 4492 | - gen_cmp_d(func-48); | 4809 | + gen_cmp_d(func-48, cc); |
| 4493 | opn = condnames[func-48]; | 4810 | opn = condnames[func-48]; |
| 4494 | break; | 4811 | break; |
| 4495 | - case FOP(0, 16): | 4812 | + case FOP(32, 17): |
| 4813 | + CHECK_FR(ctx, fs); | ||
| 4814 | + GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 4815 | + gen_op_float_cvts_d(); | ||
| 4816 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4817 | + opn = "cvt.s.d"; | ||
| 4818 | + break; | ||
| 4819 | + case FOP(36, 17): | ||
| 4820 | + CHECK_FR(ctx, fs); | ||
| 4821 | + GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 4822 | + gen_op_float_cvtw_d(); | ||
| 4823 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4824 | + opn = "cvt.w.d"; | ||
| 4825 | + break; | ||
| 4826 | + case FOP(37, 17): | ||
| 4827 | + CHECK_FR(ctx, fs | fd); | ||
| 4828 | + GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 4829 | + gen_op_float_cvtl_d(); | ||
| 4830 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4831 | + opn = "cvt.l.d"; | ||
| 4832 | + break; | ||
| 4833 | + case FOP(32, 20): | ||
| 4496 | GEN_LOAD_FREG_FTN(WT0, fs); | 4834 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4497 | - GEN_LOAD_FREG_FTN(WT1, ft); | ||
| 4498 | - gen_op_float_add_s(); | 4835 | + gen_op_float_cvts_w(); |
| 4499 | GEN_STORE_FTN_FREG(fd, WT2); | 4836 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4500 | - opn = "add.s"; | ||
| 4501 | - binary = 1; | 4837 | + opn = "cvt.s.w"; |
| 4502 | break; | 4838 | break; |
| 4503 | - case FOP(1, 16): | 4839 | + case FOP(33, 20): |
| 4840 | + CHECK_FR(ctx, fd); | ||
| 4504 | GEN_LOAD_FREG_FTN(WT0, fs); | 4841 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4842 | + gen_op_float_cvtd_w(); | ||
| 4843 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4844 | + opn = "cvt.d.w"; | ||
| 4845 | + break; | ||
| 4846 | + case FOP(32, 21): | ||
| 4847 | + CHECK_FR(ctx, fs); | ||
| 4848 | + GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 4849 | + gen_op_float_cvts_l(); | ||
| 4850 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4851 | + opn = "cvt.s.l"; | ||
| 4852 | + break; | ||
| 4853 | + case FOP(33, 21): | ||
| 4854 | + CHECK_FR(ctx, fs | fd); | ||
| 4855 | + GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 4856 | + gen_op_float_cvtd_l(); | ||
| 4857 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4858 | + opn = "cvt.d.l"; | ||
| 4859 | + break; | ||
| 4860 | + case FOP(38, 20): | ||
| 4861 | + case FOP(38, 21): | ||
| 4862 | + CHECK_FR(ctx, fs | fd); | ||
| 4863 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4864 | + GEN_LOAD_FREG_FTN(WTH0, fs); | ||
| 4865 | + gen_op_float_cvtps_pw(); | ||
| 4866 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4867 | + GEN_STORE_FTN_FREG(fd, WTH2); | ||
| 4868 | + opn = "cvt.ps.pw"; | ||
| 4869 | + break; | ||
| 4870 | + case FOP(0, 22): | ||
| 4871 | + CHECK_FR(ctx, fs | ft | fd); | ||
| 4872 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4873 | + GEN_LOAD_FREG_FTN(WTH0, fs); | ||
| 4505 | GEN_LOAD_FREG_FTN(WT1, ft); | 4874 | GEN_LOAD_FREG_FTN(WT1, ft); |
| 4506 | - gen_op_float_sub_s(); | 4875 | + GEN_LOAD_FREG_FTN(WTH1, ft); |
| 4876 | + gen_op_float_add_ps(); | ||
| 4507 | GEN_STORE_FTN_FREG(fd, WT2); | 4877 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4508 | - opn = "sub.s"; | ||
| 4509 | - binary = 1; | 4878 | + GEN_STORE_FTN_FREG(fd, WTH2); |
| 4879 | + opn = "add.ps"; | ||
| 4510 | break; | 4880 | break; |
| 4511 | - case FOP(2, 16): | 4881 | + case FOP(1, 22): |
| 4882 | + CHECK_FR(ctx, fs | ft | fd); | ||
| 4512 | GEN_LOAD_FREG_FTN(WT0, fs); | 4883 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4884 | + GEN_LOAD_FREG_FTN(WTH0, fs); | ||
| 4513 | GEN_LOAD_FREG_FTN(WT1, ft); | 4885 | GEN_LOAD_FREG_FTN(WT1, ft); |
| 4514 | - gen_op_float_mul_s(); | 4886 | + GEN_LOAD_FREG_FTN(WTH1, ft); |
| 4887 | + gen_op_float_sub_ps(); | ||
| 4515 | GEN_STORE_FTN_FREG(fd, WT2); | 4888 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4516 | - opn = "mul.s"; | ||
| 4517 | - binary = 1; | 4889 | + GEN_STORE_FTN_FREG(fd, WTH2); |
| 4890 | + opn = "sub.ps"; | ||
| 4518 | break; | 4891 | break; |
| 4519 | - case FOP(3, 16): | 4892 | + case FOP(2, 22): |
| 4893 | + CHECK_FR(ctx, fs | ft | fd); | ||
| 4520 | GEN_LOAD_FREG_FTN(WT0, fs); | 4894 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4895 | + GEN_LOAD_FREG_FTN(WTH0, fs); | ||
| 4521 | GEN_LOAD_FREG_FTN(WT1, ft); | 4896 | GEN_LOAD_FREG_FTN(WT1, ft); |
| 4522 | - gen_op_float_div_s(); | 4897 | + GEN_LOAD_FREG_FTN(WTH1, ft); |
| 4898 | + gen_op_float_mul_ps(); | ||
| 4523 | GEN_STORE_FTN_FREG(fd, WT2); | 4899 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4524 | - opn = "div.s"; | ||
| 4525 | - binary = 1; | 4900 | + GEN_STORE_FTN_FREG(fd, WTH2); |
| 4901 | + opn = "mul.ps"; | ||
| 4526 | break; | 4902 | break; |
| 4527 | - case FOP(4, 16): | 4903 | + case FOP(5, 22): |
| 4904 | + CHECK_FR(ctx, fs | fd); | ||
| 4528 | GEN_LOAD_FREG_FTN(WT0, fs); | 4905 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4529 | - gen_op_float_sqrt_s(); | 4906 | + GEN_LOAD_FREG_FTN(WTH0, fs); |
| 4907 | + gen_op_float_abs_ps(); | ||
| 4530 | GEN_STORE_FTN_FREG(fd, WT2); | 4908 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4531 | - opn = "sqrt.s"; | 4909 | + GEN_STORE_FTN_FREG(fd, WTH2); |
| 4910 | + opn = "abs.ps"; | ||
| 4532 | break; | 4911 | break; |
| 4533 | - case FOP(5, 16): | 4912 | + case FOP(6, 22): |
| 4913 | + CHECK_FR(ctx, fs | fd); | ||
| 4534 | GEN_LOAD_FREG_FTN(WT0, fs); | 4914 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4535 | - gen_op_float_abs_s(); | 4915 | + GEN_LOAD_FREG_FTN(WTH0, fs); |
| 4916 | + gen_op_float_mov_ps(); | ||
| 4536 | GEN_STORE_FTN_FREG(fd, WT2); | 4917 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4537 | - opn = "abs.s"; | 4918 | + GEN_STORE_FTN_FREG(fd, WTH2); |
| 4919 | + opn = "mov.ps"; | ||
| 4538 | break; | 4920 | break; |
| 4539 | - case FOP(6, 16): | 4921 | + case FOP(7, 22): |
| 4922 | + CHECK_FR(ctx, fs | fd); | ||
| 4540 | GEN_LOAD_FREG_FTN(WT0, fs); | 4923 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4541 | - gen_op_float_mov_s(); | 4924 | + GEN_LOAD_FREG_FTN(WTH0, fs); |
| 4925 | + gen_op_float_chs_ps(); | ||
| 4542 | GEN_STORE_FTN_FREG(fd, WT2); | 4926 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4543 | - opn = "mov.s"; | 4927 | + GEN_STORE_FTN_FREG(fd, WTH2); |
| 4928 | + opn = "neg.ps"; | ||
| 4544 | break; | 4929 | break; |
| 4545 | - case FOP(7, 16): | 4930 | + case FOP(17, 22): |
| 4931 | + GEN_LOAD_REG_TN(T0, ft); | ||
| 4546 | GEN_LOAD_FREG_FTN(WT0, fs); | 4932 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4547 | - gen_op_float_chs_s(); | 4933 | + GEN_LOAD_FREG_FTN(WTH0, fs); |
| 4934 | + GEN_LOAD_FREG_FTN(WT2, fd); | ||
| 4935 | + GEN_LOAD_FREG_FTN(WTH2, fd); | ||
| 4936 | + gen_movcf_ps(ctx, (ft >> 2) & 0x7, ft & 0x1); | ||
| 4548 | GEN_STORE_FTN_FREG(fd, WT2); | 4937 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4549 | - opn = "neg.s"; | 4938 | + GEN_STORE_FTN_FREG(fd, WTH2); |
| 4939 | + opn = "movcf.ps"; | ||
| 4550 | break; | 4940 | break; |
| 4551 | - case FOP(12, 16): | 4941 | + case FOP(18, 22): |
| 4942 | + GEN_LOAD_REG_TN(T0, ft); | ||
| 4552 | GEN_LOAD_FREG_FTN(WT0, fs); | 4943 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4553 | - gen_op_float_roundw_s(); | 4944 | + GEN_LOAD_FREG_FTN(WTH0, fs); |
| 4945 | + GEN_LOAD_FREG_FTN(WT2, fd); | ||
| 4946 | + GEN_LOAD_FREG_FTN(WTH2, fd); | ||
| 4947 | + gen_op_float_movz_ps(); | ||
| 4554 | GEN_STORE_FTN_FREG(fd, WT2); | 4948 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4555 | - opn = "round.w.s"; | 4949 | + GEN_STORE_FTN_FREG(fd, WTH2); |
| 4950 | + opn = "movz.ps"; | ||
| 4556 | break; | 4951 | break; |
| 4557 | - case FOP(13, 16): | 4952 | + case FOP(19, 22): |
| 4953 | + GEN_LOAD_REG_TN(T0, ft); | ||
| 4558 | GEN_LOAD_FREG_FTN(WT0, fs); | 4954 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4559 | - gen_op_float_truncw_s(); | 4955 | + GEN_LOAD_FREG_FTN(WTH0, fs); |
| 4956 | + GEN_LOAD_FREG_FTN(WT2, fd); | ||
| 4957 | + GEN_LOAD_FREG_FTN(WTH2, fd); | ||
| 4958 | + gen_op_float_movn_ps(); | ||
| 4560 | GEN_STORE_FTN_FREG(fd, WT2); | 4959 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4561 | - opn = "trunc.w.s"; | 4960 | + GEN_STORE_FTN_FREG(fd, WTH2); |
| 4961 | + opn = "movn.ps"; | ||
| 4562 | break; | 4962 | break; |
| 4563 | - case FOP(32, 17): | 4963 | + case FOP(32, 22): |
| 4564 | CHECK_FR(ctx, fs); | 4964 | CHECK_FR(ctx, fs); |
| 4565 | - GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 4566 | - gen_op_float_cvts_d(); | 4965 | + GEN_LOAD_FREG_FTN(WTH0, fs); |
| 4966 | + gen_op_float_cvts_pu(); | ||
| 4567 | GEN_STORE_FTN_FREG(fd, WT2); | 4967 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4568 | - opn = "cvt.s.d"; | 4968 | + opn = "cvt.s.pu"; |
| 4569 | break; | 4969 | break; |
| 4570 | - case FOP(32, 20): | 4970 | + case FOP(36, 22): |
| 4971 | + CHECK_FR(ctx, fs | fd); | ||
| 4571 | GEN_LOAD_FREG_FTN(WT0, fs); | 4972 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4572 | - gen_op_float_cvts_w(); | 4973 | + GEN_LOAD_FREG_FTN(WTH0, fs); |
| 4974 | + gen_op_float_cvtpw_ps(); | ||
| 4573 | GEN_STORE_FTN_FREG(fd, WT2); | 4975 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4574 | - opn = "cvt.s.w"; | 4976 | + GEN_STORE_FTN_FREG(fd, WTH2); |
| 4977 | + opn = "cvt.pw.ps"; | ||
| 4575 | break; | 4978 | break; |
| 4576 | - case FOP(36, 16): | 4979 | + case FOP(40, 22): |
| 4980 | + CHECK_FR(ctx, fs); | ||
| 4577 | GEN_LOAD_FREG_FTN(WT0, fs); | 4981 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4578 | - gen_op_float_cvtw_s(); | 4982 | + gen_op_float_cvts_pl(); |
| 4579 | GEN_STORE_FTN_FREG(fd, WT2); | 4983 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4580 | - opn = "cvt.w.s"; | 4984 | + opn = "cvt.s.pl"; |
| 4581 | break; | 4985 | break; |
| 4582 | - case FOP(36, 17): | ||
| 4583 | - CHECK_FR(ctx, fs); | ||
| 4584 | - GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 4585 | - gen_op_float_cvtw_d(); | ||
| 4586 | - GEN_STORE_FTN_FREG(fd, WT2); | ||
| 4587 | - opn = "cvt.w.d"; | 4986 | + case FOP(44, 22): |
| 4987 | + CHECK_FR(ctx, fs | ft | fd); | ||
| 4988 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 4989 | + GEN_LOAD_FREG_FTN(WT1, ft); | ||
| 4990 | + gen_op_float_pll_ps(); | ||
| 4991 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 4992 | + opn = "pll.ps"; | ||
| 4588 | break; | 4993 | break; |
| 4589 | - case FOP(48, 16): | ||
| 4590 | - case FOP(49, 16): | ||
| 4591 | - case FOP(50, 16): | ||
| 4592 | - case FOP(51, 16): | ||
| 4593 | - case FOP(52, 16): | ||
| 4594 | - case FOP(53, 16): | ||
| 4595 | - case FOP(54, 16): | ||
| 4596 | - case FOP(55, 16): | ||
| 4597 | - case FOP(56, 16): | ||
| 4598 | - case FOP(57, 16): | ||
| 4599 | - case FOP(58, 16): | ||
| 4600 | - case FOP(59, 16): | ||
| 4601 | - case FOP(60, 16): | ||
| 4602 | - case FOP(61, 16): | ||
| 4603 | - case FOP(62, 16): | ||
| 4604 | - case FOP(63, 16): | 4994 | + case FOP(45, 22): |
| 4995 | + CHECK_FR(ctx, fs | ft | fd); | ||
| 4605 | GEN_LOAD_FREG_FTN(WT0, fs); | 4996 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4997 | + GEN_LOAD_FREG_FTN(WTH1, ft); | ||
| 4998 | + gen_op_float_plu_ps(); | ||
| 4999 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 5000 | + opn = "plu.ps"; | ||
| 5001 | + break; | ||
| 5002 | + case FOP(46, 22): | ||
| 5003 | + CHECK_FR(ctx, fs | ft | fd); | ||
| 5004 | + GEN_LOAD_FREG_FTN(WTH0, fs); | ||
| 4606 | GEN_LOAD_FREG_FTN(WT1, ft); | 5005 | GEN_LOAD_FREG_FTN(WT1, ft); |
| 4607 | - gen_cmp_s(func-48); | 5006 | + gen_op_float_pul_ps(); |
| 5007 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 5008 | + opn = "pul.ps"; | ||
| 5009 | + break; | ||
| 5010 | + case FOP(47, 22): | ||
| 5011 | + CHECK_FR(ctx, fs | ft | fd); | ||
| 5012 | + GEN_LOAD_FREG_FTN(WTH0, fs); | ||
| 5013 | + GEN_LOAD_FREG_FTN(WTH1, ft); | ||
| 5014 | + gen_op_float_puu_ps(); | ||
| 5015 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 5016 | + opn = "puu.ps"; | ||
| 5017 | + break; | ||
| 5018 | + case FOP(48, 22): | ||
| 5019 | + case FOP(49, 22): | ||
| 5020 | + case FOP(50, 22): | ||
| 5021 | + case FOP(51, 22): | ||
| 5022 | + case FOP(52, 22): | ||
| 5023 | + case FOP(53, 22): | ||
| 5024 | + case FOP(54, 22): | ||
| 5025 | + case FOP(55, 22): | ||
| 5026 | + case FOP(56, 22): | ||
| 5027 | + case FOP(57, 22): | ||
| 5028 | + case FOP(58, 22): | ||
| 5029 | + case FOP(59, 22): | ||
| 5030 | + case FOP(60, 22): | ||
| 5031 | + case FOP(61, 22): | ||
| 5032 | + case FOP(62, 22): | ||
| 5033 | + case FOP(63, 22): | ||
| 5034 | + CHECK_FR(ctx, fs | ft); | ||
| 5035 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 5036 | + GEN_LOAD_FREG_FTN(WTH0, fs); | ||
| 5037 | + GEN_LOAD_FREG_FTN(WT1, ft); | ||
| 5038 | + GEN_LOAD_FREG_FTN(WTH1, ft); | ||
| 5039 | + gen_cmp_ps(func-48, cc); | ||
| 4608 | opn = condnames[func-48]; | 5040 | opn = condnames[func-48]; |
| 4609 | break; | 5041 | break; |
| 4610 | - default: | 5042 | + default: |
| 4611 | if (loglevel & CPU_LOG_TB_IN_ASM) { | 5043 | if (loglevel & CPU_LOG_TB_IN_ASM) { |
| 4612 | fprintf(logfile, "Invalid FP arith function: %08x %03x %03x %03x\n", | 5044 | fprintf(logfile, "Invalid FP arith function: %08x %03x %03x %03x\n", |
| 4613 | ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, | 5045 | ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, |
| @@ -4622,18 +5054,134 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) | @@ -4622,18 +5054,134 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) | ||
| 4622 | MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]); | 5054 | MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]); |
| 4623 | } | 5055 | } |
| 4624 | 5056 | ||
| 4625 | -static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) | 5057 | +/* Coprocessor 3 (FPU) */ |
| 5058 | +static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, int fd, | ||
| 5059 | + int base, int index) | ||
| 4626 | { | 5060 | { |
| 4627 | - uint32_t ccbit; | 5061 | + const char *opn = "unk"; |
| 4628 | 5062 | ||
| 4629 | - if (cc) | ||
| 4630 | - ccbit = 1 << (24 + cc); | ||
| 4631 | - else | ||
| 4632 | - ccbit = 1 << 23; | ||
| 4633 | - if (!tf) | ||
| 4634 | - gen_op_movf(ccbit, rd, rs); | ||
| 4635 | - else | ||
| 4636 | - gen_op_movt(ccbit, rd, rs); | 5063 | + GEN_LOAD_REG_TN(T0, base); |
| 5064 | + GEN_LOAD_REG_TN(T1, index); | ||
| 5065 | + /* Don't do NOP if destination is zero: we must perform the actual | ||
| 5066 | + * memory access | ||
| 5067 | + */ | ||
| 5068 | + switch (opc) { | ||
| 5069 | + case OPC_LWXC1: | ||
| 5070 | + op_ldst(lwxc1); | ||
| 5071 | + GEN_STORE_FTN_FREG(fd, WT0); | ||
| 5072 | + opn = "lwxc1"; | ||
| 5073 | + break; | ||
| 5074 | + case OPC_LDXC1: | ||
| 5075 | + op_ldst(ldxc1); | ||
| 5076 | + GEN_STORE_FTN_FREG(fd, DT0); | ||
| 5077 | + opn = "ldxc1"; | ||
| 5078 | + break; | ||
| 5079 | + case OPC_LUXC1: | ||
| 5080 | + op_ldst(luxc1); | ||
| 5081 | + GEN_STORE_FTN_FREG(fd, DT0); | ||
| 5082 | + opn = "luxc1"; | ||
| 5083 | + break; | ||
| 5084 | + case OPC_SWXC1: | ||
| 5085 | + GEN_LOAD_FREG_FTN(WT0, fd); | ||
| 5086 | + op_ldst(swxc1); | ||
| 5087 | + opn = "swxc1"; | ||
| 5088 | + break; | ||
| 5089 | + case OPC_SDXC1: | ||
| 5090 | + GEN_LOAD_FREG_FTN(DT0, fd); | ||
| 5091 | + op_ldst(sdxc1); | ||
| 5092 | + opn = "sdxc1"; | ||
| 5093 | + break; | ||
| 5094 | + case OPC_SUXC1: | ||
| 5095 | + GEN_LOAD_FREG_FTN(DT0, fd); | ||
| 5096 | + op_ldst(suxc1); | ||
| 5097 | + opn = "suxc1"; | ||
| 5098 | + break; | ||
| 5099 | + default: | ||
| 5100 | + MIPS_INVAL("extended float load/store"); | ||
| 5101 | + generate_exception(ctx, EXCP_RI); | ||
| 5102 | + return; | ||
| 5103 | + } | ||
| 5104 | + MIPS_DEBUG("%s %s, %s(%s)", opn, fregnames[fd],regnames[index], regnames[base]); | ||
| 5105 | +} | ||
| 5106 | + | ||
| 5107 | +static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, int fd, | ||
| 5108 | + int fr, int fs, int ft) | ||
| 5109 | +{ | ||
| 5110 | + const char *opn = "unk"; | ||
| 5111 | + | ||
| 5112 | + /* All of those work only on 64bit FPUs. */ | ||
| 5113 | + CHECK_FR(ctx, fd | fr | fs | ft); | ||
| 5114 | + switch (opc) { | ||
| 5115 | + case OPC_ALNV_PS: | ||
| 5116 | + GEN_LOAD_REG_TN(T0, fr); | ||
| 5117 | + GEN_LOAD_FREG_FTN(DT0, fs); | ||
| 5118 | + GEN_LOAD_FREG_FTN(DT1, ft); | ||
| 5119 | + gen_op_float_alnv_ps(); | ||
| 5120 | + GEN_STORE_FTN_FREG(fd, DT2); | ||
| 5121 | + opn = "alnv.ps"; | ||
| 5122 | + break; | ||
| 5123 | + case OPC_MADD_S: | ||
| 5124 | + GEN_LOAD_FREG_FTN(WT0, fs); | ||
| 5125 | + GEN_LOAD_FREG_FTN(WT1, ft); | ||
| 5126 | + GEN_LOAD_FREG_FTN(WT2, fr); | ||
| 5127 | + gen_op_float_muladd_s(); | ||
| 5128 | + GEN_STORE_FTN_FREG(fd, WT2); | ||
| 5129 | + opn = "madd.s"; | ||
| 5130 | + break; | ||
| 5131 | + case OPC_MADD_D: | ||
| 5132 | + generate_exception (ctx, EXCP_RI); | ||
| 5133 | + opn = "madd.d"; | ||
| 5134 | + break; | ||
| 5135 | + case OPC_MADD_PS: | ||
| 5136 | + generate_exception (ctx, EXCP_RI); | ||
| 5137 | + opn = "madd.ps"; | ||
| 5138 | + break; | ||
| 5139 | + case OPC_MSUB_S: | ||
| 5140 | + generate_exception (ctx, EXCP_RI); | ||
| 5141 | + opn = "msub.s"; | ||
| 5142 | + break; | ||
| 5143 | + case OPC_MSUB_D: | ||
| 5144 | + generate_exception (ctx, EXCP_RI); | ||
| 5145 | + opn = "msub.d"; | ||
| 5146 | + break; | ||
| 5147 | + case OPC_MSUB_PS: | ||
| 5148 | + generate_exception (ctx, EXCP_RI); | ||
| 5149 | + opn = "msub.ps"; | ||
| 5150 | + break; | ||
| 5151 | + case OPC_NMADD_S: | ||
| 5152 | + generate_exception (ctx, EXCP_RI); | ||
| 5153 | + opn = "nmadd.s"; | ||
| 5154 | + break; | ||
| 5155 | + case OPC_NMADD_D: | ||
| 5156 | + generate_exception (ctx, EXCP_RI); | ||
| 5157 | + opn = "nmadd.d"; | ||
| 5158 | + break; | ||
| 5159 | + case OPC_NMADD_PS: | ||
| 5160 | + generate_exception (ctx, EXCP_RI); | ||
| 5161 | + opn = "nmadd.ps"; | ||
| 5162 | + break; | ||
| 5163 | + case OPC_NMSUB_S: | ||
| 5164 | + generate_exception (ctx, EXCP_RI); | ||
| 5165 | + opn = "nmsub.s"; | ||
| 5166 | + break; | ||
| 5167 | + case OPC_NMSUB_D: | ||
| 5168 | + generate_exception (ctx, EXCP_RI); | ||
| 5169 | + opn = "nmsub.d"; | ||
| 5170 | + break; | ||
| 5171 | + case OPC_NMSUB_PS: | ||
| 5172 | + generate_exception (ctx, EXCP_RI); | ||
| 5173 | + opn = "nmsub.ps"; | ||
| 5174 | + break; | ||
| 5175 | + default: | ||
| 5176 | + if (loglevel & CPU_LOG_TB_IN_ASM) { | ||
| 5177 | + fprintf(logfile, "Invalid extended FP arith function: %08x %03x %03x\n", | ||
| 5178 | + ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F); | ||
| 5179 | + } | ||
| 5180 | + generate_exception (ctx, EXCP_RI); | ||
| 5181 | + return; | ||
| 5182 | + } | ||
| 5183 | + MIPS_DEBUG("%s %s, %s, %s, %s", opn, fregnames[fd], fregnames[fr], | ||
| 5184 | + fregnames[fs], fregnames[ft]); | ||
| 4637 | } | 5185 | } |
| 4638 | 5186 | ||
| 4639 | /* ISA extensions (ASEs) */ | 5187 | /* ISA extensions (ASEs) */ |
| @@ -4641,23 +5189,12 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) | @@ -4641,23 +5189,12 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) | ||
| 4641 | /* SmartMIPS extension to MIPS32 */ | 5189 | /* SmartMIPS extension to MIPS32 */ |
| 4642 | 5190 | ||
| 4643 | #ifdef TARGET_MIPS64 | 5191 | #ifdef TARGET_MIPS64 |
| 4644 | -/* Coprocessor 3 (FPU) */ | ||
| 4645 | 5192 | ||
| 4646 | /* MDMX extension to MIPS64 */ | 5193 | /* MDMX extension to MIPS64 */ |
| 4647 | /* MIPS-3D extension to MIPS64 */ | 5194 | /* MIPS-3D extension to MIPS64 */ |
| 4648 | 5195 | ||
| 4649 | #endif | 5196 | #endif |
| 4650 | 5197 | ||
| 4651 | -static void gen_blikely(DisasContext *ctx) | ||
| 4652 | -{ | ||
| 4653 | - int l1; | ||
| 4654 | - l1 = gen_new_label(); | ||
| 4655 | - gen_op_jnz_T2(l1); | ||
| 4656 | - gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK); | ||
| 4657 | - gen_goto_tb(ctx, 1, ctx->pc + 4); | ||
| 4658 | - gen_set_label(l1); | ||
| 4659 | -} | ||
| 4660 | - | ||
| 4661 | static void decode_opc (CPUState *env, DisasContext *ctx) | 5198 | static void decode_opc (CPUState *env, DisasContext *ctx) |
| 4662 | { | 5199 | { |
| 4663 | int32_t offset; | 5200 | int32_t offset; |
| @@ -4673,9 +5210,14 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | @@ -4673,9 +5210,14 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | ||
| 4673 | } | 5210 | } |
| 4674 | 5211 | ||
| 4675 | if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) { | 5212 | if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) { |
| 5213 | + int l1; | ||
| 4676 | /* Handle blikely not taken case */ | 5214 | /* Handle blikely not taken case */ |
| 4677 | MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4); | 5215 | MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4); |
| 4678 | - gen_blikely(ctx); | 5216 | + l1 = gen_new_label(); |
| 5217 | + gen_op_jnz_T2(l1); | ||
| 5218 | + gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK); | ||
| 5219 | + gen_goto_tb(ctx, 1, ctx->pc + 4); | ||
| 5220 | + gen_set_label(l1); | ||
| 4679 | } | 5221 | } |
| 4680 | op = MASK_OP_MAJOR(ctx->opcode); | 5222 | op = MASK_OP_MAJOR(ctx->opcode); |
| 4681 | rs = (ctx->opcode >> 21) & 0x1f; | 5223 | rs = (ctx->opcode >> 21) & 0x1f; |
| @@ -5024,16 +5566,21 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | @@ -5024,16 +5566,21 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | ||
| 5024 | case OPC_DMFC1: | 5566 | case OPC_DMFC1: |
| 5025 | case OPC_DMTC1: | 5567 | case OPC_DMTC1: |
| 5026 | #endif | 5568 | #endif |
| 5569 | + case OPC_MFHC1: | ||
| 5570 | + case OPC_MTHC1: | ||
| 5027 | gen_cp1(ctx, op1, rt, rd); | 5571 | gen_cp1(ctx, op1, rt, rd); |
| 5028 | break; | 5572 | break; |
| 5029 | case OPC_BC1: | 5573 | case OPC_BC1: |
| 5030 | - gen_compute_branch1(ctx, MASK_CP1_BCOND(ctx->opcode), imm << 2); | 5574 | + gen_compute_branch1(ctx, MASK_BC1(ctx->opcode), |
| 5575 | + (rt >> 2) & 0x7, imm << 2); | ||
| 5031 | return; | 5576 | return; |
| 5032 | case OPC_S_FMT: | 5577 | case OPC_S_FMT: |
| 5033 | case OPC_D_FMT: | 5578 | case OPC_D_FMT: |
| 5034 | case OPC_W_FMT: | 5579 | case OPC_W_FMT: |
| 5035 | case OPC_L_FMT: | 5580 | case OPC_L_FMT: |
| 5036 | - gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa); | 5581 | + case OPC_PS_FMT: |
| 5582 | + gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa, | ||
| 5583 | + (imm >> 8) & 0x7); | ||
| 5037 | break; | 5584 | break; |
| 5038 | default: | 5585 | default: |
| 5039 | generate_exception (ctx, EXCP_RI); | 5586 | generate_exception (ctx, EXCP_RI); |
| @@ -5060,10 +5607,32 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | @@ -5060,10 +5607,32 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | ||
| 5060 | gen_op_cp1_enabled(); | 5607 | gen_op_cp1_enabled(); |
| 5061 | op1 = MASK_CP3(ctx->opcode); | 5608 | op1 = MASK_CP3(ctx->opcode); |
| 5062 | switch (op1) { | 5609 | switch (op1) { |
| 5610 | + case OPC_LWXC1: | ||
| 5611 | + case OPC_LDXC1: | ||
| 5612 | + case OPC_LUXC1: | ||
| 5613 | + case OPC_SWXC1: | ||
| 5614 | + case OPC_SDXC1: | ||
| 5615 | + case OPC_SUXC1: | ||
| 5616 | + gen_flt3_ldst(ctx, op1, sa, rs, rt); | ||
| 5617 | + break; | ||
| 5063 | case OPC_PREFX: | 5618 | case OPC_PREFX: |
| 5064 | /* treat as noop */ | 5619 | /* treat as noop */ |
| 5065 | break; | 5620 | break; |
| 5066 | - /* Not implemented */ | 5621 | + case OPC_ALNV_PS: |
| 5622 | + case OPC_MADD_S: | ||
| 5623 | + case OPC_MADD_D: | ||
| 5624 | + case OPC_MADD_PS: | ||
| 5625 | + case OPC_MSUB_S: | ||
| 5626 | + case OPC_MSUB_D: | ||
| 5627 | + case OPC_MSUB_PS: | ||
| 5628 | + case OPC_NMADD_S: | ||
| 5629 | + case OPC_NMADD_D: | ||
| 5630 | + case OPC_NMADD_PS: | ||
| 5631 | + case OPC_NMSUB_S: | ||
| 5632 | + case OPC_NMSUB_D: | ||
| 5633 | + case OPC_NMSUB_PS: | ||
| 5634 | + gen_flt3_arith(ctx, op1, sa, rs, rd, rt); | ||
| 5635 | + break; | ||
| 5067 | default: | 5636 | default: |
| 5068 | generate_exception (ctx, EXCP_RI); | 5637 | generate_exception (ctx, EXCP_RI); |
| 5069 | break; | 5638 | break; |
| @@ -5107,7 +5676,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | @@ -5107,7 +5676,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | ||
| 5107 | ctx->hflags &= ~MIPS_HFLAG_BMASK; | 5676 | ctx->hflags &= ~MIPS_HFLAG_BMASK; |
| 5108 | ctx->bstate = BS_BRANCH; | 5677 | ctx->bstate = BS_BRANCH; |
| 5109 | save_cpu_state(ctx, 0); | 5678 | save_cpu_state(ctx, 0); |
| 5110 | - switch (hflags & MIPS_HFLAG_BMASK) { | 5679 | + switch (hflags) { |
| 5111 | case MIPS_HFLAG_B: | 5680 | case MIPS_HFLAG_B: |
| 5112 | /* unconditional branch */ | 5681 | /* unconditional branch */ |
| 5113 | MIPS_DEBUG("unconditional branch"); | 5682 | MIPS_DEBUG("unconditional branch"); |
| @@ -5134,6 +5703,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | @@ -5134,6 +5703,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | ||
| 5134 | /* unconditional branch to register */ | 5703 | /* unconditional branch to register */ |
| 5135 | MIPS_DEBUG("branch to register"); | 5704 | MIPS_DEBUG("branch to register"); |
| 5136 | gen_op_breg(); | 5705 | gen_op_breg(); |
| 5706 | + gen_op_reset_T0(); | ||
| 5707 | + gen_op_exit_tb(); | ||
| 5137 | break; | 5708 | break; |
| 5138 | default: | 5709 | default: |
| 5139 | MIPS_DEBUG("unknown branch"); | 5710 | MIPS_DEBUG("unknown branch"); |
| @@ -5166,16 +5737,18 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | @@ -5166,16 +5737,18 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | ||
| 5166 | /* Restore delay slot state from the tb context. */ | 5737 | /* Restore delay slot state from the tb context. */ |
| 5167 | ctx.hflags = tb->flags; | 5738 | ctx.hflags = tb->flags; |
| 5168 | ctx.saved_hflags = ctx.hflags; | 5739 | ctx.saved_hflags = ctx.hflags; |
| 5169 | - if (ctx.hflags & MIPS_HFLAG_BR) { | 5740 | + switch (ctx.hflags & MIPS_HFLAG_BMASK) { |
| 5741 | + case MIPS_HFLAG_BR: | ||
| 5170 | gen_op_restore_breg_target(); | 5742 | gen_op_restore_breg_target(); |
| 5171 | - } else if (ctx.hflags & MIPS_HFLAG_B) { | 5743 | + break; |
| 5744 | + case MIPS_HFLAG_B: | ||
| 5172 | ctx.btarget = env->btarget; | 5745 | ctx.btarget = env->btarget; |
| 5173 | - } else if (ctx.hflags & MIPS_HFLAG_BMASK) { | ||
| 5174 | - /* If we are in the delay slot of a conditional branch, | ||
| 5175 | - * restore the branch condition from env->bcond to T2 | ||
| 5176 | - */ | 5746 | + break; |
| 5747 | + case MIPS_HFLAG_BC: | ||
| 5748 | + case MIPS_HFLAG_BL: | ||
| 5177 | ctx.btarget = env->btarget; | 5749 | ctx.btarget = env->btarget; |
| 5178 | gen_op_restore_bcond(); | 5750 | gen_op_restore_bcond(); |
| 5751 | + break; | ||
| 5179 | } | 5752 | } |
| 5180 | #if defined(CONFIG_USER_ONLY) | 5753 | #if defined(CONFIG_USER_ONLY) |
| 5181 | ctx.mem_idx = 0; | 5754 | ctx.mem_idx = 0; |
| @@ -5237,12 +5810,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | @@ -5237,12 +5810,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | ||
| 5237 | gen_op_debug(); | 5810 | gen_op_debug(); |
| 5238 | } else { | 5811 | } else { |
| 5239 | switch (ctx.bstate) { | 5812 | switch (ctx.bstate) { |
| 5240 | - case BS_EXCP: | ||
| 5241 | - gen_op_interrupt_restart(); | ||
| 5242 | - gen_op_reset_T0(); | ||
| 5243 | - /* Generate the return instruction. */ | ||
| 5244 | - gen_op_exit_tb(); | ||
| 5245 | - break; | ||
| 5246 | case BS_STOP: | 5813 | case BS_STOP: |
| 5247 | gen_op_interrupt_restart(); | 5814 | gen_op_interrupt_restart(); |
| 5248 | /* Fall through. */ | 5815 | /* Fall through. */ |
| @@ -5250,12 +5817,14 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | @@ -5250,12 +5817,14 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, | ||
| 5250 | save_cpu_state(ctxp, 0); | 5817 | save_cpu_state(ctxp, 0); |
| 5251 | gen_goto_tb(&ctx, 0, ctx.pc); | 5818 | gen_goto_tb(&ctx, 0, ctx.pc); |
| 5252 | break; | 5819 | break; |
| 5253 | - case BS_BRANCH: | ||
| 5254 | - default: | 5820 | + case BS_EXCP: |
| 5821 | + gen_op_interrupt_restart(); | ||
| 5255 | gen_op_reset_T0(); | 5822 | gen_op_reset_T0(); |
| 5256 | - /* Generate the return instruction. */ | ||
| 5257 | gen_op_exit_tb(); | 5823 | gen_op_exit_tb(); |
| 5258 | break; | 5824 | break; |
| 5825 | + case BS_BRANCH: | ||
| 5826 | + default: | ||
| 5827 | + break; | ||
| 5259 | } | 5828 | } |
| 5260 | } | 5829 | } |
| 5261 | done_generating: | 5830 | done_generating: |
| @@ -5307,21 +5876,33 @@ void fpu_dump_state(CPUState *env, FILE *f, | @@ -5307,21 +5876,33 @@ void fpu_dump_state(CPUState *env, FILE *f, | ||
| 5307 | int flags) | 5876 | int flags) |
| 5308 | { | 5877 | { |
| 5309 | int i; | 5878 | int i; |
| 5310 | - | ||
| 5311 | -# define printfpr(fp) do { \ | ||
| 5312 | - fpu_fprintf(f, "w:%08x d:%08lx%08lx fd:%g fs:%g\n", \ | ||
| 5313 | - (fp)->w[FP_ENDIAN_IDX], (fp)->w[0], (fp)->w[1], (fp)->fd, (fp)->fs[FP_ENDIAN_IDX]); \ | 5879 | + int is_fpu64 = !!(env->CP0_Status & (1 << CP0St_FR)); |
| 5880 | + | ||
| 5881 | +#define printfpr(fp) \ | ||
| 5882 | + do { \ | ||
| 5883 | + if (is_fpu64) \ | ||
| 5884 | + fpu_fprintf(f, "w:%08x d:%016lx fd:%13g fs:%13g psu: %13g\n", \ | ||
| 5885 | + (fp)->w[FP_ENDIAN_IDX], (fp)->d, (fp)->fd, \ | ||
| 5886 | + (fp)->fs[FP_ENDIAN_IDX], (fp)->fs[!FP_ENDIAN_IDX]); \ | ||
| 5887 | + else { \ | ||
| 5888 | + fpr_t tmp; \ | ||
| 5889 | + tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \ | ||
| 5890 | + tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \ | ||
| 5891 | + fpu_fprintf(f, "w:%08x d:%016lx fd:%13g fs:%13g psu:%13g\n", \ | ||
| 5892 | + tmp.w[FP_ENDIAN_IDX], tmp.d, tmp.fd, \ | ||
| 5893 | + tmp.fs[FP_ENDIAN_IDX], tmp.fs[!FP_ENDIAN_IDX]); \ | ||
| 5894 | + } \ | ||
| 5314 | } while(0) | 5895 | } while(0) |
| 5315 | 5896 | ||
| 5316 | - fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d\n", | ||
| 5317 | - env->fcr0, env->fcr31, | ||
| 5318 | - (env->CP0_Status & (1 << CP0St_FR)) != 0); | 5897 | + |
| 5898 | + fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%08x(0x%02x)\n", | ||
| 5899 | + env->fcr0, env->fcr31, is_fpu64, env->fp_status, get_float_exception_flags(&env->fp_status)); | ||
| 5319 | fpu_fprintf(f, "FT0: "); printfpr(&env->ft0); | 5900 | fpu_fprintf(f, "FT0: "); printfpr(&env->ft0); |
| 5320 | fpu_fprintf(f, "FT1: "); printfpr(&env->ft1); | 5901 | fpu_fprintf(f, "FT1: "); printfpr(&env->ft1); |
| 5321 | fpu_fprintf(f, "FT2: "); printfpr(&env->ft2); | 5902 | fpu_fprintf(f, "FT2: "); printfpr(&env->ft2); |
| 5322 | - for(i = 0; i < 32; i += 2) { | ||
| 5323 | - fpu_fprintf(f, "%s: ", fregnames[i]); | ||
| 5324 | - printfpr(FPR(env, i)); | 5903 | + for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { |
| 5904 | + fpu_fprintf(f, "%3s: ", fregnames[i]); | ||
| 5905 | + printfpr(&env->fpr[i]); | ||
| 5325 | } | 5906 | } |
| 5326 | 5907 | ||
| 5327 | #undef printfpr | 5908 | #undef printfpr |
target-mips/translate_init.c
| @@ -55,7 +55,7 @@ | @@ -55,7 +55,7 @@ | ||
| 55 | 55 | ||
| 56 | /* Define a implementation number of 1. | 56 | /* Define a implementation number of 1. |
| 57 | Define a major version 1, minor version 0. */ | 57 | Define a major version 1, minor version 0. */ |
| 58 | -#define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0) | 58 | +#define MIPS_FCR0 ((0 << FCR0_S) | (0x1 << FCR0_PRID) | (0x10 << FCR0_REV)) |
| 59 | 59 | ||
| 60 | 60 | ||
| 61 | struct mips_def_t { | 61 | struct mips_def_t { |
| @@ -69,6 +69,7 @@ struct mips_def_t { | @@ -69,6 +69,7 @@ struct mips_def_t { | ||
| 69 | int32_t CP0_Config7; | 69 | int32_t CP0_Config7; |
| 70 | int32_t SYNCI_Step; | 70 | int32_t SYNCI_Step; |
| 71 | int32_t CCRes; | 71 | int32_t CCRes; |
| 72 | + int32_t Status_rw_bitmask; | ||
| 72 | int32_t CP1_fcr0; | 73 | int32_t CP1_fcr0; |
| 73 | }; | 74 | }; |
| 74 | 75 | ||
| @@ -86,7 +87,7 @@ static mips_def_t mips_defs[] = | @@ -86,7 +87,7 @@ static mips_def_t mips_defs[] = | ||
| 86 | .CP0_Config3 = MIPS_CONFIG3, | 87 | .CP0_Config3 = MIPS_CONFIG3, |
| 87 | .SYNCI_Step = 32, | 88 | .SYNCI_Step = 32, |
| 88 | .CCRes = 2, | 89 | .CCRes = 2, |
| 89 | - .CP1_fcr0 = MIPS_FCR0, | 90 | + .Status_rw_bitmask = 0x3278FF17, |
| 90 | }, | 91 | }, |
| 91 | { | 92 | { |
| 92 | .name = "4KEcR1", | 93 | .name = "4KEcR1", |
| @@ -97,7 +98,6 @@ static mips_def_t mips_defs[] = | @@ -97,7 +98,6 @@ static mips_def_t mips_defs[] = | ||
| 97 | .CP0_Config3 = MIPS_CONFIG3, | 98 | .CP0_Config3 = MIPS_CONFIG3, |
| 98 | .SYNCI_Step = 32, | 99 | .SYNCI_Step = 32, |
| 99 | .CCRes = 2, | 100 | .CCRes = 2, |
| 100 | - .CP1_fcr0 = MIPS_FCR0, | ||
| 101 | }, | 101 | }, |
| 102 | { | 102 | { |
| 103 | .name = "4KEc", | 103 | .name = "4KEc", |
| @@ -108,7 +108,7 @@ static mips_def_t mips_defs[] = | @@ -108,7 +108,7 @@ static mips_def_t mips_defs[] = | ||
| 108 | .CP0_Config3 = MIPS_CONFIG3, | 108 | .CP0_Config3 = MIPS_CONFIG3, |
| 109 | .SYNCI_Step = 32, | 109 | .SYNCI_Step = 32, |
| 110 | .CCRes = 2, | 110 | .CCRes = 2, |
| 111 | - .CP1_fcr0 = MIPS_FCR0, | 111 | + .Status_rw_bitmask = 0x3278FF17, |
| 112 | }, | 112 | }, |
| 113 | { | 113 | { |
| 114 | .name = "24Kc", | 114 | .name = "24Kc", |
| @@ -119,7 +119,7 @@ static mips_def_t mips_defs[] = | @@ -119,7 +119,7 @@ static mips_def_t mips_defs[] = | ||
| 119 | .CP0_Config3 = MIPS_CONFIG3, | 119 | .CP0_Config3 = MIPS_CONFIG3, |
| 120 | .SYNCI_Step = 32, | 120 | .SYNCI_Step = 32, |
| 121 | .CCRes = 2, | 121 | .CCRes = 2, |
| 122 | - .CP1_fcr0 = MIPS_FCR0, | 122 | + .Status_rw_bitmask = 0x3278FF17, |
| 123 | }, | 123 | }, |
| 124 | { | 124 | { |
| 125 | .name = "24Kf", | 125 | .name = "24Kf", |
| @@ -130,7 +130,9 @@ static mips_def_t mips_defs[] = | @@ -130,7 +130,9 @@ static mips_def_t mips_defs[] = | ||
| 130 | .CP0_Config3 = MIPS_CONFIG3, | 130 | .CP0_Config3 = MIPS_CONFIG3, |
| 131 | .SYNCI_Step = 32, | 131 | .SYNCI_Step = 32, |
| 132 | .CCRes = 2, | 132 | .CCRes = 2, |
| 133 | - .CP1_fcr0 = MIPS_FCR0, | 133 | + .Status_rw_bitmask = 0x3678FF17, |
| 134 | + .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | | ||
| 135 | + (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID), | ||
| 134 | }, | 136 | }, |
| 135 | #else | 137 | #else |
| 136 | { | 138 | { |
| @@ -142,7 +144,10 @@ static mips_def_t mips_defs[] = | @@ -142,7 +144,10 @@ static mips_def_t mips_defs[] = | ||
| 142 | .CP0_Config3 = MIPS_CONFIG3, | 144 | .CP0_Config3 = MIPS_CONFIG3, |
| 143 | .SYNCI_Step = 16, | 145 | .SYNCI_Step = 16, |
| 144 | .CCRes = 2, | 146 | .CCRes = 2, |
| 145 | - .CP1_fcr0 = MIPS_FCR0, | 147 | + .Status_rw_bitmask = 0x3678FFFF, |
| 148 | + .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | | ||
| 149 | + (1 << FCR0_D) | (1 << FCR0_S) | | ||
| 150 | + (0x4 << FCR0_PRID) | (0x0 << FCR0_REV), | ||
| 146 | }, | 151 | }, |
| 147 | #endif | 152 | #endif |
| 148 | }; | 153 | }; |
| @@ -191,6 +196,7 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) | @@ -191,6 +196,7 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) | ||
| 191 | env->CP0_Config7 = def->CP0_Config7; | 196 | env->CP0_Config7 = def->CP0_Config7; |
| 192 | env->SYNCI_Step = def->SYNCI_Step; | 197 | env->SYNCI_Step = def->SYNCI_Step; |
| 193 | env->CCRes = def->CCRes; | 198 | env->CCRes = def->CCRes; |
| 199 | + env->Status_rw_bitmask = def->Status_rw_bitmask; | ||
| 194 | env->fcr0 = def->CP1_fcr0; | 200 | env->fcr0 = def->CP1_fcr0; |
| 195 | #if defined (MIPS_USES_R4K_TLB) | 201 | #if defined (MIPS_USES_R4K_TLB) |
| 196 | env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63); | 202 | env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63); |