Revision 6ea83fed
b/configure | ||
---|---|---|
819 | 819 |
echo "TARGET_ARCH=mips" >> $config_mak |
820 | 820 |
echo "#define TARGET_ARCH \"mips\"" >> $config_h |
821 | 821 |
echo "#define TARGET_MIPS 1" >> $config_h |
822 |
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak |
|
823 |
echo "#define CONFIG_SOFTFLOAT 1" >> $config_h |
|
822 | 824 |
elif test "$target_cpu" = "sh4" ; then |
823 | 825 |
echo "TARGET_ARCH=sh4" >> $config_mak |
824 | 826 |
echo "#define TARGET_ARCH \"sh4\"" >> $config_h |
b/target-mips/cpu.h | ||
---|---|---|
10 | 10 |
|
11 | 11 |
typedef union fpr_t fpr_t; |
12 | 12 |
union fpr_t { |
13 |
double d; |
|
14 |
float f; |
|
15 |
uint32_t u[2]; |
|
13 |
float64 fd; /* ieee double precision */ |
|
14 |
float32 fs[2];/* ieee single precision */ |
|
15 |
uint64_t d; /* binary single fixed-point */ |
|
16 |
uint32_t w[2]; /* binary single fixed-point */ |
|
16 | 17 |
}; |
18 |
/* define FP_ENDIAN_IDX to access the same location |
|
19 |
* in the fpr_t union regardless of the host endianess |
|
20 |
*/ |
|
21 |
#if defined(WORDS_BIGENDIAN) |
|
22 |
# define FP_ENDIAN_IDX 1 |
|
23 |
#else |
|
24 |
# define FP_ENDIAN_IDX 0 |
|
25 |
#endif |
|
17 | 26 |
|
18 | 27 |
#if defined(MIPS_USES_R4K_TLB) |
19 | 28 |
typedef struct tlb_t tlb_t; |
... | ... | |
44 | 53 |
#if defined(MIPS_USES_FPU) |
45 | 54 |
/* Floating point registers */ |
46 | 55 |
fpr_t fpr[16]; |
47 |
/* Floating point special purpose registers */ |
|
56 |
#define FPR(cpu, n) ((fpr_t*)&(cpu)->fpr[(n) / 2]) |
|
57 |
#define FPR_FD(cpu, n) (FPR(cpu, n)->fd) |
|
58 |
#define FPR_FS(cpu, n) (FPR(cpu, n)->fs[((n) & 1) ^ FP_ENDIAN_IDX]) |
|
59 |
#define FPR_D(cpu, n) (FPR(cpu, n)->d) |
|
60 |
#define FPR_W(cpu, n) (FPR(cpu, n)->w[((n) & 1) ^ FP_ENDIAN_IDX]) |
|
61 |
|
|
62 |
#ifndef USE_HOST_FLOAT_REGS |
|
63 |
fpr_t ft0; |
|
64 |
fpr_t ft1; |
|
65 |
fpr_t ft2; |
|
66 |
#endif |
|
67 |
float_status fp_status; |
|
68 |
/* fpu implementation/revision register */ |
|
48 | 69 |
uint32_t fcr0; |
49 |
uint32_t fcr25; |
|
50 |
uint32_t fcr26; |
|
51 |
uint32_t fcr28; |
|
52 |
uint32_t fcsr; |
|
70 |
/* fcsr */ |
|
71 |
uint32_t fcr31; |
|
72 |
#define SET_FP_COND(reg) do { (reg) |= (1<<23); } while(0) |
|
73 |
#define CLEAR_FP_COND(reg) do { (reg) &= ~(1<<23); } while(0) |
|
74 |
#define IS_FP_COND_SET(reg) (((reg) & (1<<23)) != 0) |
|
75 |
#define GET_FP_CAUSE(reg) (((reg) >> 12) & 0x3f) |
|
76 |
#define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f) |
|
77 |
#define GET_FP_FLAGS(reg) (((reg) >> 2) & 0x1f) |
|
78 |
#define SET_FP_CAUSE(reg,v) do { (reg) = ((reg) & ~(0x3f << 12)) | ((v) << 12); } while(0) |
|
79 |
#define SET_FP_ENABLE(reg,v) do { (reg) = ((reg) & ~(0x1f << 7)) | ((v) << 7); } while(0) |
|
80 |
#define SET_FP_FLAGS(reg,v) do { (reg) = ((reg) & ~(0x1f << 2)) | ((v) << 2); } while(0) |
|
81 |
#define FP_INEXACT 1 |
|
82 |
#define FP_UNDERFLOW 2 |
|
83 |
#define FP_OVERFLOW 4 |
|
84 |
#define FP_DIV0 8 |
|
85 |
#define FP_INVALID 16 |
|
86 |
#define FP_UNIMPLEMENTED 32 |
|
87 |
|
|
53 | 88 |
#endif |
54 | 89 |
#if defined(MIPS_USES_R4K_TLB) |
55 | 90 |
tlb_t tlb[16]; |
... | ... | |
71 | 106 |
#define CP0St_CU1 29 |
72 | 107 |
#define CP0St_CU0 28 |
73 | 108 |
#define CP0St_RP 27 |
109 |
#define CP0St_FR 26 |
|
74 | 110 |
#define CP0St_RE 25 |
75 | 111 |
#define CP0St_BEV 22 |
76 | 112 |
#define CP0St_TS 21 |
... | ... | |
138 | 174 |
uint32_t CP0_ErrorEPC; |
139 | 175 |
uint32_t CP0_DESAVE; |
140 | 176 |
/* Qemu */ |
141 |
#if defined (USE_HOST_FLOAT_REGS) && defined(MIPS_USES_FPU) |
|
142 |
double ft0, ft1, ft2; |
|
143 |
#endif |
|
144 | 177 |
struct QEMUTimer *timer; /* Internal timer */ |
145 | 178 |
int interrupt_request; |
146 | 179 |
jmp_buf jmp_env; |
b/target-mips/exec.h | ||
---|---|---|
21 | 21 |
register host_uint_t T2 asm(AREG3); |
22 | 22 |
|
23 | 23 |
#if defined (USE_HOST_FLOAT_REGS) |
24 |
register double FT0 asm(FREG0); |
|
25 |
register double FT1 asm(FREG1); |
|
26 |
register double FT2 asm(FREG2); |
|
24 |
#error "implement me." |
|
27 | 25 |
#else |
28 |
#define FT0 (env->ft0.d) |
|
29 |
#define FT1 (env->ft1.d) |
|
30 |
#define FT2 (env->ft2.d) |
|
26 |
#define FDT0 (env->ft0.fd) |
|
27 |
#define FDT1 (env->ft1.fd) |
|
28 |
#define FDT2 (env->ft2.fd) |
|
29 |
#define FST0 (env->ft0.fs[FP_ENDIAN_IDX]) |
|
30 |
#define FST1 (env->ft1.fs[FP_ENDIAN_IDX]) |
|
31 |
#define FST2 (env->ft2.fs[FP_ENDIAN_IDX]) |
|
32 |
#define DT0 (env->ft0.d) |
|
33 |
#define DT1 (env->ft1.d) |
|
34 |
#define DT2 (env->ft2.d) |
|
35 |
#define WT0 (env->ft0.w[FP_ENDIAN_IDX]) |
|
36 |
#define WT1 (env->ft1.w[FP_ENDIAN_IDX]) |
|
37 |
#define WT2 (env->ft2.w[FP_ENDIAN_IDX]) |
|
31 | 38 |
#endif |
32 | 39 |
|
33 | 40 |
#if defined (DEBUG_OP) |
... | ... | |
65 | 72 |
void do_tlbwr (void); |
66 | 73 |
void do_tlbp (void); |
67 | 74 |
void do_tlbr (void); |
75 |
#ifdef MIPS_USES_FPU |
|
76 |
void dump_fpu(CPUState *env); |
|
77 |
void fpu_dump_state(CPUState *env, FILE *f, |
|
78 |
int (*fpu_fprintf)(FILE *f, const char *fmt, ...), |
|
79 |
int flags); |
|
80 |
#endif |
|
81 |
void dump_sc (void); |
|
68 | 82 |
void do_lwl_raw (uint32_t); |
69 | 83 |
void do_lwr_raw (uint32_t); |
70 | 84 |
uint32_t do_swl_raw (uint32_t); |
b/target-mips/fop_template.c | ||
---|---|---|
1 |
/* |
|
2 |
* MIPS emulation micro-operations templates for floating point reg |
|
3 |
* load & store for qemu. |
|
4 |
* |
|
5 |
* Copyright (c) 2006 Marius Groeger |
|
6 |
* |
|
7 |
* This library is free software; you can redistribute it and/or |
|
8 |
* modify it under the terms of the GNU Lesser General Public |
|
9 |
* License as published by the Free Software Foundation; either |
|
10 |
* version 2 of the License, or (at your option) any later version. |
|
11 |
* |
|
12 |
* This library is distributed in the hope that it will be useful, |
|
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
15 |
* Lesser General Public License for more details. |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU Lesser General Public |
|
18 |
* License along with this library; if not, write to the Free Software |
|
19 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
20 |
*/ |
|
21 |
|
|
22 |
#if defined(SFREG) |
|
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(); \ |
|
29 |
} |
|
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(); \ |
|
36 |
} |
|
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) |
|
42 |
|
|
43 |
OP_WLOAD_FREG(WT1, WT1_fpr, SFREG) |
|
44 |
OP_WSTORE_FREG(WT1, WT1_fpr, SFREG) |
|
45 |
|
|
46 |
OP_WLOAD_FREG(WT2, WT2_fpr, SFREG) |
|
47 |
OP_WSTORE_FREG(WT2, WT2_fpr, SFREG) |
|
48 |
|
|
49 |
#endif |
|
50 |
|
|
51 |
#if defined(DFREG) |
|
52 |
|
|
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(); \ |
|
58 |
} |
|
59 |
|
|
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(); \ |
|
65 |
} |
|
66 |
|
|
67 |
OP_DLOAD_FREG(DT0, DT0_fpr, DFREG) |
|
68 |
OP_DSTORE_FREG(DT0, DT0_fpr, DFREG) |
|
69 |
|
|
70 |
OP_DLOAD_FREG(DT1, DT1_fpr, DFREG) |
|
71 |
OP_DSTORE_FREG(DT1, DT1_fpr, DFREG) |
|
72 |
|
|
73 |
OP_DLOAD_FREG(DT2, DT2_fpr, DFREG) |
|
74 |
OP_DSTORE_FREG(DT2, DT2_fpr, DFREG) |
|
75 |
|
|
76 |
#endif |
|
77 |
|
|
78 |
#if defined (FTN) |
|
79 |
|
|
80 |
#define SET_RESET(treg, tregname) \ |
|
81 |
void glue(op_set, tregname)(void) \ |
|
82 |
{ \ |
|
83 |
treg = PARAM1; \ |
|
84 |
RETURN(); \ |
|
85 |
} \ |
|
86 |
void glue(op_reset, tregname)(void) \ |
|
87 |
{ \ |
|
88 |
treg = 0; \ |
|
89 |
RETURN(); \ |
|
90 |
} \ |
|
91 |
|
|
92 |
SET_RESET(WT0, _WT0) |
|
93 |
SET_RESET(WT1, _WT1) |
|
94 |
SET_RESET(WT2, _WT2) |
|
95 |
SET_RESET(DT0, _DT0) |
|
96 |
SET_RESET(DT1, _DT1) |
|
97 |
SET_RESET(DT2, _DT2) |
|
98 |
|
|
99 |
#endif |
b/target-mips/mips-defs.h | ||
---|---|---|
24 | 24 |
/* Uses MIPS R4Kc TLB model */ |
25 | 25 |
#define MIPS_USES_R4K_TLB |
26 | 26 |
#define MIPS_TLB_NB 16 |
27 |
/* basic FPU register support */ |
|
28 |
#define MIPS_USES_FPU 1 |
|
29 |
/* Define a implementation number of 1. |
|
30 |
* Define a major version 1, minor version 0. |
|
31 |
*/ |
|
32 |
#define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0) |
|
27 | 33 |
/* Have config1, runs in big-endian mode, uses TLB */ |
28 | 34 |
#define MIPS_CONFIG0 \ |
29 | 35 |
((1 << CP0C0_M) | (0x000 << CP0C0_K23) | (0x000 << CP0C0_KU) | \ |
... | ... | |
31 | 37 |
/* 16 TLBs, 64 sets Icache, 16 bytes Icache line, 2-way Icache, |
32 | 38 |
* 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache, |
33 | 39 |
* no performance counters, watch registers present, no code compression, |
34 |
* EJTAG present, no FPU
|
|
40 |
* EJTAG present, FPU enable bit depending on MIPS_USES_FPU
|
|
35 | 41 |
*/ |
36 | 42 |
#define MIPS_CONFIG1 \ |
37 | 43 |
((15 << CP0C1_MMU) | \ |
38 | 44 |
(0x000 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x01 << CP0C1_IA) | \ |
39 | 45 |
(0x000 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x01 << CP0C1_DA) | \ |
40 | 46 |
(0 << CP0C1_PC) | (1 << CP0C1_WR) | (0 << CP0C1_CA) | \ |
41 |
(1 << CP0C1_EP) | (0 << CP0C1_FP))
|
|
47 |
(1 << CP0C1_EP) | (MIPS_USES_FPU << CP0C1_FP))
|
|
42 | 48 |
#elif defined (MIPS_CPU == MIPS_R4Kp) |
43 | 49 |
/* 32 bits target */ |
44 | 50 |
#define TARGET_LONG_BITS 32 |
... | ... | |
52 | 58 |
#error "MIPS CPU not defined" |
53 | 59 |
/* Remainder for other flags */ |
54 | 60 |
//#define TARGET_MIPS64 |
55 |
//define MIPS_USES_FPU |
|
61 |
//#define MIPS_USES_FPU
|
|
56 | 62 |
#endif |
57 | 63 |
|
58 | 64 |
#endif /* !defined (__QEMU_MIPS_DEFS_H__) */ |
b/target-mips/op.c | ||
---|---|---|
2 | 2 |
* MIPS emulation micro-operations for qemu. |
3 | 3 |
* |
4 | 4 |
* Copyright (c) 2004-2005 Jocelyn Mayer |
5 |
* Copyright (c) 2006 Marius Groeger (FPU operations) |
|
5 | 6 |
* |
6 | 7 |
* This library is free software; you can redistribute it and/or |
7 | 8 |
* modify it under the terms of the GNU Lesser General Public |
... | ... | |
149 | 150 |
#include "op_template.c" |
150 | 151 |
#undef TN |
151 | 152 |
|
153 |
#ifdef MIPS_USES_FPU |
|
154 |
|
|
155 |
#define SFREG 0 |
|
156 |
#define DFREG 0 |
|
157 |
#include "fop_template.c" |
|
158 |
#undef SFREG |
|
159 |
#undef DFREG |
|
160 |
#define SFREG 1 |
|
161 |
#include "fop_template.c" |
|
162 |
#undef SFREG |
|
163 |
#define SFREG 2 |
|
164 |
#define DFREG 2 |
|
165 |
#include "fop_template.c" |
|
166 |
#undef SFREG |
|
167 |
#undef DFREG |
|
168 |
#define SFREG 3 |
|
169 |
#include "fop_template.c" |
|
170 |
#undef SFREG |
|
171 |
#define SFREG 4 |
|
172 |
#define DFREG 4 |
|
173 |
#include "fop_template.c" |
|
174 |
#undef SFREG |
|
175 |
#undef DFREG |
|
176 |
#define SFREG 5 |
|
177 |
#include "fop_template.c" |
|
178 |
#undef SFREG |
|
179 |
#define SFREG 6 |
|
180 |
#define DFREG 6 |
|
181 |
#include "fop_template.c" |
|
182 |
#undef SFREG |
|
183 |
#undef DFREG |
|
184 |
#define SFREG 7 |
|
185 |
#include "fop_template.c" |
|
186 |
#undef SFREG |
|
187 |
#define SFREG 8 |
|
188 |
#define DFREG 8 |
|
189 |
#include "fop_template.c" |
|
190 |
#undef SFREG |
|
191 |
#undef DFREG |
|
192 |
#define SFREG 9 |
|
193 |
#include "fop_template.c" |
|
194 |
#undef SFREG |
|
195 |
#define SFREG 10 |
|
196 |
#define DFREG 10 |
|
197 |
#include "fop_template.c" |
|
198 |
#undef SFREG |
|
199 |
#undef DFREG |
|
200 |
#define SFREG 11 |
|
201 |
#include "fop_template.c" |
|
202 |
#undef SFREG |
|
203 |
#define SFREG 12 |
|
204 |
#define DFREG 12 |
|
205 |
#include "fop_template.c" |
|
206 |
#undef SFREG |
|
207 |
#undef DFREG |
|
208 |
#define SFREG 13 |
|
209 |
#include "fop_template.c" |
|
210 |
#undef SFREG |
|
211 |
#define SFREG 14 |
|
212 |
#define DFREG 14 |
|
213 |
#include "fop_template.c" |
|
214 |
#undef SFREG |
|
215 |
#undef DFREG |
|
216 |
#define SFREG 15 |
|
217 |
#include "fop_template.c" |
|
218 |
#undef SFREG |
|
219 |
#define SFREG 16 |
|
220 |
#define DFREG 16 |
|
221 |
#include "fop_template.c" |
|
222 |
#undef SFREG |
|
223 |
#undef DFREG |
|
224 |
#define SFREG 17 |
|
225 |
#include "fop_template.c" |
|
226 |
#undef SFREG |
|
227 |
#define SFREG 18 |
|
228 |
#define DFREG 18 |
|
229 |
#include "fop_template.c" |
|
230 |
#undef SFREG |
|
231 |
#undef DFREG |
|
232 |
#define SFREG 19 |
|
233 |
#include "fop_template.c" |
|
234 |
#undef SFREG |
|
235 |
#define SFREG 20 |
|
236 |
#define DFREG 20 |
|
237 |
#include "fop_template.c" |
|
238 |
#undef SFREG |
|
239 |
#undef DFREG |
|
240 |
#define SFREG 21 |
|
241 |
#include "fop_template.c" |
|
242 |
#undef SFREG |
|
243 |
#define SFREG 22 |
|
244 |
#define DFREG 22 |
|
245 |
#include "fop_template.c" |
|
246 |
#undef SFREG |
|
247 |
#undef DFREG |
|
248 |
#define SFREG 23 |
|
249 |
#include "fop_template.c" |
|
250 |
#undef SFREG |
|
251 |
#define SFREG 24 |
|
252 |
#define DFREG 24 |
|
253 |
#include "fop_template.c" |
|
254 |
#undef SFREG |
|
255 |
#undef DFREG |
|
256 |
#define SFREG 25 |
|
257 |
#include "fop_template.c" |
|
258 |
#undef SFREG |
|
259 |
#define SFREG 26 |
|
260 |
#define DFREG 26 |
|
261 |
#include "fop_template.c" |
|
262 |
#undef SFREG |
|
263 |
#undef DFREG |
|
264 |
#define SFREG 27 |
|
265 |
#include "fop_template.c" |
|
266 |
#undef SFREG |
|
267 |
#define SFREG 28 |
|
268 |
#define DFREG 28 |
|
269 |
#include "fop_template.c" |
|
270 |
#undef SFREG |
|
271 |
#undef DFREG |
|
272 |
#define SFREG 29 |
|
273 |
#include "fop_template.c" |
|
274 |
#undef SFREG |
|
275 |
#define SFREG 30 |
|
276 |
#define DFREG 30 |
|
277 |
#include "fop_template.c" |
|
278 |
#undef SFREG |
|
279 |
#undef DFREG |
|
280 |
#define SFREG 31 |
|
281 |
#include "fop_template.c" |
|
282 |
#undef SFREG |
|
283 |
|
|
284 |
#define FTN |
|
285 |
#include "fop_template.c" |
|
286 |
#undef FTN |
|
287 |
|
|
288 |
#endif |
|
289 |
|
|
152 | 290 |
void op_dup_T0 (void) |
153 | 291 |
{ |
154 | 292 |
T2 = T0; |
... | ... | |
562 | 700 |
RETURN(); |
563 | 701 |
} |
564 | 702 |
|
703 |
#ifdef MIPS_USES_FPU |
|
704 |
|
|
705 |
#if 0 |
|
706 |
# define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env) |
|
707 |
#else |
|
708 |
# define DEBUG_FPU_STATE() do { } while(0) |
|
709 |
#endif |
|
710 |
|
|
711 |
void op_cp1_enabled(void) |
|
712 |
{ |
|
713 |
if (!(env->CP0_Status & (1 << CP0St_CU1))) { |
|
714 |
CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 1); |
|
715 |
} |
|
716 |
RETURN(); |
|
717 |
} |
|
718 |
|
|
719 |
/* CP1 functions */ |
|
720 |
void op_cfc1 (void) |
|
721 |
{ |
|
722 |
if (T1 == 0) { |
|
723 |
T0 = env->fcr0; |
|
724 |
} |
|
725 |
else { |
|
726 |
/* fetch fcr31, masking unused bits */ |
|
727 |
T0 = env->fcr31 & 0x0183FFFF; |
|
728 |
} |
|
729 |
DEBUG_FPU_STATE(); |
|
730 |
RETURN(); |
|
731 |
} |
|
732 |
|
|
733 |
/* convert MIPS rounding mode in FCR31 to IEEE library */ |
|
734 |
unsigned int ieee_rm[] = { |
|
735 |
float_round_nearest_even, |
|
736 |
float_round_to_zero, |
|
737 |
float_round_up, |
|
738 |
float_round_down |
|
739 |
}; |
|
740 |
|
|
741 |
#define RESTORE_ROUNDING_MODE \ |
|
742 |
set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status) |
|
743 |
|
|
744 |
void op_ctc1 (void) |
|
745 |
{ |
|
746 |
if (T1 == 0) { |
|
747 |
/* XXX should this throw an exception? |
|
748 |
* don't write to FCR0. |
|
749 |
* env->fcr0 = T0; |
|
750 |
*/ |
|
751 |
} |
|
752 |
else { |
|
753 |
/* store new fcr31, masking unused bits */ |
|
754 |
env->fcr31 = T0 & 0x0183FFFF; |
|
755 |
|
|
756 |
/* set rounding mode */ |
|
757 |
RESTORE_ROUNDING_MODE; |
|
758 |
|
|
759 |
#ifndef CONFIG_SOFTFLOAT |
|
760 |
/* no floating point exception for native float */ |
|
761 |
SET_FP_ENABLE(env->fcr31, 0); |
|
762 |
#endif |
|
763 |
} |
|
764 |
DEBUG_FPU_STATE(); |
|
765 |
RETURN(); |
|
766 |
} |
|
767 |
|
|
768 |
void op_mfc1 (void) |
|
769 |
{ |
|
770 |
T0 = WT0; |
|
771 |
DEBUG_FPU_STATE(); |
|
772 |
RETURN(); |
|
773 |
} |
|
774 |
|
|
775 |
void op_mtc1 (void) |
|
776 |
{ |
|
777 |
WT0 = T0; |
|
778 |
DEBUG_FPU_STATE(); |
|
779 |
RETURN(); |
|
780 |
} |
|
781 |
|
|
782 |
/* Float support. |
|
783 |
Single precition routines have a "s" suffix, double precision a |
|
784 |
"d" suffix. */ |
|
785 |
|
|
786 |
#define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void) |
|
787 |
|
|
788 |
FLOAT_OP(cvtd, w) |
|
789 |
{ |
|
790 |
FDT2 = int32_to_float64(WT0, &env->fp_status); |
|
791 |
DEBUG_FPU_STATE(); |
|
792 |
RETURN(); |
|
793 |
} |
|
794 |
FLOAT_OP(cvts, w) |
|
795 |
{ |
|
796 |
FST2 = int32_to_float32(WT0, &env->fp_status); |
|
797 |
DEBUG_FPU_STATE(); |
|
798 |
RETURN(); |
|
799 |
} |
|
800 |
FLOAT_OP(cvtw, s) |
|
801 |
{ |
|
802 |
WT2 = float32_to_int32(FST0, &env->fp_status); |
|
803 |
DEBUG_FPU_STATE(); |
|
804 |
RETURN(); |
|
805 |
} |
|
806 |
FLOAT_OP(cvtw, d) |
|
807 |
{ |
|
808 |
WT2 = float64_to_int32(FDT0, &env->fp_status); |
|
809 |
DEBUG_FPU_STATE(); |
|
810 |
RETURN(); |
|
811 |
} |
|
812 |
|
|
813 |
FLOAT_OP(roundw, d) |
|
814 |
{ |
|
815 |
set_float_rounding_mode(float_round_nearest_even, &env->fp_status); |
|
816 |
WT2 = float64_round_to_int(FDT0, &env->fp_status); |
|
817 |
RESTORE_ROUNDING_MODE; |
|
818 |
|
|
819 |
DEBUG_FPU_STATE(); |
|
820 |
RETURN(); |
|
821 |
} |
|
822 |
FLOAT_OP(roundw, s) |
|
823 |
{ |
|
824 |
set_float_rounding_mode(float_round_nearest_even, &env->fp_status); |
|
825 |
WT2 = float32_round_to_int(FST0, &env->fp_status); |
|
826 |
RESTORE_ROUNDING_MODE; |
|
827 |
DEBUG_FPU_STATE(); |
|
828 |
RETURN(); |
|
829 |
} |
|
830 |
|
|
831 |
FLOAT_OP(truncw, d) |
|
832 |
{ |
|
833 |
WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status); |
|
834 |
DEBUG_FPU_STATE(); |
|
835 |
RETURN(); |
|
836 |
} |
|
837 |
FLOAT_OP(truncw, s) |
|
838 |
{ |
|
839 |
WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status); |
|
840 |
DEBUG_FPU_STATE(); |
|
841 |
RETURN(); |
|
842 |
} |
|
843 |
|
|
844 |
FLOAT_OP(ceilw, d) |
|
845 |
{ |
|
846 |
set_float_rounding_mode(float_round_up, &env->fp_status); |
|
847 |
WT2 = float64_round_to_int(FDT0, &env->fp_status); |
|
848 |
RESTORE_ROUNDING_MODE; |
|
849 |
|
|
850 |
DEBUG_FPU_STATE(); |
|
851 |
RETURN(); |
|
852 |
} |
|
853 |
FLOAT_OP(ceilw, s) |
|
854 |
{ |
|
855 |
set_float_rounding_mode(float_round_up, &env->fp_status); |
|
856 |
WT2 = float32_round_to_int(FST0, &env->fp_status); |
|
857 |
RESTORE_ROUNDING_MODE; |
|
858 |
DEBUG_FPU_STATE(); |
|
859 |
RETURN(); |
|
860 |
} |
|
861 |
|
|
862 |
FLOAT_OP(floorw, d) |
|
863 |
{ |
|
864 |
set_float_rounding_mode(float_round_down, &env->fp_status); |
|
865 |
WT2 = float64_round_to_int(FDT0, &env->fp_status); |
|
866 |
RESTORE_ROUNDING_MODE; |
|
867 |
|
|
868 |
DEBUG_FPU_STATE(); |
|
869 |
RETURN(); |
|
870 |
} |
|
871 |
FLOAT_OP(floorw, s) |
|
872 |
{ |
|
873 |
set_float_rounding_mode(float_round_down, &env->fp_status); |
|
874 |
WT2 = float32_round_to_int(FST0, &env->fp_status); |
|
875 |
RESTORE_ROUNDING_MODE; |
|
876 |
DEBUG_FPU_STATE(); |
|
877 |
RETURN(); |
|
878 |
} |
|
879 |
|
|
880 |
/* binary operations */ |
|
881 |
#define FLOAT_BINOP(name) \ |
|
882 |
FLOAT_OP(name, d) \ |
|
883 |
{ \ |
|
884 |
FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \ |
|
885 |
DEBUG_FPU_STATE(); \ |
|
886 |
} \ |
|
887 |
FLOAT_OP(name, s) \ |
|
888 |
{ \ |
|
889 |
FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ |
|
890 |
DEBUG_FPU_STATE(); \ |
|
891 |
} |
|
892 |
FLOAT_BINOP(add) |
|
893 |
FLOAT_BINOP(sub) |
|
894 |
FLOAT_BINOP(mul) |
|
895 |
FLOAT_BINOP(div) |
|
896 |
#undef FLOAT_BINOP |
|
897 |
|
|
898 |
/* unary operations, modifying fp status */ |
|
899 |
#define FLOAT_UNOP(name) \ |
|
900 |
FLOAT_OP(name, d) \ |
|
901 |
{ \ |
|
902 |
FDT2 = float64_ ## name(FDT0, &env->fp_status); \ |
|
903 |
DEBUG_FPU_STATE(); \ |
|
904 |
} \ |
|
905 |
FLOAT_OP(name, s) \ |
|
906 |
{ \ |
|
907 |
FST2 = float32_ ## name(FST0, &env->fp_status); \ |
|
908 |
DEBUG_FPU_STATE(); \ |
|
909 |
} |
|
910 |
FLOAT_UNOP(sqrt) |
|
911 |
#undef FLOAT_UNOP |
|
912 |
|
|
913 |
/* unary operations, not modifying fp status */ |
|
914 |
#define FLOAT_UNOP(name) \ |
|
915 |
FLOAT_OP(name, d) \ |
|
916 |
{ \ |
|
917 |
FDT2 = float64_ ## name(FDT0); \ |
|
918 |
DEBUG_FPU_STATE(); \ |
|
919 |
} \ |
|
920 |
FLOAT_OP(name, s) \ |
|
921 |
{ \ |
|
922 |
FST2 = float32_ ## name(FST0); \ |
|
923 |
DEBUG_FPU_STATE(); \ |
|
924 |
} |
|
925 |
FLOAT_UNOP(abs) |
|
926 |
FLOAT_UNOP(chs) |
|
927 |
#undef FLOAT_UNOP |
|
928 |
|
|
929 |
FLOAT_OP(mov, d) |
|
930 |
{ |
|
931 |
FDT2 = FDT0; |
|
932 |
DEBUG_FPU_STATE(); |
|
933 |
RETURN(); |
|
934 |
} |
|
935 |
FLOAT_OP(mov, s) |
|
936 |
{ |
|
937 |
FST2 = FST0; |
|
938 |
DEBUG_FPU_STATE(); |
|
939 |
RETURN(); |
|
940 |
} |
|
941 |
|
|
942 |
#ifdef CONFIG_SOFTFLOAT |
|
943 |
#define clear_invalid() do { \ |
|
944 |
int flags = get_float_exception_flags(&env->fp_status); \ |
|
945 |
flags &= ~float_flag_invalid; \ |
|
946 |
set_float_exception_flags(flags, &env->fp_status); \ |
|
947 |
} while(0) |
|
948 |
#else |
|
949 |
#define clear_invalid() do { } while(0) |
|
950 |
#endif |
|
951 |
|
|
952 |
extern void dump_fpu_s(CPUState *env); |
|
953 |
|
|
954 |
#define FOP_COND(fmt, op, sig, cond) \ |
|
955 |
void op_cmp_ ## fmt ## _ ## op (void) \ |
|
956 |
{ \ |
|
957 |
if (cond) \ |
|
958 |
SET_FP_COND(env->fcr31); \ |
|
959 |
else \ |
|
960 |
CLEAR_FP_COND(env->fcr31); \ |
|
961 |
if (!sig) \ |
|
962 |
clear_invalid(); \ |
|
963 |
/*CALL_FROM_TB1(dump_fpu_s, env);*/ \ |
|
964 |
DEBUG_FPU_STATE(); \ |
|
965 |
RETURN(); \ |
|
966 |
} |
|
967 |
|
|
968 |
flag float64_is_unordered(float64 a, float64 b STATUS_PARAM) |
|
969 |
{ |
|
970 |
extern flag float64_is_nan( float64 a ); |
|
971 |
if (float64_is_nan(a) || float64_is_nan(b)) { |
|
972 |
float_raise(float_flag_invalid, status); |
|
973 |
return 1; |
|
974 |
} |
|
975 |
else { |
|
976 |
return 0; |
|
977 |
} |
|
978 |
} |
|
979 |
|
|
980 |
FOP_COND(d, f, 0, 0) |
|
981 |
FOP_COND(d, un, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status)) |
|
982 |
FOP_COND(d, eq, 0, float64_eq(FDT0, FDT1, &env->fp_status)) |
|
983 |
FOP_COND(d, ueq, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) |
|
984 |
FOP_COND(d, olt, 0, float64_lt(FDT0, FDT1, &env->fp_status)) |
|
985 |
FOP_COND(d, ult, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) |
|
986 |
FOP_COND(d, ole, 0, float64_le(FDT0, FDT1, &env->fp_status)) |
|
987 |
FOP_COND(d, ule, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) |
|
988 |
/* NOTE: the comma operator will make "cond" to eval to false, |
|
989 |
* but float*_is_unordered() is still called |
|
990 |
*/ |
|
991 |
FOP_COND(d, sf, 1, (float64_is_unordered(FDT0, FDT1, &env->fp_status), 0)) |
|
992 |
FOP_COND(d, ngle,1, float64_is_unordered(FDT1, FDT0, &env->fp_status)) |
|
993 |
FOP_COND(d, seq, 1, float64_eq(FDT0, FDT1, &env->fp_status)) |
|
994 |
FOP_COND(d, ngl, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) |
|
995 |
FOP_COND(d, lt, 1, float64_lt(FDT0, FDT1, &env->fp_status)) |
|
996 |
FOP_COND(d, nge, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) |
|
997 |
FOP_COND(d, le, 1, float64_le(FDT0, FDT1, &env->fp_status)) |
|
998 |
FOP_COND(d, ngt, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) |
|
999 |
|
|
1000 |
flag float32_is_unordered(float32 a, float32 b STATUS_PARAM) |
|
1001 |
{ |
|
1002 |
extern flag float32_is_nan( float32 a ); |
|
1003 |
if (float32_is_nan(a) || float32_is_nan(b)) { |
|
1004 |
float_raise(float_flag_invalid, status); |
|
1005 |
return 1; |
|
1006 |
} |
|
1007 |
else { |
|
1008 |
return 0; |
|
1009 |
} |
|
1010 |
} |
|
1011 |
|
|
1012 |
/* NOTE: the comma operator will make "cond" to eval to false, |
|
1013 |
* but float*_is_unordered() is still called |
|
1014 |
*/ |
|
1015 |
FOP_COND(s, f, 0, 0) |
|
1016 |
FOP_COND(s, un, 0, float32_is_unordered(FST1, FST0, &env->fp_status)) |
|
1017 |
FOP_COND(s, eq, 0, float32_eq(FST0, FST1, &env->fp_status)) |
|
1018 |
FOP_COND(s, ueq, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) |
|
1019 |
FOP_COND(s, olt, 0, float32_lt(FST0, FST1, &env->fp_status)) |
|
1020 |
FOP_COND(s, ult, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) |
|
1021 |
FOP_COND(s, ole, 0, float32_le(FST0, FST1, &env->fp_status)) |
|
1022 |
FOP_COND(s, ule, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) |
|
1023 |
/* NOTE: the comma operator will make "cond" to eval to false, |
|
1024 |
* but float*_is_unordered() is still called |
|
1025 |
*/ |
|
1026 |
FOP_COND(s, sf, 1, (float32_is_unordered(FST0, FST1, &env->fp_status), 0)) |
|
1027 |
FOP_COND(s, ngle,1, float32_is_unordered(FST1, FST0, &env->fp_status)) |
|
1028 |
FOP_COND(s, seq, 1, float32_eq(FST0, FST1, &env->fp_status)) |
|
1029 |
FOP_COND(s, ngl, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) |
|
1030 |
FOP_COND(s, lt, 1, float32_lt(FST0, FST1, &env->fp_status)) |
|
1031 |
FOP_COND(s, nge, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) |
|
1032 |
FOP_COND(s, le, 1, float32_le(FST0, FST1, &env->fp_status)) |
|
1033 |
FOP_COND(s, ngt, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) |
|
1034 |
|
|
1035 |
void op_bc1f (void) |
|
1036 |
{ |
|
1037 |
T0 = ! IS_FP_COND_SET(env->fcr31); |
|
1038 |
DEBUG_FPU_STATE(); |
|
1039 |
RETURN(); |
|
1040 |
} |
|
1041 |
|
|
1042 |
void op_bc1t (void) |
|
1043 |
{ |
|
1044 |
T0 = IS_FP_COND_SET(env->fcr31); |
|
1045 |
DEBUG_FPU_STATE(); |
|
1046 |
RETURN(); |
|
1047 |
} |
|
1048 |
#endif /* MIPS_USES_FPU */ |
|
1049 |
|
|
565 | 1050 |
#if defined(MIPS_USES_R4K_TLB) |
566 | 1051 |
void op_tlbwi (void) |
567 | 1052 |
{ |
b/target-mips/op_helper.c | ||
---|---|---|
529 | 529 |
return; |
530 | 530 |
} |
531 | 531 |
|
532 |
#ifdef MIPS_USES_FPU |
|
533 |
#include "softfloat.h" |
|
534 |
|
|
535 |
void fpu_handle_exception(void) |
|
536 |
{ |
|
537 |
#ifdef CONFIG_SOFTFLOAT |
|
538 |
int flags = get_float_exception_flags(&env->fp_status); |
|
539 |
unsigned int cpuflags = 0, enable, cause = 0; |
|
540 |
|
|
541 |
enable = GET_FP_ENABLE(env->fcr31); |
|
542 |
|
|
543 |
/* determine current flags */ |
|
544 |
if (flags & float_flag_invalid) { |
|
545 |
cpuflags |= FP_INVALID; |
|
546 |
cause |= FP_INVALID & enable; |
|
547 |
} |
|
548 |
if (flags & float_flag_divbyzero) { |
|
549 |
cpuflags |= FP_DIV0; |
|
550 |
cause |= FP_DIV0 & enable; |
|
551 |
} |
|
552 |
if (flags & float_flag_overflow) { |
|
553 |
cpuflags |= FP_OVERFLOW; |
|
554 |
cause |= FP_OVERFLOW & enable; |
|
555 |
} |
|
556 |
if (flags & float_flag_underflow) { |
|
557 |
cpuflags |= FP_UNDERFLOW; |
|
558 |
cause |= FP_UNDERFLOW & enable; |
|
559 |
} |
|
560 |
if (flags & float_flag_inexact) { |
|
561 |
cpuflags |= FP_INEXACT; |
|
562 |
cause |= FP_INEXACT & enable; |
|
563 |
} |
|
564 |
SET_FP_FLAGS(env->fcr31, cpuflags); |
|
565 |
SET_FP_CAUSE(env->fcr31, cause); |
|
566 |
#else |
|
567 |
SET_FP_FLAGS(env->fcr31, 0); |
|
568 |
SET_FP_CAUSE(env->fcr31, 0); |
|
569 |
#endif |
|
570 |
} |
|
571 |
#endif /* MIPS_USES_FPU */ |
|
572 |
|
|
532 | 573 |
/* TLB management */ |
533 | 574 |
#if defined(MIPS_USES_R4K_TLB) |
534 | 575 |
static void invalidate_tlb (int idx) |
b/target-mips/op_mem.c | ||
---|---|---|
118 | 118 |
} |
119 | 119 |
RETURN(); |
120 | 120 |
} |
121 |
|
|
122 |
#ifdef MIPS_USES_FPU |
|
123 |
void glue(op_lwc1, MEMSUFFIX) (void) |
|
124 |
{ |
|
125 |
WT0 = glue(ldl, MEMSUFFIX)(T0); |
|
126 |
RETURN(); |
|
127 |
} |
|
128 |
void glue(op_swc1, MEMSUFFIX) (void) |
|
129 |
{ |
|
130 |
glue(stl, MEMSUFFIX)(T0, WT0); |
|
131 |
RETURN(); |
|
132 |
} |
|
133 |
void glue(op_ldc1, MEMSUFFIX) (void) |
|
134 |
{ |
|
135 |
DT0 = glue(ldq, MEMSUFFIX)(T0); |
|
136 |
RETURN(); |
|
137 |
} |
|
138 |
void glue(op_sdc1, MEMSUFFIX) (void) |
|
139 |
{ |
|
140 |
glue(stq, MEMSUFFIX)(T0, DT0); |
|
141 |
RETURN(); |
|
142 |
} |
|
143 |
#endif |
b/target-mips/translate.c | ||
---|---|---|
2 | 2 |
* MIPS32 emulation for qemu: main translation routines. |
3 | 3 |
* |
4 | 4 |
* Copyright (c) 2004-2005 Jocelyn Mayer |
5 |
* Copyright (c) 2006 Marius Groeger (FPU operations) |
|
5 | 6 |
* |
6 | 7 |
* This library is free software; you can redistribute it and/or |
7 | 8 |
* modify it under the terms of the GNU Lesser General Public |
... | ... | |
217 | 218 |
OPC_WAIT = 0x20 | EXT_CP0, |
218 | 219 |
}; |
219 | 220 |
|
221 |
#ifdef MIPS_USES_FPU |
|
222 |
enum { |
|
223 |
/* Coprocessor 1 (FPU) */ |
|
224 |
OPC_MFC1 = 0x00 | EXT_CP1, |
|
225 |
OPC_MTC1 = 0x04 | EXT_CP1, |
|
226 |
OPC_CFC1 = 0x02 | EXT_CP1, |
|
227 |
OPC_CTC1 = 0x06 | EXT_CP1, |
|
228 |
}; |
|
229 |
#endif |
|
230 |
|
|
220 | 231 |
const unsigned char *regnames[] = |
221 | 232 |
{ "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", |
222 | 233 |
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", |
... | ... | |
248 | 259 |
GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); |
249 | 260 |
GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); |
250 | 261 |
|
262 |
#ifdef MIPS_USES_FPU |
|
263 |
const unsigned char *fregnames[] = |
|
264 |
{ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", |
|
265 |
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", |
|
266 |
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", |
|
267 |
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; |
|
268 |
|
|
269 |
# define SFGEN32(func, NAME) \ |
|
270 |
static GenOpFunc *NAME ## _table [32] = { \ |
|
271 |
NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ |
|
272 |
NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ |
|
273 |
NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ |
|
274 |
NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ |
|
275 |
NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ |
|
276 |
NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ |
|
277 |
NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ |
|
278 |
NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ |
|
279 |
}; \ |
|
280 |
static inline void func(int n) \ |
|
281 |
{ \ |
|
282 |
NAME ## _table[n](); \ |
|
283 |
} |
|
284 |
|
|
285 |
# define DFGEN32(func, NAME) \ |
|
286 |
static GenOpFunc *NAME ## _table [32] = { \ |
|
287 |
NAME ## 0, 0, NAME ## 2, 0, \ |
|
288 |
NAME ## 4, 0, NAME ## 6, 0, \ |
|
289 |
NAME ## 8, 0, NAME ## 10, 0, \ |
|
290 |
NAME ## 12, 0, NAME ## 14, 0, \ |
|
291 |
NAME ## 16, 0, NAME ## 18, 0, \ |
|
292 |
NAME ## 20, 0, NAME ## 22, 0, \ |
|
293 |
NAME ## 24, 0, NAME ## 26, 0, \ |
|
294 |
NAME ## 28, 0, NAME ## 30, 0, \ |
|
295 |
}; \ |
|
296 |
static inline void func(int n) \ |
|
297 |
{ \ |
|
298 |
NAME ## _table[n](); \ |
|
299 |
} |
|
300 |
|
|
301 |
SFGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr); |
|
302 |
SFGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr); |
|
303 |
|
|
304 |
SFGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr); |
|
305 |
SFGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr); |
|
306 |
|
|
307 |
SFGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr); |
|
308 |
SFGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr); |
|
309 |
|
|
310 |
DFGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr); |
|
311 |
DFGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr); |
|
312 |
|
|
313 |
DFGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr); |
|
314 |
DFGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr); |
|
315 |
|
|
316 |
DFGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr); |
|
317 |
DFGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr); |
|
318 |
|
|
319 |
#define FOP_CONDS(fmt) \ |
|
320 |
static GenOpFunc * cond_ ## fmt ## _table[16] = { \ |
|
321 |
gen_op_cmp_ ## fmt ## _f, \ |
|
322 |
gen_op_cmp_ ## fmt ## _un, \ |
|
323 |
gen_op_cmp_ ## fmt ## _eq, \ |
|
324 |
gen_op_cmp_ ## fmt ## _ueq, \ |
|
325 |
gen_op_cmp_ ## fmt ## _olt, \ |
|
326 |
gen_op_cmp_ ## fmt ## _ult, \ |
|
327 |
gen_op_cmp_ ## fmt ## _ole, \ |
|
328 |
gen_op_cmp_ ## fmt ## _ule, \ |
|
329 |
gen_op_cmp_ ## fmt ## _sf, \ |
|
330 |
gen_op_cmp_ ## fmt ## _ngle, \ |
|
331 |
gen_op_cmp_ ## fmt ## _seq, \ |
|
332 |
gen_op_cmp_ ## fmt ## _ngl, \ |
|
333 |
gen_op_cmp_ ## fmt ## _lt, \ |
|
334 |
gen_op_cmp_ ## fmt ## _nge, \ |
|
335 |
gen_op_cmp_ ## fmt ## _le, \ |
|
336 |
gen_op_cmp_ ## fmt ## _ngt, \ |
|
337 |
}; \ |
|
338 |
static inline void gen_cmp_ ## fmt(int n) \ |
|
339 |
{ \ |
|
340 |
cond_ ## fmt ## _table[n](); \ |
|
341 |
} |
|
342 |
|
|
343 |
FOP_CONDS(d) |
|
344 |
FOP_CONDS(s) |
|
345 |
|
|
346 |
#endif |
|
347 |
|
|
251 | 348 |
typedef struct DisasContext { |
252 | 349 |
struct TranslationBlock *tb; |
253 | 350 |
target_ulong pc, saved_pc; |
... | ... | |
312 | 409 |
} \ |
313 | 410 |
} while (0) |
314 | 411 |
|
412 |
#ifdef MIPS_USES_FPU |
|
413 |
|
|
414 |
# define GEN_LOAD_FREG_FTN(FTn, Fn) \ |
|
415 |
do { \ |
|
416 |
glue(gen_op_load_fpr_, FTn)(Fn); \ |
|
417 |
} while (0) |
|
418 |
|
|
419 |
#define GEN_STORE_FTN_FREG(Fn, FTn) \ |
|
420 |
do { \ |
|
421 |
glue(gen_op_store_fpr_, FTn)(Fn); \ |
|
422 |
} while (0) |
|
423 |
|
|
424 |
#endif |
|
425 |
|
|
315 | 426 |
static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) |
316 | 427 |
{ |
317 | 428 |
#if defined MIPS_DEBUG_DISAS |
... | ... | |
397 | 508 |
OP_ST_TABLE(b); |
398 | 509 |
OP_LD_TABLE(l); |
399 | 510 |
OP_ST_TABLE(c); |
511 |
#ifdef MIPS_USES_FPU |
|
512 |
OP_LD_TABLE(wc1); |
|
513 |
OP_ST_TABLE(wc1); |
|
514 |
OP_LD_TABLE(dc1); |
|
515 |
OP_ST_TABLE(dc1); |
|
516 |
#endif |
|
400 | 517 |
|
401 | 518 |
/* Load and store */ |
402 | 519 |
static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, |
... | ... | |
551 | 668 |
MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); |
552 | 669 |
} |
553 | 670 |
|
671 |
#ifdef MIPS_USES_FPU |
|
672 |
|
|
673 |
/* Load and store */ |
|
674 |
static void gen_flt_ldst (DisasContext *ctx, uint16_t opc, int ft, |
|
675 |
int base, int16_t offset) |
|
676 |
{ |
|
677 |
const unsigned char *opn = "unk"; |
|
678 |
|
|
679 |
if (base == 0) { |
|
680 |
GEN_LOAD_IMM_TN(T0, offset); |
|
681 |
} else if (offset == 0) { |
|
682 |
gen_op_load_gpr_T0(base); |
|
683 |
} else { |
|
684 |
gen_op_load_gpr_T0(base); |
|
685 |
gen_op_set_T1(offset); |
|
686 |
gen_op_add(); |
|
687 |
} |
|
688 |
/* Don't do NOP if destination is zero: we must perform the actual |
|
689 |
* memory access |
|
690 |
*/ |
|
691 |
switch (opc) { |
|
692 |
case OPC_LWC1: |
|
693 |
op_ldst(lwc1); |
|
694 |
GEN_STORE_FTN_FREG(ft, WT0); |
|
695 |
opn = "lwc1"; |
|
696 |
break; |
|
697 |
case OPC_SWC1: |
|
698 |
GEN_LOAD_FREG_FTN(WT0, ft); |
|
699 |
op_ldst(swc1); |
|
700 |
opn = "swc1"; |
|
701 |
break; |
|
702 |
case OPC_LDC1: |
|
703 |
op_ldst(ldc1); |
|
704 |
GEN_STORE_FTN_FREG(ft, DT0); |
|
705 |
opn = "ldc1"; |
|
706 |
break; |
|
707 |
case OPC_SDC1: |
|
708 |
GEN_LOAD_FREG_FTN(DT0, ft); |
|
709 |
op_ldst(sdc1); |
|
710 |
opn = "sdc1"; |
|
711 |
break; |
|
712 |
default: |
|
713 |
MIPS_INVAL("float load/store"); |
|
714 |
generate_exception(ctx, EXCP_CpU); |
|
715 |
return; |
|
716 |
} |
|
717 |
MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]); |
|
718 |
} |
|
719 |
#endif |
|
720 |
|
|
554 | 721 |
/* Arithmetic with immediate operand */ |
555 | 722 |
static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt, |
556 | 723 |
int rs, int16_t imm) |
... | ... | |
1265 | 1432 |
MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd); |
1266 | 1433 |
} |
1267 | 1434 |
|
1435 |
#ifdef MIPS_USES_FPU |
|
1436 |
/* CP1 Branches (before delay slot) */ |
|
1437 |
static void gen_compute_branch1 (DisasContext *ctx, uint16_t cond, |
|
1438 |
int32_t offset) |
|
1439 |
{ |
|
1440 |
target_ulong btarget; |
|
1441 |
|
|
1442 |
btarget = ctx->pc + 4 + offset; |
|
1443 |
|
|
1444 |
switch (cond) { |
|
1445 |
case 0x0000: /* bc1f */ |
|
1446 |
gen_op_bc1f(); |
|
1447 |
MIPS_DEBUG("bc1f %08x", btarget); |
|
1448 |
goto not_likely; |
|
1449 |
case 0x0002: /* bc1fl */ |
|
1450 |
gen_op_bc1f(); |
|
1451 |
MIPS_DEBUG("bc1fl %08x", btarget); |
|
1452 |
goto likely; |
|
1453 |
case 0x0001: /* bc1t */ |
|
1454 |
gen_op_bc1t(); |
|
1455 |
MIPS_DEBUG("bc1t %08x", btarget); |
|
1456 |
not_likely: |
|
1457 |
ctx->hflags |= MIPS_HFLAG_BC; |
|
1458 |
break; |
|
1459 |
case 0x0003: /* bc1tl */ |
|
1460 |
gen_op_bc1t(); |
|
1461 |
MIPS_DEBUG("bc1tl %08x", btarget); |
|
1462 |
likely: |
|
1463 |
ctx->hflags |= MIPS_HFLAG_BL; |
|
1464 |
break; |
|
1465 |
default: |
|
1466 |
MIPS_INVAL("cp1 branch/jump"); |
|
1467 |
generate_exception(ctx, EXCP_RI); |
|
1468 |
return; |
|
1469 |
} |
|
1470 |
gen_op_set_bcond(); |
|
1471 |
|
|
1472 |
MIPS_DEBUG("enter ds: cond %02x target %08x", |
|
1473 |
ctx->hflags, btarget); |
|
1474 |
ctx->btarget = btarget; |
|
1475 |
|
|
1476 |
return; |
|
1477 |
} |
|
1478 |
|
|
1268 | 1479 |
/* Coprocessor 1 (FPU) */ |
1480 |
static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs) |
|
1481 |
{ |
|
1482 |
const unsigned char *opn = "unk"; |
|
1483 |
|
|
1484 |
switch (opc) { |
|
1485 |
case OPC_MFC1: |
|
1486 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1487 |
gen_op_mfc1(); |
|
1488 |
GEN_STORE_TN_REG(rt, T0); |
|
1489 |
opn = "mfc1"; |
|
1490 |
break; |
|
1491 |
case OPC_MTC1: |
|
1492 |
GEN_LOAD_REG_TN(T0, rt); |
|
1493 |
gen_op_mtc1(); |
|
1494 |
GEN_STORE_FTN_FREG(fs, WT0); |
|
1495 |
opn = "mtc1"; |
|
1496 |
break; |
|
1497 |
case OPC_CFC1: |
|
1498 |
if (fs != 0 && fs != 31) { |
|
1499 |
MIPS_INVAL("cfc1 freg"); |
|
1500 |
generate_exception(ctx, EXCP_RI); |
|
1501 |
return; |
|
1502 |
} |
|
1503 |
GEN_LOAD_IMM_TN(T1, fs); |
|
1504 |
gen_op_cfc1(); |
|
1505 |
GEN_STORE_TN_REG(rt, T0); |
|
1506 |
opn = "cfc1"; |
|
1507 |
break; |
|
1508 |
case OPC_CTC1: |
|
1509 |
if (fs != 0 && fs != 31) { |
|
1510 |
MIPS_INVAL("ctc1 freg"); |
|
1511 |
generate_exception(ctx, EXCP_RI); |
|
1512 |
return; |
|
1513 |
} |
|
1514 |
GEN_LOAD_IMM_TN(T1, fs); |
|
1515 |
GEN_LOAD_REG_TN(T0, rt); |
|
1516 |
gen_op_ctc1(); |
|
1517 |
opn = "ctc1"; |
|
1518 |
break; |
|
1519 |
default: |
|
1520 |
if (loglevel & CPU_LOG_TB_IN_ASM) { |
|
1521 |
fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n", |
|
1522 |
ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, |
|
1523 |
((ctx->opcode >> 16) & 0x1F)); |
|
1524 |
} |
|
1525 |
generate_exception(ctx, EXCP_RI); |
|
1526 |
return; |
|
1527 |
} |
|
1528 |
MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]); |
|
1529 |
} |
|
1530 |
|
|
1531 |
/* verify if floating point register is valid; an operation is not defined |
|
1532 |
* if bit 0 of any register specification is set and the FR bit in the |
|
1533 |
* Status register equals zero, since the register numbers specify an |
|
1534 |
* even-odd pair of adjacent coprocessor general registers. When the FR bit |
|
1535 |
* in the Status register equals one, both even and odd register numbers |
|
1536 |
* are valid. |
|
1537 |
* |
|
1538 |
* Multiple float registers can be checked by calling |
|
1539 |
* CHECK_FR(ctx, freg1 | freg2 | ... | fregN); |
|
1540 |
*/ |
|
1541 |
#define CHECK_FR(ctx, freg) do { \ |
|
1542 |
if (!((ctx)->CP0_Status & (1<<CP0St_FR)) && ((freg) & 1)) { \ |
|
1543 |
generate_exception(ctx, EXCP_RI); \ |
|
1544 |
return; \ |
|
1545 |
} \ |
|
1546 |
} while(0) |
|
1547 |
|
|
1548 |
#define FOP(func, fmt) (((fmt) << 21) | (func)) |
|
1549 |
|
|
1550 |
static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, int func) |
|
1551 |
{ |
|
1552 |
const unsigned char *opn = "unk"; |
|
1553 |
const char *condnames[] = { |
|
1554 |
"c.f", |
|
1555 |
"c.un", |
|
1556 |
"c.eq", |
|
1557 |
"c.ueq", |
|
1558 |
"c.olt", |
|
1559 |
"c.ult", |
|
1560 |
"c.ole", |
|
1561 |
"c.ule", |
|
1562 |
"c.sf", |
|
1563 |
"c.ngle", |
|
1564 |
"c.seq", |
|
1565 |
"c.ngl", |
|
1566 |
"c.lt", |
|
1567 |
"c.nge", |
|
1568 |
"c.le", |
|
1569 |
"c.ngt", |
|
1570 |
}; |
|
1571 |
int binary = 0; |
|
1572 |
|
|
1573 |
switch (ctx->opcode & FOP(0x3f, 0x1f)) { |
|
1574 |
case FOP(0, 17): |
|
1575 |
CHECK_FR(ctx, fs | ft | fd); |
|
1576 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1577 |
GEN_LOAD_FREG_FTN(DT1, ft); |
|
1578 |
gen_op_float_add_d(); |
|
1579 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1580 |
opn = "add.d"; |
|
1581 |
binary = 1; |
|
1582 |
break; |
|
1583 |
case FOP(1, 17): |
|
1584 |
CHECK_FR(ctx, fs | ft | fd); |
|
1585 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1586 |
GEN_LOAD_FREG_FTN(DT1, ft); |
|
1587 |
gen_op_float_sub_d(); |
|
1588 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1589 |
opn = "sub.d"; |
|
1590 |
binary = 1; |
|
1591 |
break; |
|
1592 |
case FOP(2, 17): |
|
1593 |
CHECK_FR(ctx, fs | ft | fd); |
|
1594 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1595 |
GEN_LOAD_FREG_FTN(DT1, ft); |
|
1596 |
gen_op_float_mul_d(); |
|
1597 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1598 |
opn = "mul.d"; |
|
1599 |
binary = 1; |
|
1600 |
break; |
|
1601 |
case FOP(3, 17): |
|
1602 |
CHECK_FR(ctx, fs | ft | fd); |
|
1603 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1604 |
GEN_LOAD_FREG_FTN(DT1, ft); |
|
1605 |
gen_op_float_div_d(); |
|
1606 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1607 |
opn = "div.d"; |
|
1608 |
binary = 1; |
|
1609 |
break; |
|
1610 |
case FOP(4, 17): |
|
1611 |
CHECK_FR(ctx, fs | fd); |
|
1612 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1613 |
gen_op_float_sqrt_d(); |
|
1614 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1615 |
opn = "sqrt.d"; |
|
1616 |
break; |
|
1617 |
case FOP(5, 17): |
|
1618 |
CHECK_FR(ctx, fs | fd); |
|
1619 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1620 |
gen_op_float_abs_d(); |
|
1621 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1622 |
opn = "abs.d"; |
|
1623 |
break; |
|
1624 |
case FOP(6, 17): |
|
1625 |
CHECK_FR(ctx, fs | fd); |
|
1626 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1627 |
gen_op_float_mov_d(); |
|
1628 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1629 |
opn = "mov.d"; |
|
1630 |
break; |
|
1631 |
case FOP(7, 17): |
|
1632 |
CHECK_FR(ctx, fs | fd); |
|
1633 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1634 |
gen_op_float_chs_d(); |
|
1635 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1636 |
opn = "neg.d"; |
|
1637 |
break; |
|
1638 |
/* 8 - round.l */ |
|
1639 |
/* 9 - trunc.l */ |
|
1640 |
/* 10 - ceil.l */ |
|
1641 |
/* 11 - floor.l */ |
|
1642 |
case FOP(12, 17): |
|
1643 |
CHECK_FR(ctx, fs | fd); |
|
1644 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1645 |
gen_op_float_roundw_d(); |
|
1646 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1647 |
opn = "round.w.d"; |
|
1648 |
break; |
|
1649 |
case FOP(13, 17): |
|
1650 |
CHECK_FR(ctx, fs | fd); |
|
1651 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1652 |
gen_op_float_truncw_d(); |
|
1653 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1654 |
opn = "trunc.w.d"; |
|
1655 |
break; |
|
1656 |
case FOP(14, 17): |
|
1657 |
CHECK_FR(ctx, fs | fd); |
|
1658 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1659 |
gen_op_float_ceilw_d(); |
|
1660 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1661 |
opn = "ceil.w.d"; |
|
1662 |
break; |
|
1663 |
case FOP(15, 17): |
|
1664 |
CHECK_FR(ctx, fs | fd); |
|
1665 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1666 |
gen_op_float_floorw_d(); |
|
1667 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1668 |
opn = "ceil.w.d"; |
|
1669 |
break; |
|
1670 |
case FOP(33, 20): /* cvt.d.w */ |
|
1671 |
CHECK_FR(ctx, fs | fd); |
|
1672 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1673 |
gen_op_float_cvtd_w(); |
|
1674 |
GEN_STORE_FTN_FREG(fd, DT2); |
|
1675 |
opn = "cvt.d.w"; |
|
1676 |
break; |
|
1677 |
case FOP(48, 17): |
|
1678 |
case FOP(49, 17): |
|
1679 |
case FOP(50, 17): |
|
1680 |
case FOP(51, 17): |
|
1681 |
case FOP(52, 17): |
|
1682 |
case FOP(53, 17): |
|
1683 |
case FOP(54, 17): |
|
1684 |
case FOP(55, 17): |
|
1685 |
case FOP(56, 17): |
|
1686 |
case FOP(57, 17): |
|
1687 |
case FOP(58, 17): |
|
1688 |
case FOP(59, 17): |
|
1689 |
case FOP(60, 17): |
|
1690 |
case FOP(61, 17): |
|
1691 |
case FOP(62, 17): |
|
1692 |
case FOP(63, 17): |
|
1693 |
CHECK_FR(ctx, fs | ft); |
|
1694 |
GEN_LOAD_FREG_FTN(DT0, fs); |
|
1695 |
GEN_LOAD_FREG_FTN(DT1, ft); |
|
1696 |
gen_cmp_d(func-48); |
|
1697 |
opn = condnames[func-48]; |
|
1698 |
break; |
|
1699 |
case FOP(0, 16): |
|
1700 |
CHECK_FR(ctx, fs | ft | fd); |
|
1701 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1702 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
1703 |
gen_op_float_add_s(); |
|
1704 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1705 |
opn = "add.s"; |
|
1706 |
binary = 1; |
|
1707 |
break; |
|
1708 |
case FOP(1, 16): |
|
1709 |
CHECK_FR(ctx, fs | ft | fd); |
|
1710 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1711 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
1712 |
gen_op_float_sub_s(); |
|
1713 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1714 |
opn = "sub.s"; |
|
1715 |
binary = 1; |
|
1716 |
break; |
|
1717 |
case FOP(2, 16): |
|
1718 |
CHECK_FR(ctx, fs | ft | fd); |
|
1719 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1720 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
1721 |
gen_op_float_mul_s(); |
|
1722 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1723 |
opn = "mul.s"; |
|
1724 |
binary = 1; |
|
1725 |
break; |
|
1726 |
case FOP(3, 16): |
|
1727 |
CHECK_FR(ctx, fs | ft | fd); |
|
1728 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1729 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
1730 |
gen_op_float_div_s(); |
|
1731 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1732 |
opn = "div.s"; |
|
1733 |
binary = 1; |
|
1734 |
break; |
|
1735 |
case FOP(4, 16): |
|
1736 |
CHECK_FR(ctx, fs | fd); |
|
1737 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1738 |
gen_op_float_sqrt_s(); |
|
1739 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1740 |
opn = "sqrt.s"; |
|
1741 |
break; |
|
1742 |
case FOP(5, 16): |
|
1743 |
CHECK_FR(ctx, fs | fd); |
|
1744 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1745 |
gen_op_float_abs_s(); |
|
1746 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1747 |
opn = "abs.s"; |
|
1748 |
break; |
|
1749 |
case FOP(6, 16): |
|
1750 |
CHECK_FR(ctx, fs | fd); |
|
1751 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1752 |
gen_op_float_mov_s(); |
|
1753 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1754 |
opn = "mov.s"; |
|
1755 |
break; |
|
1756 |
case FOP(7, 16): |
|
1757 |
CHECK_FR(ctx, fs | fd); |
|
1758 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1759 |
gen_op_float_chs_s(); |
|
1760 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1761 |
opn = "neg.s"; |
|
1762 |
break; |
|
1763 |
case FOP(12, 16): |
|
1764 |
CHECK_FR(ctx, fs | fd); |
|
1765 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1766 |
gen_op_float_roundw_s(); |
|
1767 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1768 |
opn = "round.w.s"; |
|
1769 |
break; |
|
1770 |
case FOP(13, 16): |
|
1771 |
CHECK_FR(ctx, fs | fd); |
|
1772 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1773 |
gen_op_float_truncw_s(); |
|
1774 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1775 |
opn = "trunc.w.s"; |
|
1776 |
break; |
|
1777 |
case FOP(32, 20): /* cvt.s.w */ |
|
1778 |
CHECK_FR(ctx, fs | fd); |
|
1779 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1780 |
gen_op_float_cvts_w(); |
|
1781 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1782 |
opn = "cvt.s.w"; |
|
1783 |
break; |
|
1784 |
case FOP(36, 16): /* cvt.w.s */ |
|
1785 |
CHECK_FR(ctx, fs | fd); |
|
1786 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1787 |
gen_op_float_cvtw_s(); |
|
1788 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1789 |
opn = "cvt.w.s"; |
|
1790 |
break; |
|
1791 |
case FOP(36, 17): /* cvt.w.d */ |
|
1792 |
CHECK_FR(ctx, fs | fd); |
|
1793 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1794 |
gen_op_float_cvtw_d(); |
|
1795 |
GEN_STORE_FTN_FREG(fd, WT2); |
|
1796 |
opn = "cvt.w.d"; |
|
1797 |
break; |
|
1798 |
case FOP(48, 16): |
|
1799 |
case FOP(49, 16): |
|
1800 |
case FOP(50, 16): |
|
1801 |
case FOP(51, 16): |
|
1802 |
case FOP(52, 16): |
|
1803 |
case FOP(53, 16): |
|
1804 |
case FOP(54, 16): |
|
1805 |
case FOP(55, 16): |
|
1806 |
case FOP(56, 16): |
|
1807 |
case FOP(57, 16): |
|
1808 |
case FOP(58, 16): |
|
1809 |
case FOP(59, 16): |
|
1810 |
case FOP(60, 16): |
|
1811 |
case FOP(61, 16): |
|
1812 |
case FOP(62, 16): |
|
1813 |
case FOP(63, 16): |
|
1814 |
CHECK_FR(ctx, fs | ft); |
|
1815 |
GEN_LOAD_FREG_FTN(WT0, fs); |
|
1816 |
GEN_LOAD_FREG_FTN(WT1, ft); |
|
1817 |
gen_cmp_s(func-48); |
|
1818 |
opn = condnames[func-48]; |
|
1819 |
break; |
|
1820 |
default: |
|
1821 |
if (loglevel & CPU_LOG_TB_IN_ASM) { |
Also available in: Unified diff