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