root / target-mips / op.c @ aa0bf00b
History | View | Annotate | Download (23.6 kB)
1 |
/*
|
---|---|
2 |
* MIPS emulation micro-operations for qemu.
|
3 |
*
|
4 |
* Copyright (c) 2004-2005 Jocelyn Mayer
|
5 |
* Copyright (c) 2006 Marius Groeger (FPU operations)
|
6 |
* Copyright (c) 2007 Thiemo Seufer (64-bit FPU support)
|
7 |
*
|
8 |
* This library is free software; you can redistribute it and/or
|
9 |
* modify it under the terms of the GNU Lesser General Public
|
10 |
* License as published by the Free Software Foundation; either
|
11 |
* version 2 of the License, or (at your option) any later version.
|
12 |
*
|
13 |
* This library is distributed in the hope that it will be useful,
|
14 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
16 |
* Lesser General Public License for more details.
|
17 |
*
|
18 |
* You should have received a copy of the GNU Lesser General Public
|
19 |
* License along with this library; if not, write to the Free Software
|
20 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
21 |
*/
|
22 |
|
23 |
#include "config.h" |
24 |
#include "exec.h" |
25 |
#include "host-utils.h" |
26 |
|
27 |
#ifndef CALL_FROM_TB0
|
28 |
#define CALL_FROM_TB0(func) func()
|
29 |
#endif
|
30 |
#ifndef CALL_FROM_TB1
|
31 |
#define CALL_FROM_TB1(func, arg0) func(arg0)
|
32 |
#endif
|
33 |
#ifndef CALL_FROM_TB1_CONST16
|
34 |
#define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0)
|
35 |
#endif
|
36 |
#ifndef CALL_FROM_TB2
|
37 |
#define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1)
|
38 |
#endif
|
39 |
#ifndef CALL_FROM_TB2_CONST16
|
40 |
#define CALL_FROM_TB2_CONST16(func, arg0, arg1) \
|
41 |
CALL_FROM_TB2(func, arg0, arg1) |
42 |
#endif
|
43 |
#ifndef CALL_FROM_TB3
|
44 |
#define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2)
|
45 |
#endif
|
46 |
#ifndef CALL_FROM_TB4
|
47 |
#define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \
|
48 |
func(arg0, arg1, arg2, arg3) |
49 |
#endif
|
50 |
|
51 |
/* Load and store */
|
52 |
#define MEMSUFFIX _raw
|
53 |
#include "op_mem.c" |
54 |
#undef MEMSUFFIX
|
55 |
#if !defined(CONFIG_USER_ONLY)
|
56 |
#define MEMSUFFIX _user
|
57 |
#include "op_mem.c" |
58 |
#undef MEMSUFFIX
|
59 |
|
60 |
#define MEMSUFFIX _super
|
61 |
#include "op_mem.c" |
62 |
#undef MEMSUFFIX
|
63 |
|
64 |
#define MEMSUFFIX _kernel
|
65 |
#include "op_mem.c" |
66 |
#undef MEMSUFFIX
|
67 |
#endif
|
68 |
|
69 |
/* 64 bits arithmetic */
|
70 |
#if TARGET_LONG_BITS > HOST_LONG_BITS
|
71 |
void op_mult (void) |
72 |
{ |
73 |
CALL_FROM_TB0(do_mult); |
74 |
FORCE_RET(); |
75 |
} |
76 |
|
77 |
void op_multu (void) |
78 |
{ |
79 |
CALL_FROM_TB0(do_multu); |
80 |
FORCE_RET(); |
81 |
} |
82 |
|
83 |
void op_madd (void) |
84 |
{ |
85 |
CALL_FROM_TB0(do_madd); |
86 |
FORCE_RET(); |
87 |
} |
88 |
|
89 |
void op_maddu (void) |
90 |
{ |
91 |
CALL_FROM_TB0(do_maddu); |
92 |
FORCE_RET(); |
93 |
} |
94 |
|
95 |
void op_msub (void) |
96 |
{ |
97 |
CALL_FROM_TB0(do_msub); |
98 |
FORCE_RET(); |
99 |
} |
100 |
|
101 |
void op_msubu (void) |
102 |
{ |
103 |
CALL_FROM_TB0(do_msubu); |
104 |
FORCE_RET(); |
105 |
} |
106 |
|
107 |
/* Multiplication variants of the vr54xx. */
|
108 |
void op_muls (void) |
109 |
{ |
110 |
CALL_FROM_TB0(do_muls); |
111 |
FORCE_RET(); |
112 |
} |
113 |
|
114 |
void op_mulsu (void) |
115 |
{ |
116 |
CALL_FROM_TB0(do_mulsu); |
117 |
FORCE_RET(); |
118 |
} |
119 |
|
120 |
void op_macc (void) |
121 |
{ |
122 |
CALL_FROM_TB0(do_macc); |
123 |
FORCE_RET(); |
124 |
} |
125 |
|
126 |
void op_macchi (void) |
127 |
{ |
128 |
CALL_FROM_TB0(do_macchi); |
129 |
FORCE_RET(); |
130 |
} |
131 |
|
132 |
void op_maccu (void) |
133 |
{ |
134 |
CALL_FROM_TB0(do_maccu); |
135 |
FORCE_RET(); |
136 |
} |
137 |
void op_macchiu (void) |
138 |
{ |
139 |
CALL_FROM_TB0(do_macchiu); |
140 |
FORCE_RET(); |
141 |
} |
142 |
|
143 |
void op_msac (void) |
144 |
{ |
145 |
CALL_FROM_TB0(do_msac); |
146 |
FORCE_RET(); |
147 |
} |
148 |
|
149 |
void op_msachi (void) |
150 |
{ |
151 |
CALL_FROM_TB0(do_msachi); |
152 |
FORCE_RET(); |
153 |
} |
154 |
|
155 |
void op_msacu (void) |
156 |
{ |
157 |
CALL_FROM_TB0(do_msacu); |
158 |
FORCE_RET(); |
159 |
} |
160 |
|
161 |
void op_msachiu (void) |
162 |
{ |
163 |
CALL_FROM_TB0(do_msachiu); |
164 |
FORCE_RET(); |
165 |
} |
166 |
|
167 |
void op_mulhi (void) |
168 |
{ |
169 |
CALL_FROM_TB0(do_mulhi); |
170 |
FORCE_RET(); |
171 |
} |
172 |
|
173 |
void op_mulhiu (void) |
174 |
{ |
175 |
CALL_FROM_TB0(do_mulhiu); |
176 |
FORCE_RET(); |
177 |
} |
178 |
|
179 |
void op_mulshi (void) |
180 |
{ |
181 |
CALL_FROM_TB0(do_mulshi); |
182 |
FORCE_RET(); |
183 |
} |
184 |
|
185 |
void op_mulshiu (void) |
186 |
{ |
187 |
CALL_FROM_TB0(do_mulshiu); |
188 |
FORCE_RET(); |
189 |
} |
190 |
|
191 |
#else /* TARGET_LONG_BITS > HOST_LONG_BITS */ |
192 |
|
193 |
static always_inline uint64_t get_HILO (void) |
194 |
{ |
195 |
return ((uint64_t)env->HI[env->current_tc][0] << 32) | |
196 |
((uint64_t)(uint32_t)env->LO[env->current_tc][0]);
|
197 |
} |
198 |
|
199 |
static always_inline void set_HILO (uint64_t HILO) |
200 |
{ |
201 |
env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF); |
202 |
env->HI[env->current_tc][0] = (int32_t)(HILO >> 32); |
203 |
} |
204 |
|
205 |
static always_inline void set_HIT0_LO (uint64_t HILO) |
206 |
{ |
207 |
env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF); |
208 |
T0 = env->HI[env->current_tc][0] = (int32_t)(HILO >> 32); |
209 |
} |
210 |
|
211 |
static always_inline void set_HI_LOT0 (uint64_t HILO) |
212 |
{ |
213 |
T0 = env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF); |
214 |
env->HI[env->current_tc][0] = (int32_t)(HILO >> 32); |
215 |
} |
216 |
|
217 |
void op_mult (void) |
218 |
{ |
219 |
set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); |
220 |
FORCE_RET(); |
221 |
} |
222 |
|
223 |
void op_multu (void) |
224 |
{ |
225 |
set_HILO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); |
226 |
FORCE_RET(); |
227 |
} |
228 |
|
229 |
void op_madd (void) |
230 |
{ |
231 |
int64_t tmp; |
232 |
|
233 |
tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); |
234 |
set_HILO((int64_t)get_HILO() + tmp); |
235 |
FORCE_RET(); |
236 |
} |
237 |
|
238 |
void op_maddu (void) |
239 |
{ |
240 |
uint64_t tmp; |
241 |
|
242 |
tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); |
243 |
set_HILO(get_HILO() + tmp); |
244 |
FORCE_RET(); |
245 |
} |
246 |
|
247 |
void op_msub (void) |
248 |
{ |
249 |
int64_t tmp; |
250 |
|
251 |
tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); |
252 |
set_HILO((int64_t)get_HILO() - tmp); |
253 |
FORCE_RET(); |
254 |
} |
255 |
|
256 |
void op_msubu (void) |
257 |
{ |
258 |
uint64_t tmp; |
259 |
|
260 |
tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); |
261 |
set_HILO(get_HILO() - tmp); |
262 |
FORCE_RET(); |
263 |
} |
264 |
|
265 |
/* Multiplication variants of the vr54xx. */
|
266 |
void op_muls (void) |
267 |
{ |
268 |
set_HI_LOT0(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
|
269 |
FORCE_RET(); |
270 |
} |
271 |
|
272 |
void op_mulsu (void) |
273 |
{ |
274 |
set_HI_LOT0(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
|
275 |
FORCE_RET(); |
276 |
} |
277 |
|
278 |
void op_macc (void) |
279 |
{ |
280 |
set_HI_LOT0(get_HILO() + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); |
281 |
FORCE_RET(); |
282 |
} |
283 |
|
284 |
void op_macchi (void) |
285 |
{ |
286 |
set_HIT0_LO(get_HILO() + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); |
287 |
FORCE_RET(); |
288 |
} |
289 |
|
290 |
void op_maccu (void) |
291 |
{ |
292 |
set_HI_LOT0(get_HILO() + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); |
293 |
FORCE_RET(); |
294 |
} |
295 |
|
296 |
void op_macchiu (void) |
297 |
{ |
298 |
set_HIT0_LO(get_HILO() + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); |
299 |
FORCE_RET(); |
300 |
} |
301 |
|
302 |
void op_msac (void) |
303 |
{ |
304 |
set_HI_LOT0(get_HILO() - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); |
305 |
FORCE_RET(); |
306 |
} |
307 |
|
308 |
void op_msachi (void) |
309 |
{ |
310 |
set_HIT0_LO(get_HILO() - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1)); |
311 |
FORCE_RET(); |
312 |
} |
313 |
|
314 |
void op_msacu (void) |
315 |
{ |
316 |
set_HI_LOT0(get_HILO() - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); |
317 |
FORCE_RET(); |
318 |
} |
319 |
|
320 |
void op_msachiu (void) |
321 |
{ |
322 |
set_HIT0_LO(get_HILO() - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1)); |
323 |
FORCE_RET(); |
324 |
} |
325 |
|
326 |
void op_mulhi (void) |
327 |
{ |
328 |
set_HIT0_LO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); |
329 |
FORCE_RET(); |
330 |
} |
331 |
|
332 |
void op_mulhiu (void) |
333 |
{ |
334 |
set_HIT0_LO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); |
335 |
FORCE_RET(); |
336 |
} |
337 |
|
338 |
void op_mulshi (void) |
339 |
{ |
340 |
set_HIT0_LO(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
|
341 |
FORCE_RET(); |
342 |
} |
343 |
|
344 |
void op_mulshiu (void) |
345 |
{ |
346 |
set_HIT0_LO(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
|
347 |
FORCE_RET(); |
348 |
} |
349 |
|
350 |
#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ |
351 |
|
352 |
#if defined(TARGET_MIPS64)
|
353 |
void op_dmult (void) |
354 |
{ |
355 |
CALL_FROM_TB4(muls64, &(env->LO[env->current_tc][0]), &(env->HI[env->current_tc][0]), T0, T1); |
356 |
FORCE_RET(); |
357 |
} |
358 |
|
359 |
void op_dmultu (void) |
360 |
{ |
361 |
CALL_FROM_TB4(mulu64, &(env->LO[env->current_tc][0]), &(env->HI[env->current_tc][0]), T0, T1); |
362 |
FORCE_RET(); |
363 |
} |
364 |
#endif
|
365 |
|
366 |
/* CP1 functions */
|
367 |
#if 0
|
368 |
# define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env)
|
369 |
#else
|
370 |
# define DEBUG_FPU_STATE() do { } while(0) |
371 |
#endif
|
372 |
|
373 |
/* Float support.
|
374 |
Single precition routines have a "s" suffix, double precision a
|
375 |
"d" suffix, 32bit integer "w", 64bit integer "l", paired singe "ps",
|
376 |
paired single lowwer "pl", paired single upper "pu". */
|
377 |
|
378 |
#define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void) |
379 |
|
380 |
FLOAT_OP(cvtd, s) |
381 |
{ |
382 |
CALL_FROM_TB0(do_float_cvtd_s); |
383 |
DEBUG_FPU_STATE(); |
384 |
FORCE_RET(); |
385 |
} |
386 |
FLOAT_OP(cvtd, w) |
387 |
{ |
388 |
CALL_FROM_TB0(do_float_cvtd_w); |
389 |
DEBUG_FPU_STATE(); |
390 |
FORCE_RET(); |
391 |
} |
392 |
FLOAT_OP(cvtd, l) |
393 |
{ |
394 |
CALL_FROM_TB0(do_float_cvtd_l); |
395 |
DEBUG_FPU_STATE(); |
396 |
FORCE_RET(); |
397 |
} |
398 |
FLOAT_OP(cvtl, d) |
399 |
{ |
400 |
CALL_FROM_TB0(do_float_cvtl_d); |
401 |
DEBUG_FPU_STATE(); |
402 |
FORCE_RET(); |
403 |
} |
404 |
FLOAT_OP(cvtl, s) |
405 |
{ |
406 |
CALL_FROM_TB0(do_float_cvtl_s); |
407 |
DEBUG_FPU_STATE(); |
408 |
FORCE_RET(); |
409 |
} |
410 |
FLOAT_OP(cvtps, s) |
411 |
{ |
412 |
WT2 = WT0; |
413 |
WTH2 = WT1; |
414 |
DEBUG_FPU_STATE(); |
415 |
FORCE_RET(); |
416 |
} |
417 |
FLOAT_OP(cvtps, pw) |
418 |
{ |
419 |
CALL_FROM_TB0(do_float_cvtps_pw); |
420 |
DEBUG_FPU_STATE(); |
421 |
FORCE_RET(); |
422 |
} |
423 |
FLOAT_OP(cvtpw, ps) |
424 |
{ |
425 |
CALL_FROM_TB0(do_float_cvtpw_ps); |
426 |
DEBUG_FPU_STATE(); |
427 |
FORCE_RET(); |
428 |
} |
429 |
FLOAT_OP(cvts, d) |
430 |
{ |
431 |
CALL_FROM_TB0(do_float_cvts_d); |
432 |
DEBUG_FPU_STATE(); |
433 |
FORCE_RET(); |
434 |
} |
435 |
FLOAT_OP(cvts, w) |
436 |
{ |
437 |
CALL_FROM_TB0(do_float_cvts_w); |
438 |
DEBUG_FPU_STATE(); |
439 |
FORCE_RET(); |
440 |
} |
441 |
FLOAT_OP(cvts, l) |
442 |
{ |
443 |
CALL_FROM_TB0(do_float_cvts_l); |
444 |
DEBUG_FPU_STATE(); |
445 |
FORCE_RET(); |
446 |
} |
447 |
FLOAT_OP(cvts, pl) |
448 |
{ |
449 |
CALL_FROM_TB0(do_float_cvts_pl); |
450 |
DEBUG_FPU_STATE(); |
451 |
FORCE_RET(); |
452 |
} |
453 |
FLOAT_OP(cvts, pu) |
454 |
{ |
455 |
CALL_FROM_TB0(do_float_cvts_pu); |
456 |
DEBUG_FPU_STATE(); |
457 |
FORCE_RET(); |
458 |
} |
459 |
FLOAT_OP(cvtw, s) |
460 |
{ |
461 |
CALL_FROM_TB0(do_float_cvtw_s); |
462 |
DEBUG_FPU_STATE(); |
463 |
FORCE_RET(); |
464 |
} |
465 |
FLOAT_OP(cvtw, d) |
466 |
{ |
467 |
CALL_FROM_TB0(do_float_cvtw_d); |
468 |
DEBUG_FPU_STATE(); |
469 |
FORCE_RET(); |
470 |
} |
471 |
|
472 |
FLOAT_OP(pll, ps) |
473 |
{ |
474 |
DT2 = ((uint64_t)WT0 << 32) | WT1;
|
475 |
DEBUG_FPU_STATE(); |
476 |
FORCE_RET(); |
477 |
} |
478 |
FLOAT_OP(plu, ps) |
479 |
{ |
480 |
DT2 = ((uint64_t)WT0 << 32) | WTH1;
|
481 |
DEBUG_FPU_STATE(); |
482 |
FORCE_RET(); |
483 |
} |
484 |
FLOAT_OP(pul, ps) |
485 |
{ |
486 |
DT2 = ((uint64_t)WTH0 << 32) | WT1;
|
487 |
DEBUG_FPU_STATE(); |
488 |
FORCE_RET(); |
489 |
} |
490 |
FLOAT_OP(puu, ps) |
491 |
{ |
492 |
DT2 = ((uint64_t)WTH0 << 32) | WTH1;
|
493 |
DEBUG_FPU_STATE(); |
494 |
FORCE_RET(); |
495 |
} |
496 |
|
497 |
#define FLOAT_ROUNDOP(op, ttype, stype) \
|
498 |
FLOAT_OP(op ## ttype, stype) \ |
499 |
{ \ |
500 |
CALL_FROM_TB0(do_float_ ## op ## ttype ## _ ## stype); \ |
501 |
DEBUG_FPU_STATE(); \ |
502 |
FORCE_RET(); \ |
503 |
} |
504 |
|
505 |
FLOAT_ROUNDOP(round, l, d) |
506 |
FLOAT_ROUNDOP(round, l, s) |
507 |
FLOAT_ROUNDOP(round, w, d) |
508 |
FLOAT_ROUNDOP(round, w, s) |
509 |
|
510 |
FLOAT_ROUNDOP(trunc, l, d) |
511 |
FLOAT_ROUNDOP(trunc, l, s) |
512 |
FLOAT_ROUNDOP(trunc, w, d) |
513 |
FLOAT_ROUNDOP(trunc, w, s) |
514 |
|
515 |
FLOAT_ROUNDOP(ceil, l, d) |
516 |
FLOAT_ROUNDOP(ceil, l, s) |
517 |
FLOAT_ROUNDOP(ceil, w, d) |
518 |
FLOAT_ROUNDOP(ceil, w, s) |
519 |
|
520 |
FLOAT_ROUNDOP(floor, l, d) |
521 |
FLOAT_ROUNDOP(floor, l, s) |
522 |
FLOAT_ROUNDOP(floor, w, d) |
523 |
FLOAT_ROUNDOP(floor, w, s) |
524 |
#undef FLOAR_ROUNDOP
|
525 |
|
526 |
FLOAT_OP(movf, d) |
527 |
{ |
528 |
if (!(env->fpu->fcr31 & PARAM1))
|
529 |
DT2 = DT0; |
530 |
DEBUG_FPU_STATE(); |
531 |
FORCE_RET(); |
532 |
} |
533 |
FLOAT_OP(movf, s) |
534 |
{ |
535 |
if (!(env->fpu->fcr31 & PARAM1))
|
536 |
WT2 = WT0; |
537 |
DEBUG_FPU_STATE(); |
538 |
FORCE_RET(); |
539 |
} |
540 |
FLOAT_OP(movf, ps) |
541 |
{ |
542 |
unsigned int mask = GET_FP_COND (env->fpu) >> PARAM1; |
543 |
if (!(mask & 1)) |
544 |
WT2 = WT0; |
545 |
if (!(mask & 2)) |
546 |
WTH2 = WTH0; |
547 |
DEBUG_FPU_STATE(); |
548 |
FORCE_RET(); |
549 |
} |
550 |
FLOAT_OP(movt, d) |
551 |
{ |
552 |
if (env->fpu->fcr31 & PARAM1)
|
553 |
DT2 = DT0; |
554 |
DEBUG_FPU_STATE(); |
555 |
FORCE_RET(); |
556 |
} |
557 |
FLOAT_OP(movt, s) |
558 |
{ |
559 |
if (env->fpu->fcr31 & PARAM1)
|
560 |
WT2 = WT0; |
561 |
DEBUG_FPU_STATE(); |
562 |
FORCE_RET(); |
563 |
} |
564 |
FLOAT_OP(movt, ps) |
565 |
{ |
566 |
unsigned int mask = GET_FP_COND (env->fpu) >> PARAM1; |
567 |
if (mask & 1) |
568 |
WT2 = WT0; |
569 |
if (mask & 2) |
570 |
WTH2 = WTH0; |
571 |
DEBUG_FPU_STATE(); |
572 |
FORCE_RET(); |
573 |
} |
574 |
FLOAT_OP(movz, d) |
575 |
{ |
576 |
if (!T0)
|
577 |
DT2 = DT0; |
578 |
DEBUG_FPU_STATE(); |
579 |
FORCE_RET(); |
580 |
} |
581 |
FLOAT_OP(movz, s) |
582 |
{ |
583 |
if (!T0)
|
584 |
WT2 = WT0; |
585 |
DEBUG_FPU_STATE(); |
586 |
FORCE_RET(); |
587 |
} |
588 |
FLOAT_OP(movz, ps) |
589 |
{ |
590 |
if (!T0) {
|
591 |
WT2 = WT0; |
592 |
WTH2 = WTH0; |
593 |
} |
594 |
DEBUG_FPU_STATE(); |
595 |
FORCE_RET(); |
596 |
} |
597 |
FLOAT_OP(movn, d) |
598 |
{ |
599 |
if (T0)
|
600 |
DT2 = DT0; |
601 |
DEBUG_FPU_STATE(); |
602 |
FORCE_RET(); |
603 |
} |
604 |
FLOAT_OP(movn, s) |
605 |
{ |
606 |
if (T0)
|
607 |
WT2 = WT0; |
608 |
DEBUG_FPU_STATE(); |
609 |
FORCE_RET(); |
610 |
} |
611 |
FLOAT_OP(movn, ps) |
612 |
{ |
613 |
if (T0) {
|
614 |
WT2 = WT0; |
615 |
WTH2 = WTH0; |
616 |
} |
617 |
DEBUG_FPU_STATE(); |
618 |
FORCE_RET(); |
619 |
} |
620 |
|
621 |
/* operations calling helpers, for s, d and ps */
|
622 |
#define FLOAT_HOP(name) \
|
623 |
FLOAT_OP(name, d) \ |
624 |
{ \ |
625 |
CALL_FROM_TB0(do_float_ ## name ## _d); \ |
626 |
DEBUG_FPU_STATE(); \ |
627 |
FORCE_RET(); \ |
628 |
} \ |
629 |
FLOAT_OP(name, s) \ |
630 |
{ \ |
631 |
CALL_FROM_TB0(do_float_ ## name ## _s); \ |
632 |
DEBUG_FPU_STATE(); \ |
633 |
FORCE_RET(); \ |
634 |
} \ |
635 |
FLOAT_OP(name, ps) \ |
636 |
{ \ |
637 |
CALL_FROM_TB0(do_float_ ## name ## _ps); \ |
638 |
DEBUG_FPU_STATE(); \ |
639 |
FORCE_RET(); \ |
640 |
} |
641 |
FLOAT_HOP(add) |
642 |
FLOAT_HOP(sub) |
643 |
FLOAT_HOP(mul) |
644 |
FLOAT_HOP(div) |
645 |
FLOAT_HOP(recip2) |
646 |
FLOAT_HOP(rsqrt2) |
647 |
FLOAT_HOP(rsqrt1) |
648 |
FLOAT_HOP(recip1) |
649 |
#undef FLOAT_HOP
|
650 |
|
651 |
/* operations calling helpers, for s and d */
|
652 |
#define FLOAT_HOP(name) \
|
653 |
FLOAT_OP(name, d) \ |
654 |
{ \ |
655 |
CALL_FROM_TB0(do_float_ ## name ## _d); \ |
656 |
DEBUG_FPU_STATE(); \ |
657 |
FORCE_RET(); \ |
658 |
} \ |
659 |
FLOAT_OP(name, s) \ |
660 |
{ \ |
661 |
CALL_FROM_TB0(do_float_ ## name ## _s); \ |
662 |
DEBUG_FPU_STATE(); \ |
663 |
FORCE_RET(); \ |
664 |
} |
665 |
FLOAT_HOP(rsqrt) |
666 |
FLOAT_HOP(recip) |
667 |
#undef FLOAT_HOP
|
668 |
|
669 |
/* operations calling helpers, for ps */
|
670 |
#define FLOAT_HOP(name) \
|
671 |
FLOAT_OP(name, ps) \ |
672 |
{ \ |
673 |
CALL_FROM_TB0(do_float_ ## name ## _ps); \ |
674 |
DEBUG_FPU_STATE(); \ |
675 |
FORCE_RET(); \ |
676 |
} |
677 |
FLOAT_HOP(addr) |
678 |
FLOAT_HOP(mulr) |
679 |
#undef FLOAT_HOP
|
680 |
|
681 |
/* ternary operations */
|
682 |
#define FLOAT_TERNOP(name1, name2) \
|
683 |
FLOAT_OP(name1 ## name2, d) \ |
684 |
{ \ |
685 |
FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status); \ |
686 |
FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status); \ |
687 |
DEBUG_FPU_STATE(); \ |
688 |
FORCE_RET(); \ |
689 |
} \ |
690 |
FLOAT_OP(name1 ## name2, s) \ |
691 |
{ \ |
692 |
FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ |
693 |
FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ |
694 |
DEBUG_FPU_STATE(); \ |
695 |
FORCE_RET(); \ |
696 |
} \ |
697 |
FLOAT_OP(name1 ## name2, ps) \ |
698 |
{ \ |
699 |
FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ |
700 |
FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \ |
701 |
FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ |
702 |
FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \ |
703 |
DEBUG_FPU_STATE(); \ |
704 |
FORCE_RET(); \ |
705 |
} |
706 |
FLOAT_TERNOP(mul, add) |
707 |
FLOAT_TERNOP(mul, sub) |
708 |
#undef FLOAT_TERNOP
|
709 |
|
710 |
/* negated ternary operations */
|
711 |
#define FLOAT_NTERNOP(name1, name2) \
|
712 |
FLOAT_OP(n ## name1 ## name2, d) \ |
713 |
{ \ |
714 |
FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status); \ |
715 |
FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status); \ |
716 |
FDT2 = float64_chs(FDT2); \ |
717 |
DEBUG_FPU_STATE(); \ |
718 |
FORCE_RET(); \ |
719 |
} \ |
720 |
FLOAT_OP(n ## name1 ## name2, s) \ |
721 |
{ \ |
722 |
FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ |
723 |
FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ |
724 |
FST2 = float32_chs(FST2); \ |
725 |
DEBUG_FPU_STATE(); \ |
726 |
FORCE_RET(); \ |
727 |
} \ |
728 |
FLOAT_OP(n ## name1 ## name2, ps) \ |
729 |
{ \ |
730 |
FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ |
731 |
FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \ |
732 |
FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ |
733 |
FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \ |
734 |
FST2 = float32_chs(FST2); \ |
735 |
FSTH2 = float32_chs(FSTH2); \ |
736 |
DEBUG_FPU_STATE(); \ |
737 |
FORCE_RET(); \ |
738 |
} |
739 |
FLOAT_NTERNOP(mul, add) |
740 |
FLOAT_NTERNOP(mul, sub) |
741 |
#undef FLOAT_NTERNOP
|
742 |
|
743 |
/* unary operations, modifying fp status */
|
744 |
#define FLOAT_UNOP(name) \
|
745 |
FLOAT_OP(name, d) \ |
746 |
{ \ |
747 |
FDT2 = float64_ ## name(FDT0, &env->fpu->fp_status); \ |
748 |
DEBUG_FPU_STATE(); \ |
749 |
FORCE_RET(); \ |
750 |
} \ |
751 |
FLOAT_OP(name, s) \ |
752 |
{ \ |
753 |
FST2 = float32_ ## name(FST0, &env->fpu->fp_status); \ |
754 |
DEBUG_FPU_STATE(); \ |
755 |
FORCE_RET(); \ |
756 |
} |
757 |
FLOAT_UNOP(sqrt) |
758 |
#undef FLOAT_UNOP
|
759 |
|
760 |
/* unary operations, not modifying fp status */
|
761 |
#define FLOAT_UNOP(name) \
|
762 |
FLOAT_OP(name, d) \ |
763 |
{ \ |
764 |
FDT2 = float64_ ## name(FDT0); \ |
765 |
DEBUG_FPU_STATE(); \ |
766 |
FORCE_RET(); \ |
767 |
} \ |
768 |
FLOAT_OP(name, s) \ |
769 |
{ \ |
770 |
FST2 = float32_ ## name(FST0); \ |
771 |
DEBUG_FPU_STATE(); \ |
772 |
FORCE_RET(); \ |
773 |
} \ |
774 |
FLOAT_OP(name, ps) \ |
775 |
{ \ |
776 |
FST2 = float32_ ## name(FST0); \ |
777 |
FSTH2 = float32_ ## name(FSTH0); \ |
778 |
DEBUG_FPU_STATE(); \ |
779 |
FORCE_RET(); \ |
780 |
} |
781 |
FLOAT_UNOP(abs) |
782 |
FLOAT_UNOP(chs) |
783 |
#undef FLOAT_UNOP
|
784 |
|
785 |
FLOAT_OP(mov, d) |
786 |
{ |
787 |
FDT2 = FDT0; |
788 |
DEBUG_FPU_STATE(); |
789 |
FORCE_RET(); |
790 |
} |
791 |
FLOAT_OP(mov, s) |
792 |
{ |
793 |
FST2 = FST0; |
794 |
DEBUG_FPU_STATE(); |
795 |
FORCE_RET(); |
796 |
} |
797 |
FLOAT_OP(mov, ps) |
798 |
{ |
799 |
FST2 = FST0; |
800 |
FSTH2 = FSTH0; |
801 |
DEBUG_FPU_STATE(); |
802 |
FORCE_RET(); |
803 |
} |
804 |
FLOAT_OP(alnv, ps) |
805 |
{ |
806 |
switch (T0 & 0x7) { |
807 |
case 0: |
808 |
FST2 = FST0; |
809 |
FSTH2 = FSTH0; |
810 |
break;
|
811 |
case 4: |
812 |
#ifdef TARGET_WORDS_BIGENDIAN
|
813 |
FSTH2 = FST0; |
814 |
FST2 = FSTH1; |
815 |
#else
|
816 |
FSTH2 = FST1; |
817 |
FST2 = FSTH0; |
818 |
#endif
|
819 |
break;
|
820 |
default: /* unpredictable */ |
821 |
break;
|
822 |
} |
823 |
DEBUG_FPU_STATE(); |
824 |
FORCE_RET(); |
825 |
} |
826 |
|
827 |
#ifdef CONFIG_SOFTFLOAT
|
828 |
#define clear_invalid() do { \ |
829 |
int flags = get_float_exception_flags(&env->fpu->fp_status); \
|
830 |
flags &= ~float_flag_invalid; \ |
831 |
set_float_exception_flags(flags, &env->fpu->fp_status); \ |
832 |
} while(0) |
833 |
#else
|
834 |
#define clear_invalid() do { } while(0) |
835 |
#endif
|
836 |
|
837 |
extern void dump_fpu_s(CPUState *env); |
838 |
|
839 |
#define CMP_OP(fmt, op) \
|
840 |
void OPPROTO op_cmp ## _ ## fmt ## _ ## op(void) \ |
841 |
{ \ |
842 |
CALL_FROM_TB1(do_cmp ## _ ## fmt ## _ ## op, PARAM1); \ |
843 |
DEBUG_FPU_STATE(); \ |
844 |
FORCE_RET(); \ |
845 |
} \ |
846 |
void OPPROTO op_cmpabs ## _ ## fmt ## _ ## op(void) \ |
847 |
{ \ |
848 |
CALL_FROM_TB1(do_cmpabs ## _ ## fmt ## _ ## op, PARAM1); \ |
849 |
DEBUG_FPU_STATE(); \ |
850 |
FORCE_RET(); \ |
851 |
} |
852 |
#define CMP_OPS(op) \
|
853 |
CMP_OP(d, op) \ |
854 |
CMP_OP(s, op) \ |
855 |
CMP_OP(ps, op) |
856 |
|
857 |
CMP_OPS(f) |
858 |
CMP_OPS(un) |
859 |
CMP_OPS(eq) |
860 |
CMP_OPS(ueq) |
861 |
CMP_OPS(olt) |
862 |
CMP_OPS(ult) |
863 |
CMP_OPS(ole) |
864 |
CMP_OPS(ule) |
865 |
CMP_OPS(sf) |
866 |
CMP_OPS(ngle) |
867 |
CMP_OPS(seq) |
868 |
CMP_OPS(ngl) |
869 |
CMP_OPS(lt) |
870 |
CMP_OPS(nge) |
871 |
CMP_OPS(le) |
872 |
CMP_OPS(ngt) |
873 |
#undef CMP_OPS
|
874 |
#undef CMP_OP
|
875 |
|
876 |
void op_bc1f (void) |
877 |
{ |
878 |
T0 = !!(~GET_FP_COND(env->fpu) & (0x1 << PARAM1));
|
879 |
DEBUG_FPU_STATE(); |
880 |
FORCE_RET(); |
881 |
} |
882 |
void op_bc1any2f (void) |
883 |
{ |
884 |
T0 = !!(~GET_FP_COND(env->fpu) & (0x3 << PARAM1));
|
885 |
DEBUG_FPU_STATE(); |
886 |
FORCE_RET(); |
887 |
} |
888 |
void op_bc1any4f (void) |
889 |
{ |
890 |
T0 = !!(~GET_FP_COND(env->fpu) & (0xf << PARAM1));
|
891 |
DEBUG_FPU_STATE(); |
892 |
FORCE_RET(); |
893 |
} |
894 |
|
895 |
void op_bc1t (void) |
896 |
{ |
897 |
T0 = !!(GET_FP_COND(env->fpu) & (0x1 << PARAM1));
|
898 |
DEBUG_FPU_STATE(); |
899 |
FORCE_RET(); |
900 |
} |
901 |
void op_bc1any2t (void) |
902 |
{ |
903 |
T0 = !!(GET_FP_COND(env->fpu) & (0x3 << PARAM1));
|
904 |
DEBUG_FPU_STATE(); |
905 |
FORCE_RET(); |
906 |
} |
907 |
void op_bc1any4t (void) |
908 |
{ |
909 |
T0 = !!(GET_FP_COND(env->fpu) & (0xf << PARAM1));
|
910 |
DEBUG_FPU_STATE(); |
911 |
FORCE_RET(); |
912 |
} |
913 |
|
914 |
void op_tlbwi (void) |
915 |
{ |
916 |
CALL_FROM_TB0(env->tlb->do_tlbwi); |
917 |
FORCE_RET(); |
918 |
} |
919 |
|
920 |
void op_tlbwr (void) |
921 |
{ |
922 |
CALL_FROM_TB0(env->tlb->do_tlbwr); |
923 |
FORCE_RET(); |
924 |
} |
925 |
|
926 |
void op_tlbp (void) |
927 |
{ |
928 |
CALL_FROM_TB0(env->tlb->do_tlbp); |
929 |
FORCE_RET(); |
930 |
} |
931 |
|
932 |
void op_tlbr (void) |
933 |
{ |
934 |
CALL_FROM_TB0(env->tlb->do_tlbr); |
935 |
FORCE_RET(); |
936 |
} |
937 |
|
938 |
/* Specials */
|
939 |
#if defined (CONFIG_USER_ONLY)
|
940 |
void op_tls_value (void) |
941 |
{ |
942 |
T0 = env->tls_value; |
943 |
} |
944 |
#endif
|
945 |
|
946 |
void op_pmon (void) |
947 |
{ |
948 |
CALL_FROM_TB1(do_pmon, PARAM1); |
949 |
FORCE_RET(); |
950 |
} |
951 |
|
952 |
void op_di (void) |
953 |
{ |
954 |
T0 = env->CP0_Status; |
955 |
env->CP0_Status = T0 & ~(1 << CP0St_IE);
|
956 |
CALL_FROM_TB1(cpu_mips_update_irq, env); |
957 |
FORCE_RET(); |
958 |
} |
959 |
|
960 |
void op_ei (void) |
961 |
{ |
962 |
T0 = env->CP0_Status; |
963 |
env->CP0_Status = T0 | (1 << CP0St_IE);
|
964 |
CALL_FROM_TB1(cpu_mips_update_irq, env); |
965 |
FORCE_RET(); |
966 |
} |
967 |
|
968 |
void op_trap (void) |
969 |
{ |
970 |
if (T0) {
|
971 |
CALL_FROM_TB1(do_raise_exception, EXCP_TRAP); |
972 |
} |
973 |
FORCE_RET(); |
974 |
} |
975 |
|
976 |
void op_debug (void) |
977 |
{ |
978 |
CALL_FROM_TB1(do_raise_exception, EXCP_DEBUG); |
979 |
FORCE_RET(); |
980 |
} |
981 |
|
982 |
void debug_pre_eret (void); |
983 |
void debug_post_eret (void); |
984 |
void op_eret (void) |
985 |
{ |
986 |
if (loglevel & CPU_LOG_EXEC)
|
987 |
CALL_FROM_TB0(debug_pre_eret); |
988 |
if (env->CP0_Status & (1 << CP0St_ERL)) { |
989 |
env->PC[env->current_tc] = env->CP0_ErrorEPC; |
990 |
env->CP0_Status &= ~(1 << CP0St_ERL);
|
991 |
} else {
|
992 |
env->PC[env->current_tc] = env->CP0_EPC; |
993 |
env->CP0_Status &= ~(1 << CP0St_EXL);
|
994 |
} |
995 |
CALL_FROM_TB1(compute_hflags, env); |
996 |
if (loglevel & CPU_LOG_EXEC)
|
997 |
CALL_FROM_TB0(debug_post_eret); |
998 |
env->CP0_LLAddr = 1;
|
999 |
FORCE_RET(); |
1000 |
} |
1001 |
|
1002 |
void op_deret (void) |
1003 |
{ |
1004 |
if (loglevel & CPU_LOG_EXEC)
|
1005 |
CALL_FROM_TB0(debug_pre_eret); |
1006 |
env->PC[env->current_tc] = env->CP0_DEPC; |
1007 |
env->hflags &= MIPS_HFLAG_DM; |
1008 |
CALL_FROM_TB1(compute_hflags, env); |
1009 |
if (loglevel & CPU_LOG_EXEC)
|
1010 |
CALL_FROM_TB0(debug_post_eret); |
1011 |
env->CP0_LLAddr = 1;
|
1012 |
FORCE_RET(); |
1013 |
} |
1014 |
|
1015 |
void op_rdhwr_cpunum(void) |
1016 |
{ |
1017 |
if ((env->hflags & MIPS_HFLAG_CP0) ||
|
1018 |
(env->CP0_HWREna & (1 << 0))) |
1019 |
T0 = env->CP0_EBase & 0x3ff;
|
1020 |
else
|
1021 |
CALL_FROM_TB1(do_raise_exception, EXCP_RI); |
1022 |
FORCE_RET(); |
1023 |
} |
1024 |
|
1025 |
void op_rdhwr_synci_step(void) |
1026 |
{ |
1027 |
if ((env->hflags & MIPS_HFLAG_CP0) ||
|
1028 |
(env->CP0_HWREna & (1 << 1))) |
1029 |
T0 = env->SYNCI_Step; |
1030 |
else
|
1031 |
CALL_FROM_TB1(do_raise_exception, EXCP_RI); |
1032 |
FORCE_RET(); |
1033 |
} |
1034 |
|
1035 |
void op_rdhwr_cc(void) |
1036 |
{ |
1037 |
if ((env->hflags & MIPS_HFLAG_CP0) ||
|
1038 |
(env->CP0_HWREna & (1 << 2))) |
1039 |
T0 = env->CP0_Count; |
1040 |
else
|
1041 |
CALL_FROM_TB1(do_raise_exception, EXCP_RI); |
1042 |
FORCE_RET(); |
1043 |
} |
1044 |
|
1045 |
void op_rdhwr_ccres(void) |
1046 |
{ |
1047 |
if ((env->hflags & MIPS_HFLAG_CP0) ||
|
1048 |
(env->CP0_HWREna & (1 << 3))) |
1049 |
T0 = env->CCRes; |
1050 |
else
|
1051 |
CALL_FROM_TB1(do_raise_exception, EXCP_RI); |
1052 |
FORCE_RET(); |
1053 |
} |
1054 |
|
1055 |
void op_save_state (void) |
1056 |
{ |
1057 |
env->hflags = PARAM1; |
1058 |
FORCE_RET(); |
1059 |
} |
1060 |
|
1061 |
void op_wait (void) |
1062 |
{ |
1063 |
env->halted = 1;
|
1064 |
CALL_FROM_TB1(do_raise_exception, EXCP_HLT); |
1065 |
FORCE_RET(); |
1066 |
} |
1067 |
|
1068 |
/* Bitfield operations. */
|
1069 |
void op_ext(void) |
1070 |
{ |
1071 |
unsigned int pos = PARAM1; |
1072 |
unsigned int size = PARAM2; |
1073 |
|
1074 |
T0 = (int32_t)((T1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0)); |
1075 |
FORCE_RET(); |
1076 |
} |
1077 |
|
1078 |
void op_ins(void) |
1079 |
{ |
1080 |
unsigned int pos = PARAM1; |
1081 |
unsigned int size = PARAM2; |
1082 |
target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos; |
1083 |
|
1084 |
T0 = (int32_t)((T0 & ~mask) | ((T1 << pos) & mask)); |
1085 |
FORCE_RET(); |
1086 |
} |
1087 |
|
1088 |
void op_wsbh(void) |
1089 |
{ |
1090 |
T0 = (int32_t)(((T1 << 8) & ~0x00FF00FF) | ((T1 >> 8) & 0x00FF00FF)); |
1091 |
FORCE_RET(); |
1092 |
} |
1093 |
|
1094 |
#if defined(TARGET_MIPS64)
|
1095 |
void op_dext(void) |
1096 |
{ |
1097 |
unsigned int pos = PARAM1; |
1098 |
unsigned int size = PARAM2; |
1099 |
|
1100 |
T0 = (T1 >> pos) & ((size < 64) ? ((1ULL << size) - 1) : ~0ULL); |
1101 |
FORCE_RET(); |
1102 |
} |
1103 |
|
1104 |
void op_dins(void) |
1105 |
{ |
1106 |
unsigned int pos = PARAM1; |
1107 |
unsigned int size = PARAM2; |
1108 |
target_ulong mask = ((size < 64) ? ((1ULL << size) - 1) : ~0ULL) << pos; |
1109 |
|
1110 |
T0 = (T0 & ~mask) | ((T1 << pos) & mask); |
1111 |
FORCE_RET(); |
1112 |
} |
1113 |
|
1114 |
void op_dsbh(void) |
1115 |
{ |
1116 |
T0 = ((T1 << 8) & ~0x00FF00FF00FF00FFULL) | ((T1 >> 8) & 0x00FF00FF00FF00FFULL); |
1117 |
FORCE_RET(); |
1118 |
} |
1119 |
|
1120 |
void op_dshd(void) |
1121 |
{ |
1122 |
T1 = ((T1 << 16) & ~0x0000FFFF0000FFFFULL) | ((T1 >> 16) & 0x0000FFFF0000FFFFULL); |
1123 |
T0 = (T1 << 32) | (T1 >> 32); |
1124 |
FORCE_RET(); |
1125 |
} |
1126 |
#endif
|