]> git.proxmox.com Git - qemu.git/blame - target-ppc/int_helper.c
Merge remote-tracking branch 'afaerber/qom-cpu' into staging
[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
28/* multiply high word */
29uint64_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 */
38uint64_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
d15f74fb 46uint64_t helper_mulldo(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
64654ded
BS
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
62target_ulong helper_cntlzw(target_ulong t)
63{
64 return clz32(t);
65}
66
67#if defined(TARGET_PPC64)
68target_ulong helper_cntlzd(target_ulong t)
69{
70 return clz64(t);
71}
72#endif
73
74/* shift right arithmetic helper */
d15f74fb
BS
75target_ulong helper_sraw(CPUPPCState *env, target_ulong value,
76 target_ulong shift)
64654ded
BS
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)
d15f74fb
BS
105target_ulong helper_srad(CPUPPCState *env, target_ulong value,
106 target_ulong shift)
64654ded
BS
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)
136target_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
147target_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
162target_ulong helper_popcntd(target_ulong val)
163{
164 return ctpop64(val);
165}
166#else
167target_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
175target_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) */
d15f74fb 188target_ulong helper_div(CPUPPCState *env, target_ulong arg1, target_ulong arg2)
64654ded
BS
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
d15f74fb
BS
202target_ulong helper_divo(CPUPPCState *env, target_ulong arg1,
203 target_ulong arg2)
64654ded
BS
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
d15f74fb
BS
224target_ulong helper_divs(CPUPPCState *env, target_ulong arg1,
225 target_ulong arg2)
64654ded
BS
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
d15f74fb
BS
237target_ulong helper_divso(CPUPPCState *env, target_ulong arg1,
238 target_ulong arg2)
64654ded
BS
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)
261target_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
64654ded
BS
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 }
320SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
321SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
322SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
323
324SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
325SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
326SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
327SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
328SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
329SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
330#undef SATCVT
331#undef SATCVTU
332
333void 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
342void 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
d15f74fb 351void helper_mtvscr(CPUPPCState *env, ppc_avr_t *r)
64654ded
BS
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
361void 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)
382VARITH(ubm, u8)
383VARITH(uhm, u16)
384VARITH(uwm, u32)
385#undef VARITH_DO
386#undef VARITH
387
388#define VARITHFP(suffix, func) \
d15f74fb
BS
389 void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
390 ppc_avr_t *b) \
64654ded
BS
391 { \
392 int i; \
393 \
394 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
ef9bd150 395 r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
64654ded
BS
396 } \
397 }
398VARITHFP(addfp, float32_add)
399VARITHFP(subfp, float32_sub)
db1babb8
AJ
400VARITHFP(minfp, float32_min)
401VARITHFP(maxfp, float32_max)
64654ded
BS
402#undef VARITHFP
403
2f93c23f
AJ
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 }
414VARITHFPFMA(maddfp, 0);
415VARITHFPFMA(nmsubfp, float_muladd_negate_result | float_muladd_negate_c);
416#undef VARITHFPFMA
417
64654ded
BS
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) \
d15f74fb
BS
425 void helper_v##name(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
426 ppc_avr_t *b) \
64654ded
BS
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)
454VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
455VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
456VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
457VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
458VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
459VARITHSAT_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)
480VAVG(b, s8, int16_t, u8, uint16_t)
481VAVG(h, s16, int32_t, u16, uint32_t)
482VAVG(w, s32, int64_t, u32, uint64_t)
483#undef VAVG_DO
484#undef VAVG
485
486#define VCF(suffix, cvt, element) \
d15f74fb
BS
487 void helper_vcf##suffix(CPUPPCState *env, ppc_avr_t *r, \
488 ppc_avr_t *b, uint32_t uim) \
64654ded
BS
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 }
497VCF(ux, uint32_to_float32, u32)
498VCF(sx, int32_to_float32, s32)
499#undef VCF
500
501#define VCMP_DO(suffix, compare, element, record) \
d15f74fb
BS
502 void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
503 ppc_avr_t *a, ppc_avr_t *b) \
64654ded
BS
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)
534VCMP(equb, ==, u8)
535VCMP(equh, ==, u16)
536VCMP(equw, ==, u32)
537VCMP(gtub, >, u8)
538VCMP(gtuh, >, u16)
539VCMP(gtuw, >, u32)
540VCMP(gtsb, >, s8)
541VCMP(gtsh, >, s16)
542VCMP(gtsw, >, s32)
543#undef VCMP_DO
544#undef VCMP
545
546#define VCMPFP_DO(suffix, compare, order, record) \
d15f74fb
BS
547 void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
548 ppc_avr_t *a, ppc_avr_t *b) \
64654ded
BS
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)
577VCMPFP(eqfp, ==, float_relation_equal)
578VCMPFP(gefp, !=, float_relation_less)
579VCMPFP(gtfp, ==, float_relation_greater)
580#undef VCMPFP_DO
581#undef VCMPFP
582
d15f74fb
BS
583static inline void vcmpbfp_internal(CPUPPCState *env, ppc_avr_t *r,
584 ppc_avr_t *a, ppc_avr_t *b, int record)
64654ded
BS
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
d15f74fb 609void helper_vcmpbfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded 610{
d15f74fb 611 vcmpbfp_internal(env, r, a, b, 0);
64654ded
BS
612}
613
d15f74fb
BS
614void helper_vcmpbfp_dot(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
615 ppc_avr_t *b)
64654ded 616{
d15f74fb 617 vcmpbfp_internal(env, r, a, b, 1);
64654ded
BS
618}
619
620#define VCT(suffix, satcvt, element) \
d15f74fb
BS
621 void helper_vct##suffix(CPUPPCState *env, ppc_avr_t *r, \
622 ppc_avr_t *b, uint32_t uim) \
64654ded
BS
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 }
645VCT(uxs, cvtsduw, u32)
646VCT(sxs, cvtsdsw, s32)
647#undef VCT
648
d15f74fb
BS
649void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
650 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
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
d15f74fb
BS
667void helper_vmhraddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
668 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
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)
700VMINMAX(sb, s8)
701VMINMAX(sh, s16)
702VMINMAX(sw, s32)
703VMINMAX(ub, u8)
704VMINMAX(uh, u16)
705VMINMAX(uw, u32)
706#undef VMINMAX_DO
707#undef VMINMAX
708
64654ded
BS
709void 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)
749VMRG(b, u8)
750VMRG(h, u16)
751VMRG(w, u32)
752#undef VMRG_DO
753#undef VMRG
754#undef MRGHI
755#undef MRGLO
756
d15f74fb
BS
757void helper_vmsummbm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
758 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
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
d15f74fb
BS
773void helper_vmsumshm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
774 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
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
d15f74fb
BS
788void helper_vmsumshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
789 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
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
d15f74fb
BS
810void helper_vmsumubm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
811 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
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
d15f74fb
BS
826void helper_vmsumuhm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
827 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
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
d15f74fb
BS
841void helper_vmsumuhs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
842 ppc_avr_t *b, ppc_avr_t *c)
64654ded
BS
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)
881VMUL(sb, s8, s16)
882VMUL(sh, s16, s32)
883VMUL(ub, u8, u16)
884VMUL(uh, u16, u32)
885#undef VMUL_DO
886#undef VMUL
887
d15f74fb
BS
888void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
889 ppc_avr_t *c)
64654ded
BS
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
916void 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) \
d15f74fb
BS
939 void helper_vpk##suffix(CPUPPCState *env, ppc_avr_t *r, \
940 ppc_avr_t *a, ppc_avr_t *b) \
64654ded
BS
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)
958VPK(shss, s16, s8, cvtshsb, 1)
959VPK(shus, s16, u8, cvtshub, 1)
960VPK(swss, s32, s16, cvtswsh, 1)
961VPK(swus, s32, u16, cvtswuh, 1)
962VPK(uhus, u16, u8, cvtuhub, 1)
963VPK(uwus, u32, u16, cvtuwuh, 1)
964VPK(uhum, u16, u8, I, 0)
965VPK(uwum, u32, u16, I, 0)
966#undef I
967#undef VPK
968#undef PKBIG
969
d15f74fb 970void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
971{
972 int i;
973
974 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
ef9bd150 975 r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
64654ded
BS
976 }
977}
978
979#define VRFI(suffix, rounding) \
d15f74fb
BS
980 void helper_vrfi##suffix(CPUPPCState *env, ppc_avr_t *r, \
981 ppc_avr_t *b) \
64654ded
BS
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++) { \
ef9bd150 988 r->f[i] = float32_round_to_int (b->f[i], &s); \
64654ded
BS
989 } \
990 }
991VRFI(n, float_round_nearest_even)
992VRFI(m, float_round_down)
993VRFI(p, float_round_up)
994VRFI(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 }
1011VROTATE(b, u8)
1012VROTATE(h, u16)
1013VROTATE(w, u32)
1014#undef VROTATE
1015
d15f74fb 1016void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1017{
1018 int i;
1019
1020 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
ef9bd150 1021 float32 t = float32_sqrt(b->f[i], &env->vec_status);
64654ded 1022
ef9bd150 1023 r->f[i] = float32_div(float32_one, t, &env->vec_status);
64654ded
BS
1024 }
1025}
1026
d15f74fb
BS
1027void helper_vsel(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
1028 ppc_avr_t *c)
64654ded
BS
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
d15f74fb 1034void helper_vexptefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
64654ded
BS
1035{
1036 int i;
1037
1038 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
ef9bd150 1039 r->f[i] = float32_exp2(b->f[i], &env->vec_status);
64654ded
BS
1040 }
1041}
1042
d15f74fb 1043void helper_vlogefp(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_log2(b->f[i], &env->vec_status);
64654ded
BS
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 }
1088VSHIFT(l, LEFT)
1089VSHIFT(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 }
1108VSL(b, u8)
1109VSL(h, u16)
1110VSL(w, u32)
1111#undef VSL
1112
1113void 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
1141void 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 }
1172VSPLT(b, u8)
1173VSPLT(h, u16)
1174VSPLT(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 }
1189VSPLTI(b, s8, int8_t)
1190VSPLTI(h, s16, int16_t)
1191VSPLTI(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 }
1208VSR(ab, s8)
1209VSR(ah, s16)
1210VSR(aw, s32)
1211VSR(b, u8)
1212VSR(h, u16)
1213VSR(w, u32)
1214#undef VSR
1215
1216void 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
1229void 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
d15f74fb 1238void helper_vsumsws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
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
d15f74fb 1263void helper_vsum2sws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
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
d15f74fb 1290void helper_vsum4sbs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
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
d15f74fb 1309void helper_vsum4shs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
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
d15f74fb 1326void helper_vsum4ubs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
64654ded
BS
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 }
1369VUPKPX(lpx, UPKLO)
1370VUPKPX(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 }
1391VUPK(hsb, s16, s8, UPKHI)
1392VUPK(hsh, s32, s16, UPKHI)
1393VUPK(lsb, s16, s8, UPKLO)
1394VUPK(lsh, s32, s16, UPKLO)
1395#undef VUPK
1396#undef UPKHI
1397#undef UPKLO
1398
64654ded
BS
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 */
ea6c0dac 1406static const uint8_t hbrev[16] = {
64654ded
BS
1407 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
1408 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
1409};
1410
1411static inline uint8_t byte_reverse(uint8_t val)
1412{
1413 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
1414}
1415
1416static 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) */
1423target_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
1434uint32_t helper_cntlsw32(uint32_t val)
1435{
1436 if (val & 0x80000000) {
1437 return clz32(~val);
1438 } else {
1439 return clz32(val);
1440 }
1441}
1442
1443uint32_t helper_cntlzw32(uint32_t val)
1444{
1445 return clz32(val);
1446}
1447
1448/* 440 specific */
d15f74fb
BS
1449target_ulong helper_dlmzb(CPUPPCState *env, target_ulong high,
1450 target_ulong low, uint32_t update_Rc)
64654ded
BS
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}