2 * PPC emulation micro-operations for qemu.
4 * Copyright (c) 2003 Jocelyn Mayer
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.
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.
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
27 #define Ts0 (int32_t)T0
28 #define Ts1 (int32_t)T1
29 #define Ts2 (int32_t)T2
31 #define FT0 (env->ft0)
32 #define FT1 (env->ft1)
33 #define FT2 (env->ft2)
35 #define FTS0 ((float)env->ft0)
36 #define FTS1 ((float)env->ft1)
37 #define FTS2 ((float)env->ft2)
39 #define PPC_OP(name) void glue(op_, name)(void)
42 #include "op_template.h"
45 #include "op_template.h"
48 #include "op_template.h"
51 #include "op_template.h"
54 #include "op_template.h"
57 #include "op_template.h"
60 #include "op_template.h"
63 #include "op_template.h"
66 #include "op_template.h"
69 #include "op_template.h"
72 #include "op_template.h"
75 #include "op_template.h"
78 #include "op_template.h"
81 #include "op_template.h"
84 #include "op_template.h"
87 #include "op_template.h"
90 #include "op_template.h"
93 #include "op_template.h"
96 #include "op_template.h"
99 #include "op_template.h"
102 #include "op_template.h"
105 #include "op_template.h"
108 #include "op_template.h"
111 #include "op_template.h"
114 #include "op_template.h"
117 #include "op_template.h"
120 #include "op_template.h"
123 #include "op_template.h"
126 #include "op_template.h"
129 #include "op_template.h"
132 #include "op_template.h"
135 #include "op_template.h"
137 /* PPC state maintenance operations */
145 } else if (Ts0 > 0) {
160 } else if (Ts0 > 0) {
173 env->crf[0] = 0x02 | xer_ov;
180 env->crf[0] = 0x04 | xer_ov;
184 /* Set Rc1 (for floating point arithmetic) */
187 env->crf[1] = regs->fpscr[7];
210 /* Generate exceptions */
211 PPC_OP(queue_exception_err)
213 do_queue_exception_err(PARAM(1), PARAM(2));
216 PPC_OP(queue_exception)
218 do_queue_exception(PARAM(1));
221 PPC_OP(process_exceptions)
223 if (env->exceptions != 0) {
225 do_check_exception_state();
229 /* Segment registers load and store with immediate index */
232 T0 = regs->sr[T1 >> 28];
238 #if defined (DEBUG_OP)
239 dump_store_sr(T1 >> 28);
241 regs->sr[T1 >> 28] = T0;
262 /* Load/store special registers */
271 do_store_cr(PARAM(1));
277 T0 = (xer_so << 3) | (xer_ov << 2) | (xer_ca << 1);
322 T0 = regs->spr[PARAM(1)];
328 regs->spr[PARAM(1)] = T0;
356 /* Update time base */
362 #if defined (DEBUG_OP)
363 dump_update_tb(PARAM(1));
366 T1 = regs->tb[1] + 1;
375 T0 = regs->tb[PARAM(1)];
381 regs->tb[PARAM(1)] = T0;
382 #if defined (DEBUG_OP)
383 dump_store_tb(PARAM(1));
388 /* Update decrementer */
396 do_queue_exception(EXCP_DECR);
405 if (Ts0 < 0 && Ts1 > 0) {
406 do_queue_exception(EXCP_DECR);
413 T0 = regs->IBAT[PARAM(1)][PARAM(2)];
418 #if defined (DEBUG_OP)
419 dump_store_ibat(PARAM(1), PARAM(2));
421 regs->IBAT[PARAM(1)][PARAM(2)] = T0;
426 T0 = regs->DBAT[PARAM(1)][PARAM(2)];
431 #if defined (DEBUG_OP)
432 dump_store_dbat(PARAM(1), PARAM(2));
434 regs->DBAT[PARAM(1)][PARAM(2)] = T0;
446 do_store_fpscr(PARAM(1));
452 regs->fpscr[7] &= ~0x8;
456 /* Set reservation */
457 PPC_OP(set_reservation)
459 regs->reserve = T0 & ~0x03;
466 T0 = (T0 >> PARAM(1)) & 1;
472 T1 = (T1 >> PARAM(1)) & 1;
478 T1 = (T1 & PARAM(1)) | (T0 << PARAM(2));
484 #define EIP regs->nip
485 #define TB_DO_JUMP(name, tb, n, target) JUMP_TB(name, tb, n, target)
487 #define TB_DO_JUMP(name, tb, n, target) regs->nip = target;
490 #define __PPC_OP_B(name, target) \
493 TB_DO_JUMP(glue(op_, name), T1, 0, (target)); \
497 #define __PPC_OP_BL(name, target, link) \
501 TB_DO_JUMP(glue(op_, name), T1, 0, (target)); \
505 #define PPC_OP_B(name, target, link) \
506 __PPC_OP_B(name, target); \
507 __PPC_OP_BL(glue(name, l), target, link)
509 #define __PPC_OP_BC(name, cond, target) \
513 TB_DO_JUMP(glue(op_, name), T1, 1, (target)); \
515 TB_DO_JUMP(glue(op_, name), T1, 0, PARAM(1)); \
520 #define __PPC_OP_BCL(name, cond, target) \
523 regs->lr = PARAM(1); \
525 TB_DO_JUMP(glue(op_, name), T1, 1, (target)); \
527 TB_DO_JUMP(glue(op_, name), T1, 0, PARAM(1)); \
532 #define __PPC_OP_BCLRL(name, cond, target) \
536 regs->lr = PARAM(1); \
538 TB_DO_JUMP(glue(op_, name), T1, 1, T2); \
540 TB_DO_JUMP(glue(op_, name), T1, 0, PARAM(1)); \
545 #define _PPC_OP_BC(name, namel, cond, target) \
546 __PPC_OP_BC(name, cond, target); \
547 __PPC_OP_BCL(namel, cond, target)
549 /* Branch to target */
550 #define PPC_OP_BC(name, cond) \
551 _PPC_OP_BC(b_##name, bl_##name, cond, PARAM(2))
553 PPC_OP_B(b, PARAM(1), PARAM(2));
554 PPC_OP_BC(ctr, (regs->ctr != 0));
555 PPC_OP_BC(ctr_true, (regs->ctr != 0 && (T0 & PARAM(3)) != 0));
556 PPC_OP_BC(ctr_false, (regs->ctr != 0 && (T0 & PARAM(3)) == 0));
557 PPC_OP_BC(ctrz, (regs->ctr == 0));
558 PPC_OP_BC(ctrz_true, (regs->ctr == 0 && (T0 & PARAM(3)) != 0));
559 PPC_OP_BC(ctrz_false, (regs->ctr == 0 && (T0 & PARAM(3)) == 0));
560 PPC_OP_BC(true, ((T0 & PARAM(3)) != 0));
561 PPC_OP_BC(false, ((T0 & PARAM(3)) == 0));
564 #define PPC_OP_BCCTR(name, cond) \
565 _PPC_OP_BC(bctr_##name, bctrl_##name, cond, regs->ctr & ~0x03)
567 PPC_OP_B(bctr, regs->ctr & ~0x03, PARAM(1));
568 PPC_OP_BCCTR(ctr, (regs->ctr != 0));
569 PPC_OP_BCCTR(ctr_true, (regs->ctr != 0 && (T0 & PARAM(2)) != 0));
570 PPC_OP_BCCTR(ctr_false, (regs->ctr != 0 && (T0 & PARAM(2)) == 0));
571 PPC_OP_BCCTR(ctrz, (regs->ctr == 0));
572 PPC_OP_BCCTR(ctrz_true, (regs->ctr == 0 && (T0 & PARAM(2)) != 0));
573 PPC_OP_BCCTR(ctrz_false, (regs->ctr == 0 && (T0 & PARAM(2)) == 0));
574 PPC_OP_BCCTR(true, ((T0 & PARAM(2)) != 0));
575 PPC_OP_BCCTR(false, ((T0 & PARAM(2)) == 0));
578 #define PPC_OP_BCLR(name, cond) \
579 __PPC_OP_BC(blr_##name, cond, regs->lr & ~0x03); \
580 __PPC_OP_BCLRL(blrl_##name, cond, regs->lr & ~0x03)
582 __PPC_OP_B(blr, regs->lr & ~0x03);
585 T0 = regs->lr & ~0x03;
587 TB_DO_JUMP(op_blrl, T1, 0, T0);
590 PPC_OP_BCLR(ctr, (regs->ctr != 0));
591 PPC_OP_BCLR(ctr_true, (regs->ctr != 0 && (T0 & PARAM(2)) != 0));
592 PPC_OP_BCLR(ctr_false, (regs->ctr != 0 && (T0 & PARAM(2)) == 0));
593 PPC_OP_BCLR(ctrz, (regs->ctr == 0));
594 PPC_OP_BCLR(ctrz_true, (regs->ctr == 0 && (T0 & PARAM(2)) != 0));
595 PPC_OP_BCLR(ctrz_false, (regs->ctr == 0 && (T0 & PARAM(2)) == 0));
596 PPC_OP_BCLR(true, ((T0 & PARAM(2)) != 0));
597 PPC_OP_BCLR(false, ((T0 & PARAM(2)) == 0));
599 /* CTR maintenance */
606 /*** Integer arithmetic ***/
618 if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
649 if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
659 /* candidate for helper (too long) */
664 if (T0 < T2 || (xer_ca == 1 && T0 == T2)) {
676 if (T0 < T2 || (xer_ca == 1 && T0 == T2)) {
681 if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
697 /* add immediate carrying */
710 /* add to minus one extended */
724 if (T1 & (T1 ^ T0) & (1 << 31)) {
735 /* add to zero extended */
752 if ((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)) {
767 /* candidate for helper (too long) */
770 if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
771 Ts0 = (-1) * (T0 >> 31);
780 if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
783 T0 = (-1) * (T0 >> 31);
791 /* divide word unsigned */
815 /* multiply high word */
818 Ts0 = ((int64_t)Ts0 * (int64_t)Ts1) >> 32;
822 /* multiply high word unsigned */
825 T0 = ((uint64_t)T0 * (uint64_t)T1) >> 32;
829 /* multiply low immediate */
836 /* multiply low word */
845 int64_t res = (int64_t)Ts0 * (int64_t)Ts1;
847 if ((int32_t)res != res) {
860 if (T0 != 0x80000000) {
868 if (T0 == 0x80000000) {
889 if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
898 /* substract from carrying */
919 if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
928 /* substract from extended */
929 /* candidate for helper (too long) */
932 T0 = T1 + ~T0 + xer_ca;
933 if (T0 < T1 || (xer_ca == 1 && T0 == T1)) {
944 T0 = T1 + ~T0 + xer_ca;
945 if ((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)) {
951 if (T0 < T1 || (xer_ca == 1 && T0 == T1)) {
959 /* substract from immediate carrying */
962 T0 = PARAM(1) + ~T0 + 1;
963 if (T0 <= PARAM(1)) {
971 /* substract from minus one extended */
974 T0 = ~T0 + xer_ca - 1;
984 T0 = ~T0 + xer_ca - 1;
985 if (~T1 & (~T1 ^ T0) & (1 << 31)) {
996 /* substract from zero extended */
1013 if ((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)) {
1027 /*** Integer comparison ***/
1033 } else if (Ts0 > Ts1) {
1041 /* compare immediate */
1044 if (Ts0 < SPARAM(1)) {
1046 } else if (Ts0 > SPARAM(1)) {
1054 /* compare logical */
1059 } else if (T0 > T1) {
1067 /* compare logical immediate */
1070 if (T0 < PARAM(1)) {
1072 } else if (T0 > PARAM(1)) {
1080 /*** Integer logical ***/
1102 /* count leading zero */
1106 for (T0 = 32; T1 > 0; T0--)
1118 /* extend sign byte */
1125 /* extend sign half word */
1181 /*** Integer rotate ***/
1182 /* rotate left word immediate then mask insert */
1185 T0 = (rotl(T0, PARAM(1)) & PARAM(2)) | (T1 & PARAM(3));
1189 /* rotate left immediate then and with mask insert */
1192 T0 = rotl(T0, PARAM(1));
1198 T0 = T0 << PARAM(1);
1204 T0 = T0 >> PARAM(1);
1208 /* rotate left word then and with mask insert */
1211 T0 = rotl(T0, PARAM(1)) & PARAM(2);
1223 T0 = rotl(T0, T1) & PARAM(1);
1227 /*** Integer shift ***/
1228 /* shift left word */
1239 /* shift right algebraic word */
1246 /* shift right algebraic word immediate */
1250 Ts0 = Ts0 >> PARAM(1);
1251 if (Ts1 < 0 && (Ts1 & PARAM(2)) != 0) {
1259 /* shift right word */
1270 /*** Floating-Point arithmetic ***/
1278 /* fadds - fadds. */
1292 /* fsubs - fsubs. */
1306 /* fmuls - fmuls. */
1320 /* fdivs - fdivs. */
1327 /* fsqrt - fsqrt. */
1334 /* fsqrts - fsqrts. */
1348 /* frsqrte - frsqrte. */
1362 /*** Floating-Point multiply-and-add ***/
1363 /* fmadd - fmadd. */
1366 FT0 = (FT0 * FT1) + FT2;
1370 /* fmadds - fmadds. */
1373 FTS0 = (FTS0 * FTS1) + FTS2;
1377 /* fmsub - fmsub. */
1380 FT0 = (FT0 * FT1) - FT2;
1384 /* fmsubs - fmsubs. */
1387 FTS0 = (FTS0 * FTS1) - FTS2;
1391 /* fnmadd - fnmadd. - fnmadds - fnmadds. */
1394 FT0 = -((FT0 * FT1) + FT2);
1398 /* fnmadds - fnmadds. */
1401 FTS0 = -((FTS0 * FTS1) + FTS2);
1405 /* fnmsub - fnmsub. */
1408 FT0 = -((FT0 * FT1) - FT2);
1412 /* fnmsubs - fnmsubs. */
1415 FTS0 = -((FTS0 * FTS1) - FTS2);
1419 /*** Floating-Point round & convert ***/
1427 /* fctiw - fctiw. */
1434 /* fctiwz - fctiwz. */
1442 /*** Floating-Point compare ***/
1457 /*** Floating-point move ***/
1479 /* Load and store */
1480 #if defined(CONFIG_USER_ONLY)
1481 #define MEMSUFFIX _raw
1484 #define MEMSUFFIX _user
1487 #define MEMSUFFIX _kernel
1491 /* Return from interrupt */
1494 T0 = regs->spr[SRR1] & ~0xFFFF0000;
1498 regs->nip = regs->spr[SRR0] & ~0x00000003;
1499 if (env->exceptions != 0) {
1500 do_check_exception_state();
1508 if ((Ts0 < Ts1 && (PARAM(1) & 0x10)) ||
1509 (Ts0 > Ts1 && (PARAM(1) & 0x08)) ||
1510 (Ts0 == Ts1 && (PARAM(1) & 0x04)) ||
1511 (T0 < T1 && (PARAM(1) & 0x02)) ||
1512 (T0 > T1 && (PARAM(1) & 0x01)))
1513 do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP);
1519 if ((Ts0 < SPARAM(1) && (PARAM(2) & 0x10)) ||
1520 (Ts0 > SPARAM(1) && (PARAM(2) & 0x08)) ||
1521 (Ts0 == SPARAM(1) && (PARAM(2) & 0x04)) ||
1522 (T0 < (uint32_t)SPARAM(1) && (PARAM(2) & 0x02)) ||
1523 (T0 > (uint32_t)SPARAM(1) && (PARAM(2) & 0x01)))
1524 do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP);
1528 /* Instruction cache block invalidate */