]> Git Repo - qemu.git/blame - target-ppc/int_helper.c
target-ppc: Altivec 2.07: Doubleword Compares
[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
9 * version 2 of the License, or (at your option) any later version.
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 */
19#include "cpu.h"
1de7afc9 20#include "qemu/host-utils.h"
64654ded
BS
21#include "helper.h"
22
23#include "helper_regs.h"
24/*****************************************************************************/
25/* Fixed point operations helpers */
26#if defined(TARGET_PPC64)
27
d15f74fb 28uint64_t helper_mulldo(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
64654ded
BS
29{
30 int64_t th;
31 uint64_t tl;
32
33 muls64(&tl, (uint64_t *)&th, arg1, arg2);
34 /* If th != 0 && th != -1, then we had an overflow */
35 if (likely((uint64_t)(th + 1) <= 1)) {
da91a00f 36 env->ov = 0;
64654ded 37 } else {
da91a00f 38 env->so = env->ov = 1;
64654ded
BS
39 }
40 return (int64_t)tl;
41}
42#endif
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) {
65 if (unlikely(overflow)) {
66 env->so = env->ov = 1;
67 } else {
68 env->ov = 0;
69 }
70 }
71
72 return (target_ulong)rt;
73}
74
a98eb9e9
TM
75target_ulong helper_divwe(CPUPPCState *env, target_ulong ra, target_ulong rb,
76 uint32_t oe)
77{
78 int64_t rt = 0;
79 int overflow = 0;
80
81 int64_t dividend = (int64_t)ra << 32;
82 int64_t divisor = (int64_t)((int32_t)rb);
83
84 if (unlikely((divisor == 0) ||
85 ((divisor == -1ull) && (dividend == INT64_MIN)))) {
86 overflow = 1;
87 } else {
88 rt = dividend / divisor;
89 overflow = rt != (int32_t)rt;
90 }
91
92 if (unlikely(overflow)) {
93 rt = 0; /* Undefined */
94 }
95
96 if (oe) {
97 if (unlikely(overflow)) {
98 env->so = env->ov = 1;
99 } else {
100 env->ov = 0;
101 }
102 }
103
104 return (target_ulong)rt;
105}
106
98d1eb27
TM
107#if defined(TARGET_PPC64)
108
109uint64_t helper_divdeu(CPUPPCState *env, uint64_t ra, uint64_t rb, uint32_t oe)
110{
111 uint64_t rt = 0;
112 int overflow = 0;
113
114 overflow = divu128(&rt, &ra, rb);
115
116 if (unlikely(overflow)) {
117 rt = 0; /* Undefined */
118 }
119
120 if (oe) {
121 if (unlikely(overflow)) {
122 env->so = env->ov = 1;
123 } else {
124 env->ov = 0;
125 }
126 }
127
128 return rt;
129}
130
e44259b6
TM
131uint64_t helper_divde(CPUPPCState *env, uint64_t rau, uint64_t rbu, uint32_t oe)
132{
133 int64_t rt = 0;
134 int64_t ra = (int64_t)rau;
135 int64_t rb = (int64_t)rbu;
136 int overflow = divs128(&rt, &ra, rb);
137
138 if (unlikely(overflow)) {
139 rt = 0; /* Undefined */
140 }
141
142 if (oe) {
143
144 if (unlikely(overflow)) {
145 env->so = env->ov = 1;
146 } else {
147 env->ov = 0;
148 }
149 }
150
151 return rt;
152}
153
98d1eb27
TM
154#endif
155
156
64654ded
BS
157target_ulong helper_cntlzw(target_ulong t)
158{
159 return clz32(t);
160}
161
162#if defined(TARGET_PPC64)
163target_ulong helper_cntlzd(target_ulong t)
164{
165 return clz64(t);
166}
167#endif
168
86ba37ed
TM
169#if defined(TARGET_PPC64)
170
171uint64_t helper_bpermd(uint64_t rs, uint64_t rb)
172{
173 int i;
174 uint64_t ra = 0;
175
176 for (i = 0; i < 8; i++) {
177 int index = (rs >> (i*8)) & 0xFF;
178 if (index < 64) {
179 if (rb & (1ull << (63-index))) {
180 ra |= 1 << i;
181 }
182 }
183 }
184 return ra;
185}
186
187#endif
188
fcfda20f
AJ
189target_ulong helper_cmpb(target_ulong rs, target_ulong rb)
190{
191 target_ulong mask = 0xff;
192 target_ulong ra = 0;
193 int i;
194
195 for (i = 0; i < sizeof(target_ulong); i++) {
196 if ((rs & mask) == (rb & mask)) {
197 ra |= mask;
198 }
199 mask <<= 8;
200 }
201 return ra;
202}
203
64654ded 204/* shift right arithmetic helper */
d15f74fb
BS
205target_ulong helper_sraw(CPUPPCState *env, target_ulong value,
206 target_ulong shift)
64654ded
BS
207{
208 int32_t ret;
209
210 if (likely(!(shift & 0x20))) {
211 if (likely((uint32_t)shift != 0)) {
212 shift &= 0x1f;
213 ret = (int32_t)value >> shift;
214 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
da91a00f 215 env->ca = 0;
64654ded 216 } else {
da91a00f 217 env->ca = 1;
64654ded
BS
218 }
219 } else {
220 ret = (int32_t)value;
da91a00f 221 env->ca = 0;
64654ded
BS
222 }
223 } else {
224 ret = (int32_t)value >> 31;
da91a00f 225 env->ca = (ret != 0);
64654ded
BS
226 }
227 return (target_long)ret;
228}
229
230#if defined(TARGET_PPC64)
d15f74fb
BS
231target_ulong helper_srad(CPUPPCState *env, target_ulong value,
232 target_ulong shift)
64654ded
BS
233{
234 int64_t ret;
235
236 if (likely(!(shift & 0x40))) {
237 if (likely((uint64_t)shift != 0)) {
238 shift &= 0x3f;
239 ret = (int64_t)value >> shift;
240 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
da91a00f 241 env->ca = 0;
64654ded 242 } else {
da91a00f 243 env->ca = 1;
64654ded
BS
244 }
245 } else {
246 ret = (int64_t)value;
da91a00f 247 env->ca = 0;
64654ded
BS
248 }
249 } else {
250 ret = (int64_t)value >> 63;
da91a00f 251 env->ca = (ret != 0);
64654ded
BS
252 }
253 return ret;
254}
255#endif
256
257#if defined(TARGET_PPC64)
258target_ulong helper_popcntb(target_ulong val)
259{
260 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
261 0x5555555555555555ULL);
262 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
263 0x3333333333333333ULL);
264 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
265 0x0f0f0f0f0f0f0f0fULL);
266 return val;
267}
268
269target_ulong helper_popcntw(target_ulong val)
270{
271 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
272 0x5555555555555555ULL);
273 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
274 0x3333333333333333ULL);
275 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
276 0x0f0f0f0f0f0f0f0fULL);
277 val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) &
278 0x00ff00ff00ff00ffULL);
279 val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
280 0x0000ffff0000ffffULL);
281 return val;
282}
283
284target_ulong helper_popcntd(target_ulong val)
285{
286 return ctpop64(val);
287}
288#else
289target_ulong helper_popcntb(target_ulong val)
290{
291 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
292 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
293 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
294 return val;
295}
296
297target_ulong helper_popcntw(target_ulong val)
298{
299 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
300 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
301 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
302 val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff);
303 val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
304 return val;
305}
306#endif
307
308/*****************************************************************************/
309/* PowerPC 601 specific instructions (POWER bridge) */
d15f74fb 310target_ulong helper_div(CPUPPCState *env, target_ulong arg1, target_ulong arg2)
64654ded
BS
311{
312 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
313
314 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
315 (int32_t)arg2 == 0) {
316 env->spr[SPR_MQ] = 0;
317 return INT32_MIN;
318 } else {
319 env->spr[SPR_MQ] = tmp % arg2;
320 return tmp / (int32_t)arg2;
321 }
322}
323
d15f74fb
BS
324target_ulong helper_divo(CPUPPCState *env, target_ulong arg1,
325 target_ulong arg2)
64654ded
BS
326{
327 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
328
329 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
330 (int32_t)arg2 == 0) {
da91a00f 331 env->so = env->ov = 1;
64654ded
BS
332 env->spr[SPR_MQ] = 0;
333 return INT32_MIN;
334 } else {
335 env->spr[SPR_MQ] = tmp % arg2;
336 tmp /= (int32_t)arg2;
337 if ((int32_t)tmp != tmp) {
da91a00f 338 env->so = env->ov = 1;
64654ded 339 } else {
da91a00f 340 env->ov = 0;
64654ded
BS
341 }
342 return tmp;
343 }
344}
345
d15f74fb
BS
346target_ulong helper_divs(CPUPPCState *env, target_ulong arg1,
347 target_ulong arg2)
64654ded
BS
348{
349 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
350 (int32_t)arg2 == 0) {
351 env->spr[SPR_MQ] = 0;
352 return INT32_MIN;
353 } else {
354 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
355 return (int32_t)arg1 / (int32_t)arg2;
356 }
357}
358
d15f74fb
BS
359target_ulong helper_divso(CPUPPCState *env, target_ulong arg1,
360 target_ulong arg2)
64654ded
BS
361{
362 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
363 (int32_t)arg2 == 0) {
da91a00f 364 env->so = env->ov = 1;
64654ded
BS
365 env->spr[SPR_MQ] = 0;
366 return INT32_MIN;
367 } else {
da91a00f 368 env->ov = 0;
64654ded
BS
369 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
370 return (int32_t)arg1 / (int32_t)arg2;
371 }
372}
373
374/*****************************************************************************/
375/* 602 specific instructions */
376/* mfrom is the most crazy instruction ever seen, imho ! */
377/* Real implementation uses a ROM table. Do the same */
378/* Extremely decomposed:
379 * -arg / 256
380 * return 256 * log10(10 + 1.0) + 0.5
381 */
382#if !defined(CONFIG_USER_ONLY)
383target_ulong helper_602_mfrom(target_ulong arg)
384{
385 if (likely(arg < 602)) {
386#include "mfrom_table.c"
387 return mfrom_ROM_table[arg];
388 } else {
389 return 0;
390 }
391}
392#endif
393
394/*****************************************************************************/
395/* Altivec extension helpers */
396#if defined(HOST_WORDS_BIGENDIAN)
397#define HI_IDX 0
398#define LO_IDX 1
399#else
400#define HI_IDX 1
401#define LO_IDX 0
402#endif
403
404#if defined(HOST_WORDS_BIGENDIAN)
405#define VECTOR_FOR_INORDER_I(index, element) \
406 for (index = 0; index < ARRAY_SIZE(r->element); index++)
407#else
408#define VECTOR_FOR_INORDER_I(index, element) \
409 for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
410#endif
411
64654ded
BS
412/* Saturating arithmetic helpers. */
413#define SATCVT(from, to, from_type, to_type, min, max) \
414 static inline to_type cvt##from##to(from_type x, int *sat) \
415 { \
416 to_type r; \
417 \
418 if (x < (from_type)min) { \
419 r = min; \
420 *sat = 1; \
421 } else if (x > (from_type)max) { \
422 r = max; \
423 *sat = 1; \
424 } else { \
425 r = x; \
426 } \
427 return r; \
428 }
429#define SATCVTU(from, to, from_type, to_type, min, max) \
430 static inline to_type cvt##from##to(from_type x, int *sat) \
431 { \
432 to_type r; \
433 \
434 if (x > (from_type)max) { \
435 r = max; \
436 *sat = 1; \
437 } else { \
438 r = x; \
439 } \
440 return r; \
441 }
442SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
443SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
444SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
445
446SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
447SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
448SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
449SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
450SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
451SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
452#undef SATCVT
453#undef SATCVTU
454
455void helper_lvsl(ppc_avr_t *r, target_ulong sh)
456{
457 int i, j = (sh & 0xf);
458
459 VECTOR_FOR_INORDER_I(i, u8) {
460 r->u8[i] = j++;
461 }
462}
463
464void helper_lvsr(ppc_avr_t *r, target_ulong sh)
465{
466 int i, j = 0x10 - (sh & 0xf);
467
468 VECTOR_FOR_INORDER_I(i, u8) {
469 r->u8[i] = j++;
470 }
471}
472
d15f74fb 473void helper_mtvscr(CPUPPCState *env, ppc_avr_t *r)
64654ded
BS
474{
475#if defined(HOST_WORDS_BIGENDIAN)
476 env->vscr = r->u32[3];
477#else
478 env->vscr = r->u32[0];
479#endif
480 set_flush_to_zero(vscr_nj, &env->vec_status);
481}
482
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
492#define VARITH_DO(name, op, element) \
493 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
494 { \
495 int i; \
496 \
497 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
498 r->element[i] = a->element[i] op b->element[i]; \
499 } \
500 }
501#define VARITH(suffix, element) \
502 VARITH_DO(add##suffix, +, element) \
503 VARITH_DO(sub##suffix, -, element)
504VARITH(ubm, u8)
505VARITH(uhm, u16)
506VARITH(uwm, u32)
56eabc75 507VARITH(udm, u64)
953f0f58 508VARITH_DO(muluwm, *, u32)
64654ded
BS
509#undef VARITH_DO
510#undef VARITH
511
512#define VARITHFP(suffix, func) \
d15f74fb
BS
513 void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
514 ppc_avr_t *b) \
64654ded
BS
515 { \
516 int i; \
517 \
518 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
ef9bd150 519 r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
64654ded
BS
520 } \
521 }
522VARITHFP(addfp, float32_add)
523VARITHFP(subfp, float32_sub)
db1babb8
AJ
524VARITHFP(minfp, float32_min)
525VARITHFP(maxfp, float32_max)
64654ded
BS
526#undef VARITHFP
527
2f93c23f
AJ
528#define VARITHFPFMA(suffix, type) \
529 void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
530 ppc_avr_t *b, ppc_avr_t *c) \
531 { \
532 int i; \
533 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
534 r->f[i] = float32_muladd(a->f[i], c->f[i], b->f[i], \
535 type, &env->vec_status); \
536 } \
537 }
538VARITHFPFMA(maddfp, 0);
539VARITHFPFMA(nmsubfp, float_muladd_negate_result | float_muladd_negate_c);
540#undef VARITHFPFMA
541
64654ded
BS
542#define VARITHSAT_CASE(type, op, cvt, element) \
543 { \
544 type result = (type)a->element[i] op (type)b->element[i]; \
545 r->element[i] = cvt(result, &sat); \
546 }
547
548#define VARITHSAT_DO(name, op, optype, cvt, element) \
d15f74fb
BS
549 void helper_v##name(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
550 ppc_avr_t *b) \
64654ded
BS
551 { \
552 int sat = 0; \
553 int i; \
554 \
555 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
556 switch (sizeof(r->element[0])) { \
557 case 1: \
558 VARITHSAT_CASE(optype, op, cvt, element); \
559 break; \
560 case 2: \
561 VARITHSAT_CASE(optype, op, cvt, element); \
562 break; \
563 case 4: \
564 VARITHSAT_CASE(optype, op, cvt, element); \
565 break; \
566 } \
567 } \
568 if (sat) { \
569 env->vscr |= (1 << VSCR_SAT); \
570 } \
571 }
572#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
573 VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
574 VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
575#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
576 VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
577 VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
578VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
579VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
580VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
581VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
582VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
583VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
584#undef VARITHSAT_CASE
585#undef VARITHSAT_DO
586#undef VARITHSAT_SIGNED
587#undef VARITHSAT_UNSIGNED
588
589#define VAVG_DO(name, element, etype) \
590 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
591 { \
592 int i; \
593 \
594 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
595 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
596 r->element[i] = x >> 1; \
597 } \
598 }
599
600#define VAVG(type, signed_element, signed_type, unsigned_element, \
601 unsigned_type) \
602 VAVG_DO(avgs##type, signed_element, signed_type) \
603 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
604VAVG(b, s8, int16_t, u8, uint16_t)
605VAVG(h, s16, int32_t, u16, uint32_t)
606VAVG(w, s32, int64_t, u32, uint64_t)
607#undef VAVG_DO
608#undef VAVG
609
610#define VCF(suffix, cvt, element) \
d15f74fb
BS
611 void helper_vcf##suffix(CPUPPCState *env, ppc_avr_t *r, \
612 ppc_avr_t *b, uint32_t uim) \
64654ded
BS
613 { \
614 int i; \
615 \
616 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
617 float32 t = cvt(b->element[i], &env->vec_status); \
618 r->f[i] = float32_scalbn(t, -uim, &env->vec_status); \
619 } \
620 }
621VCF(ux, uint32_to_float32, u32)
622VCF(sx, int32_to_float32, s32)
623#undef VCF
624
625#define VCMP_DO(suffix, compare, element, record) \
d15f74fb
BS
626 void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
627 ppc_avr_t *a, ppc_avr_t *b) \
64654ded 628 { \
6f3dab41
TM
629 uint64_t ones = (uint64_t)-1; \
630 uint64_t all = ones; \
631 uint64_t none = 0; \
64654ded
BS
632 int i; \
633 \
634 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
6f3dab41 635 uint64_t result = (a->element[i] compare b->element[i] ? \
64654ded
BS
636 ones : 0x0); \
637 switch (sizeof(a->element[0])) { \
6f3dab41
TM
638 case 8: \
639 r->u64[i] = result; \
640 break; \
64654ded
BS
641 case 4: \
642 r->u32[i] = result; \
643 break; \
644 case 2: \
645 r->u16[i] = result; \
646 break; \
647 case 1: \
648 r->u8[i] = result; \
649 break; \
650 } \
651 all &= result; \
652 none |= result; \
653 } \
654 if (record) { \
655 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
656 } \
657 }
658#define VCMP(suffix, compare, element) \
659 VCMP_DO(suffix, compare, element, 0) \
660 VCMP_DO(suffix##_dot, compare, element, 1)
661VCMP(equb, ==, u8)
662VCMP(equh, ==, u16)
663VCMP(equw, ==, u32)
6f3dab41 664VCMP(equd, ==, u64)
64654ded
BS
665VCMP(gtub, >, u8)
666VCMP(gtuh, >, u16)
667VCMP(gtuw, >, u32)
6f3dab41 668VCMP(gtud, >, u64)
64654ded
BS
669VCMP(gtsb, >, s8)
670VCMP(gtsh, >, s16)
671VCMP(gtsw, >, s32)
6f3dab41 672VCMP(gtsd, >, s64)
64654ded
BS
673#undef VCMP_DO
674#undef VCMP
675
676#define VCMPFP_DO(suffix, compare, order, record) \
d15f74fb
BS
677 void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
678 ppc_avr_t *a, ppc_avr_t *b) \
64654ded
BS
679 { \
680 uint32_t ones = (uint32_t)-1; \
681 uint32_t all = ones; \
682 uint32_t none = 0; \
683 int i; \
684 \
685 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
686 uint32_t result; \
687 int rel = float32_compare_quiet(a->f[i], b->f[i], \
688 &env->vec_status); \
689 if (rel == float_relation_unordered) { \
690 result = 0; \
691 } else if (rel compare order) { \
692 result = ones; \
693 } else { \
694 result = 0; \
695 } \
696 r->u32[i] = result; \
697 all &= result; \
698 none |= result; \
699 } \
700 if (record) { \
701 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
702 } \
703 }
704#define VCMPFP(suffix, compare, order) \
705 VCMPFP_DO(suffix, compare, order, 0) \
706 VCMPFP_DO(suffix##_dot, compare, order, 1)
707VCMPFP(eqfp, ==, float_relation_equal)
708VCMPFP(gefp, !=, float_relation_less)
709VCMPFP(gtfp, ==, float_relation_greater)
710#undef VCMPFP_DO
711#undef VCMPFP
712
d15f74fb
BS
713static inline void vcmpbfp_internal(CPUPPCState *env, ppc_avr_t *r,
714 ppc_avr_t *a, ppc_avr_t *b, int record)
64654ded
BS
715{
716 int i;
717 int all_in = 0;
718
719 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
720 int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
721 if (le_rel == float_relation_unordered) {
722 r->u32[i] = 0xc0000000;
723 /* ALL_IN does not need to be updated here. */
724 } else {
725 float32 bneg = float32_chs(b->f[i]);
726 int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
727 int le = le_rel != float_relation_greater;
728 int ge = ge_rel != float_relation_less;
729
730 r->u32[i] = ((!le) << 31) | ((!ge) << 30);
731 all_in |= (!le | !ge);
732 }
733 }
734 if (record) {
735 env->crf[6] = (all_in == 0) << 1;
736 }
737}
738
d15f74fb 739void helper_vcmpbfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded 740{
d15f74fb 741 vcmpbfp_internal(env, r, a, b, 0);
64654ded
BS
742}
743
d15f74fb
BS
744void helper_vcmpbfp_dot(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
745 ppc_avr_t *b)
64654ded 746{
d15f74fb 747 vcmpbfp_internal(env, r, a, b, 1);
64654ded
BS
748}
749
750#define VCT(suffix, satcvt, element) \
d15f74fb
BS
751 void helper_vct##suffix(CPUPPCState *env, ppc_avr_t *r, \
752 ppc_avr_t *b, uint32_t uim) \
64654ded
BS
753 { \
754 int i; \
755 int sat = 0; \
756 float_status s = env->vec_status; \
757 \
758 set_float_rounding_mode(float_round_to_zero, &s); \
759 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
760 if (float32_is_any_nan(b->f[i])) { \
761 r->element[i] = 0; \
762 } else { \
763 float64 t = float32_to_float64(b->f[i], &s); \
764 int64_t j; \
765 \
766 t = float64_scalbn(t, uim, &s); \
767 j = float64_to_int64(t, &s); \
768 r->element[i] = satcvt(j, &sat); \
769 } \
770 } \
771 if (sat) { \
772 env->vscr |= (1 << VSCR_SAT); \
773 } \
774 }
775VCT(uxs, cvtsduw, u32)
776VCT(sxs, cvtsdsw, s32)
777#undef VCT
778
d15f74fb
BS
779void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
780 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
781{
782 int sat = 0;
783 int i;
784
785 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
786 int32_t prod = a->s16[i] * b->s16[i];
787 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
788
789 r->s16[i] = cvtswsh(t, &sat);
790 }
791
792 if (sat) {
793 env->vscr |= (1 << VSCR_SAT);
794 }
795}
796
d15f74fb
BS
797void helper_vmhraddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
798 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
799{
800 int sat = 0;
801 int i;
802
803 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
804 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
805 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
806 r->s16[i] = cvtswsh(t, &sat);
807 }
808
809 if (sat) {
810 env->vscr |= (1 << VSCR_SAT);
811 }
812}
813
814#define VMINMAX_DO(name, compare, element) \
815 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
816 { \
817 int i; \
818 \
819 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
820 if (a->element[i] compare b->element[i]) { \
821 r->element[i] = b->element[i]; \
822 } else { \
823 r->element[i] = a->element[i]; \
824 } \
825 } \
826 }
827#define VMINMAX(suffix, element) \
828 VMINMAX_DO(min##suffix, >, element) \
829 VMINMAX_DO(max##suffix, <, element)
830VMINMAX(sb, s8)
831VMINMAX(sh, s16)
832VMINMAX(sw, s32)
8203e31b 833VMINMAX(sd, s64)
64654ded
BS
834VMINMAX(ub, u8)
835VMINMAX(uh, u16)
836VMINMAX(uw, u32)
8203e31b 837VMINMAX(ud, u64)
64654ded
BS
838#undef VMINMAX_DO
839#undef VMINMAX
840
64654ded
BS
841void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
842{
843 int i;
844
845 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
846 int32_t prod = a->s16[i] * b->s16[i];
847 r->s16[i] = (int16_t) (prod + c->s16[i]);
848 }
849}
850
851#define VMRG_DO(name, element, highp) \
852 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
853 { \
854 ppc_avr_t result; \
855 int i; \
856 size_t n_elems = ARRAY_SIZE(r->element); \
857 \
858 for (i = 0; i < n_elems / 2; i++) { \
859 if (highp) { \
860 result.element[i*2+HI_IDX] = a->element[i]; \
861 result.element[i*2+LO_IDX] = b->element[i]; \
862 } else { \
863 result.element[n_elems - i * 2 - (1 + HI_IDX)] = \
864 b->element[n_elems - i - 1]; \
865 result.element[n_elems - i * 2 - (1 + LO_IDX)] = \
866 a->element[n_elems - i - 1]; \
867 } \
868 } \
869 *r = result; \
870 }
871#if defined(HOST_WORDS_BIGENDIAN)
872#define MRGHI 0
873#define MRGLO 1
874#else
875#define MRGHI 1
876#define MRGLO 0
877#endif
878#define VMRG(suffix, element) \
879 VMRG_DO(mrgl##suffix, element, MRGHI) \
880 VMRG_DO(mrgh##suffix, element, MRGLO)
881VMRG(b, u8)
882VMRG(h, u16)
883VMRG(w, u32)
884#undef VMRG_DO
885#undef VMRG
886#undef MRGHI
887#undef MRGLO
888
d15f74fb
BS
889void helper_vmsummbm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
890 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
891{
892 int32_t prod[16];
893 int i;
894
895 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
896 prod[i] = (int32_t)a->s8[i] * b->u8[i];
897 }
898
899 VECTOR_FOR_INORDER_I(i, s32) {
900 r->s32[i] = c->s32[i] + prod[4 * i] + prod[4 * i + 1] +
901 prod[4 * i + 2] + prod[4 * i + 3];
902 }
903}
904
d15f74fb
BS
905void helper_vmsumshm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
906 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
907{
908 int32_t prod[8];
909 int i;
910
911 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
912 prod[i] = a->s16[i] * b->s16[i];
913 }
914
915 VECTOR_FOR_INORDER_I(i, s32) {
916 r->s32[i] = c->s32[i] + prod[2 * i] + prod[2 * i + 1];
917 }
918}
919
d15f74fb
BS
920void helper_vmsumshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
921 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
922{
923 int32_t prod[8];
924 int i;
925 int sat = 0;
926
927 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
928 prod[i] = (int32_t)a->s16[i] * b->s16[i];
929 }
930
931 VECTOR_FOR_INORDER_I(i, s32) {
932 int64_t t = (int64_t)c->s32[i] + prod[2 * i] + prod[2 * i + 1];
933
934 r->u32[i] = cvtsdsw(t, &sat);
935 }
936
937 if (sat) {
938 env->vscr |= (1 << VSCR_SAT);
939 }
940}
941
d15f74fb
BS
942void helper_vmsumubm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
943 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
944{
945 uint16_t prod[16];
946 int i;
947
948 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
949 prod[i] = a->u8[i] * b->u8[i];
950 }
951
952 VECTOR_FOR_INORDER_I(i, u32) {
953 r->u32[i] = c->u32[i] + prod[4 * i] + prod[4 * i + 1] +
954 prod[4 * i + 2] + prod[4 * i + 3];
955 }
956}
957
d15f74fb
BS
958void helper_vmsumuhm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
959 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
960{
961 uint32_t prod[8];
962 int i;
963
964 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
965 prod[i] = a->u16[i] * b->u16[i];
966 }
967
968 VECTOR_FOR_INORDER_I(i, u32) {
969 r->u32[i] = c->u32[i] + prod[2 * i] + prod[2 * i + 1];
970 }
971}
972
d15f74fb
BS
973void helper_vmsumuhs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
974 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
975{
976 uint32_t prod[8];
977 int i;
978 int sat = 0;
979
980 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
981 prod[i] = a->u16[i] * b->u16[i];
982 }
983
984 VECTOR_FOR_INORDER_I(i, s32) {
985 uint64_t t = (uint64_t)c->u32[i] + prod[2 * i] + prod[2 * i + 1];
986
987 r->u32[i] = cvtuduw(t, &sat);
988 }
989
990 if (sat) {
991 env->vscr |= (1 << VSCR_SAT);
992 }
993}
994
aa9e930c 995#define VMUL_DO(name, mul_element, prod_element, cast, evenp) \
64654ded
BS
996 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
997 { \
998 int i; \
999 \
1000 VECTOR_FOR_INORDER_I(i, prod_element) { \
1001 if (evenp) { \
aa9e930c
TM
1002 r->prod_element[i] = \
1003 (cast)a->mul_element[i * 2 + HI_IDX] * \
1004 (cast)b->mul_element[i * 2 + HI_IDX]; \
64654ded 1005 } else { \
aa9e930c
TM
1006 r->prod_element[i] = \
1007 (cast)a->mul_element[i * 2 + LO_IDX] * \
1008 (cast)b->mul_element[i * 2 + LO_IDX]; \
64654ded
BS
1009 } \
1010 } \
1011 }
aa9e930c
TM
1012#define VMUL(suffix, mul_element, prod_element, cast) \
1013 VMUL_DO(mule##suffix, mul_element, prod_element, cast, 1) \
1014 VMUL_DO(mulo##suffix, mul_element, prod_element, cast, 0)
1015VMUL(sb, s8, s16, int16_t)
1016VMUL(sh, s16, s32, int32_t)
63be0936 1017VMUL(sw, s32, s64, int64_t)
aa9e930c
TM
1018VMUL(ub, u8, u16, uint16_t)
1019VMUL(uh, u16, u32, uint32_t)
63be0936 1020VMUL(uw, u32, u64, uint64_t)
64654ded
BS
1021#undef VMUL_DO
1022#undef VMUL
1023
d15f74fb
BS
1024void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
1025 ppc_avr_t *c)
64654ded
BS
1026{
1027 ppc_avr_t result;
1028 int i;
1029
1030 VECTOR_FOR_INORDER_I(i, u8) {
1031 int s = c->u8[i] & 0x1f;
1032#if defined(HOST_WORDS_BIGENDIAN)
1033 int index = s & 0xf;
1034#else
1035 int index = 15 - (s & 0xf);
1036#endif
1037
1038 if (s & 0x10) {
1039 result.u8[i] = b->u8[index];
1040 } else {
1041 result.u8[i] = a->u8[index];
1042 }
1043 }
1044 *r = result;
1045}
1046
4d82038e
TM
1047#if defined(HOST_WORDS_BIGENDIAN)
1048#define VBPERMQ_INDEX(avr, i) ((avr)->u8[(i)])
1049#define VBPERMQ_DW(index) (((index) & 0x40) != 0)
1050#else
1051#define VBPERMQ_INDEX(avr, i) ((avr)->u8[15-(i)])
1052#define VBPERMQ_DW(index) (((index) & 0x40) == 0)
1053#endif
1054
1055void helper_vbpermq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1056{
1057 int i;
1058 uint64_t perm = 0;
1059
1060 VECTOR_FOR_INORDER_I(i, u8) {
1061 int index = VBPERMQ_INDEX(b, i);
1062
1063 if (index < 128) {
1064 uint64_t mask = (1ull << (63-(index & 0x3F)));
1065 if (a->u64[VBPERMQ_DW(index)] & mask) {
1066 perm |= (0x8000 >> i);
1067 }
1068 }
1069 }
1070
1071 r->u64[HI_IDX] = perm;
1072 r->u64[LO_IDX] = 0;
1073}
1074
1075#undef VBPERMQ_INDEX
1076#undef VBPERMQ_DW
1077
64654ded
BS
1078#if defined(HOST_WORDS_BIGENDIAN)
1079#define PKBIG 1
1080#else
1081#define PKBIG 0
1082#endif
1083void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1084{
1085 int i, j;
1086 ppc_avr_t result;
1087#if defined(HOST_WORDS_BIGENDIAN)
1088 const ppc_avr_t *x[2] = { a, b };
1089#else
1090 const ppc_avr_t *x[2] = { b, a };
1091#endif
1092
1093 VECTOR_FOR_INORDER_I(i, u64) {
1094 VECTOR_FOR_INORDER_I(j, u32) {
1095 uint32_t e = x[i]->u32[j];
1096
1097 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
1098 ((e >> 6) & 0x3e0) |
1099 ((e >> 3) & 0x1f));
1100 }
1101 }
1102 *r = result;
1103}
1104
1105#define VPK(suffix, from, to, cvt, dosat) \
d15f74fb
BS
1106 void helper_vpk##suffix(CPUPPCState *env, ppc_avr_t *r, \
1107 ppc_avr_t *a, ppc_avr_t *b) \
64654ded
BS
1108 { \
1109 int i; \
1110 int sat = 0; \
1111 ppc_avr_t result; \
1112 ppc_avr_t *a0 = PKBIG ? a : b; \
1113 ppc_avr_t *a1 = PKBIG ? b : a; \
1114 \
1115 VECTOR_FOR_INORDER_I(i, from) { \
1116 result.to[i] = cvt(a0->from[i], &sat); \
1117 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
1118 } \
1119 *r = result; \
1120 if (dosat && sat) { \
1121 env->vscr |= (1 << VSCR_SAT); \
1122 } \
1123 }
1124#define I(x, y) (x)
1125VPK(shss, s16, s8, cvtshsb, 1)
1126VPK(shus, s16, u8, cvtshub, 1)
1127VPK(swss, s32, s16, cvtswsh, 1)
1128VPK(swus, s32, u16, cvtswuh, 1)
024215b2
TM
1129VPK(sdss, s64, s32, cvtsdsw, 1)
1130VPK(sdus, s64, u32, cvtsduw, 1)
64654ded
BS
1131VPK(uhus, u16, u8, cvtuhub, 1)
1132VPK(uwus, u32, u16, cvtuwuh, 1)
024215b2 1133VPK(udus, u64, u32, cvtuduw, 1)
64654ded
BS
1134VPK(uhum, u16, u8, I, 0)
1135VPK(uwum, u32, u16, I, 0)
024215b2 1136VPK(udum, u64, u32, I, 0)
64654ded
BS
1137#undef I
1138#undef VPK
1139#undef PKBIG
1140
d15f74fb 1141void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1142{
1143 int i;
1144
1145 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
ef9bd150 1146 r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
64654ded
BS
1147 }
1148}
1149
1150#define VRFI(suffix, rounding) \
d15f74fb
BS
1151 void helper_vrfi##suffix(CPUPPCState *env, ppc_avr_t *r, \
1152 ppc_avr_t *b) \
64654ded
BS
1153 { \
1154 int i; \
1155 float_status s = env->vec_status; \
1156 \
1157 set_float_rounding_mode(rounding, &s); \
1158 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
ef9bd150 1159 r->f[i] = float32_round_to_int (b->f[i], &s); \
64654ded
BS
1160 } \
1161 }
1162VRFI(n, float_round_nearest_even)
1163VRFI(m, float_round_down)
1164VRFI(p, float_round_up)
1165VRFI(z, float_round_to_zero)
1166#undef VRFI
1167
818692ff 1168#define VROTATE(suffix, element, mask) \
64654ded
BS
1169 void helper_vrl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1170 { \
1171 int i; \
1172 \
1173 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
64654ded
BS
1174 unsigned int shift = b->element[i] & mask; \
1175 r->element[i] = (a->element[i] << shift) | \
1176 (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
1177 } \
1178 }
818692ff
TM
1179VROTATE(b, u8, 0x7)
1180VROTATE(h, u16, 0xF)
1181VROTATE(w, u32, 0x1F)
2fdf78e6 1182VROTATE(d, u64, 0x3F)
64654ded
BS
1183#undef VROTATE
1184
d15f74fb 1185void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1186{
1187 int i;
1188
1189 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
ef9bd150 1190 float32 t = float32_sqrt(b->f[i], &env->vec_status);
64654ded 1191
ef9bd150 1192 r->f[i] = float32_div(float32_one, t, &env->vec_status);
64654ded
BS
1193 }
1194}
1195
d15f74fb
BS
1196void helper_vsel(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
1197 ppc_avr_t *c)
64654ded
BS
1198{
1199 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
1200 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
1201}
1202
d15f74fb 1203void helper_vexptefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1204{
1205 int i;
1206
1207 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
ef9bd150 1208 r->f[i] = float32_exp2(b->f[i], &env->vec_status);
64654ded
BS
1209 }
1210}
1211
d15f74fb 1212void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1213{
1214 int i;
1215
1216 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
ef9bd150 1217 r->f[i] = float32_log2(b->f[i], &env->vec_status);
64654ded
BS
1218 }
1219}
1220
1221#if defined(HOST_WORDS_BIGENDIAN)
1222#define LEFT 0
1223#define RIGHT 1
1224#else
1225#define LEFT 1
1226#define RIGHT 0
1227#endif
1228/* The specification says that the results are undefined if all of the
1229 * shift counts are not identical. We check to make sure that they are
1230 * to conform to what real hardware appears to do. */
1231#define VSHIFT(suffix, leftp) \
1232 void helper_vs##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1233 { \
1234 int shift = b->u8[LO_IDX*15] & 0x7; \
1235 int doit = 1; \
1236 int i; \
1237 \
1238 for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
1239 doit = doit && ((b->u8[i] & 0x7) == shift); \
1240 } \
1241 if (doit) { \
1242 if (shift == 0) { \
1243 *r = *a; \
1244 } else if (leftp) { \
1245 uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
1246 \
1247 r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
1248 r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
1249 } else { \
1250 uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
1251 \
1252 r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
1253 r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
1254 } \
1255 } \
1256 }
1257VSHIFT(l, LEFT)
1258VSHIFT(r, RIGHT)
1259#undef VSHIFT
1260#undef LEFT
1261#undef RIGHT
1262
818692ff 1263#define VSL(suffix, element, mask) \
64654ded
BS
1264 void helper_vsl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1265 { \
1266 int i; \
1267 \
1268 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
64654ded
BS
1269 unsigned int shift = b->element[i] & mask; \
1270 \
1271 r->element[i] = a->element[i] << shift; \
1272 } \
1273 }
818692ff
TM
1274VSL(b, u8, 0x7)
1275VSL(h, u16, 0x0F)
1276VSL(w, u32, 0x1F)
2fdf78e6 1277VSL(d, u64, 0x3F)
64654ded
BS
1278#undef VSL
1279
1280void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
1281{
1282 int sh = shift & 0xf;
1283 int i;
1284 ppc_avr_t result;
1285
1286#if defined(HOST_WORDS_BIGENDIAN)
1287 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
1288 int index = sh + i;
1289 if (index > 0xf) {
1290 result.u8[i] = b->u8[index - 0x10];
1291 } else {
1292 result.u8[i] = a->u8[index];
1293 }
1294 }
1295#else
1296 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
1297 int index = (16 - sh) + i;
1298 if (index > 0xf) {
1299 result.u8[i] = a->u8[index - 0x10];
1300 } else {
1301 result.u8[i] = b->u8[index];
1302 }
1303 }
1304#endif
1305 *r = result;
1306}
1307
1308void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1309{
1310 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
1311
1312#if defined(HOST_WORDS_BIGENDIAN)
1313 memmove(&r->u8[0], &a->u8[sh], 16 - sh);
1314 memset(&r->u8[16-sh], 0, sh);
1315#else
1316 memmove(&r->u8[sh], &a->u8[0], 16 - sh);
1317 memset(&r->u8[0], 0, sh);
1318#endif
1319}
1320
1321/* Experimental testing shows that hardware masks the immediate. */
1322#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
1323#if defined(HOST_WORDS_BIGENDIAN)
1324#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
1325#else
1326#define SPLAT_ELEMENT(element) \
1327 (ARRAY_SIZE(r->element) - 1 - _SPLAT_MASKED(element))
1328#endif
1329#define VSPLT(suffix, element) \
1330 void helper_vsplt##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
1331 { \
1332 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
1333 int i; \
1334 \
1335 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1336 r->element[i] = s; \
1337 } \
1338 }
1339VSPLT(b, u8)
1340VSPLT(h, u16)
1341VSPLT(w, u32)
1342#undef VSPLT
1343#undef SPLAT_ELEMENT
1344#undef _SPLAT_MASKED
1345
1346#define VSPLTI(suffix, element, splat_type) \
1347 void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \
1348 { \
1349 splat_type x = (int8_t)(splat << 3) >> 3; \
1350 int i; \
1351 \
1352 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1353 r->element[i] = x; \
1354 } \
1355 }
1356VSPLTI(b, s8, int8_t)
1357VSPLTI(h, s16, int16_t)
1358VSPLTI(w, s32, int32_t)
1359#undef VSPLTI
1360
818692ff 1361#define VSR(suffix, element, mask) \
64654ded
BS
1362 void helper_vsr##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1363 { \
1364 int i; \
1365 \
1366 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
64654ded 1367 unsigned int shift = b->element[i] & mask; \
64654ded
BS
1368 r->element[i] = a->element[i] >> shift; \
1369 } \
1370 }
818692ff
TM
1371VSR(ab, s8, 0x7)
1372VSR(ah, s16, 0xF)
1373VSR(aw, s32, 0x1F)
2fdf78e6 1374VSR(ad, s64, 0x3F)
818692ff
TM
1375VSR(b, u8, 0x7)
1376VSR(h, u16, 0xF)
1377VSR(w, u32, 0x1F)
2fdf78e6 1378VSR(d, u64, 0x3F)
64654ded
BS
1379#undef VSR
1380
1381void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1382{
1383 int sh = (b->u8[LO_IDX * 0xf] >> 3) & 0xf;
1384
1385#if defined(HOST_WORDS_BIGENDIAN)
1386 memmove(&r->u8[sh], &a->u8[0], 16 - sh);
1387 memset(&r->u8[0], 0, sh);
1388#else
1389 memmove(&r->u8[0], &a->u8[sh], 16 - sh);
1390 memset(&r->u8[16 - sh], 0, sh);
1391#endif
1392}
1393
1394void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1395{
1396 int i;
1397
1398 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
1399 r->u32[i] = a->u32[i] >= b->u32[i];
1400 }
1401}
1402
d15f74fb 1403void helper_vsumsws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1404{
1405 int64_t t;
1406 int i, upper;
1407 ppc_avr_t result;
1408 int sat = 0;
1409
1410#if defined(HOST_WORDS_BIGENDIAN)
1411 upper = ARRAY_SIZE(r->s32)-1;
1412#else
1413 upper = 0;
1414#endif
1415 t = (int64_t)b->s32[upper];
1416 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1417 t += a->s32[i];
1418 result.s32[i] = 0;
1419 }
1420 result.s32[upper] = cvtsdsw(t, &sat);
1421 *r = result;
1422
1423 if (sat) {
1424 env->vscr |= (1 << VSCR_SAT);
1425 }
1426}
1427
d15f74fb 1428void helper_vsum2sws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1429{
1430 int i, j, upper;
1431 ppc_avr_t result;
1432 int sat = 0;
1433
1434#if defined(HOST_WORDS_BIGENDIAN)
1435 upper = 1;
1436#else
1437 upper = 0;
1438#endif
1439 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
1440 int64_t t = (int64_t)b->s32[upper + i * 2];
1441
1442 result.u64[i] = 0;
1443 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
1444 t += a->s32[2 * i + j];
1445 }
1446 result.s32[upper + i * 2] = cvtsdsw(t, &sat);
1447 }
1448
1449 *r = result;
1450 if (sat) {
1451 env->vscr |= (1 << VSCR_SAT);
1452 }
1453}
1454
d15f74fb 1455void helper_vsum4sbs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1456{
1457 int i, j;
1458 int sat = 0;
1459
1460 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1461 int64_t t = (int64_t)b->s32[i];
1462
1463 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
1464 t += a->s8[4 * i + j];
1465 }
1466 r->s32[i] = cvtsdsw(t, &sat);
1467 }
1468
1469 if (sat) {
1470 env->vscr |= (1 << VSCR_SAT);
1471 }
1472}
1473
d15f74fb 1474void helper_vsum4shs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1475{
1476 int sat = 0;
1477 int i;
1478
1479 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1480 int64_t t = (int64_t)b->s32[i];
1481
1482 t += a->s16[2 * i] + a->s16[2 * i + 1];
1483 r->s32[i] = cvtsdsw(t, &sat);
1484 }
1485
1486 if (sat) {
1487 env->vscr |= (1 << VSCR_SAT);
1488 }
1489}
1490
d15f74fb 1491void helper_vsum4ubs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1492{
1493 int i, j;
1494 int sat = 0;
1495
1496 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
1497 uint64_t t = (uint64_t)b->u32[i];
1498
1499 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
1500 t += a->u8[4 * i + j];
1501 }
1502 r->u32[i] = cvtuduw(t, &sat);
1503 }
1504
1505 if (sat) {
1506 env->vscr |= (1 << VSCR_SAT);
1507 }
1508}
1509
1510#if defined(HOST_WORDS_BIGENDIAN)
1511#define UPKHI 1
1512#define UPKLO 0
1513#else
1514#define UPKHI 0
1515#define UPKLO 1
1516#endif
1517#define VUPKPX(suffix, hi) \
1518 void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
1519 { \
1520 int i; \
1521 ppc_avr_t result; \
1522 \
1523 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
1524 uint16_t e = b->u16[hi ? i : i+4]; \
1525 uint8_t a = (e >> 15) ? 0xff : 0; \
1526 uint8_t r = (e >> 10) & 0x1f; \
1527 uint8_t g = (e >> 5) & 0x1f; \
1528 uint8_t b = e & 0x1f; \
1529 \
1530 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
1531 } \
1532 *r = result; \
1533 }
1534VUPKPX(lpx, UPKLO)
1535VUPKPX(hpx, UPKHI)
1536#undef VUPKPX
1537
1538#define VUPK(suffix, unpacked, packee, hi) \
1539 void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
1540 { \
1541 int i; \
1542 ppc_avr_t result; \
1543 \
1544 if (hi) { \
1545 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
1546 result.unpacked[i] = b->packee[i]; \
1547 } \
1548 } else { \
1549 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); \
1550 i++) { \
1551 result.unpacked[i - ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
1552 } \
1553 } \
1554 *r = result; \
1555 }
1556VUPK(hsb, s16, s8, UPKHI)
1557VUPK(hsh, s32, s16, UPKHI)
4430e076 1558VUPK(hsw, s64, s32, UPKHI)
64654ded
BS
1559VUPK(lsb, s16, s8, UPKLO)
1560VUPK(lsh, s32, s16, UPKLO)
4430e076 1561VUPK(lsw, s64, s32, UPKLO)
64654ded
BS
1562#undef VUPK
1563#undef UPKHI
1564#undef UPKLO
1565
f293f04a
TM
1566#define VGENERIC_DO(name, element) \
1567 void helper_v##name(ppc_avr_t *r, ppc_avr_t *b) \
1568 { \
1569 int i; \
1570 \
1571 VECTOR_FOR_INORDER_I(i, element) { \
1572 r->element[i] = name(b->element[i]); \
1573 } \
1574 }
1575
1576#define clzb(v) ((v) ? clz32((uint32_t)(v) << 24) : 8)
1577#define clzh(v) ((v) ? clz32((uint32_t)(v) << 16) : 16)
1578#define clzw(v) clz32((v))
1579#define clzd(v) clz64((v))
1580
1581VGENERIC_DO(clzb, u8)
1582VGENERIC_DO(clzh, u16)
1583VGENERIC_DO(clzw, u32)
1584VGENERIC_DO(clzd, u64)
1585
1586#undef clzb
1587#undef clzh
1588#undef clzw
1589#undef clzd
1590
e13500b3
TM
1591#define popcntb(v) ctpop8(v)
1592#define popcnth(v) ctpop16(v)
1593#define popcntw(v) ctpop32(v)
1594#define popcntd(v) ctpop64(v)
1595
1596VGENERIC_DO(popcntb, u8)
1597VGENERIC_DO(popcnth, u16)
1598VGENERIC_DO(popcntw, u32)
1599VGENERIC_DO(popcntd, u64)
1600
1601#undef popcntb
1602#undef popcnth
1603#undef popcntw
1604#undef popcntd
f293f04a
TM
1605
1606#undef VGENERIC_DO
1607
b41da4eb
TM
1608#if defined(HOST_WORDS_BIGENDIAN)
1609#define QW_ONE { .u64 = { 0, 1 } }
1610#else
1611#define QW_ONE { .u64 = { 1, 0 } }
1612#endif
1613
1614#ifndef CONFIG_INT128
1615
1616static inline void avr_qw_not(ppc_avr_t *t, ppc_avr_t a)
1617{
1618 t->u64[0] = ~a.u64[0];
1619 t->u64[1] = ~a.u64[1];
1620}
1621
1622static int avr_qw_cmpu(ppc_avr_t a, ppc_avr_t b)
1623{
1624 if (a.u64[HI_IDX] < b.u64[HI_IDX]) {
1625 return -1;
1626 } else if (a.u64[HI_IDX] > b.u64[HI_IDX]) {
1627 return 1;
1628 } else if (a.u64[LO_IDX] < b.u64[LO_IDX]) {
1629 return -1;
1630 } else if (a.u64[LO_IDX] > b.u64[LO_IDX]) {
1631 return 1;
1632 } else {
1633 return 0;
1634 }
1635}
1636
1637static void avr_qw_add(ppc_avr_t *t, ppc_avr_t a, ppc_avr_t b)
1638{
1639 t->u64[LO_IDX] = a.u64[LO_IDX] + b.u64[LO_IDX];
1640 t->u64[HI_IDX] = a.u64[HI_IDX] + b.u64[HI_IDX] +
1641 (~a.u64[LO_IDX] < b.u64[LO_IDX]);
1642}
1643
1644static int avr_qw_addc(ppc_avr_t *t, ppc_avr_t a, ppc_avr_t b)
1645{
1646 ppc_avr_t not_a;
1647 t->u64[LO_IDX] = a.u64[LO_IDX] + b.u64[LO_IDX];
1648 t->u64[HI_IDX] = a.u64[HI_IDX] + b.u64[HI_IDX] +
1649 (~a.u64[LO_IDX] < b.u64[LO_IDX]);
1650 avr_qw_not(&not_a, a);
1651 return avr_qw_cmpu(not_a, b) < 0;
1652}
1653
1654#endif
1655
1656void helper_vadduqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1657{
1658#ifdef CONFIG_INT128
1659 r->u128 = a->u128 + b->u128;
1660#else
1661 avr_qw_add(r, *a, *b);
1662#endif
1663}
1664
1665void helper_vaddeuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
1666{
1667#ifdef CONFIG_INT128
1668 r->u128 = a->u128 + b->u128 + (c->u128 & 1);
1669#else
1670
1671 if (c->u64[LO_IDX] & 1) {
1672 ppc_avr_t tmp;
1673
1674 tmp.u64[HI_IDX] = 0;
1675 tmp.u64[LO_IDX] = c->u64[LO_IDX] & 1;
1676 avr_qw_add(&tmp, *a, tmp);
1677 avr_qw_add(r, tmp, *b);
1678 } else {
1679 avr_qw_add(r, *a, *b);
1680 }
1681#endif
1682}
1683
1684void helper_vaddcuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1685{
1686#ifdef CONFIG_INT128
1687 r->u128 = (~a->u128 < b->u128);
1688#else
1689 ppc_avr_t not_a;
1690
1691 avr_qw_not(&not_a, *a);
1692
1693 r->u64[HI_IDX] = 0;
1694 r->u64[LO_IDX] = (avr_qw_cmpu(not_a, *b) < 0);
1695#endif
1696}
1697
1698void helper_vaddecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
1699{
1700#ifdef CONFIG_INT128
1701 int carry_out = (~a->u128 < b->u128);
1702 if (!carry_out && (c->u128 & 1)) {
1703 carry_out = ((a->u128 + b->u128 + 1) == 0) &&
1704 ((a->u128 != 0) || (b->u128 != 0));
1705 }
1706 r->u128 = carry_out;
1707#else
1708
1709 int carry_in = c->u64[LO_IDX] & 1;
1710 int carry_out = 0;
1711 ppc_avr_t tmp;
1712
1713 carry_out = avr_qw_addc(&tmp, *a, *b);
1714
1715 if (!carry_out && carry_in) {
1716 ppc_avr_t one = QW_ONE;
1717 carry_out = avr_qw_addc(&tmp, tmp, one);
1718 }
1719 r->u64[HI_IDX] = 0;
1720 r->u64[LO_IDX] = carry_out;
1721#endif
1722}
1723
1724void helper_vsubuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1725{
1726#ifdef CONFIG_INT128
1727 r->u128 = a->u128 - b->u128;
1728#else
1729 ppc_avr_t tmp;
1730 ppc_avr_t one = QW_ONE;
1731
1732 avr_qw_not(&tmp, *b);
1733 avr_qw_add(&tmp, *a, tmp);
1734 avr_qw_add(r, tmp, one);
1735#endif
1736}
1737
1738void helper_vsubeuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
1739{
1740#ifdef CONFIG_INT128
1741 r->u128 = a->u128 + ~b->u128 + (c->u128 & 1);
1742#else
1743 ppc_avr_t tmp, sum;
1744
1745 avr_qw_not(&tmp, *b);
1746 avr_qw_add(&sum, *a, tmp);
1747
1748 tmp.u64[HI_IDX] = 0;
1749 tmp.u64[LO_IDX] = c->u64[LO_IDX] & 1;
1750 avr_qw_add(r, sum, tmp);
1751#endif
1752}
1753
1754void helper_vsubcuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1755{
1756#ifdef CONFIG_INT128
1757 r->u128 = (~a->u128 < ~b->u128) ||
1758 (a->u128 + ~b->u128 == (__uint128_t)-1);
1759#else
1760 int carry = (avr_qw_cmpu(*a, *b) > 0);
1761 if (!carry) {
1762 ppc_avr_t tmp;
1763 avr_qw_not(&tmp, *b);
1764 avr_qw_add(&tmp, *a, tmp);
1765 carry = ((tmp.s64[HI_IDX] == -1ull) && (tmp.s64[LO_IDX] == -1ull));
1766 }
1767 r->u64[HI_IDX] = 0;
1768 r->u64[LO_IDX] = carry;
1769#endif
1770}
1771
1772void helper_vsubecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
1773{
1774#ifdef CONFIG_INT128
1775 r->u128 =
1776 (~a->u128 < ~b->u128) ||
1777 ((c->u128 & 1) && (a->u128 + ~b->u128 == (__uint128_t)-1));
1778#else
1779 int carry_in = c->u64[LO_IDX] & 1;
1780 int carry_out = (avr_qw_cmpu(*a, *b) > 0);
1781 if (!carry_out && carry_in) {
1782 ppc_avr_t tmp;
1783 avr_qw_not(&tmp, *b);
1784 avr_qw_add(&tmp, *a, tmp);
1785 carry_out = ((tmp.u64[HI_IDX] == -1ull) && (tmp.u64[LO_IDX] == -1ull));
1786 }
1787
1788 r->u64[HI_IDX] = 0;
1789 r->u64[LO_IDX] = carry_out;
1790#endif
1791}
1792
f293f04a 1793
64654ded
BS
1794#undef VECTOR_FOR_INORDER_I
1795#undef HI_IDX
1796#undef LO_IDX
1797
1798/*****************************************************************************/
1799/* SPE extension helpers */
1800/* Use a table to make this quicker */
ea6c0dac 1801static const uint8_t hbrev[16] = {
64654ded
BS
1802 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
1803 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
1804};
1805
1806static inline uint8_t byte_reverse(uint8_t val)
1807{
1808 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
1809}
1810
1811static inline uint32_t word_reverse(uint32_t val)
1812{
1813 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
1814 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
1815}
1816
1817#define MASKBITS 16 /* Random value - to be fixed (implementation dependent) */
1818target_ulong helper_brinc(target_ulong arg1, target_ulong arg2)
1819{
1820 uint32_t a, b, d, mask;
1821
1822 mask = UINT32_MAX >> (32 - MASKBITS);
1823 a = arg1 & mask;
1824 b = arg2 & mask;
1825 d = word_reverse(1 + word_reverse(a | ~b));
1826 return (arg1 & ~mask) | (d & b);
1827}
1828
1829uint32_t helper_cntlsw32(uint32_t val)
1830{
1831 if (val & 0x80000000) {
1832 return clz32(~val);
1833 } else {
1834 return clz32(val);
1835 }
1836}
1837
1838uint32_t helper_cntlzw32(uint32_t val)
1839{
1840 return clz32(val);
1841}
1842
1843/* 440 specific */
d15f74fb
BS
1844target_ulong helper_dlmzb(CPUPPCState *env, target_ulong high,
1845 target_ulong low, uint32_t update_Rc)
64654ded
BS
1846{
1847 target_ulong mask;
1848 int i;
1849
1850 i = 1;
1851 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1852 if ((high & mask) == 0) {
1853 if (update_Rc) {
1854 env->crf[0] = 0x4;
1855 }
1856 goto done;
1857 }
1858 i++;
1859 }
1860 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1861 if ((low & mask) == 0) {
1862 if (update_Rc) {
1863 env->crf[0] = 0x8;
1864 }
1865 goto done;
1866 }
1867 i++;
1868 }
1869 if (update_Rc) {
1870 env->crf[0] = 0x2;
1871 }
1872 done:
1873 env->xer = (env->xer & ~0x7F) | i;
1874 if (update_Rc) {
1875 env->crf[0] |= xer_so;
1876 }
1877 return i;
1878}
This page took 0.439779 seconds and 4 git commands to generate.