]>
git.proxmox.com Git - mirror_qemu.git/blob - target-ppc/op.c
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
)
224 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;
459 T0
= (T0
>> PARAM(1)) & 1;
465 T1
= (T1
>> PARAM(1)) & 1;
471 T1
= (T1
& PARAM(1)) | (T0
<< PARAM(2));
477 #define EIP regs->nip
478 #define TB_DO_JUMP(name, tb, n, target) JUMP_TB(name, tb, n, target)
480 #define TB_DO_JUMP(name, tb, n, target) regs->nip = target;
483 #define __PPC_OP_B(name, target) \
486 TB_DO_JUMP(glue(op_, name), T1, 0, (target)); \
490 #define __PPC_OP_BL(name, target, link) \
494 TB_DO_JUMP(glue(op_, name), T1, 0, (target)); \
498 #define PPC_OP_B(name, target, link) \
499 __PPC_OP_B(name, target); \
500 __PPC_OP_BL(glue(name, l), target, link)
502 #define __PPC_OP_BC(name, cond, target) \
506 TB_DO_JUMP(glue(op_, name), T1, 1, (target)); \
508 TB_DO_JUMP(glue(op_, name), T1, 0, PARAM(1)); \
513 #define __PPC_OP_BCL(name, cond, target) \
516 regs->lr = PARAM(1); \
518 TB_DO_JUMP(glue(op_, name), T1, 1, (target)); \
520 TB_DO_JUMP(glue(op_, name), T1, 0, PARAM(1)); \
525 #define __PPC_OP_BCLRL(name, cond, target) \
529 regs->lr = PARAM(1); \
531 TB_DO_JUMP(glue(op_, name), T1, 1, T2); \
533 TB_DO_JUMP(glue(op_, name), T1, 0, PARAM(1)); \
538 #define _PPC_OP_BC(name, namel, cond, target) \
539 __PPC_OP_BC(name, cond, target); \
540 __PPC_OP_BCL(namel, cond, target)
542 /* Branch to target */
543 #define PPC_OP_BC(name, cond) \
544 _PPC_OP_BC(b_##name, bl_##name, cond, PARAM(2))
546 PPC_OP_B(b
, PARAM(1), PARAM(2));
547 PPC_OP_BC(ctr
, (regs
->ctr
!= 0));
548 PPC_OP_BC(ctr_true
, (regs
->ctr
!= 0 && (T0
& PARAM(3)) != 0));
549 PPC_OP_BC(ctr_false
, (regs
->ctr
!= 0 && (T0
& PARAM(3)) == 0));
550 PPC_OP_BC(ctrz
, (regs
->ctr
== 0));
551 PPC_OP_BC(ctrz_true
, (regs
->ctr
== 0 && (T0
& PARAM(3)) != 0));
552 PPC_OP_BC(ctrz_false
, (regs
->ctr
== 0 && (T0
& PARAM(3)) == 0));
553 PPC_OP_BC(true, ((T0
& PARAM(3)) != 0));
554 PPC_OP_BC(false, ((T0
& PARAM(3)) == 0));
557 #define PPC_OP_BCCTR(name, cond) \
558 _PPC_OP_BC(bctr_##name, bctrl_##name, cond, regs->ctr & ~0x03)
560 PPC_OP_B(bctr
, regs
->ctr
& ~0x03, PARAM(1));
561 PPC_OP_BCCTR(ctr
, (regs
->ctr
!= 0));
562 PPC_OP_BCCTR(ctr_true
, (regs
->ctr
!= 0 && (T0
& PARAM(2)) != 0));
563 PPC_OP_BCCTR(ctr_false
, (regs
->ctr
!= 0 && (T0
& PARAM(2)) == 0));
564 PPC_OP_BCCTR(ctrz
, (regs
->ctr
== 0));
565 PPC_OP_BCCTR(ctrz_true
, (regs
->ctr
== 0 && (T0
& PARAM(2)) != 0));
566 PPC_OP_BCCTR(ctrz_false
, (regs
->ctr
== 0 && (T0
& PARAM(2)) == 0));
567 PPC_OP_BCCTR(true, ((T0
& PARAM(2)) != 0));
568 PPC_OP_BCCTR(false, ((T0
& PARAM(2)) == 0));
571 #define PPC_OP_BCLR(name, cond) \
572 __PPC_OP_BC(blr_##name, cond, regs->lr & ~0x03); \
573 __PPC_OP_BCLRL(blrl_##name, cond, regs->lr & ~0x03)
575 __PPC_OP_B(blr
, regs
->lr
& ~0x03);
578 T0
= regs
->lr
& ~0x03;
580 TB_DO_JUMP(op_blrl
, T1
, 0, T0
);
583 PPC_OP_BCLR(ctr
, (regs
->ctr
!= 0));
584 PPC_OP_BCLR(ctr_true
, (regs
->ctr
!= 0 && (T0
& PARAM(2)) != 0));
585 PPC_OP_BCLR(ctr_false
, (regs
->ctr
!= 0 && (T0
& PARAM(2)) == 0));
586 PPC_OP_BCLR(ctrz
, (regs
->ctr
== 0));
587 PPC_OP_BCLR(ctrz_true
, (regs
->ctr
== 0 && (T0
& PARAM(2)) != 0));
588 PPC_OP_BCLR(ctrz_false
, (regs
->ctr
== 0 && (T0
& PARAM(2)) == 0));
589 PPC_OP_BCLR(true, ((T0
& PARAM(2)) != 0));
590 PPC_OP_BCLR(false, ((T0
& PARAM(2)) == 0));
592 /* CTR maintenance */
599 /*** Integer arithmetic ***/
611 if ((T2
^ T1
^ (-1)) & (T2
^ T0
) & (1 << 31)) {
642 if ((T2
^ T1
^ (-1)) & (T2
^ T0
) & (1 << 31)) {
652 /* candidate for helper (too long) */
657 if (T0
< T2
|| (xer_ca
== 1 && T0
== T2
)) {
669 if (T0
< T2
|| (xer_ca
== 1 && T0
== T2
)) {
674 if ((T2
^ T1
^ (-1)) & (T2
^ T0
) & (1 << 31)) {
690 /* add immediate carrying */
703 /* add to minus one extended */
717 if (T1
& (T1
^ T0
) & (1 << 31)) {
728 /* add to zero extended */
745 if ((T1
^ (-1)) & (T1
^ T0
) & (1 << 31)) {
760 /* candidate for helper (too long) */
763 if ((Ts0
== INT32_MIN
&& Ts1
== -1) || Ts1
== 0) {
764 Ts0
= (-1) * (T0
>> 31);
773 if ((Ts0
== INT32_MIN
&& Ts1
== -1) || Ts1
== 0) {
776 T0
= (-1) * (T0
>> 31);
784 /* divide word unsigned */
808 /* multiply high word */
811 Ts0
= ((int64_t)Ts0
* (int64_t)Ts1
) >> 32;
815 /* multiply high word unsigned */
818 T0
= ((uint64_t)T0
* (uint64_t)T1
) >> 32;
822 /* multiply low immediate */
829 /* multiply low word */
838 int64_t res
= (int64_t)Ts0
* (int64_t)Ts1
;
840 if ((int32_t)res
!= res
) {
853 if (T0
!= 0x80000000) {
861 if (T0
== 0x80000000) {
882 if (((~T2
) ^ T1
^ (-1)) & ((~T2
) ^ T0
) & (1 << 31)) {
891 /* substract from carrying */
912 if (((~T2
) ^ T1
^ (-1)) & ((~T2
) ^ T0
) & (1 << 31)) {
921 /* substract from extended */
922 /* candidate for helper (too long) */
925 T0
= T1
+ ~T0
+ xer_ca
;
926 if (T0
< T1
|| (xer_ca
== 1 && T0
== T1
)) {
937 T0
= T1
+ ~T0
+ xer_ca
;
938 if ((~T2
^ T1
^ (-1)) & (~T2
^ T0
) & (1 << 31)) {
944 if (T0
< T1
|| (xer_ca
== 1 && T0
== T1
)) {
952 /* substract from immediate carrying */
955 T0
= PARAM(1) + ~T0
+ 1;
956 if (T0
<= PARAM(1)) {
964 /* substract from minus one extended */
967 T0
= ~T0
+ xer_ca
- 1;
977 T0
= ~T0
+ xer_ca
- 1;
978 if (~T1
& (~T1
^ T0
) & (1 << 31)) {
989 /* substract from zero extended */
1006 if ((~T1
^ (-1)) & ((~T1
) ^ T0
) & (1 << 31)) {
1020 /*** Integer comparison ***/
1026 } else if (Ts0
> Ts1
) {
1034 /* compare immediate */
1037 if (Ts0
< SPARAM(1)) {
1039 } else if (Ts0
> SPARAM(1)) {
1047 /* compare logical */
1052 } else if (T0
> T1
) {
1060 /* compare logical immediate */
1063 if (T0
< PARAM(1)) {
1065 } else if (T0
> PARAM(1)) {
1073 /*** Integer logical ***/
1095 /* count leading zero */
1099 for (T0
= 32; T1
> 0; T0
--)
1111 /* extend sign byte */
1118 /* extend sign half word */
1174 /*** Integer rotate ***/
1175 /* rotate left word immediate then mask insert */
1178 T0
= (rotl(T0
, PARAM(1)) & PARAM(2)) | (T1
& PARAM(3));
1182 /* rotate left immediate then and with mask insert */
1185 T0
= rotl(T0
, PARAM(1));
1191 T0
= T0
<< PARAM(1);
1197 T0
= T0
>> PARAM(1);
1201 /* rotate left word then and with mask insert */
1204 T0
= rotl(T0
, PARAM(1)) & PARAM(2);
1216 T0
= rotl(T0
, T1
) & PARAM(1);
1220 /*** Integer shift ***/
1221 /* shift left word */
1232 /* shift right algebraic word */
1239 /* shift right algebraic word immediate */
1243 Ts0
= Ts0
>> PARAM(1);
1244 if (Ts1
< 0 && (Ts1
& PARAM(2)) != 0) {
1252 /* shift right word */
1263 /*** Floating-Point arithmetic ***/
1271 /* fadds - fadds. */
1285 /* fsubs - fsubs. */
1299 /* fmuls - fmuls. */
1313 /* fdivs - fdivs. */
1320 /* fsqrt - fsqrt. */
1327 /* fsqrts - fsqrts. */
1341 /* frsqrte - frsqrte. */
1355 /*** Floating-Point multiply-and-add ***/
1356 /* fmadd - fmadd. */
1359 FT0
= (FT0
* FT1
) + FT2
;
1363 /* fmadds - fmadds. */
1366 FTS0
= (FTS0
* FTS1
) + FTS2
;
1370 /* fmsub - fmsub. */
1373 FT0
= (FT0
* FT1
) - FT2
;
1377 /* fmsubs - fmsubs. */
1380 FTS0
= (FTS0
* FTS1
) - FTS2
;
1384 /* fnmadd - fnmadd. - fnmadds - fnmadds. */
1387 FT0
= -((FT0
* FT1
) + FT2
);
1391 /* fnmadds - fnmadds. */
1394 FTS0
= -((FTS0
* FTS1
) + FTS2
);
1398 /* fnmsub - fnmsub. */
1401 FT0
= -((FT0
* FT1
) - FT2
);
1405 /* fnmsubs - fnmsubs. */
1408 FTS0
= -((FTS0
* FTS1
) - FTS2
);
1412 /*** Floating-Point round & convert ***/
1420 /* fctiw - fctiw. */
1427 /* fctiwz - fctiwz. */
1435 /*** Floating-Point compare ***/
1450 /*** Floating-point move ***/
1472 /* Load and store */
1473 #if defined(CONFIG_USER_ONLY)
1474 #define MEMSUFFIX _raw
1477 #define MEMSUFFIX _user
1480 #define MEMSUFFIX _kernel
1484 /* Return from interrupt */
1487 T0
= regs
->spr
[SRR1
] & ~0xFFFF0000;
1491 regs
->nip
= regs
->spr
[SRR0
] & ~0x00000003;
1492 if (env
->exceptions
!= 0) {
1493 do_check_exception_state();
1501 if ((Ts0
< Ts1
&& (PARAM(1) & 0x10)) ||
1502 (Ts0
> Ts1
&& (PARAM(1) & 0x08)) ||
1503 (Ts0
== Ts1
&& (PARAM(1) & 0x04)) ||
1504 (T0
< T1
&& (PARAM(1) & 0x02)) ||
1505 (T0
> T1
&& (PARAM(1) & 0x01)))
1506 do_queue_exception_err(EXCP_PROGRAM
, EXCP_TRAP
);
1512 if ((Ts0
< SPARAM(1) && (PARAM(2) & 0x10)) ||
1513 (Ts0
> SPARAM(1) && (PARAM(2) & 0x08)) ||
1514 (Ts0
== SPARAM(1) && (PARAM(2) & 0x04)) ||
1515 (T0
< (uint32_t)SPARAM(1) && (PARAM(2) & 0x02)) ||
1516 (T0
> (uint32_t)SPARAM(1) && (PARAM(2) & 0x01)))
1517 do_queue_exception_err(EXCP_PROGRAM
, EXCP_TRAP
);
1521 /* Instruction cache block invalidate */