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