target-ppc: Add ISA 2.06 divwe[o] Instructions
[qemu.git] / target-ppc / int_helper.c
blob71db3fb076b79d8d9b5b9bf0960bd552bc8e760c
1 /*
2 * PowerPC integer and vector emulation helpers for QEMU.
4 * Copyright (c) 2003-2007 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, see <http://www.gnu.org/licenses/>.
19 #include "cpu.h"
20 #include "qemu/host-utils.h"
21 #include "helper.h"
23 #include "helper_regs.h"
24 /*****************************************************************************/
25 /* Fixed point operations helpers */
26 #if defined(TARGET_PPC64)
28 uint64_t helper_mulldo(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
30 int64_t th;
31 uint64_t tl;
33 muls64(&tl, (uint64_t *)&th, arg1, arg2);
34 /* If th != 0 && th != -1, then we had an overflow */
35 if (likely((uint64_t)(th + 1) <= 1)) {
36 env->ov = 0;
37 } else {
38 env->so = env->ov = 1;
40 return (int64_t)tl;
42 #endif
44 target_ulong helper_divweu(CPUPPCState *env, target_ulong ra, target_ulong rb,
45 uint32_t oe)
47 uint64_t rt = 0;
48 int overflow = 0;
50 uint64_t dividend = (uint64_t)ra << 32;
51 uint64_t divisor = (uint32_t)rb;
53 if (unlikely(divisor == 0)) {
54 overflow = 1;
55 } else {
56 rt = dividend / divisor;
57 overflow = rt > UINT32_MAX;
60 if (unlikely(overflow)) {
61 rt = 0; /* Undefined */
64 if (oe) {
65 if (unlikely(overflow)) {
66 env->so = env->ov = 1;
67 } else {
68 env->ov = 0;
72 return (target_ulong)rt;
75 target_ulong helper_divwe(CPUPPCState *env, target_ulong ra, target_ulong rb,
76 uint32_t oe)
78 int64_t rt = 0;
79 int overflow = 0;
81 int64_t dividend = (int64_t)ra << 32;
82 int64_t divisor = (int64_t)((int32_t)rb);
84 if (unlikely((divisor == 0) ||
85 ((divisor == -1ull) && (dividend == INT64_MIN)))) {
86 overflow = 1;
87 } else {
88 rt = dividend / divisor;
89 overflow = rt != (int32_t)rt;
92 if (unlikely(overflow)) {
93 rt = 0; /* Undefined */
96 if (oe) {
97 if (unlikely(overflow)) {
98 env->so = env->ov = 1;
99 } else {
100 env->ov = 0;
104 return (target_ulong)rt;
107 #if defined(TARGET_PPC64)
109 uint64_t helper_divdeu(CPUPPCState *env, uint64_t ra, uint64_t rb, uint32_t oe)
111 uint64_t rt = 0;
112 int overflow = 0;
114 overflow = divu128(&rt, &ra, rb);
116 if (unlikely(overflow)) {
117 rt = 0; /* Undefined */
120 if (oe) {
121 if (unlikely(overflow)) {
122 env->so = env->ov = 1;
123 } else {
124 env->ov = 0;
128 return rt;
131 uint64_t helper_divde(CPUPPCState *env, uint64_t rau, uint64_t rbu, uint32_t oe)
133 int64_t rt = 0;
134 int64_t ra = (int64_t)rau;
135 int64_t rb = (int64_t)rbu;
136 int overflow = divs128(&rt, &ra, rb);
138 if (unlikely(overflow)) {
139 rt = 0; /* Undefined */
142 if (oe) {
144 if (unlikely(overflow)) {
145 env->so = env->ov = 1;
146 } else {
147 env->ov = 0;
151 return rt;
154 #endif
157 target_ulong helper_cntlzw(target_ulong t)
159 return clz32(t);
162 #if defined(TARGET_PPC64)
163 target_ulong helper_cntlzd(target_ulong t)
165 return clz64(t);
167 #endif
169 #if defined(TARGET_PPC64)
171 uint64_t helper_bpermd(uint64_t rs, uint64_t rb)
173 int i;
174 uint64_t ra = 0;
176 for (i = 0; i < 8; i++) {
177 int index = (rs >> (i*8)) & 0xFF;
178 if (index < 64) {
179 if (rb & (1ull << (63-index))) {
180 ra |= 1 << i;
184 return ra;
187 #endif
189 target_ulong helper_cmpb(target_ulong rs, target_ulong rb)
191 target_ulong mask = 0xff;
192 target_ulong ra = 0;
193 int i;
195 for (i = 0; i < sizeof(target_ulong); i++) {
196 if ((rs & mask) == (rb & mask)) {
197 ra |= mask;
199 mask <<= 8;
201 return ra;
204 /* shift right arithmetic helper */
205 target_ulong helper_sraw(CPUPPCState *env, target_ulong value,
206 target_ulong shift)
208 int32_t ret;
210 if (likely(!(shift & 0x20))) {
211 if (likely((uint32_t)shift != 0)) {
212 shift &= 0x1f;
213 ret = (int32_t)value >> shift;
214 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
215 env->ca = 0;
216 } else {
217 env->ca = 1;
219 } else {
220 ret = (int32_t)value;
221 env->ca = 0;
223 } else {
224 ret = (int32_t)value >> 31;
225 env->ca = (ret != 0);
227 return (target_long)ret;
230 #if defined(TARGET_PPC64)
231 target_ulong helper_srad(CPUPPCState *env, target_ulong value,
232 target_ulong shift)
234 int64_t ret;
236 if (likely(!(shift & 0x40))) {
237 if (likely((uint64_t)shift != 0)) {
238 shift &= 0x3f;
239 ret = (int64_t)value >> shift;
240 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
241 env->ca = 0;
242 } else {
243 env->ca = 1;
245 } else {
246 ret = (int64_t)value;
247 env->ca = 0;
249 } else {
250 ret = (int64_t)value >> 63;
251 env->ca = (ret != 0);
253 return ret;
255 #endif
257 #if defined(TARGET_PPC64)
258 target_ulong helper_popcntb(target_ulong val)
260 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
261 0x5555555555555555ULL);
262 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
263 0x3333333333333333ULL);
264 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
265 0x0f0f0f0f0f0f0f0fULL);
266 return val;
269 target_ulong helper_popcntw(target_ulong val)
271 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
272 0x5555555555555555ULL);
273 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
274 0x3333333333333333ULL);
275 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
276 0x0f0f0f0f0f0f0f0fULL);
277 val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) &
278 0x00ff00ff00ff00ffULL);
279 val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
280 0x0000ffff0000ffffULL);
281 return val;
284 target_ulong helper_popcntd(target_ulong val)
286 return ctpop64(val);
288 #else
289 target_ulong helper_popcntb(target_ulong val)
291 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
292 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
293 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
294 return val;
297 target_ulong helper_popcntw(target_ulong val)
299 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
300 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
301 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
302 val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff);
303 val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
304 return val;
306 #endif
308 /*****************************************************************************/
309 /* PowerPC 601 specific instructions (POWER bridge) */
310 target_ulong helper_div(CPUPPCState *env, target_ulong arg1, target_ulong arg2)
312 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
314 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
315 (int32_t)arg2 == 0) {
316 env->spr[SPR_MQ] = 0;
317 return INT32_MIN;
318 } else {
319 env->spr[SPR_MQ] = tmp % arg2;
320 return tmp / (int32_t)arg2;
324 target_ulong helper_divo(CPUPPCState *env, target_ulong arg1,
325 target_ulong arg2)
327 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
329 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
330 (int32_t)arg2 == 0) {
331 env->so = env->ov = 1;
332 env->spr[SPR_MQ] = 0;
333 return INT32_MIN;
334 } else {
335 env->spr[SPR_MQ] = tmp % arg2;
336 tmp /= (int32_t)arg2;
337 if ((int32_t)tmp != tmp) {
338 env->so = env->ov = 1;
339 } else {
340 env->ov = 0;
342 return tmp;
346 target_ulong helper_divs(CPUPPCState *env, target_ulong arg1,
347 target_ulong arg2)
349 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
350 (int32_t)arg2 == 0) {
351 env->spr[SPR_MQ] = 0;
352 return INT32_MIN;
353 } else {
354 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
355 return (int32_t)arg1 / (int32_t)arg2;
359 target_ulong helper_divso(CPUPPCState *env, target_ulong arg1,
360 target_ulong arg2)
362 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
363 (int32_t)arg2 == 0) {
364 env->so = env->ov = 1;
365 env->spr[SPR_MQ] = 0;
366 return INT32_MIN;
367 } else {
368 env->ov = 0;
369 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
370 return (int32_t)arg1 / (int32_t)arg2;
374 /*****************************************************************************/
375 /* 602 specific instructions */
376 /* mfrom is the most crazy instruction ever seen, imho ! */
377 /* Real implementation uses a ROM table. Do the same */
378 /* Extremely decomposed:
379 * -arg / 256
380 * return 256 * log10(10 + 1.0) + 0.5
382 #if !defined(CONFIG_USER_ONLY)
383 target_ulong helper_602_mfrom(target_ulong arg)
385 if (likely(arg < 602)) {
386 #include "mfrom_table.c"
387 return mfrom_ROM_table[arg];
388 } else {
389 return 0;
392 #endif
394 /*****************************************************************************/
395 /* Altivec extension helpers */
396 #if defined(HOST_WORDS_BIGENDIAN)
397 #define HI_IDX 0
398 #define LO_IDX 1
399 #else
400 #define HI_IDX 1
401 #define LO_IDX 0
402 #endif
404 #if defined(HOST_WORDS_BIGENDIAN)
405 #define VECTOR_FOR_INORDER_I(index, element) \
406 for (index = 0; index < ARRAY_SIZE(r->element); index++)
407 #else
408 #define VECTOR_FOR_INORDER_I(index, element) \
409 for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
410 #endif
412 /* Saturating arithmetic helpers. */
413 #define SATCVT(from, to, from_type, to_type, min, max) \
414 static inline to_type cvt##from##to(from_type x, int *sat) \
416 to_type r; \
418 if (x < (from_type)min) { \
419 r = min; \
420 *sat = 1; \
421 } else if (x > (from_type)max) { \
422 r = max; \
423 *sat = 1; \
424 } else { \
425 r = x; \
427 return r; \
429 #define SATCVTU(from, to, from_type, to_type, min, max) \
430 static inline to_type cvt##from##to(from_type x, int *sat) \
432 to_type r; \
434 if (x > (from_type)max) { \
435 r = max; \
436 *sat = 1; \
437 } else { \
438 r = x; \
440 return r; \
442 SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
443 SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
444 SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
446 SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
447 SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
448 SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
449 SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
450 SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
451 SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
452 #undef SATCVT
453 #undef SATCVTU
455 void helper_lvsl(ppc_avr_t *r, target_ulong sh)
457 int i, j = (sh & 0xf);
459 VECTOR_FOR_INORDER_I(i, u8) {
460 r->u8[i] = j++;
464 void helper_lvsr(ppc_avr_t *r, target_ulong sh)
466 int i, j = 0x10 - (sh & 0xf);
468 VECTOR_FOR_INORDER_I(i, u8) {
469 r->u8[i] = j++;
473 void helper_mtvscr(CPUPPCState *env, ppc_avr_t *r)
475 #if defined(HOST_WORDS_BIGENDIAN)
476 env->vscr = r->u32[3];
477 #else
478 env->vscr = r->u32[0];
479 #endif
480 set_flush_to_zero(vscr_nj, &env->vec_status);
483 void helper_vaddcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
485 int i;
487 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
488 r->u32[i] = ~a->u32[i] < b->u32[i];
492 #define VARITH_DO(name, op, element) \
493 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
495 int i; \
497 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
498 r->element[i] = a->element[i] op b->element[i]; \
501 #define VARITH(suffix, element) \
502 VARITH_DO(add##suffix, +, element) \
503 VARITH_DO(sub##suffix, -, element)
504 VARITH(ubm, u8)
505 VARITH(uhm, u16)
506 VARITH(uwm, u32)
507 #undef VARITH_DO
508 #undef VARITH
510 #define VARITHFP(suffix, func) \
511 void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
512 ppc_avr_t *b) \
514 int i; \
516 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
517 r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
520 VARITHFP(addfp, float32_add)
521 VARITHFP(subfp, float32_sub)
522 VARITHFP(minfp, float32_min)
523 VARITHFP(maxfp, float32_max)
524 #undef VARITHFP
526 #define VARITHFPFMA(suffix, type) \
527 void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
528 ppc_avr_t *b, ppc_avr_t *c) \
530 int i; \
531 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
532 r->f[i] = float32_muladd(a->f[i], c->f[i], b->f[i], \
533 type, &env->vec_status); \
536 VARITHFPFMA(maddfp, 0);
537 VARITHFPFMA(nmsubfp, float_muladd_negate_result | float_muladd_negate_c);
538 #undef VARITHFPFMA
540 #define VARITHSAT_CASE(type, op, cvt, element) \
542 type result = (type)a->element[i] op (type)b->element[i]; \
543 r->element[i] = cvt(result, &sat); \
546 #define VARITHSAT_DO(name, op, optype, cvt, element) \
547 void helper_v##name(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
548 ppc_avr_t *b) \
550 int sat = 0; \
551 int i; \
553 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
554 switch (sizeof(r->element[0])) { \
555 case 1: \
556 VARITHSAT_CASE(optype, op, cvt, element); \
557 break; \
558 case 2: \
559 VARITHSAT_CASE(optype, op, cvt, element); \
560 break; \
561 case 4: \
562 VARITHSAT_CASE(optype, op, cvt, element); \
563 break; \
566 if (sat) { \
567 env->vscr |= (1 << VSCR_SAT); \
570 #define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
571 VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
572 VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
573 #define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
574 VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
575 VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
576 VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
577 VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
578 VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
579 VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
580 VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
581 VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
582 #undef VARITHSAT_CASE
583 #undef VARITHSAT_DO
584 #undef VARITHSAT_SIGNED
585 #undef VARITHSAT_UNSIGNED
587 #define VAVG_DO(name, element, etype) \
588 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
590 int i; \
592 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
593 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
594 r->element[i] = x >> 1; \
598 #define VAVG(type, signed_element, signed_type, unsigned_element, \
599 unsigned_type) \
600 VAVG_DO(avgs##type, signed_element, signed_type) \
601 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
602 VAVG(b, s8, int16_t, u8, uint16_t)
603 VAVG(h, s16, int32_t, u16, uint32_t)
604 VAVG(w, s32, int64_t, u32, uint64_t)
605 #undef VAVG_DO
606 #undef VAVG
608 #define VCF(suffix, cvt, element) \
609 void helper_vcf##suffix(CPUPPCState *env, ppc_avr_t *r, \
610 ppc_avr_t *b, uint32_t uim) \
612 int i; \
614 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
615 float32 t = cvt(b->element[i], &env->vec_status); \
616 r->f[i] = float32_scalbn(t, -uim, &env->vec_status); \
619 VCF(ux, uint32_to_float32, u32)
620 VCF(sx, int32_to_float32, s32)
621 #undef VCF
623 #define VCMP_DO(suffix, compare, element, record) \
624 void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
625 ppc_avr_t *a, ppc_avr_t *b) \
627 uint32_t ones = (uint32_t)-1; \
628 uint32_t all = ones; \
629 uint32_t none = 0; \
630 int i; \
632 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
633 uint32_t result = (a->element[i] compare b->element[i] ? \
634 ones : 0x0); \
635 switch (sizeof(a->element[0])) { \
636 case 4: \
637 r->u32[i] = result; \
638 break; \
639 case 2: \
640 r->u16[i] = result; \
641 break; \
642 case 1: \
643 r->u8[i] = result; \
644 break; \
646 all &= result; \
647 none |= result; \
649 if (record) { \
650 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
653 #define VCMP(suffix, compare, element) \
654 VCMP_DO(suffix, compare, element, 0) \
655 VCMP_DO(suffix##_dot, compare, element, 1)
656 VCMP(equb, ==, u8)
657 VCMP(equh, ==, u16)
658 VCMP(equw, ==, u32)
659 VCMP(gtub, >, u8)
660 VCMP(gtuh, >, u16)
661 VCMP(gtuw, >, u32)
662 VCMP(gtsb, >, s8)
663 VCMP(gtsh, >, s16)
664 VCMP(gtsw, >, s32)
665 #undef VCMP_DO
666 #undef VCMP
668 #define VCMPFP_DO(suffix, compare, order, record) \
669 void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
670 ppc_avr_t *a, ppc_avr_t *b) \
672 uint32_t ones = (uint32_t)-1; \
673 uint32_t all = ones; \
674 uint32_t none = 0; \
675 int i; \
677 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
678 uint32_t result; \
679 int rel = float32_compare_quiet(a->f[i], b->f[i], \
680 &env->vec_status); \
681 if (rel == float_relation_unordered) { \
682 result = 0; \
683 } else if (rel compare order) { \
684 result = ones; \
685 } else { \
686 result = 0; \
688 r->u32[i] = result; \
689 all &= result; \
690 none |= result; \
692 if (record) { \
693 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
696 #define VCMPFP(suffix, compare, order) \
697 VCMPFP_DO(suffix, compare, order, 0) \
698 VCMPFP_DO(suffix##_dot, compare, order, 1)
699 VCMPFP(eqfp, ==, float_relation_equal)
700 VCMPFP(gefp, !=, float_relation_less)
701 VCMPFP(gtfp, ==, float_relation_greater)
702 #undef VCMPFP_DO
703 #undef VCMPFP
705 static inline void vcmpbfp_internal(CPUPPCState *env, ppc_avr_t *r,
706 ppc_avr_t *a, ppc_avr_t *b, int record)
708 int i;
709 int all_in = 0;
711 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
712 int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
713 if (le_rel == float_relation_unordered) {
714 r->u32[i] = 0xc0000000;
715 /* ALL_IN does not need to be updated here. */
716 } else {
717 float32 bneg = float32_chs(b->f[i]);
718 int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
719 int le = le_rel != float_relation_greater;
720 int ge = ge_rel != float_relation_less;
722 r->u32[i] = ((!le) << 31) | ((!ge) << 30);
723 all_in |= (!le | !ge);
726 if (record) {
727 env->crf[6] = (all_in == 0) << 1;
731 void helper_vcmpbfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
733 vcmpbfp_internal(env, r, a, b, 0);
736 void helper_vcmpbfp_dot(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
737 ppc_avr_t *b)
739 vcmpbfp_internal(env, r, a, b, 1);
742 #define VCT(suffix, satcvt, element) \
743 void helper_vct##suffix(CPUPPCState *env, ppc_avr_t *r, \
744 ppc_avr_t *b, uint32_t uim) \
746 int i; \
747 int sat = 0; \
748 float_status s = env->vec_status; \
750 set_float_rounding_mode(float_round_to_zero, &s); \
751 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
752 if (float32_is_any_nan(b->f[i])) { \
753 r->element[i] = 0; \
754 } else { \
755 float64 t = float32_to_float64(b->f[i], &s); \
756 int64_t j; \
758 t = float64_scalbn(t, uim, &s); \
759 j = float64_to_int64(t, &s); \
760 r->element[i] = satcvt(j, &sat); \
763 if (sat) { \
764 env->vscr |= (1 << VSCR_SAT); \
767 VCT(uxs, cvtsduw, u32)
768 VCT(sxs, cvtsdsw, s32)
769 #undef VCT
771 void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
772 ppc_avr_t *b, ppc_avr_t *c)
774 int sat = 0;
775 int i;
777 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
778 int32_t prod = a->s16[i] * b->s16[i];
779 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
781 r->s16[i] = cvtswsh(t, &sat);
784 if (sat) {
785 env->vscr |= (1 << VSCR_SAT);
789 void helper_vmhraddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
790 ppc_avr_t *b, ppc_avr_t *c)
792 int sat = 0;
793 int i;
795 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
796 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
797 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
798 r->s16[i] = cvtswsh(t, &sat);
801 if (sat) {
802 env->vscr |= (1 << VSCR_SAT);
806 #define VMINMAX_DO(name, compare, element) \
807 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
809 int i; \
811 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
812 if (a->element[i] compare b->element[i]) { \
813 r->element[i] = b->element[i]; \
814 } else { \
815 r->element[i] = a->element[i]; \
819 #define VMINMAX(suffix, element) \
820 VMINMAX_DO(min##suffix, >, element) \
821 VMINMAX_DO(max##suffix, <, element)
822 VMINMAX(sb, s8)
823 VMINMAX(sh, s16)
824 VMINMAX(sw, s32)
825 VMINMAX(ub, u8)
826 VMINMAX(uh, u16)
827 VMINMAX(uw, u32)
828 #undef VMINMAX_DO
829 #undef VMINMAX
831 void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
833 int i;
835 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
836 int32_t prod = a->s16[i] * b->s16[i];
837 r->s16[i] = (int16_t) (prod + c->s16[i]);
841 #define VMRG_DO(name, element, highp) \
842 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
844 ppc_avr_t result; \
845 int i; \
846 size_t n_elems = ARRAY_SIZE(r->element); \
848 for (i = 0; i < n_elems / 2; i++) { \
849 if (highp) { \
850 result.element[i*2+HI_IDX] = a->element[i]; \
851 result.element[i*2+LO_IDX] = b->element[i]; \
852 } else { \
853 result.element[n_elems - i * 2 - (1 + HI_IDX)] = \
854 b->element[n_elems - i - 1]; \
855 result.element[n_elems - i * 2 - (1 + LO_IDX)] = \
856 a->element[n_elems - i - 1]; \
859 *r = result; \
861 #if defined(HOST_WORDS_BIGENDIAN)
862 #define MRGHI 0
863 #define MRGLO 1
864 #else
865 #define MRGHI 1
866 #define MRGLO 0
867 #endif
868 #define VMRG(suffix, element) \
869 VMRG_DO(mrgl##suffix, element, MRGHI) \
870 VMRG_DO(mrgh##suffix, element, MRGLO)
871 VMRG(b, u8)
872 VMRG(h, u16)
873 VMRG(w, u32)
874 #undef VMRG_DO
875 #undef VMRG
876 #undef MRGHI
877 #undef MRGLO
879 void helper_vmsummbm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
880 ppc_avr_t *b, ppc_avr_t *c)
882 int32_t prod[16];
883 int i;
885 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
886 prod[i] = (int32_t)a->s8[i] * b->u8[i];
889 VECTOR_FOR_INORDER_I(i, s32) {
890 r->s32[i] = c->s32[i] + prod[4 * i] + prod[4 * i + 1] +
891 prod[4 * i + 2] + prod[4 * i + 3];
895 void helper_vmsumshm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
896 ppc_avr_t *b, ppc_avr_t *c)
898 int32_t prod[8];
899 int i;
901 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
902 prod[i] = a->s16[i] * b->s16[i];
905 VECTOR_FOR_INORDER_I(i, s32) {
906 r->s32[i] = c->s32[i] + prod[2 * i] + prod[2 * i + 1];
910 void helper_vmsumshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
911 ppc_avr_t *b, ppc_avr_t *c)
913 int32_t prod[8];
914 int i;
915 int sat = 0;
917 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
918 prod[i] = (int32_t)a->s16[i] * b->s16[i];
921 VECTOR_FOR_INORDER_I(i, s32) {
922 int64_t t = (int64_t)c->s32[i] + prod[2 * i] + prod[2 * i + 1];
924 r->u32[i] = cvtsdsw(t, &sat);
927 if (sat) {
928 env->vscr |= (1 << VSCR_SAT);
932 void helper_vmsumubm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
933 ppc_avr_t *b, ppc_avr_t *c)
935 uint16_t prod[16];
936 int i;
938 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
939 prod[i] = a->u8[i] * b->u8[i];
942 VECTOR_FOR_INORDER_I(i, u32) {
943 r->u32[i] = c->u32[i] + prod[4 * i] + prod[4 * i + 1] +
944 prod[4 * i + 2] + prod[4 * i + 3];
948 void helper_vmsumuhm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
949 ppc_avr_t *b, ppc_avr_t *c)
951 uint32_t prod[8];
952 int i;
954 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
955 prod[i] = a->u16[i] * b->u16[i];
958 VECTOR_FOR_INORDER_I(i, u32) {
959 r->u32[i] = c->u32[i] + prod[2 * i] + prod[2 * i + 1];
963 void helper_vmsumuhs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
964 ppc_avr_t *b, ppc_avr_t *c)
966 uint32_t prod[8];
967 int i;
968 int sat = 0;
970 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
971 prod[i] = a->u16[i] * b->u16[i];
974 VECTOR_FOR_INORDER_I(i, s32) {
975 uint64_t t = (uint64_t)c->u32[i] + prod[2 * i] + prod[2 * i + 1];
977 r->u32[i] = cvtuduw(t, &sat);
980 if (sat) {
981 env->vscr |= (1 << VSCR_SAT);
985 #define VMUL_DO(name, mul_element, prod_element, evenp) \
986 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
988 int i; \
990 VECTOR_FOR_INORDER_I(i, prod_element) { \
991 if (evenp) { \
992 r->prod_element[i] = a->mul_element[i * 2 + HI_IDX] * \
993 b->mul_element[i * 2 + HI_IDX]; \
994 } else { \
995 r->prod_element[i] = a->mul_element[i * 2 + LO_IDX] * \
996 b->mul_element[i * 2 + LO_IDX]; \
1000 #define VMUL(suffix, mul_element, prod_element) \
1001 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
1002 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
1003 VMUL(sb, s8, s16)
1004 VMUL(sh, s16, s32)
1005 VMUL(ub, u8, u16)
1006 VMUL(uh, u16, u32)
1007 #undef VMUL_DO
1008 #undef VMUL
1010 void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
1011 ppc_avr_t *c)
1013 ppc_avr_t result;
1014 int i;
1016 VECTOR_FOR_INORDER_I(i, u8) {
1017 int s = c->u8[i] & 0x1f;
1018 #if defined(HOST_WORDS_BIGENDIAN)
1019 int index = s & 0xf;
1020 #else
1021 int index = 15 - (s & 0xf);
1022 #endif
1024 if (s & 0x10) {
1025 result.u8[i] = b->u8[index];
1026 } else {
1027 result.u8[i] = a->u8[index];
1030 *r = result;
1033 #if defined(HOST_WORDS_BIGENDIAN)
1034 #define PKBIG 1
1035 #else
1036 #define PKBIG 0
1037 #endif
1038 void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1040 int i, j;
1041 ppc_avr_t result;
1042 #if defined(HOST_WORDS_BIGENDIAN)
1043 const ppc_avr_t *x[2] = { a, b };
1044 #else
1045 const ppc_avr_t *x[2] = { b, a };
1046 #endif
1048 VECTOR_FOR_INORDER_I(i, u64) {
1049 VECTOR_FOR_INORDER_I(j, u32) {
1050 uint32_t e = x[i]->u32[j];
1052 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
1053 ((e >> 6) & 0x3e0) |
1054 ((e >> 3) & 0x1f));
1057 *r = result;
1060 #define VPK(suffix, from, to, cvt, dosat) \
1061 void helper_vpk##suffix(CPUPPCState *env, ppc_avr_t *r, \
1062 ppc_avr_t *a, ppc_avr_t *b) \
1064 int i; \
1065 int sat = 0; \
1066 ppc_avr_t result; \
1067 ppc_avr_t *a0 = PKBIG ? a : b; \
1068 ppc_avr_t *a1 = PKBIG ? b : a; \
1070 VECTOR_FOR_INORDER_I(i, from) { \
1071 result.to[i] = cvt(a0->from[i], &sat); \
1072 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
1074 *r = result; \
1075 if (dosat && sat) { \
1076 env->vscr |= (1 << VSCR_SAT); \
1079 #define I(x, y) (x)
1080 VPK(shss, s16, s8, cvtshsb, 1)
1081 VPK(shus, s16, u8, cvtshub, 1)
1082 VPK(swss, s32, s16, cvtswsh, 1)
1083 VPK(swus, s32, u16, cvtswuh, 1)
1084 VPK(uhus, u16, u8, cvtuhub, 1)
1085 VPK(uwus, u32, u16, cvtuwuh, 1)
1086 VPK(uhum, u16, u8, I, 0)
1087 VPK(uwum, u32, u16, I, 0)
1088 #undef I
1089 #undef VPK
1090 #undef PKBIG
1092 void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
1094 int i;
1096 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
1097 r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
1101 #define VRFI(suffix, rounding) \
1102 void helper_vrfi##suffix(CPUPPCState *env, ppc_avr_t *r, \
1103 ppc_avr_t *b) \
1105 int i; \
1106 float_status s = env->vec_status; \
1108 set_float_rounding_mode(rounding, &s); \
1109 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
1110 r->f[i] = float32_round_to_int (b->f[i], &s); \
1113 VRFI(n, float_round_nearest_even)
1114 VRFI(m, float_round_down)
1115 VRFI(p, float_round_up)
1116 VRFI(z, float_round_to_zero)
1117 #undef VRFI
1119 #define VROTATE(suffix, element) \
1120 void helper_vrl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1122 int i; \
1124 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1125 unsigned int mask = ((1 << \
1126 (3 + (sizeof(a->element[0]) >> 1))) \
1127 - 1); \
1128 unsigned int shift = b->element[i] & mask; \
1129 r->element[i] = (a->element[i] << shift) | \
1130 (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
1133 VROTATE(b, u8)
1134 VROTATE(h, u16)
1135 VROTATE(w, u32)
1136 #undef VROTATE
1138 void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
1140 int i;
1142 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
1143 float32 t = float32_sqrt(b->f[i], &env->vec_status);
1145 r->f[i] = float32_div(float32_one, t, &env->vec_status);
1149 void helper_vsel(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
1150 ppc_avr_t *c)
1152 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
1153 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
1156 void helper_vexptefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
1158 int i;
1160 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
1161 r->f[i] = float32_exp2(b->f[i], &env->vec_status);
1165 void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
1167 int i;
1169 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
1170 r->f[i] = float32_log2(b->f[i], &env->vec_status);
1174 #if defined(HOST_WORDS_BIGENDIAN)
1175 #define LEFT 0
1176 #define RIGHT 1
1177 #else
1178 #define LEFT 1
1179 #define RIGHT 0
1180 #endif
1181 /* The specification says that the results are undefined if all of the
1182 * shift counts are not identical. We check to make sure that they are
1183 * to conform to what real hardware appears to do. */
1184 #define VSHIFT(suffix, leftp) \
1185 void helper_vs##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1187 int shift = b->u8[LO_IDX*15] & 0x7; \
1188 int doit = 1; \
1189 int i; \
1191 for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
1192 doit = doit && ((b->u8[i] & 0x7) == shift); \
1194 if (doit) { \
1195 if (shift == 0) { \
1196 *r = *a; \
1197 } else if (leftp) { \
1198 uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
1200 r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
1201 r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
1202 } else { \
1203 uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
1205 r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
1206 r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
1210 VSHIFT(l, LEFT)
1211 VSHIFT(r, RIGHT)
1212 #undef VSHIFT
1213 #undef LEFT
1214 #undef RIGHT
1216 #define VSL(suffix, element) \
1217 void helper_vsl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1219 int i; \
1221 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1222 unsigned int mask = ((1 << \
1223 (3 + (sizeof(a->element[0]) >> 1))) \
1224 - 1); \
1225 unsigned int shift = b->element[i] & mask; \
1227 r->element[i] = a->element[i] << shift; \
1230 VSL(b, u8)
1231 VSL(h, u16)
1232 VSL(w, u32)
1233 #undef VSL
1235 void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
1237 int sh = shift & 0xf;
1238 int i;
1239 ppc_avr_t result;
1241 #if defined(HOST_WORDS_BIGENDIAN)
1242 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
1243 int index = sh + i;
1244 if (index > 0xf) {
1245 result.u8[i] = b->u8[index - 0x10];
1246 } else {
1247 result.u8[i] = a->u8[index];
1250 #else
1251 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
1252 int index = (16 - sh) + i;
1253 if (index > 0xf) {
1254 result.u8[i] = a->u8[index - 0x10];
1255 } else {
1256 result.u8[i] = b->u8[index];
1259 #endif
1260 *r = result;
1263 void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1265 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
1267 #if defined(HOST_WORDS_BIGENDIAN)
1268 memmove(&r->u8[0], &a->u8[sh], 16 - sh);
1269 memset(&r->u8[16-sh], 0, sh);
1270 #else
1271 memmove(&r->u8[sh], &a->u8[0], 16 - sh);
1272 memset(&r->u8[0], 0, sh);
1273 #endif
1276 /* Experimental testing shows that hardware masks the immediate. */
1277 #define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
1278 #if defined(HOST_WORDS_BIGENDIAN)
1279 #define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
1280 #else
1281 #define SPLAT_ELEMENT(element) \
1282 (ARRAY_SIZE(r->element) - 1 - _SPLAT_MASKED(element))
1283 #endif
1284 #define VSPLT(suffix, element) \
1285 void helper_vsplt##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
1287 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
1288 int i; \
1290 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1291 r->element[i] = s; \
1294 VSPLT(b, u8)
1295 VSPLT(h, u16)
1296 VSPLT(w, u32)
1297 #undef VSPLT
1298 #undef SPLAT_ELEMENT
1299 #undef _SPLAT_MASKED
1301 #define VSPLTI(suffix, element, splat_type) \
1302 void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \
1304 splat_type x = (int8_t)(splat << 3) >> 3; \
1305 int i; \
1307 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1308 r->element[i] = x; \
1311 VSPLTI(b, s8, int8_t)
1312 VSPLTI(h, s16, int16_t)
1313 VSPLTI(w, s32, int32_t)
1314 #undef VSPLTI
1316 #define VSR(suffix, element) \
1317 void helper_vsr##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1319 int i; \
1321 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1322 unsigned int mask = ((1 << \
1323 (3 + (sizeof(a->element[0]) >> 1))) \
1324 - 1); \
1325 unsigned int shift = b->element[i] & mask; \
1327 r->element[i] = a->element[i] >> shift; \
1330 VSR(ab, s8)
1331 VSR(ah, s16)
1332 VSR(aw, s32)
1333 VSR(b, u8)
1334 VSR(h, u16)
1335 VSR(w, u32)
1336 #undef VSR
1338 void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1340 int sh = (b->u8[LO_IDX * 0xf] >> 3) & 0xf;
1342 #if defined(HOST_WORDS_BIGENDIAN)
1343 memmove(&r->u8[sh], &a->u8[0], 16 - sh);
1344 memset(&r->u8[0], 0, sh);
1345 #else
1346 memmove(&r->u8[0], &a->u8[sh], 16 - sh);
1347 memset(&r->u8[16 - sh], 0, sh);
1348 #endif
1351 void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1353 int i;
1355 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
1356 r->u32[i] = a->u32[i] >= b->u32[i];
1360 void helper_vsumsws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1362 int64_t t;
1363 int i, upper;
1364 ppc_avr_t result;
1365 int sat = 0;
1367 #if defined(HOST_WORDS_BIGENDIAN)
1368 upper = ARRAY_SIZE(r->s32)-1;
1369 #else
1370 upper = 0;
1371 #endif
1372 t = (int64_t)b->s32[upper];
1373 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1374 t += a->s32[i];
1375 result.s32[i] = 0;
1377 result.s32[upper] = cvtsdsw(t, &sat);
1378 *r = result;
1380 if (sat) {
1381 env->vscr |= (1 << VSCR_SAT);
1385 void helper_vsum2sws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1387 int i, j, upper;
1388 ppc_avr_t result;
1389 int sat = 0;
1391 #if defined(HOST_WORDS_BIGENDIAN)
1392 upper = 1;
1393 #else
1394 upper = 0;
1395 #endif
1396 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
1397 int64_t t = (int64_t)b->s32[upper + i * 2];
1399 result.u64[i] = 0;
1400 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
1401 t += a->s32[2 * i + j];
1403 result.s32[upper + i * 2] = cvtsdsw(t, &sat);
1406 *r = result;
1407 if (sat) {
1408 env->vscr |= (1 << VSCR_SAT);
1412 void helper_vsum4sbs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1414 int i, j;
1415 int sat = 0;
1417 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1418 int64_t t = (int64_t)b->s32[i];
1420 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
1421 t += a->s8[4 * i + j];
1423 r->s32[i] = cvtsdsw(t, &sat);
1426 if (sat) {
1427 env->vscr |= (1 << VSCR_SAT);
1431 void helper_vsum4shs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1433 int sat = 0;
1434 int i;
1436 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1437 int64_t t = (int64_t)b->s32[i];
1439 t += a->s16[2 * i] + a->s16[2 * i + 1];
1440 r->s32[i] = cvtsdsw(t, &sat);
1443 if (sat) {
1444 env->vscr |= (1 << VSCR_SAT);
1448 void helper_vsum4ubs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1450 int i, j;
1451 int sat = 0;
1453 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
1454 uint64_t t = (uint64_t)b->u32[i];
1456 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
1457 t += a->u8[4 * i + j];
1459 r->u32[i] = cvtuduw(t, &sat);
1462 if (sat) {
1463 env->vscr |= (1 << VSCR_SAT);
1467 #if defined(HOST_WORDS_BIGENDIAN)
1468 #define UPKHI 1
1469 #define UPKLO 0
1470 #else
1471 #define UPKHI 0
1472 #define UPKLO 1
1473 #endif
1474 #define VUPKPX(suffix, hi) \
1475 void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
1477 int i; \
1478 ppc_avr_t result; \
1480 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
1481 uint16_t e = b->u16[hi ? i : i+4]; \
1482 uint8_t a = (e >> 15) ? 0xff : 0; \
1483 uint8_t r = (e >> 10) & 0x1f; \
1484 uint8_t g = (e >> 5) & 0x1f; \
1485 uint8_t b = e & 0x1f; \
1487 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
1489 *r = result; \
1491 VUPKPX(lpx, UPKLO)
1492 VUPKPX(hpx, UPKHI)
1493 #undef VUPKPX
1495 #define VUPK(suffix, unpacked, packee, hi) \
1496 void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
1498 int i; \
1499 ppc_avr_t result; \
1501 if (hi) { \
1502 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
1503 result.unpacked[i] = b->packee[i]; \
1505 } else { \
1506 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); \
1507 i++) { \
1508 result.unpacked[i - ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
1511 *r = result; \
1513 VUPK(hsb, s16, s8, UPKHI)
1514 VUPK(hsh, s32, s16, UPKHI)
1515 VUPK(lsb, s16, s8, UPKLO)
1516 VUPK(lsh, s32, s16, UPKLO)
1517 #undef VUPK
1518 #undef UPKHI
1519 #undef UPKLO
1521 #undef VECTOR_FOR_INORDER_I
1522 #undef HI_IDX
1523 #undef LO_IDX
1525 /*****************************************************************************/
1526 /* SPE extension helpers */
1527 /* Use a table to make this quicker */
1528 static const uint8_t hbrev[16] = {
1529 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
1530 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
1533 static inline uint8_t byte_reverse(uint8_t val)
1535 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
1538 static inline uint32_t word_reverse(uint32_t val)
1540 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
1541 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
1544 #define MASKBITS 16 /* Random value - to be fixed (implementation dependent) */
1545 target_ulong helper_brinc(target_ulong arg1, target_ulong arg2)
1547 uint32_t a, b, d, mask;
1549 mask = UINT32_MAX >> (32 - MASKBITS);
1550 a = arg1 & mask;
1551 b = arg2 & mask;
1552 d = word_reverse(1 + word_reverse(a | ~b));
1553 return (arg1 & ~mask) | (d & b);
1556 uint32_t helper_cntlsw32(uint32_t val)
1558 if (val & 0x80000000) {
1559 return clz32(~val);
1560 } else {
1561 return clz32(val);
1565 uint32_t helper_cntlzw32(uint32_t val)
1567 return clz32(val);
1570 /* 440 specific */
1571 target_ulong helper_dlmzb(CPUPPCState *env, target_ulong high,
1572 target_ulong low, uint32_t update_Rc)
1574 target_ulong mask;
1575 int i;
1577 i = 1;
1578 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1579 if ((high & mask) == 0) {
1580 if (update_Rc) {
1581 env->crf[0] = 0x4;
1583 goto done;
1585 i++;
1587 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1588 if ((low & mask) == 0) {
1589 if (update_Rc) {
1590 env->crf[0] = 0x8;
1592 goto done;
1594 i++;
1596 if (update_Rc) {
1597 env->crf[0] = 0x2;
1599 done:
1600 env->xer = (env->xer & ~0x7F) | i;
1601 if (update_Rc) {
1602 env->crf[0] |= xer_so;
1604 return i;