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