]> Git Repo - qemu.git/blame - target-ppc/int_helper.c
target-ppc: Add Flag for ISA2.06 Divide Extended Instructions
[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
44target_ulong helper_cntlzw(target_ulong t)
45{
46 return clz32(t);
47}
48
49#if defined(TARGET_PPC64)
50target_ulong helper_cntlzd(target_ulong t)
51{
52 return clz64(t);
53}
54#endif
55
86ba37ed
TM
56#if defined(TARGET_PPC64)
57
58uint64_t helper_bpermd(uint64_t rs, uint64_t rb)
59{
60 int i;
61 uint64_t ra = 0;
62
63 for (i = 0; i < 8; i++) {
64 int index = (rs >> (i*8)) & 0xFF;
65 if (index < 64) {
66 if (rb & (1ull << (63-index))) {
67 ra |= 1 << i;
68 }
69 }
70 }
71 return ra;
72}
73
74#endif
75
fcfda20f
AJ
76target_ulong helper_cmpb(target_ulong rs, target_ulong rb)
77{
78 target_ulong mask = 0xff;
79 target_ulong ra = 0;
80 int i;
81
82 for (i = 0; i < sizeof(target_ulong); i++) {
83 if ((rs & mask) == (rb & mask)) {
84 ra |= mask;
85 }
86 mask <<= 8;
87 }
88 return ra;
89}
90
64654ded 91/* shift right arithmetic helper */
d15f74fb
BS
92target_ulong helper_sraw(CPUPPCState *env, target_ulong value,
93 target_ulong shift)
64654ded
BS
94{
95 int32_t ret;
96
97 if (likely(!(shift & 0x20))) {
98 if (likely((uint32_t)shift != 0)) {
99 shift &= 0x1f;
100 ret = (int32_t)value >> shift;
101 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
da91a00f 102 env->ca = 0;
64654ded 103 } else {
da91a00f 104 env->ca = 1;
64654ded
BS
105 }
106 } else {
107 ret = (int32_t)value;
da91a00f 108 env->ca = 0;
64654ded
BS
109 }
110 } else {
111 ret = (int32_t)value >> 31;
da91a00f 112 env->ca = (ret != 0);
64654ded
BS
113 }
114 return (target_long)ret;
115}
116
117#if defined(TARGET_PPC64)
d15f74fb
BS
118target_ulong helper_srad(CPUPPCState *env, target_ulong value,
119 target_ulong shift)
64654ded
BS
120{
121 int64_t ret;
122
123 if (likely(!(shift & 0x40))) {
124 if (likely((uint64_t)shift != 0)) {
125 shift &= 0x3f;
126 ret = (int64_t)value >> shift;
127 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
da91a00f 128 env->ca = 0;
64654ded 129 } else {
da91a00f 130 env->ca = 1;
64654ded
BS
131 }
132 } else {
133 ret = (int64_t)value;
da91a00f 134 env->ca = 0;
64654ded
BS
135 }
136 } else {
137 ret = (int64_t)value >> 63;
da91a00f 138 env->ca = (ret != 0);
64654ded
BS
139 }
140 return ret;
141}
142#endif
143
144#if defined(TARGET_PPC64)
145target_ulong helper_popcntb(target_ulong val)
146{
147 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
148 0x5555555555555555ULL);
149 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
150 0x3333333333333333ULL);
151 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
152 0x0f0f0f0f0f0f0f0fULL);
153 return val;
154}
155
156target_ulong helper_popcntw(target_ulong val)
157{
158 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
159 0x5555555555555555ULL);
160 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
161 0x3333333333333333ULL);
162 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
163 0x0f0f0f0f0f0f0f0fULL);
164 val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) &
165 0x00ff00ff00ff00ffULL);
166 val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
167 0x0000ffff0000ffffULL);
168 return val;
169}
170
171target_ulong helper_popcntd(target_ulong val)
172{
173 return ctpop64(val);
174}
175#else
176target_ulong helper_popcntb(target_ulong val)
177{
178 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
179 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
180 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
181 return val;
182}
183
184target_ulong helper_popcntw(target_ulong val)
185{
186 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
187 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
188 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
189 val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff);
190 val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
191 return val;
192}
193#endif
194
195/*****************************************************************************/
196/* PowerPC 601 specific instructions (POWER bridge) */
d15f74fb 197target_ulong helper_div(CPUPPCState *env, target_ulong arg1, target_ulong arg2)
64654ded
BS
198{
199 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
200
201 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
202 (int32_t)arg2 == 0) {
203 env->spr[SPR_MQ] = 0;
204 return INT32_MIN;
205 } else {
206 env->spr[SPR_MQ] = tmp % arg2;
207 return tmp / (int32_t)arg2;
208 }
209}
210
d15f74fb
BS
211target_ulong helper_divo(CPUPPCState *env, target_ulong arg1,
212 target_ulong arg2)
64654ded
BS
213{
214 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
215
216 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
217 (int32_t)arg2 == 0) {
da91a00f 218 env->so = env->ov = 1;
64654ded
BS
219 env->spr[SPR_MQ] = 0;
220 return INT32_MIN;
221 } else {
222 env->spr[SPR_MQ] = tmp % arg2;
223 tmp /= (int32_t)arg2;
224 if ((int32_t)tmp != tmp) {
da91a00f 225 env->so = env->ov = 1;
64654ded 226 } else {
da91a00f 227 env->ov = 0;
64654ded
BS
228 }
229 return tmp;
230 }
231}
232
d15f74fb
BS
233target_ulong helper_divs(CPUPPCState *env, target_ulong arg1,
234 target_ulong arg2)
64654ded
BS
235{
236 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
237 (int32_t)arg2 == 0) {
238 env->spr[SPR_MQ] = 0;
239 return INT32_MIN;
240 } else {
241 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
242 return (int32_t)arg1 / (int32_t)arg2;
243 }
244}
245
d15f74fb
BS
246target_ulong helper_divso(CPUPPCState *env, target_ulong arg1,
247 target_ulong arg2)
64654ded
BS
248{
249 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
250 (int32_t)arg2 == 0) {
da91a00f 251 env->so = env->ov = 1;
64654ded
BS
252 env->spr[SPR_MQ] = 0;
253 return INT32_MIN;
254 } else {
da91a00f 255 env->ov = 0;
64654ded
BS
256 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
257 return (int32_t)arg1 / (int32_t)arg2;
258 }
259}
260
261/*****************************************************************************/
262/* 602 specific instructions */
263/* mfrom is the most crazy instruction ever seen, imho ! */
264/* Real implementation uses a ROM table. Do the same */
265/* Extremely decomposed:
266 * -arg / 256
267 * return 256 * log10(10 + 1.0) + 0.5
268 */
269#if !defined(CONFIG_USER_ONLY)
270target_ulong helper_602_mfrom(target_ulong arg)
271{
272 if (likely(arg < 602)) {
273#include "mfrom_table.c"
274 return mfrom_ROM_table[arg];
275 } else {
276 return 0;
277 }
278}
279#endif
280
281/*****************************************************************************/
282/* Altivec extension helpers */
283#if defined(HOST_WORDS_BIGENDIAN)
284#define HI_IDX 0
285#define LO_IDX 1
286#else
287#define HI_IDX 1
288#define LO_IDX 0
289#endif
290
291#if defined(HOST_WORDS_BIGENDIAN)
292#define VECTOR_FOR_INORDER_I(index, element) \
293 for (index = 0; index < ARRAY_SIZE(r->element); index++)
294#else
295#define VECTOR_FOR_INORDER_I(index, element) \
296 for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
297#endif
298
64654ded
BS
299/* Saturating arithmetic helpers. */
300#define SATCVT(from, to, from_type, to_type, min, max) \
301 static inline to_type cvt##from##to(from_type x, int *sat) \
302 { \
303 to_type r; \
304 \
305 if (x < (from_type)min) { \
306 r = min; \
307 *sat = 1; \
308 } else if (x > (from_type)max) { \
309 r = max; \
310 *sat = 1; \
311 } else { \
312 r = x; \
313 } \
314 return r; \
315 }
316#define SATCVTU(from, to, from_type, to_type, min, max) \
317 static inline to_type cvt##from##to(from_type x, int *sat) \
318 { \
319 to_type r; \
320 \
321 if (x > (from_type)max) { \
322 r = max; \
323 *sat = 1; \
324 } else { \
325 r = x; \
326 } \
327 return r; \
328 }
329SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
330SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
331SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
332
333SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
334SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
335SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
336SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
337SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
338SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
339#undef SATCVT
340#undef SATCVTU
341
342void helper_lvsl(ppc_avr_t *r, target_ulong sh)
343{
344 int i, j = (sh & 0xf);
345
346 VECTOR_FOR_INORDER_I(i, u8) {
347 r->u8[i] = j++;
348 }
349}
350
351void helper_lvsr(ppc_avr_t *r, target_ulong sh)
352{
353 int i, j = 0x10 - (sh & 0xf);
354
355 VECTOR_FOR_INORDER_I(i, u8) {
356 r->u8[i] = j++;
357 }
358}
359
d15f74fb 360void helper_mtvscr(CPUPPCState *env, ppc_avr_t *r)
64654ded
BS
361{
362#if defined(HOST_WORDS_BIGENDIAN)
363 env->vscr = r->u32[3];
364#else
365 env->vscr = r->u32[0];
366#endif
367 set_flush_to_zero(vscr_nj, &env->vec_status);
368}
369
370void helper_vaddcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
371{
372 int i;
373
374 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
375 r->u32[i] = ~a->u32[i] < b->u32[i];
376 }
377}
378
379#define VARITH_DO(name, op, element) \
380 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
381 { \
382 int i; \
383 \
384 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
385 r->element[i] = a->element[i] op b->element[i]; \
386 } \
387 }
388#define VARITH(suffix, element) \
389 VARITH_DO(add##suffix, +, element) \
390 VARITH_DO(sub##suffix, -, element)
391VARITH(ubm, u8)
392VARITH(uhm, u16)
393VARITH(uwm, u32)
394#undef VARITH_DO
395#undef VARITH
396
397#define VARITHFP(suffix, func) \
d15f74fb
BS
398 void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
399 ppc_avr_t *b) \
64654ded
BS
400 { \
401 int i; \
402 \
403 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
ef9bd150 404 r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
64654ded
BS
405 } \
406 }
407VARITHFP(addfp, float32_add)
408VARITHFP(subfp, float32_sub)
db1babb8
AJ
409VARITHFP(minfp, float32_min)
410VARITHFP(maxfp, float32_max)
64654ded
BS
411#undef VARITHFP
412
2f93c23f
AJ
413#define VARITHFPFMA(suffix, type) \
414 void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
415 ppc_avr_t *b, ppc_avr_t *c) \
416 { \
417 int i; \
418 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
419 r->f[i] = float32_muladd(a->f[i], c->f[i], b->f[i], \
420 type, &env->vec_status); \
421 } \
422 }
423VARITHFPFMA(maddfp, 0);
424VARITHFPFMA(nmsubfp, float_muladd_negate_result | float_muladd_negate_c);
425#undef VARITHFPFMA
426
64654ded
BS
427#define VARITHSAT_CASE(type, op, cvt, element) \
428 { \
429 type result = (type)a->element[i] op (type)b->element[i]; \
430 r->element[i] = cvt(result, &sat); \
431 }
432
433#define VARITHSAT_DO(name, op, optype, cvt, element) \
d15f74fb
BS
434 void helper_v##name(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
435 ppc_avr_t *b) \
64654ded
BS
436 { \
437 int sat = 0; \
438 int i; \
439 \
440 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
441 switch (sizeof(r->element[0])) { \
442 case 1: \
443 VARITHSAT_CASE(optype, op, cvt, element); \
444 break; \
445 case 2: \
446 VARITHSAT_CASE(optype, op, cvt, element); \
447 break; \
448 case 4: \
449 VARITHSAT_CASE(optype, op, cvt, element); \
450 break; \
451 } \
452 } \
453 if (sat) { \
454 env->vscr |= (1 << VSCR_SAT); \
455 } \
456 }
457#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
458 VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
459 VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
460#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
461 VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
462 VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
463VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
464VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
465VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
466VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
467VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
468VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
469#undef VARITHSAT_CASE
470#undef VARITHSAT_DO
471#undef VARITHSAT_SIGNED
472#undef VARITHSAT_UNSIGNED
473
474#define VAVG_DO(name, element, etype) \
475 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
476 { \
477 int i; \
478 \
479 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
480 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
481 r->element[i] = x >> 1; \
482 } \
483 }
484
485#define VAVG(type, signed_element, signed_type, unsigned_element, \
486 unsigned_type) \
487 VAVG_DO(avgs##type, signed_element, signed_type) \
488 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
489VAVG(b, s8, int16_t, u8, uint16_t)
490VAVG(h, s16, int32_t, u16, uint32_t)
491VAVG(w, s32, int64_t, u32, uint64_t)
492#undef VAVG_DO
493#undef VAVG
494
495#define VCF(suffix, cvt, element) \
d15f74fb
BS
496 void helper_vcf##suffix(CPUPPCState *env, ppc_avr_t *r, \
497 ppc_avr_t *b, uint32_t uim) \
64654ded
BS
498 { \
499 int i; \
500 \
501 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
502 float32 t = cvt(b->element[i], &env->vec_status); \
503 r->f[i] = float32_scalbn(t, -uim, &env->vec_status); \
504 } \
505 }
506VCF(ux, uint32_to_float32, u32)
507VCF(sx, int32_to_float32, s32)
508#undef VCF
509
510#define VCMP_DO(suffix, compare, element, record) \
d15f74fb
BS
511 void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
512 ppc_avr_t *a, ppc_avr_t *b) \
64654ded
BS
513 { \
514 uint32_t ones = (uint32_t)-1; \
515 uint32_t all = ones; \
516 uint32_t none = 0; \
517 int i; \
518 \
519 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
520 uint32_t result = (a->element[i] compare b->element[i] ? \
521 ones : 0x0); \
522 switch (sizeof(a->element[0])) { \
523 case 4: \
524 r->u32[i] = result; \
525 break; \
526 case 2: \
527 r->u16[i] = result; \
528 break; \
529 case 1: \
530 r->u8[i] = result; \
531 break; \
532 } \
533 all &= result; \
534 none |= result; \
535 } \
536 if (record) { \
537 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
538 } \
539 }
540#define VCMP(suffix, compare, element) \
541 VCMP_DO(suffix, compare, element, 0) \
542 VCMP_DO(suffix##_dot, compare, element, 1)
543VCMP(equb, ==, u8)
544VCMP(equh, ==, u16)
545VCMP(equw, ==, u32)
546VCMP(gtub, >, u8)
547VCMP(gtuh, >, u16)
548VCMP(gtuw, >, u32)
549VCMP(gtsb, >, s8)
550VCMP(gtsh, >, s16)
551VCMP(gtsw, >, s32)
552#undef VCMP_DO
553#undef VCMP
554
555#define VCMPFP_DO(suffix, compare, order, record) \
d15f74fb
BS
556 void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
557 ppc_avr_t *a, ppc_avr_t *b) \
64654ded
BS
558 { \
559 uint32_t ones = (uint32_t)-1; \
560 uint32_t all = ones; \
561 uint32_t none = 0; \
562 int i; \
563 \
564 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
565 uint32_t result; \
566 int rel = float32_compare_quiet(a->f[i], b->f[i], \
567 &env->vec_status); \
568 if (rel == float_relation_unordered) { \
569 result = 0; \
570 } else if (rel compare order) { \
571 result = ones; \
572 } else { \
573 result = 0; \
574 } \
575 r->u32[i] = result; \
576 all &= result; \
577 none |= result; \
578 } \
579 if (record) { \
580 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
581 } \
582 }
583#define VCMPFP(suffix, compare, order) \
584 VCMPFP_DO(suffix, compare, order, 0) \
585 VCMPFP_DO(suffix##_dot, compare, order, 1)
586VCMPFP(eqfp, ==, float_relation_equal)
587VCMPFP(gefp, !=, float_relation_less)
588VCMPFP(gtfp, ==, float_relation_greater)
589#undef VCMPFP_DO
590#undef VCMPFP
591
d15f74fb
BS
592static inline void vcmpbfp_internal(CPUPPCState *env, ppc_avr_t *r,
593 ppc_avr_t *a, ppc_avr_t *b, int record)
64654ded
BS
594{
595 int i;
596 int all_in = 0;
597
598 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
599 int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
600 if (le_rel == float_relation_unordered) {
601 r->u32[i] = 0xc0000000;
602 /* ALL_IN does not need to be updated here. */
603 } else {
604 float32 bneg = float32_chs(b->f[i]);
605 int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
606 int le = le_rel != float_relation_greater;
607 int ge = ge_rel != float_relation_less;
608
609 r->u32[i] = ((!le) << 31) | ((!ge) << 30);
610 all_in |= (!le | !ge);
611 }
612 }
613 if (record) {
614 env->crf[6] = (all_in == 0) << 1;
615 }
616}
617
d15f74fb 618void helper_vcmpbfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded 619{
d15f74fb 620 vcmpbfp_internal(env, r, a, b, 0);
64654ded
BS
621}
622
d15f74fb
BS
623void helper_vcmpbfp_dot(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
624 ppc_avr_t *b)
64654ded 625{
d15f74fb 626 vcmpbfp_internal(env, r, a, b, 1);
64654ded
BS
627}
628
629#define VCT(suffix, satcvt, element) \
d15f74fb
BS
630 void helper_vct##suffix(CPUPPCState *env, ppc_avr_t *r, \
631 ppc_avr_t *b, uint32_t uim) \
64654ded
BS
632 { \
633 int i; \
634 int sat = 0; \
635 float_status s = env->vec_status; \
636 \
637 set_float_rounding_mode(float_round_to_zero, &s); \
638 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
639 if (float32_is_any_nan(b->f[i])) { \
640 r->element[i] = 0; \
641 } else { \
642 float64 t = float32_to_float64(b->f[i], &s); \
643 int64_t j; \
644 \
645 t = float64_scalbn(t, uim, &s); \
646 j = float64_to_int64(t, &s); \
647 r->element[i] = satcvt(j, &sat); \
648 } \
649 } \
650 if (sat) { \
651 env->vscr |= (1 << VSCR_SAT); \
652 } \
653 }
654VCT(uxs, cvtsduw, u32)
655VCT(sxs, cvtsdsw, s32)
656#undef VCT
657
d15f74fb
BS
658void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
659 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
660{
661 int sat = 0;
662 int i;
663
664 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
665 int32_t prod = a->s16[i] * b->s16[i];
666 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
667
668 r->s16[i] = cvtswsh(t, &sat);
669 }
670
671 if (sat) {
672 env->vscr |= (1 << VSCR_SAT);
673 }
674}
675
d15f74fb
BS
676void helper_vmhraddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
677 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
678{
679 int sat = 0;
680 int i;
681
682 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
683 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
684 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
685 r->s16[i] = cvtswsh(t, &sat);
686 }
687
688 if (sat) {
689 env->vscr |= (1 << VSCR_SAT);
690 }
691}
692
693#define VMINMAX_DO(name, compare, element) \
694 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
695 { \
696 int i; \
697 \
698 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
699 if (a->element[i] compare b->element[i]) { \
700 r->element[i] = b->element[i]; \
701 } else { \
702 r->element[i] = a->element[i]; \
703 } \
704 } \
705 }
706#define VMINMAX(suffix, element) \
707 VMINMAX_DO(min##suffix, >, element) \
708 VMINMAX_DO(max##suffix, <, element)
709VMINMAX(sb, s8)
710VMINMAX(sh, s16)
711VMINMAX(sw, s32)
712VMINMAX(ub, u8)
713VMINMAX(uh, u16)
714VMINMAX(uw, u32)
715#undef VMINMAX_DO
716#undef VMINMAX
717
64654ded
BS
718void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
719{
720 int i;
721
722 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
723 int32_t prod = a->s16[i] * b->s16[i];
724 r->s16[i] = (int16_t) (prod + c->s16[i]);
725 }
726}
727
728#define VMRG_DO(name, element, highp) \
729 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
730 { \
731 ppc_avr_t result; \
732 int i; \
733 size_t n_elems = ARRAY_SIZE(r->element); \
734 \
735 for (i = 0; i < n_elems / 2; i++) { \
736 if (highp) { \
737 result.element[i*2+HI_IDX] = a->element[i]; \
738 result.element[i*2+LO_IDX] = b->element[i]; \
739 } else { \
740 result.element[n_elems - i * 2 - (1 + HI_IDX)] = \
741 b->element[n_elems - i - 1]; \
742 result.element[n_elems - i * 2 - (1 + LO_IDX)] = \
743 a->element[n_elems - i - 1]; \
744 } \
745 } \
746 *r = result; \
747 }
748#if defined(HOST_WORDS_BIGENDIAN)
749#define MRGHI 0
750#define MRGLO 1
751#else
752#define MRGHI 1
753#define MRGLO 0
754#endif
755#define VMRG(suffix, element) \
756 VMRG_DO(mrgl##suffix, element, MRGHI) \
757 VMRG_DO(mrgh##suffix, element, MRGLO)
758VMRG(b, u8)
759VMRG(h, u16)
760VMRG(w, u32)
761#undef VMRG_DO
762#undef VMRG
763#undef MRGHI
764#undef MRGLO
765
d15f74fb
BS
766void helper_vmsummbm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
767 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
768{
769 int32_t prod[16];
770 int i;
771
772 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
773 prod[i] = (int32_t)a->s8[i] * b->u8[i];
774 }
775
776 VECTOR_FOR_INORDER_I(i, s32) {
777 r->s32[i] = c->s32[i] + prod[4 * i] + prod[4 * i + 1] +
778 prod[4 * i + 2] + prod[4 * i + 3];
779 }
780}
781
d15f74fb
BS
782void helper_vmsumshm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
783 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
784{
785 int32_t prod[8];
786 int i;
787
788 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
789 prod[i] = a->s16[i] * b->s16[i];
790 }
791
792 VECTOR_FOR_INORDER_I(i, s32) {
793 r->s32[i] = c->s32[i] + prod[2 * i] + prod[2 * i + 1];
794 }
795}
796
d15f74fb
BS
797void helper_vmsumshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
798 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
799{
800 int32_t prod[8];
801 int i;
802 int sat = 0;
803
804 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
805 prod[i] = (int32_t)a->s16[i] * b->s16[i];
806 }
807
808 VECTOR_FOR_INORDER_I(i, s32) {
809 int64_t t = (int64_t)c->s32[i] + prod[2 * i] + prod[2 * i + 1];
810
811 r->u32[i] = cvtsdsw(t, &sat);
812 }
813
814 if (sat) {
815 env->vscr |= (1 << VSCR_SAT);
816 }
817}
818
d15f74fb
BS
819void helper_vmsumubm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
820 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
821{
822 uint16_t prod[16];
823 int i;
824
825 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
826 prod[i] = a->u8[i] * b->u8[i];
827 }
828
829 VECTOR_FOR_INORDER_I(i, u32) {
830 r->u32[i] = c->u32[i] + prod[4 * i] + prod[4 * i + 1] +
831 prod[4 * i + 2] + prod[4 * i + 3];
832 }
833}
834
d15f74fb
BS
835void helper_vmsumuhm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
836 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
837{
838 uint32_t prod[8];
839 int i;
840
841 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
842 prod[i] = a->u16[i] * b->u16[i];
843 }
844
845 VECTOR_FOR_INORDER_I(i, u32) {
846 r->u32[i] = c->u32[i] + prod[2 * i] + prod[2 * i + 1];
847 }
848}
849
d15f74fb
BS
850void helper_vmsumuhs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
851 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
852{
853 uint32_t prod[8];
854 int i;
855 int sat = 0;
856
857 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
858 prod[i] = a->u16[i] * b->u16[i];
859 }
860
861 VECTOR_FOR_INORDER_I(i, s32) {
862 uint64_t t = (uint64_t)c->u32[i] + prod[2 * i] + prod[2 * i + 1];
863
864 r->u32[i] = cvtuduw(t, &sat);
865 }
866
867 if (sat) {
868 env->vscr |= (1 << VSCR_SAT);
869 }
870}
871
872#define VMUL_DO(name, mul_element, prod_element, evenp) \
873 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
874 { \
875 int i; \
876 \
877 VECTOR_FOR_INORDER_I(i, prod_element) { \
878 if (evenp) { \
879 r->prod_element[i] = a->mul_element[i * 2 + HI_IDX] * \
880 b->mul_element[i * 2 + HI_IDX]; \
881 } else { \
882 r->prod_element[i] = a->mul_element[i * 2 + LO_IDX] * \
883 b->mul_element[i * 2 + LO_IDX]; \
884 } \
885 } \
886 }
887#define VMUL(suffix, mul_element, prod_element) \
888 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
889 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
890VMUL(sb, s8, s16)
891VMUL(sh, s16, s32)
892VMUL(ub, u8, u16)
893VMUL(uh, u16, u32)
894#undef VMUL_DO
895#undef VMUL
896
d15f74fb
BS
897void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
898 ppc_avr_t *c)
64654ded
BS
899{
900 ppc_avr_t result;
901 int i;
902
903 VECTOR_FOR_INORDER_I(i, u8) {
904 int s = c->u8[i] & 0x1f;
905#if defined(HOST_WORDS_BIGENDIAN)
906 int index = s & 0xf;
907#else
908 int index = 15 - (s & 0xf);
909#endif
910
911 if (s & 0x10) {
912 result.u8[i] = b->u8[index];
913 } else {
914 result.u8[i] = a->u8[index];
915 }
916 }
917 *r = result;
918}
919
920#if defined(HOST_WORDS_BIGENDIAN)
921#define PKBIG 1
922#else
923#define PKBIG 0
924#endif
925void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
926{
927 int i, j;
928 ppc_avr_t result;
929#if defined(HOST_WORDS_BIGENDIAN)
930 const ppc_avr_t *x[2] = { a, b };
931#else
932 const ppc_avr_t *x[2] = { b, a };
933#endif
934
935 VECTOR_FOR_INORDER_I(i, u64) {
936 VECTOR_FOR_INORDER_I(j, u32) {
937 uint32_t e = x[i]->u32[j];
938
939 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
940 ((e >> 6) & 0x3e0) |
941 ((e >> 3) & 0x1f));
942 }
943 }
944 *r = result;
945}
946
947#define VPK(suffix, from, to, cvt, dosat) \
d15f74fb
BS
948 void helper_vpk##suffix(CPUPPCState *env, ppc_avr_t *r, \
949 ppc_avr_t *a, ppc_avr_t *b) \
64654ded
BS
950 { \
951 int i; \
952 int sat = 0; \
953 ppc_avr_t result; \
954 ppc_avr_t *a0 = PKBIG ? a : b; \
955 ppc_avr_t *a1 = PKBIG ? b : a; \
956 \
957 VECTOR_FOR_INORDER_I(i, from) { \
958 result.to[i] = cvt(a0->from[i], &sat); \
959 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
960 } \
961 *r = result; \
962 if (dosat && sat) { \
963 env->vscr |= (1 << VSCR_SAT); \
964 } \
965 }
966#define I(x, y) (x)
967VPK(shss, s16, s8, cvtshsb, 1)
968VPK(shus, s16, u8, cvtshub, 1)
969VPK(swss, s32, s16, cvtswsh, 1)
970VPK(swus, s32, u16, cvtswuh, 1)
971VPK(uhus, u16, u8, cvtuhub, 1)
972VPK(uwus, u32, u16, cvtuwuh, 1)
973VPK(uhum, u16, u8, I, 0)
974VPK(uwum, u32, u16, I, 0)
975#undef I
976#undef VPK
977#undef PKBIG
978
d15f74fb 979void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
980{
981 int i;
982
983 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
ef9bd150 984 r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
64654ded
BS
985 }
986}
987
988#define VRFI(suffix, rounding) \
d15f74fb
BS
989 void helper_vrfi##suffix(CPUPPCState *env, ppc_avr_t *r, \
990 ppc_avr_t *b) \
64654ded
BS
991 { \
992 int i; \
993 float_status s = env->vec_status; \
994 \
995 set_float_rounding_mode(rounding, &s); \
996 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
ef9bd150 997 r->f[i] = float32_round_to_int (b->f[i], &s); \
64654ded
BS
998 } \
999 }
1000VRFI(n, float_round_nearest_even)
1001VRFI(m, float_round_down)
1002VRFI(p, float_round_up)
1003VRFI(z, float_round_to_zero)
1004#undef VRFI
1005
1006#define VROTATE(suffix, element) \
1007 void helper_vrl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1008 { \
1009 int i; \
1010 \
1011 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1012 unsigned int mask = ((1 << \
1013 (3 + (sizeof(a->element[0]) >> 1))) \
1014 - 1); \
1015 unsigned int shift = b->element[i] & mask; \
1016 r->element[i] = (a->element[i] << shift) | \
1017 (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
1018 } \
1019 }
1020VROTATE(b, u8)
1021VROTATE(h, u16)
1022VROTATE(w, u32)
1023#undef VROTATE
1024
d15f74fb 1025void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1026{
1027 int i;
1028
1029 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
ef9bd150 1030 float32 t = float32_sqrt(b->f[i], &env->vec_status);
64654ded 1031
ef9bd150 1032 r->f[i] = float32_div(float32_one, t, &env->vec_status);
64654ded
BS
1033 }
1034}
1035
d15f74fb
BS
1036void helper_vsel(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
1037 ppc_avr_t *c)
64654ded
BS
1038{
1039 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
1040 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
1041}
1042
d15f74fb 1043void helper_vexptefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1044{
1045 int i;
1046
1047 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
ef9bd150 1048 r->f[i] = float32_exp2(b->f[i], &env->vec_status);
64654ded
BS
1049 }
1050}
1051
d15f74fb 1052void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1053{
1054 int i;
1055
1056 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
ef9bd150 1057 r->f[i] = float32_log2(b->f[i], &env->vec_status);
64654ded
BS
1058 }
1059}
1060
1061#if defined(HOST_WORDS_BIGENDIAN)
1062#define LEFT 0
1063#define RIGHT 1
1064#else
1065#define LEFT 1
1066#define RIGHT 0
1067#endif
1068/* The specification says that the results are undefined if all of the
1069 * shift counts are not identical. We check to make sure that they are
1070 * to conform to what real hardware appears to do. */
1071#define VSHIFT(suffix, leftp) \
1072 void helper_vs##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1073 { \
1074 int shift = b->u8[LO_IDX*15] & 0x7; \
1075 int doit = 1; \
1076 int i; \
1077 \
1078 for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
1079 doit = doit && ((b->u8[i] & 0x7) == shift); \
1080 } \
1081 if (doit) { \
1082 if (shift == 0) { \
1083 *r = *a; \
1084 } else if (leftp) { \
1085 uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
1086 \
1087 r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
1088 r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
1089 } else { \
1090 uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
1091 \
1092 r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
1093 r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
1094 } \
1095 } \
1096 }
1097VSHIFT(l, LEFT)
1098VSHIFT(r, RIGHT)
1099#undef VSHIFT
1100#undef LEFT
1101#undef RIGHT
1102
1103#define VSL(suffix, element) \
1104 void helper_vsl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1105 { \
1106 int i; \
1107 \
1108 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1109 unsigned int mask = ((1 << \
1110 (3 + (sizeof(a->element[0]) >> 1))) \
1111 - 1); \
1112 unsigned int shift = b->element[i] & mask; \
1113 \
1114 r->element[i] = a->element[i] << shift; \
1115 } \
1116 }
1117VSL(b, u8)
1118VSL(h, u16)
1119VSL(w, u32)
1120#undef VSL
1121
1122void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
1123{
1124 int sh = shift & 0xf;
1125 int i;
1126 ppc_avr_t result;
1127
1128#if defined(HOST_WORDS_BIGENDIAN)
1129 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
1130 int index = sh + i;
1131 if (index > 0xf) {
1132 result.u8[i] = b->u8[index - 0x10];
1133 } else {
1134 result.u8[i] = a->u8[index];
1135 }
1136 }
1137#else
1138 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
1139 int index = (16 - sh) + i;
1140 if (index > 0xf) {
1141 result.u8[i] = a->u8[index - 0x10];
1142 } else {
1143 result.u8[i] = b->u8[index];
1144 }
1145 }
1146#endif
1147 *r = result;
1148}
1149
1150void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1151{
1152 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
1153
1154#if defined(HOST_WORDS_BIGENDIAN)
1155 memmove(&r->u8[0], &a->u8[sh], 16 - sh);
1156 memset(&r->u8[16-sh], 0, sh);
1157#else
1158 memmove(&r->u8[sh], &a->u8[0], 16 - sh);
1159 memset(&r->u8[0], 0, sh);
1160#endif
1161}
1162
1163/* Experimental testing shows that hardware masks the immediate. */
1164#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
1165#if defined(HOST_WORDS_BIGENDIAN)
1166#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
1167#else
1168#define SPLAT_ELEMENT(element) \
1169 (ARRAY_SIZE(r->element) - 1 - _SPLAT_MASKED(element))
1170#endif
1171#define VSPLT(suffix, element) \
1172 void helper_vsplt##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
1173 { \
1174 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
1175 int i; \
1176 \
1177 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1178 r->element[i] = s; \
1179 } \
1180 }
1181VSPLT(b, u8)
1182VSPLT(h, u16)
1183VSPLT(w, u32)
1184#undef VSPLT
1185#undef SPLAT_ELEMENT
1186#undef _SPLAT_MASKED
1187
1188#define VSPLTI(suffix, element, splat_type) \
1189 void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \
1190 { \
1191 splat_type x = (int8_t)(splat << 3) >> 3; \
1192 int i; \
1193 \
1194 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1195 r->element[i] = x; \
1196 } \
1197 }
1198VSPLTI(b, s8, int8_t)
1199VSPLTI(h, s16, int16_t)
1200VSPLTI(w, s32, int32_t)
1201#undef VSPLTI
1202
1203#define VSR(suffix, element) \
1204 void helper_vsr##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1205 { \
1206 int i; \
1207 \
1208 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
1209 unsigned int mask = ((1 << \
1210 (3 + (sizeof(a->element[0]) >> 1))) \
1211 - 1); \
1212 unsigned int shift = b->element[i] & mask; \
1213 \
1214 r->element[i] = a->element[i] >> shift; \
1215 } \
1216 }
1217VSR(ab, s8)
1218VSR(ah, s16)
1219VSR(aw, s32)
1220VSR(b, u8)
1221VSR(h, u16)
1222VSR(w, u32)
1223#undef VSR
1224
1225void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1226{
1227 int sh = (b->u8[LO_IDX * 0xf] >> 3) & 0xf;
1228
1229#if defined(HOST_WORDS_BIGENDIAN)
1230 memmove(&r->u8[sh], &a->u8[0], 16 - sh);
1231 memset(&r->u8[0], 0, sh);
1232#else
1233 memmove(&r->u8[0], &a->u8[sh], 16 - sh);
1234 memset(&r->u8[16 - sh], 0, sh);
1235#endif
1236}
1237
1238void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1239{
1240 int i;
1241
1242 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
1243 r->u32[i] = a->u32[i] >= b->u32[i];
1244 }
1245}
1246
d15f74fb 1247void helper_vsumsws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1248{
1249 int64_t t;
1250 int i, upper;
1251 ppc_avr_t result;
1252 int sat = 0;
1253
1254#if defined(HOST_WORDS_BIGENDIAN)
1255 upper = ARRAY_SIZE(r->s32)-1;
1256#else
1257 upper = 0;
1258#endif
1259 t = (int64_t)b->s32[upper];
1260 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1261 t += a->s32[i];
1262 result.s32[i] = 0;
1263 }
1264 result.s32[upper] = cvtsdsw(t, &sat);
1265 *r = result;
1266
1267 if (sat) {
1268 env->vscr |= (1 << VSCR_SAT);
1269 }
1270}
1271
d15f74fb 1272void helper_vsum2sws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1273{
1274 int i, j, upper;
1275 ppc_avr_t result;
1276 int sat = 0;
1277
1278#if defined(HOST_WORDS_BIGENDIAN)
1279 upper = 1;
1280#else
1281 upper = 0;
1282#endif
1283 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
1284 int64_t t = (int64_t)b->s32[upper + i * 2];
1285
1286 result.u64[i] = 0;
1287 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
1288 t += a->s32[2 * i + j];
1289 }
1290 result.s32[upper + i * 2] = cvtsdsw(t, &sat);
1291 }
1292
1293 *r = result;
1294 if (sat) {
1295 env->vscr |= (1 << VSCR_SAT);
1296 }
1297}
1298
d15f74fb 1299void helper_vsum4sbs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1300{
1301 int i, j;
1302 int sat = 0;
1303
1304 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1305 int64_t t = (int64_t)b->s32[i];
1306
1307 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
1308 t += a->s8[4 * i + j];
1309 }
1310 r->s32[i] = cvtsdsw(t, &sat);
1311 }
1312
1313 if (sat) {
1314 env->vscr |= (1 << VSCR_SAT);
1315 }
1316}
1317
d15f74fb 1318void helper_vsum4shs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1319{
1320 int sat = 0;
1321 int i;
1322
1323 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1324 int64_t t = (int64_t)b->s32[i];
1325
1326 t += a->s16[2 * i] + a->s16[2 * i + 1];
1327 r->s32[i] = cvtsdsw(t, &sat);
1328 }
1329
1330 if (sat) {
1331 env->vscr |= (1 << VSCR_SAT);
1332 }
1333}
1334
d15f74fb 1335void helper_vsum4ubs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
1336{
1337 int i, j;
1338 int sat = 0;
1339
1340 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
1341 uint64_t t = (uint64_t)b->u32[i];
1342
1343 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
1344 t += a->u8[4 * i + j];
1345 }
1346 r->u32[i] = cvtuduw(t, &sat);
1347 }
1348
1349 if (sat) {
1350 env->vscr |= (1 << VSCR_SAT);
1351 }
1352}
1353
1354#if defined(HOST_WORDS_BIGENDIAN)
1355#define UPKHI 1
1356#define UPKLO 0
1357#else
1358#define UPKHI 0
1359#define UPKLO 1
1360#endif
1361#define VUPKPX(suffix, hi) \
1362 void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
1363 { \
1364 int i; \
1365 ppc_avr_t result; \
1366 \
1367 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
1368 uint16_t e = b->u16[hi ? i : i+4]; \
1369 uint8_t a = (e >> 15) ? 0xff : 0; \
1370 uint8_t r = (e >> 10) & 0x1f; \
1371 uint8_t g = (e >> 5) & 0x1f; \
1372 uint8_t b = e & 0x1f; \
1373 \
1374 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
1375 } \
1376 *r = result; \
1377 }
1378VUPKPX(lpx, UPKLO)
1379VUPKPX(hpx, UPKHI)
1380#undef VUPKPX
1381
1382#define VUPK(suffix, unpacked, packee, hi) \
1383 void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
1384 { \
1385 int i; \
1386 ppc_avr_t result; \
1387 \
1388 if (hi) { \
1389 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
1390 result.unpacked[i] = b->packee[i]; \
1391 } \
1392 } else { \
1393 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); \
1394 i++) { \
1395 result.unpacked[i - ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
1396 } \
1397 } \
1398 *r = result; \
1399 }
1400VUPK(hsb, s16, s8, UPKHI)
1401VUPK(hsh, s32, s16, UPKHI)
1402VUPK(lsb, s16, s8, UPKLO)
1403VUPK(lsh, s32, s16, UPKLO)
1404#undef VUPK
1405#undef UPKHI
1406#undef UPKLO
1407
64654ded
BS
1408#undef VECTOR_FOR_INORDER_I
1409#undef HI_IDX
1410#undef LO_IDX
1411
1412/*****************************************************************************/
1413/* SPE extension helpers */
1414/* Use a table to make this quicker */
ea6c0dac 1415static const uint8_t hbrev[16] = {
64654ded
BS
1416 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
1417 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
1418};
1419
1420static inline uint8_t byte_reverse(uint8_t val)
1421{
1422 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
1423}
1424
1425static inline uint32_t word_reverse(uint32_t val)
1426{
1427 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
1428 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
1429}
1430
1431#define MASKBITS 16 /* Random value - to be fixed (implementation dependent) */
1432target_ulong helper_brinc(target_ulong arg1, target_ulong arg2)
1433{
1434 uint32_t a, b, d, mask;
1435
1436 mask = UINT32_MAX >> (32 - MASKBITS);
1437 a = arg1 & mask;
1438 b = arg2 & mask;
1439 d = word_reverse(1 + word_reverse(a | ~b));
1440 return (arg1 & ~mask) | (d & b);
1441}
1442
1443uint32_t helper_cntlsw32(uint32_t val)
1444{
1445 if (val & 0x80000000) {
1446 return clz32(~val);
1447 } else {
1448 return clz32(val);
1449 }
1450}
1451
1452uint32_t helper_cntlzw32(uint32_t val)
1453{
1454 return clz32(val);
1455}
1456
1457/* 440 specific */
d15f74fb
BS
1458target_ulong helper_dlmzb(CPUPPCState *env, target_ulong high,
1459 target_ulong low, uint32_t update_Rc)
64654ded
BS
1460{
1461 target_ulong mask;
1462 int i;
1463
1464 i = 1;
1465 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1466 if ((high & mask) == 0) {
1467 if (update_Rc) {
1468 env->crf[0] = 0x4;
1469 }
1470 goto done;
1471 }
1472 i++;
1473 }
1474 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1475 if ((low & mask) == 0) {
1476 if (update_Rc) {
1477 env->crf[0] = 0x8;
1478 }
1479 goto done;
1480 }
1481 i++;
1482 }
1483 if (update_Rc) {
1484 env->crf[0] = 0x2;
1485 }
1486 done:
1487 env->xer = (env->xer & ~0x7F) | i;
1488 if (update_Rc) {
1489 env->crf[0] |= xer_so;
1490 }
1491 return i;
1492}
This page took 0.399044 seconds and 4 git commands to generate.