]> git.proxmox.com Git - mirror_qemu.git/blame - target/ppc/int_helper.c
target/ppc: Move vinsertb/vinserth/vinsertw/vinsertd to decodetree
[mirror_qemu.git] / target / ppc / int_helper.c
CommitLineData
64654ded
BS
1/*
2 * PowerPC integer and vector emulation helpers for QEMU.
3 *
4 * Copyright (c) 2003-2007 Jocelyn Mayer
5 *
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
6bd039cd 9 * version 2.1 of the License, or (at your option) any later version.
64654ded
BS
10 *
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.
15 *
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/>.
18 */
db725815 19
0d75590d 20#include "qemu/osdep.h"
64654ded 21#include "cpu.h"
3e00884f 22#include "internal.h"
1de7afc9 23#include "qemu/host-utils.h"
db725815 24#include "qemu/main-loop.h"
8a05fd9a 25#include "qemu/log.h"
2ef6175a 26#include "exec/helper-proto.h"
6f2945cd 27#include "crypto/aes.h"
24f91e81 28#include "fpu/softfloat.h"
3f74b632
RH
29#include "qapi/error.h"
30#include "qemu/guest-random.h"
64654ded
BS
31
32#include "helper_regs.h"
33/*****************************************************************************/
34/* Fixed point operations helpers */
64654ded 35
f32899de
ND
36static inline void helper_update_ov_legacy(CPUPPCState *env, int ov)
37{
38 if (unlikely(ov)) {
39 env->so = env->ov = 1;
40 } else {
41 env->ov = 0;
42 }
43}
44
6a4fda33
TM
45target_ulong helper_divweu(CPUPPCState *env, target_ulong ra, target_ulong rb,
46 uint32_t oe)
47{
48 uint64_t rt = 0;
49 int overflow = 0;
50
51 uint64_t dividend = (uint64_t)ra << 32;
52 uint64_t divisor = (uint32_t)rb;
53
54 if (unlikely(divisor == 0)) {
55 overflow = 1;
56 } else {
57 rt = dividend / divisor;
58 overflow = rt > UINT32_MAX;
59 }
60
61 if (unlikely(overflow)) {
62 rt = 0; /* Undefined */
63 }
64
65 if (oe) {
f32899de 66 helper_update_ov_legacy(env, overflow);
6a4fda33
TM
67 }
68
69 return (target_ulong)rt;
70}
71
a98eb9e9
TM
72target_ulong helper_divwe(CPUPPCState *env, target_ulong ra, target_ulong rb,
73 uint32_t oe)
74{
75 int64_t rt = 0;
76 int overflow = 0;
77
78 int64_t dividend = (int64_t)ra << 32;
79 int64_t divisor = (int64_t)((int32_t)rb);
80
81 if (unlikely((divisor == 0) ||
82 ((divisor == -1ull) && (dividend == INT64_MIN)))) {
83 overflow = 1;
84 } else {
85 rt = dividend / divisor;
86 overflow = rt != (int32_t)rt;
87 }
88
89 if (unlikely(overflow)) {
90 rt = 0; /* Undefined */
91 }
92
93 if (oe) {
f32899de 94 helper_update_ov_legacy(env, overflow);
a98eb9e9
TM
95 }
96
97 return (target_ulong)rt;
98}
99
98d1eb27
TM
100#if defined(TARGET_PPC64)
101
102uint64_t helper_divdeu(CPUPPCState *env, uint64_t ra, uint64_t rb, uint32_t oe)
103{
104 uint64_t rt = 0;
105 int overflow = 0;
106
9276a31c
LP
107 if (unlikely(rb == 0 || ra >= rb)) {
108 overflow = 1;
98d1eb27 109 rt = 0; /* Undefined */
9276a31c
LP
110 } else {
111 divu128(&rt, &ra, rb);
98d1eb27
TM
112 }
113
114 if (oe) {
f32899de 115 helper_update_ov_legacy(env, overflow);
98d1eb27
TM
116 }
117
118 return rt;
119}
120
e44259b6
TM
121uint64_t helper_divde(CPUPPCState *env, uint64_t rau, uint64_t rbu, uint32_t oe)
122{
40f3e79a 123 uint64_t rt = 0;
e44259b6
TM
124 int64_t ra = (int64_t)rau;
125 int64_t rb = (int64_t)rbu;
9276a31c 126 int overflow = 0;
e44259b6 127
9276a31c
LP
128 if (unlikely(rb == 0 || uabs64(ra) >= uabs64(rb))) {
129 overflow = 1;
e44259b6 130 rt = 0; /* Undefined */
9276a31c
LP
131 } else {
132 divs128(&rt, &ra, rb);
e44259b6
TM
133 }
134
135 if (oe) {
f32899de 136 helper_update_ov_legacy(env, overflow);
e44259b6
TM
137 }
138
139 return rt;
140}
141
98d1eb27
TM
142#endif
143
144
64654ded 145#if defined(TARGET_PPC64)
082ce330
ND
146/* if x = 0xab, returns 0xababababababababa */
147#define pattern(x) (((x) & 0xff) * (~(target_ulong)0 / 0xff))
148
b6cb41b2
DG
149/*
150 * subtract 1 from each byte, and with inverse, check if MSB is set at each
082ce330
ND
151 * byte.
152 * i.e. ((0x00 - 0x01) & ~(0x00)) & 0x80
153 * (0xFF & 0xFF) & 0x80 = 0x80 (zero found)
154 */
155#define haszero(v) (((v) - pattern(0x01)) & ~(v) & pattern(0x80))
156
157/* When you XOR the pattern and there is a match, that byte will be zero */
158#define hasvalue(x, n) (haszero((x) ^ pattern(n)))
159
160uint32_t helper_cmpeqb(target_ulong ra, target_ulong rb)
161{
efa73196 162 return hasvalue(rb, ra) ? CRF_GT : 0;
082ce330
ND
163}
164
165#undef pattern
166#undef haszero
167#undef hasvalue
168
b6cb41b2 169/*
3f74b632 170 * Return a random number.
fec5c62a 171 */
3f74b632 172uint64_t helper_darn32(void)
fec5c62a 173{
3f74b632
RH
174 Error *err = NULL;
175 uint32_t ret;
176
177 if (qemu_guest_getrandom(&ret, sizeof(ret), &err) < 0) {
178 qemu_log_mask(LOG_UNIMP, "darn: Crypto failure: %s",
179 error_get_pretty(err));
180 error_free(err);
181 return -1;
182 }
fec5c62a 183
3f74b632 184 return ret;
fec5c62a
RB
185}
186
3f74b632
RH
187uint64_t helper_darn64(void)
188{
189 Error *err = NULL;
190 uint64_t ret;
191
192 if (qemu_guest_getrandom(&ret, sizeof(ret), &err) < 0) {
193 qemu_log_mask(LOG_UNIMP, "darn: Crypto failure: %s",
194 error_get_pretty(err));
195 error_free(err);
196 return -1;
197 }
64654ded 198
3f74b632
RH
199 return ret;
200}
86ba37ed
TM
201
202uint64_t helper_bpermd(uint64_t rs, uint64_t rb)
203{
204 int i;
205 uint64_t ra = 0;
206
207 for (i = 0; i < 8; i++) {
b6cb41b2 208 int index = (rs >> (i * 8)) & 0xFF;
86ba37ed 209 if (index < 64) {
a6a444a8 210 if (rb & PPC_BIT(index)) {
86ba37ed
TM
211 ra |= 1 << i;
212 }
213 }
214 }
215 return ra;
216}
217
218#endif
219
fcfda20f
AJ
220target_ulong helper_cmpb(target_ulong rs, target_ulong rb)
221{
222 target_ulong mask = 0xff;
223 target_ulong ra = 0;
224 int i;
225
226 for (i = 0; i < sizeof(target_ulong); i++) {
227 if ((rs & mask) == (rb & mask)) {
228 ra |= mask;
229 }
230 mask <<= 8;
231 }
232 return ra;
233}
234
64654ded 235/* shift right arithmetic helper */
d15f74fb
BS
236target_ulong helper_sraw(CPUPPCState *env, target_ulong value,
237 target_ulong shift)
64654ded
BS
238{
239 int32_t ret;
240
241 if (likely(!(shift & 0x20))) {
242 if (likely((uint32_t)shift != 0)) {
243 shift &= 0x1f;
244 ret = (int32_t)value >> shift;
245 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
af1c259f 246 env->ca32 = env->ca = 0;
64654ded 247 } else {
af1c259f 248 env->ca32 = env->ca = 1;
64654ded
BS
249 }
250 } else {
251 ret = (int32_t)value;
af1c259f 252 env->ca32 = env->ca = 0;
64654ded
BS
253 }
254 } else {
255 ret = (int32_t)value >> 31;
af1c259f 256 env->ca32 = env->ca = (ret != 0);
64654ded
BS
257 }
258 return (target_long)ret;
259}
260
261#if defined(TARGET_PPC64)
d15f74fb
BS
262target_ulong helper_srad(CPUPPCState *env, target_ulong value,
263 target_ulong shift)
64654ded
BS
264{
265 int64_t ret;
266
267 if (likely(!(shift & 0x40))) {
268 if (likely((uint64_t)shift != 0)) {
269 shift &= 0x3f;
270 ret = (int64_t)value >> shift;
4bc02e23 271 if (likely(ret >= 0 || (value & ((1ULL << shift) - 1)) == 0)) {
af1c259f 272 env->ca32 = env->ca = 0;
64654ded 273 } else {
af1c259f 274 env->ca32 = env->ca = 1;
64654ded
BS
275 }
276 } else {
277 ret = (int64_t)value;
af1c259f 278 env->ca32 = env->ca = 0;
64654ded
BS
279 }
280 } else {
281 ret = (int64_t)value >> 63;
af1c259f 282 env->ca32 = env->ca = (ret != 0);
64654ded
BS
283 }
284 return ret;
285}
286#endif
287
288#if defined(TARGET_PPC64)
289target_ulong helper_popcntb(target_ulong val)
290{
79770002 291 /* Note that we don't fold past bytes */
64654ded
BS
292 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
293 0x5555555555555555ULL);
294 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
295 0x3333333333333333ULL);
296 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
297 0x0f0f0f0f0f0f0f0fULL);
298 return val;
299}
300
301target_ulong helper_popcntw(target_ulong val)
302{
79770002 303 /* Note that we don't fold past words. */
64654ded
BS
304 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
305 0x5555555555555555ULL);
306 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
307 0x3333333333333333ULL);
308 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
309 0x0f0f0f0f0f0f0f0fULL);
310 val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) &
311 0x00ff00ff00ff00ffULL);
312 val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
313 0x0000ffff0000ffffULL);
314 return val;
315}
64654ded
BS
316#else
317target_ulong helper_popcntb(target_ulong val)
318{
79770002 319 /* Note that we don't fold past bytes */
64654ded
BS
320 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
321 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
322 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
323 return val;
324}
64654ded
BS
325#endif
326
6e0bbc40 327uint64_t helper_CFUGED(uint64_t src, uint64_t mask)
89ccd7dc
MF
328{
329 /*
330 * Instead of processing the mask bit-by-bit from the most significant to
331 * the least significant bit, as described in PowerISA, we'll handle it in
332 * blocks of 'n' zeros/ones from LSB to MSB. To avoid the decision to use
333 * ctz or cto, we negate the mask at the end of the loop.
334 */
335 target_ulong m, left = 0, right = 0;
336 unsigned int n, i = 64;
337 bool bit = false; /* tracks if we are processing zeros or ones */
338
339 if (mask == 0 || mask == -1) {
340 return src;
341 }
342
343 /* Processes the mask in blocks, from LSB to MSB */
344 while (i) {
345 /* Find how many bits we should take */
346 n = ctz64(mask);
347 if (n > i) {
348 n = i;
349 }
350
351 /*
352 * Extracts 'n' trailing bits of src and put them on the leading 'n'
353 * bits of 'right' or 'left', pushing down the previously extracted
354 * values.
355 */
356 m = (1ll << n) - 1;
357 if (bit) {
358 right = ror64(right | (src & m), n);
359 } else {
360 left = ror64(left | (src & m), n);
361 }
362
363 /*
364 * Discards the processed bits from 'src' and 'mask'. Note that we are
365 * removing 'n' trailing zeros from 'mask', but the logical shift will
366 * add 'n' leading zeros back, so the population count of 'mask' is kept
367 * the same.
368 */
369 src >>= n;
370 mask >>= n;
371 i -= n;
372 bit = !bit;
373 mask = ~mask;
374 }
375
376 /*
377 * At the end, right was ror'ed ctpop(mask) times. To put it back in place,
378 * we'll shift it more 64-ctpop(mask) times.
379 */
380 if (bit) {
381 n = ctpop64(mask);
382 } else {
383 n = 64 - ctpop64(mask);
384 }
385
386 return left | (right >> n);
387}
388
21ba6e58
MF
389uint64_t helper_PDEPD(uint64_t src, uint64_t mask)
390{
391 int i, o;
392 uint64_t result = 0;
393
394 if (mask == -1) {
395 return src;
396 }
397
398 for (i = 0; mask != 0; i++) {
399 o = ctz64(mask);
400 mask &= mask - 1;
401 result |= ((src >> i) & 1) << o;
402 }
403
404 return result;
405}
8bdb7606
MF
406
407uint64_t helper_PEXTD(uint64_t src, uint64_t mask)
408{
409 int i, o;
410 uint64_t result = 0;
411
412 if (mask == -1) {
413 return src;
414 }
415
416 for (o = 0; mask != 0; o++) {
417 i = ctz64(mask);
418 mask &= mask - 1;
419 result |= ((src >> i) & 1) << o;
420 }
421
422 return result;
423}
21ba6e58 424
64654ded
BS
425/*****************************************************************************/
426/* PowerPC 601 specific instructions (POWER bridge) */
d15f74fb 427target_ulong helper_div(CPUPPCState *env, target_ulong arg1, target_ulong arg2)
64654ded
BS
428{
429 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
430
431 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
432 (int32_t)arg2 == 0) {
433 env->spr[SPR_MQ] = 0;
434 return INT32_MIN;
435 } else {
436 env->spr[SPR_MQ] = tmp % arg2;
437 return tmp / (int32_t)arg2;
438 }
439}
440
d15f74fb
BS
441target_ulong helper_divo(CPUPPCState *env, target_ulong arg1,
442 target_ulong arg2)
64654ded
BS
443{
444 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
445
446 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
447 (int32_t)arg2 == 0) {
da91a00f 448 env->so = env->ov = 1;
64654ded
BS
449 env->spr[SPR_MQ] = 0;
450 return INT32_MIN;
451 } else {
452 env->spr[SPR_MQ] = tmp % arg2;
453 tmp /= (int32_t)arg2;
454 if ((int32_t)tmp != tmp) {
da91a00f 455 env->so = env->ov = 1;
64654ded 456 } else {
da91a00f 457 env->ov = 0;
64654ded
BS
458 }
459 return tmp;
460 }
461}
462
d15f74fb
BS
463target_ulong helper_divs(CPUPPCState *env, target_ulong arg1,
464 target_ulong arg2)
64654ded
BS
465{
466 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
467 (int32_t)arg2 == 0) {
468 env->spr[SPR_MQ] = 0;
469 return INT32_MIN;
470 } else {
471 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
472 return (int32_t)arg1 / (int32_t)arg2;
473 }
474}
475
d15f74fb
BS
476target_ulong helper_divso(CPUPPCState *env, target_ulong arg1,
477 target_ulong arg2)
64654ded
BS
478{
479 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
480 (int32_t)arg2 == 0) {
da91a00f 481 env->so = env->ov = 1;
64654ded
BS
482 env->spr[SPR_MQ] = 0;
483 return INT32_MIN;
484 } else {
da91a00f 485 env->ov = 0;
64654ded
BS
486 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
487 return (int32_t)arg1 / (int32_t)arg2;
488 }
489}
490
491/*****************************************************************************/
492/* 602 specific instructions */
493/* mfrom is the most crazy instruction ever seen, imho ! */
494/* Real implementation uses a ROM table. Do the same */
b6cb41b2
DG
495/*
496 * Extremely decomposed:
64654ded
BS
497 * -arg / 256
498 * return 256 * log10(10 + 1.0) + 0.5
499 */
500#if !defined(CONFIG_USER_ONLY)
501target_ulong helper_602_mfrom(target_ulong arg)
502{
503 if (likely(arg < 602)) {
139c1837 504#include "mfrom_table.c.inc"
64654ded
BS
505 return mfrom_ROM_table[arg];
506 } else {
507 return 0;
508 }
509}
510#endif
511
512/*****************************************************************************/
513/* Altivec extension helpers */
64654ded
BS
514#if defined(HOST_WORDS_BIGENDIAN)
515#define VECTOR_FOR_INORDER_I(index, element) \
516 for (index = 0; index < ARRAY_SIZE(r->element); index++)
517#else
518#define VECTOR_FOR_INORDER_I(index, element) \
b6cb41b2 519 for (index = ARRAY_SIZE(r->element) - 1; index >= 0; index--)
64654ded
BS
520#endif
521
64654ded
BS
522/* Saturating arithmetic helpers. */
523#define SATCVT(from, to, from_type, to_type, min, max) \
524 static inline to_type cvt##from##to(from_type x, int *sat) \
525 { \
526 to_type r; \
527 \
528 if (x < (from_type)min) { \
529 r = min; \
530 *sat = 1; \
531 } else if (x > (from_type)max) { \
532 r = max; \
533 *sat = 1; \
534 } else { \
535 r = x; \
536 } \
537 return r; \
538 }
539#define SATCVTU(from, to, from_type, to_type, min, max) \
540 static inline to_type cvt##from##to(from_type x, int *sat) \
541 { \
542 to_type r; \
543 \
544 if (x > (from_type)max) { \
545 r = max; \
546 *sat = 1; \
547 } else { \
548 r = x; \
549 } \
550 return r; \
551 }
552SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
553SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
554SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
555
556SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
557SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
558SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
559SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
560SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
561SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
562#undef SATCVT
563#undef SATCVTU
564
dedfaac7 565void helper_mtvscr(CPUPPCState *env, uint32_t vscr)
64654ded 566{
c19940db 567 ppc_store_vscr(env, vscr);
64654ded
BS
568}
569
cc2b90d7
RH
570uint32_t helper_mfvscr(CPUPPCState *env)
571{
c19940db 572 return ppc_get_vscr(env);
cc2b90d7
RH
573}
574
6175f5a0
RH
575static inline void set_vscr_sat(CPUPPCState *env)
576{
9b5b74da
RH
577 /* The choice of non-zero value is arbitrary. */
578 env->vscr_sat.u32[0] = 1;
6175f5a0
RH
579}
580
64654ded
BS
581void helper_vaddcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
582{
583 int i;
584
585 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
586 r->u32[i] = ~a->u32[i] < b->u32[i];
587 }
588}
589
5c69452c
AK
590/* vprtybw */
591void helper_vprtybw(ppc_avr_t *r, ppc_avr_t *b)
592{
593 int i;
594 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
595 uint64_t res = b->u32[i] ^ (b->u32[i] >> 16);
596 res ^= res >> 8;
597 r->u32[i] = res & 1;
598 }
599}
600
601/* vprtybd */
602void helper_vprtybd(ppc_avr_t *r, ppc_avr_t *b)
603{
604 int i;
605 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
606 uint64_t res = b->u64[i] ^ (b->u64[i] >> 32);
607 res ^= res >> 16;
608 res ^= res >> 8;
609 r->u64[i] = res & 1;
610 }
611}
612
613/* vprtybq */
614void helper_vprtybq(ppc_avr_t *r, ppc_avr_t *b)
615{
616 uint64_t res = b->u64[0] ^ b->u64[1];
617 res ^= res >> 32;
618 res ^= res >> 16;
619 res ^= res >> 8;
3c385a93
MCA
620 r->VsrD(1) = res & 1;
621 r->VsrD(0) = 0;
5c69452c
AK
622}
623
64654ded 624#define VARITHFP(suffix, func) \
d15f74fb
BS
625 void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
626 ppc_avr_t *b) \
64654ded
BS
627 { \
628 int i; \
629 \
05ee3e8a
MCA
630 for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \
631 r->f32[i] = func(a->f32[i], b->f32[i], &env->vec_status); \
64654ded
BS
632 } \
633 }
634VARITHFP(addfp, float32_add)
635VARITHFP(subfp, float32_sub)
db1babb8
AJ
636VARITHFP(minfp, float32_min)
637VARITHFP(maxfp, float32_max)
64654ded
BS
638#undef VARITHFP
639
2f93c23f
AJ
640#define VARITHFPFMA(suffix, type) \
641 void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
642 ppc_avr_t *b, ppc_avr_t *c) \
643 { \
644 int i; \
05ee3e8a
MCA
645 for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \
646 r->f32[i] = float32_muladd(a->f32[i], c->f32[i], b->f32[i], \
647 type, &env->vec_status); \
2f93c23f
AJ
648 } \
649 }
650VARITHFPFMA(maddfp, 0);
651VARITHFPFMA(nmsubfp, float_muladd_negate_result | float_muladd_negate_c);
652#undef VARITHFPFMA
653
64654ded
BS
654#define VARITHSAT_CASE(type, op, cvt, element) \
655 { \
656 type result = (type)a->element[i] op (type)b->element[i]; \
657 r->element[i] = cvt(result, &sat); \
658 }
659
660#define VARITHSAT_DO(name, op, optype, cvt, element) \
fb11ae7d
RH
661 void helper_v##name(ppc_avr_t *r, ppc_avr_t *vscr_sat, \
662 ppc_avr_t *a, ppc_avr_t *b, uint32_t desc) \
64654ded
BS
663 { \
664 int sat = 0; \
665 int i; \
666 \
667 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
fb11ae7d 668 VARITHSAT_CASE(optype, op, cvt, element); \
64654ded
BS
669 } \
670 if (sat) { \
fb11ae7d 671 vscr_sat->u32[0] = 1; \
64654ded
BS
672 } \
673 }
674#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
675 VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
676 VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
677#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
678 VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
679 VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
680VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
681VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
682VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
683VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
684VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
685VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
686#undef VARITHSAT_CASE
687#undef VARITHSAT_DO
688#undef VARITHSAT_SIGNED
689#undef VARITHSAT_UNSIGNED
690
691#define VAVG_DO(name, element, etype) \
692 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
693 { \
694 int i; \
695 \
696 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
697 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
698 r->element[i] = x >> 1; \
699 } \
700 }
701
702#define VAVG(type, signed_element, signed_type, unsigned_element, \
703 unsigned_type) \
704 VAVG_DO(avgs##type, signed_element, signed_type) \
705 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
706VAVG(b, s8, int16_t, u8, uint16_t)
707VAVG(h, s16, int32_t, u16, uint32_t)
708VAVG(w, s32, int64_t, u32, uint64_t)
709#undef VAVG_DO
710#undef VAVG
711
37707059
SD
712#define VABSDU_DO(name, element) \
713void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
714{ \
715 int i; \
716 \
717 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
718 r->element[i] = (a->element[i] > b->element[i]) ? \
719 (a->element[i] - b->element[i]) : \
720 (b->element[i] - a->element[i]); \
721 } \
722}
723
b6cb41b2
DG
724/*
725 * VABSDU - Vector absolute difference unsigned
37707059
SD
726 * name - instruction mnemonic suffix (b: byte, h: halfword, w: word)
727 * element - element type to access from vector
728 */
729#define VABSDU(type, element) \
730 VABSDU_DO(absdu##type, element)
731VABSDU(b, u8)
732VABSDU(h, u16)
733VABSDU(w, u32)
734#undef VABSDU_DO
735#undef VABSDU
736
64654ded 737#define VCF(suffix, cvt, element) \
d15f74fb
BS
738 void helper_vcf##suffix(CPUPPCState *env, ppc_avr_t *r, \
739 ppc_avr_t *b, uint32_t uim) \
64654ded
BS
740 { \
741 int i; \
742 \
05ee3e8a 743 for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \
64654ded 744 float32 t = cvt(b->element[i], &env->vec_status); \
05ee3e8a 745 r->f32[i] = float32_scalbn(t, -uim, &env->vec_status); \
64654ded
BS
746 } \
747 }
748VCF(ux, uint32_to_float32, u32)
749VCF(sx, int32_to_float32, s32)
750#undef VCF
751
752#define VCMP_DO(suffix, compare, element, record) \
d15f74fb
BS
753 void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
754 ppc_avr_t *a, ppc_avr_t *b) \
64654ded 755 { \
6f3dab41
TM
756 uint64_t ones = (uint64_t)-1; \
757 uint64_t all = ones; \
758 uint64_t none = 0; \
64654ded
BS
759 int i; \
760 \
761 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
6f3dab41 762 uint64_t result = (a->element[i] compare b->element[i] ? \
64654ded
BS
763 ones : 0x0); \
764 switch (sizeof(a->element[0])) { \
6f3dab41
TM
765 case 8: \
766 r->u64[i] = result; \
767 break; \
64654ded
BS
768 case 4: \
769 r->u32[i] = result; \
770 break; \
771 case 2: \
772 r->u16[i] = result; \
773 break; \
774 case 1: \
775 r->u8[i] = result; \
776 break; \
777 } \
778 all &= result; \
779 none |= result; \
780 } \
781 if (record) { \
782 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
783 } \
784 }
785#define VCMP(suffix, compare, element) \
786 VCMP_DO(suffix, compare, element, 0) \
787 VCMP_DO(suffix##_dot, compare, element, 1)
788VCMP(equb, ==, u8)
789VCMP(equh, ==, u16)
790VCMP(equw, ==, u32)
6f3dab41 791VCMP(equd, ==, u64)
64654ded
BS
792VCMP(gtub, >, u8)
793VCMP(gtuh, >, u16)
794VCMP(gtuw, >, u32)
6f3dab41 795VCMP(gtud, >, u64)
64654ded
BS
796VCMP(gtsb, >, s8)
797VCMP(gtsh, >, s16)
798VCMP(gtsw, >, s32)
6f3dab41 799VCMP(gtsd, >, s64)
64654ded
BS
800#undef VCMP_DO
801#undef VCMP
802
0fa59364
RS
803#define VCMPNE_DO(suffix, element, etype, cmpzero, record) \
804void helper_vcmpne##suffix(CPUPPCState *env, ppc_avr_t *r, \
f7cc8466
SB
805 ppc_avr_t *a, ppc_avr_t *b) \
806{ \
807 etype ones = (etype)-1; \
808 etype all = ones; \
0fa59364 809 etype result, none = 0; \
f7cc8466
SB
810 int i; \
811 \
812 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
0fa59364
RS
813 if (cmpzero) { \
814 result = ((a->element[i] == 0) \
f7cc8466
SB
815 || (b->element[i] == 0) \
816 || (a->element[i] != b->element[i]) ? \
817 ones : 0x0); \
0fa59364
RS
818 } else { \
819 result = (a->element[i] != b->element[i]) ? ones : 0x0; \
820 } \
f7cc8466
SB
821 r->element[i] = result; \
822 all &= result; \
823 none |= result; \
824 } \
825 if (record) { \
826 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
827 } \
828}
829
b6cb41b2
DG
830/*
831 * VCMPNEZ - Vector compare not equal to zero
f7cc8466
SB
832 * suffix - instruction mnemonic suffix (b: byte, h: halfword, w: word)
833 * element - element type to access from vector
834 */
0fa59364
RS
835#define VCMPNE(suffix, element, etype, cmpzero) \
836 VCMPNE_DO(suffix, element, etype, cmpzero, 0) \
837 VCMPNE_DO(suffix##_dot, element, etype, cmpzero, 1)
838VCMPNE(zb, u8, uint8_t, 1)
839VCMPNE(zh, u16, uint16_t, 1)
840VCMPNE(zw, u32, uint32_t, 1)
841VCMPNE(b, u8, uint8_t, 0)
842VCMPNE(h, u16, uint16_t, 0)
843VCMPNE(w, u32, uint32_t, 0)
844#undef VCMPNE_DO
845#undef VCMPNE
f7cc8466 846
64654ded 847#define VCMPFP_DO(suffix, compare, order, record) \
d15f74fb
BS
848 void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
849 ppc_avr_t *a, ppc_avr_t *b) \
64654ded
BS
850 { \
851 uint32_t ones = (uint32_t)-1; \
852 uint32_t all = ones; \
853 uint32_t none = 0; \
854 int i; \
855 \
05ee3e8a 856 for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \
64654ded 857 uint32_t result; \
71bfd65c
RH
858 FloatRelation rel = \
859 float32_compare_quiet(a->f32[i], b->f32[i], \
860 &env->vec_status); \
64654ded
BS
861 if (rel == float_relation_unordered) { \
862 result = 0; \
863 } else if (rel compare order) { \
864 result = ones; \
865 } else { \
866 result = 0; \
867 } \
868 r->u32[i] = result; \
869 all &= result; \
870 none |= result; \
871 } \
872 if (record) { \
873 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
874 } \
875 }
876#define VCMPFP(suffix, compare, order) \
877 VCMPFP_DO(suffix, compare, order, 0) \
878 VCMPFP_DO(suffix##_dot, compare, order, 1)
879VCMPFP(eqfp, ==, float_relation_equal)
880VCMPFP(gefp, !=, float_relation_less)
881VCMPFP(gtfp, ==, float_relation_greater)
882#undef VCMPFP_DO
883#undef VCMPFP
884
d15f74fb
BS
885static inline void vcmpbfp_internal(CPUPPCState *env, ppc_avr_t *r,
886 ppc_avr_t *a, ppc_avr_t *b, int record)
64654ded
BS
887{
888 int i;
889 int all_in = 0;
890
05ee3e8a 891 for (i = 0; i < ARRAY_SIZE(r->f32); i++) {
71bfd65c
RH
892 FloatRelation le_rel = float32_compare_quiet(a->f32[i], b->f32[i],
893 &env->vec_status);
64654ded
BS
894 if (le_rel == float_relation_unordered) {
895 r->u32[i] = 0xc0000000;
4007b8de 896 all_in = 1;
64654ded 897 } else {
05ee3e8a 898 float32 bneg = float32_chs(b->f32[i]);
71bfd65c
RH
899 FloatRelation ge_rel = float32_compare_quiet(a->f32[i], bneg,
900 &env->vec_status);
64654ded
BS
901 int le = le_rel != float_relation_greater;
902 int ge = ge_rel != float_relation_less;
903
904 r->u32[i] = ((!le) << 31) | ((!ge) << 30);
905 all_in |= (!le | !ge);
906 }
907 }
908 if (record) {
909 env->crf[6] = (all_in == 0) << 1;
910 }
911}
912
d15f74fb 913void helper_vcmpbfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded 914{
d15f74fb 915 vcmpbfp_internal(env, r, a, b, 0);
64654ded
BS
916}
917
d15f74fb
BS
918void helper_vcmpbfp_dot(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
919 ppc_avr_t *b)
64654ded 920{
d15f74fb 921 vcmpbfp_internal(env, r, a, b, 1);
64654ded
BS
922}
923
924#define VCT(suffix, satcvt, element) \
d15f74fb
BS
925 void helper_vct##suffix(CPUPPCState *env, ppc_avr_t *r, \
926 ppc_avr_t *b, uint32_t uim) \
64654ded
BS
927 { \
928 int i; \
929 int sat = 0; \
930 float_status s = env->vec_status; \
931 \
932 set_float_rounding_mode(float_round_to_zero, &s); \
05ee3e8a
MCA
933 for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \
934 if (float32_is_any_nan(b->f32[i])) { \
64654ded
BS
935 r->element[i] = 0; \
936 } else { \
05ee3e8a 937 float64 t = float32_to_float64(b->f32[i], &s); \
64654ded
BS
938 int64_t j; \
939 \
940 t = float64_scalbn(t, uim, &s); \
941 j = float64_to_int64(t, &s); \
942 r->element[i] = satcvt(j, &sat); \
943 } \
944 } \
945 if (sat) { \
6175f5a0 946 set_vscr_sat(env); \
64654ded
BS
947 } \
948 }
949VCT(uxs, cvtsduw, u32)
950VCT(sxs, cvtsdsw, s32)
951#undef VCT
952
4879538c
RS
953target_ulong helper_vclzlsbb(ppc_avr_t *r)
954{
955 target_ulong count = 0;
956 int i;
60594fea
MCA
957 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
958 if (r->VsrB(i) & 0x01) {
4879538c
RS
959 break;
960 }
961 count++;
962 }
963 return count;
964}
965
966target_ulong helper_vctzlsbb(ppc_avr_t *r)
967{
968 target_ulong count = 0;
969 int i;
4879538c 970 for (i = ARRAY_SIZE(r->u8) - 1; i >= 0; i--) {
60594fea 971 if (r->VsrB(i) & 0x01) {
4879538c
RS
972 break;
973 }
974 count++;
975 }
976 return count;
977}
978
d15f74fb
BS
979void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
980 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
981{
982 int sat = 0;
983 int i;
984
985 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
986 int32_t prod = a->s16[i] * b->s16[i];
987 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
988
989 r->s16[i] = cvtswsh(t, &sat);
990 }
991
992 if (sat) {
6175f5a0 993 set_vscr_sat(env);
64654ded
BS
994 }
995}
996
d15f74fb
BS
997void helper_vmhraddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
998 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
999{
1000 int sat = 0;
1001 int i;
1002
1003 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
1004 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
1005 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
1006 r->s16[i] = cvtswsh(t, &sat);
1007 }
1008
1009 if (sat) {
6175f5a0 1010 set_vscr_sat(env);
64654ded
BS
1011 }
1012}
1013
64654ded
BS
1014void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
1015{
1016 int i;
1017
1018 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
1019 int32_t prod = a->s16[i] * b->s16[i];
1020 r->s16[i] = (int16_t) (prod + c->s16[i]);
1021 }
1022}
1023
d81c2040
MCA
1024#define VMRG_DO(name, element, access, ofs) \
1025 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1026 { \
1027 ppc_avr_t result; \
1028 int i, half = ARRAY_SIZE(r->element) / 2; \
1029 \
1030 for (i = 0; i < half; i++) { \
1031 result.access(i * 2 + 0) = a->access(i + ofs); \
1032 result.access(i * 2 + 1) = b->access(i + ofs); \
1033 } \
1034 *r = result; \
1035 }
1036
1037#define VMRG(suffix, element, access) \
1038 VMRG_DO(mrgl##suffix, element, access, half) \
1039 VMRG_DO(mrgh##suffix, element, access, 0)
1040VMRG(b, u8, VsrB)
1041VMRG(h, u16, VsrH)
1042VMRG(w, u32, VsrW)
64654ded
BS
1043#undef VMRG_DO
1044#undef VMRG
64654ded 1045
d15f74fb
BS
1046void helper_vmsummbm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
1047 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
1048{
1049 int32_t prod[16];
1050 int i;
1051
1052 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
1053 prod[i] = (int32_t)a->s8[i] * b->u8[i];
1054 }
1055
1056 VECTOR_FOR_INORDER_I(i, s32) {
1057 r->s32[i] = c->s32[i] + prod[4 * i] + prod[4 * i + 1] +
1058 prod[4 * i + 2] + prod[4 * i + 3];
1059 }
1060}
1061
d15f74fb
BS
1062void helper_vmsumshm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
1063 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
1064{
1065 int32_t prod[8];
1066 int i;
1067
1068 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
1069 prod[i] = a->s16[i] * b->s16[i];
1070 }
1071
1072 VECTOR_FOR_INORDER_I(i, s32) {
1073 r->s32[i] = c->s32[i] + prod[2 * i] + prod[2 * i + 1];
1074 }
1075}
1076
d15f74fb
BS
1077void helper_vmsumshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
1078 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
1079{
1080 int32_t prod[8];
1081 int i;
1082 int sat = 0;
1083
1084 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
1085 prod[i] = (int32_t)a->s16[i] * b->s16[i];
1086 }
1087
1088 VECTOR_FOR_INORDER_I(i, s32) {
1089 int64_t t = (int64_t)c->s32[i] + prod[2 * i] + prod[2 * i + 1];
1090
1091 r->u32[i] = cvtsdsw(t, &sat);
1092 }
1093
1094 if (sat) {
6175f5a0 1095 set_vscr_sat(env);
64654ded
BS
1096 }
1097}
1098
d15f74fb
BS
1099void helper_vmsumubm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
1100 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
1101{
1102 uint16_t prod[16];
1103 int i;
1104
1105 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
1106 prod[i] = a->u8[i] * b->u8[i];
1107 }
1108
1109 VECTOR_FOR_INORDER_I(i, u32) {
1110 r->u32[i] = c->u32[i] + prod[4 * i] + prod[4 * i + 1] +
1111 prod[4 * i + 2] + prod[4 * i + 3];
1112 }
1113}
1114
d15f74fb
BS
1115void helper_vmsumuhm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
1116 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
1117{
1118 uint32_t prod[8];
1119 int i;
1120
1121 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
1122 prod[i] = a->u16[i] * b->u16[i];
1123 }
1124
1125 VECTOR_FOR_INORDER_I(i, u32) {
1126 r->u32[i] = c->u32[i] + prod[2 * i] + prod[2 * i + 1];
1127 }
1128}
1129
d15f74fb
BS
1130void helper_vmsumuhs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
1131 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
1132{
1133 uint32_t prod[8];
1134 int i;
1135 int sat = 0;
1136
1137 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
1138 prod[i] = a->u16[i] * b->u16[i];
1139 }
1140
1141 VECTOR_FOR_INORDER_I(i, s32) {
1142 uint64_t t = (uint64_t)c->u32[i] + prod[2 * i] + prod[2 * i + 1];
1143
1144 r->u32[i] = cvtuduw(t, &sat);
1145 }
1146
1147 if (sat) {
6175f5a0 1148 set_vscr_sat(env);
64654ded
BS
1149 }
1150}
1151
4fbc89ed 1152#define VMUL_DO_EVN(name, mul_element, mul_access, prod_access, cast) \
64654ded
BS
1153 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1154 { \
1155 int i; \
1156 \
4fbc89ed
MCA
1157 for (i = 0; i < ARRAY_SIZE(r->mul_element); i += 2) { \
1158 r->prod_access(i >> 1) = (cast)a->mul_access(i) * \
1159 (cast)b->mul_access(i); \
1160 } \
1161 }
1162
1163#define VMUL_DO_ODD(name, mul_element, mul_access, prod_access, cast) \
1164 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1165 { \
1166 int i; \
1167 \
1168 for (i = 0; i < ARRAY_SIZE(r->mul_element); i += 2) { \
1169 r->prod_access(i >> 1) = (cast)a->mul_access(i + 1) * \
1170 (cast)b->mul_access(i + 1); \
64654ded
BS
1171 } \
1172 }
4fbc89ed
MCA
1173
1174#define VMUL(suffix, mul_element, mul_access, prod_access, cast) \
1175 VMUL_DO_EVN(mule##suffix, mul_element, mul_access, prod_access, cast) \
1176 VMUL_DO_ODD(mulo##suffix, mul_element, mul_access, prod_access, cast)
1177VMUL(sb, s8, VsrSB, VsrSH, int16_t)
1178VMUL(sh, s16, VsrSH, VsrSW, int32_t)
1179VMUL(sw, s32, VsrSW, VsrSD, int64_t)
1180VMUL(ub, u8, VsrB, VsrH, uint16_t)
1181VMUL(uh, u16, VsrH, VsrW, uint32_t)
1182VMUL(uw, u32, VsrW, VsrD, uint64_t)
1183#undef VMUL_DO_EVN
1184#undef VMUL_DO_ODD
64654ded
BS
1185#undef VMUL
1186
f3e0d864
LP
1187void helper_vmulhsw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1188{
1189 int i;
1190
1191 for (i = 0; i < 4; i++) {
1192 r->s32[i] = (int32_t)(((int64_t)a->s32[i] * (int64_t)b->s32[i]) >> 32);
1193 }
1194}
1195
1196void helper_vmulhuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1197{
1198 int i;
1199
1200 for (i = 0; i < 4; i++) {
1201 r->u32[i] = (uint32_t)(((uint64_t)a->u32[i] *
1202 (uint64_t)b->u32[i]) >> 32);
1203 }
1204}
1205
c4b8b49d
LP
1206void helper_vmulhsd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1207{
1208 uint64_t discard;
1209
1210 muls64(&discard, &r->u64[0], a->s64[0], b->s64[0]);
1211 muls64(&discard, &r->u64[1], a->s64[1], b->s64[1]);
1212}
1213
1214void helper_vmulhud(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1215{
1216 uint64_t discard;
1217
1218 mulu64(&discard, &r->u64[0], a->u64[0], b->u64[0]);
1219 mulu64(&discard, &r->u64[1], a->u64[1], b->u64[1]);
1220}
1221
d15f74fb
BS
1222void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
1223 ppc_avr_t *c)
64654ded
BS
1224{
1225 ppc_avr_t result;
1226 int i;
1227
60594fea
MCA
1228 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
1229 int s = c->VsrB(i) & 0x1f;
64654ded 1230 int index = s & 0xf;
64654ded
BS
1231
1232 if (s & 0x10) {
60594fea 1233 result.VsrB(i) = b->VsrB(index);
64654ded 1234 } else {
60594fea 1235 result.VsrB(i) = a->VsrB(index);
64654ded
BS
1236 }
1237 }
1238 *r = result;
1239}
1240
ab045436
RS
1241void helper_vpermr(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
1242 ppc_avr_t *c)
1243{
1244 ppc_avr_t result;
1245 int i;
1246
60594fea
MCA
1247 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
1248 int s = c->VsrB(i) & 0x1f;
ab045436 1249 int index = 15 - (s & 0xf);
ab045436
RS
1250
1251 if (s & 0x10) {
60594fea 1252 result.VsrB(i) = a->VsrB(index);
ab045436 1253 } else {
60594fea 1254 result.VsrB(i) = b->VsrB(index);
ab045436
RS
1255 }
1256 }
1257 *r = result;
1258}
1259
4d82038e
TM
1260#if defined(HOST_WORDS_BIGENDIAN)
1261#define VBPERMQ_INDEX(avr, i) ((avr)->u8[(i)])
01fe9a47 1262#define VBPERMD_INDEX(i) (i)
4d82038e 1263#define VBPERMQ_DW(index) (((index) & 0x40) != 0)
01fe9a47 1264#define EXTRACT_BIT(avr, i, index) (extract64((avr)->u64[i], index, 1))
4d82038e 1265#else
b6cb41b2 1266#define VBPERMQ_INDEX(avr, i) ((avr)->u8[15 - (i)])
01fe9a47 1267#define VBPERMD_INDEX(i) (1 - i)
4d82038e 1268#define VBPERMQ_DW(index) (((index) & 0x40) == 0)
01fe9a47
RS
1269#define EXTRACT_BIT(avr, i, index) \
1270 (extract64((avr)->u64[1 - i], 63 - index, 1))
4d82038e
TM
1271#endif
1272
01fe9a47
RS
1273void helper_vbpermd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1274{
1275 int i, j;
1276 ppc_avr_t result = { .u64 = { 0, 0 } };
1277 VECTOR_FOR_INORDER_I(i, u64) {
1278 for (j = 0; j < 8; j++) {
1279 int index = VBPERMQ_INDEX(b, (i * 8) + j);
1280 if (index < 64 && EXTRACT_BIT(a, i, index)) {
1281 result.u64[VBPERMD_INDEX(i)] |= (0x80 >> j);
1282 }
1283 }
1284 }
1285 *r = result;
1286}
1287
4d82038e
TM
1288void helper_vbpermq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1289{
1290 int i;
1291 uint64_t perm = 0;
1292
1293 VECTOR_FOR_INORDER_I(i, u8) {
1294 int index = VBPERMQ_INDEX(b, i);
1295
1296 if (index < 128) {
b6cb41b2 1297 uint64_t mask = (1ull << (63 - (index & 0x3F)));
4d82038e
TM
1298 if (a->u64[VBPERMQ_DW(index)] & mask) {
1299 perm |= (0x8000 >> i);
1300 }
1301 }
1302 }
1303
3c385a93
MCA
1304 r->VsrD(0) = perm;
1305 r->VsrD(1) = 0;
4d82038e
TM
1306}
1307
1308#undef VBPERMQ_INDEX
1309#undef VBPERMQ_DW
1310
b8476fc7
TM
1311#define PMSUM(name, srcfld, trgfld, trgtyp) \
1312void helper_##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1313{ \
1314 int i, j; \
b6cb41b2 1315 trgtyp prod[sizeof(ppc_avr_t) / sizeof(a->srcfld[0])]; \
b8476fc7
TM
1316 \
1317 VECTOR_FOR_INORDER_I(i, srcfld) { \
1318 prod[i] = 0; \
1319 for (j = 0; j < sizeof(a->srcfld[0]) * 8; j++) { \
b6cb41b2 1320 if (a->srcfld[i] & (1ull << j)) { \
b8476fc7
TM
1321 prod[i] ^= ((trgtyp)b->srcfld[i] << j); \
1322 } \
1323 } \
1324 } \
1325 \
1326 VECTOR_FOR_INORDER_I(i, trgfld) { \
b6cb41b2 1327 r->trgfld[i] = prod[2 * i] ^ prod[2 * i + 1]; \
b8476fc7
TM
1328 } \
1329}
1330
1331PMSUM(vpmsumb, u8, u16, uint16_t)
1332PMSUM(vpmsumh, u16, u32, uint32_t)
1333PMSUM(vpmsumw, u32, u64, uint64_t)
1334
1335void helper_vpmsumd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1336{
1337
1338#ifdef CONFIG_INT128
1339 int i, j;
1340 __uint128_t prod[2];
1341
1342 VECTOR_FOR_INORDER_I(i, u64) {
1343 prod[i] = 0;
1344 for (j = 0; j < 64; j++) {
b6cb41b2 1345 if (a->u64[i] & (1ull << j)) {
b8476fc7
TM
1346 prod[i] ^= (((__uint128_t)b->u64[i]) << j);
1347 }
1348 }
1349 }
1350
1351 r->u128 = prod[0] ^ prod[1];
1352
1353#else
1354 int i, j;
1355 ppc_avr_t prod[2];
1356
1357 VECTOR_FOR_INORDER_I(i, u64) {
3c385a93 1358 prod[i].VsrD(1) = prod[i].VsrD(0) = 0;
b8476fc7 1359 for (j = 0; j < 64; j++) {
b6cb41b2 1360 if (a->u64[i] & (1ull << j)) {
b8476fc7
TM
1361 ppc_avr_t bshift;
1362 if (j == 0) {
3c385a93
MCA
1363 bshift.VsrD(0) = 0;
1364 bshift.VsrD(1) = b->u64[i];
b8476fc7 1365 } else {
3c385a93
MCA
1366 bshift.VsrD(0) = b->u64[i] >> (64 - j);
1367 bshift.VsrD(1) = b->u64[i] << j;
b8476fc7 1368 }
3c385a93
MCA
1369 prod[i].VsrD(1) ^= bshift.VsrD(1);
1370 prod[i].VsrD(0) ^= bshift.VsrD(0);
b8476fc7
TM
1371 }
1372 }
1373 }
1374
3c385a93
MCA
1375 r->VsrD(1) = prod[0].VsrD(1) ^ prod[1].VsrD(1);
1376 r->VsrD(0) = prod[0].VsrD(0) ^ prod[1].VsrD(0);
b8476fc7
TM
1377#endif
1378}
1379
1380
64654ded
BS
1381#if defined(HOST_WORDS_BIGENDIAN)
1382#define PKBIG 1
1383#else
1384#define PKBIG 0
1385#endif
1386void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1387{
1388 int i, j;
1389 ppc_avr_t result;
1390#if defined(HOST_WORDS_BIGENDIAN)
1391 const ppc_avr_t *x[2] = { a, b };
1392#else
1393 const ppc_avr_t *x[2] = { b, a };
1394#endif
1395
1396 VECTOR_FOR_INORDER_I(i, u64) {
1397 VECTOR_FOR_INORDER_I(j, u32) {
1398 uint32_t e = x[i]->u32[j];
1399
b6cb41b2
DG
1400 result.u16[4 * i + j] = (((e >> 9) & 0xfc00) |
1401 ((e >> 6) & 0x3e0) |
1402 ((e >> 3) & 0x1f));
64654ded
BS
1403 }
1404 }
1405 *r = result;
1406}
1407
1408#define VPK(suffix, from, to, cvt, dosat) \
d15f74fb
BS
1409 void helper_vpk##suffix(CPUPPCState *env, ppc_avr_t *r, \
1410 ppc_avr_t *a, ppc_avr_t *b) \
64654ded
BS
1411 { \
1412 int i; \
1413 int sat = 0; \
1414 ppc_avr_t result; \
1415 ppc_avr_t *a0 = PKBIG ? a : b; \
1416 ppc_avr_t *a1 = PKBIG ? b : a; \
1417 \
1418 VECTOR_FOR_INORDER_I(i, from) { \
1419 result.to[i] = cvt(a0->from[i], &sat); \
b6cb41b2 1420 result.to[i + ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat);\
64654ded
BS
1421 } \
1422 *r = result; \
1423 if (dosat && sat) { \
6175f5a0 1424 set_vscr_sat(env); \
64654ded
BS
1425 } \
1426 }
1427#define I(x, y) (x)
1428VPK(shss, s16, s8, cvtshsb, 1)
1429VPK(shus, s16, u8, cvtshub, 1)
1430VPK(swss, s32, s16, cvtswsh, 1)
1431VPK(swus, s32, u16, cvtswuh, 1)
024215b2
TM
1432VPK(sdss, s64, s32, cvtsdsw, 1)
1433VPK(sdus, s64, u32, cvtsduw, 1)
64654ded
BS
1434VPK(uhus, u16, u8, cvtuhub, 1)
1435VPK(uwus, u32, u16, cvtuwuh, 1)
024215b2 1436VPK(udus, u64, u32, cvtuduw, 1)
64654ded
BS
1437VPK(uhum, u16, u8, I, 0)
1438VPK(uwum, u32, u16, I, 0)
024215b2 1439VPK(udum, u64, u32, I, 0)
64654ded
BS
1440#undef I
1441#undef VPK
1442#undef PKBIG
1443
d15f74fb 1444void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1445{
1446 int i;
1447
05ee3e8a
MCA
1448 for (i = 0; i < ARRAY_SIZE(r->f32); i++) {
1449 r->f32[i] = float32_div(float32_one, b->f32[i], &env->vec_status);
64654ded
BS
1450 }
1451}
1452
1453#define VRFI(suffix, rounding) \
d15f74fb
BS
1454 void helper_vrfi##suffix(CPUPPCState *env, ppc_avr_t *r, \
1455 ppc_avr_t *b) \
64654ded
BS
1456 { \
1457 int i; \
1458 float_status s = env->vec_status; \
1459 \
1460 set_float_rounding_mode(rounding, &s); \
05ee3e8a
MCA
1461 for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \
1462 r->f32[i] = float32_round_to_int (b->f32[i], &s); \
64654ded
BS
1463 } \
1464 }
1465VRFI(n, float_round_nearest_even)
1466VRFI(m, float_round_down)
1467VRFI(p, float_round_up)
1468VRFI(z, float_round_to_zero)
1469#undef VRFI
1470
d15f74fb 1471void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1472{
1473 int i;
1474
05ee3e8a
MCA
1475 for (i = 0; i < ARRAY_SIZE(r->f32); i++) {
1476 float32 t = float32_sqrt(b->f32[i], &env->vec_status);
64654ded 1477
05ee3e8a 1478 r->f32[i] = float32_div(float32_one, t, &env->vec_status);
64654ded
BS
1479 }
1480}
1481
09a245e1 1482#define VRLMI(name, size, element, insert) \
3e00884f
GS
1483void helper_##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1484{ \
1485 int i; \
1486 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1487 uint##size##_t src1 = a->element[i]; \
1488 uint##size##_t src2 = b->element[i]; \
1489 uint##size##_t src3 = r->element[i]; \
1490 uint##size##_t begin, end, shift, mask, rot_val; \
1491 \
1492 shift = extract##size(src2, 0, 6); \
1493 end = extract##size(src2, 8, 6); \
1494 begin = extract##size(src2, 16, 6); \
1495 rot_val = rol##size(src1, shift); \
1496 mask = mask_u##size(begin, end); \
09a245e1
BR
1497 if (insert) { \
1498 r->element[i] = (rot_val & mask) | (src3 & ~mask); \
1499 } else { \
1500 r->element[i] = (rot_val & mask); \
1501 } \
3e00884f
GS
1502 } \
1503}
1504
09a245e1
BR
1505VRLMI(vrldmi, 64, u64, 1);
1506VRLMI(vrlwmi, 32, u32, 1);
1507VRLMI(vrldnm, 64, u64, 0);
1508VRLMI(vrlwnm, 32, u32, 0);
3e00884f 1509
d15f74fb
BS
1510void helper_vsel(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
1511 ppc_avr_t *c)
64654ded
BS
1512{
1513 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
1514 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
1515}
1516
d15f74fb 1517void helper_vexptefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1518{
1519 int i;
1520
05ee3e8a
MCA
1521 for (i = 0; i < ARRAY_SIZE(r->f32); i++) {
1522 r->f32[i] = float32_exp2(b->f32[i], &env->vec_status);
64654ded
BS
1523 }
1524}
1525
d15f74fb 1526void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1527{
1528 int i;
1529
05ee3e8a
MCA
1530 for (i = 0; i < ARRAY_SIZE(r->f32); i++) {
1531 r->f32[i] = float32_log2(b->f32[i], &env->vec_status);
64654ded
BS
1532 }
1533}
1534
f297c4c6
MF
1535#define VEXTU_X_DO(name, size, left) \
1536target_ulong glue(helper_, name)(target_ulong a, ppc_avr_t *b) \
1537{ \
1538 int index = (a & 0xf) * 8; \
1539 if (left) { \
1540 index = 128 - index - size; \
1541 } \
1542 return int128_getlo(int128_rshift(b->s128, index)) & \
1543 MAKE_64BIT_MASK(0, size); \
1544}
60caf221
AK
1545VEXTU_X_DO(vextublx, 8, 1)
1546VEXTU_X_DO(vextuhlx, 16, 1)
1547VEXTU_X_DO(vextuwlx, 32, 1)
1548VEXTU_X_DO(vextubrx, 8, 0)
1549VEXTU_X_DO(vextuhrx, 16, 0)
1550VEXTU_X_DO(vextuwrx, 32, 0)
1551#undef VEXTU_X_DO
1552
5644a175
VAS
1553void helper_vslv(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1554{
1555 int i;
1556 unsigned int shift, bytes, size;
1557
1558 size = ARRAY_SIZE(r->u8);
1559 for (i = 0; i < size; i++) {
63be02fc
AB
1560 shift = b->VsrB(i) & 0x7; /* extract shift value */
1561 bytes = (a->VsrB(i) << 8) + /* extract adjacent bytes */
1562 (((i + 1) < size) ? a->VsrB(i + 1) : 0);
1563 r->VsrB(i) = (bytes << shift) >> 8; /* shift and store result */
5644a175
VAS
1564 }
1565}
1566
4004c1db
VAS
1567void helper_vsrv(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1568{
1569 int i;
1570 unsigned int shift, bytes;
1571
b6cb41b2
DG
1572 /*
1573 * Use reverse order, as destination and source register can be
1574 * same. Its being modified in place saving temporary, reverse
1575 * order will guarantee that computed result is not fed back.
4004c1db
VAS
1576 */
1577 for (i = ARRAY_SIZE(r->u8) - 1; i >= 0; i--) {
63be02fc
AB
1578 shift = b->VsrB(i) & 0x7; /* extract shift value */
1579 bytes = ((i ? a->VsrB(i - 1) : 0) << 8) + a->VsrB(i);
4004c1db 1580 /* extract adjacent bytes */
63be02fc 1581 r->VsrB(i) = (bytes >> shift) & 0xFF; /* shift and store result */
4004c1db
VAS
1582 }
1583}
1584
64654ded
BS
1585void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
1586{
1587 int sh = shift & 0xf;
1588 int i;
1589 ppc_avr_t result;
1590
64654ded
BS
1591 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
1592 int index = sh + i;
1593 if (index > 0xf) {
60594fea 1594 result.VsrB(i) = b->VsrB(index - 0x10);
64654ded 1595 } else {
60594fea 1596 result.VsrB(i) = a->VsrB(index);
64654ded
BS
1597 }
1598 }
64654ded
BS
1599 *r = result;
1600}
1601
1602void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1603{
3c385a93 1604 int sh = (b->VsrB(0xf) >> 3) & 0xf;
64654ded
BS
1605
1606#if defined(HOST_WORDS_BIGENDIAN)
1607 memmove(&r->u8[0], &a->u8[sh], 16 - sh);
b6cb41b2 1608 memset(&r->u8[16 - sh], 0, sh);
64654ded
BS
1609#else
1610 memmove(&r->u8[sh], &a->u8[0], 16 - sh);
1611 memset(&r->u8[0], 0, sh);
1612#endif
1613}
1614
2cc12af3
MF
1615#if defined(HOST_WORDS_BIGENDIAN)
1616#define ELEM_ADDR(VEC, IDX, SIZE) (&(VEC)->u8[IDX])
1617#else
1618#define ELEM_ADDR(VEC, IDX, SIZE) (&(VEC)->u8[15 - (IDX)] - (SIZE) + 1)
1619#endif
1620
1621#define VINSX(SUFFIX, TYPE) \
1622void glue(glue(helper_VINS, SUFFIX), LX)(CPUPPCState *env, ppc_avr_t *t, \
1623 uint64_t val, target_ulong index) \
1624{ \
1625 const int maxidx = ARRAY_SIZE(t->u8) - sizeof(TYPE); \
1626 target_long idx = index; \
1627 \
1628 if (idx < 0 || idx > maxidx) { \
1629 idx = idx < 0 ? sizeof(TYPE) - idx : idx; \
1630 qemu_log_mask(LOG_GUEST_ERROR, \
1631 "Invalid index for Vector Insert Element after 0x" TARGET_FMT_lx \
1632 ", RA = " TARGET_FMT_ld " > %d\n", env->nip, idx, maxidx); \
1633 } else { \
1634 TYPE src = val; \
1635 memcpy(ELEM_ADDR(t, idx, sizeof(TYPE)), &src, sizeof(TYPE)); \
1636 } \
1637}
1638VINSX(B, uint8_t)
1639VINSX(H, uint16_t)
1640VINSX(W, uint32_t)
1641VINSX(D, uint64_t)
1642#undef ELEM_ADDR
1643#undef VINSX
b5d569a1
RS
1644#if defined(HOST_WORDS_BIGENDIAN)
1645#define VEXTRACT(suffix, element) \
1646 void helper_vextract##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t index) \
1647 { \
1648 uint32_t es = sizeof(r->element[0]); \
1649 memmove(&r->u8[8 - es], &b->u8[index], es); \
1650 memset(&r->u8[8], 0, 8); \
1651 memset(&r->u8[0], 0, 8 - es); \
1652 }
1653#else
1654#define VEXTRACT(suffix, element) \
1655 void helper_vextract##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t index) \
1656 { \
1657 uint32_t es = sizeof(r->element[0]); \
1658 uint32_t s = (16 - index) - es; \
1659 memmove(&r->u8[8], &b->u8[s], es); \
1660 memset(&r->u8[0], 0, 8); \
1661 memset(&r->u8[8 + es], 0, 8 - es); \
1662 }
1663#endif
1664VEXTRACT(ub, u8)
1665VEXTRACT(uh, u16)
1666VEXTRACT(uw, u32)
1667VEXTRACT(d, u64)
1668#undef VEXTRACT
64654ded 1669
5ba5335d
MCA
1670void helper_xxextractuw(CPUPPCState *env, ppc_vsr_t *xt,
1671 ppc_vsr_t *xb, uint32_t index)
8ad901e5 1672{
03b32c09 1673 ppc_vsr_t t = { };
8ad901e5
ND
1674 size_t es = sizeof(uint32_t);
1675 uint32_t ext_index;
1676 int i;
1677
8ad901e5
ND
1678 ext_index = index;
1679 for (i = 0; i < es; i++, ext_index++) {
03b32c09 1680 t.VsrB(8 - es + i) = xb->VsrB(ext_index % 16);
8ad901e5 1681 }
8ad901e5 1682
03b32c09 1683 *xt = t;
8ad901e5
ND
1684}
1685
5ba5335d
MCA
1686void helper_xxinsertw(CPUPPCState *env, ppc_vsr_t *xt,
1687 ppc_vsr_t *xb, uint32_t index)
3398b742 1688{
03b32c09 1689 ppc_vsr_t t = *xt;
3398b742
ND
1690 size_t es = sizeof(uint32_t);
1691 int ins_index, i = 0;
1692
3398b742
ND
1693 ins_index = index;
1694 for (i = 0; i < es && ins_index < 16; i++, ins_index++) {
03b32c09 1695 t.VsrB(ins_index) = xb->VsrB(8 - es + i);
3398b742 1696 }
3398b742 1697
03b32c09 1698 *xt = t;
3398b742
ND
1699}
1700
634c5835 1701#define VEXT_SIGNED(name, element, cast) \
125a9b23
ND
1702void helper_##name(ppc_avr_t *r, ppc_avr_t *b) \
1703{ \
1704 int i; \
60594fea 1705 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
634c5835 1706 r->element[i] = (cast)b->element[i]; \
125a9b23
ND
1707 } \
1708}
634c5835
MCA
1709VEXT_SIGNED(vextsb2w, s32, int8_t)
1710VEXT_SIGNED(vextsb2d, s64, int8_t)
1711VEXT_SIGNED(vextsh2w, s32, int16_t)
1712VEXT_SIGNED(vextsh2d, s64, int16_t)
1713VEXT_SIGNED(vextsw2d, s64, int32_t)
125a9b23
ND
1714#undef VEXT_SIGNED
1715
cc8b6e76
ND
1716#define VNEG(name, element) \
1717void helper_##name(ppc_avr_t *r, ppc_avr_t *b) \
1718{ \
1719 int i; \
60594fea 1720 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
cc8b6e76
ND
1721 r->element[i] = -b->element[i]; \
1722 } \
1723}
1724VNEG(vnegw, s32)
1725VNEG(vnegd, s64)
1726#undef VNEG
1727
64654ded
BS
1728void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1729{
3c385a93 1730 int sh = (b->VsrB(0xf) >> 3) & 0xf;
64654ded
BS
1731
1732#if defined(HOST_WORDS_BIGENDIAN)
1733 memmove(&r->u8[sh], &a->u8[0], 16 - sh);
1734 memset(&r->u8[0], 0, sh);
1735#else
1736 memmove(&r->u8[0], &a->u8[sh], 16 - sh);
1737 memset(&r->u8[16 - sh], 0, sh);
1738#endif
1739}
1740
1741void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1742{
1743 int i;
1744
1745 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
1746 r->u32[i] = a->u32[i] >= b->u32[i];
1747 }
1748}
1749
d15f74fb 1750void helper_vsumsws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1751{
1752 int64_t t;
1753 int i, upper;
1754 ppc_avr_t result;
1755 int sat = 0;
1756
60594fea
MCA
1757 upper = ARRAY_SIZE(r->s32) - 1;
1758 t = (int64_t)b->VsrSW(upper);
64654ded 1759 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
60594fea
MCA
1760 t += a->VsrSW(i);
1761 result.VsrSW(i) = 0;
64654ded 1762 }
60594fea 1763 result.VsrSW(upper) = cvtsdsw(t, &sat);
64654ded
BS
1764 *r = result;
1765
1766 if (sat) {
6175f5a0 1767 set_vscr_sat(env);
64654ded
BS
1768 }
1769}
1770
d15f74fb 1771void helper_vsum2sws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1772{
1773 int i, j, upper;
1774 ppc_avr_t result;
1775 int sat = 0;
1776
64654ded 1777 upper = 1;
64654ded 1778 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
60594fea 1779 int64_t t = (int64_t)b->VsrSW(upper + i * 2);
64654ded 1780
7fa0ddc1 1781 result.VsrD(i) = 0;
64654ded 1782 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
60594fea 1783 t += a->VsrSW(2 * i + j);
64654ded 1784 }
60594fea 1785 result.VsrSW(upper + i * 2) = cvtsdsw(t, &sat);
64654ded
BS
1786 }
1787
1788 *r = result;
1789 if (sat) {
6175f5a0 1790 set_vscr_sat(env);
64654ded
BS
1791 }
1792}
1793
d15f74fb 1794void helper_vsum4sbs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1795{
1796 int i, j;
1797 int sat = 0;
1798
1799 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1800 int64_t t = (int64_t)b->s32[i];
1801
1802 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
1803 t += a->s8[4 * i + j];
1804 }
1805 r->s32[i] = cvtsdsw(t, &sat);
1806 }
1807
1808 if (sat) {
6175f5a0 1809 set_vscr_sat(env);
64654ded
BS
1810 }
1811}
1812
d15f74fb 1813void helper_vsum4shs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1814{
1815 int sat = 0;
1816 int i;
1817
1818 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1819 int64_t t = (int64_t)b->s32[i];
1820
1821 t += a->s16[2 * i] + a->s16[2 * i + 1];
1822 r->s32[i] = cvtsdsw(t, &sat);
1823 }
1824
1825 if (sat) {
6175f5a0 1826 set_vscr_sat(env);
64654ded
BS
1827 }
1828}
1829
d15f74fb 1830void helper_vsum4ubs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1831{
1832 int i, j;
1833 int sat = 0;
1834
1835 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
1836 uint64_t t = (uint64_t)b->u32[i];
1837
1838 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
1839 t += a->u8[4 * i + j];
1840 }
1841 r->u32[i] = cvtuduw(t, &sat);
1842 }
1843
1844 if (sat) {
6175f5a0 1845 set_vscr_sat(env);
64654ded
BS
1846 }
1847}
1848
1849#if defined(HOST_WORDS_BIGENDIAN)
1850#define UPKHI 1
1851#define UPKLO 0
1852#else
1853#define UPKHI 0
1854#define UPKLO 1
1855#endif
1856#define VUPKPX(suffix, hi) \
1857 void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
1858 { \
1859 int i; \
1860 ppc_avr_t result; \
1861 \
1862 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
b6cb41b2 1863 uint16_t e = b->u16[hi ? i : i + 4]; \
64654ded
BS
1864 uint8_t a = (e >> 15) ? 0xff : 0; \
1865 uint8_t r = (e >> 10) & 0x1f; \
1866 uint8_t g = (e >> 5) & 0x1f; \
1867 uint8_t b = e & 0x1f; \
1868 \
1869 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
1870 } \
1871 *r = result; \
1872 }
1873VUPKPX(lpx, UPKLO)
1874VUPKPX(hpx, UPKHI)
1875#undef VUPKPX
1876
1877#define VUPK(suffix, unpacked, packee, hi) \
1878 void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
1879 { \
1880 int i; \
1881 ppc_avr_t result; \
1882 \
1883 if (hi) { \
1884 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
1885 result.unpacked[i] = b->packee[i]; \
1886 } \
1887 } else { \
1888 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); \
1889 i++) { \
1890 result.unpacked[i - ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
1891 } \
1892 } \
1893 *r = result; \
1894 }
1895VUPK(hsb, s16, s8, UPKHI)
1896VUPK(hsh, s32, s16, UPKHI)
4430e076 1897VUPK(hsw, s64, s32, UPKHI)
64654ded
BS
1898VUPK(lsb, s16, s8, UPKLO)
1899VUPK(lsh, s32, s16, UPKLO)
4430e076 1900VUPK(lsw, s64, s32, UPKLO)
64654ded
BS
1901#undef VUPK
1902#undef UPKHI
1903#undef UPKLO
1904
f293f04a
TM
1905#define VGENERIC_DO(name, element) \
1906 void helper_v##name(ppc_avr_t *r, ppc_avr_t *b) \
1907 { \
1908 int i; \
1909 \
60594fea 1910 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
f293f04a
TM
1911 r->element[i] = name(b->element[i]); \
1912 } \
1913 }
1914
1915#define clzb(v) ((v) ? clz32((uint32_t)(v) << 24) : 8)
1916#define clzh(v) ((v) ? clz32((uint32_t)(v) << 16) : 16)
f293f04a
TM
1917
1918VGENERIC_DO(clzb, u8)
1919VGENERIC_DO(clzh, u16)
f293f04a
TM
1920
1921#undef clzb
1922#undef clzh
f293f04a 1923
a5ad8fbf
RS
1924#define ctzb(v) ((v) ? ctz32(v) : 8)
1925#define ctzh(v) ((v) ? ctz32(v) : 16)
1926#define ctzw(v) ctz32((v))
1927#define ctzd(v) ctz64((v))
1928
1929VGENERIC_DO(ctzb, u8)
1930VGENERIC_DO(ctzh, u16)
1931VGENERIC_DO(ctzw, u32)
1932VGENERIC_DO(ctzd, u64)
1933
1934#undef ctzb
1935#undef ctzh
1936#undef ctzw
1937#undef ctzd
1938
e13500b3
TM
1939#define popcntb(v) ctpop8(v)
1940#define popcnth(v) ctpop16(v)
1941#define popcntw(v) ctpop32(v)
1942#define popcntd(v) ctpop64(v)
1943
1944VGENERIC_DO(popcntb, u8)
1945VGENERIC_DO(popcnth, u16)
1946VGENERIC_DO(popcntw, u32)
1947VGENERIC_DO(popcntd, u64)
1948
1949#undef popcntb
1950#undef popcnth
1951#undef popcntw
1952#undef popcntd
f293f04a
TM
1953
1954#undef VGENERIC_DO
1955
b41da4eb
TM
1956#if defined(HOST_WORDS_BIGENDIAN)
1957#define QW_ONE { .u64 = { 0, 1 } }
1958#else
1959#define QW_ONE { .u64 = { 1, 0 } }
1960#endif
1961
1962#ifndef CONFIG_INT128
1963
1964static inline void avr_qw_not(ppc_avr_t *t, ppc_avr_t a)
1965{
1966 t->u64[0] = ~a.u64[0];
1967 t->u64[1] = ~a.u64[1];
1968}
1969
1970static int avr_qw_cmpu(ppc_avr_t a, ppc_avr_t b)
1971{
3c385a93 1972 if (a.VsrD(0) < b.VsrD(0)) {
b41da4eb 1973 return -1;
3c385a93 1974 } else if (a.VsrD(0) > b.VsrD(0)) {
b41da4eb 1975 return 1;
3c385a93 1976 } else if (a.VsrD(1) < b.VsrD(1)) {
b41da4eb 1977 return -1;
3c385a93 1978 } else if (a.VsrD(1) > b.VsrD(1)) {
b41da4eb
TM
1979 return 1;
1980 } else {
1981 return 0;
1982 }
1983}
1984
1985static void avr_qw_add(ppc_avr_t *t, ppc_avr_t a, ppc_avr_t b)
1986{
3c385a93
MCA
1987 t->VsrD(1) = a.VsrD(1) + b.VsrD(1);
1988 t->VsrD(0) = a.VsrD(0) + b.VsrD(0) +
1989 (~a.VsrD(1) < b.VsrD(1));
b41da4eb
TM
1990}
1991
1992static int avr_qw_addc(ppc_avr_t *t, ppc_avr_t a, ppc_avr_t b)
1993{
1994 ppc_avr_t not_a;
3c385a93
MCA
1995 t->VsrD(1) = a.VsrD(1) + b.VsrD(1);
1996 t->VsrD(0) = a.VsrD(0) + b.VsrD(0) +
1997 (~a.VsrD(1) < b.VsrD(1));
b41da4eb
TM
1998 avr_qw_not(&not_a, a);
1999 return avr_qw_cmpu(not_a, b) < 0;
2000}
2001
2002#endif
2003
2004void helper_vadduqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2005{
2006#ifdef CONFIG_INT128
2007 r->u128 = a->u128 + b->u128;
2008#else
2009 avr_qw_add(r, *a, *b);
2010#endif
2011}
2012
2013void helper_vaddeuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2014{
2015#ifdef CONFIG_INT128
2016 r->u128 = a->u128 + b->u128 + (c->u128 & 1);
2017#else
2018
3c385a93 2019 if (c->VsrD(1) & 1) {
b41da4eb
TM
2020 ppc_avr_t tmp;
2021
3c385a93
MCA
2022 tmp.VsrD(0) = 0;
2023 tmp.VsrD(1) = c->VsrD(1) & 1;
b41da4eb
TM
2024 avr_qw_add(&tmp, *a, tmp);
2025 avr_qw_add(r, tmp, *b);
2026 } else {
2027 avr_qw_add(r, *a, *b);
2028 }
2029#endif
2030}
2031
2032void helper_vaddcuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2033{
2034#ifdef CONFIG_INT128
2035 r->u128 = (~a->u128 < b->u128);
2036#else
2037 ppc_avr_t not_a;
2038
2039 avr_qw_not(&not_a, *a);
2040
3c385a93
MCA
2041 r->VsrD(0) = 0;
2042 r->VsrD(1) = (avr_qw_cmpu(not_a, *b) < 0);
b41da4eb
TM
2043#endif
2044}
2045
2046void helper_vaddecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2047{
2048#ifdef CONFIG_INT128
2049 int carry_out = (~a->u128 < b->u128);
2050 if (!carry_out && (c->u128 & 1)) {
2051 carry_out = ((a->u128 + b->u128 + 1) == 0) &&
2052 ((a->u128 != 0) || (b->u128 != 0));
2053 }
2054 r->u128 = carry_out;
2055#else
2056
3c385a93 2057 int carry_in = c->VsrD(1) & 1;
b41da4eb
TM
2058 int carry_out = 0;
2059 ppc_avr_t tmp;
2060
2061 carry_out = avr_qw_addc(&tmp, *a, *b);
2062
2063 if (!carry_out && carry_in) {
2064 ppc_avr_t one = QW_ONE;
2065 carry_out = avr_qw_addc(&tmp, tmp, one);
2066 }
3c385a93
MCA
2067 r->VsrD(0) = 0;
2068 r->VsrD(1) = carry_out;
b41da4eb
TM
2069#endif
2070}
2071
2072void helper_vsubuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2073{
2074#ifdef CONFIG_INT128
2075 r->u128 = a->u128 - b->u128;
2076#else
2077 ppc_avr_t tmp;
2078 ppc_avr_t one = QW_ONE;
2079
2080 avr_qw_not(&tmp, *b);
2081 avr_qw_add(&tmp, *a, tmp);
2082 avr_qw_add(r, tmp, one);
2083#endif
2084}
2085
2086void helper_vsubeuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2087{
2088#ifdef CONFIG_INT128
2089 r->u128 = a->u128 + ~b->u128 + (c->u128 & 1);
2090#else
2091 ppc_avr_t tmp, sum;
2092
2093 avr_qw_not(&tmp, *b);
2094 avr_qw_add(&sum, *a, tmp);
2095
3c385a93
MCA
2096 tmp.VsrD(0) = 0;
2097 tmp.VsrD(1) = c->VsrD(1) & 1;
b41da4eb
TM
2098 avr_qw_add(r, sum, tmp);
2099#endif
2100}
2101
2102void helper_vsubcuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2103{
2104#ifdef CONFIG_INT128
2105 r->u128 = (~a->u128 < ~b->u128) ||
2106 (a->u128 + ~b->u128 == (__uint128_t)-1);
2107#else
2108 int carry = (avr_qw_cmpu(*a, *b) > 0);
2109 if (!carry) {
2110 ppc_avr_t tmp;
2111 avr_qw_not(&tmp, *b);
2112 avr_qw_add(&tmp, *a, tmp);
3c385a93 2113 carry = ((tmp.VsrSD(0) == -1ull) && (tmp.VsrSD(1) == -1ull));
b41da4eb 2114 }
3c385a93
MCA
2115 r->VsrD(0) = 0;
2116 r->VsrD(1) = carry;
b41da4eb
TM
2117#endif
2118}
2119
2120void helper_vsubecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2121{
2122#ifdef CONFIG_INT128
2123 r->u128 =
2124 (~a->u128 < ~b->u128) ||
2125 ((c->u128 & 1) && (a->u128 + ~b->u128 == (__uint128_t)-1));
2126#else
3c385a93 2127 int carry_in = c->VsrD(1) & 1;
b41da4eb
TM
2128 int carry_out = (avr_qw_cmpu(*a, *b) > 0);
2129 if (!carry_out && carry_in) {
2130 ppc_avr_t tmp;
2131 avr_qw_not(&tmp, *b);
2132 avr_qw_add(&tmp, *a, tmp);
3c385a93 2133 carry_out = ((tmp.VsrD(0) == -1ull) && (tmp.VsrD(1) == -1ull));
b41da4eb
TM
2134 }
2135
3c385a93
MCA
2136 r->VsrD(0) = 0;
2137 r->VsrD(1) = carry_out;
b41da4eb
TM
2138#endif
2139}
2140
e8f7b27b
TM
2141#define BCD_PLUS_PREF_1 0xC
2142#define BCD_PLUS_PREF_2 0xF
2143#define BCD_PLUS_ALT_1 0xA
2144#define BCD_NEG_PREF 0xD
2145#define BCD_NEG_ALT 0xB
2146#define BCD_PLUS_ALT_2 0xE
b8155872
JRZ
2147#define NATIONAL_PLUS 0x2B
2148#define NATIONAL_NEG 0x2D
e8f7b27b 2149
365206ae 2150#define BCD_DIG_BYTE(n) (15 - ((n) / 2))
e8f7b27b
TM
2151
2152static int bcd_get_sgn(ppc_avr_t *bcd)
2153{
428115c3 2154 switch (bcd->VsrB(BCD_DIG_BYTE(0)) & 0xF) {
e8f7b27b
TM
2155 case BCD_PLUS_PREF_1:
2156 case BCD_PLUS_PREF_2:
2157 case BCD_PLUS_ALT_1:
2158 case BCD_PLUS_ALT_2:
2159 {
2160 return 1;
2161 }
2162
2163 case BCD_NEG_PREF:
2164 case BCD_NEG_ALT:
2165 {
2166 return -1;
2167 }
2168
2169 default:
2170 {
2171 return 0;
2172 }
2173 }
2174}
2175
2176static int bcd_preferred_sgn(int sgn, int ps)
2177{
2178 if (sgn >= 0) {
2179 return (ps == 0) ? BCD_PLUS_PREF_1 : BCD_PLUS_PREF_2;
2180 } else {
2181 return BCD_NEG_PREF;
2182 }
2183}
2184
2185static uint8_t bcd_get_digit(ppc_avr_t *bcd, int n, int *invalid)
2186{
2187 uint8_t result;
2188 if (n & 1) {
428115c3 2189 result = bcd->VsrB(BCD_DIG_BYTE(n)) >> 4;
e8f7b27b 2190 } else {
428115c3 2191 result = bcd->VsrB(BCD_DIG_BYTE(n)) & 0xF;
e8f7b27b
TM
2192 }
2193
2194 if (unlikely(result > 9)) {
2195 *invalid = true;
2196 }
2197 return result;
2198}
2199
2200static void bcd_put_digit(ppc_avr_t *bcd, uint8_t digit, int n)
2201{
2202 if (n & 1) {
428115c3
MCA
2203 bcd->VsrB(BCD_DIG_BYTE(n)) &= 0x0F;
2204 bcd->VsrB(BCD_DIG_BYTE(n)) |= (digit << 4);
e8f7b27b 2205 } else {
428115c3
MCA
2206 bcd->VsrB(BCD_DIG_BYTE(n)) &= 0xF0;
2207 bcd->VsrB(BCD_DIG_BYTE(n)) |= digit;
e8f7b27b
TM
2208 }
2209}
2210
071663df
JRZ
2211static bool bcd_is_valid(ppc_avr_t *bcd)
2212{
2213 int i;
2214 int invalid = 0;
2215
2216 if (bcd_get_sgn(bcd) == 0) {
2217 return false;
2218 }
2219
2220 for (i = 1; i < 32; i++) {
2221 bcd_get_digit(bcd, i, &invalid);
2222 if (unlikely(invalid)) {
2223 return false;
2224 }
2225 }
2226 return true;
2227}
2228
b8155872
JRZ
2229static int bcd_cmp_zero(ppc_avr_t *bcd)
2230{
3c385a93 2231 if (bcd->VsrD(0) == 0 && (bcd->VsrD(1) >> 4) == 0) {
efa73196 2232 return CRF_EQ;
b8155872 2233 } else {
efa73196 2234 return (bcd_get_sgn(bcd) == 1) ? CRF_GT : CRF_LT;
b8155872
JRZ
2235 }
2236}
2237
2238static uint16_t get_national_digit(ppc_avr_t *reg, int n)
2239{
60594fea 2240 return reg->VsrH(7 - n);
b8155872
JRZ
2241}
2242
e2106d73
JRZ
2243static void set_national_digit(ppc_avr_t *reg, uint8_t val, int n)
2244{
60594fea 2245 reg->VsrH(7 - n) = val;
e2106d73
JRZ
2246}
2247
e8f7b27b
TM
2248static int bcd_cmp_mag(ppc_avr_t *a, ppc_avr_t *b)
2249{
2250 int i;
2251 int invalid = 0;
2252 for (i = 31; i > 0; i--) {
2253 uint8_t dig_a = bcd_get_digit(a, i, &invalid);
2254 uint8_t dig_b = bcd_get_digit(b, i, &invalid);
2255 if (unlikely(invalid)) {
3b163b01 2256 return 0; /* doesn't matter */
e8f7b27b
TM
2257 } else if (dig_a > dig_b) {
2258 return 1;
2259 } else if (dig_a < dig_b) {
2260 return -1;
2261 }
2262 }
2263
2264 return 0;
2265}
2266
936fda4d 2267static int bcd_add_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid,
e8f7b27b
TM
2268 int *overflow)
2269{
2270 int carry = 0;
2271 int i;
936fda4d
FR
2272 int is_zero = 1;
2273
e8f7b27b
TM
2274 for (i = 1; i <= 31; i++) {
2275 uint8_t digit = bcd_get_digit(a, i, invalid) +
2276 bcd_get_digit(b, i, invalid) + carry;
936fda4d 2277 is_zero &= (digit == 0);
e8f7b27b
TM
2278 if (digit > 9) {
2279 carry = 1;
2280 digit -= 10;
2281 } else {
2282 carry = 0;
2283 }
2284
2285 bcd_put_digit(t, digit, i);
e8f7b27b
TM
2286 }
2287
2288 *overflow = carry;
936fda4d 2289 return is_zero;
e8f7b27b
TM
2290}
2291
d03b174a 2292static void bcd_sub_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid,
e8f7b27b
TM
2293 int *overflow)
2294{
2295 int carry = 0;
2296 int i;
d03b174a 2297
e8f7b27b
TM
2298 for (i = 1; i <= 31; i++) {
2299 uint8_t digit = bcd_get_digit(a, i, invalid) -
2300 bcd_get_digit(b, i, invalid) + carry;
e8f7b27b
TM
2301 if (digit & 0x80) {
2302 carry = -1;
2303 digit += 10;
2304 } else {
2305 carry = 0;
2306 }
2307
2308 bcd_put_digit(t, digit, i);
e8f7b27b
TM
2309 }
2310
2311 *overflow = carry;
e8f7b27b
TM
2312}
2313
2314uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
2315{
2316
2317 int sgna = bcd_get_sgn(a);
2318 int sgnb = bcd_get_sgn(b);
2319 int invalid = (sgna == 0) || (sgnb == 0);
2320 int overflow = 0;
936fda4d 2321 int zero = 0;
e8f7b27b
TM
2322 uint32_t cr = 0;
2323 ppc_avr_t result = { .u64 = { 0, 0 } };
2324
2325 if (!invalid) {
2326 if (sgna == sgnb) {
428115c3 2327 result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgna, ps);
936fda4d
FR
2328 zero = bcd_add_mag(&result, a, b, &invalid, &overflow);
2329 cr = (sgna > 0) ? CRF_GT : CRF_LT;
e8f7b27b 2330 } else {
d03b174a
YB
2331 int magnitude = bcd_cmp_mag(a, b);
2332 if (magnitude > 0) {
428115c3 2333 result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgna, ps);
d03b174a
YB
2334 bcd_sub_mag(&result, a, b, &invalid, &overflow);
2335 cr = (sgna > 0) ? CRF_GT : CRF_LT;
2336 } else if (magnitude < 0) {
428115c3 2337 result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgnb, ps);
d03b174a
YB
2338 bcd_sub_mag(&result, b, a, &invalid, &overflow);
2339 cr = (sgnb > 0) ? CRF_GT : CRF_LT;
2340 } else {
428115c3 2341 result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(0, ps);
d03b174a
YB
2342 cr = CRF_EQ;
2343 }
e8f7b27b
TM
2344 }
2345 }
2346
2347 if (unlikely(invalid)) {
3c385a93 2348 result.VsrD(0) = result.VsrD(1) = -1;
efa73196 2349 cr = CRF_SO;
e8f7b27b 2350 } else if (overflow) {
efa73196 2351 cr |= CRF_SO;
936fda4d
FR
2352 } else if (zero) {
2353 cr |= CRF_EQ;
e8f7b27b
TM
2354 }
2355
2356 *r = result;
2357
2358 return cr;
2359}
2360
2361uint32_t helper_bcdsub(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
2362{
2363 ppc_avr_t bcopy = *b;
2364 int sgnb = bcd_get_sgn(b);
2365 if (sgnb < 0) {
2366 bcd_put_digit(&bcopy, BCD_PLUS_PREF_1, 0);
2367 } else if (sgnb > 0) {
2368 bcd_put_digit(&bcopy, BCD_NEG_PREF, 0);
2369 }
2370 /* else invalid ... defer to bcdadd code for proper handling */
2371
2372 return helper_bcdadd(r, a, &bcopy, ps);
2373}
f293f04a 2374
b8155872
JRZ
2375uint32_t helper_bcdcfn(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
2376{
2377 int i;
2378 int cr = 0;
2379 uint16_t national = 0;
2380 uint16_t sgnb = get_national_digit(b, 0);
2381 ppc_avr_t ret = { .u64 = { 0, 0 } };
2382 int invalid = (sgnb != NATIONAL_PLUS && sgnb != NATIONAL_NEG);
2383
2384 for (i = 1; i < 8; i++) {
2385 national = get_national_digit(b, i);
2386 if (unlikely(national < 0x30 || national > 0x39)) {
2387 invalid = 1;
2388 break;
2389 }
2390
2391 bcd_put_digit(&ret, national & 0xf, i);
2392 }
2393
2394 if (sgnb == NATIONAL_PLUS) {
2395 bcd_put_digit(&ret, (ps == 0) ? BCD_PLUS_PREF_1 : BCD_PLUS_PREF_2, 0);
2396 } else {
2397 bcd_put_digit(&ret, BCD_NEG_PREF, 0);
2398 }
2399
2400 cr = bcd_cmp_zero(&ret);
2401
2402 if (unlikely(invalid)) {
efa73196 2403 cr = CRF_SO;
b8155872
JRZ
2404 }
2405
2406 *r = ret;
2407
2408 return cr;
2409}
2410
e2106d73
JRZ
2411uint32_t helper_bcdctn(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
2412{
2413 int i;
2414 int cr = 0;
2415 int sgnb = bcd_get_sgn(b);
2416 int invalid = (sgnb == 0);
2417 ppc_avr_t ret = { .u64 = { 0, 0 } };
2418
3c385a93 2419 int ox_flag = (b->VsrD(0) != 0) || ((b->VsrD(1) >> 32) != 0);
e2106d73
JRZ
2420
2421 for (i = 1; i < 8; i++) {
2422 set_national_digit(&ret, 0x30 + bcd_get_digit(b, i, &invalid), i);
2423
2424 if (unlikely(invalid)) {
2425 break;
2426 }
2427 }
2428 set_national_digit(&ret, (sgnb == -1) ? NATIONAL_NEG : NATIONAL_PLUS, 0);
2429
2430 cr = bcd_cmp_zero(b);
2431
2432 if (ox_flag) {
efa73196 2433 cr |= CRF_SO;
e2106d73
JRZ
2434 }
2435
2436 if (unlikely(invalid)) {
efa73196 2437 cr = CRF_SO;
e2106d73
JRZ
2438 }
2439
2440 *r = ret;
2441
2442 return cr;
2443}
2444
38f4cb04
JRZ
2445uint32_t helper_bcdcfz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
2446{
2447 int i;
2448 int cr = 0;
2449 int invalid = 0;
2450 int zone_digit = 0;
2451 int zone_lead = ps ? 0xF : 0x3;
2452 int digit = 0;
2453 ppc_avr_t ret = { .u64 = { 0, 0 } };
428115c3 2454 int sgnb = b->VsrB(BCD_DIG_BYTE(0)) >> 4;
38f4cb04
JRZ
2455
2456 if (unlikely((sgnb < 0xA) && ps)) {
2457 invalid = 1;
2458 }
2459
2460 for (i = 0; i < 16; i++) {
428115c3
MCA
2461 zone_digit = i ? b->VsrB(BCD_DIG_BYTE(i * 2)) >> 4 : zone_lead;
2462 digit = b->VsrB(BCD_DIG_BYTE(i * 2)) & 0xF;
38f4cb04
JRZ
2463 if (unlikely(zone_digit != zone_lead || digit > 0x9)) {
2464 invalid = 1;
2465 break;
2466 }
2467
2468 bcd_put_digit(&ret, digit, i + 1);
2469 }
2470
2471 if ((ps && (sgnb == 0xB || sgnb == 0xD)) ||
2472 (!ps && (sgnb & 0x4))) {
2473 bcd_put_digit(&ret, BCD_NEG_PREF, 0);
2474 } else {
2475 bcd_put_digit(&ret, BCD_PLUS_PREF_1, 0);
2476 }
2477
2478 cr = bcd_cmp_zero(&ret);
2479
2480 if (unlikely(invalid)) {
efa73196 2481 cr = CRF_SO;
38f4cb04
JRZ
2482 }
2483
2484 *r = ret;
2485
2486 return cr;
2487}
2488
0a890b31
JRZ
2489uint32_t helper_bcdctz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
2490{
2491 int i;
2492 int cr = 0;
2493 uint8_t digit = 0;
2494 int sgnb = bcd_get_sgn(b);
2495 int zone_lead = (ps) ? 0xF0 : 0x30;
2496 int invalid = (sgnb == 0);
2497 ppc_avr_t ret = { .u64 = { 0, 0 } };
2498
3c385a93 2499 int ox_flag = ((b->VsrD(0) >> 4) != 0);
0a890b31
JRZ
2500
2501 for (i = 0; i < 16; i++) {
2502 digit = bcd_get_digit(b, i + 1, &invalid);
2503
2504 if (unlikely(invalid)) {
2505 break;
2506 }
2507
428115c3 2508 ret.VsrB(BCD_DIG_BYTE(i * 2)) = zone_lead + digit;
0a890b31
JRZ
2509 }
2510
2511 if (ps) {
2512 bcd_put_digit(&ret, (sgnb == 1) ? 0xC : 0xD, 1);
2513 } else {
2514 bcd_put_digit(&ret, (sgnb == 1) ? 0x3 : 0x7, 1);
2515 }
2516
2517 cr = bcd_cmp_zero(b);
2518
2519 if (ox_flag) {
efa73196 2520 cr |= CRF_SO;
0a890b31
JRZ
2521 }
2522
2523 if (unlikely(invalid)) {
efa73196 2524 cr = CRF_SO;
0a890b31
JRZ
2525 }
2526
2527 *r = ret;
2528
2529 return cr;
2530}
2531
a3d67f3e
LP
2532/**
2533 * Compare 2 128-bit unsigned integers, passed in as unsigned 64-bit pairs
2534 *
2535 * Returns:
2536 * > 0 if ahi|alo > bhi|blo,
2537 * 0 if ahi|alo == bhi|blo,
2538 * < 0 if ahi|alo < bhi|blo
2539 */
2540static inline int ucmp128(uint64_t alo, uint64_t ahi,
2541 uint64_t blo, uint64_t bhi)
2542{
2543 return (ahi == bhi) ?
2544 (alo > blo ? 1 : (alo == blo ? 0 : -1)) :
2545 (ahi > bhi ? 1 : -1);
2546}
2547
a406c058
JRZ
2548uint32_t helper_bcdcfsq(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
2549{
2550 int i;
a3d67f3e 2551 int cr;
a406c058
JRZ
2552 uint64_t lo_value;
2553 uint64_t hi_value;
40f3e79a 2554 uint64_t rem;
a406c058
JRZ
2555 ppc_avr_t ret = { .u64 = { 0, 0 } };
2556
3c385a93
MCA
2557 if (b->VsrSD(0) < 0) {
2558 lo_value = -b->VsrSD(1);
2559 hi_value = ~b->VsrD(0) + !lo_value;
a406c058 2560 bcd_put_digit(&ret, 0xD, 0);
a3d67f3e
LP
2561
2562 cr = CRF_LT;
a406c058 2563 } else {
3c385a93
MCA
2564 lo_value = b->VsrD(1);
2565 hi_value = b->VsrD(0);
a406c058 2566 bcd_put_digit(&ret, bcd_preferred_sgn(0, ps), 0);
a406c058 2567
a3d67f3e
LP
2568 if (hi_value == 0 && lo_value == 0) {
2569 cr = CRF_EQ;
2570 } else {
2571 cr = CRF_GT;
2572 }
a406c058
JRZ
2573 }
2574
a3d67f3e
LP
2575 /*
2576 * Check src limits: abs(src) <= 10^31 - 1
2577 *
2578 * 10^31 - 1 = 0x0000007e37be2022 c0914b267fffffff
2579 */
2580 if (ucmp128(lo_value, hi_value,
2581 0xc0914b267fffffffULL, 0x7e37be2022ULL) > 0) {
2582 cr |= CRF_SO;
a406c058 2583
a3d67f3e
LP
2584 /*
2585 * According to the ISA, if src wouldn't fit in the destination
2586 * register, the result is undefined.
2587 * In that case, we leave r unchanged.
2588 */
2589 } else {
40f3e79a 2590 rem = divu128(&lo_value, &hi_value, 1000000000000000ULL);
a406c058 2591
40f3e79a
LP
2592 for (i = 1; i < 16; rem /= 10, i++) {
2593 bcd_put_digit(&ret, rem % 10, i);
a3d67f3e 2594 }
a406c058 2595
a3d67f3e
LP
2596 for (; i < 32; lo_value /= 10, i++) {
2597 bcd_put_digit(&ret, lo_value % 10, i);
2598 }
2599
2600 *r = ret;
2601 }
a406c058
JRZ
2602
2603 return cr;
2604}
2605
c85bc7dd
JRZ
2606uint32_t helper_bcdctsq(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
2607{
2608 uint8_t i;
2609 int cr;
2610 uint64_t carry;
2611 uint64_t unused;
2612 uint64_t lo_value;
2613 uint64_t hi_value = 0;
2614 int sgnb = bcd_get_sgn(b);
2615 int invalid = (sgnb == 0);
2616
2617 lo_value = bcd_get_digit(b, 31, &invalid);
2618 for (i = 30; i > 0; i--) {
2619 mulu64(&lo_value, &carry, lo_value, 10ULL);
2620 mulu64(&hi_value, &unused, hi_value, 10ULL);
2621 lo_value += bcd_get_digit(b, i, &invalid);
2622 hi_value += carry;
2623
2624 if (unlikely(invalid)) {
2625 break;
2626 }
2627 }
2628
2629 if (sgnb == -1) {
3c385a93
MCA
2630 r->VsrSD(1) = -lo_value;
2631 r->VsrSD(0) = ~hi_value + !r->VsrSD(1);
c85bc7dd 2632 } else {
3c385a93
MCA
2633 r->VsrSD(1) = lo_value;
2634 r->VsrSD(0) = hi_value;
c85bc7dd
JRZ
2635 }
2636
2637 cr = bcd_cmp_zero(b);
2638
2639 if (unlikely(invalid)) {
2640 cr = CRF_SO;
2641 }
2642
2643 return cr;
2644}
2645
c3025c3b
JRZ
2646uint32_t helper_bcdcpsgn(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
2647{
2648 int i;
2649 int invalid = 0;
2650
2651 if (bcd_get_sgn(a) == 0 || bcd_get_sgn(b) == 0) {
2652 return CRF_SO;
2653 }
2654
2655 *r = *a;
428115c3 2656 bcd_put_digit(r, b->VsrB(BCD_DIG_BYTE(0)) & 0xF, 0);
c3025c3b
JRZ
2657
2658 for (i = 1; i < 32; i++) {
2659 bcd_get_digit(a, i, &invalid);
2660 bcd_get_digit(b, i, &invalid);
2661 if (unlikely(invalid)) {
2662 return CRF_SO;
2663 }
2664 }
2665
2666 return bcd_cmp_zero(r);
2667}
2668
466a3f9c
JRZ
2669uint32_t helper_bcdsetsgn(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
2670{
466a3f9c
JRZ
2671 int sgnb = bcd_get_sgn(b);
2672
2673 *r = *b;
2674 bcd_put_digit(r, bcd_preferred_sgn(sgnb, ps), 0);
2675
071663df
JRZ
2676 if (bcd_is_valid(b) == false) {
2677 return CRF_SO;
466a3f9c
JRZ
2678 }
2679
2680 return bcd_cmp_zero(r);
2681}
2682
e04797f7
JRZ
2683uint32_t helper_bcds(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
2684{
2685 int cr;
428115c3 2686 int i = a->VsrSB(7);
e04797f7
JRZ
2687 bool ox_flag = false;
2688 int sgnb = bcd_get_sgn(b);
2689 ppc_avr_t ret = *b;
3c385a93 2690 ret.VsrD(1) &= ~0xf;
e04797f7
JRZ
2691
2692 if (bcd_is_valid(b) == false) {
2693 return CRF_SO;
2694 }
2695
2696 if (unlikely(i > 31)) {
2697 i = 31;
2698 } else if (unlikely(i < -31)) {
2699 i = -31;
2700 }
2701
2702 if (i > 0) {
3c385a93 2703 ulshift(&ret.VsrD(1), &ret.VsrD(0), i * 4, &ox_flag);
e04797f7 2704 } else {
3c385a93 2705 urshift(&ret.VsrD(1), &ret.VsrD(0), -i * 4);
e04797f7
JRZ
2706 }
2707 bcd_put_digit(&ret, bcd_preferred_sgn(sgnb, ps), 0);
2708
2709 *r = ret;
2710
2711 cr = bcd_cmp_zero(r);
2712 if (ox_flag) {
2713 cr |= CRF_SO;
2714 }
2715
2716 return cr;
2717}
2718
a49a95e9
JRZ
2719uint32_t helper_bcdus(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
2720{
2721 int cr;
2722 int i;
2723 int invalid = 0;
2724 bool ox_flag = false;
2725 ppc_avr_t ret = *b;
2726
2727 for (i = 0; i < 32; i++) {
2728 bcd_get_digit(b, i, &invalid);
2729
2730 if (unlikely(invalid)) {
2731 return CRF_SO;
2732 }
2733 }
2734
428115c3 2735 i = a->VsrSB(7);
a49a95e9
JRZ
2736 if (i >= 32) {
2737 ox_flag = true;
3c385a93 2738 ret.VsrD(1) = ret.VsrD(0) = 0;
a49a95e9 2739 } else if (i <= -32) {
3c385a93 2740 ret.VsrD(1) = ret.VsrD(0) = 0;
a49a95e9 2741 } else if (i > 0) {
3c385a93 2742 ulshift(&ret.VsrD(1), &ret.VsrD(0), i * 4, &ox_flag);
a49a95e9 2743 } else {
3c385a93 2744 urshift(&ret.VsrD(1), &ret.VsrD(0), -i * 4);
a49a95e9
JRZ
2745 }
2746 *r = ret;
2747
2748 cr = bcd_cmp_zero(r);
2749 if (ox_flag) {
2750 cr |= CRF_SO;
2751 }
2752
2753 return cr;
2754}
2755
a54238ad
JRZ
2756uint32_t helper_bcdsr(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
2757{
2758 int cr;
2759 int unused = 0;
2760 int invalid = 0;
2761 bool ox_flag = false;
2762 int sgnb = bcd_get_sgn(b);
2763 ppc_avr_t ret = *b;
3c385a93 2764 ret.VsrD(1) &= ~0xf;
a54238ad 2765
428115c3
MCA
2766 int i = a->VsrSB(7);
2767 ppc_avr_t bcd_one;
2768
2769 bcd_one.VsrD(0) = 0;
2770 bcd_one.VsrD(1) = 0x10;
a54238ad
JRZ
2771
2772 if (bcd_is_valid(b) == false) {
2773 return CRF_SO;
2774 }
2775
2776 if (unlikely(i > 31)) {
2777 i = 31;
2778 } else if (unlikely(i < -31)) {
2779 i = -31;
2780 }
2781
2782 if (i > 0) {
3c385a93 2783 ulshift(&ret.VsrD(1), &ret.VsrD(0), i * 4, &ox_flag);
a54238ad 2784 } else {
3c385a93 2785 urshift(&ret.VsrD(1), &ret.VsrD(0), -i * 4);
a54238ad
JRZ
2786
2787 if (bcd_get_digit(&ret, 0, &invalid) >= 5) {
2788 bcd_add_mag(&ret, &ret, &bcd_one, &invalid, &unused);
2789 }
2790 }
2791 bcd_put_digit(&ret, bcd_preferred_sgn(sgnb, ps), 0);
2792
2793 cr = bcd_cmp_zero(&ret);
2794 if (ox_flag) {
2795 cr |= CRF_SO;
2796 }
2797 *r = ret;
2798
2799 return cr;
2800}
2801
31bc4d11
JRZ
2802uint32_t helper_bcdtrunc(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
2803{
2804 uint64_t mask;
2805 uint32_t ox_flag = 0;
428115c3 2806 int i = a->VsrSH(3) + 1;
31bc4d11
JRZ
2807 ppc_avr_t ret = *b;
2808
2809 if (bcd_is_valid(b) == false) {
2810 return CRF_SO;
2811 }
2812
2813 if (i > 16 && i < 32) {
2814 mask = (uint64_t)-1 >> (128 - i * 4);
3c385a93 2815 if (ret.VsrD(0) & ~mask) {
31bc4d11
JRZ
2816 ox_flag = CRF_SO;
2817 }
2818
3c385a93 2819 ret.VsrD(0) &= mask;
31bc4d11
JRZ
2820 } else if (i >= 0 && i <= 16) {
2821 mask = (uint64_t)-1 >> (64 - i * 4);
3c385a93 2822 if (ret.VsrD(0) || (ret.VsrD(1) & ~mask)) {
31bc4d11
JRZ
2823 ox_flag = CRF_SO;
2824 }
2825
3c385a93
MCA
2826 ret.VsrD(1) &= mask;
2827 ret.VsrD(0) = 0;
31bc4d11
JRZ
2828 }
2829 bcd_put_digit(&ret, bcd_preferred_sgn(bcd_get_sgn(b), ps), 0);
2830 *r = ret;
2831
2832 return bcd_cmp_zero(&ret) | ox_flag;
2833}
2834
5c32e2e4
JRZ
2835uint32_t helper_bcdutrunc(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
2836{
2837 int i;
2838 uint64_t mask;
2839 uint32_t ox_flag = 0;
2840 int invalid = 0;
2841 ppc_avr_t ret = *b;
2842
2843 for (i = 0; i < 32; i++) {
2844 bcd_get_digit(b, i, &invalid);
2845
2846 if (unlikely(invalid)) {
2847 return CRF_SO;
2848 }
2849 }
2850
428115c3 2851 i = a->VsrSH(3);
5c32e2e4
JRZ
2852 if (i > 16 && i < 33) {
2853 mask = (uint64_t)-1 >> (128 - i * 4);
3c385a93 2854 if (ret.VsrD(0) & ~mask) {
5c32e2e4
JRZ
2855 ox_flag = CRF_SO;
2856 }
2857
3c385a93 2858 ret.VsrD(0) &= mask;
5c32e2e4
JRZ
2859 } else if (i > 0 && i <= 16) {
2860 mask = (uint64_t)-1 >> (64 - i * 4);
3c385a93 2861 if (ret.VsrD(0) || (ret.VsrD(1) & ~mask)) {
5c32e2e4
JRZ
2862 ox_flag = CRF_SO;
2863 }
2864
3c385a93
MCA
2865 ret.VsrD(1) &= mask;
2866 ret.VsrD(0) = 0;
5c32e2e4 2867 } else if (i == 0) {
3c385a93 2868 if (ret.VsrD(0) || ret.VsrD(1)) {
5c32e2e4
JRZ
2869 ox_flag = CRF_SO;
2870 }
3c385a93 2871 ret.VsrD(0) = ret.VsrD(1) = 0;
5c32e2e4
JRZ
2872 }
2873
2874 *r = ret;
3c385a93 2875 if (r->VsrD(0) == 0 && r->VsrD(1) == 0) {
5c32e2e4
JRZ
2876 return ox_flag | CRF_EQ;
2877 }
2878
2879 return ox_flag | CRF_GT;
2880}
2881
c1542453 2882void helper_vsbox(ppc_avr_t *r, ppc_avr_t *a)
557d52fa
TM
2883{
2884 int i;
2885 VECTOR_FOR_INORDER_I(i, u8) {
c1542453 2886 r->u8[i] = AES_sbox[a->u8[i]];
557d52fa
TM
2887 }
2888}
2889
c1542453 2890void helper_vcipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
557d52fa 2891{
65cf1f65 2892 ppc_avr_t result;
557d52fa 2893 int i;
557d52fa 2894
c1542453 2895 VECTOR_FOR_INORDER_I(i, u32) {
2dea57db
MCA
2896 result.VsrW(i) = b->VsrW(i) ^
2897 (AES_Te0[a->VsrB(AES_shifts[4 * i + 0])] ^
2898 AES_Te1[a->VsrB(AES_shifts[4 * i + 1])] ^
2899 AES_Te2[a->VsrB(AES_shifts[4 * i + 2])] ^
2900 AES_Te3[a->VsrB(AES_shifts[4 * i + 3])]);
557d52fa 2901 }
65cf1f65 2902 *r = result;
557d52fa
TM
2903}
2904
557d52fa
TM
2905void helper_vcipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2906{
65cf1f65 2907 ppc_avr_t result;
c1542453
TM
2908 int i;
2909
2910 VECTOR_FOR_INORDER_I(i, u8) {
2dea57db 2911 result.VsrB(i) = b->VsrB(i) ^ (AES_sbox[a->VsrB(AES_shifts[i])]);
c1542453 2912 }
65cf1f65 2913 *r = result;
557d52fa
TM
2914}
2915
2916void helper_vncipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2917{
2918 /* This differs from what is written in ISA V2.07. The RTL is */
2919 /* incorrect and will be fixed in V2.07B. */
c1542453
TM
2920 int i;
2921 ppc_avr_t tmp;
2922
2923 VECTOR_FOR_INORDER_I(i, u8) {
2dea57db 2924 tmp.VsrB(i) = b->VsrB(i) ^ AES_isbox[a->VsrB(AES_ishifts[i])];
c1542453
TM
2925 }
2926
2927 VECTOR_FOR_INORDER_I(i, u32) {
2dea57db
MCA
2928 r->VsrW(i) =
2929 AES_imc[tmp.VsrB(4 * i + 0)][0] ^
2930 AES_imc[tmp.VsrB(4 * i + 1)][1] ^
2931 AES_imc[tmp.VsrB(4 * i + 2)][2] ^
2932 AES_imc[tmp.VsrB(4 * i + 3)][3];
c1542453 2933 }
557d52fa
TM
2934}
2935
2936void helper_vncipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2937{
65cf1f65 2938 ppc_avr_t result;
c1542453
TM
2939 int i;
2940
2941 VECTOR_FOR_INORDER_I(i, u8) {
2dea57db 2942 result.VsrB(i) = b->VsrB(i) ^ (AES_isbox[a->VsrB(AES_ishifts[i])]);
c1542453 2943 }
65cf1f65 2944 *r = result;
557d52fa
TM
2945}
2946
57354f8f
TM
2947void helper_vshasigmaw(ppc_avr_t *r, ppc_avr_t *a, uint32_t st_six)
2948{
2949 int st = (st_six & 0x10) != 0;
2950 int six = st_six & 0xF;
2951 int i;
2952
730d2ca3 2953 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
57354f8f
TM
2954 if (st == 0) {
2955 if ((six & (0x8 >> i)) == 0) {
0ef83bf2
MCA
2956 r->VsrW(i) = ror32(a->VsrW(i), 7) ^
2957 ror32(a->VsrW(i), 18) ^
730d2ca3 2958 (a->VsrW(i) >> 3);
57354f8f 2959 } else { /* six.bit[i] == 1 */
0ef83bf2
MCA
2960 r->VsrW(i) = ror32(a->VsrW(i), 17) ^
2961 ror32(a->VsrW(i), 19) ^
730d2ca3 2962 (a->VsrW(i) >> 10);
57354f8f
TM
2963 }
2964 } else { /* st == 1 */
2965 if ((six & (0x8 >> i)) == 0) {
0ef83bf2
MCA
2966 r->VsrW(i) = ror32(a->VsrW(i), 2) ^
2967 ror32(a->VsrW(i), 13) ^
2968 ror32(a->VsrW(i), 22);
57354f8f 2969 } else { /* six.bit[i] == 1 */
0ef83bf2
MCA
2970 r->VsrW(i) = ror32(a->VsrW(i), 6) ^
2971 ror32(a->VsrW(i), 11) ^
2972 ror32(a->VsrW(i), 25);
57354f8f
TM
2973 }
2974 }
2975 }
2976}
2977
57354f8f
TM
2978void helper_vshasigmad(ppc_avr_t *r, ppc_avr_t *a, uint32_t st_six)
2979{
2980 int st = (st_six & 0x10) != 0;
2981 int six = st_six & 0xF;
2982 int i;
2983
730d2ca3 2984 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
57354f8f 2985 if (st == 0) {
b6cb41b2 2986 if ((six & (0x8 >> (2 * i))) == 0) {
0ef83bf2
MCA
2987 r->VsrD(i) = ror64(a->VsrD(i), 1) ^
2988 ror64(a->VsrD(i), 8) ^
730d2ca3 2989 (a->VsrD(i) >> 7);
57354f8f 2990 } else { /* six.bit[2*i] == 1 */
0ef83bf2
MCA
2991 r->VsrD(i) = ror64(a->VsrD(i), 19) ^
2992 ror64(a->VsrD(i), 61) ^
730d2ca3 2993 (a->VsrD(i) >> 6);
57354f8f
TM
2994 }
2995 } else { /* st == 1 */
b6cb41b2 2996 if ((six & (0x8 >> (2 * i))) == 0) {
0ef83bf2
MCA
2997 r->VsrD(i) = ror64(a->VsrD(i), 28) ^
2998 ror64(a->VsrD(i), 34) ^
2999 ror64(a->VsrD(i), 39);
57354f8f 3000 } else { /* six.bit[2*i] == 1 */
0ef83bf2
MCA
3001 r->VsrD(i) = ror64(a->VsrD(i), 14) ^
3002 ror64(a->VsrD(i), 18) ^
3003 ror64(a->VsrD(i), 41);
57354f8f
TM
3004 }
3005 }
3006 }
3007}
3008
ac174549
TM
3009void helper_vpermxor(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
3010{
65cf1f65 3011 ppc_avr_t result;
ac174549 3012 int i;
65cf1f65 3013
60594fea
MCA
3014 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
3015 int indexA = c->VsrB(i) >> 4;
3016 int indexB = c->VsrB(i) & 0xF;
3017
3018 result.VsrB(i) = a->VsrB(indexA) ^ b->VsrB(indexB);
ac174549 3019 }
65cf1f65 3020 *r = result;
ac174549
TM
3021}
3022
64654ded 3023#undef VECTOR_FOR_INORDER_I
64654ded
BS
3024
3025/*****************************************************************************/
3026/* SPE extension helpers */
3027/* Use a table to make this quicker */
ea6c0dac 3028static const uint8_t hbrev[16] = {
64654ded
BS
3029 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
3030 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
3031};
3032
3033static inline uint8_t byte_reverse(uint8_t val)
3034{
3035 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
3036}
3037
3038static inline uint32_t word_reverse(uint32_t val)
3039{
3040 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
3041 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
3042}
3043
3044#define MASKBITS 16 /* Random value - to be fixed (implementation dependent) */
3045target_ulong helper_brinc(target_ulong arg1, target_ulong arg2)
3046{
3047 uint32_t a, b, d, mask;
3048
3049 mask = UINT32_MAX >> (32 - MASKBITS);
3050 a = arg1 & mask;
3051 b = arg2 & mask;
3052 d = word_reverse(1 + word_reverse(a | ~b));
3053 return (arg1 & ~mask) | (d & b);
3054}
3055
3056uint32_t helper_cntlsw32(uint32_t val)
3057{
3058 if (val & 0x80000000) {
3059 return clz32(~val);
3060 } else {
3061 return clz32(val);
3062 }
3063}
3064
3065uint32_t helper_cntlzw32(uint32_t val)
3066{
3067 return clz32(val);
3068}
3069
3070/* 440 specific */
d15f74fb
BS
3071target_ulong helper_dlmzb(CPUPPCState *env, target_ulong high,
3072 target_ulong low, uint32_t update_Rc)
64654ded
BS
3073{
3074 target_ulong mask;
3075 int i;
3076
3077 i = 1;
3078 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
3079 if ((high & mask) == 0) {
3080 if (update_Rc) {
3081 env->crf[0] = 0x4;
3082 }
3083 goto done;
3084 }
3085 i++;
3086 }
3087 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
3088 if ((low & mask) == 0) {
3089 if (update_Rc) {
3090 env->crf[0] = 0x8;
3091 }
3092 goto done;
3093 }
3094 i++;
3095 }
ebbd8b40 3096 i = 8;
64654ded
BS
3097 if (update_Rc) {
3098 env->crf[0] = 0x2;
3099 }
3100 done:
3101 env->xer = (env->xer & ~0x7F) | i;
3102 if (update_Rc) {
3103 env->crf[0] |= xer_so;
3104 }
3105 return i;
3106}