Pass T0/T1 explicitly to helper functions, and clean up a few dyngen
[qemu] / target-mips / op_helper.c
1 /*
2  *  MIPS emulation helpers for qemu.
3  *
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  */
20 #include <stdlib.h>
21 #include "exec.h"
22
23 #include "host-utils.h"
24
25 /*****************************************************************************/
26 /* Exceptions processing helpers */
27
28 void do_raise_exception_err (uint32_t exception, int error_code)
29 {
30 #if 1
31     if (logfile && exception < 0x100)
32         fprintf(logfile, "%s: %d %d\n", __func__, exception, error_code);
33 #endif
34     env->exception_index = exception;
35     env->error_code = error_code;
36     cpu_loop_exit();
37 }
38
39 void do_raise_exception (uint32_t exception)
40 {
41     do_raise_exception_err(exception, 0);
42 }
43
44 void do_interrupt_restart (void)
45 {
46     if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
47         !(env->CP0_Status & (1 << CP0St_ERL)) &&
48         !(env->hflags & MIPS_HFLAG_DM) &&
49         (env->CP0_Status & (1 << CP0St_IE)) &&
50         (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) {
51         env->CP0_Cause &= ~(0x1f << CP0Ca_EC);
52         do_raise_exception(EXCP_EXT_INTERRUPT);
53     }
54 }
55
56 void do_restore_state (void *pc_ptr)
57 {
58     TranslationBlock *tb;
59     unsigned long pc = (unsigned long) pc_ptr;
60     
61     tb = tb_find_pc (pc);
62     if (tb) {
63         cpu_restore_state (tb, env, pc, NULL);
64     }
65 }
66
67 target_ulong do_clo (target_ulong t0)
68 {
69     return clo32(t0);
70 }
71
72 target_ulong do_clz (target_ulong t0)
73 {
74     return clz32(t0);
75 }
76
77 #if defined(TARGET_MIPS64)
78 target_ulong do_dclo (target_ulong t0)
79 {
80     return clo64(t0);
81 }
82
83 target_ulong do_dclz (target_ulong t0)
84 {
85     return clz64(t0);
86 }
87 #endif /* TARGET_MIPS64 */
88
89 /* 64 bits arithmetic for 32 bits hosts */
90 static always_inline uint64_t get_HILO (void)
91 {
92     return ((uint64_t)(env->HI[env->current_tc][0]) << 32) | (uint32_t)env->LO[env->current_tc][0];
93 }
94
95 static always_inline void set_HILO (uint64_t HILO)
96 {
97     env->LO[env->current_tc][0] = (int32_t)HILO;
98     env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
99 }
100
101 static always_inline void set_HIT0_LO (target_ulong t0, uint64_t HILO)
102 {
103     env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF);
104     t0 = env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
105 }
106
107 static always_inline void set_HI_LOT0 (target_ulong t0, uint64_t HILO)
108 {
109     t0 = env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF);
110     env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
111 }
112
113 #if TARGET_LONG_BITS > HOST_LONG_BITS
114 void do_madd (target_ulong t0, target_ulong t1)
115 {
116     int64_t tmp;
117
118     tmp = ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1);
119     set_HILO((int64_t)get_HILO() + tmp);
120 }
121
122 void do_maddu (target_ulong t0, target_ulong t1)
123 {
124     uint64_t tmp;
125
126     tmp = ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1);
127     set_HILO(get_HILO() + tmp);
128 }
129
130 void do_msub (target_ulong t0, target_ulong t1)
131 {
132     int64_t tmp;
133
134     tmp = ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1);
135     set_HILO((int64_t)get_HILO() - tmp);
136 }
137
138 void do_msubu (target_ulong t0, target_ulong t1)
139 {
140     uint64_t tmp;
141
142     tmp = ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1);
143     set_HILO(get_HILO() - tmp);
144 }
145 #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
146
147 /* Multiplication variants of the vr54xx. */
148 target_ulong do_muls (target_ulong t0, target_ulong t1)
149 {
150     set_HI_LOT0(t0, 0 - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1));
151
152     return t0;
153 }
154
155 target_ulong do_mulsu (target_ulong t0, target_ulong t1)
156 {
157     set_HI_LOT0(t0, 0 - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1));
158
159     return t0;
160 }
161
162 target_ulong do_macc (target_ulong t0, target_ulong t1)
163 {
164     set_HI_LOT0(t0, ((int64_t)get_HILO()) + ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1));
165
166     return t0;
167 }
168
169 target_ulong do_macchi (target_ulong t0, target_ulong t1)
170 {
171     set_HIT0_LO(t0, ((int64_t)get_HILO()) + ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1));
172
173     return t0;
174 }
175
176 target_ulong do_maccu (target_ulong t0, target_ulong t1)
177 {
178     set_HI_LOT0(t0, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1));
179
180     return t0;
181 }
182
183 target_ulong do_macchiu (target_ulong t0, target_ulong t1)
184 {
185     set_HIT0_LO(t0, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1));
186
187     return t0;
188 }
189
190 target_ulong do_msac (target_ulong t0, target_ulong t1)
191 {
192     set_HI_LOT0(t0, ((int64_t)get_HILO()) - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1));
193
194     return t0;
195 }
196
197 target_ulong do_msachi (target_ulong t0, target_ulong t1)
198 {
199     set_HIT0_LO(t0, ((int64_t)get_HILO()) - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1));
200
201     return t0;
202 }
203
204 target_ulong do_msacu (target_ulong t0, target_ulong t1)
205 {
206     set_HI_LOT0(t0, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1));
207
208     return t0;
209 }
210
211 target_ulong do_msachiu (target_ulong t0, target_ulong t1)
212 {
213     set_HIT0_LO(t0, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1));
214
215     return t0;
216 }
217
218 target_ulong do_mulhi (target_ulong t0, target_ulong t1)
219 {
220     set_HIT0_LO(t0, (int64_t)(int32_t)t0 * (int64_t)(int32_t)t1);
221
222     return t0;
223 }
224
225 target_ulong do_mulhiu (target_ulong t0, target_ulong t1)
226 {
227     set_HIT0_LO(t0, (uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1);
228
229     return t0;
230 }
231
232 target_ulong do_mulshi (target_ulong t0, target_ulong t1)
233 {
234     set_HIT0_LO(t0, 0 - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1));
235
236     return t0;
237 }
238
239 target_ulong do_mulshiu (target_ulong t0, target_ulong t1)
240 {
241     set_HIT0_LO(t0, 0 - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1));
242
243     return t0;
244 }
245
246 #ifdef TARGET_MIPS64
247 void do_dmult (target_ulong t0, target_ulong t1)
248 {
249     muls64(&(env->LO[env->current_tc][0]), &(env->HI[env->current_tc][0]), t0, t1);
250 }
251
252 void do_dmultu (target_ulong t0, target_ulong t1)
253 {
254     mulu64(&(env->LO[env->current_tc][0]), &(env->HI[env->current_tc][0]), t0, t1);
255 }
256 #endif
257
258 #ifdef TARGET_WORDS_BIGENDIAN
259 #define GET_LMASK(v) ((v) & 3)
260 #define GET_OFFSET(addr, offset) (addr + (offset))
261 #else
262 #define GET_LMASK(v) (((v) & 3) ^ 3)
263 #define GET_OFFSET(addr, offset) (addr - (offset))
264 #endif
265
266 target_ulong do_lwl(target_ulong t0, target_ulong t1, int mem_idx)
267 {
268     target_ulong tmp;
269
270 #ifdef CONFIG_USER_ONLY
271 #define ldfun ldub_raw
272 #else
273     int (*ldfun)(target_ulong);
274
275     switch (mem_idx)
276     {
277     case 0: ldfun = ldub_kernel; break;
278     case 1: ldfun = ldub_super; break;
279     default:
280     case 2: ldfun = ldub_user; break;
281     }
282 #endif
283     tmp = ldfun(t0);
284     t1 = (t1 & 0x00FFFFFF) | (tmp << 24);
285
286     if (GET_LMASK(t0) <= 2) {
287         tmp = ldfun(GET_OFFSET(t0, 1));
288         t1 = (t1 & 0xFF00FFFF) | (tmp << 16);
289     }
290
291     if (GET_LMASK(t0) <= 1) {
292         tmp = ldfun(GET_OFFSET(t0, 2));
293         t1 = (t1 & 0xFFFF00FF) | (tmp << 8);
294     }
295
296     if (GET_LMASK(t0) == 0) {
297         tmp = ldfun(GET_OFFSET(t0, 3));
298         t1 = (t1 & 0xFFFFFF00) | tmp;
299     }
300     return (int32_t)t1;
301 }
302
303 target_ulong do_lwr(target_ulong t0, target_ulong t1, int mem_idx)
304 {
305     target_ulong tmp;
306
307 #ifdef CONFIG_USER_ONLY
308 #define ldfun ldub_raw
309 #else
310     int (*ldfun)(target_ulong);
311
312     switch (mem_idx)
313     {
314     case 0: ldfun = ldub_kernel; break;
315     case 1: ldfun = ldub_super; break;
316     default:
317     case 2: ldfun = ldub_user; break;
318     }
319 #endif
320     tmp = ldfun(t0);
321     t1 = (t1 & 0xFFFFFF00) | tmp;
322
323     if (GET_LMASK(t0) >= 1) {
324         tmp = ldfun(GET_OFFSET(t0, -1));
325         t1 = (t1 & 0xFFFF00FF) | (tmp << 8);
326     }
327
328     if (GET_LMASK(t0) >= 2) {
329         tmp = ldfun(GET_OFFSET(t0, -2));
330         t1 = (t1 & 0xFF00FFFF) | (tmp << 16);
331     }
332
333     if (GET_LMASK(t0) == 3) {
334         tmp = ldfun(GET_OFFSET(t0, -3));
335         t1 = (t1 & 0x00FFFFFF) | (tmp << 24);
336     }
337     return (int32_t)t1;
338 }
339
340 void do_swl(target_ulong t0, target_ulong t1, int mem_idx)
341 {
342 #ifdef CONFIG_USER_ONLY
343 #define stfun stb_raw
344 #else
345     void (*stfun)(target_ulong, int);
346
347     switch (mem_idx)
348     {
349     case 0: stfun = stb_kernel; break;
350     case 1: stfun = stb_super; break;
351     default:
352     case 2: stfun = stb_user; break;
353     }
354 #endif
355     stfun(t0, (uint8_t)(t1 >> 24));
356
357     if (GET_LMASK(t0) <= 2)
358         stfun(GET_OFFSET(t0, 1), (uint8_t)(t1 >> 16));
359
360     if (GET_LMASK(t0) <= 1)
361         stfun(GET_OFFSET(t0, 2), (uint8_t)(t1 >> 8));
362
363     if (GET_LMASK(t0) == 0)
364         stfun(GET_OFFSET(t0, 3), (uint8_t)t1);
365 }
366
367 void do_swr(target_ulong t0, target_ulong t1, int mem_idx)
368 {
369 #ifdef CONFIG_USER_ONLY
370 #define stfun stb_raw
371 #else
372     void (*stfun)(target_ulong, int);
373
374     switch (mem_idx)
375     {
376     case 0: stfun = stb_kernel; break;
377     case 1: stfun = stb_super; break;
378     default:
379     case 2: stfun = stb_user; break;
380     }
381 #endif
382     stfun(t0, (uint8_t)t1);
383
384     if (GET_LMASK(t0) >= 1)
385         stfun(GET_OFFSET(t0, -1), (uint8_t)(t1 >> 8));
386
387     if (GET_LMASK(t0) >= 2)
388         stfun(GET_OFFSET(t0, -2), (uint8_t)(t1 >> 16));
389
390     if (GET_LMASK(t0) == 3)
391         stfun(GET_OFFSET(t0, -3), (uint8_t)(t1 >> 24));
392 }
393
394 #if defined(TARGET_MIPS64)
395 /* "half" load and stores.  We must do the memory access inline,
396    or fault handling won't work.  */
397
398 #ifdef TARGET_WORDS_BIGENDIAN
399 #define GET_LMASK64(v) ((v) & 7)
400 #else
401 #define GET_LMASK64(v) (((v) & 7) ^ 7)
402 #endif
403
404 target_ulong do_ldl(target_ulong t0, target_ulong t1, int mem_idx)
405 {
406     uint64_t tmp;
407
408 #ifdef CONFIG_USER_ONLY
409 #define ldfun ldub_raw
410 #else
411     int (*ldfun)(target_ulong);
412
413     switch (mem_idx)
414     {
415     case 0: ldfun = ldub_kernel; break;
416     case 1: ldfun = ldub_super; break;
417     default:
418     case 2: ldfun = ldub_user; break;
419     }
420 #endif
421     tmp = ldfun(t0);
422     t1 = (t1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
423
424     if (GET_LMASK64(t0) <= 6) {
425         tmp = ldfun(GET_OFFSET(t0, 1));
426         t1 = (t1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
427     }
428
429     if (GET_LMASK64(t0) <= 5) {
430         tmp = ldfun(GET_OFFSET(t0, 2));
431         t1 = (t1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
432     }
433
434     if (GET_LMASK64(t0) <= 4) {
435         tmp = ldfun(GET_OFFSET(t0, 3));
436         t1 = (t1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
437     }
438
439     if (GET_LMASK64(t0) <= 3) {
440         tmp = ldfun(GET_OFFSET(t0, 4));
441         t1 = (t1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
442     }
443
444     if (GET_LMASK64(t0) <= 2) {
445         tmp = ldfun(GET_OFFSET(t0, 5));
446         t1 = (t1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
447     }
448
449     if (GET_LMASK64(t0) <= 1) {
450         tmp = ldfun(GET_OFFSET(t0, 6));
451         t1 = (t1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
452     }
453
454     if (GET_LMASK64(t0) == 0) {
455         tmp = ldfun(GET_OFFSET(t0, 7));
456         t1 = (t1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
457     }
458
459     return t1;
460 }
461
462 target_ulong do_ldr(target_ulong t0, target_ulong t1, int mem_idx)
463 {
464     uint64_t tmp;
465
466 #ifdef CONFIG_USER_ONLY
467 #define ldfun ldub_raw
468 #else
469     int (*ldfun)(target_ulong);
470
471     switch (mem_idx)
472     {
473     case 0: ldfun = ldub_kernel; break;
474     case 1: ldfun = ldub_super; break;
475     default:
476     case 2: ldfun = ldub_user; break;
477     }
478 #endif
479     tmp = ldfun(t0);
480     t1 = (t1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
481
482     if (GET_LMASK64(t0) >= 1) {
483         tmp = ldfun(GET_OFFSET(t0, -1));
484         t1 = (t1 & 0xFFFFFFFFFFFF00FFULL) | (tmp  << 8);
485     }
486
487     if (GET_LMASK64(t0) >= 2) {
488         tmp = ldfun(GET_OFFSET(t0, -2));
489         t1 = (t1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
490     }
491
492     if (GET_LMASK64(t0) >= 3) {
493         tmp = ldfun(GET_OFFSET(t0, -3));
494         t1 = (t1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
495     }
496
497     if (GET_LMASK64(t0) >= 4) {
498         tmp = ldfun(GET_OFFSET(t0, -4));
499         t1 = (t1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
500     }
501
502     if (GET_LMASK64(t0) >= 5) {
503         tmp = ldfun(GET_OFFSET(t0, -5));
504         t1 = (t1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
505     }
506
507     if (GET_LMASK64(t0) >= 6) {
508         tmp = ldfun(GET_OFFSET(t0, -6));
509         t1 = (t1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
510     }
511
512     if (GET_LMASK64(t0) == 7) {
513         tmp = ldfun(GET_OFFSET(t0, -7));
514         t1 = (t1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
515     }
516
517     return t1;
518 }
519
520 void do_sdl(target_ulong t0, target_ulong t1, int mem_idx)
521 {
522 #ifdef CONFIG_USER_ONLY
523 #define stfun stb_raw
524 #else
525     void (*stfun)(target_ulong, int);
526
527     switch (mem_idx)
528     {
529     case 0: stfun = stb_kernel; break;
530     case 1: stfun = stb_super; break;
531     default:
532     case 2: stfun = stb_user; break;
533     }
534 #endif
535     stfun(t0, (uint8_t)(t1 >> 56));
536
537     if (GET_LMASK64(t0) <= 6)
538         stfun(GET_OFFSET(t0, 1), (uint8_t)(t1 >> 48));
539
540     if (GET_LMASK64(t0) <= 5)
541         stfun(GET_OFFSET(t0, 2), (uint8_t)(t1 >> 40));
542
543     if (GET_LMASK64(t0) <= 4)
544         stfun(GET_OFFSET(t0, 3), (uint8_t)(t1 >> 32));
545
546     if (GET_LMASK64(t0) <= 3)
547         stfun(GET_OFFSET(t0, 4), (uint8_t)(t1 >> 24));
548
549     if (GET_LMASK64(t0) <= 2)
550         stfun(GET_OFFSET(t0, 5), (uint8_t)(t1 >> 16));
551
552     if (GET_LMASK64(t0) <= 1)
553         stfun(GET_OFFSET(t0, 6), (uint8_t)(t1 >> 8));
554
555     if (GET_LMASK64(t0) <= 0)
556         stfun(GET_OFFSET(t0, 7), (uint8_t)t1);
557 }
558
559 void do_sdr(target_ulong t0, target_ulong t1, int mem_idx)
560 {
561 #ifdef CONFIG_USER_ONLY
562 #define stfun stb_raw
563 #else
564     void (*stfun)(target_ulong, int);
565
566     switch (mem_idx)
567     {
568     case 0: stfun = stb_kernel; break;
569     case 1: stfun = stb_super; break;
570      default:
571     case 2: stfun = stb_user; break;
572     }
573 #endif
574     stfun(t0, (uint8_t)t1);
575
576     if (GET_LMASK64(t0) >= 1)
577         stfun(GET_OFFSET(t0, -1), (uint8_t)(t1 >> 8));
578
579     if (GET_LMASK64(t0) >= 2)
580         stfun(GET_OFFSET(t0, -2), (uint8_t)(t1 >> 16));
581
582     if (GET_LMASK64(t0) >= 3)
583         stfun(GET_OFFSET(t0, -3), (uint8_t)(t1 >> 24));
584
585     if (GET_LMASK64(t0) >= 4)
586         stfun(GET_OFFSET(t0, -4), (uint8_t)(t1 >> 32));
587
588     if (GET_LMASK64(t0) >= 5)
589         stfun(GET_OFFSET(t0, -5), (uint8_t)(t1 >> 40));
590
591     if (GET_LMASK64(t0) >= 6)
592         stfun(GET_OFFSET(t0, -6), (uint8_t)(t1 >> 48));
593
594     if (GET_LMASK64(t0) == 7)
595         stfun(GET_OFFSET(t0, -7), (uint8_t)(t1 >> 56));
596 }
597 #endif /* TARGET_MIPS64 */
598
599 #ifdef CONFIG_USER_ONLY
600 void do_mfc0_random (void)
601 {
602     cpu_abort(env, "mfc0 random\n");
603 }
604
605 void do_mfc0_count (void)
606 {
607     cpu_abort(env, "mfc0 count\n");
608 }
609
610 void cpu_mips_store_count(CPUState *env, uint32_t value)
611 {
612     cpu_abort(env, "mtc0 count\n");
613 }
614
615 void cpu_mips_store_compare(CPUState *env, uint32_t value)
616 {
617     cpu_abort(env, "mtc0 compare\n");
618 }
619
620 void cpu_mips_start_count(CPUState *env)
621 {
622     cpu_abort(env, "start count\n");
623 }
624
625 void cpu_mips_stop_count(CPUState *env)
626 {
627     cpu_abort(env, "stop count\n");
628 }
629
630 void cpu_mips_update_irq(CPUState *env)
631 {
632     cpu_abort(env, "mtc0 status / mtc0 cause\n");
633 }
634
635 void do_mtc0_status_debug(uint32_t old, uint32_t val)
636 {
637     cpu_abort(env, "mtc0 status debug\n");
638 }
639
640 void do_mtc0_status_irqraise_debug (void)
641 {
642     cpu_abort(env, "mtc0 status irqraise debug\n");
643 }
644
645 void cpu_mips_tlb_flush (CPUState *env, int flush_global)
646 {
647     cpu_abort(env, "mips_tlb_flush\n");
648 }
649
650 #else
651
652 /* CP0 helpers */
653 target_ulong do_mfc0_mvpcontrol (target_ulong t0)
654 {
655     return env->mvp->CP0_MVPControl;
656 }
657
658 target_ulong do_mfc0_mvpconf0 (target_ulong t0)
659 {
660     return env->mvp->CP0_MVPConf0;
661 }
662
663 target_ulong do_mfc0_mvpconf1 (target_ulong t0)
664 {
665     return env->mvp->CP0_MVPConf1;
666 }
667
668 target_ulong do_mfc0_random (target_ulong t0)
669 {
670     return (int32_t)cpu_mips_get_random(env);
671 }
672
673 target_ulong do_mfc0_tcstatus (target_ulong t0)
674 {
675     return env->CP0_TCStatus[env->current_tc];
676 }
677
678 target_ulong do_mftc0_tcstatus(target_ulong t0)
679 {
680     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
681
682     return env->CP0_TCStatus[other_tc];
683 }
684
685 target_ulong do_mfc0_tcbind (target_ulong t0)
686 {
687     return env->CP0_TCBind[env->current_tc];
688 }
689
690 target_ulong do_mftc0_tcbind(target_ulong t0)
691 {
692     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
693
694     return env->CP0_TCBind[other_tc];
695 }
696
697 target_ulong do_mfc0_tcrestart (target_ulong t0)
698 {
699     return env->PC[env->current_tc];
700 }
701
702 target_ulong do_mftc0_tcrestart(target_ulong t0)
703 {
704     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
705
706     return env->PC[other_tc];
707 }
708
709 target_ulong do_mfc0_tchalt (target_ulong t0)
710 {
711     return env->CP0_TCHalt[env->current_tc];
712 }
713
714 target_ulong do_mftc0_tchalt(target_ulong t0)
715 {
716     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
717
718     return env->CP0_TCHalt[other_tc];
719 }
720
721 target_ulong do_mfc0_tccontext (target_ulong t0)
722 {
723     return env->CP0_TCContext[env->current_tc];
724 }
725
726 target_ulong do_mftc0_tccontext(target_ulong t0)
727 {
728     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
729
730     return env->CP0_TCContext[other_tc];
731 }
732
733 target_ulong do_mfc0_tcschedule (target_ulong t0)
734 {
735     return env->CP0_TCSchedule[env->current_tc];
736 }
737
738 target_ulong do_mftc0_tcschedule(target_ulong t0)
739 {
740     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
741
742     return env->CP0_TCSchedule[other_tc];
743 }
744
745 target_ulong do_mfc0_tcschefback (target_ulong t0)
746 {
747     return env->CP0_TCScheFBack[env->current_tc];
748 }
749
750 target_ulong do_mftc0_tcschefback(target_ulong t0)
751 {
752     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
753
754     return env->CP0_TCScheFBack[other_tc];
755 }
756
757 target_ulong do_mfc0_count (target_ulong t0)
758 {
759     return (int32_t)cpu_mips_get_count(env);
760 }
761
762 target_ulong do_mftc0_entryhi(target_ulong t0)
763 {
764     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
765
766     return (env->CP0_EntryHi & ~0xff) | (env->CP0_TCStatus[other_tc] & 0xff);
767 }
768
769 target_ulong do_mftc0_status(target_ulong t0)
770 {
771     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
772     uint32_t tcstatus = env->CP0_TCStatus[other_tc];
773
774     t0 = env->CP0_Status & ~0xf1000018;
775     t0 |= tcstatus & (0xf << CP0TCSt_TCU0);
776     t0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX);
777     t0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU);
778
779     return t0;
780 }
781
782 target_ulong do_mfc0_lladdr (target_ulong t0)
783 {
784     return (int32_t)env->CP0_LLAddr >> 4;
785 }
786
787 target_ulong do_mfc0_watchlo (target_ulong t0, uint32_t sel)
788 {
789     return (int32_t)env->CP0_WatchLo[sel];
790 }
791
792 target_ulong do_mfc0_watchhi (target_ulong t0, uint32_t sel)
793 {
794     return env->CP0_WatchHi[sel];
795 }
796
797 target_ulong do_mfc0_debug (target_ulong t0)
798 {
799     t0 = env->CP0_Debug;
800     if (env->hflags & MIPS_HFLAG_DM)
801         t0 |= 1 << CP0DB_DM;
802
803     return t0;
804 }
805
806 target_ulong do_mftc0_debug(target_ulong t0)
807 {
808     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
809
810     /* XXX: Might be wrong, check with EJTAG spec. */
811     return (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
812             (env->CP0_Debug_tcstatus[other_tc] &
813              ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
814 }
815
816 #if defined(TARGET_MIPS64)
817 target_ulong do_dmfc0_tcrestart (target_ulong t0)
818 {
819     return env->PC[env->current_tc];
820 }
821
822 target_ulong do_dmfc0_tchalt (target_ulong t0)
823 {
824     return env->CP0_TCHalt[env->current_tc];
825 }
826
827 target_ulong do_dmfc0_tccontext (target_ulong t0)
828 {
829     return env->CP0_TCContext[env->current_tc];
830 }
831
832 target_ulong do_dmfc0_tcschedule (target_ulong t0)
833 {
834     return env->CP0_TCSchedule[env->current_tc];
835 }
836
837 target_ulong do_dmfc0_tcschefback (target_ulong t0)
838 {
839     return env->CP0_TCScheFBack[env->current_tc];
840 }
841
842 target_ulong do_dmfc0_lladdr (target_ulong t0)
843 {
844     return env->CP0_LLAddr >> 4;
845 }
846
847 target_ulong do_dmfc0_watchlo (target_ulong t0, uint32_t sel)
848 {
849     return env->CP0_WatchLo[sel];
850 }
851 #endif /* TARGET_MIPS64 */
852
853 void do_mtc0_index (target_ulong t0)
854 {
855     int num = 1;
856     unsigned int tmp = env->tlb->nb_tlb;
857
858     do {
859         tmp >>= 1;
860         num <<= 1;
861     } while (tmp);
862     env->CP0_Index = (env->CP0_Index & 0x80000000) | (t0 & (num - 1));
863 }
864
865 void do_mtc0_mvpcontrol (target_ulong t0)
866 {
867     uint32_t mask = 0;
868     uint32_t newval;
869
870     if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
871         mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
872                 (1 << CP0MVPCo_EVP);
873     if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
874         mask |= (1 << CP0MVPCo_STLB);
875     newval = (env->mvp->CP0_MVPControl & ~mask) | (t0 & mask);
876
877     // TODO: Enable/disable shared TLB, enable/disable VPEs.
878
879     env->mvp->CP0_MVPControl = newval;
880 }
881
882 void do_mtc0_vpecontrol (target_ulong t0)
883 {
884     uint32_t mask;
885     uint32_t newval;
886
887     mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
888            (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
889     newval = (env->CP0_VPEControl & ~mask) | (t0 & mask);
890
891     /* Yield scheduler intercept not implemented. */
892     /* Gating storage scheduler intercept not implemented. */
893
894     // TODO: Enable/disable TCs.
895
896     env->CP0_VPEControl = newval;
897 }
898
899 void do_mtc0_vpeconf0 (target_ulong t0)
900 {
901     uint32_t mask = 0;
902     uint32_t newval;
903
904     if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
905         if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
906             mask |= (0xff << CP0VPEC0_XTC);
907         mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
908     }
909     newval = (env->CP0_VPEConf0 & ~mask) | (t0 & mask);
910
911     // TODO: TC exclusive handling due to ERL/EXL.
912
913     env->CP0_VPEConf0 = newval;
914 }
915
916 void do_mtc0_vpeconf1 (target_ulong t0)
917 {
918     uint32_t mask = 0;
919     uint32_t newval;
920
921     if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
922         mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
923                 (0xff << CP0VPEC1_NCP1);
924     newval = (env->CP0_VPEConf1 & ~mask) | (t0 & mask);
925
926     /* UDI not implemented. */
927     /* CP2 not implemented. */
928
929     // TODO: Handle FPU (CP1) binding.
930
931     env->CP0_VPEConf1 = newval;
932 }
933
934 void do_mtc0_yqmask (target_ulong t0)
935 {
936     /* Yield qualifier inputs not implemented. */
937     env->CP0_YQMask = 0x00000000;
938 }
939
940 void do_mtc0_vpeopt (target_ulong t0)
941 {
942     env->CP0_VPEOpt = t0 & 0x0000ffff;
943 }
944
945 void do_mtc0_entrylo0 (target_ulong t0)
946 {
947     /* Large physaddr (PABITS) not implemented */
948     /* 1k pages not implemented */
949     env->CP0_EntryLo0 = t0 & 0x3FFFFFFF;
950 }
951
952 void do_mtc0_tcstatus (target_ulong t0)
953 {
954     uint32_t mask = env->CP0_TCStatus_rw_bitmask;
955     uint32_t newval;
956
957     newval = (env->CP0_TCStatus[env->current_tc] & ~mask) | (t0 & mask);
958
959     // TODO: Sync with CP0_Status.
960
961     env->CP0_TCStatus[env->current_tc] = newval;
962 }
963
964 void do_mttc0_tcstatus (target_ulong t0)
965 {
966     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
967
968     // TODO: Sync with CP0_Status.
969
970     env->CP0_TCStatus[other_tc] = t0;
971 }
972
973 void do_mtc0_tcbind (target_ulong t0)
974 {
975     uint32_t mask = (1 << CP0TCBd_TBE);
976     uint32_t newval;
977
978     if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
979         mask |= (1 << CP0TCBd_CurVPE);
980     newval = (env->CP0_TCBind[env->current_tc] & ~mask) | (t0 & mask);
981     env->CP0_TCBind[env->current_tc] = newval;
982 }
983
984 void do_mttc0_tcbind (target_ulong t0)
985 {
986     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
987     uint32_t mask = (1 << CP0TCBd_TBE);
988     uint32_t newval;
989
990     if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
991         mask |= (1 << CP0TCBd_CurVPE);
992     newval = (env->CP0_TCBind[other_tc] & ~mask) | (t0 & mask);
993     env->CP0_TCBind[other_tc] = newval;
994 }
995
996 void do_mtc0_tcrestart (target_ulong t0)
997 {
998     env->PC[env->current_tc] = t0;
999     env->CP0_TCStatus[env->current_tc] &= ~(1 << CP0TCSt_TDS);
1000     env->CP0_LLAddr = 0ULL;
1001     /* MIPS16 not implemented. */
1002 }
1003
1004 void do_mttc0_tcrestart (target_ulong t0)
1005 {
1006     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1007
1008     env->PC[other_tc] = t0;
1009     env->CP0_TCStatus[other_tc] &= ~(1 << CP0TCSt_TDS);
1010     env->CP0_LLAddr = 0ULL;
1011     /* MIPS16 not implemented. */
1012 }
1013
1014 void do_mtc0_tchalt (target_ulong t0)
1015 {
1016     env->CP0_TCHalt[env->current_tc] = t0 & 0x1;
1017
1018     // TODO: Halt TC / Restart (if allocated+active) TC.
1019 }
1020
1021 void do_mttc0_tchalt (target_ulong t0)
1022 {
1023     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1024
1025     // TODO: Halt TC / Restart (if allocated+active) TC.
1026
1027     env->CP0_TCHalt[other_tc] = t0;
1028 }
1029
1030 void do_mtc0_tccontext (target_ulong t0)
1031 {
1032     env->CP0_TCContext[env->current_tc] = t0;
1033 }
1034
1035 void do_mttc0_tccontext (target_ulong t0)
1036 {
1037     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1038
1039     env->CP0_TCContext[other_tc] = t0;
1040 }
1041
1042 void do_mtc0_tcschedule (target_ulong t0)
1043 {
1044     env->CP0_TCSchedule[env->current_tc] = t0;
1045 }
1046
1047 void do_mttc0_tcschedule (target_ulong t0)
1048 {
1049     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1050
1051     env->CP0_TCSchedule[other_tc] = t0;
1052 }
1053
1054 void do_mtc0_tcschefback (target_ulong t0)
1055 {
1056     env->CP0_TCScheFBack[env->current_tc] = t0;
1057 }
1058
1059 void do_mttc0_tcschefback (target_ulong t0)
1060 {
1061     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1062
1063     env->CP0_TCScheFBack[other_tc] = t0;
1064 }
1065
1066 void do_mtc0_entrylo1 (target_ulong t0)
1067 {
1068     /* Large physaddr (PABITS) not implemented */
1069     /* 1k pages not implemented */
1070     env->CP0_EntryLo1 = t0 & 0x3FFFFFFF;
1071 }
1072
1073 void do_mtc0_context (target_ulong t0)
1074 {
1075     env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (t0 & ~0x007FFFFF);
1076 }
1077
1078 void do_mtc0_pagemask (target_ulong t0)
1079 {
1080     /* 1k pages not implemented */
1081     env->CP0_PageMask = t0 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1082 }
1083
1084 void do_mtc0_pagegrain (target_ulong t0)
1085 {
1086     /* SmartMIPS not implemented */
1087     /* Large physaddr (PABITS) not implemented */
1088     /* 1k pages not implemented */
1089     env->CP0_PageGrain = 0;
1090 }
1091
1092 void do_mtc0_wired (target_ulong t0)
1093 {
1094     env->CP0_Wired = t0 % env->tlb->nb_tlb;
1095 }
1096
1097 void do_mtc0_srsconf0 (target_ulong t0)
1098 {
1099     env->CP0_SRSConf0 |= t0 & env->CP0_SRSConf0_rw_bitmask;
1100 }
1101
1102 void do_mtc0_srsconf1 (target_ulong t0)
1103 {
1104     env->CP0_SRSConf1 |= t0 & env->CP0_SRSConf1_rw_bitmask;
1105 }
1106
1107 void do_mtc0_srsconf2 (target_ulong t0)
1108 {
1109     env->CP0_SRSConf2 |= t0 & env->CP0_SRSConf2_rw_bitmask;
1110 }
1111
1112 void do_mtc0_srsconf3 (target_ulong t0)
1113 {
1114     env->CP0_SRSConf3 |= t0 & env->CP0_SRSConf3_rw_bitmask;
1115 }
1116
1117 void do_mtc0_srsconf4 (target_ulong t0)
1118 {
1119     env->CP0_SRSConf4 |= t0 & env->CP0_SRSConf4_rw_bitmask;
1120 }
1121
1122 void do_mtc0_hwrena (target_ulong t0)
1123 {
1124     env->CP0_HWREna = t0 & 0x0000000F;
1125 }
1126
1127 void do_mtc0_count (target_ulong t0)
1128 {
1129     cpu_mips_store_count(env, t0);
1130 }
1131
1132 void do_mtc0_entryhi (target_ulong t0)
1133 {
1134     target_ulong old, val;
1135
1136     /* 1k pages not implemented */
1137     val = t0 & ((TARGET_PAGE_MASK << 1) | 0xFF);
1138 #if defined(TARGET_MIPS64)
1139     val &= env->SEGMask;
1140 #endif
1141     old = env->CP0_EntryHi;
1142     env->CP0_EntryHi = val;
1143     if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1144         uint32_t tcst = env->CP0_TCStatus[env->current_tc] & ~0xff;
1145         env->CP0_TCStatus[env->current_tc] = tcst | (val & 0xff);
1146     }
1147     /* If the ASID changes, flush qemu's TLB.  */
1148     if ((old & 0xFF) != (val & 0xFF))
1149         cpu_mips_tlb_flush(env, 1);
1150 }
1151
1152 void do_mttc0_entryhi(target_ulong t0)
1153 {
1154     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1155
1156     env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (t0 & ~0xff);
1157     env->CP0_TCStatus[other_tc] = (env->CP0_TCStatus[other_tc] & ~0xff) | (t0 & 0xff);
1158 }
1159
1160 void do_mtc0_compare (target_ulong t0)
1161 {
1162     cpu_mips_store_compare(env, t0);
1163 }
1164
1165 void do_mtc0_status (target_ulong t0)
1166 {
1167     uint32_t val, old;
1168     uint32_t mask = env->CP0_Status_rw_bitmask;
1169
1170     val = t0 & mask;
1171     old = env->CP0_Status;
1172     env->CP0_Status = (env->CP0_Status & ~mask) | val;
1173     compute_hflags(env);
1174     if (loglevel & CPU_LOG_EXEC)
1175         do_mtc0_status_debug(old, val);
1176     cpu_mips_update_irq(env);
1177 }
1178
1179 void do_mttc0_status(target_ulong t0)
1180 {
1181     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1182     uint32_t tcstatus = env->CP0_TCStatus[other_tc];
1183
1184     env->CP0_Status = t0 & ~0xf1000018;
1185     tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (t0 & (0xf << CP0St_CU0));
1186     tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((t0 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX));
1187     tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((t0 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU));
1188     env->CP0_TCStatus[other_tc] = tcstatus;
1189 }
1190
1191 void do_mtc0_intctl (target_ulong t0)
1192 {
1193     /* vectored interrupts not implemented, no performance counters. */
1194     env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (t0 & 0x000002e0);
1195 }
1196
1197 void do_mtc0_srsctl (target_ulong t0)
1198 {
1199     uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1200     env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (t0 & mask);
1201 }
1202
1203 void do_mtc0_cause (target_ulong t0)
1204 {
1205     uint32_t mask = 0x00C00300;
1206     uint32_t old = env->CP0_Cause;
1207
1208     if (env->insn_flags & ISA_MIPS32R2)
1209         mask |= 1 << CP0Ca_DC;
1210
1211     env->CP0_Cause = (env->CP0_Cause & ~mask) | (t0 & mask);
1212
1213     if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
1214         if (env->CP0_Cause & (1 << CP0Ca_DC))
1215             cpu_mips_stop_count(env);
1216         else
1217             cpu_mips_start_count(env);
1218     }
1219
1220     /* Handle the software interrupt as an hardware one, as they
1221        are very similar */
1222     if (t0 & CP0Ca_IP_mask) {
1223         cpu_mips_update_irq(env);
1224     }
1225 }
1226
1227 void do_mtc0_ebase (target_ulong t0)
1228 {
1229     /* vectored interrupts not implemented */
1230     /* Multi-CPU not implemented */
1231     env->CP0_EBase = 0x80000000 | (t0 & 0x3FFFF000);
1232 }
1233
1234 void do_mtc0_config0 (target_ulong t0)
1235 {
1236     env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (t0 & 0x00000007);
1237 }
1238
1239 void do_mtc0_config2 (target_ulong t0)
1240 {
1241     /* tertiary/secondary caches not implemented */
1242     env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1243 }
1244
1245 void do_mtc0_watchlo (target_ulong t0, uint32_t sel)
1246 {
1247     /* Watch exceptions for instructions, data loads, data stores
1248        not implemented. */
1249     env->CP0_WatchLo[sel] = (t0 & ~0x7);
1250 }
1251
1252 void do_mtc0_watchhi (target_ulong t0, uint32_t sel)
1253 {
1254     env->CP0_WatchHi[sel] = (t0 & 0x40FF0FF8);
1255     env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & t0 & 0x7);
1256 }
1257
1258 void do_mtc0_xcontext (target_ulong t0)
1259 {
1260     target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1261     env->CP0_XContext = (env->CP0_XContext & mask) | (t0 & ~mask);
1262 }
1263
1264 void do_mtc0_framemask (target_ulong t0)
1265 {
1266     env->CP0_Framemask = t0; /* XXX */
1267 }
1268
1269 void do_mtc0_debug (target_ulong t0)
1270 {
1271     env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (t0 & 0x13300120);
1272     if (t0 & (1 << CP0DB_DM))
1273         env->hflags |= MIPS_HFLAG_DM;
1274     else
1275         env->hflags &= ~MIPS_HFLAG_DM;
1276 }
1277
1278 void do_mttc0_debug(target_ulong t0)
1279 {
1280     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1281
1282     /* XXX: Might be wrong, check with EJTAG spec. */
1283     env->CP0_Debug_tcstatus[other_tc] = t0 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
1284     env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1285                      (t0 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1286 }
1287
1288 void do_mtc0_performance0 (target_ulong t0)
1289 {
1290     env->CP0_Performance0 = t0 & 0x000007ff;
1291 }
1292
1293 void do_mtc0_taglo (target_ulong t0)
1294 {
1295     env->CP0_TagLo = t0 & 0xFFFFFCF6;
1296 }
1297
1298 void do_mtc0_datalo (target_ulong t0)
1299 {
1300     env->CP0_DataLo = t0; /* XXX */
1301 }
1302
1303 void do_mtc0_taghi (target_ulong t0)
1304 {
1305     env->CP0_TagHi = t0; /* XXX */
1306 }
1307
1308 void do_mtc0_datahi (target_ulong t0)
1309 {
1310     env->CP0_DataHi = t0; /* XXX */
1311 }
1312
1313 void do_mtc0_status_debug(uint32_t old, uint32_t val)
1314 {
1315     fprintf(logfile, "Status %08x (%08x) => %08x (%08x) Cause %08x",
1316             old, old & env->CP0_Cause & CP0Ca_IP_mask,
1317             val, val & env->CP0_Cause & CP0Ca_IP_mask,
1318             env->CP0_Cause);
1319     switch (env->hflags & MIPS_HFLAG_KSU) {
1320     case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break;
1321     case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break;
1322     case MIPS_HFLAG_KM: fputs("\n", logfile); break;
1323     default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1324     }
1325 }
1326
1327 void do_mtc0_status_irqraise_debug(void)
1328 {
1329     fprintf(logfile, "Raise pending IRQs\n");
1330 }
1331 #endif /* !CONFIG_USER_ONLY */
1332
1333 /* MIPS MT functions */
1334 target_ulong do_mftgpr(target_ulong t0, uint32_t sel)
1335 {
1336     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1337
1338     return env->gpr[other_tc][sel];
1339 }
1340
1341 target_ulong do_mftlo(target_ulong t0, uint32_t sel)
1342 {
1343     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1344
1345     return env->LO[other_tc][sel];
1346 }
1347
1348 target_ulong do_mfthi(target_ulong t0, uint32_t sel)
1349 {
1350     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1351
1352     return env->HI[other_tc][sel];
1353 }
1354
1355 target_ulong do_mftacx(target_ulong t0, uint32_t sel)
1356 {
1357     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1358
1359     return env->ACX[other_tc][sel];
1360 }
1361
1362 target_ulong do_mftdsp(target_ulong t0)
1363 {
1364     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1365
1366     return env->DSPControl[other_tc];
1367 }
1368
1369 void do_mttgpr(target_ulong t0, uint32_t sel)
1370 {
1371     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1372
1373     env->gpr[other_tc][sel] = t0;
1374 }
1375
1376 void do_mttlo(target_ulong t0, uint32_t sel)
1377 {
1378     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1379
1380     env->LO[other_tc][sel] = t0;
1381 }
1382
1383 void do_mtthi(target_ulong t0, uint32_t sel)
1384 {
1385     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1386
1387     env->HI[other_tc][sel] = t0;
1388 }
1389
1390 void do_mttacx(target_ulong t0, uint32_t sel)
1391 {
1392     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1393
1394     env->ACX[other_tc][sel] = t0;
1395 }
1396
1397 void do_mttdsp(target_ulong t0)
1398 {
1399     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1400
1401     env->DSPControl[other_tc] = t0;
1402 }
1403
1404 /* MIPS MT functions */
1405 target_ulong do_dmt(target_ulong t0)
1406 {
1407     // TODO
1408     t0 = 0;
1409     // rt = t0
1410
1411     return t0;
1412 }
1413
1414 target_ulong do_emt(target_ulong t0)
1415 {
1416     // TODO
1417     t0 = 0;
1418     // rt = t0
1419
1420     return t0;
1421 }
1422
1423 target_ulong do_dvpe(target_ulong t0)
1424 {
1425     // TODO
1426     t0 = 0;
1427     // rt = t0
1428
1429     return t0;
1430 }
1431
1432 target_ulong do_evpe(target_ulong t0)
1433 {
1434     // TODO
1435     t0 = 0;
1436     // rt = t0
1437
1438     return t0;
1439 }
1440
1441 target_ulong do_fork(target_ulong t0, target_ulong t1)
1442 {
1443     // t0 = rt, t1 = rs
1444     t0 = 0;
1445     // TODO: store to TC register
1446
1447     return t0;
1448 }
1449
1450 target_ulong do_yield(target_ulong t0)
1451 {
1452     if (t0 < 0) {
1453         /* No scheduling policy implemented. */
1454         if (t0 != -2) {
1455             if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
1456                 env->CP0_TCStatus[env->current_tc] & (1 << CP0TCSt_DT)) {
1457                 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1458                 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
1459                 do_raise_exception(EXCP_THREAD);
1460             }
1461         }
1462     } else if (t0 == 0) {
1463         if (0 /* TODO: TC underflow */) {
1464             env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1465             do_raise_exception(EXCP_THREAD);
1466         } else {
1467             // TODO: Deallocate TC
1468         }
1469     } else if (t0 > 0) {
1470         /* Yield qualifier inputs not implemented. */
1471         env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1472         env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
1473         do_raise_exception(EXCP_THREAD);
1474     }
1475     return env->CP0_YQMask;
1476 }
1477
1478 /* CP1 functions */
1479 void fpu_handle_exception(void)
1480 {
1481 #ifdef CONFIG_SOFTFLOAT
1482     int flags = get_float_exception_flags(&env->fpu->fp_status);
1483     unsigned int cpuflags = 0, enable, cause = 0;
1484
1485     enable = GET_FP_ENABLE(env->fpu->fcr31);
1486
1487     /* determine current flags */
1488     if (flags & float_flag_invalid) {
1489         cpuflags |= FP_INVALID;
1490         cause |= FP_INVALID & enable;
1491     }
1492     if (flags & float_flag_divbyzero) {
1493         cpuflags |= FP_DIV0;
1494         cause |= FP_DIV0 & enable;
1495     }
1496     if (flags & float_flag_overflow) {
1497         cpuflags |= FP_OVERFLOW;
1498         cause |= FP_OVERFLOW & enable;
1499     }
1500     if (flags & float_flag_underflow) {
1501         cpuflags |= FP_UNDERFLOW;
1502         cause |= FP_UNDERFLOW & enable;
1503     }
1504     if (flags & float_flag_inexact) {
1505         cpuflags |= FP_INEXACT;
1506         cause |= FP_INEXACT & enable;
1507     }
1508     SET_FP_FLAGS(env->fpu->fcr31, cpuflags);
1509     SET_FP_CAUSE(env->fpu->fcr31, cause);
1510 #else
1511     SET_FP_FLAGS(env->fpu->fcr31, 0);
1512     SET_FP_CAUSE(env->fpu->fcr31, 0);
1513 #endif
1514 }
1515
1516 #ifndef CONFIG_USER_ONLY
1517 /* TLB management */
1518 void cpu_mips_tlb_flush (CPUState *env, int flush_global)
1519 {
1520     /* Flush qemu's TLB and discard all shadowed entries.  */
1521     tlb_flush (env, flush_global);
1522     env->tlb->tlb_in_use = env->tlb->nb_tlb;
1523 }
1524
1525 static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
1526 {
1527     /* Discard entries from env->tlb[first] onwards.  */
1528     while (env->tlb->tlb_in_use > first) {
1529         r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
1530     }
1531 }
1532
1533 static void r4k_fill_tlb (int idx)
1534 {
1535     r4k_tlb_t *tlb;
1536
1537     /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
1538     tlb = &env->tlb->mmu.r4k.tlb[idx];
1539     tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1540 #if defined(TARGET_MIPS64)
1541     tlb->VPN &= env->SEGMask;
1542 #endif
1543     tlb->ASID = env->CP0_EntryHi & 0xFF;
1544     tlb->PageMask = env->CP0_PageMask;
1545     tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1546     tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
1547     tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
1548     tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
1549     tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
1550     tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
1551     tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
1552     tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
1553     tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
1554 }
1555
1556 void r4k_do_tlbwi (void)
1557 {
1558     /* Discard cached TLB entries.  We could avoid doing this if the
1559        tlbwi is just upgrading access permissions on the current entry;
1560        that might be a further win.  */
1561     r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
1562
1563     r4k_invalidate_tlb(env, env->CP0_Index % env->tlb->nb_tlb, 0);
1564     r4k_fill_tlb(env->CP0_Index % env->tlb->nb_tlb);
1565 }
1566
1567 void r4k_do_tlbwr (void)
1568 {
1569     int r = cpu_mips_get_random(env);
1570
1571     r4k_invalidate_tlb(env, r, 1);
1572     r4k_fill_tlb(r);
1573 }
1574
1575 void r4k_do_tlbp (void)
1576 {
1577     r4k_tlb_t *tlb;
1578     target_ulong mask;
1579     target_ulong tag;
1580     target_ulong VPN;
1581     uint8_t ASID;
1582     int i;
1583
1584     ASID = env->CP0_EntryHi & 0xFF;
1585     for (i = 0; i < env->tlb->nb_tlb; i++) {
1586         tlb = &env->tlb->mmu.r4k.tlb[i];
1587         /* 1k pages are not supported. */
1588         mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1589         tag = env->CP0_EntryHi & ~mask;
1590         VPN = tlb->VPN & ~mask;
1591         /* Check ASID, virtual page number & size */
1592         if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
1593             /* TLB match */
1594             env->CP0_Index = i;
1595             break;
1596         }
1597     }
1598     if (i == env->tlb->nb_tlb) {
1599         /* No match.  Discard any shadow entries, if any of them match.  */
1600         for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
1601             tlb = &env->tlb->mmu.r4k.tlb[i];
1602             /* 1k pages are not supported. */
1603             mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1604             tag = env->CP0_EntryHi & ~mask;
1605             VPN = tlb->VPN & ~mask;
1606             /* Check ASID, virtual page number & size */
1607             if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
1608                 r4k_mips_tlb_flush_extra (env, i);
1609                 break;
1610             }
1611         }
1612
1613         env->CP0_Index |= 0x80000000;
1614     }
1615 }
1616
1617 void r4k_do_tlbr (void)
1618 {
1619     r4k_tlb_t *tlb;
1620     uint8_t ASID;
1621
1622     ASID = env->CP0_EntryHi & 0xFF;
1623     tlb = &env->tlb->mmu.r4k.tlb[env->CP0_Index % env->tlb->nb_tlb];
1624
1625     /* If this will change the current ASID, flush qemu's TLB.  */
1626     if (ASID != tlb->ASID)
1627         cpu_mips_tlb_flush (env, 1);
1628
1629     r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
1630
1631     env->CP0_EntryHi = tlb->VPN | tlb->ASID;
1632     env->CP0_PageMask = tlb->PageMask;
1633     env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
1634                         (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
1635     env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
1636                         (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
1637 }
1638
1639 #endif /* !CONFIG_USER_ONLY */
1640
1641 /* Specials */
1642 target_ulong do_di (target_ulong t0)
1643 {
1644     t0 = env->CP0_Status;
1645     env->CP0_Status = t0 & ~(1 << CP0St_IE);
1646     cpu_mips_update_irq(env);
1647
1648     return t0;
1649 }
1650
1651 target_ulong do_ei (target_ulong t0)
1652 {
1653     t0 = env->CP0_Status;
1654     env->CP0_Status = t0 | (1 << CP0St_IE);
1655     cpu_mips_update_irq(env);
1656
1657     return t0;
1658 }
1659
1660 void debug_pre_eret (void)
1661 {
1662     fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1663             env->PC[env->current_tc], env->CP0_EPC);
1664     if (env->CP0_Status & (1 << CP0St_ERL))
1665         fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1666     if (env->hflags & MIPS_HFLAG_DM)
1667         fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1668     fputs("\n", logfile);
1669 }
1670
1671 void debug_post_eret (void)
1672 {
1673     fprintf(logfile, "  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1674             env->PC[env->current_tc], env->CP0_EPC);
1675     if (env->CP0_Status & (1 << CP0St_ERL))
1676         fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1677     if (env->hflags & MIPS_HFLAG_DM)
1678         fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1679     switch (env->hflags & MIPS_HFLAG_KSU) {
1680     case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break;
1681     case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break;
1682     case MIPS_HFLAG_KM: fputs("\n", logfile); break;
1683     default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1684     }
1685 }
1686
1687 void do_eret (target_ulong t0)
1688 {
1689     if (loglevel & CPU_LOG_EXEC)
1690         debug_pre_eret();
1691     if (env->CP0_Status & (1 << CP0St_ERL)) {
1692         env->PC[env->current_tc] = env->CP0_ErrorEPC;
1693         env->CP0_Status &= ~(1 << CP0St_ERL);
1694     } else {
1695         env->PC[env->current_tc] = env->CP0_EPC;
1696         env->CP0_Status &= ~(1 << CP0St_EXL);
1697     }
1698     compute_hflags(env);
1699     if (loglevel & CPU_LOG_EXEC)
1700         debug_post_eret();
1701     env->CP0_LLAddr = 1;
1702 }
1703
1704 void do_deret (target_ulong t0)
1705 {
1706     if (loglevel & CPU_LOG_EXEC)
1707         debug_pre_eret();
1708     env->PC[env->current_tc] = env->CP0_DEPC;
1709     env->hflags &= MIPS_HFLAG_DM;
1710     compute_hflags(env);
1711     if (loglevel & CPU_LOG_EXEC)
1712         debug_post_eret();
1713     env->CP0_LLAddr = 1;
1714 }
1715
1716 target_ulong do_rdhwr_cpunum(target_ulong t0)
1717 {
1718     if ((env->hflags & MIPS_HFLAG_CP0) ||
1719         (env->CP0_HWREna & (1 << 0)))
1720         t0 = env->CP0_EBase & 0x3ff;
1721     else
1722         do_raise_exception(EXCP_RI);
1723
1724     return t0;
1725 }
1726
1727 target_ulong do_rdhwr_synci_step(target_ulong t0)
1728 {
1729     if ((env->hflags & MIPS_HFLAG_CP0) ||
1730         (env->CP0_HWREna & (1 << 1)))
1731         t0 = env->SYNCI_Step;
1732     else
1733         do_raise_exception(EXCP_RI);
1734
1735     return t0;
1736 }
1737
1738 target_ulong do_rdhwr_cc(target_ulong t0)
1739 {
1740     if ((env->hflags & MIPS_HFLAG_CP0) ||
1741         (env->CP0_HWREna & (1 << 2)))
1742         t0 = env->CP0_Count;
1743     else
1744         do_raise_exception(EXCP_RI);
1745
1746     return t0;
1747 }
1748
1749 target_ulong do_rdhwr_ccres(target_ulong t0)
1750 {
1751     if ((env->hflags & MIPS_HFLAG_CP0) ||
1752         (env->CP0_HWREna & (1 << 3)))
1753         t0 = env->CCRes;
1754     else
1755         do_raise_exception(EXCP_RI);
1756
1757     return t0;
1758 }
1759
1760 /* Bitfield operations. */
1761 target_ulong do_ext(target_ulong t0, target_ulong t1, uint32_t pos, uint32_t size)
1762 {
1763     return (int32_t)((t1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0));
1764 }
1765
1766 target_ulong do_ins(target_ulong t0, target_ulong t1, uint32_t pos, uint32_t size)
1767 {
1768     target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos;
1769
1770     return (int32_t)((t0 & ~mask) | ((t1 << pos) & mask));
1771 }
1772
1773 target_ulong do_wsbh(target_ulong t0, target_ulong t1)
1774 {
1775     return (int32_t)(((t1 << 8) & ~0x00FF00FF) | ((t1 >> 8) & 0x00FF00FF));
1776 }
1777
1778 #if defined(TARGET_MIPS64)
1779 target_ulong do_dext(target_ulong t0, target_ulong t1, uint32_t pos, uint32_t size)
1780 {
1781     return (t1 >> pos) & ((size < 64) ? ((1ULL << size) - 1) : ~0ULL);
1782 }
1783
1784 target_ulong do_dins(target_ulong t0, target_ulong t1, uint32_t pos, uint32_t size)
1785 {
1786     target_ulong mask = ((size < 64) ? ((1ULL << size) - 1) : ~0ULL) << pos;
1787
1788     return (t0 & ~mask) | ((t1 << pos) & mask);
1789 }
1790
1791 target_ulong do_dsbh(target_ulong t0, target_ulong t1)
1792 {
1793     return ((t1 << 8) & ~0x00FF00FF00FF00FFULL) | ((t1 >> 8) & 0x00FF00FF00FF00FFULL);
1794 }
1795
1796 target_ulong do_dshd(target_ulong t0, target_ulong t1)
1797 {
1798     t1 = ((t1 << 16) & ~0x0000FFFF0000FFFFULL) | ((t1 >> 16) & 0x0000FFFF0000FFFFULL);
1799     return (t1 << 32) | (t1 >> 32);
1800 }
1801 #endif
1802
1803 void do_pmon (int function)
1804 {
1805     function /= 2;
1806     switch (function) {
1807     case 2: /* TODO: char inbyte(int waitflag); */
1808         if (env->gpr[env->current_tc][4] == 0)
1809             env->gpr[env->current_tc][2] = -1;
1810         /* Fall through */
1811     case 11: /* TODO: char inbyte (void); */
1812         env->gpr[env->current_tc][2] = -1;
1813         break;
1814     case 3:
1815     case 12:
1816         printf("%c", (char)(env->gpr[env->current_tc][4] & 0xFF));
1817         break;
1818     case 17:
1819         break;
1820     case 158:
1821         {
1822             unsigned char *fmt = (void *)(unsigned long)env->gpr[env->current_tc][4];
1823             printf("%s", fmt);
1824         }
1825         break;
1826     }
1827 }
1828
1829 void do_wait (void)
1830 {
1831     env->halted = 1;
1832     do_raise_exception(EXCP_HLT);
1833 }
1834
1835 #if !defined(CONFIG_USER_ONLY)
1836
1837 static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
1838
1839 #define MMUSUFFIX _mmu
1840 #define ALIGNED_ONLY
1841
1842 #define SHIFT 0
1843 #include "softmmu_template.h"
1844
1845 #define SHIFT 1
1846 #include "softmmu_template.h"
1847
1848 #define SHIFT 2
1849 #include "softmmu_template.h"
1850
1851 #define SHIFT 3
1852 #include "softmmu_template.h"
1853
1854 static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
1855 {
1856     env->CP0_BadVAddr = addr;
1857     do_restore_state (retaddr);
1858     do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
1859 }
1860
1861 void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
1862 {
1863     TranslationBlock *tb;
1864     CPUState *saved_env;
1865     unsigned long pc;
1866     int ret;
1867
1868     /* XXX: hack to restore env in all cases, even if not called from
1869        generated code */
1870     saved_env = env;
1871     env = cpu_single_env;
1872     ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
1873     if (ret) {
1874         if (retaddr) {
1875             /* now we have a real cpu fault */
1876             pc = (unsigned long)retaddr;
1877             tb = tb_find_pc(pc);
1878             if (tb) {
1879                 /* the PC is inside the translated code. It means that we have
1880                    a virtual CPU fault */
1881                 cpu_restore_state(tb, env, pc, NULL);
1882             }
1883         }
1884         do_raise_exception_err(env->exception_index, env->error_code);
1885     }
1886     env = saved_env;
1887 }
1888
1889 void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
1890                           int unused)
1891 {
1892     if (is_exec)
1893         do_raise_exception(EXCP_IBE);
1894     else
1895         do_raise_exception(EXCP_DBE);
1896 }
1897 #endif /* !CONFIG_USER_ONLY */
1898
1899 /* Complex FPU operations which may need stack space. */
1900
1901 #define FLOAT_ONE32 make_float32(0x3f8 << 20)
1902 #define FLOAT_ONE64 make_float64(0x3ffULL << 52)
1903 #define FLOAT_TWO32 make_float32(1 << 30)
1904 #define FLOAT_TWO64 make_float64(1ULL << 62)
1905 #define FLOAT_QNAN32 0x7fbfffff
1906 #define FLOAT_QNAN64 0x7ff7ffffffffffffULL
1907 #define FLOAT_SNAN32 0x7fffffff
1908 #define FLOAT_SNAN64 0x7fffffffffffffffULL
1909
1910 /* convert MIPS rounding mode in FCR31 to IEEE library */
1911 unsigned int ieee_rm[] = {
1912     float_round_nearest_even,
1913     float_round_to_zero,
1914     float_round_up,
1915     float_round_down
1916 };
1917
1918 #define RESTORE_ROUNDING_MODE \
1919     set_float_rounding_mode(ieee_rm[env->fpu->fcr31 & 3], &env->fpu->fp_status)
1920
1921 target_ulong do_cfc1 (target_ulong t0, uint32_t reg)
1922 {
1923     switch (reg) {
1924     case 0:
1925         t0 = (int32_t)env->fpu->fcr0;
1926         break;
1927     case 25:
1928         t0 = ((env->fpu->fcr31 >> 24) & 0xfe) | ((env->fpu->fcr31 >> 23) & 0x1);
1929         break;
1930     case 26:
1931         t0 = env->fpu->fcr31 & 0x0003f07c;
1932         break;
1933     case 28:
1934         t0 = (env->fpu->fcr31 & 0x00000f83) | ((env->fpu->fcr31 >> 22) & 0x4);
1935         break;
1936     default:
1937         t0 = (int32_t)env->fpu->fcr31;
1938         break;
1939     }
1940
1941     return t0;
1942 }
1943
1944 void do_ctc1 (target_ulong t0, uint32_t reg)
1945 {
1946     switch(reg) {
1947     case 25:
1948         if (t0 & 0xffffff00)
1949             return;
1950         env->fpu->fcr31 = (env->fpu->fcr31 & 0x017fffff) | ((t0 & 0xfe) << 24) |
1951                      ((t0 & 0x1) << 23);
1952         break;
1953     case 26:
1954         if (t0 & 0x007c0000)
1955             return;
1956         env->fpu->fcr31 = (env->fpu->fcr31 & 0xfffc0f83) | (t0 & 0x0003f07c);
1957         break;
1958     case 28:
1959         if (t0 & 0x007c0000)
1960             return;
1961         env->fpu->fcr31 = (env->fpu->fcr31 & 0xfefff07c) | (t0 & 0x00000f83) |
1962                      ((t0 & 0x4) << 22);
1963         break;
1964     case 31:
1965         if (t0 & 0x007c0000)
1966             return;
1967         env->fpu->fcr31 = t0;
1968         break;
1969     default:
1970         return;
1971     }
1972     /* set rounding mode */
1973     RESTORE_ROUNDING_MODE;
1974     set_float_exception_flags(0, &env->fpu->fp_status);
1975     if ((GET_FP_ENABLE(env->fpu->fcr31) | 0x20) & GET_FP_CAUSE(env->fpu->fcr31))
1976         do_raise_exception(EXCP_FPE);
1977 }
1978
1979 static always_inline char ieee_ex_to_mips(char xcpt)
1980 {
1981     return (xcpt & float_flag_inexact) >> 5 |
1982            (xcpt & float_flag_underflow) >> 3 |
1983            (xcpt & float_flag_overflow) >> 1 |
1984            (xcpt & float_flag_divbyzero) << 1 |
1985            (xcpt & float_flag_invalid) << 4;
1986 }
1987
1988 static always_inline char mips_ex_to_ieee(char xcpt)
1989 {
1990     return (xcpt & FP_INEXACT) << 5 |
1991            (xcpt & FP_UNDERFLOW) << 3 |
1992            (xcpt & FP_OVERFLOW) << 1 |
1993            (xcpt & FP_DIV0) >> 1 |
1994            (xcpt & FP_INVALID) >> 4;
1995 }
1996
1997 static always_inline void update_fcr31(void)
1998 {
1999     int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fpu->fp_status));
2000
2001     SET_FP_CAUSE(env->fpu->fcr31, tmp);
2002     if (GET_FP_ENABLE(env->fpu->fcr31) & tmp)
2003         do_raise_exception(EXCP_FPE);
2004     else
2005         UPDATE_FP_FLAGS(env->fpu->fcr31, tmp);
2006 }
2007
2008 /* Float support.
2009    Single precition routines have a "s" suffix, double precision a
2010    "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2011    paired single lower "pl", paired single upper "pu".  */
2012
2013 #define FLOAT_OP(name, p) void do_float_##name##_##p(void)
2014
2015 /* unary operations, modifying fp status  */
2016 #define FLOAT_UNOP(name)  \
2017 FLOAT_OP(name, d)         \
2018 {                         \
2019     FDT2 = float64_ ## name(FDT0, &env->fpu->fp_status); \
2020 }                         \
2021 FLOAT_OP(name, s)         \
2022 {                         \
2023     FST2 = float32_ ## name(FST0, &env->fpu->fp_status); \
2024 }
2025 FLOAT_UNOP(sqrt)
2026 #undef FLOAT_UNOP
2027
2028 FLOAT_OP(cvtd, s)
2029 {
2030     set_float_exception_flags(0, &env->fpu->fp_status);
2031     FDT2 = float32_to_float64(FST0, &env->fpu->fp_status);
2032     update_fcr31();
2033 }
2034 FLOAT_OP(cvtd, w)
2035 {
2036     set_float_exception_flags(0, &env->fpu->fp_status);
2037     FDT2 = int32_to_float64(WT0, &env->fpu->fp_status);
2038     update_fcr31();
2039 }
2040 FLOAT_OP(cvtd, l)
2041 {
2042     set_float_exception_flags(0, &env->fpu->fp_status);
2043     FDT2 = int64_to_float64(DT0, &env->fpu->fp_status);
2044     update_fcr31();
2045 }
2046 FLOAT_OP(cvtl, d)
2047 {
2048     set_float_exception_flags(0, &env->fpu->fp_status);
2049     DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
2050     update_fcr31();
2051     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2052         DT2 = FLOAT_SNAN64;
2053 }
2054 FLOAT_OP(cvtl, s)
2055 {
2056     set_float_exception_flags(0, &env->fpu->fp_status);
2057     DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
2058     update_fcr31();
2059     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2060         DT2 = FLOAT_SNAN64;
2061 }
2062
2063 FLOAT_OP(cvtps, pw)
2064 {
2065     set_float_exception_flags(0, &env->fpu->fp_status);
2066     FST2 = int32_to_float32(WT0, &env->fpu->fp_status);
2067     FSTH2 = int32_to_float32(WTH0, &env->fpu->fp_status);
2068     update_fcr31();
2069 }
2070 FLOAT_OP(cvtpw, ps)
2071 {
2072     set_float_exception_flags(0, &env->fpu->fp_status);
2073     WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
2074     WTH2 = float32_to_int32(FSTH0, &env->fpu->fp_status);
2075     update_fcr31();
2076     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2077         WT2 = FLOAT_SNAN32;
2078 }
2079 FLOAT_OP(cvts, d)
2080 {
2081     set_float_exception_flags(0, &env->fpu->fp_status);
2082     FST2 = float64_to_float32(FDT0, &env->fpu->fp_status);
2083     update_fcr31();
2084 }
2085 FLOAT_OP(cvts, w)
2086 {
2087     set_float_exception_flags(0, &env->fpu->fp_status);
2088     FST2 = int32_to_float32(WT0, &env->fpu->fp_status);
2089     update_fcr31();
2090 }
2091 FLOAT_OP(cvts, l)
2092 {
2093     set_float_exception_flags(0, &env->fpu->fp_status);
2094     FST2 = int64_to_float32(DT0, &env->fpu->fp_status);
2095     update_fcr31();
2096 }
2097 FLOAT_OP(cvts, pl)
2098 {
2099     set_float_exception_flags(0, &env->fpu->fp_status);
2100     WT2 = WT0;
2101     update_fcr31();
2102 }
2103 FLOAT_OP(cvts, pu)
2104 {
2105     set_float_exception_flags(0, &env->fpu->fp_status);
2106     WT2 = WTH0;
2107     update_fcr31();
2108 }
2109 FLOAT_OP(cvtw, s)
2110 {
2111     set_float_exception_flags(0, &env->fpu->fp_status);
2112     WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
2113     update_fcr31();
2114     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2115         WT2 = FLOAT_SNAN32;
2116 }
2117 FLOAT_OP(cvtw, d)
2118 {
2119     set_float_exception_flags(0, &env->fpu->fp_status);
2120     WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
2121     update_fcr31();
2122     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2123         WT2 = FLOAT_SNAN32;
2124 }
2125
2126 FLOAT_OP(roundl, d)
2127 {
2128     set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
2129     DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
2130     RESTORE_ROUNDING_MODE;
2131     update_fcr31();
2132     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2133         DT2 = FLOAT_SNAN64;
2134 }
2135 FLOAT_OP(roundl, s)
2136 {
2137     set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
2138     DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
2139     RESTORE_ROUNDING_MODE;
2140     update_fcr31();
2141     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2142         DT2 = FLOAT_SNAN64;
2143 }
2144 FLOAT_OP(roundw, d)
2145 {
2146     set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
2147     WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
2148     RESTORE_ROUNDING_MODE;
2149     update_fcr31();
2150     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2151         WT2 = FLOAT_SNAN32;
2152 }
2153 FLOAT_OP(roundw, s)
2154 {
2155     set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
2156     WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
2157     RESTORE_ROUNDING_MODE;
2158     update_fcr31();
2159     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2160         WT2 = FLOAT_SNAN32;
2161 }
2162
2163 FLOAT_OP(truncl, d)
2164 {
2165     DT2 = float64_to_int64_round_to_zero(FDT0, &env->fpu->fp_status);
2166     update_fcr31();
2167     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2168         DT2 = FLOAT_SNAN64;
2169 }
2170 FLOAT_OP(truncl, s)
2171 {
2172     DT2 = float32_to_int64_round_to_zero(FST0, &env->fpu->fp_status);
2173     update_fcr31();
2174     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2175         DT2 = FLOAT_SNAN64;
2176 }
2177 FLOAT_OP(truncw, d)
2178 {
2179     WT2 = float64_to_int32_round_to_zero(FDT0, &env->fpu->fp_status);
2180     update_fcr31();
2181     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2182         WT2 = FLOAT_SNAN32;
2183 }
2184 FLOAT_OP(truncw, s)
2185 {
2186     WT2 = float32_to_int32_round_to_zero(FST0, &env->fpu->fp_status);
2187     update_fcr31();
2188     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2189         WT2 = FLOAT_SNAN32;
2190 }
2191
2192 FLOAT_OP(ceill, d)
2193 {
2194     set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
2195     DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
2196     RESTORE_ROUNDING_MODE;
2197     update_fcr31();
2198     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2199         DT2 = FLOAT_SNAN64;
2200 }
2201 FLOAT_OP(ceill, s)
2202 {
2203     set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
2204     DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
2205     RESTORE_ROUNDING_MODE;
2206     update_fcr31();
2207     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2208         DT2 = FLOAT_SNAN64;
2209 }
2210 FLOAT_OP(ceilw, d)
2211 {
2212     set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
2213     WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
2214     RESTORE_ROUNDING_MODE;
2215     update_fcr31();
2216     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2217         WT2 = FLOAT_SNAN32;
2218 }
2219 FLOAT_OP(ceilw, s)
2220 {
2221     set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
2222     WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
2223     RESTORE_ROUNDING_MODE;
2224     update_fcr31();
2225     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2226         WT2 = FLOAT_SNAN32;
2227 }
2228
2229 FLOAT_OP(floorl, d)
2230 {
2231     set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
2232     DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
2233     RESTORE_ROUNDING_MODE;
2234     update_fcr31();
2235     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2236         DT2 = FLOAT_SNAN64;
2237 }
2238 FLOAT_OP(floorl, s)
2239 {
2240     set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
2241     DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
2242     RESTORE_ROUNDING_MODE;
2243     update_fcr31();
2244     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2245         DT2 = FLOAT_SNAN64;
2246 }
2247 FLOAT_OP(floorw, d)
2248 {
2249     set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
2250     WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
2251     RESTORE_ROUNDING_MODE;
2252     update_fcr31();
2253     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2254         WT2 = FLOAT_SNAN32;
2255 }
2256 FLOAT_OP(floorw, s)
2257 {
2258     set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
2259     WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
2260     RESTORE_ROUNDING_MODE;
2261     update_fcr31();
2262     if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
2263         WT2 = FLOAT_SNAN32;
2264 }
2265
2266 /* unary operations, not modifying fp status  */
2267 #define FLOAT_UNOP(name)  \
2268 FLOAT_OP(name, d)         \
2269 {                         \
2270     FDT2 = float64_ ## name(FDT0);   \
2271 }                         \
2272 FLOAT_OP(name, s)         \
2273 {                         \
2274     FST2 = float32_ ## name(FST0);   \
2275 }                         \
2276 FLOAT_OP(name, ps)        \
2277 {                         \
2278     FST2 = float32_ ## name(FST0);   \
2279     FSTH2 = float32_ ## name(FSTH0); \
2280 }
2281 FLOAT_UNOP(abs)
2282 FLOAT_UNOP(chs)
2283 #undef FLOAT_UNOP
2284
2285 /* MIPS specific unary operations */
2286 FLOAT_OP(recip, d)
2287 {
2288     set_float_exception_flags(0, &env->fpu->fp_status);
2289     FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status);
2290     update_fcr31();
2291 }
2292 FLOAT_OP(recip, s)
2293 {
2294     set_float_exception_flags(0, &env->fpu->fp_status);
2295     FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
2296     update_fcr31();
2297 }
2298
2299 FLOAT_OP(rsqrt, d)
2300 {
2301     set_float_exception_flags(0, &env->fpu->fp_status);
2302     FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status);
2303     FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status);
2304     update_fcr31();
2305 }
2306 FLOAT_OP(rsqrt, s)
2307 {
2308     set_float_exception_flags(0, &env->fpu->fp_status);
2309     FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
2310     FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
2311     update_fcr31();
2312 }
2313
2314 FLOAT_OP(recip1, d)
2315 {
2316     set_float_exception_flags(0, &env->fpu->fp_status);
2317     FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status);
2318     update_fcr31();
2319 }
2320 FLOAT_OP(recip1, s)
2321 {
2322     set_float_exception_flags(0, &env->fpu->fp_status);
2323     FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
2324     update_fcr31();
2325 }
2326 FLOAT_OP(recip1, ps)
2327 {
2328     set_float_exception_flags(0, &env->fpu->fp_status);
2329     FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
2330     FSTH2 = float32_div(FLOAT_ONE32, FSTH0, &env->fpu->fp_status);
2331     update_fcr31();
2332 }
2333
2334 FLOAT_OP(rsqrt1, d)
2335 {
2336     set_float_exception_flags(0, &env->fpu->fp_status);
2337     FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status);
2338     FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status);
2339     update_fcr31();
2340 }
2341 FLOAT_OP(rsqrt1, s)
2342 {
2343     set_float_exception_flags(0, &env->fpu->fp_status);
2344     FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
2345     FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
2346     update_fcr31();
2347 }
2348 FLOAT_OP(rsqrt1, ps)
2349 {
2350     set_float_exception_flags(0, &env->fpu->fp_status);
2351     FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
2352     FSTH2 = float32_sqrt(FSTH0, &env->fpu->fp_status);
2353     FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
2354     FSTH2 = float32_div(FLOAT_ONE32, FSTH2, &env->fpu->fp_status);
2355     update_fcr31();
2356 }
2357
2358 /* binary operations */
2359 #define FLOAT_BINOP(name) \
2360 FLOAT_OP(name, d)         \
2361 {                         \
2362     set_float_exception_flags(0, &env->fpu->fp_status);            \
2363     FDT2 = float64_ ## name (FDT0, FDT1, &env->fpu->fp_status);    \
2364     update_fcr31();                                                \
2365     if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID)                \
2366         DT2 = FLOAT_QNAN64;                                        \
2367 }                         \
2368 FLOAT_OP(name, s)         \
2369 {                         \
2370     set_float_exception_flags(0, &env->fpu->fp_status);            \
2371     FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status);    \
2372     update_fcr31();                                                \
2373     if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID)                \
2374         WT2 = FLOAT_QNAN32;                                        \
2375 }                         \
2376 FLOAT_OP(name, ps)        \
2377 {                         \
2378     set_float_exception_flags(0, &env->fpu->fp_status);            \
2379     FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status);    \
2380     FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fpu->fp_status); \
2381     update_fcr31();       \
2382     if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) {              \
2383         WT2 = FLOAT_QNAN32;                                        \
2384         WTH2 = FLOAT_QNAN32;                                       \
2385     }                     \
2386 }
2387 FLOAT_BINOP(add)
2388 FLOAT_BINOP(sub)
2389 FLOAT_BINOP(mul)
2390 FLOAT_BINOP(div)
2391 #undef FLOAT_BINOP
2392
2393 /* ternary operations */
2394 #define FLOAT_TERNOP(name1, name2) \
2395 FLOAT_OP(name1 ## name2, d)        \
2396 {                                  \
2397     FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status);    \
2398     FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status);    \
2399 }                                  \
2400 FLOAT_OP(name1 ## name2, s)        \
2401 {                                  \
2402     FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status);    \
2403     FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status);    \
2404 }                                  \
2405 FLOAT_OP(name1 ## name2, ps)       \
2406 {                                  \
2407     FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status);    \
2408     FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \
2409     FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status);    \
2410     FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \
2411 }
2412 FLOAT_TERNOP(mul, add)
2413 FLOAT_TERNOP(mul, sub)
2414 #undef FLOAT_TERNOP
2415
2416 /* negated ternary operations */
2417 #define FLOAT_NTERNOP(name1, name2) \
2418 FLOAT_OP(n ## name1 ## name2, d)    \
2419 {                                   \
2420     FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status);    \
2421     FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status);    \
2422     FDT2 = float64_chs(FDT2);       \
2423 }                                   \
2424 FLOAT_OP(n ## name1 ## name2, s)    \
2425 {                                   \
2426     FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status);    \
2427     FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status);    \
2428     FST2 = float32_chs(FST2);       \
2429 }                                   \
2430 FLOAT_OP(n ## name1 ## name2, ps)   \
2431 {                                   \
2432     FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status);    \
2433     FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \
2434     FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status);    \
2435     FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \
2436     FST2 = float32_chs(FST2);       \
2437     FSTH2 = float32_chs(FSTH2);     \
2438 }
2439 FLOAT_NTERNOP(mul, add)
2440 FLOAT_NTERNOP(mul, sub)
2441 #undef FLOAT_NTERNOP
2442
2443 /* MIPS specific binary operations */
2444 FLOAT_OP(recip2, d)
2445 {
2446     set_float_exception_flags(0, &env->fpu->fp_status);
2447     FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status);
2448     FDT2 = float64_chs(float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status));
2449     update_fcr31();
2450 }
2451 FLOAT_OP(recip2, s)
2452 {
2453     set_float_exception_flags(0, &env->fpu->fp_status);
2454     FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
2455     FST2 = float32_chs(float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status));
2456     update_fcr31();
2457 }
2458 FLOAT_OP(recip2, ps)
2459 {
2460     set_float_exception_flags(0, &env->fpu->fp_status);
2461     FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
2462     FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status);
2463     FST2 = float32_chs(float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status));
2464     FSTH2 = float32_chs(float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status));
2465     update_fcr31();
2466 }
2467
2468 FLOAT_OP(rsqrt2, d)
2469 {
2470     set_float_exception_flags(0, &env->fpu->fp_status);
2471     FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status);
2472     FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status);
2473     FDT2 = float64_chs(float64_div(FDT2, FLOAT_TWO64, &env->fpu->fp_status));
2474     update_fcr31();
2475 }
2476 FLOAT_OP(rsqrt2, s)
2477 {
2478     set_float_exception_flags(0, &env->fpu->fp_status);
2479     FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
2480     FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status);
2481     FST2 = float32_chs(float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status));
2482     update_fcr31();
2483 }
2484 FLOAT_OP(rsqrt2, ps)
2485 {
2486     set_float_exception_flags(0, &env->fpu->fp_status);
2487     FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
2488     FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status);
2489     FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status);
2490     FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status);
2491     FST2 = float32_chs(float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status));
2492     FSTH2 = float32_chs(float32_div(FSTH2, FLOAT_TWO32, &env->fpu->fp_status));
2493     update_fcr31();
2494 }
2495
2496 FLOAT_OP(addr, ps)
2497 {
2498     set_float_exception_flags(0, &env->fpu->fp_status);
2499     FST2 = float32_add (FST0, FSTH0, &env->fpu->fp_status);
2500     FSTH2 = float32_add (FST1, FSTH1, &env->fpu->fp_status);
2501     update_fcr31();
2502 }
2503
2504 FLOAT_OP(mulr, ps)
2505 {
2506     set_float_exception_flags(0, &env->fpu->fp_status);
2507     FST2 = float32_mul (FST0, FSTH0, &env->fpu->fp_status);
2508     FSTH2 = float32_mul (FST1, FSTH1, &env->fpu->fp_status);
2509     update_fcr31();
2510 }
2511
2512 /* compare operations */
2513 #define FOP_COND_D(op, cond)                   \
2514 void do_cmp_d_ ## op (long cc)                 \
2515 {                                              \
2516     int c = cond;                              \
2517     update_fcr31();                            \
2518     if (c)                                     \
2519         SET_FP_COND(cc, env->fpu);             \
2520     else                                       \
2521         CLEAR_FP_COND(cc, env->fpu);           \
2522 }                                              \
2523 void do_cmpabs_d_ ## op (long cc)              \
2524 {                                              \
2525     int c;                                     \
2526     FDT0 = float64_abs(FDT0);                  \
2527     FDT1 = float64_abs(FDT1);                  \
2528     c = cond;                                  \
2529     update_fcr31();                            \
2530     if (c)                                     \
2531         SET_FP_COND(cc, env->fpu);             \
2532     else                                       \
2533         CLEAR_FP_COND(cc, env->fpu);           \
2534 }
2535
2536 int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
2537 {
2538     if (float64_is_signaling_nan(a) ||
2539         float64_is_signaling_nan(b) ||
2540         (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
2541         float_raise(float_flag_invalid, status);
2542         return 1;
2543     } else if (float64_is_nan(a) || float64_is_nan(b)) {
2544         return 1;
2545     } else {
2546         return 0;
2547     }
2548 }
2549
2550 /* NOTE: the comma operator will make "cond" to eval to false,
2551  * but float*_is_unordered() is still called. */
2552 FOP_COND_D(f,   (float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status), 0))
2553 FOP_COND_D(un,  float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status))
2554 FOP_COND_D(eq,  !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status))
2555 FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)  || float64_eq(FDT0, FDT1, &env->fpu->fp_status))
2556 FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status))
2557 FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)  || float64_lt(FDT0, FDT1, &env->fpu->fp_status))
2558 FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status))
2559 FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)  || float64_le(FDT0, FDT1, &env->fpu->fp_status))
2560 /* NOTE: the comma operator will make "cond" to eval to false,
2561  * but float*_is_unordered() is still called. */
2562 FOP_COND_D(sf,  (float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status), 0))
2563 FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status))
2564 FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status))
2565 FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)  || float64_eq(FDT0, FDT1, &env->fpu->fp_status))
2566 FOP_COND_D(lt,  !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status))
2567 FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)  || float64_lt(FDT0, FDT1, &env->fpu->fp_status))
2568 FOP_COND_D(le,  !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status))
2569 FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)  || float64_le(FDT0, FDT1, &env->fpu->fp_status))
2570
2571 #define FOP_COND_S(op, cond)                   \
2572 void do_cmp_s_ ## op (long cc)                 \
2573 {                                              \
2574     int c = cond;                              \
2575     update_fcr31();                            \
2576     if (c)                                     \
2577         SET_FP_COND(cc, env->fpu);             \
2578     else                                       \
2579         CLEAR_FP_COND(cc, env->fpu);           \
2580 }                                              \
2581 void do_cmpabs_s_ ## op (long cc)              \
2582 {                                              \
2583     int c;                                     \
2584     FST0 = float32_abs(FST0);                  \
2585     FST1 = float32_abs(FST1);                  \
2586     c = cond;                                  \
2587     update_fcr31();                            \
2588     if (c)                                     \
2589         SET_FP_COND(cc, env->fpu);             \
2590     else                                       \
2591         CLEAR_FP_COND(cc, env->fpu);           \
2592 }
2593
2594 flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
2595 {
2596     if (float32_is_signaling_nan(a) ||
2597         float32_is_signaling_nan(b) ||
2598         (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
2599         float_raise(float_flag_invalid, status);
2600         return 1;
2601     } else if (float32_is_nan(a) || float32_is_nan(b)) {
2602         return 1;
2603     } else {
2604         return 0;
2605     }
2606 }
2607
2608 /* NOTE: the comma operator will make "cond" to eval to false,
2609  * but float*_is_unordered() is still called. */
2610 FOP_COND_S(f,   (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0))
2611 FOP_COND_S(un,  float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status))
2612 FOP_COND_S(eq,  !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status))
2613 FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)  || float32_eq(FST0, FST1, &env->fpu->fp_status))
2614 FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status))
2615 FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)  || float32_lt(FST0, FST1, &env->fpu->fp_status))
2616 FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status))
2617 FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)  || float32_le(FST0, FST1, &env->fpu->fp_status))
2618 /* NOTE: the comma operator will make "cond" to eval to false,
2619  * but float*_is_unordered() is still called. */
2620 FOP_COND_S(sf,  (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0))
2621 FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status))
2622 FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status))
2623 FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)  || float32_eq(FST0, FST1, &env->fpu->fp_status))
2624 FOP_COND_S(lt,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status))
2625 FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)  || float32_lt(FST0, FST1, &env->fpu->fp_status))
2626 FOP_COND_S(le,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status))
2627 FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)  || float32_le(FST0, FST1, &env->fpu->fp_status))
2628
2629 #define FOP_COND_PS(op, condl, condh)          \
2630 void do_cmp_ps_ ## op (long cc)                \
2631 {                                              \
2632     int cl = condl;                            \
2633     int ch = condh;                            \
2634     update_fcr31();                            \
2635     if (cl)                                    \
2636         SET_FP_COND(cc, env->fpu);             \
2637     else                                       \
2638         CLEAR_FP_COND(cc, env->fpu);           \
2639     if (ch)                                    \
2640         SET_FP_COND(cc + 1, env->fpu);         \
2641     else                                       \
2642         CLEAR_FP_COND(cc + 1, env->fpu);       \
2643 }                                              \
2644 void do_cmpabs_ps_ ## op (long cc)             \
2645 {                                              \
2646     int cl, ch;                                \
2647     FST0 = float32_abs(FST0);                  \
2648     FSTH0 = float32_abs(FSTH0);                \
2649     FST1 = float32_abs(FST1);                  \
2650     FSTH1 = float32_abs(FSTH1);                \
2651     cl = condl;                                \
2652     ch = condh;                                \
2653     update_fcr31();                            \
2654     if (cl)                                    \
2655         SET_FP_COND(cc, env->fpu);             \
2656     else                                       \
2657         CLEAR_FP_COND(cc, env->fpu);           \
2658     if (ch)                                    \
2659         SET_FP_COND(cc + 1, env->fpu);         \
2660     else                                       \
2661         CLEAR_FP_COND(cc + 1, env->fpu);       \
2662 }
2663
2664 /* NOTE: the comma operator will make "cond" to eval to false,
2665  * but float*_is_unordered() is still called. */
2666 FOP_COND_PS(f,   (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0),
2667                  (float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status), 0))
2668 FOP_COND_PS(un,  float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status),
2669                  float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status))
2670 FOP_COND_PS(eq,  !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)   && float32_eq(FST0, FST1, &env->fpu->fp_status),
2671                  !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
2672 FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)    || float32_eq(FST0, FST1, &env->fpu->fp_status),
2673                  float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
2674 FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)   && float32_lt(FST0, FST1, &env->fpu->fp_status),
2675                  !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
2676 FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)    || float32_lt(FST0, FST1, &env->fpu->fp_status),
2677                  float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
2678 FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)   && float32_le(FST0, FST1, &env->fpu->fp_status),
2679                  !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
2680 FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)    || float32_le(FST0, FST1, &env->fpu->fp_status),
2681                  float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
2682 /* NOTE: the comma operator will make "cond" to eval to false,
2683  * but float*_is_unordered() is still called. */
2684 FOP_COND_PS(sf,  (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0),
2685                  (float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status), 0))
2686 FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status),
2687                  float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status))
2688 FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)   && float32_eq(FST0, FST1, &env->fpu->fp_status),
2689                  !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
2690 FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)    || float32_eq(FST0, FST1, &env->fpu->fp_status),
2691                  float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
2692 FOP_COND_PS(lt,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)   && float32_lt(FST0, FST1, &env->fpu->fp_status),
2693                  !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
2694 FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)    || float32_lt(FST0, FST1, &env->fpu->fp_status),
2695                  float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
2696 FOP_COND_PS(le,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)   && float32_le(FST0, FST1, &env->fpu->fp_status),
2697                  !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
2698 FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)    || float32_le(FST0, FST1, &env->fpu->fp_status),
2699                  float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_le(FSTH0, FSTH1, &env->fpu->fp_status))