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