]> Git Repo - qemu.git/blame - target-ppc/int_helper.c
target-ppc: Altivec 2.07: vmuluw Instruction
[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
BS
628 { \
629 uint32_t ones = (uint32_t)-1; \
630 uint32_t all = ones; \
631 uint32_t none = 0; \
632 int i; \
633 \
634 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
635 uint32_t result = (a->element[i] compare b->element[i] ? \
636 ones : 0x0); \
637 switch (sizeof(a->element[0])) { \
638 case 4: \
639 r->u32[i] = result; \
640 break; \
641 case 2: \
642 r->u16[i] = result; \
643 break; \
644 case 1: \
645 r->u8[i] = result; \
646 break; \
647 } \
648 all &= result; \
649 none |= result; \
650 } \
651 if (record) { \
652 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
653 } \
654 }
655#define VCMP(suffix, compare, element) \
656 VCMP_DO(suffix, compare, element, 0) \
657 VCMP_DO(suffix##_dot, compare, element, 1)
658VCMP(equb, ==, u8)
659VCMP(equh, ==, u16)
660VCMP(equw, ==, u32)
661VCMP(gtub, >, u8)
662VCMP(gtuh, >, u16)
663VCMP(gtuw, >, u32)
664VCMP(gtsb, >, s8)
665VCMP(gtsh, >, s16)
666VCMP(gtsw, >, s32)
667#undef VCMP_DO
668#undef VCMP
669
670#define VCMPFP_DO(suffix, compare, order, record) \
d15f74fb
BS
671 void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
672 ppc_avr_t *a, ppc_avr_t *b) \
64654ded
BS
673 { \
674 uint32_t ones = (uint32_t)-1; \
675 uint32_t all = ones; \
676 uint32_t none = 0; \
677 int i; \
678 \
679 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
680 uint32_t result; \
681 int rel = float32_compare_quiet(a->f[i], b->f[i], \
682 &env->vec_status); \
683 if (rel == float_relation_unordered) { \
684 result = 0; \
685 } else if (rel compare order) { \
686 result = ones; \
687 } else { \
688 result = 0; \
689 } \
690 r->u32[i] = result; \
691 all &= result; \
692 none |= result; \
693 } \
694 if (record) { \
695 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
696 } \
697 }
698#define VCMPFP(suffix, compare, order) \
699 VCMPFP_DO(suffix, compare, order, 0) \
700 VCMPFP_DO(suffix##_dot, compare, order, 1)
701VCMPFP(eqfp, ==, float_relation_equal)
702VCMPFP(gefp, !=, float_relation_less)
703VCMPFP(gtfp, ==, float_relation_greater)
704#undef VCMPFP_DO
705#undef VCMPFP
706
d15f74fb
BS
707static inline void vcmpbfp_internal(CPUPPCState *env, ppc_avr_t *r,
708 ppc_avr_t *a, ppc_avr_t *b, int record)
64654ded
BS
709{
710 int i;
711 int all_in = 0;
712
713 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
714 int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
715 if (le_rel == float_relation_unordered) {
716 r->u32[i] = 0xc0000000;
717 /* ALL_IN does not need to be updated here. */
718 } else {
719 float32 bneg = float32_chs(b->f[i]);
720 int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
721 int le = le_rel != float_relation_greater;
722 int ge = ge_rel != float_relation_less;
723
724 r->u32[i] = ((!le) << 31) | ((!ge) << 30);
725 all_in |= (!le | !ge);
726 }
727 }
728 if (record) {
729 env->crf[6] = (all_in == 0) << 1;
730 }
731}
732
d15f74fb 733void helper_vcmpbfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded 734{
d15f74fb 735 vcmpbfp_internal(env, r, a, b, 0);
64654ded
BS
736}
737
d15f74fb
BS
738void helper_vcmpbfp_dot(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
739 ppc_avr_t *b)
64654ded 740{
d15f74fb 741 vcmpbfp_internal(env, r, a, b, 1);
64654ded
BS
742}
743
744#define VCT(suffix, satcvt, element) \
d15f74fb
BS
745 void helper_vct##suffix(CPUPPCState *env, ppc_avr_t *r, \
746 ppc_avr_t *b, uint32_t uim) \
64654ded
BS
747 { \
748 int i; \
749 int sat = 0; \
750 float_status s = env->vec_status; \
751 \
752 set_float_rounding_mode(float_round_to_zero, &s); \
753 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
754 if (float32_is_any_nan(b->f[i])) { \
755 r->element[i] = 0; \
756 } else { \
757 float64 t = float32_to_float64(b->f[i], &s); \
758 int64_t j; \
759 \
760 t = float64_scalbn(t, uim, &s); \
761 j = float64_to_int64(t, &s); \
762 r->element[i] = satcvt(j, &sat); \
763 } \
764 } \
765 if (sat) { \
766 env->vscr |= (1 << VSCR_SAT); \
767 } \
768 }
769VCT(uxs, cvtsduw, u32)
770VCT(sxs, cvtsdsw, s32)
771#undef VCT
772
d15f74fb
BS
773void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
774 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
775{
776 int sat = 0;
777 int i;
778
779 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
780 int32_t prod = a->s16[i] * b->s16[i];
781 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
782
783 r->s16[i] = cvtswsh(t, &sat);
784 }
785
786 if (sat) {
787 env->vscr |= (1 << VSCR_SAT);
788 }
789}
790
d15f74fb
BS
791void helper_vmhraddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
792 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
793{
794 int sat = 0;
795 int i;
796
797 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
798 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
799 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
800 r->s16[i] = cvtswsh(t, &sat);
801 }
802
803 if (sat) {
804 env->vscr |= (1 << VSCR_SAT);
805 }
806}
807
808#define VMINMAX_DO(name, compare, element) \
809 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
810 { \
811 int i; \
812 \
813 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
814 if (a->element[i] compare b->element[i]) { \
815 r->element[i] = b->element[i]; \
816 } else { \
817 r->element[i] = a->element[i]; \
818 } \
819 } \
820 }
821#define VMINMAX(suffix, element) \
822 VMINMAX_DO(min##suffix, >, element) \
823 VMINMAX_DO(max##suffix, <, element)
824VMINMAX(sb, s8)
825VMINMAX(sh, s16)
826VMINMAX(sw, s32)
827VMINMAX(ub, u8)
828VMINMAX(uh, u16)
829VMINMAX(uw, u32)
830#undef VMINMAX_DO
831#undef VMINMAX
832
64654ded
BS
833void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
834{
835 int i;
836
837 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
838 int32_t prod = a->s16[i] * b->s16[i];
839 r->s16[i] = (int16_t) (prod + c->s16[i]);
840 }
841}
842
843#define VMRG_DO(name, element, highp) \
844 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
845 { \
846 ppc_avr_t result; \
847 int i; \
848 size_t n_elems = ARRAY_SIZE(r->element); \
849 \
850 for (i = 0; i < n_elems / 2; i++) { \
851 if (highp) { \
852 result.element[i*2+HI_IDX] = a->element[i]; \
853 result.element[i*2+LO_IDX] = b->element[i]; \
854 } else { \
855 result.element[n_elems - i * 2 - (1 + HI_IDX)] = \
856 b->element[n_elems - i - 1]; \
857 result.element[n_elems - i * 2 - (1 + LO_IDX)] = \
858 a->element[n_elems - i - 1]; \
859 } \
860 } \
861 *r = result; \
862 }
863#if defined(HOST_WORDS_BIGENDIAN)
864#define MRGHI 0
865#define MRGLO 1
866#else
867#define MRGHI 1
868#define MRGLO 0
869#endif
870#define VMRG(suffix, element) \
871 VMRG_DO(mrgl##suffix, element, MRGHI) \
872 VMRG_DO(mrgh##suffix, element, MRGLO)
873VMRG(b, u8)
874VMRG(h, u16)
875VMRG(w, u32)
876#undef VMRG_DO
877#undef VMRG
878#undef MRGHI
879#undef MRGLO
880
d15f74fb
BS
881void helper_vmsummbm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
882 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
883{
884 int32_t prod[16];
885 int i;
886
887 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
888 prod[i] = (int32_t)a->s8[i] * b->u8[i];
889 }
890
891 VECTOR_FOR_INORDER_I(i, s32) {
892 r->s32[i] = c->s32[i] + prod[4 * i] + prod[4 * i + 1] +
893 prod[4 * i + 2] + prod[4 * i + 3];
894 }
895}
896
d15f74fb
BS
897void helper_vmsumshm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
898 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
899{
900 int32_t prod[8];
901 int i;
902
903 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
904 prod[i] = a->s16[i] * b->s16[i];
905 }
906
907 VECTOR_FOR_INORDER_I(i, s32) {
908 r->s32[i] = c->s32[i] + prod[2 * i] + prod[2 * i + 1];
909 }
910}
911
d15f74fb
BS
912void helper_vmsumshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
913 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
914{
915 int32_t prod[8];
916 int i;
917 int sat = 0;
918
919 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
920 prod[i] = (int32_t)a->s16[i] * b->s16[i];
921 }
922
923 VECTOR_FOR_INORDER_I(i, s32) {
924 int64_t t = (int64_t)c->s32[i] + prod[2 * i] + prod[2 * i + 1];
925
926 r->u32[i] = cvtsdsw(t, &sat);
927 }
928
929 if (sat) {
930 env->vscr |= (1 << VSCR_SAT);
931 }
932}
933
d15f74fb
BS
934void helper_vmsumubm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
935 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
936{
937 uint16_t prod[16];
938 int i;
939
940 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
941 prod[i] = a->u8[i] * b->u8[i];
942 }
943
944 VECTOR_FOR_INORDER_I(i, u32) {
945 r->u32[i] = c->u32[i] + prod[4 * i] + prod[4 * i + 1] +
946 prod[4 * i + 2] + prod[4 * i + 3];
947 }
948}
949
d15f74fb
BS
950void helper_vmsumuhm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
951 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
952{
953 uint32_t prod[8];
954 int i;
955
956 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
957 prod[i] = a->u16[i] * b->u16[i];
958 }
959
960 VECTOR_FOR_INORDER_I(i, u32) {
961 r->u32[i] = c->u32[i] + prod[2 * i] + prod[2 * i + 1];
962 }
963}
964
d15f74fb
BS
965void helper_vmsumuhs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
966 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
967{
968 uint32_t prod[8];
969 int i;
970 int sat = 0;
971
972 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
973 prod[i] = a->u16[i] * b->u16[i];
974 }
975
976 VECTOR_FOR_INORDER_I(i, s32) {
977 uint64_t t = (uint64_t)c->u32[i] + prod[2 * i] + prod[2 * i + 1];
978
979 r->u32[i] = cvtuduw(t, &sat);
980 }
981
982 if (sat) {
983 env->vscr |= (1 << VSCR_SAT);
984 }
985}
986
aa9e930c 987#define VMUL_DO(name, mul_element, prod_element, cast, evenp) \
64654ded
BS
988 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
989 { \
990 int i; \
991 \
992 VECTOR_FOR_INORDER_I(i, prod_element) { \
993 if (evenp) { \
aa9e930c
TM
994 r->prod_element[i] = \
995 (cast)a->mul_element[i * 2 + HI_IDX] * \
996 (cast)b->mul_element[i * 2 + HI_IDX]; \
64654ded 997 } else { \
aa9e930c
TM
998 r->prod_element[i] = \
999 (cast)a->mul_element[i * 2 + LO_IDX] * \
1000 (cast)b->mul_element[i * 2 + LO_IDX]; \
64654ded
BS
1001 } \
1002 } \
1003 }
aa9e930c
TM
1004#define VMUL(suffix, mul_element, prod_element, cast) \
1005 VMUL_DO(mule##suffix, mul_element, prod_element, cast, 1) \
1006 VMUL_DO(mulo##suffix, mul_element, prod_element, cast, 0)
1007VMUL(sb, s8, s16, int16_t)
1008VMUL(sh, s16, s32, int32_t)
63be0936 1009VMUL(sw, s32, s64, int64_t)
aa9e930c
TM
1010VMUL(ub, u8, u16, uint16_t)
1011VMUL(uh, u16, u32, uint32_t)
63be0936 1012VMUL(uw, u32, u64, uint64_t)
64654ded
BS
1013#undef VMUL_DO
1014#undef VMUL
1015
d15f74fb
BS
1016void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
1017 ppc_avr_t *c)
64654ded
BS
1018{
1019 ppc_avr_t result;
1020 int i;
1021
1022 VECTOR_FOR_INORDER_I(i, u8) {
1023 int s = c->u8[i] & 0x1f;
1024#if defined(HOST_WORDS_BIGENDIAN)
1025 int index = s & 0xf;
1026#else
1027 int index = 15 - (s & 0xf);
1028#endif
1029
1030 if (s & 0x10) {
1031 result.u8[i] = b->u8[index];
1032 } else {
1033 result.u8[i] = a->u8[index];
1034 }
1035 }
1036 *r = result;
1037}
1038
1039#if defined(HOST_WORDS_BIGENDIAN)
1040#define PKBIG 1
1041#else
1042#define PKBIG 0
1043#endif
1044void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1045{
1046 int i, j;
1047 ppc_avr_t result;
1048#if defined(HOST_WORDS_BIGENDIAN)
1049 const ppc_avr_t *x[2] = { a, b };
1050#else
1051 const ppc_avr_t *x[2] = { b, a };
1052#endif
1053
1054 VECTOR_FOR_INORDER_I(i, u64) {
1055 VECTOR_FOR_INORDER_I(j, u32) {
1056 uint32_t e = x[i]->u32[j];
1057
1058 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
1059 ((e >> 6) & 0x3e0) |
1060 ((e >> 3) & 0x1f));
1061 }
1062 }
1063 *r = result;
1064}
1065
1066#define VPK(suffix, from, to, cvt, dosat) \
d15f74fb
BS
1067 void helper_vpk##suffix(CPUPPCState *env, ppc_avr_t *r, \
1068 ppc_avr_t *a, ppc_avr_t *b) \
64654ded
BS
1069 { \
1070 int i; \
1071 int sat = 0; \
1072 ppc_avr_t result; \
1073 ppc_avr_t *a0 = PKBIG ? a : b; \
1074 ppc_avr_t *a1 = PKBIG ? b : a; \
1075 \
1076 VECTOR_FOR_INORDER_I(i, from) { \
1077 result.to[i] = cvt(a0->from[i], &sat); \
1078 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
1079 } \
1080 *r = result; \
1081 if (dosat && sat) { \
1082 env->vscr |= (1 << VSCR_SAT); \
1083 } \
1084 }
1085#define I(x, y) (x)
1086VPK(shss, s16, s8, cvtshsb, 1)
1087VPK(shus, s16, u8, cvtshub, 1)
1088VPK(swss, s32, s16, cvtswsh, 1)
1089VPK(swus, s32, u16, cvtswuh, 1)
1090VPK(uhus, u16, u8, cvtuhub, 1)
1091VPK(uwus, u32, u16, cvtuwuh, 1)
1092VPK(uhum, u16, u8, I, 0)
1093VPK(uwum, u32, u16, I, 0)
1094#undef I
1095#undef VPK
1096#undef PKBIG
1097
d15f74fb 1098void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1099{
1100 int i;
1101
1102 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
ef9bd150 1103 r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
64654ded
BS
1104 }
1105}
1106
1107#define VRFI(suffix, rounding) \
d15f74fb
BS
1108 void helper_vrfi##suffix(CPUPPCState *env, ppc_avr_t *r, \
1109 ppc_avr_t *b) \
64654ded
BS
1110 { \
1111 int i; \
1112 float_status s = env->vec_status; \
1113 \
1114 set_float_rounding_mode(rounding, &s); \
1115 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
ef9bd150 1116 r->f[i] = float32_round_to_int (b->f[i], &s); \
64654ded
BS
1117 } \
1118 }
1119VRFI(n, float_round_nearest_even)
1120VRFI(m, float_round_down)
1121VRFI(p, float_round_up)
1122VRFI(z, float_round_to_zero)
1123#undef VRFI
1124
1125#define VROTATE(suffix, element) \
1126 void helper_vrl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1127 { \
1128 int i; \
1129 \
1130 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1131 unsigned int mask = ((1 << \
1132 (3 + (sizeof(a->element[0]) >> 1))) \
1133 - 1); \
1134 unsigned int shift = b->element[i] & mask; \
1135 r->element[i] = (a->element[i] << shift) | \
1136 (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
1137 } \
1138 }
1139VROTATE(b, u8)
1140VROTATE(h, u16)
1141VROTATE(w, u32)
1142#undef VROTATE
1143
d15f74fb 1144void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1145{
1146 int i;
1147
1148 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
ef9bd150 1149 float32 t = float32_sqrt(b->f[i], &env->vec_status);
64654ded 1150
ef9bd150 1151 r->f[i] = float32_div(float32_one, t, &env->vec_status);
64654ded
BS
1152 }
1153}
1154
d15f74fb
BS
1155void helper_vsel(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
1156 ppc_avr_t *c)
64654ded
BS
1157{
1158 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
1159 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
1160}
1161
d15f74fb 1162void helper_vexptefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1163{
1164 int i;
1165
1166 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
ef9bd150 1167 r->f[i] = float32_exp2(b->f[i], &env->vec_status);
64654ded
BS
1168 }
1169}
1170
d15f74fb 1171void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1172{
1173 int i;
1174
1175 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
ef9bd150 1176 r->f[i] = float32_log2(b->f[i], &env->vec_status);
64654ded
BS
1177 }
1178}
1179
1180#if defined(HOST_WORDS_BIGENDIAN)
1181#define LEFT 0
1182#define RIGHT 1
1183#else
1184#define LEFT 1
1185#define RIGHT 0
1186#endif
1187/* The specification says that the results are undefined if all of the
1188 * shift counts are not identical. We check to make sure that they are
1189 * to conform to what real hardware appears to do. */
1190#define VSHIFT(suffix, leftp) \
1191 void helper_vs##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1192 { \
1193 int shift = b->u8[LO_IDX*15] & 0x7; \
1194 int doit = 1; \
1195 int i; \
1196 \
1197 for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
1198 doit = doit && ((b->u8[i] & 0x7) == shift); \
1199 } \
1200 if (doit) { \
1201 if (shift == 0) { \
1202 *r = *a; \
1203 } else if (leftp) { \
1204 uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
1205 \
1206 r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
1207 r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
1208 } else { \
1209 uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
1210 \
1211 r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
1212 r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
1213 } \
1214 } \
1215 }
1216VSHIFT(l, LEFT)
1217VSHIFT(r, RIGHT)
1218#undef VSHIFT
1219#undef LEFT
1220#undef RIGHT
1221
1222#define VSL(suffix, element) \
1223 void helper_vsl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1224 { \
1225 int i; \
1226 \
1227 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1228 unsigned int mask = ((1 << \
1229 (3 + (sizeof(a->element[0]) >> 1))) \
1230 - 1); \
1231 unsigned int shift = b->element[i] & mask; \
1232 \
1233 r->element[i] = a->element[i] << shift; \
1234 } \
1235 }
1236VSL(b, u8)
1237VSL(h, u16)
1238VSL(w, u32)
1239#undef VSL
1240
1241void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
1242{
1243 int sh = shift & 0xf;
1244 int i;
1245 ppc_avr_t result;
1246
1247#if defined(HOST_WORDS_BIGENDIAN)
1248 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
1249 int index = sh + i;
1250 if (index > 0xf) {
1251 result.u8[i] = b->u8[index - 0x10];
1252 } else {
1253 result.u8[i] = a->u8[index];
1254 }
1255 }
1256#else
1257 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
1258 int index = (16 - sh) + i;
1259 if (index > 0xf) {
1260 result.u8[i] = a->u8[index - 0x10];
1261 } else {
1262 result.u8[i] = b->u8[index];
1263 }
1264 }
1265#endif
1266 *r = result;
1267}
1268
1269void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1270{
1271 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
1272
1273#if defined(HOST_WORDS_BIGENDIAN)
1274 memmove(&r->u8[0], &a->u8[sh], 16 - sh);
1275 memset(&r->u8[16-sh], 0, sh);
1276#else
1277 memmove(&r->u8[sh], &a->u8[0], 16 - sh);
1278 memset(&r->u8[0], 0, sh);
1279#endif
1280}
1281
1282/* Experimental testing shows that hardware masks the immediate. */
1283#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
1284#if defined(HOST_WORDS_BIGENDIAN)
1285#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
1286#else
1287#define SPLAT_ELEMENT(element) \
1288 (ARRAY_SIZE(r->element) - 1 - _SPLAT_MASKED(element))
1289#endif
1290#define VSPLT(suffix, element) \
1291 void helper_vsplt##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
1292 { \
1293 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
1294 int i; \
1295 \
1296 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1297 r->element[i] = s; \
1298 } \
1299 }
1300VSPLT(b, u8)
1301VSPLT(h, u16)
1302VSPLT(w, u32)
1303#undef VSPLT
1304#undef SPLAT_ELEMENT
1305#undef _SPLAT_MASKED
1306
1307#define VSPLTI(suffix, element, splat_type) \
1308 void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \
1309 { \
1310 splat_type x = (int8_t)(splat << 3) >> 3; \
1311 int i; \
1312 \
1313 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1314 r->element[i] = x; \
1315 } \
1316 }
1317VSPLTI(b, s8, int8_t)
1318VSPLTI(h, s16, int16_t)
1319VSPLTI(w, s32, int32_t)
1320#undef VSPLTI
1321
1322#define VSR(suffix, element) \
1323 void helper_vsr##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1324 { \
1325 int i; \
1326 \
1327 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1328 unsigned int mask = ((1 << \
1329 (3 + (sizeof(a->element[0]) >> 1))) \
1330 - 1); \
1331 unsigned int shift = b->element[i] & mask; \
1332 \
1333 r->element[i] = a->element[i] >> shift; \
1334 } \
1335 }
1336VSR(ab, s8)
1337VSR(ah, s16)
1338VSR(aw, s32)
1339VSR(b, u8)
1340VSR(h, u16)
1341VSR(w, u32)
1342#undef VSR
1343
1344void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1345{
1346 int sh = (b->u8[LO_IDX * 0xf] >> 3) & 0xf;
1347
1348#if defined(HOST_WORDS_BIGENDIAN)
1349 memmove(&r->u8[sh], &a->u8[0], 16 - sh);
1350 memset(&r->u8[0], 0, sh);
1351#else
1352 memmove(&r->u8[0], &a->u8[sh], 16 - sh);
1353 memset(&r->u8[16 - sh], 0, sh);
1354#endif
1355}
1356
1357void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1358{
1359 int i;
1360
1361 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
1362 r->u32[i] = a->u32[i] >= b->u32[i];
1363 }
1364}
1365
d15f74fb 1366void helper_vsumsws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1367{
1368 int64_t t;
1369 int i, upper;
1370 ppc_avr_t result;
1371 int sat = 0;
1372
1373#if defined(HOST_WORDS_BIGENDIAN)
1374 upper = ARRAY_SIZE(r->s32)-1;
1375#else
1376 upper = 0;
1377#endif
1378 t = (int64_t)b->s32[upper];
1379 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1380 t += a->s32[i];
1381 result.s32[i] = 0;
1382 }
1383 result.s32[upper] = cvtsdsw(t, &sat);
1384 *r = result;
1385
1386 if (sat) {
1387 env->vscr |= (1 << VSCR_SAT);
1388 }
1389}
1390
d15f74fb 1391void helper_vsum2sws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1392{
1393 int i, j, upper;
1394 ppc_avr_t result;
1395 int sat = 0;
1396
1397#if defined(HOST_WORDS_BIGENDIAN)
1398 upper = 1;
1399#else
1400 upper = 0;
1401#endif
1402 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
1403 int64_t t = (int64_t)b->s32[upper + i * 2];
1404
1405 result.u64[i] = 0;
1406 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
1407 t += a->s32[2 * i + j];
1408 }
1409 result.s32[upper + i * 2] = cvtsdsw(t, &sat);
1410 }
1411
1412 *r = result;
1413 if (sat) {
1414 env->vscr |= (1 << VSCR_SAT);
1415 }
1416}
1417
d15f74fb 1418void helper_vsum4sbs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1419{
1420 int i, j;
1421 int sat = 0;
1422
1423 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1424 int64_t t = (int64_t)b->s32[i];
1425
1426 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
1427 t += a->s8[4 * i + j];
1428 }
1429 r->s32[i] = cvtsdsw(t, &sat);
1430 }
1431
1432 if (sat) {
1433 env->vscr |= (1 << VSCR_SAT);
1434 }
1435}
1436
d15f74fb 1437void helper_vsum4shs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1438{
1439 int sat = 0;
1440 int i;
1441
1442 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1443 int64_t t = (int64_t)b->s32[i];
1444
1445 t += a->s16[2 * i] + a->s16[2 * i + 1];
1446 r->s32[i] = cvtsdsw(t, &sat);
1447 }
1448
1449 if (sat) {
1450 env->vscr |= (1 << VSCR_SAT);
1451 }
1452}
1453
d15f74fb 1454void helper_vsum4ubs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1455{
1456 int i, j;
1457 int sat = 0;
1458
1459 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
1460 uint64_t t = (uint64_t)b->u32[i];
1461
1462 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
1463 t += a->u8[4 * i + j];
1464 }
1465 r->u32[i] = cvtuduw(t, &sat);
1466 }
1467
1468 if (sat) {
1469 env->vscr |= (1 << VSCR_SAT);
1470 }
1471}
1472
1473#if defined(HOST_WORDS_BIGENDIAN)
1474#define UPKHI 1
1475#define UPKLO 0
1476#else
1477#define UPKHI 0
1478#define UPKLO 1
1479#endif
1480#define VUPKPX(suffix, hi) \
1481 void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
1482 { \
1483 int i; \
1484 ppc_avr_t result; \
1485 \
1486 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
1487 uint16_t e = b->u16[hi ? i : i+4]; \
1488 uint8_t a = (e >> 15) ? 0xff : 0; \
1489 uint8_t r = (e >> 10) & 0x1f; \
1490 uint8_t g = (e >> 5) & 0x1f; \
1491 uint8_t b = e & 0x1f; \
1492 \
1493 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
1494 } \
1495 *r = result; \
1496 }
1497VUPKPX(lpx, UPKLO)
1498VUPKPX(hpx, UPKHI)
1499#undef VUPKPX
1500
1501#define VUPK(suffix, unpacked, packee, hi) \
1502 void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
1503 { \
1504 int i; \
1505 ppc_avr_t result; \
1506 \
1507 if (hi) { \
1508 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
1509 result.unpacked[i] = b->packee[i]; \
1510 } \
1511 } else { \
1512 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); \
1513 i++) { \
1514 result.unpacked[i - ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
1515 } \
1516 } \
1517 *r = result; \
1518 }
1519VUPK(hsb, s16, s8, UPKHI)
1520VUPK(hsh, s32, s16, UPKHI)
1521VUPK(lsb, s16, s8, UPKLO)
1522VUPK(lsh, s32, s16, UPKLO)
1523#undef VUPK
1524#undef UPKHI
1525#undef UPKLO
1526
64654ded
BS
1527#undef VECTOR_FOR_INORDER_I
1528#undef HI_IDX
1529#undef LO_IDX
1530
1531/*****************************************************************************/
1532/* SPE extension helpers */
1533/* Use a table to make this quicker */
ea6c0dac 1534static const uint8_t hbrev[16] = {
64654ded
BS
1535 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
1536 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
1537};
1538
1539static inline uint8_t byte_reverse(uint8_t val)
1540{
1541 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
1542}
1543
1544static inline uint32_t word_reverse(uint32_t val)
1545{
1546 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
1547 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
1548}
1549
1550#define MASKBITS 16 /* Random value - to be fixed (implementation dependent) */
1551target_ulong helper_brinc(target_ulong arg1, target_ulong arg2)
1552{
1553 uint32_t a, b, d, mask;
1554
1555 mask = UINT32_MAX >> (32 - MASKBITS);
1556 a = arg1 & mask;
1557 b = arg2 & mask;
1558 d = word_reverse(1 + word_reverse(a | ~b));
1559 return (arg1 & ~mask) | (d & b);
1560}
1561
1562uint32_t helper_cntlsw32(uint32_t val)
1563{
1564 if (val & 0x80000000) {
1565 return clz32(~val);
1566 } else {
1567 return clz32(val);
1568 }
1569}
1570
1571uint32_t helper_cntlzw32(uint32_t val)
1572{
1573 return clz32(val);
1574}
1575
1576/* 440 specific */
d15f74fb
BS
1577target_ulong helper_dlmzb(CPUPPCState *env, target_ulong high,
1578 target_ulong low, uint32_t update_Rc)
64654ded
BS
1579{
1580 target_ulong mask;
1581 int i;
1582
1583 i = 1;
1584 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1585 if ((high & mask) == 0) {
1586 if (update_Rc) {
1587 env->crf[0] = 0x4;
1588 }
1589 goto done;
1590 }
1591 i++;
1592 }
1593 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1594 if ((low & mask) == 0) {
1595 if (update_Rc) {
1596 env->crf[0] = 0x8;
1597 }
1598 goto done;
1599 }
1600 i++;
1601 }
1602 if (update_Rc) {
1603 env->crf[0] = 0x2;
1604 }
1605 done:
1606 env->xer = (env->xer & ~0x7F) | i;
1607 if (update_Rc) {
1608 env->crf[0] |= xer_so;
1609 }
1610 return i;
1611}
This page took 0.399252 seconds and 4 git commands to generate.