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