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