]> Git Repo - qemu.git/blame - target-mips/op_helper.c
Switch most MIPS logical and arithmetic instructions to TCG.
[qemu.git] / target-mips / op_helper.c
CommitLineData
6af0bf9c
FB
1/*
2 * MIPS emulation helpers for qemu.
5fafdf24 3 *
6af0bf9c
FB
4 * Copyright (c) 2004-2005 Jocelyn Mayer
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
2d0e944d 20#include <stdlib.h>
6af0bf9c
FB
21#include "exec.h"
22
05f778c8
TS
23#include "host-utils.h"
24
273af660
TS
25#ifdef __s390__
26# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL))
27#else
28# define GETPC() (__builtin_return_address(0))
29#endif
4ad40f36 30
6af0bf9c
FB
31/*****************************************************************************/
32/* Exceptions processing helpers */
6af0bf9c 33
6af0bf9c
FB
34void do_raise_exception_err (uint32_t exception, int error_code)
35{
36#if 1
37 if (logfile && exception < 0x100)
38 fprintf(logfile, "%s: %d %d\n", __func__, exception, error_code);
39#endif
40 env->exception_index = exception;
41 env->error_code = error_code;
42 T0 = 0;
43 cpu_loop_exit();
44}
45
6af0bf9c
FB
46void do_raise_exception (uint32_t exception)
47{
48 do_raise_exception_err(exception, 0);
49}
50
48d38ca5
TS
51void do_interrupt_restart (void)
52{
53 if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
54 !(env->CP0_Status & (1 << CP0St_ERL)) &&
55 !(env->hflags & MIPS_HFLAG_DM) &&
56 (env->CP0_Status & (1 << CP0St_IE)) &&
57 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) {
58 env->CP0_Cause &= ~(0x1f << CP0Ca_EC);
59 do_raise_exception(EXCP_EXT_INTERRUPT);
60 }
61}
62
4ad40f36
FB
63void do_restore_state (void *pc_ptr)
64{
a607922c
FB
65 TranslationBlock *tb;
66 unsigned long pc = (unsigned long) pc_ptr;
67
68 tb = tb_find_pc (pc);
69 if (tb) {
70 cpu_restore_state (tb, env, pc, NULL);
71 }
4ad40f36
FB
72}
73
d26bc211 74#if defined(TARGET_MIPS64)
c570fd16
TS
75#if TARGET_LONG_BITS > HOST_LONG_BITS
76/* Those might call libgcc functions. */
77void do_dsll (void)
78{
79 T0 = T0 << T1;
80}
81
82void do_dsll32 (void)
83{
84 T0 = T0 << (T1 + 32);
85}
86
87void do_dsra (void)
88{
89 T0 = (int64_t)T0 >> T1;
90}
91
92void do_dsra32 (void)
93{
94 T0 = (int64_t)T0 >> (T1 + 32);
95}
96
97void do_dsrl (void)
98{
99 T0 = T0 >> T1;
100}
101
102void do_dsrl32 (void)
103{
104 T0 = T0 >> (T1 + 32);
105}
106
107void do_drotr (void)
108{
109 target_ulong tmp;
110
111 if (T1) {
c6d6dd7c
TS
112 tmp = T0 << (0x40 - T1);
113 T0 = (T0 >> T1) | tmp;
5a63bcb2 114 }
c570fd16
TS
115}
116
117void do_drotr32 (void)
118{
119 target_ulong tmp;
120
c6d6dd7c
TS
121 tmp = T0 << (0x40 - (32 + T1));
122 T0 = (T0 >> (32 + T1)) | tmp;
c570fd16
TS
123}
124
125void do_dsllv (void)
126{
127 T0 = T1 << (T0 & 0x3F);
128}
129
130void do_dsrav (void)
131{
132 T0 = (int64_t)T1 >> (T0 & 0x3F);
133}
134
135void do_dsrlv (void)
136{
137 T0 = T1 >> (T0 & 0x3F);
138}
139
140void do_drotrv (void)
141{
142 target_ulong tmp;
143
144 T0 &= 0x3F;
145 if (T0) {
c6d6dd7c
TS
146 tmp = T1 << (0x40 - T0);
147 T0 = (T1 >> T0) | tmp;
c570fd16 148 } else
c6d6dd7c 149 T0 = T1;
c570fd16 150}
05f778c8
TS
151
152void do_dclo (void)
153{
154 T0 = clo64(T0);
155}
156
157void do_dclz (void)
158{
159 T0 = clz64(T0);
160}
161
c570fd16 162#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
d26bc211 163#endif /* TARGET_MIPS64 */
c570fd16 164
6af0bf9c 165/* 64 bits arithmetic for 32 bits hosts */
c570fd16 166#if TARGET_LONG_BITS > HOST_LONG_BITS
aa343735 167static always_inline uint64_t get_HILO (void)
6af0bf9c 168{
d0dc7dc3 169 return (env->HI[env->current_tc][0] << 32) | (uint32_t)env->LO[env->current_tc][0];
6af0bf9c
FB
170}
171
aa343735 172static always_inline void set_HILO (uint64_t HILO)
6af0bf9c 173{
d0dc7dc3
TS
174 env->LO[env->current_tc][0] = (int32_t)HILO;
175 env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
6af0bf9c
FB
176}
177
e9c71dd1
TS
178static always_inline void set_HIT0_LO (uint64_t HILO)
179{
d0dc7dc3
TS
180 env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF);
181 T0 = env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
e9c71dd1
TS
182}
183
184static always_inline void set_HI_LOT0 (uint64_t HILO)
185{
d0dc7dc3
TS
186 T0 = env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF);
187 env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
e9c71dd1
TS
188}
189
6af0bf9c
FB
190void do_mult (void)
191{
4ad40f36 192 set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
6af0bf9c
FB
193}
194
195void do_multu (void)
196{
c570fd16 197 set_HILO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
6af0bf9c
FB
198}
199
200void do_madd (void)
201{
202 int64_t tmp;
203
4ad40f36 204 tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
6af0bf9c
FB
205 set_HILO((int64_t)get_HILO() + tmp);
206}
207
208void do_maddu (void)
209{
210 uint64_t tmp;
211
c570fd16 212 tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
6af0bf9c
FB
213 set_HILO(get_HILO() + tmp);
214}
215
216void do_msub (void)
217{
218 int64_t tmp;
219
4ad40f36 220 tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
6af0bf9c
FB
221 set_HILO((int64_t)get_HILO() - tmp);
222}
223
224void do_msubu (void)
225{
226 uint64_t tmp;
227
c570fd16 228 tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
6af0bf9c
FB
229 set_HILO(get_HILO() - tmp);
230}
e9c71dd1
TS
231
232/* Multiplication variants of the vr54xx. */
233void do_muls (void)
234{
235 set_HI_LOT0(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
236}
237
238void do_mulsu (void)
239{
240 set_HI_LOT0(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
241}
242
243void do_macc (void)
244{
245 set_HI_LOT0(((int64_t)get_HILO()) + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
246}
247
248void do_macchi (void)
249{
250 set_HIT0_LO(((int64_t)get_HILO()) + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
251}
252
253void do_maccu (void)
254{
255 set_HI_LOT0(((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
256}
257
258void do_macchiu (void)
259{
260 set_HIT0_LO(((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
261}
262
263void do_msac (void)
264{
265 set_HI_LOT0(((int64_t)get_HILO()) - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
266}
267
268void do_msachi (void)
269{
270 set_HIT0_LO(((int64_t)get_HILO()) - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
271}
272
273void do_msacu (void)
274{
275 set_HI_LOT0(((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
276}
277
278void do_msachiu (void)
279{
280 set_HIT0_LO(((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
281}
282
283void do_mulhi (void)
284{
285 set_HIT0_LO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
286}
287
288void do_mulhiu (void)
289{
290 set_HIT0_LO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
291}
292
293void do_mulshi (void)
294{
295 set_HIT0_LO(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
296}
297
298void do_mulshiu (void)
299{
300 set_HIT0_LO(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
301}
302#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
6af0bf9c 303
5fafdf24 304#if defined(CONFIG_USER_ONLY)
873eb012 305void do_mfc0_random (void)
048f6b4d 306{
873eb012 307 cpu_abort(env, "mfc0 random\n");
048f6b4d 308}
873eb012
TS
309
310void do_mfc0_count (void)
311{
312 cpu_abort(env, "mfc0 count\n");
313}
314
8c0fdd85 315void cpu_mips_store_count(CPUState *env, uint32_t value)
048f6b4d 316{
8c0fdd85
TS
317 cpu_abort(env, "mtc0 count\n");
318}
319
320void cpu_mips_store_compare(CPUState *env, uint32_t value)
321{
322 cpu_abort(env, "mtc0 compare\n");
323}
324
42532189
TS
325void cpu_mips_start_count(CPUState *env)
326{
327 cpu_abort(env, "start count\n");
328}
329
330void cpu_mips_stop_count(CPUState *env)
331{
332 cpu_abort(env, "stop count\n");
333}
334
4de9b249
TS
335void cpu_mips_update_irq(CPUState *env)
336{
337 cpu_abort(env, "mtc0 status / mtc0 cause\n");
338}
339
8c0fdd85
TS
340void do_mtc0_status_debug(uint32_t old, uint32_t val)
341{
7a387fff 342 cpu_abort(env, "mtc0 status debug\n");
8c0fdd85
TS
343}
344
7a387fff 345void do_mtc0_status_irqraise_debug (void)
8c0fdd85 346{
7a387fff 347 cpu_abort(env, "mtc0 status irqraise debug\n");
048f6b4d
FB
348}
349
8c0fdd85
TS
350void cpu_mips_tlb_flush (CPUState *env, int flush_global)
351{
352 cpu_abort(env, "mips_tlb_flush\n");
353}
354
048f6b4d
FB
355#else
356
6af0bf9c 357/* CP0 helpers */
873eb012 358void do_mfc0_random (void)
6af0bf9c 359{
5dc4b744 360 T0 = (int32_t)cpu_mips_get_random(env);
873eb012 361}
6af0bf9c 362
873eb012
TS
363void do_mfc0_count (void)
364{
5dc4b744 365 T0 = (int32_t)cpu_mips_get_count(env);
6af0bf9c
FB
366}
367
8c0fdd85 368void do_mtc0_status_debug(uint32_t old, uint32_t val)
6af0bf9c 369{
f41c52f1
TS
370 fprintf(logfile, "Status %08x (%08x) => %08x (%08x) Cause %08x",
371 old, old & env->CP0_Cause & CP0Ca_IP_mask,
372 val, val & env->CP0_Cause & CP0Ca_IP_mask,
373 env->CP0_Cause);
623a930e
TS
374 switch (env->hflags & MIPS_HFLAG_KSU) {
375 case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break;
376 case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break;
377 case MIPS_HFLAG_KM: fputs("\n", logfile); break;
378 default: cpu_abort(env, "Invalid MMU mode!\n"); break;
379 }
8c0fdd85
TS
380}
381
382void do_mtc0_status_irqraise_debug(void)
383{
384 fprintf(logfile, "Raise pending IRQs\n");
6af0bf9c
FB
385}
386
6ea83fed
FB
387void fpu_handle_exception(void)
388{
389#ifdef CONFIG_SOFTFLOAT
ead9360e 390 int flags = get_float_exception_flags(&env->fpu->fp_status);
6ea83fed
FB
391 unsigned int cpuflags = 0, enable, cause = 0;
392
ead9360e 393 enable = GET_FP_ENABLE(env->fpu->fcr31);
6ea83fed 394
3b46e624 395 /* determine current flags */
6ea83fed
FB
396 if (flags & float_flag_invalid) {
397 cpuflags |= FP_INVALID;
398 cause |= FP_INVALID & enable;
399 }
400 if (flags & float_flag_divbyzero) {
3b46e624 401 cpuflags |= FP_DIV0;
6ea83fed
FB
402 cause |= FP_DIV0 & enable;
403 }
404 if (flags & float_flag_overflow) {
3b46e624 405 cpuflags |= FP_OVERFLOW;
6ea83fed
FB
406 cause |= FP_OVERFLOW & enable;
407 }
408 if (flags & float_flag_underflow) {
3b46e624 409 cpuflags |= FP_UNDERFLOW;
6ea83fed
FB
410 cause |= FP_UNDERFLOW & enable;
411 }
412 if (flags & float_flag_inexact) {
5fafdf24 413 cpuflags |= FP_INEXACT;
6ea83fed
FB
414 cause |= FP_INEXACT & enable;
415 }
ead9360e
TS
416 SET_FP_FLAGS(env->fpu->fcr31, cpuflags);
417 SET_FP_CAUSE(env->fpu->fcr31, cause);
6ea83fed 418#else
ead9360e
TS
419 SET_FP_FLAGS(env->fpu->fcr31, 0);
420 SET_FP_CAUSE(env->fpu->fcr31, 0);
6ea83fed
FB
421#endif
422}
6ea83fed 423
6af0bf9c 424/* TLB management */
814b9a47
TS
425void cpu_mips_tlb_flush (CPUState *env, int flush_global)
426{
427 /* Flush qemu's TLB and discard all shadowed entries. */
428 tlb_flush (env, flush_global);
ead9360e 429 env->tlb->tlb_in_use = env->tlb->nb_tlb;
814b9a47
TS
430}
431
29929e34 432static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
814b9a47
TS
433{
434 /* Discard entries from env->tlb[first] onwards. */
ead9360e
TS
435 while (env->tlb->tlb_in_use > first) {
436 r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
814b9a47
TS
437 }
438}
439
29929e34 440static void r4k_fill_tlb (int idx)
6af0bf9c 441{
29929e34 442 r4k_tlb_t *tlb;
6af0bf9c
FB
443
444 /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
ead9360e 445 tlb = &env->tlb->mmu.r4k.tlb[idx];
f2e9ebef 446 tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
d26bc211 447#if defined(TARGET_MIPS64)
e034e2c3 448 tlb->VPN &= env->SEGMask;
100ce988 449#endif
98c1b82b 450 tlb->ASID = env->CP0_EntryHi & 0xFF;
3b1c8be4 451 tlb->PageMask = env->CP0_PageMask;
6af0bf9c 452 tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
98c1b82b
PB
453 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
454 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
455 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
6af0bf9c 456 tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
98c1b82b
PB
457 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
458 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
459 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
6af0bf9c
FB
460 tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
461}
462
29929e34 463void r4k_do_tlbwi (void)
6af0bf9c 464{
814b9a47
TS
465 /* Discard cached TLB entries. We could avoid doing this if the
466 tlbwi is just upgrading access permissions on the current entry;
467 that might be a further win. */
ead9360e 468 r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
814b9a47 469
ead9360e
TS
470 r4k_invalidate_tlb(env, env->CP0_Index % env->tlb->nb_tlb, 0);
471 r4k_fill_tlb(env->CP0_Index % env->tlb->nb_tlb);
6af0bf9c
FB
472}
473
29929e34 474void r4k_do_tlbwr (void)
6af0bf9c
FB
475{
476 int r = cpu_mips_get_random(env);
477
29929e34
TS
478 r4k_invalidate_tlb(env, r, 1);
479 r4k_fill_tlb(r);
6af0bf9c
FB
480}
481
29929e34 482void r4k_do_tlbp (void)
6af0bf9c 483{
29929e34 484 r4k_tlb_t *tlb;
f2e9ebef 485 target_ulong mask;
6af0bf9c 486 target_ulong tag;
f2e9ebef 487 target_ulong VPN;
6af0bf9c
FB
488 uint8_t ASID;
489 int i;
490
3d9fb9fe 491 ASID = env->CP0_EntryHi & 0xFF;
ead9360e
TS
492 for (i = 0; i < env->tlb->nb_tlb; i++) {
493 tlb = &env->tlb->mmu.r4k.tlb[i];
f2e9ebef
TS
494 /* 1k pages are not supported. */
495 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
496 tag = env->CP0_EntryHi & ~mask;
497 VPN = tlb->VPN & ~mask;
6af0bf9c 498 /* Check ASID, virtual page number & size */
f2e9ebef 499 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
6af0bf9c 500 /* TLB match */
9c2149c8 501 env->CP0_Index = i;
6af0bf9c
FB
502 break;
503 }
504 }
ead9360e 505 if (i == env->tlb->nb_tlb) {
814b9a47 506 /* No match. Discard any shadow entries, if any of them match. */
ead9360e
TS
507 for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
508 tlb = &env->tlb->mmu.r4k.tlb[i];
f2e9ebef
TS
509 /* 1k pages are not supported. */
510 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
511 tag = env->CP0_EntryHi & ~mask;
512 VPN = tlb->VPN & ~mask;
814b9a47 513 /* Check ASID, virtual page number & size */
f2e9ebef 514 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
29929e34 515 r4k_mips_tlb_flush_extra (env, i);
814b9a47
TS
516 break;
517 }
518 }
519
9c2149c8 520 env->CP0_Index |= 0x80000000;
6af0bf9c
FB
521 }
522}
523
29929e34 524void r4k_do_tlbr (void)
6af0bf9c 525{
29929e34 526 r4k_tlb_t *tlb;
09c56b84 527 uint8_t ASID;
6af0bf9c 528
09c56b84 529 ASID = env->CP0_EntryHi & 0xFF;
ead9360e 530 tlb = &env->tlb->mmu.r4k.tlb[env->CP0_Index % env->tlb->nb_tlb];
4ad40f36
FB
531
532 /* If this will change the current ASID, flush qemu's TLB. */
814b9a47
TS
533 if (ASID != tlb->ASID)
534 cpu_mips_tlb_flush (env, 1);
535
ead9360e 536 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
4ad40f36 537
6af0bf9c 538 env->CP0_EntryHi = tlb->VPN | tlb->ASID;
3b1c8be4 539 env->CP0_PageMask = tlb->PageMask;
7495fd0f
TS
540 env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
541 (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
542 env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
543 (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
6af0bf9c 544}
6af0bf9c 545
048f6b4d
FB
546#endif /* !CONFIG_USER_ONLY */
547
c570fd16 548void dump_ldst (const unsigned char *func)
6af0bf9c
FB
549{
550 if (loglevel)
3594c774 551 fprintf(logfile, "%s => " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, T0, T1);
6af0bf9c
FB
552}
553
554void dump_sc (void)
555{
556 if (loglevel) {
3594c774 557 fprintf(logfile, "%s " TARGET_FMT_lx " at " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", __func__,
6af0bf9c
FB
558 T1, T0, env->CP0_LLAddr);
559 }
560}
561
f41c52f1 562void debug_pre_eret (void)
6af0bf9c 563{
f41c52f1 564 fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
ead9360e 565 env->PC[env->current_tc], env->CP0_EPC);
f41c52f1
TS
566 if (env->CP0_Status & (1 << CP0St_ERL))
567 fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
568 if (env->hflags & MIPS_HFLAG_DM)
569 fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
570 fputs("\n", logfile);
571}
572
573void debug_post_eret (void)
574{
744e0915 575 fprintf(logfile, " => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
ead9360e 576 env->PC[env->current_tc], env->CP0_EPC);
f41c52f1
TS
577 if (env->CP0_Status & (1 << CP0St_ERL))
578 fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
579 if (env->hflags & MIPS_HFLAG_DM)
580 fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
623a930e
TS
581 switch (env->hflags & MIPS_HFLAG_KSU) {
582 case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break;
583 case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break;
584 case MIPS_HFLAG_KM: fputs("\n", logfile); break;
585 default: cpu_abort(env, "Invalid MMU mode!\n"); break;
586 }
6af0bf9c
FB
587}
588
6af0bf9c
FB
589void do_pmon (int function)
590{
591 function /= 2;
592 switch (function) {
593 case 2: /* TODO: char inbyte(int waitflag); */
d0dc7dc3
TS
594 if (env->gpr[env->current_tc][4] == 0)
595 env->gpr[env->current_tc][2] = -1;
6af0bf9c
FB
596 /* Fall through */
597 case 11: /* TODO: char inbyte (void); */
d0dc7dc3 598 env->gpr[env->current_tc][2] = -1;
6af0bf9c
FB
599 break;
600 case 3:
601 case 12:
d0dc7dc3 602 printf("%c", (char)(env->gpr[env->current_tc][4] & 0xFF));
6af0bf9c
FB
603 break;
604 case 17:
605 break;
606 case 158:
607 {
d0dc7dc3 608 unsigned char *fmt = (void *)(unsigned long)env->gpr[env->current_tc][4];
6af0bf9c
FB
609 printf("%s", fmt);
610 }
611 break;
612 }
613}
e37e863f 614
5fafdf24 615#if !defined(CONFIG_USER_ONLY)
e37e863f 616
4ad40f36
FB
617static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
618
e37e863f 619#define MMUSUFFIX _mmu
4ad40f36 620#define ALIGNED_ONLY
e37e863f
FB
621
622#define SHIFT 0
623#include "softmmu_template.h"
624
625#define SHIFT 1
626#include "softmmu_template.h"
627
628#define SHIFT 2
629#include "softmmu_template.h"
630
631#define SHIFT 3
632#include "softmmu_template.h"
633
4ad40f36
FB
634static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
635{
636 env->CP0_BadVAddr = addr;
637 do_restore_state (retaddr);
638 do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
639}
640
6ebbf390 641void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
e37e863f
FB
642{
643 TranslationBlock *tb;
644 CPUState *saved_env;
645 unsigned long pc;
646 int ret;
647
648 /* XXX: hack to restore env in all cases, even if not called from
649 generated code */
650 saved_env = env;
651 env = cpu_single_env;
6ebbf390 652 ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
e37e863f
FB
653 if (ret) {
654 if (retaddr) {
655 /* now we have a real cpu fault */
656 pc = (unsigned long)retaddr;
657 tb = tb_find_pc(pc);
658 if (tb) {
659 /* the PC is inside the translated code. It means that we have
660 a virtual CPU fault */
661 cpu_restore_state(tb, env, pc, NULL);
662 }
663 }
664 do_raise_exception_err(env->exception_index, env->error_code);
665 }
666 env = saved_env;
667}
668
647de6ca
TS
669void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
670 int unused)
671{
672 if (is_exec)
673 do_raise_exception(EXCP_IBE);
674 else
675 do_raise_exception(EXCP_DBE);
676}
e37e863f 677#endif
fd4a04eb
TS
678
679/* Complex FPU operations which may need stack space. */
680
f090c9d4
PB
681#define FLOAT_ONE32 make_float32(0x3f8 << 20)
682#define FLOAT_ONE64 make_float64(0x3ffULL << 52)
683#define FLOAT_TWO32 make_float32(1 << 30)
684#define FLOAT_TWO64 make_float64(1ULL << 62)
54454097
TS
685#define FLOAT_QNAN32 0x7fbfffff
686#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
687#define FLOAT_SNAN32 0x7fffffff
688#define FLOAT_SNAN64 0x7fffffffffffffffULL
8dfdb87c 689
fd4a04eb
TS
690/* convert MIPS rounding mode in FCR31 to IEEE library */
691unsigned int ieee_rm[] = {
692 float_round_nearest_even,
693 float_round_to_zero,
694 float_round_up,
695 float_round_down
696};
697
698#define RESTORE_ROUNDING_MODE \
ead9360e 699 set_float_rounding_mode(ieee_rm[env->fpu->fcr31 & 3], &env->fpu->fp_status)
fd4a04eb 700
ead9360e 701void do_cfc1 (int reg)
fd4a04eb 702{
ead9360e
TS
703 switch (reg) {
704 case 0:
705 T0 = (int32_t)env->fpu->fcr0;
706 break;
707 case 25:
708 T0 = ((env->fpu->fcr31 >> 24) & 0xfe) | ((env->fpu->fcr31 >> 23) & 0x1);
709 break;
710 case 26:
711 T0 = env->fpu->fcr31 & 0x0003f07c;
712 break;
713 case 28:
714 T0 = (env->fpu->fcr31 & 0x00000f83) | ((env->fpu->fcr31 >> 22) & 0x4);
715 break;
716 default:
717 T0 = (int32_t)env->fpu->fcr31;
718 break;
719 }
720}
721
722void do_ctc1 (int reg)
723{
724 switch(reg) {
fd4a04eb
TS
725 case 25:
726 if (T0 & 0xffffff00)
727 return;
ead9360e 728 env->fpu->fcr31 = (env->fpu->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) |
fd4a04eb
TS
729 ((T0 & 0x1) << 23);
730 break;
731 case 26:
732 if (T0 & 0x007c0000)
733 return;
ead9360e 734 env->fpu->fcr31 = (env->fpu->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c);
fd4a04eb
TS
735 break;
736 case 28:
737 if (T0 & 0x007c0000)
738 return;
ead9360e 739 env->fpu->fcr31 = (env->fpu->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) |
fd4a04eb
TS
740 ((T0 & 0x4) << 22);
741 break;
742 case 31:
743 if (T0 & 0x007c0000)
744 return;
ead9360e 745 env->fpu->fcr31 = T0;
fd4a04eb
TS
746 break;
747 default:
748 return;
749 }
750 /* set rounding mode */
751 RESTORE_ROUNDING_MODE;
ead9360e
TS
752 set_float_exception_flags(0, &env->fpu->fp_status);
753 if ((GET_FP_ENABLE(env->fpu->fcr31) | 0x20) & GET_FP_CAUSE(env->fpu->fcr31))
fd4a04eb
TS
754 do_raise_exception(EXCP_FPE);
755}
756
aa343735 757static always_inline char ieee_ex_to_mips(char xcpt)
fd4a04eb
TS
758{
759 return (xcpt & float_flag_inexact) >> 5 |
760 (xcpt & float_flag_underflow) >> 3 |
761 (xcpt & float_flag_overflow) >> 1 |
762 (xcpt & float_flag_divbyzero) << 1 |
763 (xcpt & float_flag_invalid) << 4;
764}
765
aa343735 766static always_inline char mips_ex_to_ieee(char xcpt)
fd4a04eb
TS
767{
768 return (xcpt & FP_INEXACT) << 5 |
769 (xcpt & FP_UNDERFLOW) << 3 |
770 (xcpt & FP_OVERFLOW) << 1 |
771 (xcpt & FP_DIV0) >> 1 |
772 (xcpt & FP_INVALID) >> 4;
773}
774
aa343735 775static always_inline void update_fcr31(void)
fd4a04eb 776{
ead9360e 777 int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fpu->fp_status));
fd4a04eb 778
ead9360e
TS
779 SET_FP_CAUSE(env->fpu->fcr31, tmp);
780 if (GET_FP_ENABLE(env->fpu->fcr31) & tmp)
fd4a04eb
TS
781 do_raise_exception(EXCP_FPE);
782 else
ead9360e 783 UPDATE_FP_FLAGS(env->fpu->fcr31, tmp);
fd4a04eb
TS
784}
785
786#define FLOAT_OP(name, p) void do_float_##name##_##p(void)
787
788FLOAT_OP(cvtd, s)
789{
ead9360e
TS
790 set_float_exception_flags(0, &env->fpu->fp_status);
791 FDT2 = float32_to_float64(FST0, &env->fpu->fp_status);
fd4a04eb
TS
792 update_fcr31();
793}
794FLOAT_OP(cvtd, w)
795{
ead9360e
TS
796 set_float_exception_flags(0, &env->fpu->fp_status);
797 FDT2 = int32_to_float64(WT0, &env->fpu->fp_status);
fd4a04eb
TS
798 update_fcr31();
799}
800FLOAT_OP(cvtd, l)
801{
ead9360e
TS
802 set_float_exception_flags(0, &env->fpu->fp_status);
803 FDT2 = int64_to_float64(DT0, &env->fpu->fp_status);
fd4a04eb
TS
804 update_fcr31();
805}
806FLOAT_OP(cvtl, d)
807{
ead9360e
TS
808 set_float_exception_flags(0, &env->fpu->fp_status);
809 DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
fd4a04eb 810 update_fcr31();
ead9360e 811 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 812 DT2 = FLOAT_SNAN64;
fd4a04eb
TS
813}
814FLOAT_OP(cvtl, s)
815{
ead9360e
TS
816 set_float_exception_flags(0, &env->fpu->fp_status);
817 DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
fd4a04eb 818 update_fcr31();
ead9360e 819 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 820 DT2 = FLOAT_SNAN64;
fd4a04eb
TS
821}
822
823FLOAT_OP(cvtps, pw)
824{
ead9360e
TS
825 set_float_exception_flags(0, &env->fpu->fp_status);
826 FST2 = int32_to_float32(WT0, &env->fpu->fp_status);
827 FSTH2 = int32_to_float32(WTH0, &env->fpu->fp_status);
fd4a04eb
TS
828 update_fcr31();
829}
830FLOAT_OP(cvtpw, ps)
831{
ead9360e
TS
832 set_float_exception_flags(0, &env->fpu->fp_status);
833 WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
834 WTH2 = float32_to_int32(FSTH0, &env->fpu->fp_status);
fd4a04eb 835 update_fcr31();
ead9360e 836 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 837 WT2 = FLOAT_SNAN32;
fd4a04eb
TS
838}
839FLOAT_OP(cvts, d)
840{
ead9360e
TS
841 set_float_exception_flags(0, &env->fpu->fp_status);
842 FST2 = float64_to_float32(FDT0, &env->fpu->fp_status);
fd4a04eb
TS
843 update_fcr31();
844}
845FLOAT_OP(cvts, w)
846{
ead9360e
TS
847 set_float_exception_flags(0, &env->fpu->fp_status);
848 FST2 = int32_to_float32(WT0, &env->fpu->fp_status);
fd4a04eb
TS
849 update_fcr31();
850}
851FLOAT_OP(cvts, l)
852{
ead9360e
TS
853 set_float_exception_flags(0, &env->fpu->fp_status);
854 FST2 = int64_to_float32(DT0, &env->fpu->fp_status);
fd4a04eb
TS
855 update_fcr31();
856}
857FLOAT_OP(cvts, pl)
858{
ead9360e 859 set_float_exception_flags(0, &env->fpu->fp_status);
fd4a04eb
TS
860 WT2 = WT0;
861 update_fcr31();
862}
863FLOAT_OP(cvts, pu)
864{
ead9360e 865 set_float_exception_flags(0, &env->fpu->fp_status);
fd4a04eb
TS
866 WT2 = WTH0;
867 update_fcr31();
868}
869FLOAT_OP(cvtw, s)
870{
ead9360e
TS
871 set_float_exception_flags(0, &env->fpu->fp_status);
872 WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
fd4a04eb 873 update_fcr31();
ead9360e 874 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 875 WT2 = FLOAT_SNAN32;
fd4a04eb
TS
876}
877FLOAT_OP(cvtw, d)
878{
ead9360e
TS
879 set_float_exception_flags(0, &env->fpu->fp_status);
880 WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
fd4a04eb 881 update_fcr31();
ead9360e 882 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 883 WT2 = FLOAT_SNAN32;
fd4a04eb
TS
884}
885
886FLOAT_OP(roundl, d)
887{
ead9360e
TS
888 set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
889 DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
fd4a04eb
TS
890 RESTORE_ROUNDING_MODE;
891 update_fcr31();
ead9360e 892 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 893 DT2 = FLOAT_SNAN64;
fd4a04eb
TS
894}
895FLOAT_OP(roundl, s)
896{
ead9360e
TS
897 set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
898 DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
fd4a04eb
TS
899 RESTORE_ROUNDING_MODE;
900 update_fcr31();
ead9360e 901 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 902 DT2 = FLOAT_SNAN64;
fd4a04eb
TS
903}
904FLOAT_OP(roundw, d)
905{
ead9360e
TS
906 set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
907 WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
fd4a04eb
TS
908 RESTORE_ROUNDING_MODE;
909 update_fcr31();
ead9360e 910 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 911 WT2 = FLOAT_SNAN32;
fd4a04eb
TS
912}
913FLOAT_OP(roundw, s)
914{
ead9360e
TS
915 set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
916 WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
fd4a04eb
TS
917 RESTORE_ROUNDING_MODE;
918 update_fcr31();
ead9360e 919 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 920 WT2 = FLOAT_SNAN32;
fd4a04eb
TS
921}
922
923FLOAT_OP(truncl, d)
924{
ead9360e 925 DT2 = float64_to_int64_round_to_zero(FDT0, &env->fpu->fp_status);
fd4a04eb 926 update_fcr31();
ead9360e 927 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 928 DT2 = FLOAT_SNAN64;
fd4a04eb
TS
929}
930FLOAT_OP(truncl, s)
931{
ead9360e 932 DT2 = float32_to_int64_round_to_zero(FST0, &env->fpu->fp_status);
fd4a04eb 933 update_fcr31();
ead9360e 934 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 935 DT2 = FLOAT_SNAN64;
fd4a04eb
TS
936}
937FLOAT_OP(truncw, d)
938{
ead9360e 939 WT2 = float64_to_int32_round_to_zero(FDT0, &env->fpu->fp_status);
fd4a04eb 940 update_fcr31();
ead9360e 941 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 942 WT2 = FLOAT_SNAN32;
fd4a04eb
TS
943}
944FLOAT_OP(truncw, s)
945{
ead9360e 946 WT2 = float32_to_int32_round_to_zero(FST0, &env->fpu->fp_status);
fd4a04eb 947 update_fcr31();
ead9360e 948 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 949 WT2 = FLOAT_SNAN32;
fd4a04eb
TS
950}
951
952FLOAT_OP(ceill, d)
953{
ead9360e
TS
954 set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
955 DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
fd4a04eb
TS
956 RESTORE_ROUNDING_MODE;
957 update_fcr31();
ead9360e 958 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 959 DT2 = FLOAT_SNAN64;
fd4a04eb
TS
960}
961FLOAT_OP(ceill, s)
962{
ead9360e
TS
963 set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
964 DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
fd4a04eb
TS
965 RESTORE_ROUNDING_MODE;
966 update_fcr31();
ead9360e 967 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 968 DT2 = FLOAT_SNAN64;
fd4a04eb
TS
969}
970FLOAT_OP(ceilw, d)
971{
ead9360e
TS
972 set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
973 WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
fd4a04eb
TS
974 RESTORE_ROUNDING_MODE;
975 update_fcr31();
ead9360e 976 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 977 WT2 = FLOAT_SNAN32;
fd4a04eb
TS
978}
979FLOAT_OP(ceilw, s)
980{
ead9360e
TS
981 set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
982 WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
fd4a04eb
TS
983 RESTORE_ROUNDING_MODE;
984 update_fcr31();
ead9360e 985 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 986 WT2 = FLOAT_SNAN32;
fd4a04eb
TS
987}
988
989FLOAT_OP(floorl, d)
990{
ead9360e
TS
991 set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
992 DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
fd4a04eb
TS
993 RESTORE_ROUNDING_MODE;
994 update_fcr31();
ead9360e 995 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 996 DT2 = FLOAT_SNAN64;
fd4a04eb
TS
997}
998FLOAT_OP(floorl, s)
999{
ead9360e
TS
1000 set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
1001 DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
fd4a04eb
TS
1002 RESTORE_ROUNDING_MODE;
1003 update_fcr31();
ead9360e 1004 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 1005 DT2 = FLOAT_SNAN64;
fd4a04eb
TS
1006}
1007FLOAT_OP(floorw, d)
1008{
ead9360e
TS
1009 set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
1010 WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
fd4a04eb
TS
1011 RESTORE_ROUNDING_MODE;
1012 update_fcr31();
ead9360e 1013 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 1014 WT2 = FLOAT_SNAN32;
fd4a04eb
TS
1015}
1016FLOAT_OP(floorw, s)
1017{
ead9360e
TS
1018 set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
1019 WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
fd4a04eb
TS
1020 RESTORE_ROUNDING_MODE;
1021 update_fcr31();
ead9360e 1022 if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
54454097 1023 WT2 = FLOAT_SNAN32;
fd4a04eb
TS
1024}
1025
8dfdb87c
TS
1026/* MIPS specific unary operations */
1027FLOAT_OP(recip, d)
1028{
ead9360e
TS
1029 set_float_exception_flags(0, &env->fpu->fp_status);
1030 FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status);
8dfdb87c
TS
1031 update_fcr31();
1032}
1033FLOAT_OP(recip, s)
1034{
ead9360e
TS
1035 set_float_exception_flags(0, &env->fpu->fp_status);
1036 FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
8dfdb87c 1037 update_fcr31();
57fa1fb3 1038}
57fa1fb3 1039
8dfdb87c
TS
1040FLOAT_OP(rsqrt, d)
1041{
ead9360e
TS
1042 set_float_exception_flags(0, &env->fpu->fp_status);
1043 FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status);
1044 FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status);
8dfdb87c
TS
1045 update_fcr31();
1046}
1047FLOAT_OP(rsqrt, s)
1048{
ead9360e
TS
1049 set_float_exception_flags(0, &env->fpu->fp_status);
1050 FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
1051 FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
8dfdb87c
TS
1052 update_fcr31();
1053}
1054
1055FLOAT_OP(recip1, d)
1056{
ead9360e
TS
1057 set_float_exception_flags(0, &env->fpu->fp_status);
1058 FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status);
8dfdb87c
TS
1059 update_fcr31();
1060}
1061FLOAT_OP(recip1, s)
1062{
ead9360e
TS
1063 set_float_exception_flags(0, &env->fpu->fp_status);
1064 FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
8dfdb87c
TS
1065 update_fcr31();
1066}
1067FLOAT_OP(recip1, ps)
1068{
ead9360e
TS
1069 set_float_exception_flags(0, &env->fpu->fp_status);
1070 FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
1071 FSTH2 = float32_div(FLOAT_ONE32, FSTH0, &env->fpu->fp_status);
8dfdb87c
TS
1072 update_fcr31();
1073}
1074
1075FLOAT_OP(rsqrt1, d)
1076{
ead9360e
TS
1077 set_float_exception_flags(0, &env->fpu->fp_status);
1078 FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status);
1079 FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status);
8dfdb87c
TS
1080 update_fcr31();
1081}
1082FLOAT_OP(rsqrt1, s)
1083{
ead9360e
TS
1084 set_float_exception_flags(0, &env->fpu->fp_status);
1085 FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
1086 FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
8dfdb87c
TS
1087 update_fcr31();
1088}
1089FLOAT_OP(rsqrt1, ps)
1090{
ead9360e
TS
1091 set_float_exception_flags(0, &env->fpu->fp_status);
1092 FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
1093 FSTH2 = float32_sqrt(FSTH0, &env->fpu->fp_status);
1094 FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
1095 FSTH2 = float32_div(FLOAT_ONE32, FSTH2, &env->fpu->fp_status);
8dfdb87c 1096 update_fcr31();
57fa1fb3 1097}
57fa1fb3 1098
fd4a04eb
TS
1099/* binary operations */
1100#define FLOAT_BINOP(name) \
1101FLOAT_OP(name, d) \
1102{ \
ead9360e
TS
1103 set_float_exception_flags(0, &env->fpu->fp_status); \
1104 FDT2 = float64_ ## name (FDT0, FDT1, &env->fpu->fp_status); \
1105 update_fcr31(); \
1106 if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \
5747c073 1107 DT2 = FLOAT_QNAN64; \
fd4a04eb
TS
1108} \
1109FLOAT_OP(name, s) \
1110{ \
ead9360e
TS
1111 set_float_exception_flags(0, &env->fpu->fp_status); \
1112 FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status); \
1113 update_fcr31(); \
1114 if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \
5747c073 1115 WT2 = FLOAT_QNAN32; \
fd4a04eb
TS
1116} \
1117FLOAT_OP(name, ps) \
1118{ \
ead9360e
TS
1119 set_float_exception_flags(0, &env->fpu->fp_status); \
1120 FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status); \
1121 FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fpu->fp_status); \
fd4a04eb 1122 update_fcr31(); \
ead9360e 1123 if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) { \
5747c073
PB
1124 WT2 = FLOAT_QNAN32; \
1125 WTH2 = FLOAT_QNAN32; \
3a5b360d 1126 } \
fd4a04eb
TS
1127}
1128FLOAT_BINOP(add)
1129FLOAT_BINOP(sub)
1130FLOAT_BINOP(mul)
1131FLOAT_BINOP(div)
1132#undef FLOAT_BINOP
1133
8dfdb87c
TS
1134/* MIPS specific binary operations */
1135FLOAT_OP(recip2, d)
1136{
ead9360e
TS
1137 set_float_exception_flags(0, &env->fpu->fp_status);
1138 FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status);
5747c073 1139 FDT2 = float64_chs(float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status));
8dfdb87c
TS
1140 update_fcr31();
1141}
1142FLOAT_OP(recip2, s)
1143{
ead9360e
TS
1144 set_float_exception_flags(0, &env->fpu->fp_status);
1145 FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
5747c073 1146 FST2 = float32_chs(float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status));
8dfdb87c
TS
1147 update_fcr31();
1148}
1149FLOAT_OP(recip2, ps)
1150{
ead9360e
TS
1151 set_float_exception_flags(0, &env->fpu->fp_status);
1152 FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
1153 FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status);
5747c073
PB
1154 FST2 = float32_chs(float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status));
1155 FSTH2 = float32_chs(float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status));
8dfdb87c
TS
1156 update_fcr31();
1157}
1158
1159FLOAT_OP(rsqrt2, d)
1160{
ead9360e
TS
1161 set_float_exception_flags(0, &env->fpu->fp_status);
1162 FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status);
1163 FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status);
5747c073 1164 FDT2 = float64_chs(float64_div(FDT2, FLOAT_TWO64, &env->fpu->fp_status));
8dfdb87c
TS
1165 update_fcr31();
1166}
1167FLOAT_OP(rsqrt2, s)
1168{
ead9360e
TS
1169 set_float_exception_flags(0, &env->fpu->fp_status);
1170 FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
1171 FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status);
5747c073 1172 FST2 = float32_chs(float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status));
8dfdb87c
TS
1173 update_fcr31();
1174}
1175FLOAT_OP(rsqrt2, ps)
1176{
ead9360e
TS
1177 set_float_exception_flags(0, &env->fpu->fp_status);
1178 FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
1179 FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status);
1180 FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status);
1181 FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status);
5747c073
PB
1182 FST2 = float32_chs(float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status));
1183 FSTH2 = float32_chs(float32_div(FSTH2, FLOAT_TWO32, &env->fpu->fp_status));
8dfdb87c 1184 update_fcr31();
57fa1fb3 1185}
57fa1fb3 1186
fd4a04eb
TS
1187FLOAT_OP(addr, ps)
1188{
ead9360e
TS
1189 set_float_exception_flags(0, &env->fpu->fp_status);
1190 FST2 = float32_add (FST0, FSTH0, &env->fpu->fp_status);
1191 FSTH2 = float32_add (FST1, FSTH1, &env->fpu->fp_status);
fd4a04eb
TS
1192 update_fcr31();
1193}
1194
57fa1fb3
TS
1195FLOAT_OP(mulr, ps)
1196{
ead9360e
TS
1197 set_float_exception_flags(0, &env->fpu->fp_status);
1198 FST2 = float32_mul (FST0, FSTH0, &env->fpu->fp_status);
1199 FSTH2 = float32_mul (FST1, FSTH1, &env->fpu->fp_status);
57fa1fb3
TS
1200 update_fcr31();
1201}
1202
8dfdb87c 1203/* compare operations */
fd4a04eb
TS
1204#define FOP_COND_D(op, cond) \
1205void do_cmp_d_ ## op (long cc) \
1206{ \
1207 int c = cond; \
1208 update_fcr31(); \
1209 if (c) \
ead9360e 1210 SET_FP_COND(cc, env->fpu); \
fd4a04eb 1211 else \
ead9360e 1212 CLEAR_FP_COND(cc, env->fpu); \
fd4a04eb
TS
1213} \
1214void do_cmpabs_d_ ## op (long cc) \
1215{ \
1216 int c; \
6b5435d7
TS
1217 FDT0 = float64_abs(FDT0); \
1218 FDT1 = float64_abs(FDT1); \
fd4a04eb
TS
1219 c = cond; \
1220 update_fcr31(); \
1221 if (c) \
ead9360e 1222 SET_FP_COND(cc, env->fpu); \
fd4a04eb 1223 else \
ead9360e 1224 CLEAR_FP_COND(cc, env->fpu); \
fd4a04eb
TS
1225}
1226
1227int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
1228{
1229 if (float64_is_signaling_nan(a) ||
1230 float64_is_signaling_nan(b) ||
1231 (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
1232 float_raise(float_flag_invalid, status);
1233 return 1;
1234 } else if (float64_is_nan(a) || float64_is_nan(b)) {
1235 return 1;
1236 } else {
1237 return 0;
1238 }
1239}
1240
1241/* NOTE: the comma operator will make "cond" to eval to false,
1242 * but float*_is_unordered() is still called. */
ead9360e
TS
1243FOP_COND_D(f, (float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status), 0))
1244FOP_COND_D(un, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status))
1245FOP_COND_D(eq, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status))
1246FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) || float64_eq(FDT0, FDT1, &env->fpu->fp_status))
1247FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status))
1248FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) || float64_lt(FDT0, FDT1, &env->fpu->fp_status))
1249FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status))
1250FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) || float64_le(FDT0, FDT1, &env->fpu->fp_status))
fd4a04eb
TS
1251/* NOTE: the comma operator will make "cond" to eval to false,
1252 * but float*_is_unordered() is still called. */
ead9360e
TS
1253FOP_COND_D(sf, (float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status), 0))
1254FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status))
1255FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status))
1256FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) || float64_eq(FDT0, FDT1, &env->fpu->fp_status))
1257FOP_COND_D(lt, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status))
1258FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) || float64_lt(FDT0, FDT1, &env->fpu->fp_status))
1259FOP_COND_D(le, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status))
1260FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) || float64_le(FDT0, FDT1, &env->fpu->fp_status))
fd4a04eb
TS
1261
1262#define FOP_COND_S(op, cond) \
1263void do_cmp_s_ ## op (long cc) \
1264{ \
1265 int c = cond; \
1266 update_fcr31(); \
1267 if (c) \
ead9360e 1268 SET_FP_COND(cc, env->fpu); \
fd4a04eb 1269 else \
ead9360e 1270 CLEAR_FP_COND(cc, env->fpu); \
fd4a04eb
TS
1271} \
1272void do_cmpabs_s_ ## op (long cc) \
1273{ \
1274 int c; \
5747c073
PB
1275 FST0 = float32_abs(FST0); \
1276 FST1 = float32_abs(FST1); \
fd4a04eb
TS
1277 c = cond; \
1278 update_fcr31(); \
1279 if (c) \
ead9360e 1280 SET_FP_COND(cc, env->fpu); \
fd4a04eb 1281 else \
ead9360e 1282 CLEAR_FP_COND(cc, env->fpu); \
fd4a04eb
TS
1283}
1284
1285flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
1286{
fd4a04eb
TS
1287 if (float32_is_signaling_nan(a) ||
1288 float32_is_signaling_nan(b) ||
1289 (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
1290 float_raise(float_flag_invalid, status);
1291 return 1;
1292 } else if (float32_is_nan(a) || float32_is_nan(b)) {
1293 return 1;
1294 } else {
1295 return 0;
1296 }
1297}
1298
1299/* NOTE: the comma operator will make "cond" to eval to false,
1300 * but float*_is_unordered() is still called. */
ead9360e
TS
1301FOP_COND_S(f, (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0))
1302FOP_COND_S(un, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status))
1303FOP_COND_S(eq, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status))
1304FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status))
1305FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status))
1306FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status))
1307FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status))
1308FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status))
fd4a04eb
TS
1309/* NOTE: the comma operator will make "cond" to eval to false,
1310 * but float*_is_unordered() is still called. */
ead9360e
TS
1311FOP_COND_S(sf, (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0))
1312FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status))
1313FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status))
1314FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status))
1315FOP_COND_S(lt, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status))
1316FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status))
1317FOP_COND_S(le, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status))
1318FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status))
fd4a04eb
TS
1319
1320#define FOP_COND_PS(op, condl, condh) \
1321void do_cmp_ps_ ## op (long cc) \
1322{ \
1323 int cl = condl; \
1324 int ch = condh; \
1325 update_fcr31(); \
1326 if (cl) \
ead9360e 1327 SET_FP_COND(cc, env->fpu); \
fd4a04eb 1328 else \
ead9360e 1329 CLEAR_FP_COND(cc, env->fpu); \
fd4a04eb 1330 if (ch) \
ead9360e 1331 SET_FP_COND(cc + 1, env->fpu); \
fd4a04eb 1332 else \
ead9360e 1333 CLEAR_FP_COND(cc + 1, env->fpu); \
fd4a04eb
TS
1334} \
1335void do_cmpabs_ps_ ## op (long cc) \
1336{ \
1337 int cl, ch; \
5747c073
PB
1338 FST0 = float32_abs(FST0); \
1339 FSTH0 = float32_abs(FSTH0); \
1340 FST1 = float32_abs(FST1); \
1341 FSTH1 = float32_abs(FSTH1); \
fd4a04eb
TS
1342 cl = condl; \
1343 ch = condh; \
1344 update_fcr31(); \
1345 if (cl) \
ead9360e 1346 SET_FP_COND(cc, env->fpu); \
fd4a04eb 1347 else \
ead9360e 1348 CLEAR_FP_COND(cc, env->fpu); \
fd4a04eb 1349 if (ch) \
ead9360e 1350 SET_FP_COND(cc + 1, env->fpu); \
fd4a04eb 1351 else \
ead9360e 1352 CLEAR_FP_COND(cc + 1, env->fpu); \
fd4a04eb
TS
1353}
1354
1355/* NOTE: the comma operator will make "cond" to eval to false,
1356 * but float*_is_unordered() is still called. */
ead9360e
TS
1357FOP_COND_PS(f, (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0),
1358 (float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status), 0))
1359FOP_COND_PS(un, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status),
1360 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status))
1361FOP_COND_PS(eq, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status),
1362 !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
1363FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status),
1364 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
1365FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status),
1366 !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
1367FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status),
1368 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
1369FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status),
1370 !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
1371FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status),
1372 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) || float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
fd4a04eb
TS
1373/* NOTE: the comma operator will make "cond" to eval to false,
1374 * but float*_is_unordered() is still called. */
ead9360e
TS
1375FOP_COND_PS(sf, (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0),
1376 (float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status), 0))
1377FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status),
1378 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status))
1379FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status),
1380 !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
1381FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status),
1382 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
1383FOP_COND_PS(lt, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status),
1384 !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
1385FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status),
1386 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
1387FOP_COND_PS(le, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status),
1388 !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
1389FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status),
1390 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) || float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
This page took 0.391248 seconds and 4 git commands to generate.