|
|
1.1 root 1: /*
2: * MIPS emulation micro-operations for qemu.
3: *
4: * Copyright (c) 2004-2005 Jocelyn Mayer
1.1.1.4 ! root 5: * Copyright (c) 2006 Marius Groeger (FPU operations)
1.1 root 6: *
7: * This library is free software; you can redistribute it and/or
8: * modify it under the terms of the GNU Lesser General Public
9: * License as published by the Free Software Foundation; either
10: * version 2 of the License, or (at your option) any later version.
11: *
12: * This library is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15: * Lesser General Public License for more details.
16: *
17: * You should have received a copy of the GNU Lesser General Public
18: * License along with this library; if not, write to the Free Software
19: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20: */
21:
22: #include "config.h"
23: #include "exec.h"
24:
25: #ifndef CALL_FROM_TB0
26: #define CALL_FROM_TB0(func) func();
27: #endif
28: #ifndef CALL_FROM_TB1
29: #define CALL_FROM_TB1(func, arg0) func(arg0);
30: #endif
31: #ifndef CALL_FROM_TB1_CONST16
32: #define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0);
33: #endif
34: #ifndef CALL_FROM_TB2
35: #define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1);
36: #endif
37: #ifndef CALL_FROM_TB2_CONST16
38: #define CALL_FROM_TB2_CONST16(func, arg0, arg1) \
39: CALL_FROM_TB2(func, arg0, arg1);
40: #endif
41: #ifndef CALL_FROM_TB3
42: #define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2);
43: #endif
44: #ifndef CALL_FROM_TB4
45: #define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \
46: func(arg0, arg1, arg2, arg3);
47: #endif
48:
49: #define REG 1
50: #include "op_template.c"
51: #undef REG
52: #define REG 2
53: #include "op_template.c"
54: #undef REG
55: #define REG 3
56: #include "op_template.c"
57: #undef REG
58: #define REG 4
59: #include "op_template.c"
60: #undef REG
61: #define REG 5
62: #include "op_template.c"
63: #undef REG
64: #define REG 6
65: #include "op_template.c"
66: #undef REG
67: #define REG 7
68: #include "op_template.c"
69: #undef REG
70: #define REG 8
71: #include "op_template.c"
72: #undef REG
73: #define REG 9
74: #include "op_template.c"
75: #undef REG
76: #define REG 10
77: #include "op_template.c"
78: #undef REG
79: #define REG 11
80: #include "op_template.c"
81: #undef REG
82: #define REG 12
83: #include "op_template.c"
84: #undef REG
85: #define REG 13
86: #include "op_template.c"
87: #undef REG
88: #define REG 14
89: #include "op_template.c"
90: #undef REG
91: #define REG 15
92: #include "op_template.c"
93: #undef REG
94: #define REG 16
95: #include "op_template.c"
96: #undef REG
97: #define REG 17
98: #include "op_template.c"
99: #undef REG
100: #define REG 18
101: #include "op_template.c"
102: #undef REG
103: #define REG 19
104: #include "op_template.c"
105: #undef REG
106: #define REG 20
107: #include "op_template.c"
108: #undef REG
109: #define REG 21
110: #include "op_template.c"
111: #undef REG
112: #define REG 22
113: #include "op_template.c"
114: #undef REG
115: #define REG 23
116: #include "op_template.c"
117: #undef REG
118: #define REG 24
119: #include "op_template.c"
120: #undef REG
121: #define REG 25
122: #include "op_template.c"
123: #undef REG
124: #define REG 26
125: #include "op_template.c"
126: #undef REG
127: #define REG 27
128: #include "op_template.c"
129: #undef REG
130: #define REG 28
131: #include "op_template.c"
132: #undef REG
133: #define REG 29
134: #include "op_template.c"
135: #undef REG
136: #define REG 30
137: #include "op_template.c"
138: #undef REG
139: #define REG 31
140: #include "op_template.c"
141: #undef REG
142:
143: #define TN T0
144: #include "op_template.c"
145: #undef TN
146: #define TN T1
147: #include "op_template.c"
148: #undef TN
149: #define TN T2
150: #include "op_template.c"
151: #undef TN
152:
1.1.1.4 ! root 153: #ifdef MIPS_USES_FPU
! 154:
! 155: #define SFREG 0
! 156: #define DFREG 0
! 157: #include "fop_template.c"
! 158: #undef SFREG
! 159: #undef DFREG
! 160: #define SFREG 1
! 161: #include "fop_template.c"
! 162: #undef SFREG
! 163: #define SFREG 2
! 164: #define DFREG 2
! 165: #include "fop_template.c"
! 166: #undef SFREG
! 167: #undef DFREG
! 168: #define SFREG 3
! 169: #include "fop_template.c"
! 170: #undef SFREG
! 171: #define SFREG 4
! 172: #define DFREG 4
! 173: #include "fop_template.c"
! 174: #undef SFREG
! 175: #undef DFREG
! 176: #define SFREG 5
! 177: #include "fop_template.c"
! 178: #undef SFREG
! 179: #define SFREG 6
! 180: #define DFREG 6
! 181: #include "fop_template.c"
! 182: #undef SFREG
! 183: #undef DFREG
! 184: #define SFREG 7
! 185: #include "fop_template.c"
! 186: #undef SFREG
! 187: #define SFREG 8
! 188: #define DFREG 8
! 189: #include "fop_template.c"
! 190: #undef SFREG
! 191: #undef DFREG
! 192: #define SFREG 9
! 193: #include "fop_template.c"
! 194: #undef SFREG
! 195: #define SFREG 10
! 196: #define DFREG 10
! 197: #include "fop_template.c"
! 198: #undef SFREG
! 199: #undef DFREG
! 200: #define SFREG 11
! 201: #include "fop_template.c"
! 202: #undef SFREG
! 203: #define SFREG 12
! 204: #define DFREG 12
! 205: #include "fop_template.c"
! 206: #undef SFREG
! 207: #undef DFREG
! 208: #define SFREG 13
! 209: #include "fop_template.c"
! 210: #undef SFREG
! 211: #define SFREG 14
! 212: #define DFREG 14
! 213: #include "fop_template.c"
! 214: #undef SFREG
! 215: #undef DFREG
! 216: #define SFREG 15
! 217: #include "fop_template.c"
! 218: #undef SFREG
! 219: #define SFREG 16
! 220: #define DFREG 16
! 221: #include "fop_template.c"
! 222: #undef SFREG
! 223: #undef DFREG
! 224: #define SFREG 17
! 225: #include "fop_template.c"
! 226: #undef SFREG
! 227: #define SFREG 18
! 228: #define DFREG 18
! 229: #include "fop_template.c"
! 230: #undef SFREG
! 231: #undef DFREG
! 232: #define SFREG 19
! 233: #include "fop_template.c"
! 234: #undef SFREG
! 235: #define SFREG 20
! 236: #define DFREG 20
! 237: #include "fop_template.c"
! 238: #undef SFREG
! 239: #undef DFREG
! 240: #define SFREG 21
! 241: #include "fop_template.c"
! 242: #undef SFREG
! 243: #define SFREG 22
! 244: #define DFREG 22
! 245: #include "fop_template.c"
! 246: #undef SFREG
! 247: #undef DFREG
! 248: #define SFREG 23
! 249: #include "fop_template.c"
! 250: #undef SFREG
! 251: #define SFREG 24
! 252: #define DFREG 24
! 253: #include "fop_template.c"
! 254: #undef SFREG
! 255: #undef DFREG
! 256: #define SFREG 25
! 257: #include "fop_template.c"
! 258: #undef SFREG
! 259: #define SFREG 26
! 260: #define DFREG 26
! 261: #include "fop_template.c"
! 262: #undef SFREG
! 263: #undef DFREG
! 264: #define SFREG 27
! 265: #include "fop_template.c"
! 266: #undef SFREG
! 267: #define SFREG 28
! 268: #define DFREG 28
! 269: #include "fop_template.c"
! 270: #undef SFREG
! 271: #undef DFREG
! 272: #define SFREG 29
! 273: #include "fop_template.c"
! 274: #undef SFREG
! 275: #define SFREG 30
! 276: #define DFREG 30
! 277: #include "fop_template.c"
! 278: #undef SFREG
! 279: #undef DFREG
! 280: #define SFREG 31
! 281: #include "fop_template.c"
! 282: #undef SFREG
! 283:
! 284: #define FTN
! 285: #include "fop_template.c"
! 286: #undef FTN
! 287:
! 288: #endif
! 289:
1.1 root 290: void op_dup_T0 (void)
291: {
292: T2 = T0;
293: RETURN();
294: }
295:
296: void op_load_HI (void)
297: {
298: T0 = env->HI;
299: RETURN();
300: }
301:
302: void op_store_HI (void)
303: {
304: env->HI = T0;
305: RETURN();
306: }
307:
308: void op_load_LO (void)
309: {
310: T0 = env->LO;
311: RETURN();
312: }
313:
314: void op_store_LO (void)
315: {
316: env->LO = T0;
317: RETURN();
318: }
319:
320: /* Load and store */
321: #define MEMSUFFIX _raw
322: #include "op_mem.c"
323: #undef MEMSUFFIX
324: #if !defined(CONFIG_USER_ONLY)
325: #define MEMSUFFIX _user
326: #include "op_mem.c"
327: #undef MEMSUFFIX
328:
329: #define MEMSUFFIX _kernel
330: #include "op_mem.c"
331: #undef MEMSUFFIX
332: #endif
333:
334: /* Arithmetic */
335: void op_add (void)
336: {
337: T0 += T1;
338: RETURN();
339: }
340:
341: void op_addo (void)
342: {
343: target_ulong tmp;
344:
345: tmp = T0;
346: T0 += T1;
1.1.1.3 root 347: if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 31) {
348: /* operands of same sign, result different sign */
1.1.1.2 root 349: CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
1.1 root 350: }
351: RETURN();
352: }
353:
354: void op_sub (void)
355: {
356: T0 -= T1;
357: RETURN();
358: }
359:
360: void op_subo (void)
361: {
362: target_ulong tmp;
363:
364: tmp = T0;
365: T0 = (int32_t)T0 - (int32_t)T1;
1.1.1.3 root 366: if (((tmp ^ T1) & (tmp ^ T0)) >> 31) {
367: /* operands of different sign, first operand and result different sign */
1.1.1.2 root 368: CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
1.1 root 369: }
370: RETURN();
371: }
372:
373: void op_mul (void)
374: {
375: T0 = (int32_t)T0 * (int32_t)T1;
376: RETURN();
377: }
378:
379: void op_div (void)
380: {
381: if (T1 != 0) {
382: env->LO = (int32_t)T0 / (int32_t)T1;
383: env->HI = (int32_t)T0 % (int32_t)T1;
384: }
385: RETURN();
386: }
387:
388: void op_divu (void)
389: {
390: if (T1 != 0) {
391: env->LO = T0 / T1;
392: env->HI = T0 % T1;
393: }
394: RETURN();
395: }
396:
397: /* Logical */
398: void op_and (void)
399: {
400: T0 &= T1;
401: RETURN();
402: }
403:
404: void op_nor (void)
405: {
406: T0 = ~(T0 | T1);
407: RETURN();
408: }
409:
410: void op_or (void)
411: {
412: T0 |= T1;
413: RETURN();
414: }
415:
416: void op_xor (void)
417: {
418: T0 ^= T1;
419: RETURN();
420: }
421:
422: void op_sll (void)
423: {
424: T0 = T0 << T1;
425: RETURN();
426: }
427:
428: void op_sra (void)
429: {
430: T0 = (int32_t)T0 >> T1;
431: RETURN();
432: }
433:
434: void op_srl (void)
435: {
436: T0 = T0 >> T1;
437: RETURN();
438: }
439:
440: void op_sllv (void)
441: {
442: T0 = T1 << (T0 & 0x1F);
443: RETURN();
444: }
445:
446: void op_srav (void)
447: {
448: T0 = (int32_t)T1 >> (T0 & 0x1F);
449: RETURN();
450: }
451:
452: void op_srlv (void)
453: {
454: T0 = T1 >> (T0 & 0x1F);
455: RETURN();
456: }
457:
458: void op_clo (void)
459: {
460: int n;
461:
462: if (T0 == (target_ulong)-1) {
463: T0 = 32;
464: } else {
465: for (n = 0; n < 32; n++) {
466: if (!(T0 & (1 << 31)))
467: break;
468: T0 = T0 << 1;
469: }
470: T0 = n;
471: }
472: RETURN();
473: }
474:
475: void op_clz (void)
476: {
477: int n;
478:
479: if (T0 == 0) {
480: T0 = 32;
481: } else {
482: for (n = 0; n < 32; n++) {
483: if (T0 & (1 << 31))
484: break;
485: T0 = T0 << 1;
486: }
487: T0 = n;
488: }
489: RETURN();
490: }
491:
492: /* 64 bits arithmetic */
493: #if (HOST_LONG_BITS == 64)
494: static inline uint64_t get_HILO (void)
495: {
496: return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
497: }
498:
499: static inline void set_HILO (uint64_t HILO)
500: {
501: env->LO = HILO & 0xFFFFFFFF;
502: env->HI = HILO >> 32;
503: }
504:
505: void op_mult (void)
506: {
1.1.1.2 root 507: set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
1.1 root 508: RETURN();
509: }
510:
511: void op_multu (void)
512: {
513: set_HILO((uint64_t)T0 * (uint64_t)T1);
514: RETURN();
515: }
516:
517: void op_madd (void)
518: {
519: int64_t tmp;
520:
1.1.1.2 root 521: tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
1.1 root 522: set_HILO((int64_t)get_HILO() + tmp);
523: RETURN();
524: }
525:
526: void op_maddu (void)
527: {
528: uint64_t tmp;
529:
530: tmp = ((uint64_t)T0 * (uint64_t)T1);
531: set_HILO(get_HILO() + tmp);
532: RETURN();
533: }
534:
535: void op_msub (void)
536: {
537: int64_t tmp;
538:
1.1.1.2 root 539: tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
1.1 root 540: set_HILO((int64_t)get_HILO() - tmp);
541: RETURN();
542: }
543:
544: void op_msubu (void)
545: {
546: uint64_t tmp;
547:
548: tmp = ((uint64_t)T0 * (uint64_t)T1);
549: set_HILO(get_HILO() - tmp);
550: RETURN();
551: }
552: #else
553: void op_mult (void)
554: {
555: CALL_FROM_TB0(do_mult);
556: RETURN();
557: }
558:
559: void op_multu (void)
560: {
561: CALL_FROM_TB0(do_multu);
562: RETURN();
563: }
564:
565: void op_madd (void)
566: {
567: CALL_FROM_TB0(do_madd);
568: RETURN();
569: }
570:
571: void op_maddu (void)
572: {
573: CALL_FROM_TB0(do_maddu);
574: RETURN();
575: }
576:
577: void op_msub (void)
578: {
579: CALL_FROM_TB0(do_msub);
580: RETURN();
581: }
582:
583: void op_msubu (void)
584: {
585: CALL_FROM_TB0(do_msubu);
586: RETURN();
587: }
588: #endif
589:
590: /* Conditional moves */
591: void op_movn (void)
592: {
593: if (T1 != 0)
594: env->gpr[PARAM1] = T0;
595: RETURN();
596: }
597:
598: void op_movz (void)
599: {
600: if (T1 == 0)
601: env->gpr[PARAM1] = T0;
602: RETURN();
603: }
604:
605: /* Tests */
606: #define OP_COND(name, cond) \
607: void glue(op_, name) (void) \
608: { \
609: if (cond) { \
610: T0 = 1; \
611: } else { \
612: T0 = 0; \
613: } \
614: RETURN(); \
615: }
616:
617: OP_COND(eq, T0 == T1);
618: OP_COND(ne, T0 != T1);
619: OP_COND(ge, (int32_t)T0 >= (int32_t)T1);
620: OP_COND(geu, T0 >= T1);
621: OP_COND(lt, (int32_t)T0 < (int32_t)T1);
622: OP_COND(ltu, T0 < T1);
623: OP_COND(gez, (int32_t)T0 >= 0);
624: OP_COND(gtz, (int32_t)T0 > 0);
625: OP_COND(lez, (int32_t)T0 <= 0);
626: OP_COND(ltz, (int32_t)T0 < 0);
627:
628: /* Branchs */
629: //#undef USE_DIRECT_JUMP
1.1.1.2 root 630:
631: void OPPROTO op_goto_tb0(void)
632: {
633: GOTO_TB(op_goto_tb0, PARAM1, 0);
634: }
635:
636: void OPPROTO op_goto_tb1(void)
637: {
638: GOTO_TB(op_goto_tb1, PARAM1, 1);
639: }
1.1 root 640:
641: /* Branch to register */
642: void op_save_breg_target (void)
643: {
644: env->btarget = T2;
645: }
646:
647: void op_restore_breg_target (void)
648: {
649: T2 = env->btarget;
650: }
651:
652: void op_breg (void)
653: {
654: env->PC = T2;
655: RETURN();
656: }
657:
658: void op_save_btarget (void)
659: {
660: env->btarget = PARAM1;
661: RETURN();
662: }
663:
664: /* Conditional branch */
665: void op_set_bcond (void)
666: {
667: T2 = T0;
668: RETURN();
669: }
670:
671: void op_save_bcond (void)
672: {
673: env->bcond = T2;
674: RETURN();
675: }
676:
677: void op_restore_bcond (void)
678: {
679: T2 = env->bcond;
680: RETURN();
681: }
682:
1.1.1.2 root 683: void op_jnz_T2 (void)
1.1 root 684: {
1.1.1.2 root 685: if (T2)
686: GOTO_LABEL_PARAM(1);
1.1 root 687: RETURN();
688: }
689:
690: /* CP0 functions */
691: void op_mfc0 (void)
692: {
693: CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2);
694: RETURN();
695: }
696:
697: void op_mtc0 (void)
698: {
699: CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2);
700: RETURN();
701: }
702:
1.1.1.4 ! root 703: #ifdef MIPS_USES_FPU
! 704:
! 705: #if 0
! 706: # define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env)
! 707: #else
! 708: # define DEBUG_FPU_STATE() do { } while(0)
! 709: #endif
! 710:
! 711: void op_cp1_enabled(void)
! 712: {
! 713: if (!(env->CP0_Status & (1 << CP0St_CU1))) {
! 714: CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 1);
! 715: }
! 716: RETURN();
! 717: }
! 718:
! 719: /* CP1 functions */
! 720: void op_cfc1 (void)
! 721: {
! 722: if (T1 == 0) {
! 723: T0 = env->fcr0;
! 724: }
! 725: else {
! 726: /* fetch fcr31, masking unused bits */
! 727: T0 = env->fcr31 & 0x0183FFFF;
! 728: }
! 729: DEBUG_FPU_STATE();
! 730: RETURN();
! 731: }
! 732:
! 733: /* convert MIPS rounding mode in FCR31 to IEEE library */
! 734: unsigned int ieee_rm[] = {
! 735: float_round_nearest_even,
! 736: float_round_to_zero,
! 737: float_round_up,
! 738: float_round_down
! 739: };
! 740:
! 741: #define RESTORE_ROUNDING_MODE \
! 742: set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status)
! 743:
! 744: void op_ctc1 (void)
! 745: {
! 746: if (T1 == 0) {
! 747: /* XXX should this throw an exception?
! 748: * don't write to FCR0.
! 749: * env->fcr0 = T0;
! 750: */
! 751: }
! 752: else {
! 753: /* store new fcr31, masking unused bits */
! 754: env->fcr31 = T0 & 0x0183FFFF;
! 755:
! 756: /* set rounding mode */
! 757: RESTORE_ROUNDING_MODE;
! 758:
! 759: #ifndef CONFIG_SOFTFLOAT
! 760: /* no floating point exception for native float */
! 761: SET_FP_ENABLE(env->fcr31, 0);
! 762: #endif
! 763: }
! 764: DEBUG_FPU_STATE();
! 765: RETURN();
! 766: }
! 767:
! 768: void op_mfc1 (void)
! 769: {
! 770: T0 = WT0;
! 771: DEBUG_FPU_STATE();
! 772: RETURN();
! 773: }
! 774:
! 775: void op_mtc1 (void)
! 776: {
! 777: WT0 = T0;
! 778: DEBUG_FPU_STATE();
! 779: RETURN();
! 780: }
! 781:
! 782: /* Float support.
! 783: Single precition routines have a "s" suffix, double precision a
! 784: "d" suffix. */
! 785:
! 786: #define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void)
! 787:
! 788: FLOAT_OP(cvtd, w)
! 789: {
! 790: FDT2 = int32_to_float64(WT0, &env->fp_status);
! 791: DEBUG_FPU_STATE();
! 792: RETURN();
! 793: }
! 794: FLOAT_OP(cvts, w)
! 795: {
! 796: FST2 = int32_to_float32(WT0, &env->fp_status);
! 797: DEBUG_FPU_STATE();
! 798: RETURN();
! 799: }
! 800: FLOAT_OP(cvtw, s)
! 801: {
! 802: WT2 = float32_to_int32(FST0, &env->fp_status);
! 803: DEBUG_FPU_STATE();
! 804: RETURN();
! 805: }
! 806: FLOAT_OP(cvtw, d)
! 807: {
! 808: WT2 = float64_to_int32(FDT0, &env->fp_status);
! 809: DEBUG_FPU_STATE();
! 810: RETURN();
! 811: }
! 812:
! 813: FLOAT_OP(roundw, d)
! 814: {
! 815: set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
! 816: WT2 = float64_round_to_int(FDT0, &env->fp_status);
! 817: RESTORE_ROUNDING_MODE;
! 818:
! 819: DEBUG_FPU_STATE();
! 820: RETURN();
! 821: }
! 822: FLOAT_OP(roundw, s)
! 823: {
! 824: set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
! 825: WT2 = float32_round_to_int(FST0, &env->fp_status);
! 826: RESTORE_ROUNDING_MODE;
! 827: DEBUG_FPU_STATE();
! 828: RETURN();
! 829: }
! 830:
! 831: FLOAT_OP(truncw, d)
! 832: {
! 833: WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status);
! 834: DEBUG_FPU_STATE();
! 835: RETURN();
! 836: }
! 837: FLOAT_OP(truncw, s)
! 838: {
! 839: WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status);
! 840: DEBUG_FPU_STATE();
! 841: RETURN();
! 842: }
! 843:
! 844: FLOAT_OP(ceilw, d)
! 845: {
! 846: set_float_rounding_mode(float_round_up, &env->fp_status);
! 847: WT2 = float64_round_to_int(FDT0, &env->fp_status);
! 848: RESTORE_ROUNDING_MODE;
! 849:
! 850: DEBUG_FPU_STATE();
! 851: RETURN();
! 852: }
! 853: FLOAT_OP(ceilw, s)
! 854: {
! 855: set_float_rounding_mode(float_round_up, &env->fp_status);
! 856: WT2 = float32_round_to_int(FST0, &env->fp_status);
! 857: RESTORE_ROUNDING_MODE;
! 858: DEBUG_FPU_STATE();
! 859: RETURN();
! 860: }
! 861:
! 862: FLOAT_OP(floorw, d)
! 863: {
! 864: set_float_rounding_mode(float_round_down, &env->fp_status);
! 865: WT2 = float64_round_to_int(FDT0, &env->fp_status);
! 866: RESTORE_ROUNDING_MODE;
! 867:
! 868: DEBUG_FPU_STATE();
! 869: RETURN();
! 870: }
! 871: FLOAT_OP(floorw, s)
! 872: {
! 873: set_float_rounding_mode(float_round_down, &env->fp_status);
! 874: WT2 = float32_round_to_int(FST0, &env->fp_status);
! 875: RESTORE_ROUNDING_MODE;
! 876: DEBUG_FPU_STATE();
! 877: RETURN();
! 878: }
! 879:
! 880: /* binary operations */
! 881: #define FLOAT_BINOP(name) \
! 882: FLOAT_OP(name, d) \
! 883: { \
! 884: FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \
! 885: DEBUG_FPU_STATE(); \
! 886: } \
! 887: FLOAT_OP(name, s) \
! 888: { \
! 889: FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \
! 890: DEBUG_FPU_STATE(); \
! 891: }
! 892: FLOAT_BINOP(add)
! 893: FLOAT_BINOP(sub)
! 894: FLOAT_BINOP(mul)
! 895: FLOAT_BINOP(div)
! 896: #undef FLOAT_BINOP
! 897:
! 898: /* unary operations, modifying fp status */
! 899: #define FLOAT_UNOP(name) \
! 900: FLOAT_OP(name, d) \
! 901: { \
! 902: FDT2 = float64_ ## name(FDT0, &env->fp_status); \
! 903: DEBUG_FPU_STATE(); \
! 904: } \
! 905: FLOAT_OP(name, s) \
! 906: { \
! 907: FST2 = float32_ ## name(FST0, &env->fp_status); \
! 908: DEBUG_FPU_STATE(); \
! 909: }
! 910: FLOAT_UNOP(sqrt)
! 911: #undef FLOAT_UNOP
! 912:
! 913: /* unary operations, not modifying fp status */
! 914: #define FLOAT_UNOP(name) \
! 915: FLOAT_OP(name, d) \
! 916: { \
! 917: FDT2 = float64_ ## name(FDT0); \
! 918: DEBUG_FPU_STATE(); \
! 919: } \
! 920: FLOAT_OP(name, s) \
! 921: { \
! 922: FST2 = float32_ ## name(FST0); \
! 923: DEBUG_FPU_STATE(); \
! 924: }
! 925: FLOAT_UNOP(abs)
! 926: FLOAT_UNOP(chs)
! 927: #undef FLOAT_UNOP
! 928:
! 929: FLOAT_OP(mov, d)
! 930: {
! 931: FDT2 = FDT0;
! 932: DEBUG_FPU_STATE();
! 933: RETURN();
! 934: }
! 935: FLOAT_OP(mov, s)
! 936: {
! 937: FST2 = FST0;
! 938: DEBUG_FPU_STATE();
! 939: RETURN();
! 940: }
! 941:
! 942: #ifdef CONFIG_SOFTFLOAT
! 943: #define clear_invalid() do { \
! 944: int flags = get_float_exception_flags(&env->fp_status); \
! 945: flags &= ~float_flag_invalid; \
! 946: set_float_exception_flags(flags, &env->fp_status); \
! 947: } while(0)
! 948: #else
! 949: #define clear_invalid() do { } while(0)
! 950: #endif
! 951:
! 952: extern void dump_fpu_s(CPUState *env);
! 953:
! 954: #define FOP_COND(fmt, op, sig, cond) \
! 955: void op_cmp_ ## fmt ## _ ## op (void) \
! 956: { \
! 957: if (cond) \
! 958: SET_FP_COND(env->fcr31); \
! 959: else \
! 960: CLEAR_FP_COND(env->fcr31); \
! 961: if (!sig) \
! 962: clear_invalid(); \
! 963: /*CALL_FROM_TB1(dump_fpu_s, env);*/ \
! 964: DEBUG_FPU_STATE(); \
! 965: RETURN(); \
! 966: }
! 967:
! 968: flag float64_is_unordered(float64 a, float64 b STATUS_PARAM)
! 969: {
! 970: extern flag float64_is_nan( float64 a );
! 971: if (float64_is_nan(a) || float64_is_nan(b)) {
! 972: float_raise(float_flag_invalid, status);
! 973: return 1;
! 974: }
! 975: else {
! 976: return 0;
! 977: }
! 978: }
! 979:
! 980: FOP_COND(d, f, 0, 0)
! 981: FOP_COND(d, un, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status))
! 982: FOP_COND(d, eq, 0, float64_eq(FDT0, FDT1, &env->fp_status))
! 983: FOP_COND(d, ueq, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status))
! 984: FOP_COND(d, olt, 0, float64_lt(FDT0, FDT1, &env->fp_status))
! 985: FOP_COND(d, ult, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status))
! 986: FOP_COND(d, ole, 0, float64_le(FDT0, FDT1, &env->fp_status))
! 987: FOP_COND(d, ule, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status))
! 988: /* NOTE: the comma operator will make "cond" to eval to false,
! 989: * but float*_is_unordered() is still called
! 990: */
! 991: FOP_COND(d, sf, 1, (float64_is_unordered(FDT0, FDT1, &env->fp_status), 0))
! 992: FOP_COND(d, ngle,1, float64_is_unordered(FDT1, FDT0, &env->fp_status))
! 993: FOP_COND(d, seq, 1, float64_eq(FDT0, FDT1, &env->fp_status))
! 994: FOP_COND(d, ngl, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status))
! 995: FOP_COND(d, lt, 1, float64_lt(FDT0, FDT1, &env->fp_status))
! 996: FOP_COND(d, nge, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status))
! 997: FOP_COND(d, le, 1, float64_le(FDT0, FDT1, &env->fp_status))
! 998: FOP_COND(d, ngt, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status))
! 999:
! 1000: flag float32_is_unordered(float32 a, float32 b STATUS_PARAM)
! 1001: {
! 1002: extern flag float32_is_nan( float32 a );
! 1003: if (float32_is_nan(a) || float32_is_nan(b)) {
! 1004: float_raise(float_flag_invalid, status);
! 1005: return 1;
! 1006: }
! 1007: else {
! 1008: return 0;
! 1009: }
! 1010: }
! 1011:
! 1012: /* NOTE: the comma operator will make "cond" to eval to false,
! 1013: * but float*_is_unordered() is still called
! 1014: */
! 1015: FOP_COND(s, f, 0, 0)
! 1016: FOP_COND(s, un, 0, float32_is_unordered(FST1, FST0, &env->fp_status))
! 1017: FOP_COND(s, eq, 0, float32_eq(FST0, FST1, &env->fp_status))
! 1018: FOP_COND(s, ueq, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status))
! 1019: FOP_COND(s, olt, 0, float32_lt(FST0, FST1, &env->fp_status))
! 1020: FOP_COND(s, ult, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status))
! 1021: FOP_COND(s, ole, 0, float32_le(FST0, FST1, &env->fp_status))
! 1022: FOP_COND(s, ule, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status))
! 1023: /* NOTE: the comma operator will make "cond" to eval to false,
! 1024: * but float*_is_unordered() is still called
! 1025: */
! 1026: FOP_COND(s, sf, 1, (float32_is_unordered(FST0, FST1, &env->fp_status), 0))
! 1027: FOP_COND(s, ngle,1, float32_is_unordered(FST1, FST0, &env->fp_status))
! 1028: FOP_COND(s, seq, 1, float32_eq(FST0, FST1, &env->fp_status))
! 1029: FOP_COND(s, ngl, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status))
! 1030: FOP_COND(s, lt, 1, float32_lt(FST0, FST1, &env->fp_status))
! 1031: FOP_COND(s, nge, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status))
! 1032: FOP_COND(s, le, 1, float32_le(FST0, FST1, &env->fp_status))
! 1033: FOP_COND(s, ngt, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status))
! 1034:
! 1035: void op_bc1f (void)
! 1036: {
! 1037: T0 = ! IS_FP_COND_SET(env->fcr31);
! 1038: DEBUG_FPU_STATE();
! 1039: RETURN();
! 1040: }
! 1041:
! 1042: void op_bc1t (void)
! 1043: {
! 1044: T0 = IS_FP_COND_SET(env->fcr31);
! 1045: DEBUG_FPU_STATE();
! 1046: RETURN();
! 1047: }
! 1048: #endif /* MIPS_USES_FPU */
! 1049:
1.1 root 1050: #if defined(MIPS_USES_R4K_TLB)
1051: void op_tlbwi (void)
1052: {
1053: CALL_FROM_TB0(do_tlbwi);
1054: RETURN();
1055: }
1056:
1057: void op_tlbwr (void)
1058: {
1059: CALL_FROM_TB0(do_tlbwr);
1060: RETURN();
1061: }
1062:
1063: void op_tlbp (void)
1064: {
1065: CALL_FROM_TB0(do_tlbp);
1066: RETURN();
1067: }
1068:
1069: void op_tlbr (void)
1070: {
1071: CALL_FROM_TB0(do_tlbr);
1072: RETURN();
1073: }
1074: #endif
1075:
1076: /* Specials */
1077: void op_pmon (void)
1078: {
1079: CALL_FROM_TB1(do_pmon, PARAM1);
1080: }
1081:
1082: void op_trap (void)
1083: {
1084: if (T0) {
1.1.1.2 root 1085: CALL_FROM_TB1(do_raise_exception_direct, EXCP_TRAP);
1.1 root 1086: }
1087: RETURN();
1088: }
1089:
1.1.1.2 root 1090: void op_debug (void)
1091: {
1.1.1.3 root 1092: CALL_FROM_TB1(do_raise_exception, EXCP_DEBUG);
1.1.1.2 root 1093: }
1094:
1.1 root 1095: void op_set_lladdr (void)
1096: {
1097: env->CP0_LLAddr = T2;
1098: }
1099:
1100: void debug_eret (void);
1101: void op_eret (void)
1102: {
1103: CALL_FROM_TB0(debug_eret);
1104: if (env->hflags & MIPS_HFLAG_ERL) {
1105: env->PC = env->CP0_ErrorEPC;
1106: env->hflags &= ~MIPS_HFLAG_ERL;
1.1.1.4 ! root 1107: env->CP0_Status &= ~(1 << CP0St_ERL);
1.1 root 1108: } else {
1109: env->PC = env->CP0_EPC;
1110: env->hflags &= ~MIPS_HFLAG_EXL;
1.1.1.4 ! root 1111: env->CP0_Status &= ~(1 << CP0St_EXL);
1.1 root 1112: }
1113: env->CP0_LLAddr = 1;
1114: }
1115:
1116: void op_deret (void)
1117: {
1118: CALL_FROM_TB0(debug_eret);
1119: env->PC = env->CP0_DEPC;
1120: }
1121:
1122: void op_save_state (void)
1123: {
1124: env->hflags = PARAM1;
1125: RETURN();
1126: }
1127:
1128: void op_save_pc (void)
1129: {
1130: env->PC = PARAM1;
1131: RETURN();
1132: }
1133:
1134: void op_raise_exception (void)
1135: {
1136: CALL_FROM_TB1(do_raise_exception, PARAM1);
1137: RETURN();
1138: }
1139:
1140: void op_raise_exception_err (void)
1141: {
1142: CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2);
1143: RETURN();
1144: }
1145:
1146: void op_exit_tb (void)
1147: {
1148: EXIT_TB();
1149: }
1150:
1.1.1.2 root 1151: void op_wait (void)
1152: {
1153: env->halted = 1;
1154: CALL_FROM_TB1(do_raise_exception, EXCP_HLT);
1155: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.