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