]> git.proxmox.com Git - mirror_qemu.git/blob - target-ppc/int_helper.c
target-ppc: Add ISA2.06 bpermd Instruction
[mirror_qemu.git] / target-ppc / int_helper.c
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"
20 #include "qemu/host-utils.h"
21 #include "helper.h"
22
23 #include "helper_regs.h"
24 /*****************************************************************************/
25 /* Fixed point operations helpers */
26 #if defined(TARGET_PPC64)
27
28 uint64_t helper_mulldo(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
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)) {
36 env->ov = 0;
37 } else {
38 env->so = env->ov = 1;
39 }
40 return (int64_t)tl;
41 }
42 #endif
43
44 target_ulong helper_cntlzw(target_ulong t)
45 {
46 return clz32(t);
47 }
48
49 #if defined(TARGET_PPC64)
50 target_ulong helper_cntlzd(target_ulong t)
51 {
52 return clz64(t);
53 }
54 #endif
55
56 #if defined(TARGET_PPC64)
57
58 uint64_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
76 target_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
91 /* shift right arithmetic helper */
92 target_ulong helper_sraw(CPUPPCState *env, target_ulong value,
93 target_ulong shift)
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)) {
102 env->ca = 0;
103 } else {
104 env->ca = 1;
105 }
106 } else {
107 ret = (int32_t)value;
108 env->ca = 0;
109 }
110 } else {
111 ret = (int32_t)value >> 31;
112 env->ca = (ret != 0);
113 }
114 return (target_long)ret;
115 }
116
117 #if defined(TARGET_PPC64)
118 target_ulong helper_srad(CPUPPCState *env, target_ulong value,
119 target_ulong shift)
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)) {
128 env->ca = 0;
129 } else {
130 env->ca = 1;
131 }
132 } else {
133 ret = (int64_t)value;
134 env->ca = 0;
135 }
136 } else {
137 ret = (int64_t)value >> 63;
138 env->ca = (ret != 0);
139 }
140 return ret;
141 }
142 #endif
143
144 #if defined(TARGET_PPC64)
145 target_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
156 target_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
171 target_ulong helper_popcntd(target_ulong val)
172 {
173 return ctpop64(val);
174 }
175 #else
176 target_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
184 target_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) */
197 target_ulong helper_div(CPUPPCState *env, target_ulong arg1, target_ulong arg2)
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
211 target_ulong helper_divo(CPUPPCState *env, target_ulong arg1,
212 target_ulong arg2)
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) {
218 env->so = env->ov = 1;
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) {
225 env->so = env->ov = 1;
226 } else {
227 env->ov = 0;
228 }
229 return tmp;
230 }
231 }
232
233 target_ulong helper_divs(CPUPPCState *env, target_ulong arg1,
234 target_ulong arg2)
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
246 target_ulong helper_divso(CPUPPCState *env, target_ulong arg1,
247 target_ulong arg2)
248 {
249 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
250 (int32_t)arg2 == 0) {
251 env->so = env->ov = 1;
252 env->spr[SPR_MQ] = 0;
253 return INT32_MIN;
254 } else {
255 env->ov = 0;
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)
270 target_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
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 }
329 SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
330 SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
331 SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
332
333 SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
334 SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
335 SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
336 SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
337 SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
338 SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
339 #undef SATCVT
340 #undef SATCVTU
341
342 void 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
351 void 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
360 void helper_mtvscr(CPUPPCState *env, ppc_avr_t *r)
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
370 void 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)
391 VARITH(ubm, u8)
392 VARITH(uhm, u16)
393 VARITH(uwm, u32)
394 #undef VARITH_DO
395 #undef VARITH
396
397 #define VARITHFP(suffix, func) \
398 void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
399 ppc_avr_t *b) \
400 { \
401 int i; \
402 \
403 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
404 r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
405 } \
406 }
407 VARITHFP(addfp, float32_add)
408 VARITHFP(subfp, float32_sub)
409 VARITHFP(minfp, float32_min)
410 VARITHFP(maxfp, float32_max)
411 #undef VARITHFP
412
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 }
423 VARITHFPFMA(maddfp, 0);
424 VARITHFPFMA(nmsubfp, float_muladd_negate_result | float_muladd_negate_c);
425 #undef VARITHFPFMA
426
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) \
434 void helper_v##name(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
435 ppc_avr_t *b) \
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)
463 VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
464 VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
465 VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
466 VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
467 VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
468 VARITHSAT_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)
489 VAVG(b, s8, int16_t, u8, uint16_t)
490 VAVG(h, s16, int32_t, u16, uint32_t)
491 VAVG(w, s32, int64_t, u32, uint64_t)
492 #undef VAVG_DO
493 #undef VAVG
494
495 #define VCF(suffix, cvt, element) \
496 void helper_vcf##suffix(CPUPPCState *env, ppc_avr_t *r, \
497 ppc_avr_t *b, uint32_t uim) \
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 }
506 VCF(ux, uint32_to_float32, u32)
507 VCF(sx, int32_to_float32, s32)
508 #undef VCF
509
510 #define VCMP_DO(suffix, compare, element, record) \
511 void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
512 ppc_avr_t *a, ppc_avr_t *b) \
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)
543 VCMP(equb, ==, u8)
544 VCMP(equh, ==, u16)
545 VCMP(equw, ==, u32)
546 VCMP(gtub, >, u8)
547 VCMP(gtuh, >, u16)
548 VCMP(gtuw, >, u32)
549 VCMP(gtsb, >, s8)
550 VCMP(gtsh, >, s16)
551 VCMP(gtsw, >, s32)
552 #undef VCMP_DO
553 #undef VCMP
554
555 #define VCMPFP_DO(suffix, compare, order, record) \
556 void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
557 ppc_avr_t *a, ppc_avr_t *b) \
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)
586 VCMPFP(eqfp, ==, float_relation_equal)
587 VCMPFP(gefp, !=, float_relation_less)
588 VCMPFP(gtfp, ==, float_relation_greater)
589 #undef VCMPFP_DO
590 #undef VCMPFP
591
592 static inline void vcmpbfp_internal(CPUPPCState *env, ppc_avr_t *r,
593 ppc_avr_t *a, ppc_avr_t *b, int record)
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
618 void helper_vcmpbfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
619 {
620 vcmpbfp_internal(env, r, a, b, 0);
621 }
622
623 void helper_vcmpbfp_dot(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
624 ppc_avr_t *b)
625 {
626 vcmpbfp_internal(env, r, a, b, 1);
627 }
628
629 #define VCT(suffix, satcvt, element) \
630 void helper_vct##suffix(CPUPPCState *env, ppc_avr_t *r, \
631 ppc_avr_t *b, uint32_t uim) \
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 }
654 VCT(uxs, cvtsduw, u32)
655 VCT(sxs, cvtsdsw, s32)
656 #undef VCT
657
658 void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
659 ppc_avr_t *b, ppc_avr_t *c)
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
676 void helper_vmhraddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
677 ppc_avr_t *b, ppc_avr_t *c)
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)
709 VMINMAX(sb, s8)
710 VMINMAX(sh, s16)
711 VMINMAX(sw, s32)
712 VMINMAX(ub, u8)
713 VMINMAX(uh, u16)
714 VMINMAX(uw, u32)
715 #undef VMINMAX_DO
716 #undef VMINMAX
717
718 void 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)
758 VMRG(b, u8)
759 VMRG(h, u16)
760 VMRG(w, u32)
761 #undef VMRG_DO
762 #undef VMRG
763 #undef MRGHI
764 #undef MRGLO
765
766 void helper_vmsummbm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
767 ppc_avr_t *b, ppc_avr_t *c)
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
782 void helper_vmsumshm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
783 ppc_avr_t *b, ppc_avr_t *c)
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
797 void helper_vmsumshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
798 ppc_avr_t *b, ppc_avr_t *c)
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
819 void helper_vmsumubm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
820 ppc_avr_t *b, ppc_avr_t *c)
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
835 void helper_vmsumuhm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
836 ppc_avr_t *b, ppc_avr_t *c)
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
850 void helper_vmsumuhs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
851 ppc_avr_t *b, ppc_avr_t *c)
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)
890 VMUL(sb, s8, s16)
891 VMUL(sh, s16, s32)
892 VMUL(ub, u8, u16)
893 VMUL(uh, u16, u32)
894 #undef VMUL_DO
895 #undef VMUL
896
897 void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
898 ppc_avr_t *c)
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
925 void 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) \
948 void helper_vpk##suffix(CPUPPCState *env, ppc_avr_t *r, \
949 ppc_avr_t *a, ppc_avr_t *b) \
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)
967 VPK(shss, s16, s8, cvtshsb, 1)
968 VPK(shus, s16, u8, cvtshub, 1)
969 VPK(swss, s32, s16, cvtswsh, 1)
970 VPK(swus, s32, u16, cvtswuh, 1)
971 VPK(uhus, u16, u8, cvtuhub, 1)
972 VPK(uwus, u32, u16, cvtuwuh, 1)
973 VPK(uhum, u16, u8, I, 0)
974 VPK(uwum, u32, u16, I, 0)
975 #undef I
976 #undef VPK
977 #undef PKBIG
978
979 void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
980 {
981 int i;
982
983 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
984 r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
985 }
986 }
987
988 #define VRFI(suffix, rounding) \
989 void helper_vrfi##suffix(CPUPPCState *env, ppc_avr_t *r, \
990 ppc_avr_t *b) \
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++) { \
997 r->f[i] = float32_round_to_int (b->f[i], &s); \
998 } \
999 }
1000 VRFI(n, float_round_nearest_even)
1001 VRFI(m, float_round_down)
1002 VRFI(p, float_round_up)
1003 VRFI(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 }
1020 VROTATE(b, u8)
1021 VROTATE(h, u16)
1022 VROTATE(w, u32)
1023 #undef VROTATE
1024
1025 void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
1026 {
1027 int i;
1028
1029 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
1030 float32 t = float32_sqrt(b->f[i], &env->vec_status);
1031
1032 r->f[i] = float32_div(float32_one, t, &env->vec_status);
1033 }
1034 }
1035
1036 void helper_vsel(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
1037 ppc_avr_t *c)
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
1043 void helper_vexptefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
1044 {
1045 int i;
1046
1047 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
1048 r->f[i] = float32_exp2(b->f[i], &env->vec_status);
1049 }
1050 }
1051
1052 void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
1053 {
1054 int i;
1055
1056 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
1057 r->f[i] = float32_log2(b->f[i], &env->vec_status);
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 }
1097 VSHIFT(l, LEFT)
1098 VSHIFT(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 }
1117 VSL(b, u8)
1118 VSL(h, u16)
1119 VSL(w, u32)
1120 #undef VSL
1121
1122 void 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
1150 void 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 }
1181 VSPLT(b, u8)
1182 VSPLT(h, u16)
1183 VSPLT(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 }
1198 VSPLTI(b, s8, int8_t)
1199 VSPLTI(h, s16, int16_t)
1200 VSPLTI(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 }
1217 VSR(ab, s8)
1218 VSR(ah, s16)
1219 VSR(aw, s32)
1220 VSR(b, u8)
1221 VSR(h, u16)
1222 VSR(w, u32)
1223 #undef VSR
1224
1225 void 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
1238 void 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
1247 void helper_vsumsws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
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
1272 void helper_vsum2sws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
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
1299 void helper_vsum4sbs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
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
1318 void helper_vsum4shs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
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
1335 void helper_vsum4ubs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
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 }
1378 VUPKPX(lpx, UPKLO)
1379 VUPKPX(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 }
1400 VUPK(hsb, s16, s8, UPKHI)
1401 VUPK(hsh, s32, s16, UPKHI)
1402 VUPK(lsb, s16, s8, UPKLO)
1403 VUPK(lsh, s32, s16, UPKLO)
1404 #undef VUPK
1405 #undef UPKHI
1406 #undef UPKLO
1407
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 */
1415 static const uint8_t hbrev[16] = {
1416 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
1417 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
1418 };
1419
1420 static inline uint8_t byte_reverse(uint8_t val)
1421 {
1422 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
1423 }
1424
1425 static 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) */
1432 target_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
1443 uint32_t helper_cntlsw32(uint32_t val)
1444 {
1445 if (val & 0x80000000) {
1446 return clz32(~val);
1447 } else {
1448 return clz32(val);
1449 }
1450 }
1451
1452 uint32_t helper_cntlzw32(uint32_t val)
1453 {
1454 return clz32(val);
1455 }
1456
1457 /* 440 specific */
1458 target_ulong helper_dlmzb(CPUPPCState *env, target_ulong high,
1459 target_ulong low, uint32_t update_Rc)
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 }