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
31 #define Ts0 (int32_t)T0
32 #define Ts1 (int32_t)T1
33 #define Ts2 (int32_t)T2
37 #define PPC_OP(name) void op_##name(void)
39 /* PPC state maintenance operations */
75 set_CRn(0, 0x02 | xer_ov);
82 set_CRn(0, 0x04 | xer_ov);
104 /* Update time base */
107 T0 = regs->spr[SPR_ENCODE(268)];
111 T1 = regs->spr[SPR_ENCODE(269)] + 1;
112 regs->spr[SPR_ENCODE(269)] = T1;
114 regs->spr[SPR_ENCODE(268)] = T0;
118 PPC_OP(raise_exception)
120 raise_exception(PARAM(1));
137 do_store_cr(PARAM(1), T0);
143 T0 = (xer_so << 3) | (xer_ov << 2) | (xer_ca << 1);
191 /* Set reservation */
192 PPC_OP(set_reservation)
194 regs->reserve = T1 & ~0x03;
198 /* Reset reservation */
199 PPC_OP(reset_reservation)
208 T0 = (T0 >> PARAM(1)) & 1;
214 T1 = (T1 >> PARAM(1)) & 1;
220 T1 = (T1 & PARAM(1)) | (T0 << PARAM(2));
225 #define __PPC_OP_B(name, target) \
228 regs->nip = (target); \
232 #define __PPC_OP_BL(name, target) \
235 regs->LR = PARAM(1); \
236 regs->nip = (target); \
240 #define PPC_OP_B(name, target) \
241 __PPC_OP_B(name, target); \
242 __PPC_OP_BL(name##l, target)
244 #define __PPC_OP_BC(name, cond, target) \
256 #define __PPC_OP_BCL(name, cond, target) \
261 regs->LR = PARAM(1); \
269 #define _PPC_OP_BC(name, namel, cond, target) \
270 __PPC_OP_BC(name, cond, target); \
271 __PPC_OP_BCL(namel, cond, target)
273 /* Branch to target */
274 #define PPC_OP_BC(name, cond) \
275 _PPC_OP_BC(b_##name, bl_##name, cond, PARAM(2))
277 PPC_OP_B(b, PARAM(1));
278 PPC_OP_BC(ctr, (regs->CTR != 0));
279 PPC_OP_BC(ctr_true, (regs->CTR != 0 && (T0 & PARAM(3)) != 0));
280 PPC_OP_BC(ctr_false, (regs->CTR != 0 && (T0 & PARAM(3)) == 0));
281 PPC_OP_BC(ctrz, (regs->CTR == 0));
282 PPC_OP_BC(ctrz_true, (regs->CTR == 0 && (T0 & PARAM(3)) != 0));
283 PPC_OP_BC(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(3)) == 0));
284 PPC_OP_BC(true, ((T0 & PARAM(3)) != 0));
285 PPC_OP_BC(false, ((T0 & PARAM(3)) == 0));
288 #define PPC_OP_BCCTR(name, cond) \
289 _PPC_OP_BC(bctr_##name, bctrl_##name, cond, regs->CTR & ~0x03)
291 PPC_OP_B(bctr, regs->CTR & ~0x03);
292 PPC_OP_BCCTR(ctr, (regs->CTR != 0));
293 PPC_OP_BCCTR(ctr_true, (regs->CTR != 0 && (T0 & PARAM(2)) != 0));
294 PPC_OP_BCCTR(ctr_false, (regs->CTR != 0 && (T0 & PARAM(2)) == 0));
295 PPC_OP_BCCTR(ctrz, (regs->CTR == 0));
296 PPC_OP_BCCTR(ctrz_true, (regs->CTR == 0 && (T0 & PARAM(2)) != 0));
297 PPC_OP_BCCTR(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(2)) == 0));
298 PPC_OP_BCCTR(true, ((T0 & PARAM(2)) != 0));
299 PPC_OP_BCCTR(false, ((T0 & PARAM(2)) == 0));
302 #define PPC_OP_BCLR(name, cond) \
303 _PPC_OP_BC(blr_##name, blrl_##name, cond, regs->LR & ~0x03)
305 PPC_OP_B(blr, regs->LR & ~0x03);
306 PPC_OP_BCLR(ctr, (regs->CTR != 0));
307 PPC_OP_BCLR(ctr_true, (regs->CTR != 0 && (T0 & PARAM(2)) != 0));
308 PPC_OP_BCLR(ctr_false, (regs->CTR != 0 && (T0 & PARAM(2)) == 0));
309 PPC_OP_BCLR(ctrz, (regs->CTR == 0));
310 PPC_OP_BCLR(ctrz_true, (regs->CTR == 0 && (T0 & PARAM(2)) != 0));
311 PPC_OP_BCLR(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(2)) == 0));
312 PPC_OP_BCLR(true, ((T0 & PARAM(2)) != 0));
313 PPC_OP_BCLR(false, ((T0 & PARAM(2)) == 0));
315 /* CTR maintenance */
322 /*** Integer arithmetic ***/
334 if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
365 if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
375 /* candidate for helper (too long) */
380 if (T0 < T2 || (xer_ca == 1 && T0 == T2)) {
392 if (T0 < T2 || (xer_ca == 1 && T0 == T2)) {
397 if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
413 /* add immediate carrying */
426 /* add to minus one extended */
440 if (T1 & (T1 ^ T0) & (1 << 31)) {
451 /* add to zero extended */
468 if ((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)) {
483 /* candidate for helper (too long) */
486 if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
487 Ts0 = (-1) * (T0 >> 31);
496 if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
499 T0 = (-1) * (T0 >> 31);
507 /* divide word unsigned */
531 /* multiply high word */
534 Ts0 = ((int64_t)Ts0 * (int64_t)Ts1) >> 32;
538 /* multiply high word unsigned */
541 T0 = ((uint64_t)T0 * (uint64_t)T1) >> 32;
545 /* multiply low immediate */
552 /* multiply low word */
561 int64_t res = (int64_t)Ts0 * (int64_t)Ts1;
563 if ((int32_t)res != res) {
576 if (T0 != 0x80000000) {
584 if (T0 == 0x80000000) {
605 if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
614 /* substract from carrying */
635 if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
644 /* substract from extended */
645 /* candidate for helper (too long) */
648 T0 = T1 + ~T0 + xer_ca;
649 if (T0 < T1 || (xer_ca == 1 && T0 == T1)) {
660 T0 = T1 + ~T0 + xer_ca;
661 if ((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)) {
667 if (T0 < T1 || (xer_ca == 1 && T0 == T1)) {
675 /* substract from immediate carrying */
678 T0 = PARAM(1) + ~T0 + 1;
679 if (T0 <= PARAM(1)) {
687 /* substract from minus one extended */
690 T0 = ~T0 + xer_ca - 1;
700 T0 = ~T0 + xer_ca - 1;
701 if (~T1 & (~T1 ^ T0) & (1 << 31)) {
712 /* substract from zero extended */
729 if ((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)) {
743 /*** Integer comparison ***/
749 } else if (Ts0 > Ts1) {
757 /* compare immediate */
760 if (Ts0 < SPARAM(1)) {
762 } else if (Ts0 > SPARAM(1)) {
770 /* compare logical */
775 } else if (T0 > T1) {
783 /* compare logical immediate */
788 } else if (T0 > PARAM(1)) {
796 /*** Integer logical ***/
818 /* count leading zero */
822 for (T0 = 32; T1 > 0; T0--)
834 /* extend sign byte */
841 /* extend sign half word */
897 /*** Integer rotate ***/
898 /* rotate left word immediate then mask insert */
901 T0 = rotl(T0, PARAM(1) & PARAM(2)) | (T0 & PARAM(3));
905 /* rotate left immediate then and with mask insert */
908 T0 = rotl(T0, PARAM(1));
924 /* rotate left word then and with mask insert */
927 T0 = rotl(T0, PARAM(1)) & PARAM(2);
939 T0 = rotl(T0, T1) & PARAM(1);
943 /*** Integer shift ***/
944 /* shift left word */
955 /* shift right algebraic word */
958 Ts0 = do_sraw(Ts0, T1);
962 /* shift right algebraic word immediate */
966 Ts0 = Ts0 >> PARAM(1);
967 if (Ts1 < 0 && (Ts1 & PARAM(2)) != 0) {
975 /* shift right word */
986 /*** Floating-Point arithmetic ***/
988 /*** Floating-Point multiply-and-add ***/
990 /*** Floating-Point round & convert ***/
992 /*** Floating-Point compare ***/
994 /*** Floating-Point status & ctrl register ***/
996 /*** Integer load ***/
997 #define ld16x(x) s_ext16(ld16(x))
998 #define PPC_ILD_OPX(name, op) \
999 PPC_OP(l##name##x_z) \
1004 PPC_OP(l##name##x) \
1011 #define PPC_ILD_OP(name, op) \
1012 PPC_OP(l##name##_z) \
1014 T1 = op(SPARAM(1)); \
1023 PPC_ILD_OPX(name, op)
1025 PPC_ILD_OP(bz, ld8);
1026 PPC_ILD_OP(ha, ld16x);
1027 PPC_ILD_OP(hz, ld16);
1028 PPC_ILD_OP(wz, ld32);
1030 /*** Integer store ***/
1031 #define PPC_IST_OPX(name, op) \
1032 PPC_OP(st##name##x_z) \
1037 PPC_OP(st##name##x) \
1044 #define PPC_IST_OP(name, op) \
1045 PPC_OP(st##name##_z) \
1047 op(SPARAM(1), T0); \
1056 PPC_IST_OPX(name, op);
1059 PPC_IST_OP(h, st16);
1060 PPC_IST_OP(w, st32);
1062 /*** Integer load and store with byte reverse ***/
1063 PPC_ILD_OPX(hbr, ld16r);
1064 PPC_ILD_OPX(wbr, ld32r);
1065 PPC_IST_OPX(hbr, st16r);
1066 PPC_IST_OPX(wbr, st32r);
1068 /*** Integer load and store multiple ***/
1071 do_lmw(PARAM(1), SPARAM(2) + T0);
1077 do_stmw(PARAM(1), SPARAM(2) + T0);
1081 /*** Integer load and store strings ***/
1084 do_lsw(PARAM(1), PARAM(2), T0);
1090 do_lsw(PARAM(1), T0, T1 + T2);
1096 do_stsw(PARAM(1), PARAM(2), 0);
1102 do_stsw(PARAM(1), PARAM(2), T0);
1108 do_stsw(PARAM(1), T0, T1);
1114 do_stsw(PARAM(1), T0, T1 + T2);