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
gdbstub.c
| ... | ... | @@ -575,7 +575,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) |
| 575 | 575 | { |
| 576 | 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 | 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 | 637 | { |
| 638 | 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 | 641 | ptr += 4; |
| 642 | 642 | } |
| 643 | 643 | ... | ... |
target-mips/TODO
| ... | ... | @@ -10,11 +10,12 @@ General |
| 10 | 10 | when the Qemu FPU emulation is disabled. Also gdb inside the emulated |
| 11 | 11 | system does not work. Both problems are caused by insufficient |
| 12 | 12 | handling of self-modifying code. |
| 13 | +- Floating point exception emulation is incomplete. | |
| 13 | 14 | |
| 14 | 15 | MIPS64 |
| 15 | 16 | ------ |
| 16 | 17 | - No 64bit TLB support |
| 17 | -- no 64bit wide registers for FPU | |
| 18 | +- 64bit FPU not fully implemented | |
| 18 | 19 | - 64bit mul/div handling broken |
| 19 | 20 | |
| 20 | 21 | "Generic" 4Kc system emulation | ... | ... |
target-mips/cpu.h
| ... | ... | @@ -21,7 +21,7 @@ typedef union fpr_t fpr_t; |
| 21 | 21 | union fpr_t { |
| 22 | 22 | float64 fd; /* ieee double precision */ |
| 23 | 23 | float32 fs[2];/* ieee single precision */ |
| 24 | - uint64_t d; /* binary single fixed-point */ | |
| 24 | + uint64_t d; /* binary double fixed-point */ | |
| 25 | 25 | uint32_t w[2]; /* binary single fixed-point */ |
| 26 | 26 | }; |
| 27 | 27 | /* define FP_ENDIAN_IDX to access the same location |
| ... | ... | @@ -64,31 +64,35 @@ struct CPUMIPSState { |
| 64 | 64 | target_ulong HI, LO; |
| 65 | 65 | /* Floating point registers */ |
| 66 | 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 | 67 | #ifndef USE_HOST_FLOAT_REGS |
| 74 | 68 | fpr_t ft0; |
| 75 | 69 | fpr_t ft1; |
| 76 | 70 | fpr_t ft2; |
| 77 | 71 | #endif |
| 78 | 72 | float_status fp_status; |
| 79 | - /* fpu implementation/revision register */ | |
| 73 | + /* fpu implementation/revision register (fir) */ | |
| 80 | 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 | 84 | /* fcsr */ |
| 82 | 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 | 96 | #define FP_INEXACT 1 |
| 93 | 97 | #define FP_UNDERFLOW 2 |
| 94 | 98 | #define FP_OVERFLOW 4 |
| ... | ... | @@ -267,6 +271,7 @@ struct CPUMIPSState { |
| 267 | 271 | |
| 268 | 272 | int SYNCI_Step; /* Address step size for SYNCI */ |
| 269 | 273 | int CCRes; /* Cycle count resolution/divisor */ |
| 274 | + int Status_rw_bitmask; /* Read/write bits in CP0_Status */ | |
| 270 | 275 | |
| 271 | 276 | #if defined(CONFIG_USER_ONLY) |
| 272 | 277 | target_ulong tls_value; |
| ... | ... | @@ -330,10 +335,11 @@ enum { |
| 330 | 335 | EXCP_RI, |
| 331 | 336 | EXCP_OVERFLOW, |
| 332 | 337 | EXCP_TRAP, |
| 338 | + EXCP_FPE, | |
| 333 | 339 | EXCP_DDBS, |
| 334 | 340 | EXCP_DWATCH, |
| 335 | - EXCP_LAE, | |
| 336 | - EXCP_SAE, /* 24 */ | |
| 341 | + EXCP_LAE, /* 24 */ | |
| 342 | + EXCP_SAE, | |
| 337 | 343 | EXCP_LTLBL, |
| 338 | 344 | EXCP_TLBL, |
| 339 | 345 | EXCP_TLBS, | ... | ... |
target-mips/exec.h
| ... | ... | @@ -29,12 +29,18 @@ register target_ulong T2 asm(AREG3); |
| 29 | 29 | #define FST0 (env->ft0.fs[FP_ENDIAN_IDX]) |
| 30 | 30 | #define FST1 (env->ft1.fs[FP_ENDIAN_IDX]) |
| 31 | 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 | 35 | #define DT0 (env->ft0.d) |
| 33 | 36 | #define DT1 (env->ft1.d) |
| 34 | 37 | #define DT2 (env->ft2.d) |
| 35 | 38 | #define WT0 (env->ft0.w[FP_ENDIAN_IDX]) |
| 36 | 39 | #define WT1 (env->ft1.w[FP_ENDIAN_IDX]) |
| 37 | 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 | 44 | #endif |
| 39 | 45 | |
| 40 | 46 | #if defined (DEBUG_OP) | ... | ... |
target-mips/fop_template.c
| ... | ... | @@ -19,75 +19,103 @@ |
| 19 | 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 | 104 | #endif |
| 77 | 105 | |
| 78 | 106 | #if defined (FTN) |
| 79 | 107 | |
| 80 | -#define SET_RESET(treg, tregname) \ | |
| 108 | +#define SET_RESET(treg, tregname) \ | |
| 81 | 109 | void glue(op_set, tregname)(void) \ |
| 82 | - { \ | |
| 83 | - treg = PARAM1; \ | |
| 84 | - RETURN(); \ | |
| 85 | - } \ | |
| 110 | + { \ | |
| 111 | + treg = PARAM1; \ | |
| 112 | + RETURN(); \ | |
| 113 | + } \ | |
| 86 | 114 | void glue(op_reset, tregname)(void) \ |
| 87 | - { \ | |
| 88 | - treg = 0; \ | |
| 89 | - RETURN(); \ | |
| 90 | - } \ | |
| 115 | + { \ | |
| 116 | + treg = 0; \ | |
| 117 | + RETURN(); \ | |
| 118 | + } | |
| 91 | 119 | |
| 92 | 120 | SET_RESET(WT0, _WT0) |
| 93 | 121 | SET_RESET(WT1, _WT1) |
| ... | ... | @@ -95,6 +123,9 @@ SET_RESET(WT2, _WT2) |
| 95 | 123 | SET_RESET(DT0, _DT0) |
| 96 | 124 | SET_RESET(DT1, _DT1) |
| 97 | 125 | SET_RESET(DT2, _DT2) |
| 126 | +SET_RESET(WTH0, _WTH0) | |
| 127 | +SET_RESET(WTH1, _WTH1) | |
| 128 | +SET_RESET(WTH2, _WTH2) | |
| 98 | 129 | |
| 99 | 130 | #undef SET_RESET |
| 100 | 131 | #endif | ... | ... |
target-mips/helper.c
target-mips/op.c
| ... | ... | @@ -23,27 +23,27 @@ |
| 23 | 23 | #include "exec.h" |
| 24 | 24 | |
| 25 | 25 | #ifndef CALL_FROM_TB0 |
| 26 | -#define CALL_FROM_TB0(func) func(); | |
| 26 | +#define CALL_FROM_TB0(func) func() | |
| 27 | 27 | #endif |
| 28 | 28 | #ifndef CALL_FROM_TB1 |
| 29 | -#define CALL_FROM_TB1(func, arg0) func(arg0); | |
| 29 | +#define CALL_FROM_TB1(func, arg0) func(arg0) | |
| 30 | 30 | #endif |
| 31 | 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 | 33 | #endif |
| 34 | 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 | 36 | #endif |
| 37 | 37 | #ifndef CALL_FROM_TB2_CONST16 |
| 38 | 38 | #define CALL_FROM_TB2_CONST16(func, arg0, arg1) \ |
| 39 | -CALL_FROM_TB2(func, arg0, arg1); | |
| 39 | + CALL_FROM_TB2(func, arg0, arg1) | |
| 40 | 40 | #endif |
| 41 | 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 | 43 | #endif |
| 44 | 44 | #ifndef CALL_FROM_TB4 |
| 45 | 45 | #define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \ |
| 46 | - func(arg0, arg1, arg2, arg3); | |
| 46 | + func(arg0, arg1, arg2, arg3) | |
| 47 | 47 | #endif |
| 48 | 48 | |
| 49 | 49 | #define REG 1 |
| ... | ... | @@ -144,134 +144,102 @@ CALL_FROM_TB2(func, arg0, arg1); |
| 144 | 144 | #include "op_template.c" |
| 145 | 145 | #undef TN |
| 146 | 146 | |
| 147 | -#define SFREG 0 | |
| 148 | -#define DFREG 0 | |
| 147 | +#define FREG 0 | |
| 149 | 148 | #include "fop_template.c" |
| 150 | -#undef SFREG | |
| 151 | -#undef DFREG | |
| 152 | -#define SFREG 1 | |
| 149 | +#undef FREG | |
| 150 | +#define FREG 1 | |
| 153 | 151 | #include "fop_template.c" |
| 154 | -#undef SFREG | |
| 155 | -#define SFREG 2 | |
| 156 | -#define DFREG 2 | |
| 152 | +#undef FREG | |
| 153 | +#define FREG 2 | |
| 157 | 154 | #include "fop_template.c" |
| 158 | -#undef SFREG | |
| 159 | -#undef DFREG | |
| 160 | -#define SFREG 3 | |
| 155 | +#undef FREG | |
| 156 | +#define FREG 3 | |
| 161 | 157 | #include "fop_template.c" |
| 162 | -#undef SFREG | |
| 163 | -#define SFREG 4 | |
| 164 | -#define DFREG 4 | |
| 158 | +#undef FREG | |
| 159 | +#define FREG 4 | |
| 165 | 160 | #include "fop_template.c" |
| 166 | -#undef SFREG | |
| 167 | -#undef DFREG | |
| 168 | -#define SFREG 5 | |
| 161 | +#undef FREG | |
| 162 | +#define FREG 5 | |
| 169 | 163 | #include "fop_template.c" |
| 170 | -#undef SFREG | |
| 171 | -#define SFREG 6 | |
| 172 | -#define DFREG 6 | |
| 164 | +#undef FREG | |
| 165 | +#define FREG 6 | |
| 173 | 166 | #include "fop_template.c" |
| 174 | -#undef SFREG | |
| 175 | -#undef DFREG | |
| 176 | -#define SFREG 7 | |
| 167 | +#undef FREG | |
| 168 | +#define FREG 7 | |
| 177 | 169 | #include "fop_template.c" |
| 178 | -#undef SFREG | |
| 179 | -#define SFREG 8 | |
| 180 | -#define DFREG 8 | |
| 170 | +#undef FREG | |
| 171 | +#define FREG 8 | |
| 181 | 172 | #include "fop_template.c" |
| 182 | -#undef SFREG | |
| 183 | -#undef DFREG | |
| 184 | -#define SFREG 9 | |
| 173 | +#undef FREG | |
| 174 | +#define FREG 9 | |
| 185 | 175 | #include "fop_template.c" |
| 186 | -#undef SFREG | |
| 187 | -#define SFREG 10 | |
| 188 | -#define DFREG 10 | |
| 176 | +#undef FREG | |
| 177 | +#define FREG 10 | |
| 189 | 178 | #include "fop_template.c" |
| 190 | -#undef SFREG | |
| 191 | -#undef DFREG | |
| 192 | -#define SFREG 11 | |
| 179 | +#undef FREG | |
| 180 | +#define FREG 11 | |
| 193 | 181 | #include "fop_template.c" |
| 194 | -#undef SFREG | |
| 195 | -#define SFREG 12 | |
| 196 | -#define DFREG 12 | |
| 182 | +#undef FREG | |
| 183 | +#define FREG 12 | |
| 197 | 184 | #include "fop_template.c" |
| 198 | -#undef SFREG | |
| 199 | -#undef DFREG | |
| 200 | -#define SFREG 13 | |
| 185 | +#undef FREG | |
| 186 | +#define FREG 13 | |
| 201 | 187 | #include "fop_template.c" |
| 202 | -#undef SFREG | |
| 203 | -#define SFREG 14 | |
| 204 | -#define DFREG 14 | |
| 188 | +#undef FREG | |
| 189 | +#define FREG 14 | |
| 205 | 190 | #include "fop_template.c" |
| 206 | -#undef SFREG | |
| 207 | -#undef DFREG | |
| 208 | -#define SFREG 15 | |
| 191 | +#undef FREG | |
| 192 | +#define FREG 15 | |
| 209 | 193 | #include "fop_template.c" |
| 210 | -#undef SFREG | |
| 211 | -#define SFREG 16 | |
| 212 | -#define DFREG 16 | |
| 194 | +#undef FREG | |
| 195 | +#define FREG 16 | |
| 213 | 196 | #include "fop_template.c" |
| 214 | -#undef SFREG | |
| 215 | -#undef DFREG | |
| 216 | -#define SFREG 17 | |
| 197 | +#undef FREG | |
| 198 | +#define FREG 17 | |
| 217 | 199 | #include "fop_template.c" |
| 218 | -#undef SFREG | |
| 219 | -#define SFREG 18 | |
| 220 | -#define DFREG 18 | |
| 200 | +#undef FREG | |
| 201 | +#define FREG 18 | |
| 221 | 202 | #include "fop_template.c" |
| 222 | -#undef SFREG | |
| 223 | -#undef DFREG | |
| 224 | -#define SFREG 19 | |
| 203 | +#undef FREG | |
| 204 | +#define FREG 19 | |
| 225 | 205 | #include "fop_template.c" |
| 226 | -#undef SFREG | |
| 227 | -#define SFREG 20 | |
| 228 | -#define DFREG 20 | |
| 206 | +#undef FREG | |
| 207 | +#define FREG 20 | |
| 229 | 208 | #include "fop_template.c" |
| 230 | -#undef SFREG | |
| 231 | -#undef DFREG | |
| 232 | -#define SFREG 21 | |
| 209 | +#undef FREG | |
| 210 | +#define FREG 21 | |
| 233 | 211 | #include "fop_template.c" |
| 234 | -#undef SFREG | |
| 235 | -#define SFREG 22 | |
| 236 | -#define DFREG 22 | |
| 212 | +#undef FREG | |
| 213 | +#define FREG 22 | |
| 237 | 214 | #include "fop_template.c" |
| 238 | -#undef SFREG | |
| 239 | -#undef DFREG | |
| 240 | -#define SFREG 23 | |
| 215 | +#undef FREG | |
| 216 | +#define FREG 23 | |
| 241 | 217 | #include "fop_template.c" |
| 242 | -#undef SFREG | |
| 243 | -#define SFREG 24 | |
| 244 | -#define DFREG 24 | |
| 218 | +#undef FREG | |
| 219 | +#define FREG 24 | |
| 245 | 220 | #include "fop_template.c" |
| 246 | -#undef SFREG | |
| 247 | -#undef DFREG | |
| 248 | -#define SFREG 25 | |
| 221 | +#undef FREG | |
| 222 | +#define FREG 25 | |
| 249 | 223 | #include "fop_template.c" |
| 250 | -#undef SFREG | |
| 251 | -#define SFREG 26 | |
| 252 | -#define DFREG 26 | |
| 224 | +#undef FREG | |
| 225 | +#define FREG 26 | |
| 253 | 226 | #include "fop_template.c" |
| 254 | -#undef SFREG | |
| 255 | -#undef DFREG | |
| 256 | -#define SFREG 27 | |
| 227 | +#undef FREG | |
| 228 | +#define FREG 27 | |
| 257 | 229 | #include "fop_template.c" |
| 258 | -#undef SFREG | |
| 259 | -#define SFREG 28 | |
| 260 | -#define DFREG 28 | |
| 230 | +#undef FREG | |
| 231 | +#define FREG 28 | |
| 261 | 232 | #include "fop_template.c" |
| 262 | -#undef SFREG | |
| 263 | -#undef DFREG | |
| 264 | -#define SFREG 29 | |
| 233 | +#undef FREG | |
| 234 | +#define FREG 29 | |
| 265 | 235 | #include "fop_template.c" |
| 266 | -#undef SFREG | |
| 267 | -#define SFREG 30 | |
| 268 | -#define DFREG 30 | |
| 236 | +#undef FREG | |
| 237 | +#define FREG 30 | |
| 269 | 238 | #include "fop_template.c" |
| 270 | -#undef SFREG | |
| 271 | -#undef DFREG | |
| 272 | -#define SFREG 31 | |
| 239 | +#undef FREG | |
| 240 | +#define FREG 31 | |
| 273 | 241 | #include "fop_template.c" |
| 274 | -#undef SFREG | |
| 242 | +#undef FREG | |
| 275 | 243 | |
| 276 | 244 | #define FTN |
| 277 | 245 | #include "fop_template.c" |
| ... | ... | @@ -919,14 +887,14 @@ void op_movz (void) |
| 919 | 887 | void op_movf (void) |
| 920 | 888 | { |
| 921 | 889 | if (!(env->fcr31 & PARAM1)) |
| 922 | - env->gpr[PARAM2] = env->gpr[PARAM3]; | |
| 890 | + T0 = T1; | |
| 923 | 891 | RETURN(); |
| 924 | 892 | } |
| 925 | 893 | |
| 926 | 894 | void op_movt (void) |
| 927 | 895 | { |
| 928 | 896 | if (env->fcr31 & PARAM1) |
| 929 | - env->gpr[PARAM2] = env->gpr[PARAM3]; | |
| 897 | + T0 = T1; | |
| 930 | 898 | RETURN(); |
| 931 | 899 | } |
| 932 | 900 | |
| ... | ... | @@ -1354,17 +1322,18 @@ void op_mtc0_compare (void) |
| 1354 | 1322 | void op_mtc0_status (void) |
| 1355 | 1323 | { |
| 1356 | 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 | 1328 | no 64bit addressing implemented. */ |
| 1360 | - val = (int32_t)T0 & 0xF878FF17; | |
| 1329 | + val = (int32_t)T0 & mask; | |
| 1361 | 1330 | old = env->CP0_Status; |
| 1362 | 1331 | if (!(val & (1 << CP0St_EXL)) && |
| 1363 | 1332 | !(val & (1 << CP0St_ERL)) && |
| 1364 | 1333 | !(env->hflags & MIPS_HFLAG_DM) && |
| 1365 | 1334 | (val & (1 << CP0St_UM))) |
| 1366 | 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 | 1337 | if (loglevel & CPU_LOG_EXEC) |
| 1369 | 1338 | CALL_FROM_TB2(do_mtc0_status_debug, old, val); |
| 1370 | 1339 | CALL_FROM_TB1(cpu_mips_update_irq, env); |
| ... | ... | @@ -1643,6 +1612,7 @@ void op_dmtc0_errorepc (void) |
| 1643 | 1612 | } |
| 1644 | 1613 | #endif /* TARGET_MIPS64 */ |
| 1645 | 1614 | |
| 1615 | +/* CP1 functions */ | |
| 1646 | 1616 | #if 0 |
| 1647 | 1617 | # define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env) |
| 1648 | 1618 | #else |
| ... | ... | @@ -1666,20 +1636,6 @@ void op_cp1_enabled(void) |
| 1666 | 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 | 1639 | /* convert MIPS rounding mode in FCR31 to IEEE library */ |
| 1684 | 1640 | unsigned int ieee_rm[] = { |
| 1685 | 1641 | float_round_nearest_even, |
| ... | ... | @@ -1691,26 +1647,93 @@ unsigned int ieee_rm[] = { |
| 1691 | 1647 | #define RESTORE_ROUNDING_MODE \ |
| 1692 | 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 | 1737 | DEBUG_FPU_STATE(); |
| 1715 | 1738 | RETURN(); |
| 1716 | 1739 | } |
| ... | ... | @@ -1729,55 +1752,219 @@ void op_mtc1 (void) |
| 1729 | 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 | 1783 | /* Float support. |
| 1733 | 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 | 1788 | #define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void) |
| 1737 | 1789 | |
| 1738 | 1790 | FLOAT_OP(cvtd, s) |
| 1739 | 1791 | { |
| 1792 | + set_float_exception_flags(0, &env->fp_status); | |
| 1740 | 1793 | FDT2 = float32_to_float64(FST0, &env->fp_status); |
| 1794 | + update_fcr31(); | |
| 1741 | 1795 | DEBUG_FPU_STATE(); |
| 1742 | 1796 | RETURN(); |
| 1743 | 1797 | } |
| 1744 | 1798 | FLOAT_OP(cvtd, w) |
| 1745 | 1799 | { |
| 1800 | + set_float_exception_flags(0, &env->fp_status); | |
| 1746 | 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 | 1858 | DEBUG_FPU_STATE(); |
| 1748 | 1859 | RETURN(); |
| 1749 | 1860 | } |
| 1750 | 1861 | FLOAT_OP(cvts, d) |
| 1751 | 1862 | { |
| 1863 | + set_float_exception_flags(0, &env->fp_status); | |
| 1752 | 1864 | FST2 = float64_to_float32(FDT0, &env->fp_status); |
| 1865 | + update_fcr31(); | |
| 1753 | 1866 | DEBUG_FPU_STATE(); |
| 1754 | 1867 | RETURN(); |
| 1755 | 1868 | } |
| 1756 | 1869 | FLOAT_OP(cvts, w) |
| 1757 | 1870 | { |
| 1871 | + set_float_exception_flags(0, &env->fp_status); | |
| 1758 | 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 | 1898 | DEBUG_FPU_STATE(); |
| 1760 | 1899 | RETURN(); |
| 1761 | 1900 | } |
| 1762 | 1901 | FLOAT_OP(cvtw, s) |
| 1763 | 1902 | { |
| 1903 | + set_float_exception_flags(0, &env->fp_status); | |
| 1764 | 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 | 1908 | DEBUG_FPU_STATE(); |
| 1766 | 1909 | RETURN(); |
| 1767 | 1910 | } |
| 1768 | 1911 | FLOAT_OP(cvtw, d) |
| 1769 | 1912 | { |
| 1913 | + set_float_exception_flags(0, &env->fp_status); | |
| 1770 | 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 | 1943 | DEBUG_FPU_STATE(); |
| 1772 | 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 | 1963 | FLOAT_OP(roundw, d) |
| 1776 | 1964 | { |
| 1777 | 1965 | set_float_rounding_mode(float_round_nearest_even, &env->fp_status); |
| 1778 | 1966 | WT2 = float64_round_to_int(FDT0, &env->fp_status); |
| 1779 | 1967 | RESTORE_ROUNDING_MODE; |
| 1780 | - | |
| 1781 | 1968 | DEBUG_FPU_STATE(); |
| 1782 | 1969 | RETURN(); |
| 1783 | 1970 | } |
| ... | ... | @@ -1790,6 +1977,18 @@ FLOAT_OP(roundw, s) |
| 1790 | 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 | 1992 | FLOAT_OP(truncw, d) |
| 1794 | 1993 | { |
| 1795 | 1994 | WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status); |
| ... | ... | @@ -1803,12 +2002,27 @@ FLOAT_OP(truncw, s) |
| 1803 | 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 | 2021 | FLOAT_OP(ceilw, d) |
| 1807 | 2022 | { |
| 1808 | 2023 | set_float_rounding_mode(float_round_up, &env->fp_status); |
| 1809 | 2024 | WT2 = float64_round_to_int(FDT0, &env->fp_status); |
| 1810 | 2025 | RESTORE_ROUNDING_MODE; |
| 1811 | - | |
| 1812 | 2026 | DEBUG_FPU_STATE(); |
| 1813 | 2027 | RETURN(); |
| 1814 | 2028 | } |
| ... | ... | @@ -1821,12 +2035,27 @@ FLOAT_OP(ceilw, s) |
| 1821 | 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 | 2054 | FLOAT_OP(floorw, d) |
| 1825 | 2055 | { |
| 1826 | 2056 | set_float_rounding_mode(float_round_down, &env->fp_status); |
| 1827 | 2057 | WT2 = float64_round_to_int(FDT0, &env->fp_status); |
| 1828 | 2058 | RESTORE_ROUNDING_MODE; |
| 1829 | - | |
| 1830 | 2059 | DEBUG_FPU_STATE(); |
| 1831 | 2060 | RETURN(); |
| 1832 | 2061 | } |
| ... | ... | @@ -1839,16 +2068,121 @@ FLOAT_OP(floorw, s) |
| 1839 | 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 | 2164 | /* binary operations */ |
| 1843 | 2165 | #define FLOAT_BINOP(name) \ |
| 1844 | 2166 | FLOAT_OP(name, d) \ |
| 1845 | 2167 | { \ |
| 2168 | + set_float_exception_flags(0, &env->fp_status); \ | |
| 1846 | 2169 | FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \ |
| 2170 | + update_fcr31(); \ | |
| 1847 | 2171 | DEBUG_FPU_STATE(); \ |
| 1848 | 2172 | } \ |
| 1849 | 2173 | FLOAT_OP(name, s) \ |
| 1850 | 2174 | { \ |
| 2175 | + set_float_exception_flags(0, &env->fp_status); \ | |
| 1851 | 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 | 2186 | DEBUG_FPU_STATE(); \ |
| 1853 | 2187 | } |
| 1854 | 2188 | FLOAT_BINOP(add) |
| ... | ... | @@ -1857,6 +2191,32 @@ FLOAT_BINOP(mul) |
| 1857 | 2191 | FLOAT_BINOP(div) |
| 1858 | 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 | 2220 | /* unary operations, modifying fp status */ |
| 1861 | 2221 | #define FLOAT_UNOP(name) \ |
| 1862 | 2222 | FLOAT_OP(name, d) \ |
| ... | ... | @@ -1868,6 +2228,12 @@ FLOAT_OP(name, s) \ |
| 1868 | 2228 | { \ |
| 1869 | 2229 | FST2 = float32_ ## name(FST0, &env->fp_status); \ |
| 1870 | 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 | 2238 | FLOAT_UNOP(sqrt) |
| 1873 | 2239 | #undef FLOAT_UNOP |
| ... | ... | @@ -1883,6 +2249,12 @@ FLOAT_OP(name, s) \ |
| 1883 | 2249 | { \ |
| 1884 | 2250 | FST2 = float32_ ## name(FST0); \ |
| 1885 | 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 | 2259 | FLOAT_UNOP(abs) |
| 1888 | 2260 | FLOAT_UNOP(chs) |
| ... | ... | @@ -1900,6 +2272,35 @@ FLOAT_OP(mov, s) |
| 1900 | 2272 | DEBUG_FPU_STATE(); |
| 1901 | 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 | 2305 | #ifdef CONFIG_SOFTFLOAT |
| 1905 | 2306 | #define clear_invalid() do { \ |
| ... | ... | @@ -1913,96 +2314,200 @@ FLOAT_OP(mov, s) |
| 1913 | 2314 | |
| 1914 | 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 | 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 | 2326 | DEBUG_FPU_STATE(); \ |
| 1927 | 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 | 2335 | float_raise(float_flag_invalid, status); |
| 1934 | 2336 | return 1; |
| 1935 | - } | |
| 1936 | - else { | |
| 2337 | + } else if (float64_is_nan(a) || float64_is_nan(b)) { | |
| 2338 | + return 1; | |
| 2339 | + } else { | |
| 1937 | 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 | 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 | 2384 | float_raise(float_flag_invalid, status); |
| 1966 | 2385 | return 1; |
| 1967 | - } | |
| 1968 | - else { | |
| 2386 | + } else if (float32_is_nan(a) || float32_is_nan(b)) { | |
| 2387 | + return 1; | |
| 2388 | + } else { | |
| 1969 | 2389 | return 0; |
| 1970 | 2390 | } |
| 1971 | 2391 | } |
| 1972 | 2392 | |
| 1973 | 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 | 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 | 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 | 2488 | DEBUG_FPU_STATE(); |
| 2000 | 2489 | RETURN(); |
| 2001 | 2490 | } |
| 2002 | 2491 | |
| 2003 | 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 | 2511 | DEBUG_FPU_STATE(); |
| 2007 | 2512 | RETURN(); |
| 2008 | 2513 | } |
| ... | ... | @@ -2037,7 +2542,7 @@ void op_tlbr (void) |
| 2037 | 2542 | #if defined (CONFIG_USER_ONLY) |
| 2038 | 2543 | void op_tls_value (void) |
| 2039 | 2544 | { |
| 2040 | - T0 = env->tls_value; | |
| 2545 | + T0 = env->tls_value; | |
| 2041 | 2546 | } |
| 2042 | 2547 | #endif |
| 2043 | 2548 | |
| ... | ... | @@ -2180,6 +2685,17 @@ void op_save_pc (void) |
| 2180 | 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 | 2699 | void op_interrupt_restart (void) |
| 2184 | 2700 | { |
| 2185 | 2701 | if (!(env->CP0_Status & (1 << CP0St_EXL)) && | ... | ... |
target-mips/op_mem.c
| ... | ... | @@ -220,3 +220,35 @@ void glue(op_sdc1, MEMSUFFIX) (void) |
| 220 | 220 | glue(stq, MEMSUFFIX)(T0, DT0); |
| 221 | 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 | 333 | OPC_MFC1 = (0x00 << 21) | OPC_CP1, |
| 334 | 334 | OPC_DMFC1 = (0x01 << 21) | OPC_CP1, |
| 335 | 335 | OPC_CFC1 = (0x02 << 21) | OPC_CP1, |
| 336 | - OPC_MFHCI = (0x03 << 21) | OPC_CP1, | |
| 336 | + OPC_MFHC1 = (0x03 << 21) | OPC_CP1, | |
| 337 | 337 | OPC_MTC1 = (0x04 << 21) | OPC_CP1, |
| 338 | 338 | OPC_DMTC1 = (0x05 << 21) | OPC_CP1, |
| 339 | 339 | OPC_CTC1 = (0x06 << 21) | OPC_CP1, |
| 340 | - OPC_MTHCI = (0x07 << 21) | OPC_CP1, | |
| 340 | + OPC_MTHC1 = (0x07 << 21) | OPC_CP1, | |
| 341 | 341 | OPC_BC1 = (0x08 << 21) | OPC_CP1, /* bc */ |
| 342 | + OPC_BC1ANY2 = (0x09 << 21) | OPC_CP1, | |
| 343 | + OPC_BC1ANY4 = (0x0A << 21) | OPC_CP1, | |
| 342 | 344 | OPC_S_FMT = (0x10 << 21) | OPC_CP1, /* 16: fmt=single fp */ |
| 343 | 345 | OPC_D_FMT = (0x11 << 21) | OPC_CP1, /* 17: fmt=double fp */ |
| 344 | 346 | OPC_E_FMT = (0x12 << 21) | OPC_CP1, /* 18: fmt=extended fp */ |
| 345 | 347 | OPC_Q_FMT = (0x13 << 21) | OPC_CP1, /* 19: fmt=quad fp */ |
| 346 | 348 | OPC_W_FMT = (0x14 << 21) | OPC_CP1, /* 20: fmt=32bit fixed */ |
| 347 | 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 | 356 | enum { |
| 351 | 357 | OPC_BC1F = (0x00 << 16) | OPC_BC1, |
| 352 | 358 | OPC_BC1T = (0x01 << 16) | OPC_BC1, |
| ... | ... | @@ -354,8 +360,15 @@ enum { |
| 354 | 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 | 373 | #define MASK_CP2(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) |
| 361 | 374 | |
| ... | ... | @@ -404,20 +417,20 @@ const unsigned char *regnames[] = |
| 404 | 417 | "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", }; |
| 405 | 418 | |
| 406 | 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 | 436 | /* General purpose registers moves */ |
| ... | ... | @@ -434,58 +447,51 @@ static const char *fregnames[] = |
| 434 | 447 | "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", |
| 435 | 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 | 493 | #define FOP_CONDS(fmt) \ |
| 488 | -static GenOpFunc * cond_ ## fmt ## _table[16] = { \ | |
| 494 | +static GenOpFunc1 * cond_ ## fmt ## _table[16] = { \ | |
| 489 | 495 | gen_op_cmp_ ## fmt ## _f, \ |
| 490 | 496 | gen_op_cmp_ ## fmt ## _un, \ |
| 491 | 497 | gen_op_cmp_ ## fmt ## _eq, \ |
| ... | ... | @@ -503,18 +509,20 @@ static GenOpFunc * cond_ ## fmt ## _table[16] = { \ |
| 503 | 509 | gen_op_cmp_ ## fmt ## _le, \ |
| 504 | 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 | 517 | FOP_CONDS(d) |
| 512 | 518 | FOP_CONDS(s) |
| 519 | +FOP_CONDS(ps) | |
| 513 | 520 | |
| 514 | 521 | typedef struct DisasContext { |
| 515 | 522 | struct TranslationBlock *tb; |
| 516 | 523 | target_ulong pc, saved_pc; |
| 517 | 524 | uint32_t opcode; |
| 525 | + uint32_t fp_status, saved_fp_status; | |
| 518 | 526 | /* Routine used to access memory */ |
| 519 | 527 | int mem_idx; |
| 520 | 528 | uint32_t hflags, saved_hflags; |
| ... | ... | @@ -600,17 +608,31 @@ static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) |
| 600 | 608 | if (ctx->hflags != ctx->saved_hflags) { |
| 601 | 609 | gen_op_save_state(ctx->hflags); |
| 602 | 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 | 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 | 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 | 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 | 636 | static inline void generate_exception_err (DisasContext *ctx, int excp, int err) |
| 615 | 637 | { |
| 616 | 638 | #if defined MIPS_DEBUG_DISAS |
| ... | ... | @@ -677,6 +699,12 @@ OP_LD_TABLE(wc1); |
| 677 | 699 | OP_ST_TABLE(wc1); |
| 678 | 700 | OP_LD_TABLE(dc1); |
| 679 | 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 | 709 | /* Load and store */ |
| 682 | 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 | 1500 | if (ctx->hflags & MIPS_HFLAG_BMASK) { |
| 1473 | 1501 | if (loglevel & CPU_LOG_TB_IN_ASM) { |
| 1474 | 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 | 1504 | ctx->pc); |
| 1477 | 1505 | } |
| 1478 | 1506 | MIPS_INVAL("branch/jump in bdelay slot"); |
| ... | ... | @@ -1672,6 +1700,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, |
| 1672 | 1700 | MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget); |
| 1673 | 1701 | not_likely: |
| 1674 | 1702 | ctx->hflags |= MIPS_HFLAG_BC; |
| 1703 | + gen_op_set_bcond(); | |
| 1675 | 1704 | break; |
| 1676 | 1705 | case OPC_BLTZALL: |
| 1677 | 1706 | gen_op_ltz(); |
| ... | ... | @@ -1679,13 +1708,14 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, |
| 1679 | 1708 | MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget); |
| 1680 | 1709 | likely: |
| 1681 | 1710 | ctx->hflags |= MIPS_HFLAG_BL; |
| 1711 | + gen_op_set_bcond(); | |
| 1712 | + gen_op_save_bcond(); | |
| 1682 | 1713 | break; |
| 1683 | 1714 | default: |
| 1684 | 1715 | MIPS_INVAL("conditional branch/jump"); |
| 1685 | 1716 | generate_exception(ctx, EXCP_RI); |
| 1686 | 1717 | return; |
| 1687 | 1718 | } |
| 1688 | - gen_op_set_bcond(); | |
| 1689 | 1719 | } |
| 1690 | 1720 | MIPS_DEBUG("enter ds: link %d cond %02x target %08x", |
| 1691 | 1721 | blink, ctx->hflags, btarget); |
| ... | ... | @@ -4220,7 +4250,7 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) |
| 4220 | 4250 | |
| 4221 | 4251 | /* CP1 Branches (before delay slot) */ |
| 4222 | 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 | 4255 | target_ulong btarget; |
| 4226 | 4256 | |
| ... | ... | @@ -4228,31 +4258,49 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, |
| 4228 | 4258 | |
| 4229 | 4259 | switch (op) { |
| 4230 | 4260 | case OPC_BC1F: |
| 4231 | - gen_op_bc1f(); | |
| 4261 | + gen_op_bc1f(cc); | |
| 4232 | 4262 | MIPS_DEBUG("bc1f " TARGET_FMT_lx, btarget); |
| 4233 | 4263 | goto not_likely; |
| 4234 | 4264 | case OPC_BC1FL: |
| 4235 | - gen_op_bc1f(); | |
| 4265 | + gen_op_bc1f(cc); | |
| 4236 | 4266 | MIPS_DEBUG("bc1fl " TARGET_FMT_lx, btarget); |
| 4237 | 4267 | goto likely; |
| 4238 | 4268 | case OPC_BC1T: |
| 4239 | - gen_op_bc1t(); | |
| 4269 | + gen_op_bc1t(cc); | |
| 4240 | 4270 | MIPS_DEBUG("bc1t " TARGET_FMT_lx, btarget); |
| 4241 | - not_likely: | |
| 4242 | - ctx->hflags |= MIPS_HFLAG_BC; | |
| 4243 | - break; | |
| 4271 | + goto not_likely; | |
| 4244 | 4272 | case OPC_BC1TL: |
| 4245 | - gen_op_bc1t(); | |
| 4273 | + gen_op_bc1t(cc); | |
| 4246 | 4274 | MIPS_DEBUG("bc1tl " TARGET_FMT_lx, btarget); |
| 4247 | 4275 | likely: |
| 4248 | 4276 | ctx->hflags |= MIPS_HFLAG_BL; |
| 4277 | + gen_op_set_bcond(); | |
| 4278 | + gen_op_save_bcond(); | |
| 4249 | 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 | 4301 | generate_exception (ctx, EXCP_RI); |
| 4253 | 4302 | return; |
| 4254 | 4303 | } |
| 4255 | - gen_op_set_bcond(); | |
| 4256 | 4304 | |
| 4257 | 4305 | MIPS_DEBUG("enter ds: cond %02x target " TARGET_FMT_lx, |
| 4258 | 4306 | ctx->hflags, btarget); |
| ... | ... | @@ -4262,6 +4310,29 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, |
| 4262 | 4310 | } |
| 4263 | 4311 | |
| 4264 | 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 | 4336 | static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) |
| 4266 | 4337 | { |
| 4267 | 4338 | const char *opn = "unk"; |
| ... | ... | @@ -4280,30 +4351,43 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) |
| 4280 | 4351 | opn = "mtc1"; |
| 4281 | 4352 | break; |
| 4282 | 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 | 4354 | GEN_LOAD_IMM_TN(T1, fs); |
| 4289 | 4355 | gen_op_cfc1(); |
| 4290 | 4356 | GEN_STORE_TN_REG(rt, T0); |
| 4291 | 4357 | opn = "cfc1"; |
| 4292 | 4358 | break; |
| 4293 | 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 | 4360 | GEN_LOAD_IMM_TN(T1, fs); |
| 4300 | 4361 | GEN_LOAD_REG_TN(T0, rt); |
| 4301 | 4362 | gen_op_ctc1(); |
| 4302 | 4363 | opn = "ctc1"; |
| 4303 | 4364 | break; |
| 4304 | 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 | 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 | 4391 | default: |
| 4308 | 4392 | if (loglevel & CPU_LOG_TB_IN_ASM) { |
| 4309 | 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 | 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 | 4442 | const char *opn = "unk"; |
| 4341 | 4443 | const char *condnames[] = { |
| ... | ... | @@ -4360,6 +4462,187 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) |
| 4360 | 4462 | uint32_t func = ctx->opcode & 0x3f; |
| 4361 | 4463 | |
| 4362 | 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 | 4646 | case FOP(0, 17): |
| 4364 | 4647 | CHECK_FR(ctx, fs | ft | fd); |
| 4365 | 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 | 4707 | GEN_STORE_FTN_FREG(fd, DT2); |
| 4425 | 4708 | opn = "neg.d"; |
| 4426 | 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 | 4738 | case FOP(12, 17): |
| 4432 | 4739 | CHECK_FR(ctx, fs); |
| 4433 | 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 | 4763 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4457 | 4764 | opn = "floor.w.d"; |
| 4458 | 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 | 4771 | GEN_STORE_FTN_FREG(fd, DT2); |
| 4464 | - opn = "cvt.d.s"; | |
| 4772 | + opn = "movcf.d"; | |
| 4465 | 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 | 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 | 4789 | break; |
| 4473 | 4790 | case FOP(48, 17): |
| 4474 | 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 | 4806 | CHECK_FR(ctx, fs | ft); |
| 4490 | 4807 | GEN_LOAD_FREG_FTN(DT0, fs); |
| 4491 | 4808 | GEN_LOAD_FREG_FTN(DT1, ft); |
| 4492 | - gen_cmp_d(func-48); | |
| 4809 | + gen_cmp_d(func-48, cc); | |
| 4493 | 4810 | opn = condnames[func-48]; |
| 4494 | 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 | 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 | 4836 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4500 | - opn = "add.s"; | |
| 4501 | - binary = 1; | |
| 4837 | + opn = "cvt.s.w"; | |
| 4502 | 4838 | break; |
| 4503 | - case FOP(1, 16): | |
| 4839 | + case FOP(33, 20): | |
| 4840 | + CHECK_FR(ctx, fd); | |
| 4504 | 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 | 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 | 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 | 4880 | break; |
| 4511 | - case FOP(2, 16): | |
| 4881 | + case FOP(1, 22): | |
| 4882 | + CHECK_FR(ctx, fs | ft | fd); | |
| 4512 | 4883 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4884 | + GEN_LOAD_FREG_FTN(WTH0, fs); | |
| 4513 | 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 | 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 | 4891 | break; |
| 4519 | - case FOP(3, 16): | |
| 4892 | + case FOP(2, 22): | |
| 4893 | + CHECK_FR(ctx, fs | ft | fd); | |
| 4520 | 4894 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4895 | + GEN_LOAD_FREG_FTN(WTH0, fs); | |
| 4521 | 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 | 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 | 4902 | break; |
| 4527 | - case FOP(4, 16): | |
| 4903 | + case FOP(5, 22): | |
| 4904 | + CHECK_FR(ctx, fs | fd); | |
| 4528 | 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 | 4908 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4531 | - opn = "sqrt.s"; | |
| 4909 | + GEN_STORE_FTN_FREG(fd, WTH2); | |
| 4910 | + opn = "abs.ps"; | |
| 4532 | 4911 | break; |
| 4533 | - case FOP(5, 16): | |
| 4912 | + case FOP(6, 22): | |
| 4913 | + CHECK_FR(ctx, fs | fd); | |
| 4534 | 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 | 4917 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4537 | - opn = "abs.s"; | |
| 4918 | + GEN_STORE_FTN_FREG(fd, WTH2); | |
| 4919 | + opn = "mov.ps"; | |
| 4538 | 4920 | break; |
| 4539 | - case FOP(6, 16): | |
| 4921 | + case FOP(7, 22): | |
| 4922 | + CHECK_FR(ctx, fs | fd); | |
| 4540 | 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 | 4926 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4543 | - opn = "mov.s"; | |
| 4927 | + GEN_STORE_FTN_FREG(fd, WTH2); | |
| 4928 | + opn = "neg.ps"; | |
| 4544 | 4929 | break; |
| 4545 | - case FOP(7, 16): | |
| 4930 | + case FOP(17, 22): | |
| 4931 | + GEN_LOAD_REG_TN(T0, ft); | |
| 4546 | 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 | 4937 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4549 | - opn = "neg.s"; | |
| 4938 | + GEN_STORE_FTN_FREG(fd, WTH2); | |
| 4939 | + opn = "movcf.ps"; | |
| 4550 | 4940 | break; |
| 4551 | - case FOP(12, 16): | |
| 4941 | + case FOP(18, 22): | |
| 4942 | + GEN_LOAD_REG_TN(T0, ft); | |
| 4552 | 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 | 4948 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4555 | - opn = "round.w.s"; | |
| 4949 | + GEN_STORE_FTN_FREG(fd, WTH2); | |
| 4950 | + opn = "movz.ps"; | |
| 4556 | 4951 | break; |
| 4557 | - case FOP(13, 16): | |
| 4952 | + case FOP(19, 22): | |
| 4953 | + GEN_LOAD_REG_TN(T0, ft); | |
| 4558 | 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 | 4959 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4561 | - opn = "trunc.w.s"; | |
| 4960 | + GEN_STORE_FTN_FREG(fd, WTH2); | |
| 4961 | + opn = "movn.ps"; | |
| 4562 | 4962 | break; |
| 4563 | - case FOP(32, 17): | |
| 4963 | + case FOP(32, 22): | |
| 4564 | 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 | 4967 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4568 | - opn = "cvt.s.d"; | |
| 4968 | + opn = "cvt.s.pu"; | |
| 4569 | 4969 | break; |
| 4570 | - case FOP(32, 20): | |
| 4970 | + case FOP(36, 22): | |
| 4971 | + CHECK_FR(ctx, fs | fd); | |
| 4571 | 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 | 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 | 4978 | break; |
| 4576 | - case FOP(36, 16): | |
| 4979 | + case FOP(40, 22): | |
| 4980 | + CHECK_FR(ctx, fs); | |
| 4577 | 4981 | GEN_LOAD_FREG_FTN(WT0, fs); |
| 4578 | - gen_op_float_cvtw_s(); | |
| 4982 | + gen_op_float_cvts_pl(); | |
| 4579 | 4983 | GEN_STORE_FTN_FREG(fd, WT2); |
| 4580 | - opn = "cvt.w.s"; | |
| 4984 | + opn = "cvt.s.pl"; | |
| 4581 | 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 | 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 | 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 | 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 | 5040 | opn = condnames[func-48]; |
| 4609 | 5041 | break; |
| 4610 | - default: | |
| 5042 | + default: | |
| 4611 | 5043 | if (loglevel & CPU_LOG_TB_IN_ASM) { |
| 4612 | 5044 | fprintf(logfile, "Invalid FP arith function: %08x %03x %03x %03x\n", |
| 4613 | 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 | 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 | 5187 | /* ISA extensions (ASEs) */ |
| ... | ... | @@ -4641,23 +5189,12 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) |
| 4641 | 5189 | /* SmartMIPS extension to MIPS32 */ |
| 4642 | 5190 | |
| 4643 | 5191 | #ifdef TARGET_MIPS64 |
| 4644 | -/* Coprocessor 3 (FPU) */ | |
| 4645 | 5192 | |
| 4646 | 5193 | /* MDMX extension to MIPS64 */ |
| 4647 | 5194 | /* MIPS-3D extension to MIPS64 */ |
| 4648 | 5195 | |
| 4649 | 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 | 5198 | static void decode_opc (CPUState *env, DisasContext *ctx) |
| 4662 | 5199 | { |
| 4663 | 5200 | int32_t offset; |
| ... | ... | @@ -4673,9 +5210,14 @@ static void decode_opc (CPUState *env, DisasContext *ctx) |
| 4673 | 5210 | } |
| 4674 | 5211 | |
| 4675 | 5212 | if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) { |
| 5213 | + int l1; | |
| 4676 | 5214 | /* Handle blikely not taken case */ |
| 4677 | 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 | 5222 | op = MASK_OP_MAJOR(ctx->opcode); |
| 4681 | 5223 | rs = (ctx->opcode >> 21) & 0x1f; |
| ... | ... | @@ -5024,16 +5566,21 @@ static void decode_opc (CPUState *env, DisasContext *ctx) |
| 5024 | 5566 | case OPC_DMFC1: |
| 5025 | 5567 | case OPC_DMTC1: |
| 5026 | 5568 | #endif |
| 5569 | + case OPC_MFHC1: | |
| 5570 | + case OPC_MTHC1: | |
| 5027 | 5571 | gen_cp1(ctx, op1, rt, rd); |
| 5028 | 5572 | break; |
| 5029 | 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 | 5576 | return; |
| 5032 | 5577 | case OPC_S_FMT: |
| 5033 | 5578 | case OPC_D_FMT: |
| 5034 | 5579 | case OPC_W_FMT: |
| 5035 | 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 | 5584 | break; |
| 5038 | 5585 | default: |
| 5039 | 5586 | generate_exception (ctx, EXCP_RI); |
| ... | ... | @@ -5060,10 +5607,32 @@ static void decode_opc (CPUState *env, DisasContext *ctx) |
| 5060 | 5607 | gen_op_cp1_enabled(); |
| 5061 | 5608 | op1 = MASK_CP3(ctx->opcode); |
| 5062 | 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 | 5618 | case OPC_PREFX: |
| 5064 | 5619 | /* treat as noop */ |
| 5065 | 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 | 5636 | default: |
| 5068 | 5637 | generate_exception (ctx, EXCP_RI); |
| 5069 | 5638 | break; |
| ... | ... | @@ -5107,7 +5676,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) |
| 5107 | 5676 | ctx->hflags &= ~MIPS_HFLAG_BMASK; |
| 5108 | 5677 | ctx->bstate = BS_BRANCH; |
| 5109 | 5678 | save_cpu_state(ctx, 0); |
| 5110 | - switch (hflags & MIPS_HFLAG_BMASK) { | |
| 5679 | + switch (hflags) { | |
| 5111 | 5680 | case MIPS_HFLAG_B: |
| 5112 | 5681 | /* unconditional branch */ |
| 5113 | 5682 | MIPS_DEBUG("unconditional branch"); |
| ... | ... | @@ -5134,6 +5703,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx) |
| 5134 | 5703 | /* unconditional branch to register */ |
| 5135 | 5704 | MIPS_DEBUG("branch to register"); |
| 5136 | 5705 | gen_op_breg(); |
| 5706 | + gen_op_reset_T0(); | |
| 5707 | + gen_op_exit_tb(); | |
| 5137 | 5708 | break; |
| 5138 | 5709 | default: |
| 5139 | 5710 | MIPS_DEBUG("unknown branch"); |
| ... | ... | @@ -5166,16 +5737,18 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, |
| 5166 | 5737 | /* Restore delay slot state from the tb context. */ |
| 5167 | 5738 | ctx.hflags = tb->flags; |
| 5168 | 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 | 5742 | gen_op_restore_breg_target(); |
| 5171 | - } else if (ctx.hflags & MIPS_HFLAG_B) { | |
| 5743 | + break; | |
| 5744 | + case MIPS_HFLAG_B: | |
| 5172 | 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 | 5749 | ctx.btarget = env->btarget; |
| 5178 | 5750 | gen_op_restore_bcond(); |
| 5751 | + break; | |
| 5179 | 5752 | } |
| 5180 | 5753 | #if defined(CONFIG_USER_ONLY) |
| 5181 | 5754 | ctx.mem_idx = 0; |
| ... | ... | @@ -5237,12 +5810,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, |
| 5237 | 5810 | gen_op_debug(); |
| 5238 | 5811 | } else { |
| 5239 | 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 | 5813 | case BS_STOP: |
| 5247 | 5814 | gen_op_interrupt_restart(); |
| 5248 | 5815 | /* Fall through. */ |
| ... | ... | @@ -5250,12 +5817,14 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, |
| 5250 | 5817 | save_cpu_state(ctxp, 0); |
| 5251 | 5818 | gen_goto_tb(&ctx, 0, ctx.pc); |
| 5252 | 5819 | break; |
| 5253 | - case BS_BRANCH: | |
| 5254 | - default: | |
| 5820 | + case BS_EXCP: | |
| 5821 | + gen_op_interrupt_restart(); | |
| 5255 | 5822 | gen_op_reset_T0(); |
| 5256 | - /* Generate the return instruction. */ | |
| 5257 | 5823 | gen_op_exit_tb(); |
| 5258 | 5824 | break; |
| 5825 | + case BS_BRANCH: | |
| 5826 | + default: | |
| 5827 | + break; | |
| 5259 | 5828 | } |
| 5260 | 5829 | } |
| 5261 | 5830 | done_generating: |
| ... | ... | @@ -5307,21 +5876,33 @@ void fpu_dump_state(CPUState *env, FILE *f, |
| 5307 | 5876 | int flags) |
| 5308 | 5877 | { |
| 5309 | 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 | 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 | 5900 | fpu_fprintf(f, "FT0: "); printfpr(&env->ft0); |
| 5320 | 5901 | fpu_fprintf(f, "FT1: "); printfpr(&env->ft1); |
| 5321 | 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 | 5908 | #undef printfpr | ... | ... |
target-mips/translate_init.c
| ... | ... | @@ -55,7 +55,7 @@ |
| 55 | 55 | |
| 56 | 56 | /* Define a implementation number of 1. |
| 57 | 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 | 61 | struct mips_def_t { |
| ... | ... | @@ -69,6 +69,7 @@ struct mips_def_t { |
| 69 | 69 | int32_t CP0_Config7; |
| 70 | 70 | int32_t SYNCI_Step; |
| 71 | 71 | int32_t CCRes; |
| 72 | + int32_t Status_rw_bitmask; | |
| 72 | 73 | int32_t CP1_fcr0; |
| 73 | 74 | }; |
| 74 | 75 | |
| ... | ... | @@ -86,7 +87,7 @@ static mips_def_t mips_defs[] = |
| 86 | 87 | .CP0_Config3 = MIPS_CONFIG3, |
| 87 | 88 | .SYNCI_Step = 32, |
| 88 | 89 | .CCRes = 2, |
| 89 | - .CP1_fcr0 = MIPS_FCR0, | |
| 90 | + .Status_rw_bitmask = 0x3278FF17, | |
| 90 | 91 | }, |
| 91 | 92 | { |
| 92 | 93 | .name = "4KEcR1", |
| ... | ... | @@ -97,7 +98,6 @@ static mips_def_t mips_defs[] = |
| 97 | 98 | .CP0_Config3 = MIPS_CONFIG3, |
| 98 | 99 | .SYNCI_Step = 32, |
| 99 | 100 | .CCRes = 2, |
| 100 | - .CP1_fcr0 = MIPS_FCR0, | |
| 101 | 101 | }, |
| 102 | 102 | { |
| 103 | 103 | .name = "4KEc", |
| ... | ... | @@ -108,7 +108,7 @@ static mips_def_t mips_defs[] = |
| 108 | 108 | .CP0_Config3 = MIPS_CONFIG3, |
| 109 | 109 | .SYNCI_Step = 32, |
| 110 | 110 | .CCRes = 2, |
| 111 | - .CP1_fcr0 = MIPS_FCR0, | |
| 111 | + .Status_rw_bitmask = 0x3278FF17, | |
| 112 | 112 | }, |
| 113 | 113 | { |
| 114 | 114 | .name = "24Kc", |
| ... | ... | @@ -119,7 +119,7 @@ static mips_def_t mips_defs[] = |
| 119 | 119 | .CP0_Config3 = MIPS_CONFIG3, |
| 120 | 120 | .SYNCI_Step = 32, |
| 121 | 121 | .CCRes = 2, |
| 122 | - .CP1_fcr0 = MIPS_FCR0, | |
| 122 | + .Status_rw_bitmask = 0x3278FF17, | |
| 123 | 123 | }, |
| 124 | 124 | { |
| 125 | 125 | .name = "24Kf", |
| ... | ... | @@ -130,7 +130,9 @@ static mips_def_t mips_defs[] = |
| 130 | 130 | .CP0_Config3 = MIPS_CONFIG3, |
| 131 | 131 | .SYNCI_Step = 32, |
| 132 | 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 | 137 | #else |
| 136 | 138 | { |
| ... | ... | @@ -142,7 +144,10 @@ static mips_def_t mips_defs[] = |
| 142 | 144 | .CP0_Config3 = MIPS_CONFIG3, |
| 143 | 145 | .SYNCI_Step = 16, |
| 144 | 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 | 152 | #endif |
| 148 | 153 | }; |
| ... | ... | @@ -191,6 +196,7 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) |
| 191 | 196 | env->CP0_Config7 = def->CP0_Config7; |
| 192 | 197 | env->SYNCI_Step = def->SYNCI_Step; |
| 193 | 198 | env->CCRes = def->CCRes; |
| 199 | + env->Status_rw_bitmask = def->Status_rw_bitmask; | |
| 194 | 200 | env->fcr0 = def->CP1_fcr0; |
| 195 | 201 | #if defined (MIPS_USES_R4K_TLB) |
| 196 | 202 | env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63); | ... | ... |