xref: /openbmc/qemu/target/ppc/int_helper.c (revision 40f3e79a862554553811d0681c05e00a4705e91c)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  *  PowerPC integer and vector emulation helpers for QEMU.
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  *  Copyright (c) 2003-2007 Jocelyn Mayer
5fcf5ef2aSThomas Huth  *
6fcf5ef2aSThomas Huth  * This library is free software; you can redistribute it and/or
7fcf5ef2aSThomas Huth  * modify it under the terms of the GNU Lesser General Public
8fcf5ef2aSThomas Huth  * License as published by the Free Software Foundation; either
96bd039cdSChetan Pant  * version 2.1 of the License, or (at your option) any later version.
10fcf5ef2aSThomas Huth  *
11fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
12fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14fcf5ef2aSThomas Huth  * Lesser General Public License for more details.
15fcf5ef2aSThomas Huth  *
16fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
17fcf5ef2aSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18fcf5ef2aSThomas Huth  */
19db725815SMarkus Armbruster 
20fcf5ef2aSThomas Huth #include "qemu/osdep.h"
21fcf5ef2aSThomas Huth #include "cpu.h"
22fcf5ef2aSThomas Huth #include "internal.h"
23fcf5ef2aSThomas Huth #include "qemu/host-utils.h"
24db725815SMarkus Armbruster #include "qemu/main-loop.h"
258a05fd9aSRichard Henderson #include "qemu/log.h"
26fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
27fcf5ef2aSThomas Huth #include "crypto/aes.h"
2824f91e81SAlex Bennée #include "fpu/softfloat.h"
293f74b632SRichard Henderson #include "qapi/error.h"
303f74b632SRichard Henderson #include "qemu/guest-random.h"
31fcf5ef2aSThomas Huth 
32fcf5ef2aSThomas Huth #include "helper_regs.h"
33fcf5ef2aSThomas Huth /*****************************************************************************/
34fcf5ef2aSThomas Huth /* Fixed point operations helpers */
35fcf5ef2aSThomas Huth 
36f32899deSNikunj A Dadhania static inline void helper_update_ov_legacy(CPUPPCState *env, int ov)
37f32899deSNikunj A Dadhania {
38f32899deSNikunj A Dadhania     if (unlikely(ov)) {
39f32899deSNikunj A Dadhania         env->so = env->ov = 1;
40f32899deSNikunj A Dadhania     } else {
41f32899deSNikunj A Dadhania         env->ov = 0;
42f32899deSNikunj A Dadhania     }
43f32899deSNikunj A Dadhania }
44f32899deSNikunj A Dadhania 
45fcf5ef2aSThomas Huth target_ulong helper_divweu(CPUPPCState *env, target_ulong ra, target_ulong rb,
46fcf5ef2aSThomas Huth                            uint32_t oe)
47fcf5ef2aSThomas Huth {
48fcf5ef2aSThomas Huth     uint64_t rt = 0;
49fcf5ef2aSThomas Huth     int overflow = 0;
50fcf5ef2aSThomas Huth 
51fcf5ef2aSThomas Huth     uint64_t dividend = (uint64_t)ra << 32;
52fcf5ef2aSThomas Huth     uint64_t divisor = (uint32_t)rb;
53fcf5ef2aSThomas Huth 
54fcf5ef2aSThomas Huth     if (unlikely(divisor == 0)) {
55fcf5ef2aSThomas Huth         overflow = 1;
56fcf5ef2aSThomas Huth     } else {
57fcf5ef2aSThomas Huth         rt = dividend / divisor;
58fcf5ef2aSThomas Huth         overflow = rt > UINT32_MAX;
59fcf5ef2aSThomas Huth     }
60fcf5ef2aSThomas Huth 
61fcf5ef2aSThomas Huth     if (unlikely(overflow)) {
62fcf5ef2aSThomas Huth         rt = 0; /* Undefined */
63fcf5ef2aSThomas Huth     }
64fcf5ef2aSThomas Huth 
65fcf5ef2aSThomas Huth     if (oe) {
66f32899deSNikunj A Dadhania         helper_update_ov_legacy(env, overflow);
67fcf5ef2aSThomas Huth     }
68fcf5ef2aSThomas Huth 
69fcf5ef2aSThomas Huth     return (target_ulong)rt;
70fcf5ef2aSThomas Huth }
71fcf5ef2aSThomas Huth 
72fcf5ef2aSThomas Huth target_ulong helper_divwe(CPUPPCState *env, target_ulong ra, target_ulong rb,
73fcf5ef2aSThomas Huth                           uint32_t oe)
74fcf5ef2aSThomas Huth {
75fcf5ef2aSThomas Huth     int64_t rt = 0;
76fcf5ef2aSThomas Huth     int overflow = 0;
77fcf5ef2aSThomas Huth 
78fcf5ef2aSThomas Huth     int64_t dividend = (int64_t)ra << 32;
79fcf5ef2aSThomas Huth     int64_t divisor = (int64_t)((int32_t)rb);
80fcf5ef2aSThomas Huth 
81fcf5ef2aSThomas Huth     if (unlikely((divisor == 0) ||
82fcf5ef2aSThomas Huth                  ((divisor == -1ull) && (dividend == INT64_MIN)))) {
83fcf5ef2aSThomas Huth         overflow = 1;
84fcf5ef2aSThomas Huth     } else {
85fcf5ef2aSThomas Huth         rt = dividend / divisor;
86fcf5ef2aSThomas Huth         overflow = rt != (int32_t)rt;
87fcf5ef2aSThomas Huth     }
88fcf5ef2aSThomas Huth 
89fcf5ef2aSThomas Huth     if (unlikely(overflow)) {
90fcf5ef2aSThomas Huth         rt = 0; /* Undefined */
91fcf5ef2aSThomas Huth     }
92fcf5ef2aSThomas Huth 
93fcf5ef2aSThomas Huth     if (oe) {
94f32899deSNikunj A Dadhania         helper_update_ov_legacy(env, overflow);
95fcf5ef2aSThomas Huth     }
96fcf5ef2aSThomas Huth 
97fcf5ef2aSThomas Huth     return (target_ulong)rt;
98fcf5ef2aSThomas Huth }
99fcf5ef2aSThomas Huth 
100fcf5ef2aSThomas Huth #if defined(TARGET_PPC64)
101fcf5ef2aSThomas Huth 
102fcf5ef2aSThomas Huth uint64_t helper_divdeu(CPUPPCState *env, uint64_t ra, uint64_t rb, uint32_t oe)
103fcf5ef2aSThomas Huth {
104fcf5ef2aSThomas Huth     uint64_t rt = 0;
105fcf5ef2aSThomas Huth     int overflow = 0;
106fcf5ef2aSThomas Huth 
1079276a31cSLuis Pires     if (unlikely(rb == 0 || ra >= rb)) {
1089276a31cSLuis Pires         overflow = 1;
109fcf5ef2aSThomas Huth         rt = 0; /* Undefined */
1109276a31cSLuis Pires     } else {
1119276a31cSLuis Pires         divu128(&rt, &ra, rb);
112fcf5ef2aSThomas Huth     }
113fcf5ef2aSThomas Huth 
114fcf5ef2aSThomas Huth     if (oe) {
115f32899deSNikunj A Dadhania         helper_update_ov_legacy(env, overflow);
116fcf5ef2aSThomas Huth     }
117fcf5ef2aSThomas Huth 
118fcf5ef2aSThomas Huth     return rt;
119fcf5ef2aSThomas Huth }
120fcf5ef2aSThomas Huth 
121fcf5ef2aSThomas Huth uint64_t helper_divde(CPUPPCState *env, uint64_t rau, uint64_t rbu, uint32_t oe)
122fcf5ef2aSThomas Huth {
123*40f3e79aSLuis Pires     uint64_t rt = 0;
124fcf5ef2aSThomas Huth     int64_t ra = (int64_t)rau;
125fcf5ef2aSThomas Huth     int64_t rb = (int64_t)rbu;
1269276a31cSLuis Pires     int overflow = 0;
127fcf5ef2aSThomas Huth 
1289276a31cSLuis Pires     if (unlikely(rb == 0 || uabs64(ra) >= uabs64(rb))) {
1299276a31cSLuis Pires         overflow = 1;
130fcf5ef2aSThomas Huth         rt = 0; /* Undefined */
1319276a31cSLuis Pires     } else {
1329276a31cSLuis Pires         divs128(&rt, &ra, rb);
133fcf5ef2aSThomas Huth     }
134fcf5ef2aSThomas Huth 
135fcf5ef2aSThomas Huth     if (oe) {
136f32899deSNikunj A Dadhania         helper_update_ov_legacy(env, overflow);
137fcf5ef2aSThomas Huth     }
138fcf5ef2aSThomas Huth 
139fcf5ef2aSThomas Huth     return rt;
140fcf5ef2aSThomas Huth }
141fcf5ef2aSThomas Huth 
142fcf5ef2aSThomas Huth #endif
143fcf5ef2aSThomas Huth 
144fcf5ef2aSThomas Huth 
145fcf5ef2aSThomas Huth #if defined(TARGET_PPC64)
146fcf5ef2aSThomas Huth /* if x = 0xab, returns 0xababababababababa */
147fcf5ef2aSThomas Huth #define pattern(x) (((x) & 0xff) * (~(target_ulong)0 / 0xff))
148fcf5ef2aSThomas Huth 
149b6cb41b2SDavid Gibson /*
150b6cb41b2SDavid Gibson  * subtract 1 from each byte, and with inverse, check if MSB is set at each
151fcf5ef2aSThomas Huth  * byte.
152fcf5ef2aSThomas Huth  * i.e. ((0x00 - 0x01) & ~(0x00)) & 0x80
153fcf5ef2aSThomas Huth  *      (0xFF & 0xFF) & 0x80 = 0x80 (zero found)
154fcf5ef2aSThomas Huth  */
155fcf5ef2aSThomas Huth #define haszero(v) (((v) - pattern(0x01)) & ~(v) & pattern(0x80))
156fcf5ef2aSThomas Huth 
157fcf5ef2aSThomas Huth /* When you XOR the pattern and there is a match, that byte will be zero */
158fcf5ef2aSThomas Huth #define hasvalue(x, n)  (haszero((x) ^ pattern(n)))
159fcf5ef2aSThomas Huth 
160fcf5ef2aSThomas Huth uint32_t helper_cmpeqb(target_ulong ra, target_ulong rb)
161fcf5ef2aSThomas Huth {
162efa73196SNikunj A Dadhania     return hasvalue(rb, ra) ? CRF_GT : 0;
163fcf5ef2aSThomas Huth }
164fcf5ef2aSThomas Huth 
165fcf5ef2aSThomas Huth #undef pattern
166fcf5ef2aSThomas Huth #undef haszero
167fcf5ef2aSThomas Huth #undef hasvalue
168fcf5ef2aSThomas Huth 
169b6cb41b2SDavid Gibson /*
1703f74b632SRichard Henderson  * Return a random number.
171fcf5ef2aSThomas Huth  */
1723f74b632SRichard Henderson uint64_t helper_darn32(void)
173fcf5ef2aSThomas Huth {
1743f74b632SRichard Henderson     Error *err = NULL;
1753f74b632SRichard Henderson     uint32_t ret;
1763f74b632SRichard Henderson 
1773f74b632SRichard Henderson     if (qemu_guest_getrandom(&ret, sizeof(ret), &err) < 0) {
1783f74b632SRichard Henderson         qemu_log_mask(LOG_UNIMP, "darn: Crypto failure: %s",
1793f74b632SRichard Henderson                       error_get_pretty(err));
1803f74b632SRichard Henderson         error_free(err);
181fcf5ef2aSThomas Huth         return -1;
182fcf5ef2aSThomas Huth     }
183fcf5ef2aSThomas Huth 
1843f74b632SRichard Henderson     return ret;
1853f74b632SRichard Henderson }
1863f74b632SRichard Henderson 
1873f74b632SRichard Henderson uint64_t helper_darn64(void)
188fcf5ef2aSThomas Huth {
1893f74b632SRichard Henderson     Error *err = NULL;
1903f74b632SRichard Henderson     uint64_t ret;
1913f74b632SRichard Henderson 
1923f74b632SRichard Henderson     if (qemu_guest_getrandom(&ret, sizeof(ret), &err) < 0) {
1933f74b632SRichard Henderson         qemu_log_mask(LOG_UNIMP, "darn: Crypto failure: %s",
1943f74b632SRichard Henderson                       error_get_pretty(err));
1953f74b632SRichard Henderson         error_free(err);
196fcf5ef2aSThomas Huth         return -1;
197fcf5ef2aSThomas Huth     }
198fcf5ef2aSThomas Huth 
1993f74b632SRichard Henderson     return ret;
2003f74b632SRichard Henderson }
201fcf5ef2aSThomas Huth 
202fcf5ef2aSThomas Huth uint64_t helper_bpermd(uint64_t rs, uint64_t rb)
203fcf5ef2aSThomas Huth {
204fcf5ef2aSThomas Huth     int i;
205fcf5ef2aSThomas Huth     uint64_t ra = 0;
206fcf5ef2aSThomas Huth 
207fcf5ef2aSThomas Huth     for (i = 0; i < 8; i++) {
208fcf5ef2aSThomas Huth         int index = (rs >> (i * 8)) & 0xFF;
209fcf5ef2aSThomas Huth         if (index < 64) {
210a6a444a8SCédric Le Goater             if (rb & PPC_BIT(index)) {
211fcf5ef2aSThomas Huth                 ra |= 1 << i;
212fcf5ef2aSThomas Huth             }
213fcf5ef2aSThomas Huth         }
214fcf5ef2aSThomas Huth     }
215fcf5ef2aSThomas Huth     return ra;
216fcf5ef2aSThomas Huth }
217fcf5ef2aSThomas Huth 
218fcf5ef2aSThomas Huth #endif
219fcf5ef2aSThomas Huth 
220fcf5ef2aSThomas Huth target_ulong helper_cmpb(target_ulong rs, target_ulong rb)
221fcf5ef2aSThomas Huth {
222fcf5ef2aSThomas Huth     target_ulong mask = 0xff;
223fcf5ef2aSThomas Huth     target_ulong ra = 0;
224fcf5ef2aSThomas Huth     int i;
225fcf5ef2aSThomas Huth 
226fcf5ef2aSThomas Huth     for (i = 0; i < sizeof(target_ulong); i++) {
227fcf5ef2aSThomas Huth         if ((rs & mask) == (rb & mask)) {
228fcf5ef2aSThomas Huth             ra |= mask;
229fcf5ef2aSThomas Huth         }
230fcf5ef2aSThomas Huth         mask <<= 8;
231fcf5ef2aSThomas Huth     }
232fcf5ef2aSThomas Huth     return ra;
233fcf5ef2aSThomas Huth }
234fcf5ef2aSThomas Huth 
235fcf5ef2aSThomas Huth /* shift right arithmetic helper */
236fcf5ef2aSThomas Huth target_ulong helper_sraw(CPUPPCState *env, target_ulong value,
237fcf5ef2aSThomas Huth                          target_ulong shift)
238fcf5ef2aSThomas Huth {
239fcf5ef2aSThomas Huth     int32_t ret;
240fcf5ef2aSThomas Huth 
241fcf5ef2aSThomas Huth     if (likely(!(shift & 0x20))) {
242fcf5ef2aSThomas Huth         if (likely((uint32_t)shift != 0)) {
243fcf5ef2aSThomas Huth             shift &= 0x1f;
244fcf5ef2aSThomas Huth             ret = (int32_t)value >> shift;
245fcf5ef2aSThomas Huth             if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
246af1c259fSSandipan Das                 env->ca32 = env->ca = 0;
247fcf5ef2aSThomas Huth             } else {
248af1c259fSSandipan Das                 env->ca32 = env->ca = 1;
249fcf5ef2aSThomas Huth             }
250fcf5ef2aSThomas Huth         } else {
251fcf5ef2aSThomas Huth             ret = (int32_t)value;
252af1c259fSSandipan Das             env->ca32 = env->ca = 0;
253fcf5ef2aSThomas Huth         }
254fcf5ef2aSThomas Huth     } else {
255fcf5ef2aSThomas Huth         ret = (int32_t)value >> 31;
256af1c259fSSandipan Das         env->ca32 = env->ca = (ret != 0);
257fcf5ef2aSThomas Huth     }
258fcf5ef2aSThomas Huth     return (target_long)ret;
259fcf5ef2aSThomas Huth }
260fcf5ef2aSThomas Huth 
261fcf5ef2aSThomas Huth #if defined(TARGET_PPC64)
262fcf5ef2aSThomas Huth target_ulong helper_srad(CPUPPCState *env, target_ulong value,
263fcf5ef2aSThomas Huth                          target_ulong shift)
264fcf5ef2aSThomas Huth {
265fcf5ef2aSThomas Huth     int64_t ret;
266fcf5ef2aSThomas Huth 
267fcf5ef2aSThomas Huth     if (likely(!(shift & 0x40))) {
268fcf5ef2aSThomas Huth         if (likely((uint64_t)shift != 0)) {
269fcf5ef2aSThomas Huth             shift &= 0x3f;
270fcf5ef2aSThomas Huth             ret = (int64_t)value >> shift;
271fcf5ef2aSThomas Huth             if (likely(ret >= 0 || (value & ((1ULL << shift) - 1)) == 0)) {
272af1c259fSSandipan Das                 env->ca32 = env->ca = 0;
273fcf5ef2aSThomas Huth             } else {
274af1c259fSSandipan Das                 env->ca32 = env->ca = 1;
275fcf5ef2aSThomas Huth             }
276fcf5ef2aSThomas Huth         } else {
277fcf5ef2aSThomas Huth             ret = (int64_t)value;
278af1c259fSSandipan Das             env->ca32 = env->ca = 0;
279fcf5ef2aSThomas Huth         }
280fcf5ef2aSThomas Huth     } else {
281fcf5ef2aSThomas Huth         ret = (int64_t)value >> 63;
282af1c259fSSandipan Das         env->ca32 = env->ca = (ret != 0);
283fcf5ef2aSThomas Huth     }
284fcf5ef2aSThomas Huth     return ret;
285fcf5ef2aSThomas Huth }
286fcf5ef2aSThomas Huth #endif
287fcf5ef2aSThomas Huth 
288fcf5ef2aSThomas Huth #if defined(TARGET_PPC64)
289fcf5ef2aSThomas Huth target_ulong helper_popcntb(target_ulong val)
290fcf5ef2aSThomas Huth {
29179770002SRichard Henderson     /* Note that we don't fold past bytes */
292fcf5ef2aSThomas Huth     val = (val & 0x5555555555555555ULL) + ((val >>  1) &
293fcf5ef2aSThomas Huth                                            0x5555555555555555ULL);
294fcf5ef2aSThomas Huth     val = (val & 0x3333333333333333ULL) + ((val >>  2) &
295fcf5ef2aSThomas Huth                                            0x3333333333333333ULL);
296fcf5ef2aSThomas Huth     val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) &
297fcf5ef2aSThomas Huth                                            0x0f0f0f0f0f0f0f0fULL);
298fcf5ef2aSThomas Huth     return val;
299fcf5ef2aSThomas Huth }
300fcf5ef2aSThomas Huth 
301fcf5ef2aSThomas Huth target_ulong helper_popcntw(target_ulong val)
302fcf5ef2aSThomas Huth {
30379770002SRichard Henderson     /* Note that we don't fold past words.  */
304fcf5ef2aSThomas Huth     val = (val & 0x5555555555555555ULL) + ((val >>  1) &
305fcf5ef2aSThomas Huth                                            0x5555555555555555ULL);
306fcf5ef2aSThomas Huth     val = (val & 0x3333333333333333ULL) + ((val >>  2) &
307fcf5ef2aSThomas Huth                                            0x3333333333333333ULL);
308fcf5ef2aSThomas Huth     val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) &
309fcf5ef2aSThomas Huth                                            0x0f0f0f0f0f0f0f0fULL);
310fcf5ef2aSThomas Huth     val = (val & 0x00ff00ff00ff00ffULL) + ((val >>  8) &
311fcf5ef2aSThomas Huth                                            0x00ff00ff00ff00ffULL);
312fcf5ef2aSThomas Huth     val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
313fcf5ef2aSThomas Huth                                            0x0000ffff0000ffffULL);
314fcf5ef2aSThomas Huth     return val;
315fcf5ef2aSThomas Huth }
316fcf5ef2aSThomas Huth #else
317fcf5ef2aSThomas Huth target_ulong helper_popcntb(target_ulong val)
318fcf5ef2aSThomas Huth {
31979770002SRichard Henderson     /* Note that we don't fold past bytes */
320fcf5ef2aSThomas Huth     val = (val & 0x55555555) + ((val >>  1) & 0x55555555);
321fcf5ef2aSThomas Huth     val = (val & 0x33333333) + ((val >>  2) & 0x33333333);
322fcf5ef2aSThomas Huth     val = (val & 0x0f0f0f0f) + ((val >>  4) & 0x0f0f0f0f);
323fcf5ef2aSThomas Huth     return val;
324fcf5ef2aSThomas Huth }
325fcf5ef2aSThomas Huth #endif
326fcf5ef2aSThomas Huth 
32789ccd7dcSMatheus Ferst uint64_t helper_cfuged(uint64_t src, uint64_t mask)
32889ccd7dcSMatheus Ferst {
32989ccd7dcSMatheus Ferst     /*
33089ccd7dcSMatheus Ferst      * Instead of processing the mask bit-by-bit from the most significant to
33189ccd7dcSMatheus Ferst      * the least significant bit, as described in PowerISA, we'll handle it in
33289ccd7dcSMatheus Ferst      * blocks of 'n' zeros/ones from LSB to MSB. To avoid the decision to use
33389ccd7dcSMatheus Ferst      * ctz or cto, we negate the mask at the end of the loop.
33489ccd7dcSMatheus Ferst      */
33589ccd7dcSMatheus Ferst     target_ulong m, left = 0, right = 0;
33689ccd7dcSMatheus Ferst     unsigned int n, i = 64;
33789ccd7dcSMatheus Ferst     bool bit = false; /* tracks if we are processing zeros or ones */
33889ccd7dcSMatheus Ferst 
33989ccd7dcSMatheus Ferst     if (mask == 0 || mask == -1) {
34089ccd7dcSMatheus Ferst         return src;
34189ccd7dcSMatheus Ferst     }
34289ccd7dcSMatheus Ferst 
34389ccd7dcSMatheus Ferst     /* Processes the mask in blocks, from LSB to MSB */
34489ccd7dcSMatheus Ferst     while (i) {
34589ccd7dcSMatheus Ferst         /* Find how many bits we should take */
34689ccd7dcSMatheus Ferst         n = ctz64(mask);
34789ccd7dcSMatheus Ferst         if (n > i) {
34889ccd7dcSMatheus Ferst             n = i;
34989ccd7dcSMatheus Ferst         }
35089ccd7dcSMatheus Ferst 
35189ccd7dcSMatheus Ferst         /*
35289ccd7dcSMatheus Ferst          * Extracts 'n' trailing bits of src and put them on the leading 'n'
35389ccd7dcSMatheus Ferst          * bits of 'right' or 'left', pushing down the previously extracted
35489ccd7dcSMatheus Ferst          * values.
35589ccd7dcSMatheus Ferst          */
35689ccd7dcSMatheus Ferst         m = (1ll << n) - 1;
35789ccd7dcSMatheus Ferst         if (bit) {
35889ccd7dcSMatheus Ferst             right = ror64(right | (src & m), n);
35989ccd7dcSMatheus Ferst         } else {
36089ccd7dcSMatheus Ferst             left = ror64(left | (src & m), n);
36189ccd7dcSMatheus Ferst         }
36289ccd7dcSMatheus Ferst 
36389ccd7dcSMatheus Ferst         /*
36489ccd7dcSMatheus Ferst          * Discards the processed bits from 'src' and 'mask'. Note that we are
36589ccd7dcSMatheus Ferst          * removing 'n' trailing zeros from 'mask', but the logical shift will
36689ccd7dcSMatheus Ferst          * add 'n' leading zeros back, so the population count of 'mask' is kept
36789ccd7dcSMatheus Ferst          * the same.
36889ccd7dcSMatheus Ferst          */
36989ccd7dcSMatheus Ferst         src >>= n;
37089ccd7dcSMatheus Ferst         mask >>= n;
37189ccd7dcSMatheus Ferst         i -= n;
37289ccd7dcSMatheus Ferst         bit = !bit;
37389ccd7dcSMatheus Ferst         mask = ~mask;
37489ccd7dcSMatheus Ferst     }
37589ccd7dcSMatheus Ferst 
37689ccd7dcSMatheus Ferst     /*
37789ccd7dcSMatheus Ferst      * At the end, right was ror'ed ctpop(mask) times. To put it back in place,
37889ccd7dcSMatheus Ferst      * we'll shift it more 64-ctpop(mask) times.
37989ccd7dcSMatheus Ferst      */
38089ccd7dcSMatheus Ferst     if (bit) {
38189ccd7dcSMatheus Ferst         n = ctpop64(mask);
38289ccd7dcSMatheus Ferst     } else {
38389ccd7dcSMatheus Ferst         n = 64 - ctpop64(mask);
38489ccd7dcSMatheus Ferst     }
38589ccd7dcSMatheus Ferst 
38689ccd7dcSMatheus Ferst     return left | (right >> n);
38789ccd7dcSMatheus Ferst }
38889ccd7dcSMatheus Ferst 
389fcf5ef2aSThomas Huth /*****************************************************************************/
390fcf5ef2aSThomas Huth /* PowerPC 601 specific instructions (POWER bridge) */
391fcf5ef2aSThomas Huth target_ulong helper_div(CPUPPCState *env, target_ulong arg1, target_ulong arg2)
392fcf5ef2aSThomas Huth {
393fcf5ef2aSThomas Huth     uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
394fcf5ef2aSThomas Huth 
395fcf5ef2aSThomas Huth     if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
396fcf5ef2aSThomas Huth         (int32_t)arg2 == 0) {
397fcf5ef2aSThomas Huth         env->spr[SPR_MQ] = 0;
398fcf5ef2aSThomas Huth         return INT32_MIN;
399fcf5ef2aSThomas Huth     } else {
400fcf5ef2aSThomas Huth         env->spr[SPR_MQ] = tmp % arg2;
401fcf5ef2aSThomas Huth         return  tmp / (int32_t)arg2;
402fcf5ef2aSThomas Huth     }
403fcf5ef2aSThomas Huth }
404fcf5ef2aSThomas Huth 
405fcf5ef2aSThomas Huth target_ulong helper_divo(CPUPPCState *env, target_ulong arg1,
406fcf5ef2aSThomas Huth                          target_ulong arg2)
407fcf5ef2aSThomas Huth {
408fcf5ef2aSThomas Huth     uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
409fcf5ef2aSThomas Huth 
410fcf5ef2aSThomas Huth     if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
411fcf5ef2aSThomas Huth         (int32_t)arg2 == 0) {
412fcf5ef2aSThomas Huth         env->so = env->ov = 1;
413fcf5ef2aSThomas Huth         env->spr[SPR_MQ] = 0;
414fcf5ef2aSThomas Huth         return INT32_MIN;
415fcf5ef2aSThomas Huth     } else {
416fcf5ef2aSThomas Huth         env->spr[SPR_MQ] = tmp % arg2;
417fcf5ef2aSThomas Huth         tmp /= (int32_t)arg2;
418fcf5ef2aSThomas Huth         if ((int32_t)tmp != tmp) {
419fcf5ef2aSThomas Huth             env->so = env->ov = 1;
420fcf5ef2aSThomas Huth         } else {
421fcf5ef2aSThomas Huth             env->ov = 0;
422fcf5ef2aSThomas Huth         }
423fcf5ef2aSThomas Huth         return tmp;
424fcf5ef2aSThomas Huth     }
425fcf5ef2aSThomas Huth }
426fcf5ef2aSThomas Huth 
427fcf5ef2aSThomas Huth target_ulong helper_divs(CPUPPCState *env, target_ulong arg1,
428fcf5ef2aSThomas Huth                          target_ulong arg2)
429fcf5ef2aSThomas Huth {
430fcf5ef2aSThomas Huth     if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
431fcf5ef2aSThomas Huth         (int32_t)arg2 == 0) {
432fcf5ef2aSThomas Huth         env->spr[SPR_MQ] = 0;
433fcf5ef2aSThomas Huth         return INT32_MIN;
434fcf5ef2aSThomas Huth     } else {
435fcf5ef2aSThomas Huth         env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
436fcf5ef2aSThomas Huth         return (int32_t)arg1 / (int32_t)arg2;
437fcf5ef2aSThomas Huth     }
438fcf5ef2aSThomas Huth }
439fcf5ef2aSThomas Huth 
440fcf5ef2aSThomas Huth target_ulong helper_divso(CPUPPCState *env, target_ulong arg1,
441fcf5ef2aSThomas Huth                           target_ulong arg2)
442fcf5ef2aSThomas Huth {
443fcf5ef2aSThomas Huth     if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
444fcf5ef2aSThomas Huth         (int32_t)arg2 == 0) {
445fcf5ef2aSThomas Huth         env->so = env->ov = 1;
446fcf5ef2aSThomas Huth         env->spr[SPR_MQ] = 0;
447fcf5ef2aSThomas Huth         return INT32_MIN;
448fcf5ef2aSThomas Huth     } else {
449fcf5ef2aSThomas Huth         env->ov = 0;
450fcf5ef2aSThomas Huth         env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
451fcf5ef2aSThomas Huth         return (int32_t)arg1 / (int32_t)arg2;
452fcf5ef2aSThomas Huth     }
453fcf5ef2aSThomas Huth }
454fcf5ef2aSThomas Huth 
455fcf5ef2aSThomas Huth /*****************************************************************************/
456fcf5ef2aSThomas Huth /* 602 specific instructions */
457fcf5ef2aSThomas Huth /* mfrom is the most crazy instruction ever seen, imho ! */
458fcf5ef2aSThomas Huth /* Real implementation uses a ROM table. Do the same */
459b6cb41b2SDavid Gibson /*
460b6cb41b2SDavid Gibson  * Extremely decomposed:
461fcf5ef2aSThomas Huth  *                      -arg / 256
462fcf5ef2aSThomas Huth  * return 256 * log10(10           + 1.0) + 0.5
463fcf5ef2aSThomas Huth  */
464fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY)
465fcf5ef2aSThomas Huth target_ulong helper_602_mfrom(target_ulong arg)
466fcf5ef2aSThomas Huth {
467fcf5ef2aSThomas Huth     if (likely(arg < 602)) {
468139c1837SPaolo Bonzini #include "mfrom_table.c.inc"
469fcf5ef2aSThomas Huth         return mfrom_ROM_table[arg];
470fcf5ef2aSThomas Huth     } else {
471fcf5ef2aSThomas Huth         return 0;
472fcf5ef2aSThomas Huth     }
473fcf5ef2aSThomas Huth }
474fcf5ef2aSThomas Huth #endif
475fcf5ef2aSThomas Huth 
476fcf5ef2aSThomas Huth /*****************************************************************************/
477fcf5ef2aSThomas Huth /* Altivec extension helpers */
478fcf5ef2aSThomas Huth #if defined(HOST_WORDS_BIGENDIAN)
479fcf5ef2aSThomas Huth #define VECTOR_FOR_INORDER_I(index, element)                    \
480fcf5ef2aSThomas Huth     for (index = 0; index < ARRAY_SIZE(r->element); index++)
481fcf5ef2aSThomas Huth #else
482fcf5ef2aSThomas Huth #define VECTOR_FOR_INORDER_I(index, element)                    \
483fcf5ef2aSThomas Huth     for (index = ARRAY_SIZE(r->element) - 1; index >= 0; index--)
484fcf5ef2aSThomas Huth #endif
485fcf5ef2aSThomas Huth 
486fcf5ef2aSThomas Huth /* Saturating arithmetic helpers.  */
487fcf5ef2aSThomas Huth #define SATCVT(from, to, from_type, to_type, min, max)          \
488fcf5ef2aSThomas Huth     static inline to_type cvt##from##to(from_type x, int *sat)  \
489fcf5ef2aSThomas Huth     {                                                           \
490fcf5ef2aSThomas Huth         to_type r;                                              \
491fcf5ef2aSThomas Huth                                                                 \
492fcf5ef2aSThomas Huth         if (x < (from_type)min) {                               \
493fcf5ef2aSThomas Huth             r = min;                                            \
494fcf5ef2aSThomas Huth             *sat = 1;                                           \
495fcf5ef2aSThomas Huth         } else if (x > (from_type)max) {                        \
496fcf5ef2aSThomas Huth             r = max;                                            \
497fcf5ef2aSThomas Huth             *sat = 1;                                           \
498fcf5ef2aSThomas Huth         } else {                                                \
499fcf5ef2aSThomas Huth             r = x;                                              \
500fcf5ef2aSThomas Huth         }                                                       \
501fcf5ef2aSThomas Huth         return r;                                               \
502fcf5ef2aSThomas Huth     }
503fcf5ef2aSThomas Huth #define SATCVTU(from, to, from_type, to_type, min, max)         \
504fcf5ef2aSThomas Huth     static inline to_type cvt##from##to(from_type x, int *sat)  \
505fcf5ef2aSThomas Huth     {                                                           \
506fcf5ef2aSThomas Huth         to_type r;                                              \
507fcf5ef2aSThomas Huth                                                                 \
508fcf5ef2aSThomas Huth         if (x > (from_type)max) {                               \
509fcf5ef2aSThomas Huth             r = max;                                            \
510fcf5ef2aSThomas Huth             *sat = 1;                                           \
511fcf5ef2aSThomas Huth         } else {                                                \
512fcf5ef2aSThomas Huth             r = x;                                              \
513fcf5ef2aSThomas Huth         }                                                       \
514fcf5ef2aSThomas Huth         return r;                                               \
515fcf5ef2aSThomas Huth     }
516fcf5ef2aSThomas Huth SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
517fcf5ef2aSThomas Huth SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
518fcf5ef2aSThomas Huth SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
519fcf5ef2aSThomas Huth 
520fcf5ef2aSThomas Huth SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
521fcf5ef2aSThomas Huth SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
522fcf5ef2aSThomas Huth SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
523fcf5ef2aSThomas Huth SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
524fcf5ef2aSThomas Huth SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
525fcf5ef2aSThomas Huth SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
526fcf5ef2aSThomas Huth #undef SATCVT
527fcf5ef2aSThomas Huth #undef SATCVTU
528fcf5ef2aSThomas Huth 
529dedfaac7SRichard Henderson void helper_mtvscr(CPUPPCState *env, uint32_t vscr)
530fcf5ef2aSThomas Huth {
531c19940dbSBruno Larsen (billionai)     ppc_store_vscr(env, vscr);
532fcf5ef2aSThomas Huth }
533fcf5ef2aSThomas Huth 
534cc2b90d7SRichard Henderson uint32_t helper_mfvscr(CPUPPCState *env)
535cc2b90d7SRichard Henderson {
536c19940dbSBruno Larsen (billionai)     return ppc_get_vscr(env);
537cc2b90d7SRichard Henderson }
538cc2b90d7SRichard Henderson 
5396175f5a0SRichard Henderson static inline void set_vscr_sat(CPUPPCState *env)
5406175f5a0SRichard Henderson {
5419b5b74daSRichard Henderson     /* The choice of non-zero value is arbitrary.  */
5429b5b74daSRichard Henderson     env->vscr_sat.u32[0] = 1;
5436175f5a0SRichard Henderson }
5446175f5a0SRichard Henderson 
545fcf5ef2aSThomas Huth void helper_vaddcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
546fcf5ef2aSThomas Huth {
547fcf5ef2aSThomas Huth     int i;
548fcf5ef2aSThomas Huth 
549fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
550fcf5ef2aSThomas Huth         r->u32[i] = ~a->u32[i] < b->u32[i];
551fcf5ef2aSThomas Huth     }
552fcf5ef2aSThomas Huth }
553fcf5ef2aSThomas Huth 
554fcf5ef2aSThomas Huth /* vprtybw */
555fcf5ef2aSThomas Huth void helper_vprtybw(ppc_avr_t *r, ppc_avr_t *b)
556fcf5ef2aSThomas Huth {
557fcf5ef2aSThomas Huth     int i;
558fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
559fcf5ef2aSThomas Huth         uint64_t res = b->u32[i] ^ (b->u32[i] >> 16);
560fcf5ef2aSThomas Huth         res ^= res >> 8;
561fcf5ef2aSThomas Huth         r->u32[i] = res & 1;
562fcf5ef2aSThomas Huth     }
563fcf5ef2aSThomas Huth }
564fcf5ef2aSThomas Huth 
565fcf5ef2aSThomas Huth /* vprtybd */
566fcf5ef2aSThomas Huth void helper_vprtybd(ppc_avr_t *r, ppc_avr_t *b)
567fcf5ef2aSThomas Huth {
568fcf5ef2aSThomas Huth     int i;
569fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
570fcf5ef2aSThomas Huth         uint64_t res = b->u64[i] ^ (b->u64[i] >> 32);
571fcf5ef2aSThomas Huth         res ^= res >> 16;
572fcf5ef2aSThomas Huth         res ^= res >> 8;
573fcf5ef2aSThomas Huth         r->u64[i] = res & 1;
574fcf5ef2aSThomas Huth     }
575fcf5ef2aSThomas Huth }
576fcf5ef2aSThomas Huth 
577fcf5ef2aSThomas Huth /* vprtybq */
578fcf5ef2aSThomas Huth void helper_vprtybq(ppc_avr_t *r, ppc_avr_t *b)
579fcf5ef2aSThomas Huth {
580fcf5ef2aSThomas Huth     uint64_t res = b->u64[0] ^ b->u64[1];
581fcf5ef2aSThomas Huth     res ^= res >> 32;
582fcf5ef2aSThomas Huth     res ^= res >> 16;
583fcf5ef2aSThomas Huth     res ^= res >> 8;
5843c385a93SMark Cave-Ayland     r->VsrD(1) = res & 1;
5853c385a93SMark Cave-Ayland     r->VsrD(0) = 0;
586fcf5ef2aSThomas Huth }
587fcf5ef2aSThomas Huth 
588fcf5ef2aSThomas Huth #define VARITHFP(suffix, func)                                          \
589fcf5ef2aSThomas Huth     void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
590fcf5ef2aSThomas Huth                           ppc_avr_t *b)                                 \
591fcf5ef2aSThomas Huth     {                                                                   \
592fcf5ef2aSThomas Huth         int i;                                                          \
593fcf5ef2aSThomas Huth                                                                         \
59405ee3e8aSMark Cave-Ayland         for (i = 0; i < ARRAY_SIZE(r->f32); i++) {                      \
59505ee3e8aSMark Cave-Ayland             r->f32[i] = func(a->f32[i], b->f32[i], &env->vec_status);   \
596fcf5ef2aSThomas Huth         }                                                               \
597fcf5ef2aSThomas Huth     }
598fcf5ef2aSThomas Huth VARITHFP(addfp, float32_add)
599fcf5ef2aSThomas Huth VARITHFP(subfp, float32_sub)
600fcf5ef2aSThomas Huth VARITHFP(minfp, float32_min)
601fcf5ef2aSThomas Huth VARITHFP(maxfp, float32_max)
602fcf5ef2aSThomas Huth #undef VARITHFP
603fcf5ef2aSThomas Huth 
604fcf5ef2aSThomas Huth #define VARITHFPFMA(suffix, type)                                       \
605fcf5ef2aSThomas Huth     void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
606fcf5ef2aSThomas Huth                            ppc_avr_t *b, ppc_avr_t *c)                  \
607fcf5ef2aSThomas Huth     {                                                                   \
608fcf5ef2aSThomas Huth         int i;                                                          \
60905ee3e8aSMark Cave-Ayland         for (i = 0; i < ARRAY_SIZE(r->f32); i++) {                      \
61005ee3e8aSMark Cave-Ayland             r->f32[i] = float32_muladd(a->f32[i], c->f32[i], b->f32[i], \
611fcf5ef2aSThomas Huth                                        type, &env->vec_status);         \
612fcf5ef2aSThomas Huth         }                                                               \
613fcf5ef2aSThomas Huth     }
614fcf5ef2aSThomas Huth VARITHFPFMA(maddfp, 0);
615fcf5ef2aSThomas Huth VARITHFPFMA(nmsubfp, float_muladd_negate_result | float_muladd_negate_c);
616fcf5ef2aSThomas Huth #undef VARITHFPFMA
617fcf5ef2aSThomas Huth 
618fcf5ef2aSThomas Huth #define VARITHSAT_CASE(type, op, cvt, element)                          \
619fcf5ef2aSThomas Huth     {                                                                   \
620fcf5ef2aSThomas Huth         type result = (type)a->element[i] op (type)b->element[i];       \
621fcf5ef2aSThomas Huth         r->element[i] = cvt(result, &sat);                              \
622fcf5ef2aSThomas Huth     }
623fcf5ef2aSThomas Huth 
624fcf5ef2aSThomas Huth #define VARITHSAT_DO(name, op, optype, cvt, element)                    \
625fb11ae7dSRichard Henderson     void helper_v##name(ppc_avr_t *r, ppc_avr_t *vscr_sat,              \
626fb11ae7dSRichard Henderson                         ppc_avr_t *a, ppc_avr_t *b, uint32_t desc)      \
627fcf5ef2aSThomas Huth     {                                                                   \
628fcf5ef2aSThomas Huth         int sat = 0;                                                    \
629fcf5ef2aSThomas Huth         int i;                                                          \
630fcf5ef2aSThomas Huth                                                                         \
631fcf5ef2aSThomas Huth         for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
632fcf5ef2aSThomas Huth             VARITHSAT_CASE(optype, op, cvt, element);                   \
633fcf5ef2aSThomas Huth         }                                                               \
634fcf5ef2aSThomas Huth         if (sat) {                                                      \
635fb11ae7dSRichard Henderson             vscr_sat->u32[0] = 1;                                       \
636fcf5ef2aSThomas Huth         }                                                               \
637fcf5ef2aSThomas Huth     }
638fcf5ef2aSThomas Huth #define VARITHSAT_SIGNED(suffix, element, optype, cvt)          \
639fcf5ef2aSThomas Huth     VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element)      \
640fcf5ef2aSThomas Huth     VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
641fcf5ef2aSThomas Huth #define VARITHSAT_UNSIGNED(suffix, element, optype, cvt)        \
642fcf5ef2aSThomas Huth     VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element)      \
643fcf5ef2aSThomas Huth     VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
644fcf5ef2aSThomas Huth VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
645fcf5ef2aSThomas Huth VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
646fcf5ef2aSThomas Huth VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
647fcf5ef2aSThomas Huth VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
648fcf5ef2aSThomas Huth VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
649fcf5ef2aSThomas Huth VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
650fcf5ef2aSThomas Huth #undef VARITHSAT_CASE
651fcf5ef2aSThomas Huth #undef VARITHSAT_DO
652fcf5ef2aSThomas Huth #undef VARITHSAT_SIGNED
653fcf5ef2aSThomas Huth #undef VARITHSAT_UNSIGNED
654fcf5ef2aSThomas Huth 
655fcf5ef2aSThomas Huth #define VAVG_DO(name, element, etype)                                   \
656fcf5ef2aSThomas Huth     void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)       \
657fcf5ef2aSThomas Huth     {                                                                   \
658fcf5ef2aSThomas Huth         int i;                                                          \
659fcf5ef2aSThomas Huth                                                                         \
660fcf5ef2aSThomas Huth         for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
661fcf5ef2aSThomas Huth             etype x = (etype)a->element[i] + (etype)b->element[i] + 1;  \
662fcf5ef2aSThomas Huth             r->element[i] = x >> 1;                                     \
663fcf5ef2aSThomas Huth         }                                                               \
664fcf5ef2aSThomas Huth     }
665fcf5ef2aSThomas Huth 
666fcf5ef2aSThomas Huth #define VAVG(type, signed_element, signed_type, unsigned_element,       \
667fcf5ef2aSThomas Huth              unsigned_type)                                             \
668fcf5ef2aSThomas Huth     VAVG_DO(avgs##type, signed_element, signed_type)                    \
669fcf5ef2aSThomas Huth     VAVG_DO(avgu##type, unsigned_element, unsigned_type)
670fcf5ef2aSThomas Huth VAVG(b, s8, int16_t, u8, uint16_t)
671fcf5ef2aSThomas Huth VAVG(h, s16, int32_t, u16, uint32_t)
672fcf5ef2aSThomas Huth VAVG(w, s32, int64_t, u32, uint64_t)
673fcf5ef2aSThomas Huth #undef VAVG_DO
674fcf5ef2aSThomas Huth #undef VAVG
675fcf5ef2aSThomas Huth 
676fcf5ef2aSThomas Huth #define VABSDU_DO(name, element)                                        \
677fcf5ef2aSThomas Huth void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)           \
678fcf5ef2aSThomas Huth {                                                                       \
679fcf5ef2aSThomas Huth     int i;                                                              \
680fcf5ef2aSThomas Huth                                                                         \
681fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->element); i++) {                      \
682fcf5ef2aSThomas Huth         r->element[i] = (a->element[i] > b->element[i]) ?               \
683fcf5ef2aSThomas Huth             (a->element[i] - b->element[i]) :                           \
684fcf5ef2aSThomas Huth             (b->element[i] - a->element[i]);                            \
685fcf5ef2aSThomas Huth     }                                                                   \
686fcf5ef2aSThomas Huth }
687fcf5ef2aSThomas Huth 
688b6cb41b2SDavid Gibson /*
689b6cb41b2SDavid Gibson  * VABSDU - Vector absolute difference unsigned
690fcf5ef2aSThomas Huth  *   name    - instruction mnemonic suffix (b: byte, h: halfword, w: word)
691fcf5ef2aSThomas Huth  *   element - element type to access from vector
692fcf5ef2aSThomas Huth  */
693fcf5ef2aSThomas Huth #define VABSDU(type, element)                   \
694fcf5ef2aSThomas Huth     VABSDU_DO(absdu##type, element)
695fcf5ef2aSThomas Huth VABSDU(b, u8)
696fcf5ef2aSThomas Huth VABSDU(h, u16)
697fcf5ef2aSThomas Huth VABSDU(w, u32)
698fcf5ef2aSThomas Huth #undef VABSDU_DO
699fcf5ef2aSThomas Huth #undef VABSDU
700fcf5ef2aSThomas Huth 
701fcf5ef2aSThomas Huth #define VCF(suffix, cvt, element)                                       \
702fcf5ef2aSThomas Huth     void helper_vcf##suffix(CPUPPCState *env, ppc_avr_t *r,             \
703fcf5ef2aSThomas Huth                             ppc_avr_t *b, uint32_t uim)                 \
704fcf5ef2aSThomas Huth     {                                                                   \
705fcf5ef2aSThomas Huth         int i;                                                          \
706fcf5ef2aSThomas Huth                                                                         \
70705ee3e8aSMark Cave-Ayland         for (i = 0; i < ARRAY_SIZE(r->f32); i++) {                      \
708fcf5ef2aSThomas Huth             float32 t = cvt(b->element[i], &env->vec_status);           \
70905ee3e8aSMark Cave-Ayland             r->f32[i] = float32_scalbn(t, -uim, &env->vec_status);      \
710fcf5ef2aSThomas Huth         }                                                               \
711fcf5ef2aSThomas Huth     }
712fcf5ef2aSThomas Huth VCF(ux, uint32_to_float32, u32)
713fcf5ef2aSThomas Huth VCF(sx, int32_to_float32, s32)
714fcf5ef2aSThomas Huth #undef VCF
715fcf5ef2aSThomas Huth 
716fcf5ef2aSThomas Huth #define VCMP_DO(suffix, compare, element, record)                       \
717fcf5ef2aSThomas Huth     void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r,            \
718fcf5ef2aSThomas Huth                              ppc_avr_t *a, ppc_avr_t *b)                \
719fcf5ef2aSThomas Huth     {                                                                   \
720fcf5ef2aSThomas Huth         uint64_t ones = (uint64_t)-1;                                   \
721fcf5ef2aSThomas Huth         uint64_t all = ones;                                            \
722fcf5ef2aSThomas Huth         uint64_t none = 0;                                              \
723fcf5ef2aSThomas Huth         int i;                                                          \
724fcf5ef2aSThomas Huth                                                                         \
725fcf5ef2aSThomas Huth         for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
726fcf5ef2aSThomas Huth             uint64_t result = (a->element[i] compare b->element[i] ?    \
727fcf5ef2aSThomas Huth                                ones : 0x0);                             \
728fcf5ef2aSThomas Huth             switch (sizeof(a->element[0])) {                            \
729fcf5ef2aSThomas Huth             case 8:                                                     \
730fcf5ef2aSThomas Huth                 r->u64[i] = result;                                     \
731fcf5ef2aSThomas Huth                 break;                                                  \
732fcf5ef2aSThomas Huth             case 4:                                                     \
733fcf5ef2aSThomas Huth                 r->u32[i] = result;                                     \
734fcf5ef2aSThomas Huth                 break;                                                  \
735fcf5ef2aSThomas Huth             case 2:                                                     \
736fcf5ef2aSThomas Huth                 r->u16[i] = result;                                     \
737fcf5ef2aSThomas Huth                 break;                                                  \
738fcf5ef2aSThomas Huth             case 1:                                                     \
739fcf5ef2aSThomas Huth                 r->u8[i] = result;                                      \
740fcf5ef2aSThomas Huth                 break;                                                  \
741fcf5ef2aSThomas Huth             }                                                           \
742fcf5ef2aSThomas Huth             all &= result;                                              \
743fcf5ef2aSThomas Huth             none |= result;                                             \
744fcf5ef2aSThomas Huth         }                                                               \
745fcf5ef2aSThomas Huth         if (record) {                                                   \
746fcf5ef2aSThomas Huth             env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1);       \
747fcf5ef2aSThomas Huth         }                                                               \
748fcf5ef2aSThomas Huth     }
749fcf5ef2aSThomas Huth #define VCMP(suffix, compare, element)          \
750fcf5ef2aSThomas Huth     VCMP_DO(suffix, compare, element, 0)        \
751fcf5ef2aSThomas Huth     VCMP_DO(suffix##_dot, compare, element, 1)
752fcf5ef2aSThomas Huth VCMP(equb, ==, u8)
753fcf5ef2aSThomas Huth VCMP(equh, ==, u16)
754fcf5ef2aSThomas Huth VCMP(equw, ==, u32)
755fcf5ef2aSThomas Huth VCMP(equd, ==, u64)
756fcf5ef2aSThomas Huth VCMP(gtub, >, u8)
757fcf5ef2aSThomas Huth VCMP(gtuh, >, u16)
758fcf5ef2aSThomas Huth VCMP(gtuw, >, u32)
759fcf5ef2aSThomas Huth VCMP(gtud, >, u64)
760fcf5ef2aSThomas Huth VCMP(gtsb, >, s8)
761fcf5ef2aSThomas Huth VCMP(gtsh, >, s16)
762fcf5ef2aSThomas Huth VCMP(gtsw, >, s32)
763fcf5ef2aSThomas Huth VCMP(gtsd, >, s64)
764fcf5ef2aSThomas Huth #undef VCMP_DO
765fcf5ef2aSThomas Huth #undef VCMP
766fcf5ef2aSThomas Huth 
767fcf5ef2aSThomas Huth #define VCMPNE_DO(suffix, element, etype, cmpzero, record)              \
768fcf5ef2aSThomas Huth void helper_vcmpne##suffix(CPUPPCState *env, ppc_avr_t *r,              \
769fcf5ef2aSThomas Huth                             ppc_avr_t *a, ppc_avr_t *b)                 \
770fcf5ef2aSThomas Huth {                                                                       \
771fcf5ef2aSThomas Huth     etype ones = (etype)-1;                                             \
772fcf5ef2aSThomas Huth     etype all = ones;                                                   \
773fcf5ef2aSThomas Huth     etype result, none = 0;                                             \
774fcf5ef2aSThomas Huth     int i;                                                              \
775fcf5ef2aSThomas Huth                                                                         \
776fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->element); i++) {                      \
777fcf5ef2aSThomas Huth         if (cmpzero) {                                                  \
778fcf5ef2aSThomas Huth             result = ((a->element[i] == 0)                              \
779fcf5ef2aSThomas Huth                            || (b->element[i] == 0)                      \
780fcf5ef2aSThomas Huth                            || (a->element[i] != b->element[i]) ?        \
781fcf5ef2aSThomas Huth                            ones : 0x0);                                 \
782fcf5ef2aSThomas Huth         } else {                                                        \
783fcf5ef2aSThomas Huth             result = (a->element[i] != b->element[i]) ? ones : 0x0;     \
784fcf5ef2aSThomas Huth         }                                                               \
785fcf5ef2aSThomas Huth         r->element[i] = result;                                         \
786fcf5ef2aSThomas Huth         all &= result;                                                  \
787fcf5ef2aSThomas Huth         none |= result;                                                 \
788fcf5ef2aSThomas Huth     }                                                                   \
789fcf5ef2aSThomas Huth     if (record) {                                                       \
790fcf5ef2aSThomas Huth         env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1);           \
791fcf5ef2aSThomas Huth     }                                                                   \
792fcf5ef2aSThomas Huth }
793fcf5ef2aSThomas Huth 
794b6cb41b2SDavid Gibson /*
795b6cb41b2SDavid Gibson  * VCMPNEZ - Vector compare not equal to zero
796fcf5ef2aSThomas Huth  *   suffix  - instruction mnemonic suffix (b: byte, h: halfword, w: word)
797fcf5ef2aSThomas Huth  *   element - element type to access from vector
798fcf5ef2aSThomas Huth  */
799fcf5ef2aSThomas Huth #define VCMPNE(suffix, element, etype, cmpzero)         \
800fcf5ef2aSThomas Huth     VCMPNE_DO(suffix, element, etype, cmpzero, 0)       \
801fcf5ef2aSThomas Huth     VCMPNE_DO(suffix##_dot, element, etype, cmpzero, 1)
802fcf5ef2aSThomas Huth VCMPNE(zb, u8, uint8_t, 1)
803fcf5ef2aSThomas Huth VCMPNE(zh, u16, uint16_t, 1)
804fcf5ef2aSThomas Huth VCMPNE(zw, u32, uint32_t, 1)
805fcf5ef2aSThomas Huth VCMPNE(b, u8, uint8_t, 0)
806fcf5ef2aSThomas Huth VCMPNE(h, u16, uint16_t, 0)
807fcf5ef2aSThomas Huth VCMPNE(w, u32, uint32_t, 0)
808fcf5ef2aSThomas Huth #undef VCMPNE_DO
809fcf5ef2aSThomas Huth #undef VCMPNE
810fcf5ef2aSThomas Huth 
811fcf5ef2aSThomas Huth #define VCMPFP_DO(suffix, compare, order, record)                       \
812fcf5ef2aSThomas Huth     void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r,            \
813fcf5ef2aSThomas Huth                              ppc_avr_t *a, ppc_avr_t *b)                \
814fcf5ef2aSThomas Huth     {                                                                   \
815fcf5ef2aSThomas Huth         uint32_t ones = (uint32_t)-1;                                   \
816fcf5ef2aSThomas Huth         uint32_t all = ones;                                            \
817fcf5ef2aSThomas Huth         uint32_t none = 0;                                              \
818fcf5ef2aSThomas Huth         int i;                                                          \
819fcf5ef2aSThomas Huth                                                                         \
82005ee3e8aSMark Cave-Ayland         for (i = 0; i < ARRAY_SIZE(r->f32); i++) {                      \
821fcf5ef2aSThomas Huth             uint32_t result;                                            \
82271bfd65cSRichard Henderson             FloatRelation rel =                                         \
82371bfd65cSRichard Henderson                 float32_compare_quiet(a->f32[i], b->f32[i],             \
824fcf5ef2aSThomas Huth                                       &env->vec_status);                \
825fcf5ef2aSThomas Huth             if (rel == float_relation_unordered) {                      \
826fcf5ef2aSThomas Huth                 result = 0;                                             \
827fcf5ef2aSThomas Huth             } else if (rel compare order) {                             \
828fcf5ef2aSThomas Huth                 result = ones;                                          \
829fcf5ef2aSThomas Huth             } else {                                                    \
830fcf5ef2aSThomas Huth                 result = 0;                                             \
831fcf5ef2aSThomas Huth             }                                                           \
832fcf5ef2aSThomas Huth             r->u32[i] = result;                                         \
833fcf5ef2aSThomas Huth             all &= result;                                              \
834fcf5ef2aSThomas Huth             none |= result;                                             \
835fcf5ef2aSThomas Huth         }                                                               \
836fcf5ef2aSThomas Huth         if (record) {                                                   \
837fcf5ef2aSThomas Huth             env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1);       \
838fcf5ef2aSThomas Huth         }                                                               \
839fcf5ef2aSThomas Huth     }
840fcf5ef2aSThomas Huth #define VCMPFP(suffix, compare, order)          \
841fcf5ef2aSThomas Huth     VCMPFP_DO(suffix, compare, order, 0)        \
842fcf5ef2aSThomas Huth     VCMPFP_DO(suffix##_dot, compare, order, 1)
843fcf5ef2aSThomas Huth VCMPFP(eqfp, ==, float_relation_equal)
844fcf5ef2aSThomas Huth VCMPFP(gefp, !=, float_relation_less)
845fcf5ef2aSThomas Huth VCMPFP(gtfp, ==, float_relation_greater)
846fcf5ef2aSThomas Huth #undef VCMPFP_DO
847fcf5ef2aSThomas Huth #undef VCMPFP
848fcf5ef2aSThomas Huth 
849fcf5ef2aSThomas Huth static inline void vcmpbfp_internal(CPUPPCState *env, ppc_avr_t *r,
850fcf5ef2aSThomas Huth                                     ppc_avr_t *a, ppc_avr_t *b, int record)
851fcf5ef2aSThomas Huth {
852fcf5ef2aSThomas Huth     int i;
853fcf5ef2aSThomas Huth     int all_in = 0;
854fcf5ef2aSThomas Huth 
85505ee3e8aSMark Cave-Ayland     for (i = 0; i < ARRAY_SIZE(r->f32); i++) {
85671bfd65cSRichard Henderson         FloatRelation le_rel = float32_compare_quiet(a->f32[i], b->f32[i],
85705ee3e8aSMark Cave-Ayland                                                      &env->vec_status);
858fcf5ef2aSThomas Huth         if (le_rel == float_relation_unordered) {
859fcf5ef2aSThomas Huth             r->u32[i] = 0xc0000000;
860fcf5ef2aSThomas Huth             all_in = 1;
861fcf5ef2aSThomas Huth         } else {
86205ee3e8aSMark Cave-Ayland             float32 bneg = float32_chs(b->f32[i]);
86371bfd65cSRichard Henderson             FloatRelation ge_rel = float32_compare_quiet(a->f32[i], bneg,
86405ee3e8aSMark Cave-Ayland                                                          &env->vec_status);
865fcf5ef2aSThomas Huth             int le = le_rel != float_relation_greater;
866fcf5ef2aSThomas Huth             int ge = ge_rel != float_relation_less;
867fcf5ef2aSThomas Huth 
868fcf5ef2aSThomas Huth             r->u32[i] = ((!le) << 31) | ((!ge) << 30);
869fcf5ef2aSThomas Huth             all_in |= (!le | !ge);
870fcf5ef2aSThomas Huth         }
871fcf5ef2aSThomas Huth     }
872fcf5ef2aSThomas Huth     if (record) {
873fcf5ef2aSThomas Huth         env->crf[6] = (all_in == 0) << 1;
874fcf5ef2aSThomas Huth     }
875fcf5ef2aSThomas Huth }
876fcf5ef2aSThomas Huth 
877fcf5ef2aSThomas Huth void helper_vcmpbfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
878fcf5ef2aSThomas Huth {
879fcf5ef2aSThomas Huth     vcmpbfp_internal(env, r, a, b, 0);
880fcf5ef2aSThomas Huth }
881fcf5ef2aSThomas Huth 
882fcf5ef2aSThomas Huth void helper_vcmpbfp_dot(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
883fcf5ef2aSThomas Huth                         ppc_avr_t *b)
884fcf5ef2aSThomas Huth {
885fcf5ef2aSThomas Huth     vcmpbfp_internal(env, r, a, b, 1);
886fcf5ef2aSThomas Huth }
887fcf5ef2aSThomas Huth 
888fcf5ef2aSThomas Huth #define VCT(suffix, satcvt, element)                                    \
889fcf5ef2aSThomas Huth     void helper_vct##suffix(CPUPPCState *env, ppc_avr_t *r,             \
890fcf5ef2aSThomas Huth                             ppc_avr_t *b, uint32_t uim)                 \
891fcf5ef2aSThomas Huth     {                                                                   \
892fcf5ef2aSThomas Huth         int i;                                                          \
893fcf5ef2aSThomas Huth         int sat = 0;                                                    \
894fcf5ef2aSThomas Huth         float_status s = env->vec_status;                               \
895fcf5ef2aSThomas Huth                                                                         \
896fcf5ef2aSThomas Huth         set_float_rounding_mode(float_round_to_zero, &s);               \
89705ee3e8aSMark Cave-Ayland         for (i = 0; i < ARRAY_SIZE(r->f32); i++) {                      \
89805ee3e8aSMark Cave-Ayland             if (float32_is_any_nan(b->f32[i])) {                        \
899fcf5ef2aSThomas Huth                 r->element[i] = 0;                                      \
900fcf5ef2aSThomas Huth             } else {                                                    \
90105ee3e8aSMark Cave-Ayland                 float64 t = float32_to_float64(b->f32[i], &s);          \
902fcf5ef2aSThomas Huth                 int64_t j;                                              \
903fcf5ef2aSThomas Huth                                                                         \
904fcf5ef2aSThomas Huth                 t = float64_scalbn(t, uim, &s);                         \
905fcf5ef2aSThomas Huth                 j = float64_to_int64(t, &s);                            \
906fcf5ef2aSThomas Huth                 r->element[i] = satcvt(j, &sat);                        \
907fcf5ef2aSThomas Huth             }                                                           \
908fcf5ef2aSThomas Huth         }                                                               \
909fcf5ef2aSThomas Huth         if (sat) {                                                      \
9106175f5a0SRichard Henderson             set_vscr_sat(env);                                          \
911fcf5ef2aSThomas Huth         }                                                               \
912fcf5ef2aSThomas Huth     }
913fcf5ef2aSThomas Huth VCT(uxs, cvtsduw, u32)
914fcf5ef2aSThomas Huth VCT(sxs, cvtsdsw, s32)
915fcf5ef2aSThomas Huth #undef VCT
916fcf5ef2aSThomas Huth 
917fcf5ef2aSThomas Huth target_ulong helper_vclzlsbb(ppc_avr_t *r)
918fcf5ef2aSThomas Huth {
919fcf5ef2aSThomas Huth     target_ulong count = 0;
920fcf5ef2aSThomas Huth     int i;
92160594feaSMark Cave-Ayland     for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
92260594feaSMark Cave-Ayland         if (r->VsrB(i) & 0x01) {
923fcf5ef2aSThomas Huth             break;
924fcf5ef2aSThomas Huth         }
925fcf5ef2aSThomas Huth         count++;
926fcf5ef2aSThomas Huth     }
927fcf5ef2aSThomas Huth     return count;
928fcf5ef2aSThomas Huth }
929fcf5ef2aSThomas Huth 
930fcf5ef2aSThomas Huth target_ulong helper_vctzlsbb(ppc_avr_t *r)
931fcf5ef2aSThomas Huth {
932fcf5ef2aSThomas Huth     target_ulong count = 0;
933fcf5ef2aSThomas Huth     int i;
934fcf5ef2aSThomas Huth     for (i = ARRAY_SIZE(r->u8) - 1; i >= 0; i--) {
93560594feaSMark Cave-Ayland         if (r->VsrB(i) & 0x01) {
936fcf5ef2aSThomas Huth             break;
937fcf5ef2aSThomas Huth         }
938fcf5ef2aSThomas Huth         count++;
939fcf5ef2aSThomas Huth     }
940fcf5ef2aSThomas Huth     return count;
941fcf5ef2aSThomas Huth }
942fcf5ef2aSThomas Huth 
943fcf5ef2aSThomas Huth void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
944fcf5ef2aSThomas Huth                       ppc_avr_t *b, ppc_avr_t *c)
945fcf5ef2aSThomas Huth {
946fcf5ef2aSThomas Huth     int sat = 0;
947fcf5ef2aSThomas Huth     int i;
948fcf5ef2aSThomas Huth 
949fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
950fcf5ef2aSThomas Huth         int32_t prod = a->s16[i] * b->s16[i];
951fcf5ef2aSThomas Huth         int32_t t = (int32_t)c->s16[i] + (prod >> 15);
952fcf5ef2aSThomas Huth 
953fcf5ef2aSThomas Huth         r->s16[i] = cvtswsh(t, &sat);
954fcf5ef2aSThomas Huth     }
955fcf5ef2aSThomas Huth 
956fcf5ef2aSThomas Huth     if (sat) {
9576175f5a0SRichard Henderson         set_vscr_sat(env);
958fcf5ef2aSThomas Huth     }
959fcf5ef2aSThomas Huth }
960fcf5ef2aSThomas Huth 
961fcf5ef2aSThomas Huth void helper_vmhraddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
962fcf5ef2aSThomas Huth                        ppc_avr_t *b, ppc_avr_t *c)
963fcf5ef2aSThomas Huth {
964fcf5ef2aSThomas Huth     int sat = 0;
965fcf5ef2aSThomas Huth     int i;
966fcf5ef2aSThomas Huth 
967fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
968fcf5ef2aSThomas Huth         int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
969fcf5ef2aSThomas Huth         int32_t t = (int32_t)c->s16[i] + (prod >> 15);
970fcf5ef2aSThomas Huth         r->s16[i] = cvtswsh(t, &sat);
971fcf5ef2aSThomas Huth     }
972fcf5ef2aSThomas Huth 
973fcf5ef2aSThomas Huth     if (sat) {
9746175f5a0SRichard Henderson         set_vscr_sat(env);
975fcf5ef2aSThomas Huth     }
976fcf5ef2aSThomas Huth }
977fcf5ef2aSThomas Huth 
978fcf5ef2aSThomas Huth void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
979fcf5ef2aSThomas Huth {
980fcf5ef2aSThomas Huth     int i;
981fcf5ef2aSThomas Huth 
982fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
983fcf5ef2aSThomas Huth         int32_t prod = a->s16[i] * b->s16[i];
984fcf5ef2aSThomas Huth         r->s16[i] = (int16_t) (prod + c->s16[i]);
985fcf5ef2aSThomas Huth     }
986fcf5ef2aSThomas Huth }
987fcf5ef2aSThomas Huth 
988d81c2040SMark Cave-Ayland #define VMRG_DO(name, element, access, ofs)                                  \
989fcf5ef2aSThomas Huth     void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)            \
990fcf5ef2aSThomas Huth     {                                                                        \
991fcf5ef2aSThomas Huth         ppc_avr_t result;                                                    \
992d81c2040SMark Cave-Ayland         int i, half = ARRAY_SIZE(r->element) / 2;                            \
993fcf5ef2aSThomas Huth                                                                              \
994d81c2040SMark Cave-Ayland         for (i = 0; i < half; i++) {                                         \
995d81c2040SMark Cave-Ayland             result.access(i * 2 + 0) = a->access(i + ofs);                   \
996d81c2040SMark Cave-Ayland             result.access(i * 2 + 1) = b->access(i + ofs);                   \
997fcf5ef2aSThomas Huth         }                                                                    \
998fcf5ef2aSThomas Huth         *r = result;                                                         \
999fcf5ef2aSThomas Huth     }
1000d81c2040SMark Cave-Ayland 
1001d81c2040SMark Cave-Ayland #define VMRG(suffix, element, access)          \
1002d81c2040SMark Cave-Ayland     VMRG_DO(mrgl##suffix, element, access, half)   \
1003d81c2040SMark Cave-Ayland     VMRG_DO(mrgh##suffix, element, access, 0)
1004d81c2040SMark Cave-Ayland VMRG(b, u8, VsrB)
1005d81c2040SMark Cave-Ayland VMRG(h, u16, VsrH)
1006d81c2040SMark Cave-Ayland VMRG(w, u32, VsrW)
1007fcf5ef2aSThomas Huth #undef VMRG_DO
1008fcf5ef2aSThomas Huth #undef VMRG
1009fcf5ef2aSThomas Huth 
1010fcf5ef2aSThomas Huth void helper_vmsummbm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
1011fcf5ef2aSThomas Huth                      ppc_avr_t *b, ppc_avr_t *c)
1012fcf5ef2aSThomas Huth {
1013fcf5ef2aSThomas Huth     int32_t prod[16];
1014fcf5ef2aSThomas Huth     int i;
1015fcf5ef2aSThomas Huth 
1016fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
1017fcf5ef2aSThomas Huth         prod[i] = (int32_t)a->s8[i] * b->u8[i];
1018fcf5ef2aSThomas Huth     }
1019fcf5ef2aSThomas Huth 
1020fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, s32) {
1021fcf5ef2aSThomas Huth         r->s32[i] = c->s32[i] + prod[4 * i] + prod[4 * i + 1] +
1022fcf5ef2aSThomas Huth             prod[4 * i + 2] + prod[4 * i + 3];
1023fcf5ef2aSThomas Huth     }
1024fcf5ef2aSThomas Huth }
1025fcf5ef2aSThomas Huth 
1026fcf5ef2aSThomas Huth void helper_vmsumshm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
1027fcf5ef2aSThomas Huth                      ppc_avr_t *b, ppc_avr_t *c)
1028fcf5ef2aSThomas Huth {
1029fcf5ef2aSThomas Huth     int32_t prod[8];
1030fcf5ef2aSThomas Huth     int i;
1031fcf5ef2aSThomas Huth 
1032fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
1033fcf5ef2aSThomas Huth         prod[i] = a->s16[i] * b->s16[i];
1034fcf5ef2aSThomas Huth     }
1035fcf5ef2aSThomas Huth 
1036fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, s32) {
1037fcf5ef2aSThomas Huth         r->s32[i] = c->s32[i] + prod[2 * i] + prod[2 * i + 1];
1038fcf5ef2aSThomas Huth     }
1039fcf5ef2aSThomas Huth }
1040fcf5ef2aSThomas Huth 
1041fcf5ef2aSThomas Huth void helper_vmsumshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
1042fcf5ef2aSThomas Huth                      ppc_avr_t *b, ppc_avr_t *c)
1043fcf5ef2aSThomas Huth {
1044fcf5ef2aSThomas Huth     int32_t prod[8];
1045fcf5ef2aSThomas Huth     int i;
1046fcf5ef2aSThomas Huth     int sat = 0;
1047fcf5ef2aSThomas Huth 
1048fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
1049fcf5ef2aSThomas Huth         prod[i] = (int32_t)a->s16[i] * b->s16[i];
1050fcf5ef2aSThomas Huth     }
1051fcf5ef2aSThomas Huth 
1052fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, s32) {
1053fcf5ef2aSThomas Huth         int64_t t = (int64_t)c->s32[i] + prod[2 * i] + prod[2 * i + 1];
1054fcf5ef2aSThomas Huth 
1055fcf5ef2aSThomas Huth         r->u32[i] = cvtsdsw(t, &sat);
1056fcf5ef2aSThomas Huth     }
1057fcf5ef2aSThomas Huth 
1058fcf5ef2aSThomas Huth     if (sat) {
10596175f5a0SRichard Henderson         set_vscr_sat(env);
1060fcf5ef2aSThomas Huth     }
1061fcf5ef2aSThomas Huth }
1062fcf5ef2aSThomas Huth 
1063fcf5ef2aSThomas Huth void helper_vmsumubm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
1064fcf5ef2aSThomas Huth                      ppc_avr_t *b, ppc_avr_t *c)
1065fcf5ef2aSThomas Huth {
1066fcf5ef2aSThomas Huth     uint16_t prod[16];
1067fcf5ef2aSThomas Huth     int i;
1068fcf5ef2aSThomas Huth 
1069fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
1070fcf5ef2aSThomas Huth         prod[i] = a->u8[i] * b->u8[i];
1071fcf5ef2aSThomas Huth     }
1072fcf5ef2aSThomas Huth 
1073fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, u32) {
1074fcf5ef2aSThomas Huth         r->u32[i] = c->u32[i] + prod[4 * i] + prod[4 * i + 1] +
1075fcf5ef2aSThomas Huth             prod[4 * i + 2] + prod[4 * i + 3];
1076fcf5ef2aSThomas Huth     }
1077fcf5ef2aSThomas Huth }
1078fcf5ef2aSThomas Huth 
1079fcf5ef2aSThomas Huth void helper_vmsumuhm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
1080fcf5ef2aSThomas Huth                      ppc_avr_t *b, ppc_avr_t *c)
1081fcf5ef2aSThomas Huth {
1082fcf5ef2aSThomas Huth     uint32_t prod[8];
1083fcf5ef2aSThomas Huth     int i;
1084fcf5ef2aSThomas Huth 
1085fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
1086fcf5ef2aSThomas Huth         prod[i] = a->u16[i] * b->u16[i];
1087fcf5ef2aSThomas Huth     }
1088fcf5ef2aSThomas Huth 
1089fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, u32) {
1090fcf5ef2aSThomas Huth         r->u32[i] = c->u32[i] + prod[2 * i] + prod[2 * i + 1];
1091fcf5ef2aSThomas Huth     }
1092fcf5ef2aSThomas Huth }
1093fcf5ef2aSThomas Huth 
1094fcf5ef2aSThomas Huth void helper_vmsumuhs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
1095fcf5ef2aSThomas Huth                      ppc_avr_t *b, ppc_avr_t *c)
1096fcf5ef2aSThomas Huth {
1097fcf5ef2aSThomas Huth     uint32_t prod[8];
1098fcf5ef2aSThomas Huth     int i;
1099fcf5ef2aSThomas Huth     int sat = 0;
1100fcf5ef2aSThomas Huth 
1101fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
1102fcf5ef2aSThomas Huth         prod[i] = a->u16[i] * b->u16[i];
1103fcf5ef2aSThomas Huth     }
1104fcf5ef2aSThomas Huth 
1105fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, s32) {
1106fcf5ef2aSThomas Huth         uint64_t t = (uint64_t)c->u32[i] + prod[2 * i] + prod[2 * i + 1];
1107fcf5ef2aSThomas Huth 
1108fcf5ef2aSThomas Huth         r->u32[i] = cvtuduw(t, &sat);
1109fcf5ef2aSThomas Huth     }
1110fcf5ef2aSThomas Huth 
1111fcf5ef2aSThomas Huth     if (sat) {
11126175f5a0SRichard Henderson         set_vscr_sat(env);
1113fcf5ef2aSThomas Huth     }
1114fcf5ef2aSThomas Huth }
1115fcf5ef2aSThomas Huth 
11164fbc89edSMark Cave-Ayland #define VMUL_DO_EVN(name, mul_element, mul_access, prod_access, cast)   \
1117fcf5ef2aSThomas Huth     void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)       \
1118fcf5ef2aSThomas Huth     {                                                                   \
1119fcf5ef2aSThomas Huth         int i;                                                          \
1120fcf5ef2aSThomas Huth                                                                         \
11214fbc89edSMark Cave-Ayland         for (i = 0; i < ARRAY_SIZE(r->mul_element); i += 2) {           \
11224fbc89edSMark Cave-Ayland             r->prod_access(i >> 1) = (cast)a->mul_access(i) *           \
11234fbc89edSMark Cave-Ayland                                      (cast)b->mul_access(i);            \
1124fcf5ef2aSThomas Huth         }                                                               \
1125fcf5ef2aSThomas Huth     }
11264fbc89edSMark Cave-Ayland 
11274fbc89edSMark Cave-Ayland #define VMUL_DO_ODD(name, mul_element, mul_access, prod_access, cast)   \
11284fbc89edSMark Cave-Ayland     void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)       \
11294fbc89edSMark Cave-Ayland     {                                                                   \
11304fbc89edSMark Cave-Ayland         int i;                                                          \
11314fbc89edSMark Cave-Ayland                                                                         \
11324fbc89edSMark Cave-Ayland         for (i = 0; i < ARRAY_SIZE(r->mul_element); i += 2) {           \
11334fbc89edSMark Cave-Ayland             r->prod_access(i >> 1) = (cast)a->mul_access(i + 1) *       \
11344fbc89edSMark Cave-Ayland                                      (cast)b->mul_access(i + 1);        \
11354fbc89edSMark Cave-Ayland         }                                                               \
11364fbc89edSMark Cave-Ayland     }
11374fbc89edSMark Cave-Ayland 
11384fbc89edSMark Cave-Ayland #define VMUL(suffix, mul_element, mul_access, prod_access, cast)       \
11394fbc89edSMark Cave-Ayland     VMUL_DO_EVN(mule##suffix, mul_element, mul_access, prod_access, cast)  \
11404fbc89edSMark Cave-Ayland     VMUL_DO_ODD(mulo##suffix, mul_element, mul_access, prod_access, cast)
11414fbc89edSMark Cave-Ayland VMUL(sb, s8, VsrSB, VsrSH, int16_t)
11424fbc89edSMark Cave-Ayland VMUL(sh, s16, VsrSH, VsrSW, int32_t)
11434fbc89edSMark Cave-Ayland VMUL(sw, s32, VsrSW, VsrSD, int64_t)
11444fbc89edSMark Cave-Ayland VMUL(ub, u8, VsrB, VsrH, uint16_t)
11454fbc89edSMark Cave-Ayland VMUL(uh, u16, VsrH, VsrW, uint32_t)
11464fbc89edSMark Cave-Ayland VMUL(uw, u32, VsrW, VsrD, uint64_t)
11474fbc89edSMark Cave-Ayland #undef VMUL_DO_EVN
11484fbc89edSMark Cave-Ayland #undef VMUL_DO_ODD
1149fcf5ef2aSThomas Huth #undef VMUL
1150fcf5ef2aSThomas Huth 
1151f3e0d864SLijun Pan void helper_vmulhsw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1152f3e0d864SLijun Pan {
1153f3e0d864SLijun Pan     int i;
1154f3e0d864SLijun Pan 
1155f3e0d864SLijun Pan     for (i = 0; i < 4; i++) {
1156f3e0d864SLijun Pan         r->s32[i] = (int32_t)(((int64_t)a->s32[i] * (int64_t)b->s32[i]) >> 32);
1157f3e0d864SLijun Pan     }
1158f3e0d864SLijun Pan }
1159f3e0d864SLijun Pan 
1160f3e0d864SLijun Pan void helper_vmulhuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1161f3e0d864SLijun Pan {
1162f3e0d864SLijun Pan     int i;
1163f3e0d864SLijun Pan 
1164f3e0d864SLijun Pan     for (i = 0; i < 4; i++) {
1165f3e0d864SLijun Pan         r->u32[i] = (uint32_t)(((uint64_t)a->u32[i] *
1166f3e0d864SLijun Pan                                (uint64_t)b->u32[i]) >> 32);
1167f3e0d864SLijun Pan     }
1168f3e0d864SLijun Pan }
1169f3e0d864SLijun Pan 
1170c4b8b49dSLijun Pan void helper_vmulhsd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1171c4b8b49dSLijun Pan {
1172c4b8b49dSLijun Pan     uint64_t discard;
1173c4b8b49dSLijun Pan 
1174c4b8b49dSLijun Pan     muls64(&discard, &r->u64[0], a->s64[0], b->s64[0]);
1175c4b8b49dSLijun Pan     muls64(&discard, &r->u64[1], a->s64[1], b->s64[1]);
1176c4b8b49dSLijun Pan }
1177c4b8b49dSLijun Pan 
1178c4b8b49dSLijun Pan void helper_vmulhud(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1179c4b8b49dSLijun Pan {
1180c4b8b49dSLijun Pan     uint64_t discard;
1181c4b8b49dSLijun Pan 
1182c4b8b49dSLijun Pan     mulu64(&discard, &r->u64[0], a->u64[0], b->u64[0]);
1183c4b8b49dSLijun Pan     mulu64(&discard, &r->u64[1], a->u64[1], b->u64[1]);
1184c4b8b49dSLijun Pan }
1185c4b8b49dSLijun Pan 
1186fcf5ef2aSThomas Huth void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
1187fcf5ef2aSThomas Huth                   ppc_avr_t *c)
1188fcf5ef2aSThomas Huth {
1189fcf5ef2aSThomas Huth     ppc_avr_t result;
1190fcf5ef2aSThomas Huth     int i;
1191fcf5ef2aSThomas Huth 
119260594feaSMark Cave-Ayland     for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
119360594feaSMark Cave-Ayland         int s = c->VsrB(i) & 0x1f;
1194fcf5ef2aSThomas Huth         int index = s & 0xf;
1195fcf5ef2aSThomas Huth 
1196fcf5ef2aSThomas Huth         if (s & 0x10) {
119760594feaSMark Cave-Ayland             result.VsrB(i) = b->VsrB(index);
1198fcf5ef2aSThomas Huth         } else {
119960594feaSMark Cave-Ayland             result.VsrB(i) = a->VsrB(index);
1200fcf5ef2aSThomas Huth         }
1201fcf5ef2aSThomas Huth     }
1202fcf5ef2aSThomas Huth     *r = result;
1203fcf5ef2aSThomas Huth }
1204fcf5ef2aSThomas Huth 
1205fcf5ef2aSThomas Huth void helper_vpermr(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
1206fcf5ef2aSThomas Huth                   ppc_avr_t *c)
1207fcf5ef2aSThomas Huth {
1208fcf5ef2aSThomas Huth     ppc_avr_t result;
1209fcf5ef2aSThomas Huth     int i;
1210fcf5ef2aSThomas Huth 
121160594feaSMark Cave-Ayland     for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
121260594feaSMark Cave-Ayland         int s = c->VsrB(i) & 0x1f;
1213fcf5ef2aSThomas Huth         int index = 15 - (s & 0xf);
1214fcf5ef2aSThomas Huth 
1215fcf5ef2aSThomas Huth         if (s & 0x10) {
121660594feaSMark Cave-Ayland             result.VsrB(i) = a->VsrB(index);
1217fcf5ef2aSThomas Huth         } else {
121860594feaSMark Cave-Ayland             result.VsrB(i) = b->VsrB(index);
1219fcf5ef2aSThomas Huth         }
1220fcf5ef2aSThomas Huth     }
1221fcf5ef2aSThomas Huth     *r = result;
1222fcf5ef2aSThomas Huth }
1223fcf5ef2aSThomas Huth 
1224fcf5ef2aSThomas Huth #if defined(HOST_WORDS_BIGENDIAN)
1225fcf5ef2aSThomas Huth #define VBPERMQ_INDEX(avr, i) ((avr)->u8[(i)])
1226fcf5ef2aSThomas Huth #define VBPERMD_INDEX(i) (i)
1227fcf5ef2aSThomas Huth #define VBPERMQ_DW(index) (((index) & 0x40) != 0)
1228fcf5ef2aSThomas Huth #define EXTRACT_BIT(avr, i, index) (extract64((avr)->u64[i], index, 1))
1229fcf5ef2aSThomas Huth #else
1230fcf5ef2aSThomas Huth #define VBPERMQ_INDEX(avr, i) ((avr)->u8[15 - (i)])
1231fcf5ef2aSThomas Huth #define VBPERMD_INDEX(i) (1 - i)
1232fcf5ef2aSThomas Huth #define VBPERMQ_DW(index) (((index) & 0x40) == 0)
1233fcf5ef2aSThomas Huth #define EXTRACT_BIT(avr, i, index) \
1234fcf5ef2aSThomas Huth         (extract64((avr)->u64[1 - i], 63 - index, 1))
1235fcf5ef2aSThomas Huth #endif
1236fcf5ef2aSThomas Huth 
1237fcf5ef2aSThomas Huth void helper_vbpermd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1238fcf5ef2aSThomas Huth {
1239fcf5ef2aSThomas Huth     int i, j;
1240fcf5ef2aSThomas Huth     ppc_avr_t result = { .u64 = { 0, 0 } };
1241fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, u64) {
1242fcf5ef2aSThomas Huth         for (j = 0; j < 8; j++) {
1243fcf5ef2aSThomas Huth             int index = VBPERMQ_INDEX(b, (i * 8) + j);
1244fcf5ef2aSThomas Huth             if (index < 64 && EXTRACT_BIT(a, i, index)) {
1245fcf5ef2aSThomas Huth                 result.u64[VBPERMD_INDEX(i)] |= (0x80 >> j);
1246fcf5ef2aSThomas Huth             }
1247fcf5ef2aSThomas Huth         }
1248fcf5ef2aSThomas Huth     }
1249fcf5ef2aSThomas Huth     *r = result;
1250fcf5ef2aSThomas Huth }
1251fcf5ef2aSThomas Huth 
1252fcf5ef2aSThomas Huth void helper_vbpermq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1253fcf5ef2aSThomas Huth {
1254fcf5ef2aSThomas Huth     int i;
1255fcf5ef2aSThomas Huth     uint64_t perm = 0;
1256fcf5ef2aSThomas Huth 
1257fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, u8) {
1258fcf5ef2aSThomas Huth         int index = VBPERMQ_INDEX(b, i);
1259fcf5ef2aSThomas Huth 
1260fcf5ef2aSThomas Huth         if (index < 128) {
1261fcf5ef2aSThomas Huth             uint64_t mask = (1ull << (63 - (index & 0x3F)));
1262fcf5ef2aSThomas Huth             if (a->u64[VBPERMQ_DW(index)] & mask) {
1263fcf5ef2aSThomas Huth                 perm |= (0x8000 >> i);
1264fcf5ef2aSThomas Huth             }
1265fcf5ef2aSThomas Huth         }
1266fcf5ef2aSThomas Huth     }
1267fcf5ef2aSThomas Huth 
12683c385a93SMark Cave-Ayland     r->VsrD(0) = perm;
12693c385a93SMark Cave-Ayland     r->VsrD(1) = 0;
1270fcf5ef2aSThomas Huth }
1271fcf5ef2aSThomas Huth 
1272fcf5ef2aSThomas Huth #undef VBPERMQ_INDEX
1273fcf5ef2aSThomas Huth #undef VBPERMQ_DW
1274fcf5ef2aSThomas Huth 
1275fcf5ef2aSThomas Huth #define PMSUM(name, srcfld, trgfld, trgtyp)                   \
1276fcf5ef2aSThomas Huth void helper_##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
1277fcf5ef2aSThomas Huth {                                                             \
1278fcf5ef2aSThomas Huth     int i, j;                                                 \
1279fcf5ef2aSThomas Huth     trgtyp prod[sizeof(ppc_avr_t) / sizeof(a->srcfld[0])];    \
1280fcf5ef2aSThomas Huth                                                               \
1281fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, srcfld) {                         \
1282fcf5ef2aSThomas Huth         prod[i] = 0;                                          \
1283fcf5ef2aSThomas Huth         for (j = 0; j < sizeof(a->srcfld[0]) * 8; j++) {      \
1284fcf5ef2aSThomas Huth             if (a->srcfld[i] & (1ull << j)) {                 \
1285fcf5ef2aSThomas Huth                 prod[i] ^= ((trgtyp)b->srcfld[i] << j);       \
1286fcf5ef2aSThomas Huth             }                                                 \
1287fcf5ef2aSThomas Huth         }                                                     \
1288fcf5ef2aSThomas Huth     }                                                         \
1289fcf5ef2aSThomas Huth                                                               \
1290fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, trgfld) {                         \
1291fcf5ef2aSThomas Huth         r->trgfld[i] = prod[2 * i] ^ prod[2 * i + 1];         \
1292fcf5ef2aSThomas Huth     }                                                         \
1293fcf5ef2aSThomas Huth }
1294fcf5ef2aSThomas Huth 
1295fcf5ef2aSThomas Huth PMSUM(vpmsumb, u8, u16, uint16_t)
1296fcf5ef2aSThomas Huth PMSUM(vpmsumh, u16, u32, uint32_t)
1297fcf5ef2aSThomas Huth PMSUM(vpmsumw, u32, u64, uint64_t)
1298fcf5ef2aSThomas Huth 
1299fcf5ef2aSThomas Huth void helper_vpmsumd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1300fcf5ef2aSThomas Huth {
1301fcf5ef2aSThomas Huth 
1302fcf5ef2aSThomas Huth #ifdef CONFIG_INT128
1303fcf5ef2aSThomas Huth     int i, j;
1304fcf5ef2aSThomas Huth     __uint128_t prod[2];
1305fcf5ef2aSThomas Huth 
1306fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, u64) {
1307fcf5ef2aSThomas Huth         prod[i] = 0;
1308fcf5ef2aSThomas Huth         for (j = 0; j < 64; j++) {
1309fcf5ef2aSThomas Huth             if (a->u64[i] & (1ull << j)) {
1310fcf5ef2aSThomas Huth                 prod[i] ^= (((__uint128_t)b->u64[i]) << j);
1311fcf5ef2aSThomas Huth             }
1312fcf5ef2aSThomas Huth         }
1313fcf5ef2aSThomas Huth     }
1314fcf5ef2aSThomas Huth 
1315fcf5ef2aSThomas Huth     r->u128 = prod[0] ^ prod[1];
1316fcf5ef2aSThomas Huth 
1317fcf5ef2aSThomas Huth #else
1318fcf5ef2aSThomas Huth     int i, j;
1319fcf5ef2aSThomas Huth     ppc_avr_t prod[2];
1320fcf5ef2aSThomas Huth 
1321fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, u64) {
13223c385a93SMark Cave-Ayland         prod[i].VsrD(1) = prod[i].VsrD(0) = 0;
1323fcf5ef2aSThomas Huth         for (j = 0; j < 64; j++) {
1324fcf5ef2aSThomas Huth             if (a->u64[i] & (1ull << j)) {
1325fcf5ef2aSThomas Huth                 ppc_avr_t bshift;
1326fcf5ef2aSThomas Huth                 if (j == 0) {
13273c385a93SMark Cave-Ayland                     bshift.VsrD(0) = 0;
13283c385a93SMark Cave-Ayland                     bshift.VsrD(1) = b->u64[i];
1329fcf5ef2aSThomas Huth                 } else {
13303c385a93SMark Cave-Ayland                     bshift.VsrD(0) = b->u64[i] >> (64 - j);
13313c385a93SMark Cave-Ayland                     bshift.VsrD(1) = b->u64[i] << j;
1332fcf5ef2aSThomas Huth                 }
13333c385a93SMark Cave-Ayland                 prod[i].VsrD(1) ^= bshift.VsrD(1);
13343c385a93SMark Cave-Ayland                 prod[i].VsrD(0) ^= bshift.VsrD(0);
1335fcf5ef2aSThomas Huth             }
1336fcf5ef2aSThomas Huth         }
1337fcf5ef2aSThomas Huth     }
1338fcf5ef2aSThomas Huth 
13393c385a93SMark Cave-Ayland     r->VsrD(1) = prod[0].VsrD(1) ^ prod[1].VsrD(1);
13403c385a93SMark Cave-Ayland     r->VsrD(0) = prod[0].VsrD(0) ^ prod[1].VsrD(0);
1341fcf5ef2aSThomas Huth #endif
1342fcf5ef2aSThomas Huth }
1343fcf5ef2aSThomas Huth 
1344fcf5ef2aSThomas Huth 
1345fcf5ef2aSThomas Huth #if defined(HOST_WORDS_BIGENDIAN)
1346fcf5ef2aSThomas Huth #define PKBIG 1
1347fcf5ef2aSThomas Huth #else
1348fcf5ef2aSThomas Huth #define PKBIG 0
1349fcf5ef2aSThomas Huth #endif
1350fcf5ef2aSThomas Huth void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1351fcf5ef2aSThomas Huth {
1352fcf5ef2aSThomas Huth     int i, j;
1353fcf5ef2aSThomas Huth     ppc_avr_t result;
1354fcf5ef2aSThomas Huth #if defined(HOST_WORDS_BIGENDIAN)
1355fcf5ef2aSThomas Huth     const ppc_avr_t *x[2] = { a, b };
1356fcf5ef2aSThomas Huth #else
1357fcf5ef2aSThomas Huth     const ppc_avr_t *x[2] = { b, a };
1358fcf5ef2aSThomas Huth #endif
1359fcf5ef2aSThomas Huth 
1360fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, u64) {
1361fcf5ef2aSThomas Huth         VECTOR_FOR_INORDER_I(j, u32) {
1362fcf5ef2aSThomas Huth             uint32_t e = x[i]->u32[j];
1363fcf5ef2aSThomas Huth 
1364fcf5ef2aSThomas Huth             result.u16[4 * i + j] = (((e >> 9) & 0xfc00) |
1365fcf5ef2aSThomas Huth                                      ((e >> 6) & 0x3e0) |
1366fcf5ef2aSThomas Huth                                      ((e >> 3) & 0x1f));
1367fcf5ef2aSThomas Huth         }
1368fcf5ef2aSThomas Huth     }
1369fcf5ef2aSThomas Huth     *r = result;
1370fcf5ef2aSThomas Huth }
1371fcf5ef2aSThomas Huth 
1372fcf5ef2aSThomas Huth #define VPK(suffix, from, to, cvt, dosat)                               \
1373fcf5ef2aSThomas Huth     void helper_vpk##suffix(CPUPPCState *env, ppc_avr_t *r,             \
1374fcf5ef2aSThomas Huth                             ppc_avr_t *a, ppc_avr_t *b)                 \
1375fcf5ef2aSThomas Huth     {                                                                   \
1376fcf5ef2aSThomas Huth         int i;                                                          \
1377fcf5ef2aSThomas Huth         int sat = 0;                                                    \
1378fcf5ef2aSThomas Huth         ppc_avr_t result;                                               \
1379fcf5ef2aSThomas Huth         ppc_avr_t *a0 = PKBIG ? a : b;                                  \
1380fcf5ef2aSThomas Huth         ppc_avr_t *a1 = PKBIG ? b : a;                                  \
1381fcf5ef2aSThomas Huth                                                                         \
1382fcf5ef2aSThomas Huth         VECTOR_FOR_INORDER_I(i, from) {                                 \
1383fcf5ef2aSThomas Huth             result.to[i] = cvt(a0->from[i], &sat);                      \
1384fcf5ef2aSThomas Huth             result.to[i + ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat);\
1385fcf5ef2aSThomas Huth         }                                                               \
1386fcf5ef2aSThomas Huth         *r = result;                                                    \
1387fcf5ef2aSThomas Huth         if (dosat && sat) {                                             \
13886175f5a0SRichard Henderson             set_vscr_sat(env);                                          \
1389fcf5ef2aSThomas Huth         }                                                               \
1390fcf5ef2aSThomas Huth     }
1391fcf5ef2aSThomas Huth #define I(x, y) (x)
1392fcf5ef2aSThomas Huth VPK(shss, s16, s8, cvtshsb, 1)
1393fcf5ef2aSThomas Huth VPK(shus, s16, u8, cvtshub, 1)
1394fcf5ef2aSThomas Huth VPK(swss, s32, s16, cvtswsh, 1)
1395fcf5ef2aSThomas Huth VPK(swus, s32, u16, cvtswuh, 1)
1396fcf5ef2aSThomas Huth VPK(sdss, s64, s32, cvtsdsw, 1)
1397fcf5ef2aSThomas Huth VPK(sdus, s64, u32, cvtsduw, 1)
1398fcf5ef2aSThomas Huth VPK(uhus, u16, u8, cvtuhub, 1)
1399fcf5ef2aSThomas Huth VPK(uwus, u32, u16, cvtuwuh, 1)
1400fcf5ef2aSThomas Huth VPK(udus, u64, u32, cvtuduw, 1)
1401fcf5ef2aSThomas Huth VPK(uhum, u16, u8, I, 0)
1402fcf5ef2aSThomas Huth VPK(uwum, u32, u16, I, 0)
1403fcf5ef2aSThomas Huth VPK(udum, u64, u32, I, 0)
1404fcf5ef2aSThomas Huth #undef I
1405fcf5ef2aSThomas Huth #undef VPK
1406fcf5ef2aSThomas Huth #undef PKBIG
1407fcf5ef2aSThomas Huth 
1408fcf5ef2aSThomas Huth void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
1409fcf5ef2aSThomas Huth {
1410fcf5ef2aSThomas Huth     int i;
1411fcf5ef2aSThomas Huth 
141205ee3e8aSMark Cave-Ayland     for (i = 0; i < ARRAY_SIZE(r->f32); i++) {
141305ee3e8aSMark Cave-Ayland         r->f32[i] = float32_div(float32_one, b->f32[i], &env->vec_status);
1414fcf5ef2aSThomas Huth     }
1415fcf5ef2aSThomas Huth }
1416fcf5ef2aSThomas Huth 
1417fcf5ef2aSThomas Huth #define VRFI(suffix, rounding)                                  \
1418fcf5ef2aSThomas Huth     void helper_vrfi##suffix(CPUPPCState *env, ppc_avr_t *r,    \
1419fcf5ef2aSThomas Huth                              ppc_avr_t *b)                      \
1420fcf5ef2aSThomas Huth     {                                                           \
1421fcf5ef2aSThomas Huth         int i;                                                  \
1422fcf5ef2aSThomas Huth         float_status s = env->vec_status;                       \
1423fcf5ef2aSThomas Huth                                                                 \
1424fcf5ef2aSThomas Huth         set_float_rounding_mode(rounding, &s);                  \
142505ee3e8aSMark Cave-Ayland         for (i = 0; i < ARRAY_SIZE(r->f32); i++) {              \
142605ee3e8aSMark Cave-Ayland             r->f32[i] = float32_round_to_int (b->f32[i], &s);   \
1427fcf5ef2aSThomas Huth         }                                                       \
1428fcf5ef2aSThomas Huth     }
1429fcf5ef2aSThomas Huth VRFI(n, float_round_nearest_even)
1430fcf5ef2aSThomas Huth VRFI(m, float_round_down)
1431fcf5ef2aSThomas Huth VRFI(p, float_round_up)
1432fcf5ef2aSThomas Huth VRFI(z, float_round_to_zero)
1433fcf5ef2aSThomas Huth #undef VRFI
1434fcf5ef2aSThomas Huth 
1435fcf5ef2aSThomas Huth void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
1436fcf5ef2aSThomas Huth {
1437fcf5ef2aSThomas Huth     int i;
1438fcf5ef2aSThomas Huth 
143905ee3e8aSMark Cave-Ayland     for (i = 0; i < ARRAY_SIZE(r->f32); i++) {
144005ee3e8aSMark Cave-Ayland         float32 t = float32_sqrt(b->f32[i], &env->vec_status);
1441fcf5ef2aSThomas Huth 
144205ee3e8aSMark Cave-Ayland         r->f32[i] = float32_div(float32_one, t, &env->vec_status);
1443fcf5ef2aSThomas Huth     }
1444fcf5ef2aSThomas Huth }
1445fcf5ef2aSThomas Huth 
1446fcf5ef2aSThomas Huth #define VRLMI(name, size, element, insert)                            \
1447fcf5ef2aSThomas Huth void helper_##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)          \
1448fcf5ef2aSThomas Huth {                                                                     \
1449fcf5ef2aSThomas Huth     int i;                                                            \
1450fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->element); i++) {                    \
1451fcf5ef2aSThomas Huth         uint##size##_t src1 = a->element[i];                          \
1452fcf5ef2aSThomas Huth         uint##size##_t src2 = b->element[i];                          \
1453fcf5ef2aSThomas Huth         uint##size##_t src3 = r->element[i];                          \
1454fcf5ef2aSThomas Huth         uint##size##_t begin, end, shift, mask, rot_val;              \
1455fcf5ef2aSThomas Huth                                                                       \
1456fcf5ef2aSThomas Huth         shift = extract##size(src2, 0, 6);                            \
1457fcf5ef2aSThomas Huth         end   = extract##size(src2, 8, 6);                            \
1458fcf5ef2aSThomas Huth         begin = extract##size(src2, 16, 6);                           \
1459fcf5ef2aSThomas Huth         rot_val = rol##size(src1, shift);                             \
1460fcf5ef2aSThomas Huth         mask = mask_u##size(begin, end);                              \
1461fcf5ef2aSThomas Huth         if (insert) {                                                 \
1462fcf5ef2aSThomas Huth             r->element[i] = (rot_val & mask) | (src3 & ~mask);        \
1463fcf5ef2aSThomas Huth         } else {                                                      \
1464fcf5ef2aSThomas Huth             r->element[i] = (rot_val & mask);                         \
1465fcf5ef2aSThomas Huth         }                                                             \
1466fcf5ef2aSThomas Huth     }                                                                 \
1467fcf5ef2aSThomas Huth }
1468fcf5ef2aSThomas Huth 
1469fcf5ef2aSThomas Huth VRLMI(vrldmi, 64, u64, 1);
1470fcf5ef2aSThomas Huth VRLMI(vrlwmi, 32, u32, 1);
1471fcf5ef2aSThomas Huth VRLMI(vrldnm, 64, u64, 0);
1472fcf5ef2aSThomas Huth VRLMI(vrlwnm, 32, u32, 0);
1473fcf5ef2aSThomas Huth 
1474fcf5ef2aSThomas Huth void helper_vsel(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
1475fcf5ef2aSThomas Huth                  ppc_avr_t *c)
1476fcf5ef2aSThomas Huth {
1477fcf5ef2aSThomas Huth     r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
1478fcf5ef2aSThomas Huth     r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
1479fcf5ef2aSThomas Huth }
1480fcf5ef2aSThomas Huth 
1481fcf5ef2aSThomas Huth void helper_vexptefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
1482fcf5ef2aSThomas Huth {
1483fcf5ef2aSThomas Huth     int i;
1484fcf5ef2aSThomas Huth 
148505ee3e8aSMark Cave-Ayland     for (i = 0; i < ARRAY_SIZE(r->f32); i++) {
148605ee3e8aSMark Cave-Ayland         r->f32[i] = float32_exp2(b->f32[i], &env->vec_status);
1487fcf5ef2aSThomas Huth     }
1488fcf5ef2aSThomas Huth }
1489fcf5ef2aSThomas Huth 
1490fcf5ef2aSThomas Huth void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
1491fcf5ef2aSThomas Huth {
1492fcf5ef2aSThomas Huth     int i;
1493fcf5ef2aSThomas Huth 
149405ee3e8aSMark Cave-Ayland     for (i = 0; i < ARRAY_SIZE(r->f32); i++) {
149505ee3e8aSMark Cave-Ayland         r->f32[i] = float32_log2(b->f32[i], &env->vec_status);
1496fcf5ef2aSThomas Huth     }
1497fcf5ef2aSThomas Huth }
1498fcf5ef2aSThomas Huth 
149960caf221SAvinesh Kumar #define VEXTU_X_DO(name, size, left)                            \
150060caf221SAvinesh Kumar target_ulong glue(helper_, name)(target_ulong a, ppc_avr_t *b)  \
150160caf221SAvinesh Kumar {                                                               \
1502f297c4c6SMatheus Ferst     int index = (a & 0xf) * 8;                                  \
150360caf221SAvinesh Kumar     if (left) {                                                 \
1504f297c4c6SMatheus Ferst         index = 128 - index - size;                             \
150560caf221SAvinesh Kumar     }                                                           \
150660caf221SAvinesh Kumar     return int128_getlo(int128_rshift(b->s128, index)) &        \
150760caf221SAvinesh Kumar         MAKE_64BIT_MASK(0, size);                               \
150860caf221SAvinesh Kumar }
150960caf221SAvinesh Kumar VEXTU_X_DO(vextublx,  8, 1)
151060caf221SAvinesh Kumar VEXTU_X_DO(vextuhlx, 16, 1)
151160caf221SAvinesh Kumar VEXTU_X_DO(vextuwlx, 32, 1)
151260caf221SAvinesh Kumar VEXTU_X_DO(vextubrx,  8, 0)
151360caf221SAvinesh Kumar VEXTU_X_DO(vextuhrx, 16, 0)
151460caf221SAvinesh Kumar VEXTU_X_DO(vextuwrx, 32, 0)
151560caf221SAvinesh Kumar #undef VEXTU_X_DO
151660caf221SAvinesh Kumar 
1517fcf5ef2aSThomas Huth void helper_vslv(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1518fcf5ef2aSThomas Huth {
1519fcf5ef2aSThomas Huth     int i;
1520fcf5ef2aSThomas Huth     unsigned int shift, bytes, size;
1521fcf5ef2aSThomas Huth 
1522fcf5ef2aSThomas Huth     size = ARRAY_SIZE(r->u8);
1523fcf5ef2aSThomas Huth     for (i = 0; i < size; i++) {
152463be02fcSAnton Blanchard         shift = b->VsrB(i) & 0x7;             /* extract shift value */
152563be02fcSAnton Blanchard         bytes = (a->VsrB(i) << 8) +           /* extract adjacent bytes */
152663be02fcSAnton Blanchard             (((i + 1) < size) ? a->VsrB(i + 1) : 0);
152763be02fcSAnton Blanchard         r->VsrB(i) = (bytes << shift) >> 8;   /* shift and store result */
1528fcf5ef2aSThomas Huth     }
1529fcf5ef2aSThomas Huth }
1530fcf5ef2aSThomas Huth 
1531fcf5ef2aSThomas Huth void helper_vsrv(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1532fcf5ef2aSThomas Huth {
1533fcf5ef2aSThomas Huth     int i;
1534fcf5ef2aSThomas Huth     unsigned int shift, bytes;
1535fcf5ef2aSThomas Huth 
1536b6cb41b2SDavid Gibson     /*
1537b6cb41b2SDavid Gibson      * Use reverse order, as destination and source register can be
1538b6cb41b2SDavid Gibson      * same. Its being modified in place saving temporary, reverse
1539b6cb41b2SDavid Gibson      * order will guarantee that computed result is not fed back.
1540fcf5ef2aSThomas Huth      */
1541fcf5ef2aSThomas Huth     for (i = ARRAY_SIZE(r->u8) - 1; i >= 0; i--) {
154263be02fcSAnton Blanchard         shift = b->VsrB(i) & 0x7;               /* extract shift value */
154363be02fcSAnton Blanchard         bytes = ((i ? a->VsrB(i - 1) : 0) << 8) + a->VsrB(i);
1544fcf5ef2aSThomas Huth                                                 /* extract adjacent bytes */
154563be02fcSAnton Blanchard         r->VsrB(i) = (bytes >> shift) & 0xFF;   /* shift and store result */
1546fcf5ef2aSThomas Huth     }
1547fcf5ef2aSThomas Huth }
1548fcf5ef2aSThomas Huth 
1549fcf5ef2aSThomas Huth void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
1550fcf5ef2aSThomas Huth {
1551fcf5ef2aSThomas Huth     int sh = shift & 0xf;
1552fcf5ef2aSThomas Huth     int i;
1553fcf5ef2aSThomas Huth     ppc_avr_t result;
1554fcf5ef2aSThomas Huth 
1555fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
1556fcf5ef2aSThomas Huth         int index = sh + i;
1557fcf5ef2aSThomas Huth         if (index > 0xf) {
155860594feaSMark Cave-Ayland             result.VsrB(i) = b->VsrB(index - 0x10);
1559fcf5ef2aSThomas Huth         } else {
156060594feaSMark Cave-Ayland             result.VsrB(i) = a->VsrB(index);
1561fcf5ef2aSThomas Huth         }
1562fcf5ef2aSThomas Huth     }
1563fcf5ef2aSThomas Huth     *r = result;
1564fcf5ef2aSThomas Huth }
1565fcf5ef2aSThomas Huth 
1566fcf5ef2aSThomas Huth void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1567fcf5ef2aSThomas Huth {
15683c385a93SMark Cave-Ayland     int sh = (b->VsrB(0xf) >> 3) & 0xf;
1569fcf5ef2aSThomas Huth 
1570fcf5ef2aSThomas Huth #if defined(HOST_WORDS_BIGENDIAN)
1571fcf5ef2aSThomas Huth     memmove(&r->u8[0], &a->u8[sh], 16 - sh);
1572fcf5ef2aSThomas Huth     memset(&r->u8[16 - sh], 0, sh);
1573fcf5ef2aSThomas Huth #else
1574fcf5ef2aSThomas Huth     memmove(&r->u8[sh], &a->u8[0], 16 - sh);
1575fcf5ef2aSThomas Huth     memset(&r->u8[0], 0, sh);
1576fcf5ef2aSThomas Huth #endif
1577fcf5ef2aSThomas Huth }
1578fcf5ef2aSThomas Huth 
1579fcf5ef2aSThomas Huth #if defined(HOST_WORDS_BIGENDIAN)
1580fcf5ef2aSThomas Huth #define VINSERT(suffix, element)                                            \
1581fcf5ef2aSThomas Huth     void helper_vinsert##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t index) \
1582fcf5ef2aSThomas Huth     {                                                                       \
15834fff7218SLaurent Vivier         memmove(&r->u8[index], &b->u8[8 - sizeof(r->element[0])],           \
1584fcf5ef2aSThomas Huth                sizeof(r->element[0]));                                      \
1585fcf5ef2aSThomas Huth     }
1586fcf5ef2aSThomas Huth #else
1587fcf5ef2aSThomas Huth #define VINSERT(suffix, element)                                            \
1588fcf5ef2aSThomas Huth     void helper_vinsert##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t index) \
1589fcf5ef2aSThomas Huth     {                                                                       \
1590fcf5ef2aSThomas Huth         uint32_t d = (16 - index) - sizeof(r->element[0]);                  \
1591fcf5ef2aSThomas Huth         memmove(&r->u8[d], &b->u8[8], sizeof(r->element[0]));               \
1592fcf5ef2aSThomas Huth     }
1593fcf5ef2aSThomas Huth #endif
1594fcf5ef2aSThomas Huth VINSERT(b, u8)
1595fcf5ef2aSThomas Huth VINSERT(h, u16)
1596fcf5ef2aSThomas Huth VINSERT(w, u32)
1597fcf5ef2aSThomas Huth VINSERT(d, u64)
1598fcf5ef2aSThomas Huth #undef VINSERT
1599fcf5ef2aSThomas Huth #if defined(HOST_WORDS_BIGENDIAN)
1600fcf5ef2aSThomas Huth #define VEXTRACT(suffix, element)                                            \
1601fcf5ef2aSThomas Huth     void helper_vextract##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t index) \
1602fcf5ef2aSThomas Huth     {                                                                        \
1603fcf5ef2aSThomas Huth         uint32_t es = sizeof(r->element[0]);                                 \
1604fcf5ef2aSThomas Huth         memmove(&r->u8[8 - es], &b->u8[index], es);                          \
1605fcf5ef2aSThomas Huth         memset(&r->u8[8], 0, 8);                                             \
1606fcf5ef2aSThomas Huth         memset(&r->u8[0], 0, 8 - es);                                        \
1607fcf5ef2aSThomas Huth     }
1608fcf5ef2aSThomas Huth #else
1609fcf5ef2aSThomas Huth #define VEXTRACT(suffix, element)                                            \
1610fcf5ef2aSThomas Huth     void helper_vextract##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t index) \
1611fcf5ef2aSThomas Huth     {                                                                        \
1612fcf5ef2aSThomas Huth         uint32_t es = sizeof(r->element[0]);                                 \
1613fcf5ef2aSThomas Huth         uint32_t s = (16 - index) - es;                                      \
1614fcf5ef2aSThomas Huth         memmove(&r->u8[8], &b->u8[s], es);                                   \
1615fcf5ef2aSThomas Huth         memset(&r->u8[0], 0, 8);                                             \
1616fcf5ef2aSThomas Huth         memset(&r->u8[8 + es], 0, 8 - es);                                   \
1617fcf5ef2aSThomas Huth     }
1618fcf5ef2aSThomas Huth #endif
1619fcf5ef2aSThomas Huth VEXTRACT(ub, u8)
1620fcf5ef2aSThomas Huth VEXTRACT(uh, u16)
1621fcf5ef2aSThomas Huth VEXTRACT(uw, u32)
1622fcf5ef2aSThomas Huth VEXTRACT(d, u64)
1623fcf5ef2aSThomas Huth #undef VEXTRACT
1624fcf5ef2aSThomas Huth 
16255ba5335dSMark Cave-Ayland void helper_xxextractuw(CPUPPCState *env, ppc_vsr_t *xt,
16265ba5335dSMark Cave-Ayland                         ppc_vsr_t *xb, uint32_t index)
16278ad901e5SNikunj A Dadhania {
162803b32c09SMark Cave-Ayland     ppc_vsr_t t = { };
16298ad901e5SNikunj A Dadhania     size_t es = sizeof(uint32_t);
16308ad901e5SNikunj A Dadhania     uint32_t ext_index;
16318ad901e5SNikunj A Dadhania     int i;
16328ad901e5SNikunj A Dadhania 
16338ad901e5SNikunj A Dadhania     ext_index = index;
16348ad901e5SNikunj A Dadhania     for (i = 0; i < es; i++, ext_index++) {
163503b32c09SMark Cave-Ayland         t.VsrB(8 - es + i) = xb->VsrB(ext_index % 16);
16368ad901e5SNikunj A Dadhania     }
16378ad901e5SNikunj A Dadhania 
163803b32c09SMark Cave-Ayland     *xt = t;
16398ad901e5SNikunj A Dadhania }
16408ad901e5SNikunj A Dadhania 
16415ba5335dSMark Cave-Ayland void helper_xxinsertw(CPUPPCState *env, ppc_vsr_t *xt,
16425ba5335dSMark Cave-Ayland                       ppc_vsr_t *xb, uint32_t index)
16433398b742SNikunj A Dadhania {
164403b32c09SMark Cave-Ayland     ppc_vsr_t t = *xt;
16453398b742SNikunj A Dadhania     size_t es = sizeof(uint32_t);
16463398b742SNikunj A Dadhania     int ins_index, i = 0;
16473398b742SNikunj A Dadhania 
16483398b742SNikunj A Dadhania     ins_index = index;
16493398b742SNikunj A Dadhania     for (i = 0; i < es && ins_index < 16; i++, ins_index++) {
165003b32c09SMark Cave-Ayland         t.VsrB(ins_index) = xb->VsrB(8 - es + i);
16513398b742SNikunj A Dadhania     }
16523398b742SNikunj A Dadhania 
165303b32c09SMark Cave-Ayland     *xt = t;
16543398b742SNikunj A Dadhania }
16553398b742SNikunj A Dadhania 
1656634c5835SMark Cave-Ayland #define VEXT_SIGNED(name, element, cast)                            \
1657fcf5ef2aSThomas Huth void helper_##name(ppc_avr_t *r, ppc_avr_t *b)                      \
1658fcf5ef2aSThomas Huth {                                                                   \
1659fcf5ef2aSThomas Huth     int i;                                                          \
166060594feaSMark Cave-Ayland     for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
1661634c5835SMark Cave-Ayland         r->element[i] = (cast)b->element[i];                        \
1662fcf5ef2aSThomas Huth     }                                                               \
1663fcf5ef2aSThomas Huth }
1664634c5835SMark Cave-Ayland VEXT_SIGNED(vextsb2w, s32, int8_t)
1665634c5835SMark Cave-Ayland VEXT_SIGNED(vextsb2d, s64, int8_t)
1666634c5835SMark Cave-Ayland VEXT_SIGNED(vextsh2w, s32, int16_t)
1667634c5835SMark Cave-Ayland VEXT_SIGNED(vextsh2d, s64, int16_t)
1668634c5835SMark Cave-Ayland VEXT_SIGNED(vextsw2d, s64, int32_t)
1669fcf5ef2aSThomas Huth #undef VEXT_SIGNED
1670fcf5ef2aSThomas Huth 
1671fcf5ef2aSThomas Huth #define VNEG(name, element)                                         \
1672fcf5ef2aSThomas Huth void helper_##name(ppc_avr_t *r, ppc_avr_t *b)                      \
1673fcf5ef2aSThomas Huth {                                                                   \
1674fcf5ef2aSThomas Huth     int i;                                                          \
167560594feaSMark Cave-Ayland     for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
1676fcf5ef2aSThomas Huth         r->element[i] = -b->element[i];                             \
1677fcf5ef2aSThomas Huth     }                                                               \
1678fcf5ef2aSThomas Huth }
1679fcf5ef2aSThomas Huth VNEG(vnegw, s32)
1680fcf5ef2aSThomas Huth VNEG(vnegd, s64)
1681fcf5ef2aSThomas Huth #undef VNEG
1682fcf5ef2aSThomas Huth 
1683fcf5ef2aSThomas Huth void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1684fcf5ef2aSThomas Huth {
16853c385a93SMark Cave-Ayland     int sh = (b->VsrB(0xf) >> 3) & 0xf;
1686fcf5ef2aSThomas Huth 
1687fcf5ef2aSThomas Huth #if defined(HOST_WORDS_BIGENDIAN)
1688fcf5ef2aSThomas Huth     memmove(&r->u8[sh], &a->u8[0], 16 - sh);
1689fcf5ef2aSThomas Huth     memset(&r->u8[0], 0, sh);
1690fcf5ef2aSThomas Huth #else
1691fcf5ef2aSThomas Huth     memmove(&r->u8[0], &a->u8[sh], 16 - sh);
1692fcf5ef2aSThomas Huth     memset(&r->u8[16 - sh], 0, sh);
1693fcf5ef2aSThomas Huth #endif
1694fcf5ef2aSThomas Huth }
1695fcf5ef2aSThomas Huth 
1696fcf5ef2aSThomas Huth void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1697fcf5ef2aSThomas Huth {
1698fcf5ef2aSThomas Huth     int i;
1699fcf5ef2aSThomas Huth 
1700fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
1701fcf5ef2aSThomas Huth         r->u32[i] = a->u32[i] >= b->u32[i];
1702fcf5ef2aSThomas Huth     }
1703fcf5ef2aSThomas Huth }
1704fcf5ef2aSThomas Huth 
1705fcf5ef2aSThomas Huth void helper_vsumsws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1706fcf5ef2aSThomas Huth {
1707fcf5ef2aSThomas Huth     int64_t t;
1708fcf5ef2aSThomas Huth     int i, upper;
1709fcf5ef2aSThomas Huth     ppc_avr_t result;
1710fcf5ef2aSThomas Huth     int sat = 0;
1711fcf5ef2aSThomas Huth 
1712fcf5ef2aSThomas Huth     upper = ARRAY_SIZE(r->s32) - 1;
171360594feaSMark Cave-Ayland     t = (int64_t)b->VsrSW(upper);
1714fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
171560594feaSMark Cave-Ayland         t += a->VsrSW(i);
171660594feaSMark Cave-Ayland         result.VsrSW(i) = 0;
1717fcf5ef2aSThomas Huth     }
171860594feaSMark Cave-Ayland     result.VsrSW(upper) = cvtsdsw(t, &sat);
1719fcf5ef2aSThomas Huth     *r = result;
1720fcf5ef2aSThomas Huth 
1721fcf5ef2aSThomas Huth     if (sat) {
17226175f5a0SRichard Henderson         set_vscr_sat(env);
1723fcf5ef2aSThomas Huth     }
1724fcf5ef2aSThomas Huth }
1725fcf5ef2aSThomas Huth 
1726fcf5ef2aSThomas Huth void helper_vsum2sws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1727fcf5ef2aSThomas Huth {
1728fcf5ef2aSThomas Huth     int i, j, upper;
1729fcf5ef2aSThomas Huth     ppc_avr_t result;
1730fcf5ef2aSThomas Huth     int sat = 0;
1731fcf5ef2aSThomas Huth 
1732fcf5ef2aSThomas Huth     upper = 1;
1733fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
173460594feaSMark Cave-Ayland         int64_t t = (int64_t)b->VsrSW(upper + i * 2);
1735fcf5ef2aSThomas Huth 
17367fa0ddc1SAnton Blanchard         result.VsrD(i) = 0;
1737fcf5ef2aSThomas Huth         for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
173860594feaSMark Cave-Ayland             t += a->VsrSW(2 * i + j);
1739fcf5ef2aSThomas Huth         }
174060594feaSMark Cave-Ayland         result.VsrSW(upper + i * 2) = cvtsdsw(t, &sat);
1741fcf5ef2aSThomas Huth     }
1742fcf5ef2aSThomas Huth 
1743fcf5ef2aSThomas Huth     *r = result;
1744fcf5ef2aSThomas Huth     if (sat) {
17456175f5a0SRichard Henderson         set_vscr_sat(env);
1746fcf5ef2aSThomas Huth     }
1747fcf5ef2aSThomas Huth }
1748fcf5ef2aSThomas Huth 
1749fcf5ef2aSThomas Huth void helper_vsum4sbs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1750fcf5ef2aSThomas Huth {
1751fcf5ef2aSThomas Huth     int i, j;
1752fcf5ef2aSThomas Huth     int sat = 0;
1753fcf5ef2aSThomas Huth 
1754fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1755fcf5ef2aSThomas Huth         int64_t t = (int64_t)b->s32[i];
1756fcf5ef2aSThomas Huth 
1757fcf5ef2aSThomas Huth         for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
1758fcf5ef2aSThomas Huth             t += a->s8[4 * i + j];
1759fcf5ef2aSThomas Huth         }
1760fcf5ef2aSThomas Huth         r->s32[i] = cvtsdsw(t, &sat);
1761fcf5ef2aSThomas Huth     }
1762fcf5ef2aSThomas Huth 
1763fcf5ef2aSThomas Huth     if (sat) {
17646175f5a0SRichard Henderson         set_vscr_sat(env);
1765fcf5ef2aSThomas Huth     }
1766fcf5ef2aSThomas Huth }
1767fcf5ef2aSThomas Huth 
1768fcf5ef2aSThomas Huth void helper_vsum4shs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1769fcf5ef2aSThomas Huth {
1770fcf5ef2aSThomas Huth     int sat = 0;
1771fcf5ef2aSThomas Huth     int i;
1772fcf5ef2aSThomas Huth 
1773fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
1774fcf5ef2aSThomas Huth         int64_t t = (int64_t)b->s32[i];
1775fcf5ef2aSThomas Huth 
1776fcf5ef2aSThomas Huth         t += a->s16[2 * i] + a->s16[2 * i + 1];
1777fcf5ef2aSThomas Huth         r->s32[i] = cvtsdsw(t, &sat);
1778fcf5ef2aSThomas Huth     }
1779fcf5ef2aSThomas Huth 
1780fcf5ef2aSThomas Huth     if (sat) {
17816175f5a0SRichard Henderson         set_vscr_sat(env);
1782fcf5ef2aSThomas Huth     }
1783fcf5ef2aSThomas Huth }
1784fcf5ef2aSThomas Huth 
1785fcf5ef2aSThomas Huth void helper_vsum4ubs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1786fcf5ef2aSThomas Huth {
1787fcf5ef2aSThomas Huth     int i, j;
1788fcf5ef2aSThomas Huth     int sat = 0;
1789fcf5ef2aSThomas Huth 
1790fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
1791fcf5ef2aSThomas Huth         uint64_t t = (uint64_t)b->u32[i];
1792fcf5ef2aSThomas Huth 
1793fcf5ef2aSThomas Huth         for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
1794fcf5ef2aSThomas Huth             t += a->u8[4 * i + j];
1795fcf5ef2aSThomas Huth         }
1796fcf5ef2aSThomas Huth         r->u32[i] = cvtuduw(t, &sat);
1797fcf5ef2aSThomas Huth     }
1798fcf5ef2aSThomas Huth 
1799fcf5ef2aSThomas Huth     if (sat) {
18006175f5a0SRichard Henderson         set_vscr_sat(env);
1801fcf5ef2aSThomas Huth     }
1802fcf5ef2aSThomas Huth }
1803fcf5ef2aSThomas Huth 
1804fcf5ef2aSThomas Huth #if defined(HOST_WORDS_BIGENDIAN)
1805fcf5ef2aSThomas Huth #define UPKHI 1
1806fcf5ef2aSThomas Huth #define UPKLO 0
1807fcf5ef2aSThomas Huth #else
1808fcf5ef2aSThomas Huth #define UPKHI 0
1809fcf5ef2aSThomas Huth #define UPKLO 1
1810fcf5ef2aSThomas Huth #endif
1811fcf5ef2aSThomas Huth #define VUPKPX(suffix, hi)                                              \
1812fcf5ef2aSThomas Huth     void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b)                \
1813fcf5ef2aSThomas Huth     {                                                                   \
1814fcf5ef2aSThomas Huth         int i;                                                          \
1815fcf5ef2aSThomas Huth         ppc_avr_t result;                                               \
1816fcf5ef2aSThomas Huth                                                                         \
1817fcf5ef2aSThomas Huth         for (i = 0; i < ARRAY_SIZE(r->u32); i++) {                      \
1818fcf5ef2aSThomas Huth             uint16_t e = b->u16[hi ? i : i + 4];                        \
1819fcf5ef2aSThomas Huth             uint8_t a = (e >> 15) ? 0xff : 0;                           \
1820fcf5ef2aSThomas Huth             uint8_t r = (e >> 10) & 0x1f;                               \
1821fcf5ef2aSThomas Huth             uint8_t g = (e >> 5) & 0x1f;                                \
1822fcf5ef2aSThomas Huth             uint8_t b = e & 0x1f;                                       \
1823fcf5ef2aSThomas Huth                                                                         \
1824fcf5ef2aSThomas Huth             result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b;       \
1825fcf5ef2aSThomas Huth         }                                                               \
1826fcf5ef2aSThomas Huth         *r = result;                                                    \
1827fcf5ef2aSThomas Huth     }
1828fcf5ef2aSThomas Huth VUPKPX(lpx, UPKLO)
1829fcf5ef2aSThomas Huth VUPKPX(hpx, UPKHI)
1830fcf5ef2aSThomas Huth #undef VUPKPX
1831fcf5ef2aSThomas Huth 
1832fcf5ef2aSThomas Huth #define VUPK(suffix, unpacked, packee, hi)                              \
1833fcf5ef2aSThomas Huth     void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b)                \
1834fcf5ef2aSThomas Huth     {                                                                   \
1835fcf5ef2aSThomas Huth         int i;                                                          \
1836fcf5ef2aSThomas Huth         ppc_avr_t result;                                               \
1837fcf5ef2aSThomas Huth                                                                         \
1838fcf5ef2aSThomas Huth         if (hi) {                                                       \
1839fcf5ef2aSThomas Huth             for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) {             \
1840fcf5ef2aSThomas Huth                 result.unpacked[i] = b->packee[i];                      \
1841fcf5ef2aSThomas Huth             }                                                           \
1842fcf5ef2aSThomas Huth         } else {                                                        \
1843fcf5ef2aSThomas Huth             for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); \
1844fcf5ef2aSThomas Huth                  i++) {                                                 \
1845fcf5ef2aSThomas Huth                 result.unpacked[i - ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
1846fcf5ef2aSThomas Huth             }                                                           \
1847fcf5ef2aSThomas Huth         }                                                               \
1848fcf5ef2aSThomas Huth         *r = result;                                                    \
1849fcf5ef2aSThomas Huth     }
1850fcf5ef2aSThomas Huth VUPK(hsb, s16, s8, UPKHI)
1851fcf5ef2aSThomas Huth VUPK(hsh, s32, s16, UPKHI)
1852fcf5ef2aSThomas Huth VUPK(hsw, s64, s32, UPKHI)
1853fcf5ef2aSThomas Huth VUPK(lsb, s16, s8, UPKLO)
1854fcf5ef2aSThomas Huth VUPK(lsh, s32, s16, UPKLO)
1855fcf5ef2aSThomas Huth VUPK(lsw, s64, s32, UPKLO)
1856fcf5ef2aSThomas Huth #undef VUPK
1857fcf5ef2aSThomas Huth #undef UPKHI
1858fcf5ef2aSThomas Huth #undef UPKLO
1859fcf5ef2aSThomas Huth 
1860fcf5ef2aSThomas Huth #define VGENERIC_DO(name, element)                                      \
1861fcf5ef2aSThomas Huth     void helper_v##name(ppc_avr_t *r, ppc_avr_t *b)                     \
1862fcf5ef2aSThomas Huth     {                                                                   \
1863fcf5ef2aSThomas Huth         int i;                                                          \
1864fcf5ef2aSThomas Huth                                                                         \
186560594feaSMark Cave-Ayland         for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
1866fcf5ef2aSThomas Huth             r->element[i] = name(b->element[i]);                        \
1867fcf5ef2aSThomas Huth         }                                                               \
1868fcf5ef2aSThomas Huth     }
1869fcf5ef2aSThomas Huth 
1870fcf5ef2aSThomas Huth #define clzb(v) ((v) ? clz32((uint32_t)(v) << 24) : 8)
1871fcf5ef2aSThomas Huth #define clzh(v) ((v) ? clz32((uint32_t)(v) << 16) : 16)
1872fcf5ef2aSThomas Huth 
1873fcf5ef2aSThomas Huth VGENERIC_DO(clzb, u8)
1874fcf5ef2aSThomas Huth VGENERIC_DO(clzh, u16)
1875fcf5ef2aSThomas Huth 
1876fcf5ef2aSThomas Huth #undef clzb
1877fcf5ef2aSThomas Huth #undef clzh
1878fcf5ef2aSThomas Huth 
1879fcf5ef2aSThomas Huth #define ctzb(v) ((v) ? ctz32(v) : 8)
1880fcf5ef2aSThomas Huth #define ctzh(v) ((v) ? ctz32(v) : 16)
1881fcf5ef2aSThomas Huth #define ctzw(v) ctz32((v))
1882fcf5ef2aSThomas Huth #define ctzd(v) ctz64((v))
1883fcf5ef2aSThomas Huth 
1884fcf5ef2aSThomas Huth VGENERIC_DO(ctzb, u8)
1885fcf5ef2aSThomas Huth VGENERIC_DO(ctzh, u16)
1886fcf5ef2aSThomas Huth VGENERIC_DO(ctzw, u32)
1887fcf5ef2aSThomas Huth VGENERIC_DO(ctzd, u64)
1888fcf5ef2aSThomas Huth 
1889fcf5ef2aSThomas Huth #undef ctzb
1890fcf5ef2aSThomas Huth #undef ctzh
1891fcf5ef2aSThomas Huth #undef ctzw
1892fcf5ef2aSThomas Huth #undef ctzd
1893fcf5ef2aSThomas Huth 
1894fcf5ef2aSThomas Huth #define popcntb(v) ctpop8(v)
1895fcf5ef2aSThomas Huth #define popcnth(v) ctpop16(v)
1896fcf5ef2aSThomas Huth #define popcntw(v) ctpop32(v)
1897fcf5ef2aSThomas Huth #define popcntd(v) ctpop64(v)
1898fcf5ef2aSThomas Huth 
1899fcf5ef2aSThomas Huth VGENERIC_DO(popcntb, u8)
1900fcf5ef2aSThomas Huth VGENERIC_DO(popcnth, u16)
1901fcf5ef2aSThomas Huth VGENERIC_DO(popcntw, u32)
1902fcf5ef2aSThomas Huth VGENERIC_DO(popcntd, u64)
1903fcf5ef2aSThomas Huth 
1904fcf5ef2aSThomas Huth #undef popcntb
1905fcf5ef2aSThomas Huth #undef popcnth
1906fcf5ef2aSThomas Huth #undef popcntw
1907fcf5ef2aSThomas Huth #undef popcntd
1908fcf5ef2aSThomas Huth 
1909fcf5ef2aSThomas Huth #undef VGENERIC_DO
1910fcf5ef2aSThomas Huth 
1911fcf5ef2aSThomas Huth #if defined(HOST_WORDS_BIGENDIAN)
1912fcf5ef2aSThomas Huth #define QW_ONE { .u64 = { 0, 1 } }
1913fcf5ef2aSThomas Huth #else
1914fcf5ef2aSThomas Huth #define QW_ONE { .u64 = { 1, 0 } }
1915fcf5ef2aSThomas Huth #endif
1916fcf5ef2aSThomas Huth 
1917fcf5ef2aSThomas Huth #ifndef CONFIG_INT128
1918fcf5ef2aSThomas Huth 
1919fcf5ef2aSThomas Huth static inline void avr_qw_not(ppc_avr_t *t, ppc_avr_t a)
1920fcf5ef2aSThomas Huth {
1921fcf5ef2aSThomas Huth     t->u64[0] = ~a.u64[0];
1922fcf5ef2aSThomas Huth     t->u64[1] = ~a.u64[1];
1923fcf5ef2aSThomas Huth }
1924fcf5ef2aSThomas Huth 
1925fcf5ef2aSThomas Huth static int avr_qw_cmpu(ppc_avr_t a, ppc_avr_t b)
1926fcf5ef2aSThomas Huth {
19273c385a93SMark Cave-Ayland     if (a.VsrD(0) < b.VsrD(0)) {
1928fcf5ef2aSThomas Huth         return -1;
19293c385a93SMark Cave-Ayland     } else if (a.VsrD(0) > b.VsrD(0)) {
1930fcf5ef2aSThomas Huth         return 1;
19313c385a93SMark Cave-Ayland     } else if (a.VsrD(1) < b.VsrD(1)) {
1932fcf5ef2aSThomas Huth         return -1;
19333c385a93SMark Cave-Ayland     } else if (a.VsrD(1) > b.VsrD(1)) {
1934fcf5ef2aSThomas Huth         return 1;
1935fcf5ef2aSThomas Huth     } else {
1936fcf5ef2aSThomas Huth         return 0;
1937fcf5ef2aSThomas Huth     }
1938fcf5ef2aSThomas Huth }
1939fcf5ef2aSThomas Huth 
1940fcf5ef2aSThomas Huth static void avr_qw_add(ppc_avr_t *t, ppc_avr_t a, ppc_avr_t b)
1941fcf5ef2aSThomas Huth {
19423c385a93SMark Cave-Ayland     t->VsrD(1) = a.VsrD(1) + b.VsrD(1);
19433c385a93SMark Cave-Ayland     t->VsrD(0) = a.VsrD(0) + b.VsrD(0) +
19443c385a93SMark Cave-Ayland                      (~a.VsrD(1) < b.VsrD(1));
1945fcf5ef2aSThomas Huth }
1946fcf5ef2aSThomas Huth 
1947fcf5ef2aSThomas Huth static int avr_qw_addc(ppc_avr_t *t, ppc_avr_t a, ppc_avr_t b)
1948fcf5ef2aSThomas Huth {
1949fcf5ef2aSThomas Huth     ppc_avr_t not_a;
19503c385a93SMark Cave-Ayland     t->VsrD(1) = a.VsrD(1) + b.VsrD(1);
19513c385a93SMark Cave-Ayland     t->VsrD(0) = a.VsrD(0) + b.VsrD(0) +
19523c385a93SMark Cave-Ayland                      (~a.VsrD(1) < b.VsrD(1));
1953fcf5ef2aSThomas Huth     avr_qw_not(&not_a, a);
1954fcf5ef2aSThomas Huth     return avr_qw_cmpu(not_a, b) < 0;
1955fcf5ef2aSThomas Huth }
1956fcf5ef2aSThomas Huth 
1957fcf5ef2aSThomas Huth #endif
1958fcf5ef2aSThomas Huth 
1959fcf5ef2aSThomas Huth void helper_vadduqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1960fcf5ef2aSThomas Huth {
1961fcf5ef2aSThomas Huth #ifdef CONFIG_INT128
1962fcf5ef2aSThomas Huth     r->u128 = a->u128 + b->u128;
1963fcf5ef2aSThomas Huth #else
1964fcf5ef2aSThomas Huth     avr_qw_add(r, *a, *b);
1965fcf5ef2aSThomas Huth #endif
1966fcf5ef2aSThomas Huth }
1967fcf5ef2aSThomas Huth 
1968fcf5ef2aSThomas Huth void helper_vaddeuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
1969fcf5ef2aSThomas Huth {
1970fcf5ef2aSThomas Huth #ifdef CONFIG_INT128
1971fcf5ef2aSThomas Huth     r->u128 = a->u128 + b->u128 + (c->u128 & 1);
1972fcf5ef2aSThomas Huth #else
1973fcf5ef2aSThomas Huth 
19743c385a93SMark Cave-Ayland     if (c->VsrD(1) & 1) {
1975fcf5ef2aSThomas Huth         ppc_avr_t tmp;
1976fcf5ef2aSThomas Huth 
19773c385a93SMark Cave-Ayland         tmp.VsrD(0) = 0;
19783c385a93SMark Cave-Ayland         tmp.VsrD(1) = c->VsrD(1) & 1;
1979fcf5ef2aSThomas Huth         avr_qw_add(&tmp, *a, tmp);
1980fcf5ef2aSThomas Huth         avr_qw_add(r, tmp, *b);
1981fcf5ef2aSThomas Huth     } else {
1982fcf5ef2aSThomas Huth         avr_qw_add(r, *a, *b);
1983fcf5ef2aSThomas Huth     }
1984fcf5ef2aSThomas Huth #endif
1985fcf5ef2aSThomas Huth }
1986fcf5ef2aSThomas Huth 
1987fcf5ef2aSThomas Huth void helper_vaddcuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1988fcf5ef2aSThomas Huth {
1989fcf5ef2aSThomas Huth #ifdef CONFIG_INT128
1990fcf5ef2aSThomas Huth     r->u128 = (~a->u128 < b->u128);
1991fcf5ef2aSThomas Huth #else
1992fcf5ef2aSThomas Huth     ppc_avr_t not_a;
1993fcf5ef2aSThomas Huth 
1994fcf5ef2aSThomas Huth     avr_qw_not(&not_a, *a);
1995fcf5ef2aSThomas Huth 
19963c385a93SMark Cave-Ayland     r->VsrD(0) = 0;
19973c385a93SMark Cave-Ayland     r->VsrD(1) = (avr_qw_cmpu(not_a, *b) < 0);
1998fcf5ef2aSThomas Huth #endif
1999fcf5ef2aSThomas Huth }
2000fcf5ef2aSThomas Huth 
2001fcf5ef2aSThomas Huth void helper_vaddecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2002fcf5ef2aSThomas Huth {
2003fcf5ef2aSThomas Huth #ifdef CONFIG_INT128
2004fcf5ef2aSThomas Huth     int carry_out = (~a->u128 < b->u128);
2005fcf5ef2aSThomas Huth     if (!carry_out && (c->u128 & 1)) {
2006fcf5ef2aSThomas Huth         carry_out = ((a->u128 + b->u128 + 1) == 0) &&
2007fcf5ef2aSThomas Huth                     ((a->u128 != 0) || (b->u128 != 0));
2008fcf5ef2aSThomas Huth     }
2009fcf5ef2aSThomas Huth     r->u128 = carry_out;
2010fcf5ef2aSThomas Huth #else
2011fcf5ef2aSThomas Huth 
20123c385a93SMark Cave-Ayland     int carry_in = c->VsrD(1) & 1;
2013fcf5ef2aSThomas Huth     int carry_out = 0;
2014fcf5ef2aSThomas Huth     ppc_avr_t tmp;
2015fcf5ef2aSThomas Huth 
2016fcf5ef2aSThomas Huth     carry_out = avr_qw_addc(&tmp, *a, *b);
2017fcf5ef2aSThomas Huth 
2018fcf5ef2aSThomas Huth     if (!carry_out && carry_in) {
2019fcf5ef2aSThomas Huth         ppc_avr_t one = QW_ONE;
2020fcf5ef2aSThomas Huth         carry_out = avr_qw_addc(&tmp, tmp, one);
2021fcf5ef2aSThomas Huth     }
20223c385a93SMark Cave-Ayland     r->VsrD(0) = 0;
20233c385a93SMark Cave-Ayland     r->VsrD(1) = carry_out;
2024fcf5ef2aSThomas Huth #endif
2025fcf5ef2aSThomas Huth }
2026fcf5ef2aSThomas Huth 
2027fcf5ef2aSThomas Huth void helper_vsubuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2028fcf5ef2aSThomas Huth {
2029fcf5ef2aSThomas Huth #ifdef CONFIG_INT128
2030fcf5ef2aSThomas Huth     r->u128 = a->u128 - b->u128;
2031fcf5ef2aSThomas Huth #else
2032fcf5ef2aSThomas Huth     ppc_avr_t tmp;
2033fcf5ef2aSThomas Huth     ppc_avr_t one = QW_ONE;
2034fcf5ef2aSThomas Huth 
2035fcf5ef2aSThomas Huth     avr_qw_not(&tmp, *b);
2036fcf5ef2aSThomas Huth     avr_qw_add(&tmp, *a, tmp);
2037fcf5ef2aSThomas Huth     avr_qw_add(r, tmp, one);
2038fcf5ef2aSThomas Huth #endif
2039fcf5ef2aSThomas Huth }
2040fcf5ef2aSThomas Huth 
2041fcf5ef2aSThomas Huth void helper_vsubeuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2042fcf5ef2aSThomas Huth {
2043fcf5ef2aSThomas Huth #ifdef CONFIG_INT128
2044fcf5ef2aSThomas Huth     r->u128 = a->u128 + ~b->u128 + (c->u128 & 1);
2045fcf5ef2aSThomas Huth #else
2046fcf5ef2aSThomas Huth     ppc_avr_t tmp, sum;
2047fcf5ef2aSThomas Huth 
2048fcf5ef2aSThomas Huth     avr_qw_not(&tmp, *b);
2049fcf5ef2aSThomas Huth     avr_qw_add(&sum, *a, tmp);
2050fcf5ef2aSThomas Huth 
20513c385a93SMark Cave-Ayland     tmp.VsrD(0) = 0;
20523c385a93SMark Cave-Ayland     tmp.VsrD(1) = c->VsrD(1) & 1;
2053fcf5ef2aSThomas Huth     avr_qw_add(r, sum, tmp);
2054fcf5ef2aSThomas Huth #endif
2055fcf5ef2aSThomas Huth }
2056fcf5ef2aSThomas Huth 
2057fcf5ef2aSThomas Huth void helper_vsubcuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2058fcf5ef2aSThomas Huth {
2059fcf5ef2aSThomas Huth #ifdef CONFIG_INT128
2060fcf5ef2aSThomas Huth     r->u128 = (~a->u128 < ~b->u128) ||
2061fcf5ef2aSThomas Huth                  (a->u128 + ~b->u128 == (__uint128_t)-1);
2062fcf5ef2aSThomas Huth #else
2063fcf5ef2aSThomas Huth     int carry = (avr_qw_cmpu(*a, *b) > 0);
2064fcf5ef2aSThomas Huth     if (!carry) {
2065fcf5ef2aSThomas Huth         ppc_avr_t tmp;
2066fcf5ef2aSThomas Huth         avr_qw_not(&tmp, *b);
2067fcf5ef2aSThomas Huth         avr_qw_add(&tmp, *a, tmp);
20683c385a93SMark Cave-Ayland         carry = ((tmp.VsrSD(0) == -1ull) && (tmp.VsrSD(1) == -1ull));
2069fcf5ef2aSThomas Huth     }
20703c385a93SMark Cave-Ayland     r->VsrD(0) = 0;
20713c385a93SMark Cave-Ayland     r->VsrD(1) = carry;
2072fcf5ef2aSThomas Huth #endif
2073fcf5ef2aSThomas Huth }
2074fcf5ef2aSThomas Huth 
2075fcf5ef2aSThomas Huth void helper_vsubecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2076fcf5ef2aSThomas Huth {
2077fcf5ef2aSThomas Huth #ifdef CONFIG_INT128
2078fcf5ef2aSThomas Huth     r->u128 =
2079fcf5ef2aSThomas Huth         (~a->u128 < ~b->u128) ||
2080fcf5ef2aSThomas Huth         ((c->u128 & 1) && (a->u128 + ~b->u128 == (__uint128_t)-1));
2081fcf5ef2aSThomas Huth #else
20823c385a93SMark Cave-Ayland     int carry_in = c->VsrD(1) & 1;
2083fcf5ef2aSThomas Huth     int carry_out = (avr_qw_cmpu(*a, *b) > 0);
2084fcf5ef2aSThomas Huth     if (!carry_out && carry_in) {
2085fcf5ef2aSThomas Huth         ppc_avr_t tmp;
2086fcf5ef2aSThomas Huth         avr_qw_not(&tmp, *b);
2087fcf5ef2aSThomas Huth         avr_qw_add(&tmp, *a, tmp);
20883c385a93SMark Cave-Ayland         carry_out = ((tmp.VsrD(0) == -1ull) && (tmp.VsrD(1) == -1ull));
2089fcf5ef2aSThomas Huth     }
2090fcf5ef2aSThomas Huth 
20913c385a93SMark Cave-Ayland     r->VsrD(0) = 0;
20923c385a93SMark Cave-Ayland     r->VsrD(1) = carry_out;
2093fcf5ef2aSThomas Huth #endif
2094fcf5ef2aSThomas Huth }
2095fcf5ef2aSThomas Huth 
2096fcf5ef2aSThomas Huth #define BCD_PLUS_PREF_1 0xC
2097fcf5ef2aSThomas Huth #define BCD_PLUS_PREF_2 0xF
2098fcf5ef2aSThomas Huth #define BCD_PLUS_ALT_1  0xA
2099fcf5ef2aSThomas Huth #define BCD_NEG_PREF    0xD
2100fcf5ef2aSThomas Huth #define BCD_NEG_ALT     0xB
2101fcf5ef2aSThomas Huth #define BCD_PLUS_ALT_2  0xE
2102fcf5ef2aSThomas Huth #define NATIONAL_PLUS   0x2B
2103fcf5ef2aSThomas Huth #define NATIONAL_NEG    0x2D
2104fcf5ef2aSThomas Huth 
2105365206aeSJose Ricardo Ziviani #define BCD_DIG_BYTE(n) (15 - ((n) / 2))
2106fcf5ef2aSThomas Huth 
2107fcf5ef2aSThomas Huth static int bcd_get_sgn(ppc_avr_t *bcd)
2108fcf5ef2aSThomas Huth {
2109428115c3SMark Cave-Ayland     switch (bcd->VsrB(BCD_DIG_BYTE(0)) & 0xF) {
2110fcf5ef2aSThomas Huth     case BCD_PLUS_PREF_1:
2111fcf5ef2aSThomas Huth     case BCD_PLUS_PREF_2:
2112fcf5ef2aSThomas Huth     case BCD_PLUS_ALT_1:
2113fcf5ef2aSThomas Huth     case BCD_PLUS_ALT_2:
2114fcf5ef2aSThomas Huth     {
2115fcf5ef2aSThomas Huth         return 1;
2116fcf5ef2aSThomas Huth     }
2117fcf5ef2aSThomas Huth 
2118fcf5ef2aSThomas Huth     case BCD_NEG_PREF:
2119fcf5ef2aSThomas Huth     case BCD_NEG_ALT:
2120fcf5ef2aSThomas Huth     {
2121fcf5ef2aSThomas Huth         return -1;
2122fcf5ef2aSThomas Huth     }
2123fcf5ef2aSThomas Huth 
2124fcf5ef2aSThomas Huth     default:
2125fcf5ef2aSThomas Huth     {
2126fcf5ef2aSThomas Huth         return 0;
2127fcf5ef2aSThomas Huth     }
2128fcf5ef2aSThomas Huth     }
2129fcf5ef2aSThomas Huth }
2130fcf5ef2aSThomas Huth 
2131fcf5ef2aSThomas Huth static int bcd_preferred_sgn(int sgn, int ps)
2132fcf5ef2aSThomas Huth {
2133fcf5ef2aSThomas Huth     if (sgn >= 0) {
2134fcf5ef2aSThomas Huth         return (ps == 0) ? BCD_PLUS_PREF_1 : BCD_PLUS_PREF_2;
2135fcf5ef2aSThomas Huth     } else {
2136fcf5ef2aSThomas Huth         return BCD_NEG_PREF;
2137fcf5ef2aSThomas Huth     }
2138fcf5ef2aSThomas Huth }
2139fcf5ef2aSThomas Huth 
2140fcf5ef2aSThomas Huth static uint8_t bcd_get_digit(ppc_avr_t *bcd, int n, int *invalid)
2141fcf5ef2aSThomas Huth {
2142fcf5ef2aSThomas Huth     uint8_t result;
2143fcf5ef2aSThomas Huth     if (n & 1) {
2144428115c3SMark Cave-Ayland         result = bcd->VsrB(BCD_DIG_BYTE(n)) >> 4;
2145fcf5ef2aSThomas Huth     } else {
2146428115c3SMark Cave-Ayland        result = bcd->VsrB(BCD_DIG_BYTE(n)) & 0xF;
2147fcf5ef2aSThomas Huth     }
2148fcf5ef2aSThomas Huth 
2149fcf5ef2aSThomas Huth     if (unlikely(result > 9)) {
2150fcf5ef2aSThomas Huth         *invalid = true;
2151fcf5ef2aSThomas Huth     }
2152fcf5ef2aSThomas Huth     return result;
2153fcf5ef2aSThomas Huth }
2154fcf5ef2aSThomas Huth 
2155fcf5ef2aSThomas Huth static void bcd_put_digit(ppc_avr_t *bcd, uint8_t digit, int n)
2156fcf5ef2aSThomas Huth {
2157fcf5ef2aSThomas Huth     if (n & 1) {
2158428115c3SMark Cave-Ayland         bcd->VsrB(BCD_DIG_BYTE(n)) &= 0x0F;
2159428115c3SMark Cave-Ayland         bcd->VsrB(BCD_DIG_BYTE(n)) |= (digit << 4);
2160fcf5ef2aSThomas Huth     } else {
2161428115c3SMark Cave-Ayland         bcd->VsrB(BCD_DIG_BYTE(n)) &= 0xF0;
2162428115c3SMark Cave-Ayland         bcd->VsrB(BCD_DIG_BYTE(n)) |= digit;
2163fcf5ef2aSThomas Huth     }
2164fcf5ef2aSThomas Huth }
2165fcf5ef2aSThomas Huth 
2166071663dfSJose Ricardo Ziviani static bool bcd_is_valid(ppc_avr_t *bcd)
2167071663dfSJose Ricardo Ziviani {
2168071663dfSJose Ricardo Ziviani     int i;
2169071663dfSJose Ricardo Ziviani     int invalid = 0;
2170071663dfSJose Ricardo Ziviani 
2171071663dfSJose Ricardo Ziviani     if (bcd_get_sgn(bcd) == 0) {
2172071663dfSJose Ricardo Ziviani         return false;
2173071663dfSJose Ricardo Ziviani     }
2174071663dfSJose Ricardo Ziviani 
2175071663dfSJose Ricardo Ziviani     for (i = 1; i < 32; i++) {
2176071663dfSJose Ricardo Ziviani         bcd_get_digit(bcd, i, &invalid);
2177071663dfSJose Ricardo Ziviani         if (unlikely(invalid)) {
2178071663dfSJose Ricardo Ziviani             return false;
2179071663dfSJose Ricardo Ziviani         }
2180071663dfSJose Ricardo Ziviani     }
2181071663dfSJose Ricardo Ziviani     return true;
2182071663dfSJose Ricardo Ziviani }
2183071663dfSJose Ricardo Ziviani 
2184fcf5ef2aSThomas Huth static int bcd_cmp_zero(ppc_avr_t *bcd)
2185fcf5ef2aSThomas Huth {
21863c385a93SMark Cave-Ayland     if (bcd->VsrD(0) == 0 && (bcd->VsrD(1) >> 4) == 0) {
2187efa73196SNikunj A Dadhania         return CRF_EQ;
2188fcf5ef2aSThomas Huth     } else {
2189efa73196SNikunj A Dadhania         return (bcd_get_sgn(bcd) == 1) ? CRF_GT : CRF_LT;
2190fcf5ef2aSThomas Huth     }
2191fcf5ef2aSThomas Huth }
2192fcf5ef2aSThomas Huth 
2193fcf5ef2aSThomas Huth static uint16_t get_national_digit(ppc_avr_t *reg, int n)
2194fcf5ef2aSThomas Huth {
219560594feaSMark Cave-Ayland     return reg->VsrH(7 - n);
2196fcf5ef2aSThomas Huth }
2197fcf5ef2aSThomas Huth 
2198fcf5ef2aSThomas Huth static void set_national_digit(ppc_avr_t *reg, uint8_t val, int n)
2199fcf5ef2aSThomas Huth {
220060594feaSMark Cave-Ayland     reg->VsrH(7 - n) = val;
2201fcf5ef2aSThomas Huth }
2202fcf5ef2aSThomas Huth 
2203fcf5ef2aSThomas Huth static int bcd_cmp_mag(ppc_avr_t *a, ppc_avr_t *b)
2204fcf5ef2aSThomas Huth {
2205fcf5ef2aSThomas Huth     int i;
2206fcf5ef2aSThomas Huth     int invalid = 0;
2207fcf5ef2aSThomas Huth     for (i = 31; i > 0; i--) {
2208fcf5ef2aSThomas Huth         uint8_t dig_a = bcd_get_digit(a, i, &invalid);
2209fcf5ef2aSThomas Huth         uint8_t dig_b = bcd_get_digit(b, i, &invalid);
2210fcf5ef2aSThomas Huth         if (unlikely(invalid)) {
2211fcf5ef2aSThomas Huth             return 0; /* doesn't matter */
2212fcf5ef2aSThomas Huth         } else if (dig_a > dig_b) {
2213fcf5ef2aSThomas Huth             return 1;
2214fcf5ef2aSThomas Huth         } else if (dig_a < dig_b) {
2215fcf5ef2aSThomas Huth             return -1;
2216fcf5ef2aSThomas Huth         }
2217fcf5ef2aSThomas Huth     }
2218fcf5ef2aSThomas Huth 
2219fcf5ef2aSThomas Huth     return 0;
2220fcf5ef2aSThomas Huth }
2221fcf5ef2aSThomas Huth 
2222936fda4dSFabiano Rosas static int bcd_add_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid,
2223fcf5ef2aSThomas Huth                        int *overflow)
2224fcf5ef2aSThomas Huth {
2225fcf5ef2aSThomas Huth     int carry = 0;
2226fcf5ef2aSThomas Huth     int i;
2227936fda4dSFabiano Rosas     int is_zero = 1;
2228936fda4dSFabiano Rosas 
2229fcf5ef2aSThomas Huth     for (i = 1; i <= 31; i++) {
2230fcf5ef2aSThomas Huth         uint8_t digit = bcd_get_digit(a, i, invalid) +
2231fcf5ef2aSThomas Huth                         bcd_get_digit(b, i, invalid) + carry;
2232936fda4dSFabiano Rosas         is_zero &= (digit == 0);
2233fcf5ef2aSThomas Huth         if (digit > 9) {
2234fcf5ef2aSThomas Huth             carry = 1;
2235fcf5ef2aSThomas Huth             digit -= 10;
2236fcf5ef2aSThomas Huth         } else {
2237fcf5ef2aSThomas Huth             carry = 0;
2238fcf5ef2aSThomas Huth         }
2239fcf5ef2aSThomas Huth 
2240fcf5ef2aSThomas Huth         bcd_put_digit(t, digit, i);
2241fcf5ef2aSThomas Huth     }
2242fcf5ef2aSThomas Huth 
2243fcf5ef2aSThomas Huth     *overflow = carry;
2244936fda4dSFabiano Rosas     return is_zero;
2245fcf5ef2aSThomas Huth }
2246fcf5ef2aSThomas Huth 
2247d03b174aSYasmin Beatriz static void bcd_sub_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid,
2248fcf5ef2aSThomas Huth                        int *overflow)
2249fcf5ef2aSThomas Huth {
2250fcf5ef2aSThomas Huth     int carry = 0;
2251fcf5ef2aSThomas Huth     int i;
2252d03b174aSYasmin Beatriz 
2253fcf5ef2aSThomas Huth     for (i = 1; i <= 31; i++) {
2254fcf5ef2aSThomas Huth         uint8_t digit = bcd_get_digit(a, i, invalid) -
2255fcf5ef2aSThomas Huth                         bcd_get_digit(b, i, invalid) + carry;
2256fcf5ef2aSThomas Huth         if (digit & 0x80) {
2257fcf5ef2aSThomas Huth             carry = -1;
2258fcf5ef2aSThomas Huth             digit += 10;
2259fcf5ef2aSThomas Huth         } else {
2260fcf5ef2aSThomas Huth             carry = 0;
2261fcf5ef2aSThomas Huth         }
2262fcf5ef2aSThomas Huth 
2263fcf5ef2aSThomas Huth         bcd_put_digit(t, digit, i);
2264fcf5ef2aSThomas Huth     }
2265fcf5ef2aSThomas Huth 
2266fcf5ef2aSThomas Huth     *overflow = carry;
2267fcf5ef2aSThomas Huth }
2268fcf5ef2aSThomas Huth 
2269fcf5ef2aSThomas Huth uint32_t helper_bcdadd(ppc_avr_t *r,  ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
2270fcf5ef2aSThomas Huth {
2271fcf5ef2aSThomas Huth 
2272fcf5ef2aSThomas Huth     int sgna = bcd_get_sgn(a);
2273fcf5ef2aSThomas Huth     int sgnb = bcd_get_sgn(b);
2274fcf5ef2aSThomas Huth     int invalid = (sgna == 0) || (sgnb == 0);
2275fcf5ef2aSThomas Huth     int overflow = 0;
2276936fda4dSFabiano Rosas     int zero = 0;
2277fcf5ef2aSThomas Huth     uint32_t cr = 0;
2278fcf5ef2aSThomas Huth     ppc_avr_t result = { .u64 = { 0, 0 } };
2279fcf5ef2aSThomas Huth 
2280fcf5ef2aSThomas Huth     if (!invalid) {
2281fcf5ef2aSThomas Huth         if (sgna == sgnb) {
2282428115c3SMark Cave-Ayland             result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgna, ps);
2283936fda4dSFabiano Rosas             zero = bcd_add_mag(&result, a, b, &invalid, &overflow);
2284936fda4dSFabiano Rosas             cr = (sgna > 0) ? CRF_GT : CRF_LT;
2285fcf5ef2aSThomas Huth         } else {
2286d03b174aSYasmin Beatriz             int magnitude = bcd_cmp_mag(a, b);
2287d03b174aSYasmin Beatriz             if (magnitude > 0) {
2288428115c3SMark Cave-Ayland                 result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgna, ps);
2289d03b174aSYasmin Beatriz                 bcd_sub_mag(&result, a, b, &invalid, &overflow);
2290d03b174aSYasmin Beatriz                 cr = (sgna > 0) ? CRF_GT : CRF_LT;
2291d03b174aSYasmin Beatriz             } else if (magnitude < 0) {
2292428115c3SMark Cave-Ayland                 result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgnb, ps);
2293d03b174aSYasmin Beatriz                 bcd_sub_mag(&result, b, a, &invalid, &overflow);
2294efa73196SNikunj A Dadhania                 cr = (sgnb > 0) ? CRF_GT : CRF_LT;
2295d03b174aSYasmin Beatriz             } else {
2296428115c3SMark Cave-Ayland                 result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(0, ps);
2297d03b174aSYasmin Beatriz                 cr = CRF_EQ;
2298d03b174aSYasmin Beatriz             }
2299fcf5ef2aSThomas Huth         }
2300fcf5ef2aSThomas Huth     }
2301fcf5ef2aSThomas Huth 
2302fcf5ef2aSThomas Huth     if (unlikely(invalid)) {
23033c385a93SMark Cave-Ayland         result.VsrD(0) = result.VsrD(1) = -1;
2304efa73196SNikunj A Dadhania         cr = CRF_SO;
2305fcf5ef2aSThomas Huth     } else if (overflow) {
2306efa73196SNikunj A Dadhania         cr |= CRF_SO;
2307936fda4dSFabiano Rosas     } else if (zero) {
2308936fda4dSFabiano Rosas         cr |= CRF_EQ;
2309fcf5ef2aSThomas Huth     }
2310fcf5ef2aSThomas Huth 
2311fcf5ef2aSThomas Huth     *r = result;
2312fcf5ef2aSThomas Huth 
2313fcf5ef2aSThomas Huth     return cr;
2314fcf5ef2aSThomas Huth }
2315fcf5ef2aSThomas Huth 
2316fcf5ef2aSThomas Huth uint32_t helper_bcdsub(ppc_avr_t *r,  ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
2317fcf5ef2aSThomas Huth {
2318fcf5ef2aSThomas Huth     ppc_avr_t bcopy = *b;
2319fcf5ef2aSThomas Huth     int sgnb = bcd_get_sgn(b);
2320fcf5ef2aSThomas Huth     if (sgnb < 0) {
2321fcf5ef2aSThomas Huth         bcd_put_digit(&bcopy, BCD_PLUS_PREF_1, 0);
2322fcf5ef2aSThomas Huth     } else if (sgnb > 0) {
2323fcf5ef2aSThomas Huth         bcd_put_digit(&bcopy, BCD_NEG_PREF, 0);
2324fcf5ef2aSThomas Huth     }
2325fcf5ef2aSThomas Huth     /* else invalid ... defer to bcdadd code for proper handling */
2326fcf5ef2aSThomas Huth 
2327fcf5ef2aSThomas Huth     return helper_bcdadd(r, a, &bcopy, ps);
2328fcf5ef2aSThomas Huth }
2329fcf5ef2aSThomas Huth 
2330fcf5ef2aSThomas Huth uint32_t helper_bcdcfn(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
2331fcf5ef2aSThomas Huth {
2332fcf5ef2aSThomas Huth     int i;
2333fcf5ef2aSThomas Huth     int cr = 0;
2334fcf5ef2aSThomas Huth     uint16_t national = 0;
2335fcf5ef2aSThomas Huth     uint16_t sgnb = get_national_digit(b, 0);
2336fcf5ef2aSThomas Huth     ppc_avr_t ret = { .u64 = { 0, 0 } };
2337fcf5ef2aSThomas Huth     int invalid = (sgnb != NATIONAL_PLUS && sgnb != NATIONAL_NEG);
2338fcf5ef2aSThomas Huth 
2339fcf5ef2aSThomas Huth     for (i = 1; i < 8; i++) {
2340fcf5ef2aSThomas Huth         national = get_national_digit(b, i);
2341fcf5ef2aSThomas Huth         if (unlikely(national < 0x30 || national > 0x39)) {
2342fcf5ef2aSThomas Huth             invalid = 1;
2343fcf5ef2aSThomas Huth             break;
2344fcf5ef2aSThomas Huth         }
2345fcf5ef2aSThomas Huth 
2346fcf5ef2aSThomas Huth         bcd_put_digit(&ret, national & 0xf, i);
2347fcf5ef2aSThomas Huth     }
2348fcf5ef2aSThomas Huth 
2349fcf5ef2aSThomas Huth     if (sgnb == NATIONAL_PLUS) {
2350fcf5ef2aSThomas Huth         bcd_put_digit(&ret, (ps == 0) ? BCD_PLUS_PREF_1 : BCD_PLUS_PREF_2, 0);
2351fcf5ef2aSThomas Huth     } else {
2352fcf5ef2aSThomas Huth         bcd_put_digit(&ret, BCD_NEG_PREF, 0);
2353fcf5ef2aSThomas Huth     }
2354fcf5ef2aSThomas Huth 
2355fcf5ef2aSThomas Huth     cr = bcd_cmp_zero(&ret);
2356fcf5ef2aSThomas Huth 
2357fcf5ef2aSThomas Huth     if (unlikely(invalid)) {
2358efa73196SNikunj A Dadhania         cr = CRF_SO;
2359fcf5ef2aSThomas Huth     }
2360fcf5ef2aSThomas Huth 
2361fcf5ef2aSThomas Huth     *r = ret;
2362fcf5ef2aSThomas Huth 
2363fcf5ef2aSThomas Huth     return cr;
2364fcf5ef2aSThomas Huth }
2365fcf5ef2aSThomas Huth 
2366fcf5ef2aSThomas Huth uint32_t helper_bcdctn(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
2367fcf5ef2aSThomas Huth {
2368fcf5ef2aSThomas Huth     int i;
2369fcf5ef2aSThomas Huth     int cr = 0;
2370fcf5ef2aSThomas Huth     int sgnb = bcd_get_sgn(b);
2371fcf5ef2aSThomas Huth     int invalid = (sgnb == 0);
2372fcf5ef2aSThomas Huth     ppc_avr_t ret = { .u64 = { 0, 0 } };
2373fcf5ef2aSThomas Huth 
23743c385a93SMark Cave-Ayland     int ox_flag = (b->VsrD(0) != 0) || ((b->VsrD(1) >> 32) != 0);
2375fcf5ef2aSThomas Huth 
2376fcf5ef2aSThomas Huth     for (i = 1; i < 8; i++) {
2377fcf5ef2aSThomas Huth         set_national_digit(&ret, 0x30 + bcd_get_digit(b, i, &invalid), i);
2378fcf5ef2aSThomas Huth 
2379fcf5ef2aSThomas Huth         if (unlikely(invalid)) {
2380fcf5ef2aSThomas Huth             break;
2381fcf5ef2aSThomas Huth         }
2382fcf5ef2aSThomas Huth     }
2383fcf5ef2aSThomas Huth     set_national_digit(&ret, (sgnb == -1) ? NATIONAL_NEG : NATIONAL_PLUS, 0);
2384fcf5ef2aSThomas Huth 
2385fcf5ef2aSThomas Huth     cr = bcd_cmp_zero(b);
2386fcf5ef2aSThomas Huth 
2387fcf5ef2aSThomas Huth     if (ox_flag) {
2388efa73196SNikunj A Dadhania         cr |= CRF_SO;
2389fcf5ef2aSThomas Huth     }
2390fcf5ef2aSThomas Huth 
2391fcf5ef2aSThomas Huth     if (unlikely(invalid)) {
2392efa73196SNikunj A Dadhania         cr = CRF_SO;
2393fcf5ef2aSThomas Huth     }
2394fcf5ef2aSThomas Huth 
2395fcf5ef2aSThomas Huth     *r = ret;
2396fcf5ef2aSThomas Huth 
2397fcf5ef2aSThomas Huth     return cr;
2398fcf5ef2aSThomas Huth }
2399fcf5ef2aSThomas Huth 
2400fcf5ef2aSThomas Huth uint32_t helper_bcdcfz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
2401fcf5ef2aSThomas Huth {
2402fcf5ef2aSThomas Huth     int i;
2403fcf5ef2aSThomas Huth     int cr = 0;
2404fcf5ef2aSThomas Huth     int invalid = 0;
2405fcf5ef2aSThomas Huth     int zone_digit = 0;
2406fcf5ef2aSThomas Huth     int zone_lead = ps ? 0xF : 0x3;
2407fcf5ef2aSThomas Huth     int digit = 0;
2408fcf5ef2aSThomas Huth     ppc_avr_t ret = { .u64 = { 0, 0 } };
2409428115c3SMark Cave-Ayland     int sgnb = b->VsrB(BCD_DIG_BYTE(0)) >> 4;
2410fcf5ef2aSThomas Huth 
2411fcf5ef2aSThomas Huth     if (unlikely((sgnb < 0xA) && ps)) {
2412fcf5ef2aSThomas Huth         invalid = 1;
2413fcf5ef2aSThomas Huth     }
2414fcf5ef2aSThomas Huth 
2415fcf5ef2aSThomas Huth     for (i = 0; i < 16; i++) {
2416428115c3SMark Cave-Ayland         zone_digit = i ? b->VsrB(BCD_DIG_BYTE(i * 2)) >> 4 : zone_lead;
2417428115c3SMark Cave-Ayland         digit = b->VsrB(BCD_DIG_BYTE(i * 2)) & 0xF;
2418fcf5ef2aSThomas Huth         if (unlikely(zone_digit != zone_lead || digit > 0x9)) {
2419fcf5ef2aSThomas Huth             invalid = 1;
2420fcf5ef2aSThomas Huth             break;
2421fcf5ef2aSThomas Huth         }
2422fcf5ef2aSThomas Huth 
2423fcf5ef2aSThomas Huth         bcd_put_digit(&ret, digit, i + 1);
2424fcf5ef2aSThomas Huth     }
2425fcf5ef2aSThomas Huth 
2426fcf5ef2aSThomas Huth     if ((ps && (sgnb == 0xB || sgnb == 0xD)) ||
2427fcf5ef2aSThomas Huth             (!ps && (sgnb & 0x4))) {
2428fcf5ef2aSThomas Huth         bcd_put_digit(&ret, BCD_NEG_PREF, 0);
2429fcf5ef2aSThomas Huth     } else {
2430fcf5ef2aSThomas Huth         bcd_put_digit(&ret, BCD_PLUS_PREF_1, 0);
2431fcf5ef2aSThomas Huth     }
2432fcf5ef2aSThomas Huth 
2433fcf5ef2aSThomas Huth     cr = bcd_cmp_zero(&ret);
2434fcf5ef2aSThomas Huth 
2435fcf5ef2aSThomas Huth     if (unlikely(invalid)) {
2436efa73196SNikunj A Dadhania         cr = CRF_SO;
2437fcf5ef2aSThomas Huth     }
2438fcf5ef2aSThomas Huth 
2439fcf5ef2aSThomas Huth     *r = ret;
2440fcf5ef2aSThomas Huth 
2441fcf5ef2aSThomas Huth     return cr;
2442fcf5ef2aSThomas Huth }
2443fcf5ef2aSThomas Huth 
2444fcf5ef2aSThomas Huth uint32_t helper_bcdctz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
2445fcf5ef2aSThomas Huth {
2446fcf5ef2aSThomas Huth     int i;
2447fcf5ef2aSThomas Huth     int cr = 0;
2448fcf5ef2aSThomas Huth     uint8_t digit = 0;
2449fcf5ef2aSThomas Huth     int sgnb = bcd_get_sgn(b);
2450fcf5ef2aSThomas Huth     int zone_lead = (ps) ? 0xF0 : 0x30;
2451fcf5ef2aSThomas Huth     int invalid = (sgnb == 0);
2452fcf5ef2aSThomas Huth     ppc_avr_t ret = { .u64 = { 0, 0 } };
2453fcf5ef2aSThomas Huth 
24543c385a93SMark Cave-Ayland     int ox_flag = ((b->VsrD(0) >> 4) != 0);
2455fcf5ef2aSThomas Huth 
2456fcf5ef2aSThomas Huth     for (i = 0; i < 16; i++) {
2457fcf5ef2aSThomas Huth         digit = bcd_get_digit(b, i + 1, &invalid);
2458fcf5ef2aSThomas Huth 
2459fcf5ef2aSThomas Huth         if (unlikely(invalid)) {
2460fcf5ef2aSThomas Huth             break;
2461fcf5ef2aSThomas Huth         }
2462fcf5ef2aSThomas Huth 
2463428115c3SMark Cave-Ayland         ret.VsrB(BCD_DIG_BYTE(i * 2)) = zone_lead + digit;
2464fcf5ef2aSThomas Huth     }
2465fcf5ef2aSThomas Huth 
2466fcf5ef2aSThomas Huth     if (ps) {
2467fcf5ef2aSThomas Huth         bcd_put_digit(&ret, (sgnb == 1) ? 0xC : 0xD, 1);
2468fcf5ef2aSThomas Huth     } else {
2469fcf5ef2aSThomas Huth         bcd_put_digit(&ret, (sgnb == 1) ? 0x3 : 0x7, 1);
2470fcf5ef2aSThomas Huth     }
2471fcf5ef2aSThomas Huth 
2472fcf5ef2aSThomas Huth     cr = bcd_cmp_zero(b);
2473fcf5ef2aSThomas Huth 
2474fcf5ef2aSThomas Huth     if (ox_flag) {
2475efa73196SNikunj A Dadhania         cr |= CRF_SO;
2476fcf5ef2aSThomas Huth     }
2477fcf5ef2aSThomas Huth 
2478fcf5ef2aSThomas Huth     if (unlikely(invalid)) {
2479efa73196SNikunj A Dadhania         cr = CRF_SO;
2480fcf5ef2aSThomas Huth     }
2481fcf5ef2aSThomas Huth 
2482fcf5ef2aSThomas Huth     *r = ret;
2483fcf5ef2aSThomas Huth 
2484fcf5ef2aSThomas Huth     return cr;
2485fcf5ef2aSThomas Huth }
2486fcf5ef2aSThomas Huth 
2487a3d67f3eSLuis Pires /**
2488a3d67f3eSLuis Pires  * Compare 2 128-bit unsigned integers, passed in as unsigned 64-bit pairs
2489a3d67f3eSLuis Pires  *
2490a3d67f3eSLuis Pires  * Returns:
2491a3d67f3eSLuis Pires  * > 0 if ahi|alo > bhi|blo,
2492a3d67f3eSLuis Pires  * 0 if ahi|alo == bhi|blo,
2493a3d67f3eSLuis Pires  * < 0 if ahi|alo < bhi|blo
2494a3d67f3eSLuis Pires  */
2495a3d67f3eSLuis Pires static inline int ucmp128(uint64_t alo, uint64_t ahi,
2496a3d67f3eSLuis Pires                           uint64_t blo, uint64_t bhi)
2497a3d67f3eSLuis Pires {
2498a3d67f3eSLuis Pires     return (ahi == bhi) ?
2499a3d67f3eSLuis Pires         (alo > blo ? 1 : (alo == blo ? 0 : -1)) :
2500a3d67f3eSLuis Pires         (ahi > bhi ? 1 : -1);
2501a3d67f3eSLuis Pires }
2502a3d67f3eSLuis Pires 
2503a406c058SJose Ricardo Ziviani uint32_t helper_bcdcfsq(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
2504a406c058SJose Ricardo Ziviani {
2505a406c058SJose Ricardo Ziviani     int i;
2506a3d67f3eSLuis Pires     int cr;
2507a406c058SJose Ricardo Ziviani     uint64_t lo_value;
2508a406c058SJose Ricardo Ziviani     uint64_t hi_value;
2509*40f3e79aSLuis Pires     uint64_t rem;
2510a406c058SJose Ricardo Ziviani     ppc_avr_t ret = { .u64 = { 0, 0 } };
2511a406c058SJose Ricardo Ziviani 
25123c385a93SMark Cave-Ayland     if (b->VsrSD(0) < 0) {
25133c385a93SMark Cave-Ayland         lo_value = -b->VsrSD(1);
25143c385a93SMark Cave-Ayland         hi_value = ~b->VsrD(0) + !lo_value;
2515a406c058SJose Ricardo Ziviani         bcd_put_digit(&ret, 0xD, 0);
2516a3d67f3eSLuis Pires 
2517a3d67f3eSLuis Pires         cr = CRF_LT;
2518a406c058SJose Ricardo Ziviani     } else {
25193c385a93SMark Cave-Ayland         lo_value = b->VsrD(1);
25203c385a93SMark Cave-Ayland         hi_value = b->VsrD(0);
2521a406c058SJose Ricardo Ziviani         bcd_put_digit(&ret, bcd_preferred_sgn(0, ps), 0);
2522a3d67f3eSLuis Pires 
2523a3d67f3eSLuis Pires         if (hi_value == 0 && lo_value == 0) {
2524a3d67f3eSLuis Pires             cr = CRF_EQ;
2525a3d67f3eSLuis Pires         } else {
2526a3d67f3eSLuis Pires             cr = CRF_GT;
2527a3d67f3eSLuis Pires         }
2528a406c058SJose Ricardo Ziviani     }
2529a406c058SJose Ricardo Ziviani 
2530a3d67f3eSLuis Pires     /*
2531a3d67f3eSLuis Pires      * Check src limits: abs(src) <= 10^31 - 1
2532a3d67f3eSLuis Pires      *
2533a3d67f3eSLuis Pires      * 10^31 - 1 = 0x0000007e37be2022 c0914b267fffffff
2534a3d67f3eSLuis Pires      */
2535a3d67f3eSLuis Pires     if (ucmp128(lo_value, hi_value,
2536a3d67f3eSLuis Pires                 0xc0914b267fffffffULL, 0x7e37be2022ULL) > 0) {
2537a3d67f3eSLuis Pires         cr |= CRF_SO;
2538a3d67f3eSLuis Pires 
2539a3d67f3eSLuis Pires         /*
2540a3d67f3eSLuis Pires          * According to the ISA, if src wouldn't fit in the destination
2541a3d67f3eSLuis Pires          * register, the result is undefined.
2542a3d67f3eSLuis Pires          * In that case, we leave r unchanged.
2543a3d67f3eSLuis Pires          */
2544a3d67f3eSLuis Pires     } else {
2545*40f3e79aSLuis Pires         rem = divu128(&lo_value, &hi_value, 1000000000000000ULL);
2546a406c058SJose Ricardo Ziviani 
2547*40f3e79aSLuis Pires         for (i = 1; i < 16; rem /= 10, i++) {
2548*40f3e79aSLuis Pires             bcd_put_digit(&ret, rem % 10, i);
2549a406c058SJose Ricardo Ziviani         }
2550a406c058SJose Ricardo Ziviani 
2551a406c058SJose Ricardo Ziviani         for (; i < 32; lo_value /= 10, i++) {
2552a406c058SJose Ricardo Ziviani             bcd_put_digit(&ret, lo_value % 10, i);
2553a406c058SJose Ricardo Ziviani         }
2554a406c058SJose Ricardo Ziviani 
2555a406c058SJose Ricardo Ziviani         *r = ret;
2556a3d67f3eSLuis Pires     }
2557a406c058SJose Ricardo Ziviani 
2558a406c058SJose Ricardo Ziviani     return cr;
2559a406c058SJose Ricardo Ziviani }
2560a406c058SJose Ricardo Ziviani 
2561c85bc7ddSJose Ricardo Ziviani uint32_t helper_bcdctsq(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
2562c85bc7ddSJose Ricardo Ziviani {
2563c85bc7ddSJose Ricardo Ziviani     uint8_t i;
2564c85bc7ddSJose Ricardo Ziviani     int cr;
2565c85bc7ddSJose Ricardo Ziviani     uint64_t carry;
2566c85bc7ddSJose Ricardo Ziviani     uint64_t unused;
2567c85bc7ddSJose Ricardo Ziviani     uint64_t lo_value;
2568c85bc7ddSJose Ricardo Ziviani     uint64_t hi_value = 0;
2569c85bc7ddSJose Ricardo Ziviani     int sgnb = bcd_get_sgn(b);
2570c85bc7ddSJose Ricardo Ziviani     int invalid = (sgnb == 0);
2571c85bc7ddSJose Ricardo Ziviani 
2572c85bc7ddSJose Ricardo Ziviani     lo_value = bcd_get_digit(b, 31, &invalid);
2573c85bc7ddSJose Ricardo Ziviani     for (i = 30; i > 0; i--) {
2574c85bc7ddSJose Ricardo Ziviani         mulu64(&lo_value, &carry, lo_value, 10ULL);
2575c85bc7ddSJose Ricardo Ziviani         mulu64(&hi_value, &unused, hi_value, 10ULL);
2576c85bc7ddSJose Ricardo Ziviani         lo_value += bcd_get_digit(b, i, &invalid);
2577c85bc7ddSJose Ricardo Ziviani         hi_value += carry;
2578c85bc7ddSJose Ricardo Ziviani 
2579c85bc7ddSJose Ricardo Ziviani         if (unlikely(invalid)) {
2580c85bc7ddSJose Ricardo Ziviani             break;
2581c85bc7ddSJose Ricardo Ziviani         }
2582c85bc7ddSJose Ricardo Ziviani     }
2583c85bc7ddSJose Ricardo Ziviani 
2584c85bc7ddSJose Ricardo Ziviani     if (sgnb == -1) {
25853c385a93SMark Cave-Ayland         r->VsrSD(1) = -lo_value;
25863c385a93SMark Cave-Ayland         r->VsrSD(0) = ~hi_value + !r->VsrSD(1);
2587c85bc7ddSJose Ricardo Ziviani     } else {
25883c385a93SMark Cave-Ayland         r->VsrSD(1) = lo_value;
25893c385a93SMark Cave-Ayland         r->VsrSD(0) = hi_value;
2590c85bc7ddSJose Ricardo Ziviani     }
2591c85bc7ddSJose Ricardo Ziviani 
2592c85bc7ddSJose Ricardo Ziviani     cr = bcd_cmp_zero(b);
2593c85bc7ddSJose Ricardo Ziviani 
2594c85bc7ddSJose Ricardo Ziviani     if (unlikely(invalid)) {
2595c85bc7ddSJose Ricardo Ziviani         cr = CRF_SO;
2596c85bc7ddSJose Ricardo Ziviani     }
2597c85bc7ddSJose Ricardo Ziviani 
2598c85bc7ddSJose Ricardo Ziviani     return cr;
2599c85bc7ddSJose Ricardo Ziviani }
2600c85bc7ddSJose Ricardo Ziviani 
2601c3025c3bSJose Ricardo Ziviani uint32_t helper_bcdcpsgn(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
2602c3025c3bSJose Ricardo Ziviani {
2603c3025c3bSJose Ricardo Ziviani     int i;
2604c3025c3bSJose Ricardo Ziviani     int invalid = 0;
2605c3025c3bSJose Ricardo Ziviani 
2606c3025c3bSJose Ricardo Ziviani     if (bcd_get_sgn(a) == 0 || bcd_get_sgn(b) == 0) {
2607c3025c3bSJose Ricardo Ziviani         return CRF_SO;
2608c3025c3bSJose Ricardo Ziviani     }
2609c3025c3bSJose Ricardo Ziviani 
2610c3025c3bSJose Ricardo Ziviani     *r = *a;
2611428115c3SMark Cave-Ayland     bcd_put_digit(r, b->VsrB(BCD_DIG_BYTE(0)) & 0xF, 0);
2612c3025c3bSJose Ricardo Ziviani 
2613c3025c3bSJose Ricardo Ziviani     for (i = 1; i < 32; i++) {
2614c3025c3bSJose Ricardo Ziviani         bcd_get_digit(a, i, &invalid);
2615c3025c3bSJose Ricardo Ziviani         bcd_get_digit(b, i, &invalid);
2616c3025c3bSJose Ricardo Ziviani         if (unlikely(invalid)) {
2617c3025c3bSJose Ricardo Ziviani             return CRF_SO;
2618c3025c3bSJose Ricardo Ziviani         }
2619c3025c3bSJose Ricardo Ziviani     }
2620c3025c3bSJose Ricardo Ziviani 
2621c3025c3bSJose Ricardo Ziviani     return bcd_cmp_zero(r);
2622c3025c3bSJose Ricardo Ziviani }
2623c3025c3bSJose Ricardo Ziviani 
2624466a3f9cSJose Ricardo Ziviani uint32_t helper_bcdsetsgn(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
2625466a3f9cSJose Ricardo Ziviani {
2626466a3f9cSJose Ricardo Ziviani     int sgnb = bcd_get_sgn(b);
2627466a3f9cSJose Ricardo Ziviani 
2628466a3f9cSJose Ricardo Ziviani     *r = *b;
2629466a3f9cSJose Ricardo Ziviani     bcd_put_digit(r, bcd_preferred_sgn(sgnb, ps), 0);
2630466a3f9cSJose Ricardo Ziviani 
2631071663dfSJose Ricardo Ziviani     if (bcd_is_valid(b) == false) {
2632466a3f9cSJose Ricardo Ziviani         return CRF_SO;
2633466a3f9cSJose Ricardo Ziviani     }
2634466a3f9cSJose Ricardo Ziviani 
2635466a3f9cSJose Ricardo Ziviani     return bcd_cmp_zero(r);
2636466a3f9cSJose Ricardo Ziviani }
2637466a3f9cSJose Ricardo Ziviani 
2638e04797f7SJose Ricardo Ziviani uint32_t helper_bcds(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
2639e04797f7SJose Ricardo Ziviani {
2640e04797f7SJose Ricardo Ziviani     int cr;
2641428115c3SMark Cave-Ayland     int i = a->VsrSB(7);
2642e04797f7SJose Ricardo Ziviani     bool ox_flag = false;
2643e04797f7SJose Ricardo Ziviani     int sgnb = bcd_get_sgn(b);
2644e04797f7SJose Ricardo Ziviani     ppc_avr_t ret = *b;
26453c385a93SMark Cave-Ayland     ret.VsrD(1) &= ~0xf;
2646e04797f7SJose Ricardo Ziviani 
2647e04797f7SJose Ricardo Ziviani     if (bcd_is_valid(b) == false) {
2648e04797f7SJose Ricardo Ziviani         return CRF_SO;
2649e04797f7SJose Ricardo Ziviani     }
2650e04797f7SJose Ricardo Ziviani 
2651e04797f7SJose Ricardo Ziviani     if (unlikely(i > 31)) {
2652e04797f7SJose Ricardo Ziviani         i = 31;
2653e04797f7SJose Ricardo Ziviani     } else if (unlikely(i < -31)) {
2654e04797f7SJose Ricardo Ziviani         i = -31;
2655e04797f7SJose Ricardo Ziviani     }
2656e04797f7SJose Ricardo Ziviani 
2657e04797f7SJose Ricardo Ziviani     if (i > 0) {
26583c385a93SMark Cave-Ayland         ulshift(&ret.VsrD(1), &ret.VsrD(0), i * 4, &ox_flag);
2659e04797f7SJose Ricardo Ziviani     } else {
26603c385a93SMark Cave-Ayland         urshift(&ret.VsrD(1), &ret.VsrD(0), -i * 4);
2661e04797f7SJose Ricardo Ziviani     }
2662e04797f7SJose Ricardo Ziviani     bcd_put_digit(&ret, bcd_preferred_sgn(sgnb, ps), 0);
2663e04797f7SJose Ricardo Ziviani 
2664e04797f7SJose Ricardo Ziviani     *r = ret;
2665e04797f7SJose Ricardo Ziviani 
2666e04797f7SJose Ricardo Ziviani     cr = bcd_cmp_zero(r);
2667e04797f7SJose Ricardo Ziviani     if (ox_flag) {
2668e04797f7SJose Ricardo Ziviani         cr |= CRF_SO;
2669e04797f7SJose Ricardo Ziviani     }
2670e04797f7SJose Ricardo Ziviani 
2671e04797f7SJose Ricardo Ziviani     return cr;
2672e04797f7SJose Ricardo Ziviani }
2673e04797f7SJose Ricardo Ziviani 
2674a49a95e9SJose Ricardo Ziviani uint32_t helper_bcdus(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
2675a49a95e9SJose Ricardo Ziviani {
2676a49a95e9SJose Ricardo Ziviani     int cr;
2677a49a95e9SJose Ricardo Ziviani     int i;
2678a49a95e9SJose Ricardo Ziviani     int invalid = 0;
2679a49a95e9SJose Ricardo Ziviani     bool ox_flag = false;
2680a49a95e9SJose Ricardo Ziviani     ppc_avr_t ret = *b;
2681a49a95e9SJose Ricardo Ziviani 
2682a49a95e9SJose Ricardo Ziviani     for (i = 0; i < 32; i++) {
2683a49a95e9SJose Ricardo Ziviani         bcd_get_digit(b, i, &invalid);
2684a49a95e9SJose Ricardo Ziviani 
2685a49a95e9SJose Ricardo Ziviani         if (unlikely(invalid)) {
2686a49a95e9SJose Ricardo Ziviani             return CRF_SO;
2687a49a95e9SJose Ricardo Ziviani         }
2688a49a95e9SJose Ricardo Ziviani     }
2689a49a95e9SJose Ricardo Ziviani 
2690428115c3SMark Cave-Ayland     i = a->VsrSB(7);
2691a49a95e9SJose Ricardo Ziviani     if (i >= 32) {
2692a49a95e9SJose Ricardo Ziviani         ox_flag = true;
26933c385a93SMark Cave-Ayland         ret.VsrD(1) = ret.VsrD(0) = 0;
2694a49a95e9SJose Ricardo Ziviani     } else if (i <= -32) {
26953c385a93SMark Cave-Ayland         ret.VsrD(1) = ret.VsrD(0) = 0;
2696a49a95e9SJose Ricardo Ziviani     } else if (i > 0) {
26973c385a93SMark Cave-Ayland         ulshift(&ret.VsrD(1), &ret.VsrD(0), i * 4, &ox_flag);
2698a49a95e9SJose Ricardo Ziviani     } else {
26993c385a93SMark Cave-Ayland         urshift(&ret.VsrD(1), &ret.VsrD(0), -i * 4);
2700a49a95e9SJose Ricardo Ziviani     }
2701a49a95e9SJose Ricardo Ziviani     *r = ret;
2702a49a95e9SJose Ricardo Ziviani 
2703a49a95e9SJose Ricardo Ziviani     cr = bcd_cmp_zero(r);
2704a49a95e9SJose Ricardo Ziviani     if (ox_flag) {
2705a49a95e9SJose Ricardo Ziviani         cr |= CRF_SO;
2706a49a95e9SJose Ricardo Ziviani     }
2707a49a95e9SJose Ricardo Ziviani 
2708a49a95e9SJose Ricardo Ziviani     return cr;
2709a49a95e9SJose Ricardo Ziviani }
2710a49a95e9SJose Ricardo Ziviani 
2711a54238adSJose Ricardo Ziviani uint32_t helper_bcdsr(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
2712a54238adSJose Ricardo Ziviani {
2713a54238adSJose Ricardo Ziviani     int cr;
2714a54238adSJose Ricardo Ziviani     int unused = 0;
2715a54238adSJose Ricardo Ziviani     int invalid = 0;
2716a54238adSJose Ricardo Ziviani     bool ox_flag = false;
2717a54238adSJose Ricardo Ziviani     int sgnb = bcd_get_sgn(b);
2718a54238adSJose Ricardo Ziviani     ppc_avr_t ret = *b;
27193c385a93SMark Cave-Ayland     ret.VsrD(1) &= ~0xf;
2720a54238adSJose Ricardo Ziviani 
2721428115c3SMark Cave-Ayland     int i = a->VsrSB(7);
2722428115c3SMark Cave-Ayland     ppc_avr_t bcd_one;
2723428115c3SMark Cave-Ayland 
2724428115c3SMark Cave-Ayland     bcd_one.VsrD(0) = 0;
2725428115c3SMark Cave-Ayland     bcd_one.VsrD(1) = 0x10;
2726a54238adSJose Ricardo Ziviani 
2727a54238adSJose Ricardo Ziviani     if (bcd_is_valid(b) == false) {
2728a54238adSJose Ricardo Ziviani         return CRF_SO;
2729a54238adSJose Ricardo Ziviani     }
2730a54238adSJose Ricardo Ziviani 
2731a54238adSJose Ricardo Ziviani     if (unlikely(i > 31)) {
2732a54238adSJose Ricardo Ziviani         i = 31;
2733a54238adSJose Ricardo Ziviani     } else if (unlikely(i < -31)) {
2734a54238adSJose Ricardo Ziviani         i = -31;
2735a54238adSJose Ricardo Ziviani     }
2736a54238adSJose Ricardo Ziviani 
2737a54238adSJose Ricardo Ziviani     if (i > 0) {
27383c385a93SMark Cave-Ayland         ulshift(&ret.VsrD(1), &ret.VsrD(0), i * 4, &ox_flag);
2739a54238adSJose Ricardo Ziviani     } else {
27403c385a93SMark Cave-Ayland         urshift(&ret.VsrD(1), &ret.VsrD(0), -i * 4);
2741a54238adSJose Ricardo Ziviani 
2742a54238adSJose Ricardo Ziviani         if (bcd_get_digit(&ret, 0, &invalid) >= 5) {
2743a54238adSJose Ricardo Ziviani             bcd_add_mag(&ret, &ret, &bcd_one, &invalid, &unused);
2744a54238adSJose Ricardo Ziviani         }
2745a54238adSJose Ricardo Ziviani     }
2746a54238adSJose Ricardo Ziviani     bcd_put_digit(&ret, bcd_preferred_sgn(sgnb, ps), 0);
2747a54238adSJose Ricardo Ziviani 
2748a54238adSJose Ricardo Ziviani     cr = bcd_cmp_zero(&ret);
2749a54238adSJose Ricardo Ziviani     if (ox_flag) {
2750a54238adSJose Ricardo Ziviani         cr |= CRF_SO;
2751a54238adSJose Ricardo Ziviani     }
2752a54238adSJose Ricardo Ziviani     *r = ret;
2753a54238adSJose Ricardo Ziviani 
2754a54238adSJose Ricardo Ziviani     return cr;
2755a54238adSJose Ricardo Ziviani }
2756a54238adSJose Ricardo Ziviani 
275731bc4d11SJose Ricardo Ziviani uint32_t helper_bcdtrunc(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
275831bc4d11SJose Ricardo Ziviani {
275931bc4d11SJose Ricardo Ziviani     uint64_t mask;
276031bc4d11SJose Ricardo Ziviani     uint32_t ox_flag = 0;
2761428115c3SMark Cave-Ayland     int i = a->VsrSH(3) + 1;
276231bc4d11SJose Ricardo Ziviani     ppc_avr_t ret = *b;
276331bc4d11SJose Ricardo Ziviani 
276431bc4d11SJose Ricardo Ziviani     if (bcd_is_valid(b) == false) {
276531bc4d11SJose Ricardo Ziviani         return CRF_SO;
276631bc4d11SJose Ricardo Ziviani     }
276731bc4d11SJose Ricardo Ziviani 
276831bc4d11SJose Ricardo Ziviani     if (i > 16 && i < 32) {
276931bc4d11SJose Ricardo Ziviani         mask = (uint64_t)-1 >> (128 - i * 4);
27703c385a93SMark Cave-Ayland         if (ret.VsrD(0) & ~mask) {
277131bc4d11SJose Ricardo Ziviani             ox_flag = CRF_SO;
277231bc4d11SJose Ricardo Ziviani         }
277331bc4d11SJose Ricardo Ziviani 
27743c385a93SMark Cave-Ayland         ret.VsrD(0) &= mask;
277531bc4d11SJose Ricardo Ziviani     } else if (i >= 0 && i <= 16) {
277631bc4d11SJose Ricardo Ziviani         mask = (uint64_t)-1 >> (64 - i * 4);
27773c385a93SMark Cave-Ayland         if (ret.VsrD(0) || (ret.VsrD(1) & ~mask)) {
277831bc4d11SJose Ricardo Ziviani             ox_flag = CRF_SO;
277931bc4d11SJose Ricardo Ziviani         }
278031bc4d11SJose Ricardo Ziviani 
27813c385a93SMark Cave-Ayland         ret.VsrD(1) &= mask;
27823c385a93SMark Cave-Ayland         ret.VsrD(0) = 0;
278331bc4d11SJose Ricardo Ziviani     }
278431bc4d11SJose Ricardo Ziviani     bcd_put_digit(&ret, bcd_preferred_sgn(bcd_get_sgn(b), ps), 0);
278531bc4d11SJose Ricardo Ziviani     *r = ret;
278631bc4d11SJose Ricardo Ziviani 
278731bc4d11SJose Ricardo Ziviani     return bcd_cmp_zero(&ret) | ox_flag;
278831bc4d11SJose Ricardo Ziviani }
278931bc4d11SJose Ricardo Ziviani 
27905c32e2e4SJose Ricardo Ziviani uint32_t helper_bcdutrunc(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
27915c32e2e4SJose Ricardo Ziviani {
27925c32e2e4SJose Ricardo Ziviani     int i;
27935c32e2e4SJose Ricardo Ziviani     uint64_t mask;
27945c32e2e4SJose Ricardo Ziviani     uint32_t ox_flag = 0;
27955c32e2e4SJose Ricardo Ziviani     int invalid = 0;
27965c32e2e4SJose Ricardo Ziviani     ppc_avr_t ret = *b;
27975c32e2e4SJose Ricardo Ziviani 
27985c32e2e4SJose Ricardo Ziviani     for (i = 0; i < 32; i++) {
27995c32e2e4SJose Ricardo Ziviani         bcd_get_digit(b, i, &invalid);
28005c32e2e4SJose Ricardo Ziviani 
28015c32e2e4SJose Ricardo Ziviani         if (unlikely(invalid)) {
28025c32e2e4SJose Ricardo Ziviani             return CRF_SO;
28035c32e2e4SJose Ricardo Ziviani         }
28045c32e2e4SJose Ricardo Ziviani     }
28055c32e2e4SJose Ricardo Ziviani 
2806428115c3SMark Cave-Ayland     i = a->VsrSH(3);
28075c32e2e4SJose Ricardo Ziviani     if (i > 16 && i < 33) {
28085c32e2e4SJose Ricardo Ziviani         mask = (uint64_t)-1 >> (128 - i * 4);
28093c385a93SMark Cave-Ayland         if (ret.VsrD(0) & ~mask) {
28105c32e2e4SJose Ricardo Ziviani             ox_flag = CRF_SO;
28115c32e2e4SJose Ricardo Ziviani         }
28125c32e2e4SJose Ricardo Ziviani 
28133c385a93SMark Cave-Ayland         ret.VsrD(0) &= mask;
28145c32e2e4SJose Ricardo Ziviani     } else if (i > 0 && i <= 16) {
28155c32e2e4SJose Ricardo Ziviani         mask = (uint64_t)-1 >> (64 - i * 4);
28163c385a93SMark Cave-Ayland         if (ret.VsrD(0) || (ret.VsrD(1) & ~mask)) {
28175c32e2e4SJose Ricardo Ziviani             ox_flag = CRF_SO;
28185c32e2e4SJose Ricardo Ziviani         }
28195c32e2e4SJose Ricardo Ziviani 
28203c385a93SMark Cave-Ayland         ret.VsrD(1) &= mask;
28213c385a93SMark Cave-Ayland         ret.VsrD(0) = 0;
28225c32e2e4SJose Ricardo Ziviani     } else if (i == 0) {
28233c385a93SMark Cave-Ayland         if (ret.VsrD(0) || ret.VsrD(1)) {
28245c32e2e4SJose Ricardo Ziviani             ox_flag = CRF_SO;
28255c32e2e4SJose Ricardo Ziviani         }
28263c385a93SMark Cave-Ayland         ret.VsrD(0) = ret.VsrD(1) = 0;
28275c32e2e4SJose Ricardo Ziviani     }
28285c32e2e4SJose Ricardo Ziviani 
28295c32e2e4SJose Ricardo Ziviani     *r = ret;
28303c385a93SMark Cave-Ayland     if (r->VsrD(0) == 0 && r->VsrD(1) == 0) {
28315c32e2e4SJose Ricardo Ziviani         return ox_flag | CRF_EQ;
28325c32e2e4SJose Ricardo Ziviani     }
28335c32e2e4SJose Ricardo Ziviani 
28345c32e2e4SJose Ricardo Ziviani     return ox_flag | CRF_GT;
28355c32e2e4SJose Ricardo Ziviani }
28365c32e2e4SJose Ricardo Ziviani 
2837fcf5ef2aSThomas Huth void helper_vsbox(ppc_avr_t *r, ppc_avr_t *a)
2838fcf5ef2aSThomas Huth {
2839fcf5ef2aSThomas Huth     int i;
2840fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, u8) {
2841fcf5ef2aSThomas Huth         r->u8[i] = AES_sbox[a->u8[i]];
2842fcf5ef2aSThomas Huth     }
2843fcf5ef2aSThomas Huth }
2844fcf5ef2aSThomas Huth 
2845fcf5ef2aSThomas Huth void helper_vcipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2846fcf5ef2aSThomas Huth {
2847fcf5ef2aSThomas Huth     ppc_avr_t result;
2848fcf5ef2aSThomas Huth     int i;
2849fcf5ef2aSThomas Huth 
2850fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, u32) {
28512dea57dbSMark Cave-Ayland         result.VsrW(i) = b->VsrW(i) ^
28522dea57dbSMark Cave-Ayland             (AES_Te0[a->VsrB(AES_shifts[4 * i + 0])] ^
28532dea57dbSMark Cave-Ayland              AES_Te1[a->VsrB(AES_shifts[4 * i + 1])] ^
28542dea57dbSMark Cave-Ayland              AES_Te2[a->VsrB(AES_shifts[4 * i + 2])] ^
28552dea57dbSMark Cave-Ayland              AES_Te3[a->VsrB(AES_shifts[4 * i + 3])]);
2856fcf5ef2aSThomas Huth     }
2857fcf5ef2aSThomas Huth     *r = result;
2858fcf5ef2aSThomas Huth }
2859fcf5ef2aSThomas Huth 
2860fcf5ef2aSThomas Huth void helper_vcipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2861fcf5ef2aSThomas Huth {
2862fcf5ef2aSThomas Huth     ppc_avr_t result;
2863fcf5ef2aSThomas Huth     int i;
2864fcf5ef2aSThomas Huth 
2865fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, u8) {
28662dea57dbSMark Cave-Ayland         result.VsrB(i) = b->VsrB(i) ^ (AES_sbox[a->VsrB(AES_shifts[i])]);
2867fcf5ef2aSThomas Huth     }
2868fcf5ef2aSThomas Huth     *r = result;
2869fcf5ef2aSThomas Huth }
2870fcf5ef2aSThomas Huth 
2871fcf5ef2aSThomas Huth void helper_vncipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2872fcf5ef2aSThomas Huth {
2873fcf5ef2aSThomas Huth     /* This differs from what is written in ISA V2.07.  The RTL is */
2874fcf5ef2aSThomas Huth     /* incorrect and will be fixed in V2.07B.                      */
2875fcf5ef2aSThomas Huth     int i;
2876fcf5ef2aSThomas Huth     ppc_avr_t tmp;
2877fcf5ef2aSThomas Huth 
2878fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, u8) {
28792dea57dbSMark Cave-Ayland         tmp.VsrB(i) = b->VsrB(i) ^ AES_isbox[a->VsrB(AES_ishifts[i])];
2880fcf5ef2aSThomas Huth     }
2881fcf5ef2aSThomas Huth 
2882fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, u32) {
28832dea57dbSMark Cave-Ayland         r->VsrW(i) =
28842dea57dbSMark Cave-Ayland             AES_imc[tmp.VsrB(4 * i + 0)][0] ^
28852dea57dbSMark Cave-Ayland             AES_imc[tmp.VsrB(4 * i + 1)][1] ^
28862dea57dbSMark Cave-Ayland             AES_imc[tmp.VsrB(4 * i + 2)][2] ^
28872dea57dbSMark Cave-Ayland             AES_imc[tmp.VsrB(4 * i + 3)][3];
2888fcf5ef2aSThomas Huth     }
2889fcf5ef2aSThomas Huth }
2890fcf5ef2aSThomas Huth 
2891fcf5ef2aSThomas Huth void helper_vncipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2892fcf5ef2aSThomas Huth {
2893fcf5ef2aSThomas Huth     ppc_avr_t result;
2894fcf5ef2aSThomas Huth     int i;
2895fcf5ef2aSThomas Huth 
2896fcf5ef2aSThomas Huth     VECTOR_FOR_INORDER_I(i, u8) {
28972dea57dbSMark Cave-Ayland         result.VsrB(i) = b->VsrB(i) ^ (AES_isbox[a->VsrB(AES_ishifts[i])]);
2898fcf5ef2aSThomas Huth     }
2899fcf5ef2aSThomas Huth     *r = result;
2900fcf5ef2aSThomas Huth }
2901fcf5ef2aSThomas Huth 
2902fcf5ef2aSThomas Huth void helper_vshasigmaw(ppc_avr_t *r,  ppc_avr_t *a, uint32_t st_six)
2903fcf5ef2aSThomas Huth {
2904fcf5ef2aSThomas Huth     int st = (st_six & 0x10) != 0;
2905fcf5ef2aSThomas Huth     int six = st_six & 0xF;
2906fcf5ef2aSThomas Huth     int i;
2907fcf5ef2aSThomas Huth 
2908730d2ca3SMark Cave-Ayland     for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2909fcf5ef2aSThomas Huth         if (st == 0) {
2910fcf5ef2aSThomas Huth             if ((six & (0x8 >> i)) == 0) {
29110ef83bf2SMark Cave-Ayland                 r->VsrW(i) = ror32(a->VsrW(i), 7) ^
29120ef83bf2SMark Cave-Ayland                              ror32(a->VsrW(i), 18) ^
2913730d2ca3SMark Cave-Ayland                              (a->VsrW(i) >> 3);
2914fcf5ef2aSThomas Huth             } else { /* six.bit[i] == 1 */
29150ef83bf2SMark Cave-Ayland                 r->VsrW(i) = ror32(a->VsrW(i), 17) ^
29160ef83bf2SMark Cave-Ayland                              ror32(a->VsrW(i), 19) ^
2917730d2ca3SMark Cave-Ayland                              (a->VsrW(i) >> 10);
2918fcf5ef2aSThomas Huth             }
2919fcf5ef2aSThomas Huth         } else { /* st == 1 */
2920fcf5ef2aSThomas Huth             if ((six & (0x8 >> i)) == 0) {
29210ef83bf2SMark Cave-Ayland                 r->VsrW(i) = ror32(a->VsrW(i), 2) ^
29220ef83bf2SMark Cave-Ayland                              ror32(a->VsrW(i), 13) ^
29230ef83bf2SMark Cave-Ayland                              ror32(a->VsrW(i), 22);
2924fcf5ef2aSThomas Huth             } else { /* six.bit[i] == 1 */
29250ef83bf2SMark Cave-Ayland                 r->VsrW(i) = ror32(a->VsrW(i), 6) ^
29260ef83bf2SMark Cave-Ayland                              ror32(a->VsrW(i), 11) ^
29270ef83bf2SMark Cave-Ayland                              ror32(a->VsrW(i), 25);
2928fcf5ef2aSThomas Huth             }
2929fcf5ef2aSThomas Huth         }
2930fcf5ef2aSThomas Huth     }
2931fcf5ef2aSThomas Huth }
2932fcf5ef2aSThomas Huth 
2933fcf5ef2aSThomas Huth void helper_vshasigmad(ppc_avr_t *r,  ppc_avr_t *a, uint32_t st_six)
2934fcf5ef2aSThomas Huth {
2935fcf5ef2aSThomas Huth     int st = (st_six & 0x10) != 0;
2936fcf5ef2aSThomas Huth     int six = st_six & 0xF;
2937fcf5ef2aSThomas Huth     int i;
2938fcf5ef2aSThomas Huth 
2939730d2ca3SMark Cave-Ayland     for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2940fcf5ef2aSThomas Huth         if (st == 0) {
2941fcf5ef2aSThomas Huth             if ((six & (0x8 >> (2 * i))) == 0) {
29420ef83bf2SMark Cave-Ayland                 r->VsrD(i) = ror64(a->VsrD(i), 1) ^
29430ef83bf2SMark Cave-Ayland                              ror64(a->VsrD(i), 8) ^
2944730d2ca3SMark Cave-Ayland                              (a->VsrD(i) >> 7);
2945fcf5ef2aSThomas Huth             } else { /* six.bit[2*i] == 1 */
29460ef83bf2SMark Cave-Ayland                 r->VsrD(i) = ror64(a->VsrD(i), 19) ^
29470ef83bf2SMark Cave-Ayland                              ror64(a->VsrD(i), 61) ^
2948730d2ca3SMark Cave-Ayland                              (a->VsrD(i) >> 6);
2949fcf5ef2aSThomas Huth             }
2950fcf5ef2aSThomas Huth         } else { /* st == 1 */
2951fcf5ef2aSThomas Huth             if ((six & (0x8 >> (2 * i))) == 0) {
29520ef83bf2SMark Cave-Ayland                 r->VsrD(i) = ror64(a->VsrD(i), 28) ^
29530ef83bf2SMark Cave-Ayland                              ror64(a->VsrD(i), 34) ^
29540ef83bf2SMark Cave-Ayland                              ror64(a->VsrD(i), 39);
2955fcf5ef2aSThomas Huth             } else { /* six.bit[2*i] == 1 */
29560ef83bf2SMark Cave-Ayland                 r->VsrD(i) = ror64(a->VsrD(i), 14) ^
29570ef83bf2SMark Cave-Ayland                              ror64(a->VsrD(i), 18) ^
29580ef83bf2SMark Cave-Ayland                              ror64(a->VsrD(i), 41);
2959fcf5ef2aSThomas Huth             }
2960fcf5ef2aSThomas Huth         }
2961fcf5ef2aSThomas Huth     }
2962fcf5ef2aSThomas Huth }
2963fcf5ef2aSThomas Huth 
2964fcf5ef2aSThomas Huth void helper_vpermxor(ppc_avr_t *r,  ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2965fcf5ef2aSThomas Huth {
2966fcf5ef2aSThomas Huth     ppc_avr_t result;
2967fcf5ef2aSThomas Huth     int i;
2968fcf5ef2aSThomas Huth 
296960594feaSMark Cave-Ayland     for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
297060594feaSMark Cave-Ayland         int indexA = c->VsrB(i) >> 4;
297160594feaSMark Cave-Ayland         int indexB = c->VsrB(i) & 0xF;
297260594feaSMark Cave-Ayland 
297360594feaSMark Cave-Ayland         result.VsrB(i) = a->VsrB(indexA) ^ b->VsrB(indexB);
2974fcf5ef2aSThomas Huth     }
2975fcf5ef2aSThomas Huth     *r = result;
2976fcf5ef2aSThomas Huth }
2977fcf5ef2aSThomas Huth 
2978fcf5ef2aSThomas Huth #undef VECTOR_FOR_INORDER_I
2979fcf5ef2aSThomas Huth 
2980fcf5ef2aSThomas Huth /*****************************************************************************/
2981fcf5ef2aSThomas Huth /* SPE extension helpers */
2982fcf5ef2aSThomas Huth /* Use a table to make this quicker */
2983fcf5ef2aSThomas Huth static const uint8_t hbrev[16] = {
2984fcf5ef2aSThomas Huth     0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
2985fcf5ef2aSThomas Huth     0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
2986fcf5ef2aSThomas Huth };
2987fcf5ef2aSThomas Huth 
2988fcf5ef2aSThomas Huth static inline uint8_t byte_reverse(uint8_t val)
2989fcf5ef2aSThomas Huth {
2990fcf5ef2aSThomas Huth     return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
2991fcf5ef2aSThomas Huth }
2992fcf5ef2aSThomas Huth 
2993fcf5ef2aSThomas Huth static inline uint32_t word_reverse(uint32_t val)
2994fcf5ef2aSThomas Huth {
2995fcf5ef2aSThomas Huth     return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
2996fcf5ef2aSThomas Huth         (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
2997fcf5ef2aSThomas Huth }
2998fcf5ef2aSThomas Huth 
2999fcf5ef2aSThomas Huth #define MASKBITS 16 /* Random value - to be fixed (implementation dependent) */
3000fcf5ef2aSThomas Huth target_ulong helper_brinc(target_ulong arg1, target_ulong arg2)
3001fcf5ef2aSThomas Huth {
3002fcf5ef2aSThomas Huth     uint32_t a, b, d, mask;
3003fcf5ef2aSThomas Huth 
3004fcf5ef2aSThomas Huth     mask = UINT32_MAX >> (32 - MASKBITS);
3005fcf5ef2aSThomas Huth     a = arg1 & mask;
3006fcf5ef2aSThomas Huth     b = arg2 & mask;
3007fcf5ef2aSThomas Huth     d = word_reverse(1 + word_reverse(a | ~b));
3008fcf5ef2aSThomas Huth     return (arg1 & ~mask) | (d & b);
3009fcf5ef2aSThomas Huth }
3010fcf5ef2aSThomas Huth 
3011fcf5ef2aSThomas Huth uint32_t helper_cntlsw32(uint32_t val)
3012fcf5ef2aSThomas Huth {
3013fcf5ef2aSThomas Huth     if (val & 0x80000000) {
3014fcf5ef2aSThomas Huth         return clz32(~val);
3015fcf5ef2aSThomas Huth     } else {
3016fcf5ef2aSThomas Huth         return clz32(val);
3017fcf5ef2aSThomas Huth     }
3018fcf5ef2aSThomas Huth }
3019fcf5ef2aSThomas Huth 
3020fcf5ef2aSThomas Huth uint32_t helper_cntlzw32(uint32_t val)
3021fcf5ef2aSThomas Huth {
3022fcf5ef2aSThomas Huth     return clz32(val);
3023fcf5ef2aSThomas Huth }
3024fcf5ef2aSThomas Huth 
3025fcf5ef2aSThomas Huth /* 440 specific */
3026fcf5ef2aSThomas Huth target_ulong helper_dlmzb(CPUPPCState *env, target_ulong high,
3027fcf5ef2aSThomas Huth                           target_ulong low, uint32_t update_Rc)
3028fcf5ef2aSThomas Huth {
3029fcf5ef2aSThomas Huth     target_ulong mask;
3030fcf5ef2aSThomas Huth     int i;
3031fcf5ef2aSThomas Huth 
3032fcf5ef2aSThomas Huth     i = 1;
3033fcf5ef2aSThomas Huth     for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
3034fcf5ef2aSThomas Huth         if ((high & mask) == 0) {
3035fcf5ef2aSThomas Huth             if (update_Rc) {
3036fcf5ef2aSThomas Huth                 env->crf[0] = 0x4;
3037fcf5ef2aSThomas Huth             }
3038fcf5ef2aSThomas Huth             goto done;
3039fcf5ef2aSThomas Huth         }
3040fcf5ef2aSThomas Huth         i++;
3041fcf5ef2aSThomas Huth     }
3042fcf5ef2aSThomas Huth     for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
3043fcf5ef2aSThomas Huth         if ((low & mask) == 0) {
3044fcf5ef2aSThomas Huth             if (update_Rc) {
3045fcf5ef2aSThomas Huth                 env->crf[0] = 0x8;
3046fcf5ef2aSThomas Huth             }
3047fcf5ef2aSThomas Huth             goto done;
3048fcf5ef2aSThomas Huth         }
3049fcf5ef2aSThomas Huth         i++;
3050fcf5ef2aSThomas Huth     }
3051fcf5ef2aSThomas Huth     i = 8;
3052fcf5ef2aSThomas Huth     if (update_Rc) {
3053fcf5ef2aSThomas Huth         env->crf[0] = 0x2;
3054fcf5ef2aSThomas Huth     }
3055fcf5ef2aSThomas Huth  done:
3056fcf5ef2aSThomas Huth     env->xer = (env->xer & ~0x7F) | i;
3057fcf5ef2aSThomas Huth     if (update_Rc) {
3058fcf5ef2aSThomas Huth         env->crf[0] |= xer_so;
3059fcf5ef2aSThomas Huth     }
3060fcf5ef2aSThomas Huth     return i;
3061fcf5ef2aSThomas Huth }
3062