xref: /openbmc/qemu/target/ppc/dfp_helper.c (revision 173c427eb5705064da7dc8db22553c8df34f7f58)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  *  PowerPC Decimal Floating Point (DPF) emulation helpers for QEMU.
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  *  Copyright (c) 2014 IBM Corporation.
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  */
19fcf5ef2aSThomas Huth 
20fcf5ef2aSThomas Huth #include "qemu/osdep.h"
21fcf5ef2aSThomas Huth #include "cpu.h"
22fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
23fcf5ef2aSThomas Huth 
24fcf5ef2aSThomas Huth #define DECNUMDIGITS 34
25fcf5ef2aSThomas Huth #include "libdecnumber/decContext.h"
26fcf5ef2aSThomas Huth #include "libdecnumber/decNumber.h"
27fcf5ef2aSThomas Huth #include "libdecnumber/dpd/decimal32.h"
28fcf5ef2aSThomas Huth #include "libdecnumber/dpd/decimal64.h"
29fcf5ef2aSThomas Huth #include "libdecnumber/dpd/decimal128.h"
30fcf5ef2aSThomas Huth 
31fcf5ef2aSThomas Huth 
get_dfp64(ppc_vsr_t * dst,ppc_fprp_t * dfp)3264b8574eSMark Cave-Ayland static void get_dfp64(ppc_vsr_t *dst, ppc_fprp_t *dfp)
336a8fbb9bSMark Cave-Ayland {
3464b8574eSMark Cave-Ayland     dst->VsrD(1) = dfp->VsrD(0);
356a8fbb9bSMark Cave-Ayland }
366a8fbb9bSMark Cave-Ayland 
get_dfp128(ppc_vsr_t * dst,ppc_fprp_t * dfp)3764b8574eSMark Cave-Ayland static void get_dfp128(ppc_vsr_t *dst, ppc_fprp_t *dfp)
386a8fbb9bSMark Cave-Ayland {
3964b8574eSMark Cave-Ayland     dst->VsrD(0) = dfp[0].VsrD(0);
4064b8574eSMark Cave-Ayland     dst->VsrD(1) = dfp[1].VsrD(0);
416a8fbb9bSMark Cave-Ayland }
426a8fbb9bSMark Cave-Ayland 
set_dfp64(ppc_fprp_t * dfp,ppc_vsr_t * src)4364b8574eSMark Cave-Ayland static void set_dfp64(ppc_fprp_t *dfp, ppc_vsr_t *src)
4433432d77SMark Cave-Ayland {
4534f760baSVíctor Colombo     dfp[0].VsrD(0) = src->VsrD(1);
4634f760baSVíctor Colombo     dfp[0].VsrD(1) = 0ULL;
4733432d77SMark Cave-Ayland }
4833432d77SMark Cave-Ayland 
set_dfp128(ppc_fprp_t * dfp,ppc_vsr_t * src)4964b8574eSMark Cave-Ayland static void set_dfp128(ppc_fprp_t *dfp, ppc_vsr_t *src)
5033432d77SMark Cave-Ayland {
5164b8574eSMark Cave-Ayland     dfp[0].VsrD(0) = src->VsrD(0);
5264b8574eSMark Cave-Ayland     dfp[1].VsrD(0) = src->VsrD(1);
5334f760baSVíctor Colombo     dfp[0].VsrD(1) = 0ULL;
5434f760baSVíctor Colombo     dfp[1].VsrD(1) = 0ULL;
5533432d77SMark Cave-Ayland }
5633432d77SMark Cave-Ayland 
set_dfp128_to_avr(ppc_avr_t * dst,ppc_vsr_t * src)57328747f3SLuis Pires static void set_dfp128_to_avr(ppc_avr_t *dst, ppc_vsr_t *src)
58328747f3SLuis Pires {
59328747f3SLuis Pires     *dst = *src;
60328747f3SLuis Pires }
61328747f3SLuis Pires 
62fcf5ef2aSThomas Huth struct PPC_DFP {
63fcf5ef2aSThomas Huth     CPUPPCState *env;
6464b8574eSMark Cave-Ayland     ppc_vsr_t vt, va, vb;
65fcf5ef2aSThomas Huth     decNumber t, a, b;
66fcf5ef2aSThomas Huth     decContext context;
67fcf5ef2aSThomas Huth     uint8_t crbf;
68fcf5ef2aSThomas Huth };
69fcf5ef2aSThomas Huth 
dfp_prepare_rounding_mode(decContext * context,uint64_t fpscr)70fcf5ef2aSThomas Huth static void dfp_prepare_rounding_mode(decContext *context, uint64_t fpscr)
71fcf5ef2aSThomas Huth {
72fcf5ef2aSThomas Huth     enum rounding rnd;
73fcf5ef2aSThomas Huth 
74a2735cf4SPaul A. Clarke     switch ((fpscr & FP_DRN) >> FPSCR_DRN0) {
75fcf5ef2aSThomas Huth     case 0:
76fcf5ef2aSThomas Huth         rnd = DEC_ROUND_HALF_EVEN;
77fcf5ef2aSThomas Huth         break;
78fcf5ef2aSThomas Huth     case 1:
79fcf5ef2aSThomas Huth         rnd = DEC_ROUND_DOWN;
80fcf5ef2aSThomas Huth         break;
81fcf5ef2aSThomas Huth     case 2:
82fcf5ef2aSThomas Huth          rnd = DEC_ROUND_CEILING;
83fcf5ef2aSThomas Huth          break;
84fcf5ef2aSThomas Huth     case 3:
85fcf5ef2aSThomas Huth          rnd = DEC_ROUND_FLOOR;
86fcf5ef2aSThomas Huth          break;
87fcf5ef2aSThomas Huth     case 4:
88fcf5ef2aSThomas Huth          rnd = DEC_ROUND_HALF_UP;
89fcf5ef2aSThomas Huth          break;
90fcf5ef2aSThomas Huth     case 5:
91fcf5ef2aSThomas Huth          rnd = DEC_ROUND_HALF_DOWN;
92fcf5ef2aSThomas Huth          break;
93fcf5ef2aSThomas Huth     case 6:
94fcf5ef2aSThomas Huth          rnd = DEC_ROUND_UP;
95fcf5ef2aSThomas Huth          break;
96fcf5ef2aSThomas Huth     case 7:
97fcf5ef2aSThomas Huth          rnd = DEC_ROUND_05UP;
98fcf5ef2aSThomas Huth          break;
99fcf5ef2aSThomas Huth     default:
100fcf5ef2aSThomas Huth         g_assert_not_reached();
101fcf5ef2aSThomas Huth     }
102fcf5ef2aSThomas Huth 
103fcf5ef2aSThomas Huth     decContextSetRounding(context, rnd);
104fcf5ef2aSThomas Huth }
105fcf5ef2aSThomas Huth 
dfp_set_round_mode_from_immediate(uint8_t r,uint8_t rmc,struct PPC_DFP * dfp)106fcf5ef2aSThomas Huth static void dfp_set_round_mode_from_immediate(uint8_t r, uint8_t rmc,
107fcf5ef2aSThomas Huth                                                   struct PPC_DFP *dfp)
108fcf5ef2aSThomas Huth {
109fcf5ef2aSThomas Huth     enum rounding rnd;
110fcf5ef2aSThomas Huth     if (r == 0) {
111fcf5ef2aSThomas Huth         switch (rmc & 3) {
112fcf5ef2aSThomas Huth         case 0:
113fcf5ef2aSThomas Huth             rnd = DEC_ROUND_HALF_EVEN;
114fcf5ef2aSThomas Huth             break;
115fcf5ef2aSThomas Huth         case 1:
116fcf5ef2aSThomas Huth             rnd = DEC_ROUND_DOWN;
117fcf5ef2aSThomas Huth             break;
118fcf5ef2aSThomas Huth         case 2:
119fcf5ef2aSThomas Huth             rnd = DEC_ROUND_HALF_UP;
120fcf5ef2aSThomas Huth             break;
121fcf5ef2aSThomas Huth         case 3: /* use FPSCR rounding mode */
122fcf5ef2aSThomas Huth             return;
123fcf5ef2aSThomas Huth         default:
124a1a65aadSPierrick Bouvier             g_assert_not_reached();
125fcf5ef2aSThomas Huth         }
126fcf5ef2aSThomas Huth     } else { /* r == 1 */
127fcf5ef2aSThomas Huth         switch (rmc & 3) {
128fcf5ef2aSThomas Huth         case 0:
129fcf5ef2aSThomas Huth             rnd = DEC_ROUND_CEILING;
130fcf5ef2aSThomas Huth             break;
131fcf5ef2aSThomas Huth         case 1:
132fcf5ef2aSThomas Huth             rnd = DEC_ROUND_FLOOR;
133fcf5ef2aSThomas Huth             break;
134fcf5ef2aSThomas Huth         case 2:
135fcf5ef2aSThomas Huth             rnd = DEC_ROUND_UP;
136fcf5ef2aSThomas Huth             break;
137fcf5ef2aSThomas Huth         case 3:
138fcf5ef2aSThomas Huth             rnd = DEC_ROUND_HALF_DOWN;
139fcf5ef2aSThomas Huth             break;
140fcf5ef2aSThomas Huth         default:
141a1a65aadSPierrick Bouvier             g_assert_not_reached();
142fcf5ef2aSThomas Huth         }
143fcf5ef2aSThomas Huth     }
144fcf5ef2aSThomas Huth     decContextSetRounding(&dfp->context, rnd);
145fcf5ef2aSThomas Huth }
146fcf5ef2aSThomas Huth 
dfp_prepare_decimal64(struct PPC_DFP * dfp,ppc_fprp_t * a,ppc_fprp_t * b,CPUPPCState * env)147d9acba31SMark Cave-Ayland static void dfp_prepare_decimal64(struct PPC_DFP *dfp, ppc_fprp_t *a,
148d9acba31SMark Cave-Ayland                                   ppc_fprp_t *b, CPUPPCState *env)
149fcf5ef2aSThomas Huth {
150fcf5ef2aSThomas Huth     decContextDefault(&dfp->context, DEC_INIT_DECIMAL64);
151fcf5ef2aSThomas Huth     dfp_prepare_rounding_mode(&dfp->context, env->fpscr);
152fcf5ef2aSThomas Huth     dfp->env = env;
153fcf5ef2aSThomas Huth 
154fcf5ef2aSThomas Huth     if (a) {
15564b8574eSMark Cave-Ayland         get_dfp64(&dfp->va, a);
15664b8574eSMark Cave-Ayland         decimal64ToNumber((decimal64 *)&dfp->va.VsrD(1), &dfp->a);
157fcf5ef2aSThomas Huth     } else {
15864b8574eSMark Cave-Ayland         dfp->va.VsrD(1) = 0;
159fcf5ef2aSThomas Huth         decNumberZero(&dfp->a);
160fcf5ef2aSThomas Huth     }
161fcf5ef2aSThomas Huth 
162fcf5ef2aSThomas Huth     if (b) {
16364b8574eSMark Cave-Ayland         get_dfp64(&dfp->vb, b);
16464b8574eSMark Cave-Ayland         decimal64ToNumber((decimal64 *)&dfp->vb.VsrD(1), &dfp->b);
165fcf5ef2aSThomas Huth     } else {
16664b8574eSMark Cave-Ayland         dfp->vb.VsrD(1) = 0;
167fcf5ef2aSThomas Huth         decNumberZero(&dfp->b);
168fcf5ef2aSThomas Huth     }
169fcf5ef2aSThomas Huth }
170fcf5ef2aSThomas Huth 
dfp_prepare_decimal128(struct PPC_DFP * dfp,ppc_fprp_t * a,ppc_fprp_t * b,CPUPPCState * env)171d9acba31SMark Cave-Ayland static void dfp_prepare_decimal128(struct PPC_DFP *dfp, ppc_fprp_t *a,
172d9acba31SMark Cave-Ayland                                    ppc_fprp_t *b, CPUPPCState *env)
173fcf5ef2aSThomas Huth {
174fcf5ef2aSThomas Huth     decContextDefault(&dfp->context, DEC_INIT_DECIMAL128);
175fcf5ef2aSThomas Huth     dfp_prepare_rounding_mode(&dfp->context, env->fpscr);
176fcf5ef2aSThomas Huth     dfp->env = env;
177fcf5ef2aSThomas Huth 
178fcf5ef2aSThomas Huth     if (a) {
17964b8574eSMark Cave-Ayland         get_dfp128(&dfp->va, a);
18064b8574eSMark Cave-Ayland         decimal128ToNumber((decimal128 *)&dfp->va, &dfp->a);
181fcf5ef2aSThomas Huth     } else {
18264b8574eSMark Cave-Ayland         dfp->va.VsrD(0) = dfp->va.VsrD(1) = 0;
183fcf5ef2aSThomas Huth         decNumberZero(&dfp->a);
184fcf5ef2aSThomas Huth     }
185fcf5ef2aSThomas Huth 
186fcf5ef2aSThomas Huth     if (b) {
18764b8574eSMark Cave-Ayland         get_dfp128(&dfp->vb, b);
18864b8574eSMark Cave-Ayland         decimal128ToNumber((decimal128 *)&dfp->vb, &dfp->b);
189fcf5ef2aSThomas Huth     } else {
19064b8574eSMark Cave-Ayland         dfp->vb.VsrD(0) = dfp->vb.VsrD(1) = 0;
191fcf5ef2aSThomas Huth         decNumberZero(&dfp->b);
192fcf5ef2aSThomas Huth     }
193fcf5ef2aSThomas Huth }
194fcf5ef2aSThomas Huth 
dfp_finalize_decimal64(struct PPC_DFP * dfp)195474c2e93SMark Cave-Ayland static void dfp_finalize_decimal64(struct PPC_DFP *dfp)
196474c2e93SMark Cave-Ayland {
19764b8574eSMark Cave-Ayland     decimal64FromNumber((decimal64 *)&dfp->vt.VsrD(1), &dfp->t, &dfp->context);
198474c2e93SMark Cave-Ayland }
199474c2e93SMark Cave-Ayland 
dfp_finalize_decimal128(struct PPC_DFP * dfp)200474c2e93SMark Cave-Ayland static void dfp_finalize_decimal128(struct PPC_DFP *dfp)
201474c2e93SMark Cave-Ayland {
20264b8574eSMark Cave-Ayland     decimal128FromNumber((decimal128 *)&dfp->vt, &dfp->t, &dfp->context);
203474c2e93SMark Cave-Ayland }
204474c2e93SMark Cave-Ayland 
dfp_set_FPSCR_flag(struct PPC_DFP * dfp,uint64_t flag,uint64_t enabled)205fcf5ef2aSThomas Huth static void dfp_set_FPSCR_flag(struct PPC_DFP *dfp, uint64_t flag,
206fcf5ef2aSThomas Huth                 uint64_t enabled)
207fcf5ef2aSThomas Huth {
208fcf5ef2aSThomas Huth     dfp->env->fpscr |= (flag | FP_FX);
209fcf5ef2aSThomas Huth     if (dfp->env->fpscr & enabled) {
210fcf5ef2aSThomas Huth         dfp->env->fpscr |= FP_FEX;
211fcf5ef2aSThomas Huth     }
212fcf5ef2aSThomas Huth }
213fcf5ef2aSThomas Huth 
dfp_set_FPRF_from_FRT_with_context(struct PPC_DFP * dfp,decContext * context)214fcf5ef2aSThomas Huth static void dfp_set_FPRF_from_FRT_with_context(struct PPC_DFP *dfp,
215fcf5ef2aSThomas Huth                 decContext *context)
216fcf5ef2aSThomas Huth {
217fcf5ef2aSThomas Huth     uint64_t fprf = 0;
218fcf5ef2aSThomas Huth 
219fcf5ef2aSThomas Huth     /* construct FPRF */
220fcf5ef2aSThomas Huth     switch (decNumberClass(&dfp->t, context)) {
221fcf5ef2aSThomas Huth     case DEC_CLASS_SNAN:
222fcf5ef2aSThomas Huth         fprf = 0x01;
223fcf5ef2aSThomas Huth         break;
224fcf5ef2aSThomas Huth     case DEC_CLASS_QNAN:
225fcf5ef2aSThomas Huth         fprf = 0x11;
226fcf5ef2aSThomas Huth         break;
227fcf5ef2aSThomas Huth     case DEC_CLASS_NEG_INF:
228fcf5ef2aSThomas Huth         fprf = 0x09;
229fcf5ef2aSThomas Huth         break;
230fcf5ef2aSThomas Huth     case DEC_CLASS_NEG_NORMAL:
231fcf5ef2aSThomas Huth         fprf = 0x08;
232fcf5ef2aSThomas Huth         break;
233fcf5ef2aSThomas Huth     case DEC_CLASS_NEG_SUBNORMAL:
234fcf5ef2aSThomas Huth         fprf = 0x18;
235fcf5ef2aSThomas Huth         break;
236fcf5ef2aSThomas Huth     case DEC_CLASS_NEG_ZERO:
237fcf5ef2aSThomas Huth         fprf = 0x12;
238fcf5ef2aSThomas Huth         break;
239fcf5ef2aSThomas Huth     case DEC_CLASS_POS_ZERO:
240fcf5ef2aSThomas Huth         fprf = 0x02;
241fcf5ef2aSThomas Huth         break;
242fcf5ef2aSThomas Huth     case DEC_CLASS_POS_SUBNORMAL:
243fcf5ef2aSThomas Huth         fprf = 0x14;
244fcf5ef2aSThomas Huth         break;
245fcf5ef2aSThomas Huth     case DEC_CLASS_POS_NORMAL:
246fcf5ef2aSThomas Huth         fprf = 0x04;
247fcf5ef2aSThomas Huth         break;
248fcf5ef2aSThomas Huth     case DEC_CLASS_POS_INF:
249fcf5ef2aSThomas Huth         fprf = 0x05;
250fcf5ef2aSThomas Huth         break;
251fcf5ef2aSThomas Huth     default:
252*52d9ffd8SPierrick Bouvier         g_assert_not_reached();
253fcf5ef2aSThomas Huth     }
2545c94dd38SPaul A. Clarke     dfp->env->fpscr &= ~FP_FPRF;
2555c94dd38SPaul A. Clarke     dfp->env->fpscr |= (fprf << FPSCR_FPRF);
256fcf5ef2aSThomas Huth }
257fcf5ef2aSThomas Huth 
dfp_set_FPRF_from_FRT(struct PPC_DFP * dfp)258fcf5ef2aSThomas Huth static void dfp_set_FPRF_from_FRT(struct PPC_DFP *dfp)
259fcf5ef2aSThomas Huth {
260fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT_with_context(dfp, &dfp->context);
261fcf5ef2aSThomas Huth }
262fcf5ef2aSThomas Huth 
dfp_set_FPRF_from_FRT_short(struct PPC_DFP * dfp)263fcf5ef2aSThomas Huth static void dfp_set_FPRF_from_FRT_short(struct PPC_DFP *dfp)
264fcf5ef2aSThomas Huth {
265fcf5ef2aSThomas Huth     decContext shortContext;
266fcf5ef2aSThomas Huth     decContextDefault(&shortContext, DEC_INIT_DECIMAL32);
267fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT_with_context(dfp, &shortContext);
268fcf5ef2aSThomas Huth }
269fcf5ef2aSThomas Huth 
dfp_set_FPRF_from_FRT_long(struct PPC_DFP * dfp)270fcf5ef2aSThomas Huth static void dfp_set_FPRF_from_FRT_long(struct PPC_DFP *dfp)
271fcf5ef2aSThomas Huth {
272fcf5ef2aSThomas Huth     decContext longContext;
273fcf5ef2aSThomas Huth     decContextDefault(&longContext, DEC_INIT_DECIMAL64);
274fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT_with_context(dfp, &longContext);
275fcf5ef2aSThomas Huth }
276fcf5ef2aSThomas Huth 
dfp_check_for_OX(struct PPC_DFP * dfp)277fcf5ef2aSThomas Huth static void dfp_check_for_OX(struct PPC_DFP *dfp)
278fcf5ef2aSThomas Huth {
279fcf5ef2aSThomas Huth     if (dfp->context.status & DEC_Overflow) {
280fcf5ef2aSThomas Huth         dfp_set_FPSCR_flag(dfp, FP_OX, FP_OE);
281fcf5ef2aSThomas Huth     }
282fcf5ef2aSThomas Huth }
283fcf5ef2aSThomas Huth 
dfp_check_for_UX(struct PPC_DFP * dfp)284fcf5ef2aSThomas Huth static void dfp_check_for_UX(struct PPC_DFP *dfp)
285fcf5ef2aSThomas Huth {
286fcf5ef2aSThomas Huth     if (dfp->context.status & DEC_Underflow) {
287fcf5ef2aSThomas Huth         dfp_set_FPSCR_flag(dfp, FP_UX, FP_UE);
288fcf5ef2aSThomas Huth     }
289fcf5ef2aSThomas Huth }
290fcf5ef2aSThomas Huth 
dfp_check_for_XX(struct PPC_DFP * dfp)291fcf5ef2aSThomas Huth static void dfp_check_for_XX(struct PPC_DFP *dfp)
292fcf5ef2aSThomas Huth {
293fcf5ef2aSThomas Huth     if (dfp->context.status & DEC_Inexact) {
294fcf5ef2aSThomas Huth         dfp_set_FPSCR_flag(dfp, FP_XX | FP_FI, FP_XE);
295fcf5ef2aSThomas Huth     }
296fcf5ef2aSThomas Huth }
297fcf5ef2aSThomas Huth 
dfp_check_for_ZX(struct PPC_DFP * dfp)298fcf5ef2aSThomas Huth static void dfp_check_for_ZX(struct PPC_DFP *dfp)
299fcf5ef2aSThomas Huth {
300fcf5ef2aSThomas Huth     if (dfp->context.status & DEC_Division_by_zero) {
301fcf5ef2aSThomas Huth         dfp_set_FPSCR_flag(dfp, FP_ZX, FP_ZE);
302fcf5ef2aSThomas Huth     }
303fcf5ef2aSThomas Huth }
304fcf5ef2aSThomas Huth 
dfp_check_for_VXSNAN(struct PPC_DFP * dfp)305fcf5ef2aSThomas Huth static void dfp_check_for_VXSNAN(struct PPC_DFP *dfp)
306fcf5ef2aSThomas Huth {
307fcf5ef2aSThomas Huth     if (dfp->context.status & DEC_Invalid_operation) {
308fcf5ef2aSThomas Huth         if (decNumberIsSNaN(&dfp->a) || decNumberIsSNaN(&dfp->b)) {
309fcf5ef2aSThomas Huth             dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXSNAN, FP_VE);
310fcf5ef2aSThomas Huth         }
311fcf5ef2aSThomas Huth     }
312fcf5ef2aSThomas Huth }
313fcf5ef2aSThomas Huth 
dfp_check_for_VXSNAN_and_convert_to_QNaN(struct PPC_DFP * dfp)314fcf5ef2aSThomas Huth static void dfp_check_for_VXSNAN_and_convert_to_QNaN(struct PPC_DFP *dfp)
315fcf5ef2aSThomas Huth {
316fcf5ef2aSThomas Huth     if (decNumberIsSNaN(&dfp->t)) {
317fcf5ef2aSThomas Huth         dfp->t.bits &= ~DECSNAN;
318fcf5ef2aSThomas Huth         dfp->t.bits |= DECNAN;
319fcf5ef2aSThomas Huth         dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXSNAN, FP_VE);
320fcf5ef2aSThomas Huth     }
321fcf5ef2aSThomas Huth }
322fcf5ef2aSThomas Huth 
dfp_check_for_VXISI(struct PPC_DFP * dfp,int testForSameSign)323fcf5ef2aSThomas Huth static void dfp_check_for_VXISI(struct PPC_DFP *dfp, int testForSameSign)
324fcf5ef2aSThomas Huth {
325fcf5ef2aSThomas Huth     if (dfp->context.status & DEC_Invalid_operation) {
326fcf5ef2aSThomas Huth         if (decNumberIsInfinite(&dfp->a) && decNumberIsInfinite(&dfp->b)) {
327fcf5ef2aSThomas Huth             int same = decNumberClass(&dfp->a, &dfp->context) ==
328fcf5ef2aSThomas Huth                        decNumberClass(&dfp->b, &dfp->context);
329fcf5ef2aSThomas Huth             if ((same && testForSameSign) || (!same && !testForSameSign)) {
330fcf5ef2aSThomas Huth                 dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXISI, FP_VE);
331fcf5ef2aSThomas Huth             }
332fcf5ef2aSThomas Huth         }
333fcf5ef2aSThomas Huth     }
334fcf5ef2aSThomas Huth }
335fcf5ef2aSThomas Huth 
dfp_check_for_VXISI_add(struct PPC_DFP * dfp)336fcf5ef2aSThomas Huth static void dfp_check_for_VXISI_add(struct PPC_DFP *dfp)
337fcf5ef2aSThomas Huth {
338fcf5ef2aSThomas Huth     dfp_check_for_VXISI(dfp, 0);
339fcf5ef2aSThomas Huth }
340fcf5ef2aSThomas Huth 
dfp_check_for_VXISI_subtract(struct PPC_DFP * dfp)341fcf5ef2aSThomas Huth static void dfp_check_for_VXISI_subtract(struct PPC_DFP *dfp)
342fcf5ef2aSThomas Huth {
343fcf5ef2aSThomas Huth     dfp_check_for_VXISI(dfp, 1);
344fcf5ef2aSThomas Huth }
345fcf5ef2aSThomas Huth 
dfp_check_for_VXIMZ(struct PPC_DFP * dfp)346fcf5ef2aSThomas Huth static void dfp_check_for_VXIMZ(struct PPC_DFP *dfp)
347fcf5ef2aSThomas Huth {
348fcf5ef2aSThomas Huth     if (dfp->context.status & DEC_Invalid_operation) {
349fcf5ef2aSThomas Huth         if ((decNumberIsInfinite(&dfp->a) && decNumberIsZero(&dfp->b)) ||
350fcf5ef2aSThomas Huth             (decNumberIsInfinite(&dfp->b) && decNumberIsZero(&dfp->a))) {
351fcf5ef2aSThomas Huth             dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXIMZ, FP_VE);
352fcf5ef2aSThomas Huth         }
353fcf5ef2aSThomas Huth     }
354fcf5ef2aSThomas Huth }
355fcf5ef2aSThomas Huth 
dfp_check_for_VXZDZ(struct PPC_DFP * dfp)356fcf5ef2aSThomas Huth static void dfp_check_for_VXZDZ(struct PPC_DFP *dfp)
357fcf5ef2aSThomas Huth {
358fcf5ef2aSThomas Huth     if (dfp->context.status & DEC_Division_undefined) {
359fcf5ef2aSThomas Huth         dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXZDZ, FP_VE);
360fcf5ef2aSThomas Huth     }
361fcf5ef2aSThomas Huth }
362fcf5ef2aSThomas Huth 
dfp_check_for_VXIDI(struct PPC_DFP * dfp)363fcf5ef2aSThomas Huth static void dfp_check_for_VXIDI(struct PPC_DFP *dfp)
364fcf5ef2aSThomas Huth {
365fcf5ef2aSThomas Huth     if (dfp->context.status & DEC_Invalid_operation) {
366fcf5ef2aSThomas Huth         if (decNumberIsInfinite(&dfp->a) && decNumberIsInfinite(&dfp->b)) {
367fcf5ef2aSThomas Huth             dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXIDI, FP_VE);
368fcf5ef2aSThomas Huth         }
369fcf5ef2aSThomas Huth     }
370fcf5ef2aSThomas Huth }
371fcf5ef2aSThomas Huth 
dfp_check_for_VXVC(struct PPC_DFP * dfp)372fcf5ef2aSThomas Huth static void dfp_check_for_VXVC(struct PPC_DFP *dfp)
373fcf5ef2aSThomas Huth {
374fcf5ef2aSThomas Huth     if (decNumberIsNaN(&dfp->a) || decNumberIsNaN(&dfp->b)) {
375fcf5ef2aSThomas Huth         dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXVC, FP_VE);
376fcf5ef2aSThomas Huth     }
377fcf5ef2aSThomas Huth }
378fcf5ef2aSThomas Huth 
dfp_check_for_VXCVI(struct PPC_DFP * dfp)379fcf5ef2aSThomas Huth static void dfp_check_for_VXCVI(struct PPC_DFP *dfp)
380fcf5ef2aSThomas Huth {
381fcf5ef2aSThomas Huth     if ((dfp->context.status & DEC_Invalid_operation) &&
382fcf5ef2aSThomas Huth         (!decNumberIsSNaN(&dfp->a)) &&
383fcf5ef2aSThomas Huth         (!decNumberIsSNaN(&dfp->b))) {
384fcf5ef2aSThomas Huth         dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXCVI, FP_VE);
385fcf5ef2aSThomas Huth     }
386fcf5ef2aSThomas Huth }
387fcf5ef2aSThomas Huth 
dfp_set_CRBF_from_T(struct PPC_DFP * dfp)388fcf5ef2aSThomas Huth static void dfp_set_CRBF_from_T(struct PPC_DFP *dfp)
389fcf5ef2aSThomas Huth {
390fcf5ef2aSThomas Huth     if (decNumberIsNaN(&dfp->t)) {
391fcf5ef2aSThomas Huth         dfp->crbf = 1;
392fcf5ef2aSThomas Huth     } else if (decNumberIsZero(&dfp->t)) {
393fcf5ef2aSThomas Huth         dfp->crbf = 2;
394fcf5ef2aSThomas Huth     } else if (decNumberIsNegative(&dfp->t)) {
395fcf5ef2aSThomas Huth         dfp->crbf = 8;
396fcf5ef2aSThomas Huth     } else {
397fcf5ef2aSThomas Huth         dfp->crbf = 4;
398fcf5ef2aSThomas Huth     }
399fcf5ef2aSThomas Huth }
400fcf5ef2aSThomas Huth 
dfp_set_FPCC_from_CRBF(struct PPC_DFP * dfp)401fcf5ef2aSThomas Huth static void dfp_set_FPCC_from_CRBF(struct PPC_DFP *dfp)
402fcf5ef2aSThomas Huth {
4035c94dd38SPaul A. Clarke     dfp->env->fpscr &= ~FP_FPCC;
4045c94dd38SPaul A. Clarke     dfp->env->fpscr |= (dfp->crbf << FPSCR_FPCC);
405fcf5ef2aSThomas Huth }
406fcf5ef2aSThomas Huth 
dfp_makeQNaN(decNumber * dn)407fcf5ef2aSThomas Huth static inline void dfp_makeQNaN(decNumber *dn)
408fcf5ef2aSThomas Huth {
409fcf5ef2aSThomas Huth     dn->bits &= ~DECSPECIAL;
410fcf5ef2aSThomas Huth     dn->bits |= DECNAN;
411fcf5ef2aSThomas Huth }
412fcf5ef2aSThomas Huth 
dfp_get_digit(decNumber * dn,int n)413fcf5ef2aSThomas Huth static inline int dfp_get_digit(decNumber *dn, int n)
414fcf5ef2aSThomas Huth {
415fcf5ef2aSThomas Huth     assert(DECDPUN == 3);
416fcf5ef2aSThomas Huth     int unit = n / DECDPUN;
417fcf5ef2aSThomas Huth     int dig = n % DECDPUN;
418fcf5ef2aSThomas Huth     switch (dig) {
419fcf5ef2aSThomas Huth     case 0:
420fcf5ef2aSThomas Huth         return dn->lsu[unit] % 10;
421fcf5ef2aSThomas Huth     case 1:
422fcf5ef2aSThomas Huth         return (dn->lsu[unit] / 10) % 10;
423fcf5ef2aSThomas Huth     case 2:
424fcf5ef2aSThomas Huth         return dn->lsu[unit] / 100;
425fcf5ef2aSThomas Huth     }
426fcf5ef2aSThomas Huth     g_assert_not_reached();
427fcf5ef2aSThomas Huth }
428fcf5ef2aSThomas Huth 
429fcf5ef2aSThomas Huth #define DFP_HELPER_TAB(op, dnop, postprocs, size)                              \
430d9acba31SMark Cave-Ayland void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a,               \
431d9acba31SMark Cave-Ayland                  ppc_fprp_t *b)                                                \
432fcf5ef2aSThomas Huth {                                                                              \
433fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                        \
434fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, a, b, env);                                \
435fcf5ef2aSThomas Huth     dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context);                                \
436474c2e93SMark Cave-Ayland     dfp_finalize_decimal##size(&dfp);                                          \
437fcf5ef2aSThomas Huth     postprocs(&dfp);                                                           \
438f6d4c423SMark Cave-Ayland     set_dfp##size(t, &dfp.vt);                                                 \
439fcf5ef2aSThomas Huth }
440fcf5ef2aSThomas Huth 
ADD_PPs(struct PPC_DFP * dfp)441fcf5ef2aSThomas Huth static void ADD_PPs(struct PPC_DFP *dfp)
442fcf5ef2aSThomas Huth {
443fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT(dfp);
444fcf5ef2aSThomas Huth     dfp_check_for_OX(dfp);
445fcf5ef2aSThomas Huth     dfp_check_for_UX(dfp);
446fcf5ef2aSThomas Huth     dfp_check_for_XX(dfp);
447fcf5ef2aSThomas Huth     dfp_check_for_VXSNAN(dfp);
448fcf5ef2aSThomas Huth     dfp_check_for_VXISI_add(dfp);
449fcf5ef2aSThomas Huth }
450fcf5ef2aSThomas Huth 
451afdc9310SLuis Pires DFP_HELPER_TAB(DADD, decNumberAdd, ADD_PPs, 64)
452afdc9310SLuis Pires DFP_HELPER_TAB(DADDQ, decNumberAdd, ADD_PPs, 128)
453fcf5ef2aSThomas Huth 
SUB_PPs(struct PPC_DFP * dfp)454fcf5ef2aSThomas Huth static void SUB_PPs(struct PPC_DFP *dfp)
455fcf5ef2aSThomas Huth {
456fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT(dfp);
457fcf5ef2aSThomas Huth     dfp_check_for_OX(dfp);
458fcf5ef2aSThomas Huth     dfp_check_for_UX(dfp);
459fcf5ef2aSThomas Huth     dfp_check_for_XX(dfp);
460fcf5ef2aSThomas Huth     dfp_check_for_VXSNAN(dfp);
461fcf5ef2aSThomas Huth     dfp_check_for_VXISI_subtract(dfp);
462fcf5ef2aSThomas Huth }
463fcf5ef2aSThomas Huth 
464afdc9310SLuis Pires DFP_HELPER_TAB(DSUB, decNumberSubtract, SUB_PPs, 64)
465afdc9310SLuis Pires DFP_HELPER_TAB(DSUBQ, decNumberSubtract, SUB_PPs, 128)
466fcf5ef2aSThomas Huth 
MUL_PPs(struct PPC_DFP * dfp)467fcf5ef2aSThomas Huth static void MUL_PPs(struct PPC_DFP *dfp)
468fcf5ef2aSThomas Huth {
469fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT(dfp);
470fcf5ef2aSThomas Huth     dfp_check_for_OX(dfp);
471fcf5ef2aSThomas Huth     dfp_check_for_UX(dfp);
472fcf5ef2aSThomas Huth     dfp_check_for_XX(dfp);
473fcf5ef2aSThomas Huth     dfp_check_for_VXSNAN(dfp);
474fcf5ef2aSThomas Huth     dfp_check_for_VXIMZ(dfp);
475fcf5ef2aSThomas Huth }
476fcf5ef2aSThomas Huth 
477afdc9310SLuis Pires DFP_HELPER_TAB(DMUL, decNumberMultiply, MUL_PPs, 64)
478afdc9310SLuis Pires DFP_HELPER_TAB(DMULQ, decNumberMultiply, MUL_PPs, 128)
479fcf5ef2aSThomas Huth 
DIV_PPs(struct PPC_DFP * dfp)480fcf5ef2aSThomas Huth static void DIV_PPs(struct PPC_DFP *dfp)
481fcf5ef2aSThomas Huth {
482fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT(dfp);
483fcf5ef2aSThomas Huth     dfp_check_for_OX(dfp);
484fcf5ef2aSThomas Huth     dfp_check_for_UX(dfp);
485fcf5ef2aSThomas Huth     dfp_check_for_ZX(dfp);
486fcf5ef2aSThomas Huth     dfp_check_for_XX(dfp);
487fcf5ef2aSThomas Huth     dfp_check_for_VXSNAN(dfp);
488fcf5ef2aSThomas Huth     dfp_check_for_VXZDZ(dfp);
489fcf5ef2aSThomas Huth     dfp_check_for_VXIDI(dfp);
490fcf5ef2aSThomas Huth }
491fcf5ef2aSThomas Huth 
492afdc9310SLuis Pires DFP_HELPER_TAB(DDIV, decNumberDivide, DIV_PPs, 64)
493afdc9310SLuis Pires DFP_HELPER_TAB(DDIVQ, decNumberDivide, DIV_PPs, 128)
494fcf5ef2aSThomas Huth 
495fcf5ef2aSThomas Huth #define DFP_HELPER_BF_AB(op, dnop, postprocs, size)                            \
496d9acba31SMark Cave-Ayland uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b)           \
497fcf5ef2aSThomas Huth {                                                                              \
498fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                        \
499fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, a, b, env);                                \
500fcf5ef2aSThomas Huth     dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context);                                \
501474c2e93SMark Cave-Ayland     dfp_finalize_decimal##size(&dfp);                                          \
502fcf5ef2aSThomas Huth     postprocs(&dfp);                                                           \
503fcf5ef2aSThomas Huth     return dfp.crbf;                                                           \
504fcf5ef2aSThomas Huth }
505fcf5ef2aSThomas Huth 
CMPU_PPs(struct PPC_DFP * dfp)506fcf5ef2aSThomas Huth static void CMPU_PPs(struct PPC_DFP *dfp)
507fcf5ef2aSThomas Huth {
508fcf5ef2aSThomas Huth     dfp_set_CRBF_from_T(dfp);
509fcf5ef2aSThomas Huth     dfp_set_FPCC_from_CRBF(dfp);
510fcf5ef2aSThomas Huth     dfp_check_for_VXSNAN(dfp);
511fcf5ef2aSThomas Huth }
512fcf5ef2aSThomas Huth 
51385c38a46SLuis Pires DFP_HELPER_BF_AB(DCMPU, decNumberCompare, CMPU_PPs, 64)
51485c38a46SLuis Pires DFP_HELPER_BF_AB(DCMPUQ, decNumberCompare, CMPU_PPs, 128)
515fcf5ef2aSThomas Huth 
CMPO_PPs(struct PPC_DFP * dfp)516fcf5ef2aSThomas Huth static void CMPO_PPs(struct PPC_DFP *dfp)
517fcf5ef2aSThomas Huth {
518fcf5ef2aSThomas Huth     dfp_set_CRBF_from_T(dfp);
519fcf5ef2aSThomas Huth     dfp_set_FPCC_from_CRBF(dfp);
520fcf5ef2aSThomas Huth     dfp_check_for_VXSNAN(dfp);
521fcf5ef2aSThomas Huth     dfp_check_for_VXVC(dfp);
522fcf5ef2aSThomas Huth }
523fcf5ef2aSThomas Huth 
52485c38a46SLuis Pires DFP_HELPER_BF_AB(DCMPO, decNumberCompare, CMPO_PPs, 64)
52585c38a46SLuis Pires DFP_HELPER_BF_AB(DCMPOQ, decNumberCompare, CMPO_PPs, 128)
526fcf5ef2aSThomas Huth 
527fcf5ef2aSThomas Huth #define DFP_HELPER_TSTDC(op, size)                                       \
528d9acba31SMark Cave-Ayland uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, uint32_t dcm)      \
529fcf5ef2aSThomas Huth {                                                                        \
530fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                  \
531fcf5ef2aSThomas Huth     int match = 0;                                                       \
532fcf5ef2aSThomas Huth                                                                          \
533fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, a, 0, env);                          \
534fcf5ef2aSThomas Huth                                                                          \
535fcf5ef2aSThomas Huth     match |= (dcm & 0x20) && decNumberIsZero(&dfp.a);                    \
536fcf5ef2aSThomas Huth     match |= (dcm & 0x10) && decNumberIsSubnormal(&dfp.a, &dfp.context); \
537fcf5ef2aSThomas Huth     match |= (dcm & 0x08) && decNumberIsNormal(&dfp.a, &dfp.context);    \
538fcf5ef2aSThomas Huth     match |= (dcm & 0x04) && decNumberIsInfinite(&dfp.a);                \
539fcf5ef2aSThomas Huth     match |= (dcm & 0x02) && decNumberIsQNaN(&dfp.a);                    \
540fcf5ef2aSThomas Huth     match |= (dcm & 0x01) && decNumberIsSNaN(&dfp.a);                    \
541fcf5ef2aSThomas Huth                                                                          \
542fcf5ef2aSThomas Huth     if (decNumberIsNegative(&dfp.a)) {                                   \
543fcf5ef2aSThomas Huth         dfp.crbf = match ? 0xA : 0x8;                                    \
544fcf5ef2aSThomas Huth     } else {                                                             \
545fcf5ef2aSThomas Huth         dfp.crbf = match ? 0x2 : 0x0;                                    \
546fcf5ef2aSThomas Huth     }                                                                    \
547fcf5ef2aSThomas Huth                                                                          \
548fcf5ef2aSThomas Huth     dfp_set_FPCC_from_CRBF(&dfp);                                        \
549fcf5ef2aSThomas Huth     return dfp.crbf;                                                     \
550fcf5ef2aSThomas Huth }
551fcf5ef2aSThomas Huth 
55287bc8e52SLuis Pires DFP_HELPER_TSTDC(DTSTDC, 64)
55387bc8e52SLuis Pires DFP_HELPER_TSTDC(DTSTDCQ, 128)
554fcf5ef2aSThomas Huth 
555fcf5ef2aSThomas Huth #define DFP_HELPER_TSTDG(op, size)                                       \
556d9acba31SMark Cave-Ayland uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, uint32_t dcm)      \
557fcf5ef2aSThomas Huth {                                                                        \
558fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                  \
559fcf5ef2aSThomas Huth     int minexp, maxexp, nzero_digits, nzero_idx, is_negative, is_zero,   \
560fcf5ef2aSThomas Huth         is_extreme_exp, is_subnormal, is_normal, leftmost_is_nonzero,    \
561fcf5ef2aSThomas Huth         match;                                                           \
562fcf5ef2aSThomas Huth                                                                          \
563fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, a, 0, env);                          \
564fcf5ef2aSThomas Huth                                                                          \
565fcf5ef2aSThomas Huth     if ((size) == 64) {                                                  \
566fcf5ef2aSThomas Huth         minexp = -398;                                                   \
567fcf5ef2aSThomas Huth         maxexp = 369;                                                    \
568fcf5ef2aSThomas Huth         nzero_digits = 16;                                               \
569fcf5ef2aSThomas Huth         nzero_idx = 5;                                                   \
570fcf5ef2aSThomas Huth     } else if ((size) == 128) {                                          \
571fcf5ef2aSThomas Huth         minexp = -6176;                                                  \
572fcf5ef2aSThomas Huth         maxexp = 6111;                                                   \
573fcf5ef2aSThomas Huth         nzero_digits = 34;                                               \
574fcf5ef2aSThomas Huth         nzero_idx = 11;                                                  \
575fcf5ef2aSThomas Huth     }                                                                    \
576fcf5ef2aSThomas Huth                                                                          \
577fcf5ef2aSThomas Huth     is_negative = decNumberIsNegative(&dfp.a);                           \
578fcf5ef2aSThomas Huth     is_zero = decNumberIsZero(&dfp.a);                                   \
579fcf5ef2aSThomas Huth     is_extreme_exp = (dfp.a.exponent == maxexp) ||                       \
580fcf5ef2aSThomas Huth                      (dfp.a.exponent == minexp);                         \
581fcf5ef2aSThomas Huth     is_subnormal = decNumberIsSubnormal(&dfp.a, &dfp.context);           \
582fcf5ef2aSThomas Huth     is_normal = decNumberIsNormal(&dfp.a, &dfp.context);                 \
583fcf5ef2aSThomas Huth     leftmost_is_nonzero = (dfp.a.digits == nzero_digits) &&              \
584fcf5ef2aSThomas Huth                           (dfp.a.lsu[nzero_idx] != 0);                   \
585fcf5ef2aSThomas Huth     match = 0;                                                           \
586fcf5ef2aSThomas Huth                                                                          \
587fcf5ef2aSThomas Huth     match |= (dcm & 0x20) && is_zero && !is_extreme_exp;                 \
588fcf5ef2aSThomas Huth     match |= (dcm & 0x10) && is_zero && is_extreme_exp;                  \
589fcf5ef2aSThomas Huth     match |= (dcm & 0x08) &&                                             \
590fcf5ef2aSThomas Huth              (is_subnormal || (is_normal && is_extreme_exp));            \
591fcf5ef2aSThomas Huth     match |= (dcm & 0x04) && is_normal && !is_extreme_exp &&             \
592fcf5ef2aSThomas Huth              !leftmost_is_nonzero;                                       \
593fcf5ef2aSThomas Huth     match |= (dcm & 0x02) && is_normal && !is_extreme_exp &&             \
594fcf5ef2aSThomas Huth              leftmost_is_nonzero;                                        \
595fcf5ef2aSThomas Huth     match |= (dcm & 0x01) && decNumberIsSpecial(&dfp.a);                 \
596fcf5ef2aSThomas Huth                                                                          \
597fcf5ef2aSThomas Huth     if (is_negative) {                                                   \
598fcf5ef2aSThomas Huth         dfp.crbf = match ? 0xA : 0x8;                                    \
599fcf5ef2aSThomas Huth     } else {                                                             \
600fcf5ef2aSThomas Huth         dfp.crbf = match ? 0x2 : 0x0;                                    \
601fcf5ef2aSThomas Huth     }                                                                    \
602fcf5ef2aSThomas Huth                                                                          \
603fcf5ef2aSThomas Huth     dfp_set_FPCC_from_CRBF(&dfp);                                        \
604fcf5ef2aSThomas Huth     return dfp.crbf;                                                     \
605fcf5ef2aSThomas Huth }
606fcf5ef2aSThomas Huth 
60787bc8e52SLuis Pires DFP_HELPER_TSTDG(DTSTDG, 64)
60887bc8e52SLuis Pires DFP_HELPER_TSTDG(DTSTDGQ, 128)
609fcf5ef2aSThomas Huth 
610fcf5ef2aSThomas Huth #define DFP_HELPER_TSTEX(op, size)                                       \
611d9acba31SMark Cave-Ayland uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b)     \
612fcf5ef2aSThomas Huth {                                                                        \
613fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                  \
614fcf5ef2aSThomas Huth     int expa, expb, a_is_special, b_is_special;                          \
615fcf5ef2aSThomas Huth                                                                          \
616fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, a, b, env);                          \
617fcf5ef2aSThomas Huth                                                                          \
618fcf5ef2aSThomas Huth     expa = dfp.a.exponent;                                               \
619fcf5ef2aSThomas Huth     expb = dfp.b.exponent;                                               \
620fcf5ef2aSThomas Huth     a_is_special = decNumberIsSpecial(&dfp.a);                           \
621fcf5ef2aSThomas Huth     b_is_special = decNumberIsSpecial(&dfp.b);                           \
622fcf5ef2aSThomas Huth                                                                          \
623fcf5ef2aSThomas Huth     if (a_is_special || b_is_special) {                                  \
624fcf5ef2aSThomas Huth         int atype = a_is_special ? (decNumberIsNaN(&dfp.a) ? 4 : 2) : 1; \
625fcf5ef2aSThomas Huth         int btype = b_is_special ? (decNumberIsNaN(&dfp.b) ? 4 : 2) : 1; \
626fcf5ef2aSThomas Huth         dfp.crbf = (atype ^ btype) ? 0x1 : 0x2;                          \
627fcf5ef2aSThomas Huth     } else if (expa < expb) {                                            \
628fcf5ef2aSThomas Huth         dfp.crbf = 0x8;                                                  \
629fcf5ef2aSThomas Huth     } else if (expa > expb) {                                            \
630fcf5ef2aSThomas Huth         dfp.crbf = 0x4;                                                  \
631fcf5ef2aSThomas Huth     } else {                                                             \
632fcf5ef2aSThomas Huth         dfp.crbf = 0x2;                                                  \
633fcf5ef2aSThomas Huth     }                                                                    \
634fcf5ef2aSThomas Huth                                                                          \
635fcf5ef2aSThomas Huth     dfp_set_FPCC_from_CRBF(&dfp);                                        \
636fcf5ef2aSThomas Huth     return dfp.crbf;                                                     \
637fcf5ef2aSThomas Huth }
638fcf5ef2aSThomas Huth 
63985c38a46SLuis Pires DFP_HELPER_TSTEX(DTSTEX, 64)
64085c38a46SLuis Pires DFP_HELPER_TSTEX(DTSTEXQ, 128)
641fcf5ef2aSThomas Huth 
642fcf5ef2aSThomas Huth #define DFP_HELPER_TSTSF(op, size)                                       \
643d9acba31SMark Cave-Ayland uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b)     \
644fcf5ef2aSThomas Huth {                                                                        \
645fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                  \
646fcf5ef2aSThomas Huth     unsigned k;                                                          \
64764b8574eSMark Cave-Ayland     ppc_vsr_t va;                                                        \
648fcf5ef2aSThomas Huth                                                                          \
649fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, 0, b, env);                          \
650fcf5ef2aSThomas Huth                                                                          \
65164b8574eSMark Cave-Ayland     get_dfp64(&va, a);                                                   \
65264b8574eSMark Cave-Ayland     k = va.VsrD(1) & 0x3F;                                               \
653fcf5ef2aSThomas Huth                                                                          \
654fcf5ef2aSThomas Huth     if (unlikely(decNumberIsSpecial(&dfp.b))) {                          \
655fcf5ef2aSThomas Huth         dfp.crbf = 1;                                                    \
656fcf5ef2aSThomas Huth     } else if (k == 0) {                                                 \
657fcf5ef2aSThomas Huth         dfp.crbf = 4;                                                    \
658fcf5ef2aSThomas Huth     } else if (unlikely(decNumberIsZero(&dfp.b))) {                      \
659fcf5ef2aSThomas Huth         /* Zero has no sig digits */                                     \
660fcf5ef2aSThomas Huth         dfp.crbf = 4;                                                    \
661fcf5ef2aSThomas Huth     } else {                                                             \
662fcf5ef2aSThomas Huth         unsigned nsd = dfp.b.digits;                                     \
663fcf5ef2aSThomas Huth         if (k < nsd) {                                                   \
664fcf5ef2aSThomas Huth             dfp.crbf = 8;                                                \
665fcf5ef2aSThomas Huth         } else if (k > nsd) {                                            \
666fcf5ef2aSThomas Huth             dfp.crbf = 4;                                                \
667fcf5ef2aSThomas Huth         } else {                                                         \
668fcf5ef2aSThomas Huth             dfp.crbf = 2;                                                \
669fcf5ef2aSThomas Huth         }                                                                \
670fcf5ef2aSThomas Huth     }                                                                    \
671fcf5ef2aSThomas Huth                                                                          \
672fcf5ef2aSThomas Huth     dfp_set_FPCC_from_CRBF(&dfp);                                        \
673fcf5ef2aSThomas Huth     return dfp.crbf;                                                     \
674fcf5ef2aSThomas Huth }
675fcf5ef2aSThomas Huth 
67685c38a46SLuis Pires DFP_HELPER_TSTSF(DTSTSF, 64)
67785c38a46SLuis Pires DFP_HELPER_TSTSF(DTSTSFQ, 128)
678fcf5ef2aSThomas Huth 
679fcf5ef2aSThomas Huth #define DFP_HELPER_TSTSFI(op, size)                                     \
680d9acba31SMark Cave-Ayland uint32_t helper_##op(CPUPPCState *env, uint32_t a, ppc_fprp_t *b)       \
681fcf5ef2aSThomas Huth {                                                                       \
682fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                 \
683fcf5ef2aSThomas Huth     unsigned uim;                                                       \
684fcf5ef2aSThomas Huth                                                                         \
685fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, 0, b, env);                         \
686fcf5ef2aSThomas Huth                                                                         \
687fcf5ef2aSThomas Huth     uim = a & 0x3F;                                                     \
688fcf5ef2aSThomas Huth                                                                         \
689fcf5ef2aSThomas Huth     if (unlikely(decNumberIsSpecial(&dfp.b))) {                         \
690fcf5ef2aSThomas Huth         dfp.crbf = 1;                                                   \
691fcf5ef2aSThomas Huth     } else if (uim == 0) {                                              \
692fcf5ef2aSThomas Huth         dfp.crbf = 4;                                                   \
693fcf5ef2aSThomas Huth     } else if (unlikely(decNumberIsZero(&dfp.b))) {                     \
694fcf5ef2aSThomas Huth         /* Zero has no sig digits */                                    \
695fcf5ef2aSThomas Huth         dfp.crbf = 4;                                                   \
696fcf5ef2aSThomas Huth     } else {                                                            \
697fcf5ef2aSThomas Huth         unsigned nsd = dfp.b.digits;                                    \
698fcf5ef2aSThomas Huth         if (uim < nsd) {                                                \
699fcf5ef2aSThomas Huth             dfp.crbf = 8;                                               \
700fcf5ef2aSThomas Huth         } else if (uim > nsd) {                                         \
701fcf5ef2aSThomas Huth             dfp.crbf = 4;                                               \
702fcf5ef2aSThomas Huth         } else {                                                        \
703fcf5ef2aSThomas Huth             dfp.crbf = 2;                                               \
704fcf5ef2aSThomas Huth         }                                                               \
705fcf5ef2aSThomas Huth     }                                                                   \
706fcf5ef2aSThomas Huth                                                                         \
707fcf5ef2aSThomas Huth     dfp_set_FPCC_from_CRBF(&dfp);                                       \
708fcf5ef2aSThomas Huth     return dfp.crbf;                                                    \
709fcf5ef2aSThomas Huth }
710fcf5ef2aSThomas Huth 
71185c38a46SLuis Pires DFP_HELPER_TSTSFI(DTSTSFI, 64)
71285c38a46SLuis Pires DFP_HELPER_TSTSFI(DTSTSFIQ, 128)
713fcf5ef2aSThomas Huth 
QUA_PPs(struct PPC_DFP * dfp)714fcf5ef2aSThomas Huth static void QUA_PPs(struct PPC_DFP *dfp)
715fcf5ef2aSThomas Huth {
716fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT(dfp);
717fcf5ef2aSThomas Huth     dfp_check_for_XX(dfp);
718fcf5ef2aSThomas Huth     dfp_check_for_VXSNAN(dfp);
719fcf5ef2aSThomas Huth     dfp_check_for_VXCVI(dfp);
720fcf5ef2aSThomas Huth }
721fcf5ef2aSThomas Huth 
dfp_quantize(uint8_t rmc,struct PPC_DFP * dfp)722fcf5ef2aSThomas Huth static void dfp_quantize(uint8_t rmc, struct PPC_DFP *dfp)
723fcf5ef2aSThomas Huth {
724fcf5ef2aSThomas Huth     dfp_set_round_mode_from_immediate(0, rmc, dfp);
725fcf5ef2aSThomas Huth     decNumberQuantize(&dfp->t, &dfp->b, &dfp->a, &dfp->context);
726fcf5ef2aSThomas Huth     if (decNumberIsSNaN(&dfp->a)) {
727fcf5ef2aSThomas Huth         dfp->t = dfp->a;
728fcf5ef2aSThomas Huth         dfp_makeQNaN(&dfp->t);
729fcf5ef2aSThomas Huth     } else if (decNumberIsSNaN(&dfp->b)) {
730fcf5ef2aSThomas Huth         dfp->t = dfp->b;
731fcf5ef2aSThomas Huth         dfp_makeQNaN(&dfp->t);
732fcf5ef2aSThomas Huth     } else if (decNumberIsQNaN(&dfp->a)) {
733fcf5ef2aSThomas Huth         dfp->t = dfp->a;
734fcf5ef2aSThomas Huth     } else if (decNumberIsQNaN(&dfp->b)) {
735fcf5ef2aSThomas Huth         dfp->t = dfp->b;
736fcf5ef2aSThomas Huth     }
737fcf5ef2aSThomas Huth }
738fcf5ef2aSThomas Huth 
739fcf5ef2aSThomas Huth #define DFP_HELPER_QUAI(op, size)                                       \
740d9acba31SMark Cave-Ayland void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b,        \
741fcf5ef2aSThomas Huth                  uint32_t te, uint32_t rmc)                             \
742fcf5ef2aSThomas Huth {                                                                       \
743fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                 \
744fcf5ef2aSThomas Huth                                                                         \
745fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, 0, b, env);                         \
746fcf5ef2aSThomas Huth                                                                         \
747fcf5ef2aSThomas Huth     decNumberFromUInt32(&dfp.a, 1);                                     \
748fcf5ef2aSThomas Huth     dfp.a.exponent = (int32_t)((int8_t)(te << 3) >> 3);                 \
749fcf5ef2aSThomas Huth                                                                         \
750fcf5ef2aSThomas Huth     dfp_quantize(rmc, &dfp);                                            \
751474c2e93SMark Cave-Ayland     dfp_finalize_decimal##size(&dfp);                                   \
752fcf5ef2aSThomas Huth     QUA_PPs(&dfp);                                                      \
753fcf5ef2aSThomas Huth                                                                         \
754f6d4c423SMark Cave-Ayland     set_dfp##size(t, &dfp.vt);                                          \
755fcf5ef2aSThomas Huth }
756fcf5ef2aSThomas Huth 
75778464edbSLuis Pires DFP_HELPER_QUAI(DQUAI, 64)
75878464edbSLuis Pires DFP_HELPER_QUAI(DQUAIQ, 128)
759fcf5ef2aSThomas Huth 
760fcf5ef2aSThomas Huth #define DFP_HELPER_QUA(op, size)                                        \
761d9acba31SMark Cave-Ayland void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a,        \
762d9acba31SMark Cave-Ayland                  ppc_fprp_t *b, uint32_t rmc)                           \
763fcf5ef2aSThomas Huth {                                                                       \
764fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                 \
765fcf5ef2aSThomas Huth                                                                         \
766fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, a, b, env);                         \
767fcf5ef2aSThomas Huth                                                                         \
768fcf5ef2aSThomas Huth     dfp_quantize(rmc, &dfp);                                            \
769474c2e93SMark Cave-Ayland     dfp_finalize_decimal##size(&dfp);                                   \
770fcf5ef2aSThomas Huth     QUA_PPs(&dfp);                                                      \
771fcf5ef2aSThomas Huth                                                                         \
772f6d4c423SMark Cave-Ayland     set_dfp##size(t, &dfp.vt);                                          \
773fcf5ef2aSThomas Huth }
774fcf5ef2aSThomas Huth 
775a8f4bce6SLuis Pires DFP_HELPER_QUA(DQUA, 64)
776a8f4bce6SLuis Pires DFP_HELPER_QUA(DQUAQ, 128)
777fcf5ef2aSThomas Huth 
_dfp_reround(uint8_t rmc,int32_t ref_sig,int32_t xmax,struct PPC_DFP * dfp)778fcf5ef2aSThomas Huth static void _dfp_reround(uint8_t rmc, int32_t ref_sig, int32_t xmax,
779fcf5ef2aSThomas Huth                              struct PPC_DFP *dfp)
780fcf5ef2aSThomas Huth {
781fcf5ef2aSThomas Huth     int msd_orig, msd_rslt;
782fcf5ef2aSThomas Huth 
783fcf5ef2aSThomas Huth     if (unlikely((ref_sig == 0) || (dfp->b.digits <= ref_sig))) {
784fcf5ef2aSThomas Huth         dfp->t = dfp->b;
785fcf5ef2aSThomas Huth         if (decNumberIsSNaN(&dfp->b)) {
786fcf5ef2aSThomas Huth             dfp_makeQNaN(&dfp->t);
787fcf5ef2aSThomas Huth             dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXSNAN, FPSCR_VE);
788fcf5ef2aSThomas Huth         }
789fcf5ef2aSThomas Huth         return;
790fcf5ef2aSThomas Huth     }
791fcf5ef2aSThomas Huth 
792fcf5ef2aSThomas Huth     /* Reround is equivalent to quantizing b with 1**E(n) where */
793fcf5ef2aSThomas Huth     /* n = exp(b) + numDigits(b) - reference_significance.      */
794fcf5ef2aSThomas Huth 
795fcf5ef2aSThomas Huth     decNumberFromUInt32(&dfp->a, 1);
796fcf5ef2aSThomas Huth     dfp->a.exponent = dfp->b.exponent + dfp->b.digits - ref_sig;
797fcf5ef2aSThomas Huth 
798fcf5ef2aSThomas Huth     if (unlikely(dfp->a.exponent > xmax)) {
799fcf5ef2aSThomas Huth         dfp->t.digits = 0;
800fcf5ef2aSThomas Huth         dfp->t.bits &= ~DECNEG;
801fcf5ef2aSThomas Huth         dfp_makeQNaN(&dfp->t);
802fcf5ef2aSThomas Huth         dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXCVI, FPSCR_VE);
803fcf5ef2aSThomas Huth         return;
804fcf5ef2aSThomas Huth     }
805fcf5ef2aSThomas Huth 
806fcf5ef2aSThomas Huth     dfp_quantize(rmc, dfp);
807fcf5ef2aSThomas Huth 
808fcf5ef2aSThomas Huth     msd_orig = dfp_get_digit(&dfp->b, dfp->b.digits-1);
809fcf5ef2aSThomas Huth     msd_rslt = dfp_get_digit(&dfp->t, dfp->t.digits-1);
810fcf5ef2aSThomas Huth 
811fcf5ef2aSThomas Huth     /* If the quantization resulted in rounding up to the next magnitude, */
812fcf5ef2aSThomas Huth     /* then we need to shift the significand and adjust the exponent.     */
813fcf5ef2aSThomas Huth 
814fcf5ef2aSThomas Huth     if (unlikely((msd_orig == 9) && (msd_rslt == 1))) {
815fcf5ef2aSThomas Huth 
816fcf5ef2aSThomas Huth         decNumber negone;
817fcf5ef2aSThomas Huth 
818fcf5ef2aSThomas Huth         decNumberFromInt32(&negone, -1);
819fcf5ef2aSThomas Huth         decNumberShift(&dfp->t, &dfp->t, &negone, &dfp->context);
820fcf5ef2aSThomas Huth         dfp->t.exponent++;
821fcf5ef2aSThomas Huth 
822fcf5ef2aSThomas Huth         if (unlikely(dfp->t.exponent > xmax)) {
823fcf5ef2aSThomas Huth             dfp_makeQNaN(&dfp->t);
824fcf5ef2aSThomas Huth             dfp->t.digits = 0;
825fcf5ef2aSThomas Huth             dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXCVI, FP_VE);
826fcf5ef2aSThomas Huth             /* Inhibit XX in this case */
827fcf5ef2aSThomas Huth             decContextClearStatus(&dfp->context, DEC_Inexact);
828fcf5ef2aSThomas Huth         }
829fcf5ef2aSThomas Huth     }
830fcf5ef2aSThomas Huth }
831fcf5ef2aSThomas Huth 
832fcf5ef2aSThomas Huth #define DFP_HELPER_RRND(op, size)                                       \
833d9acba31SMark Cave-Ayland void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a,        \
834d9acba31SMark Cave-Ayland                  ppc_fprp_t *b, uint32_t rmc)                           \
835fcf5ef2aSThomas Huth {                                                                       \
836fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                 \
83764b8574eSMark Cave-Ayland     ppc_vsr_t va;                                                       \
8386a8fbb9bSMark Cave-Ayland     int32_t ref_sig;                                                    \
839fcf5ef2aSThomas Huth     int32_t xmax = ((size) == 64) ? 369 : 6111;                         \
840fcf5ef2aSThomas Huth                                                                         \
841fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, 0, b, env);                         \
842fcf5ef2aSThomas Huth                                                                         \
84364b8574eSMark Cave-Ayland     get_dfp64(&va, a);                                                  \
84464b8574eSMark Cave-Ayland     ref_sig = va.VsrD(1) & 0x3f;                                        \
8456a8fbb9bSMark Cave-Ayland                                                                         \
846fcf5ef2aSThomas Huth     _dfp_reround(rmc, ref_sig, xmax, &dfp);                             \
847474c2e93SMark Cave-Ayland     dfp_finalize_decimal##size(&dfp);                                   \
848fcf5ef2aSThomas Huth     QUA_PPs(&dfp);                                                      \
849fcf5ef2aSThomas Huth                                                                         \
850f6d4c423SMark Cave-Ayland     set_dfp##size(t, &dfp.vt);                                          \
851fcf5ef2aSThomas Huth }
852fcf5ef2aSThomas Huth 
853a8f4bce6SLuis Pires DFP_HELPER_RRND(DRRND, 64)
854a8f4bce6SLuis Pires DFP_HELPER_RRND(DRRNDQ, 128)
855fcf5ef2aSThomas Huth 
856fcf5ef2aSThomas Huth #define DFP_HELPER_RINT(op, postprocs, size)                                   \
857d9acba31SMark Cave-Ayland void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b,               \
858fcf5ef2aSThomas Huth              uint32_t r, uint32_t rmc)                                         \
859fcf5ef2aSThomas Huth {                                                                              \
860fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                        \
861fcf5ef2aSThomas Huth                                                                                \
862fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, 0, b, env);                                \
863fcf5ef2aSThomas Huth                                                                                \
864fcf5ef2aSThomas Huth     dfp_set_round_mode_from_immediate(r, rmc, &dfp);                           \
865fcf5ef2aSThomas Huth     decNumberToIntegralExact(&dfp.t, &dfp.b, &dfp.context);                    \
866474c2e93SMark Cave-Ayland     dfp_finalize_decimal##size(&dfp);                                          \
867fcf5ef2aSThomas Huth     postprocs(&dfp);                                                           \
868fcf5ef2aSThomas Huth                                                                                \
869f6d4c423SMark Cave-Ayland     set_dfp##size(t, &dfp.vt);                                                 \
870fcf5ef2aSThomas Huth }
871fcf5ef2aSThomas Huth 
RINTX_PPs(struct PPC_DFP * dfp)872fcf5ef2aSThomas Huth static void RINTX_PPs(struct PPC_DFP *dfp)
873fcf5ef2aSThomas Huth {
874fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT(dfp);
875fcf5ef2aSThomas Huth     dfp_check_for_XX(dfp);
876fcf5ef2aSThomas Huth     dfp_check_for_VXSNAN(dfp);
877fcf5ef2aSThomas Huth }
878fcf5ef2aSThomas Huth 
87978464edbSLuis Pires DFP_HELPER_RINT(DRINTX, RINTX_PPs, 64)
88078464edbSLuis Pires DFP_HELPER_RINT(DRINTXQ, RINTX_PPs, 128)
881fcf5ef2aSThomas Huth 
RINTN_PPs(struct PPC_DFP * dfp)882fcf5ef2aSThomas Huth static void RINTN_PPs(struct PPC_DFP *dfp)
883fcf5ef2aSThomas Huth {
884fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT(dfp);
885fcf5ef2aSThomas Huth     dfp_check_for_VXSNAN(dfp);
886fcf5ef2aSThomas Huth }
887fcf5ef2aSThomas Huth 
88878464edbSLuis Pires DFP_HELPER_RINT(DRINTN, RINTN_PPs, 64)
88978464edbSLuis Pires DFP_HELPER_RINT(DRINTNQ, RINTN_PPs, 128)
890fcf5ef2aSThomas Huth 
helper_DCTDP(CPUPPCState * env,ppc_fprp_t * t,ppc_fprp_t * b)891c8ef4d1eSLuis Pires void helper_DCTDP(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b)
892fcf5ef2aSThomas Huth {
893fcf5ef2aSThomas Huth     struct PPC_DFP dfp;
89464b8574eSMark Cave-Ayland     ppc_vsr_t vb;
8956a8fbb9bSMark Cave-Ayland     uint32_t b_short;
8966a8fbb9bSMark Cave-Ayland 
89764b8574eSMark Cave-Ayland     get_dfp64(&vb, b);
89864b8574eSMark Cave-Ayland     b_short = (uint32_t)vb.VsrD(1);
8996a8fbb9bSMark Cave-Ayland 
900fcf5ef2aSThomas Huth     dfp_prepare_decimal64(&dfp, 0, 0, env);
901fcf5ef2aSThomas Huth     decimal32ToNumber((decimal32 *)&b_short, &dfp.t);
902474c2e93SMark Cave-Ayland     dfp_finalize_decimal64(&dfp);
90364b8574eSMark Cave-Ayland     set_dfp64(t, &dfp.vt);
904fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT(&dfp);
905fcf5ef2aSThomas Huth }
906fcf5ef2aSThomas Huth 
helper_DCTQPQ(CPUPPCState * env,ppc_fprp_t * t,ppc_fprp_t * b)907c8ef4d1eSLuis Pires void helper_DCTQPQ(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b)
908fcf5ef2aSThomas Huth {
909fcf5ef2aSThomas Huth     struct PPC_DFP dfp;
91064b8574eSMark Cave-Ayland     ppc_vsr_t vb;
911fcf5ef2aSThomas Huth     dfp_prepare_decimal128(&dfp, 0, 0, env);
91264b8574eSMark Cave-Ayland     get_dfp64(&vb, b);
91364b8574eSMark Cave-Ayland     decimal64ToNumber((decimal64 *)&vb.VsrD(1), &dfp.t);
914fcf5ef2aSThomas Huth 
915fcf5ef2aSThomas Huth     dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp);
916fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT(&dfp);
917fcf5ef2aSThomas Huth 
918474c2e93SMark Cave-Ayland     dfp_finalize_decimal128(&dfp);
91964b8574eSMark Cave-Ayland     set_dfp128(t, &dfp.vt);
920fcf5ef2aSThomas Huth }
921fcf5ef2aSThomas Huth 
helper_DRSP(CPUPPCState * env,ppc_fprp_t * t,ppc_fprp_t * b)922c8ef4d1eSLuis Pires void helper_DRSP(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b)
923fcf5ef2aSThomas Huth {
924fcf5ef2aSThomas Huth     struct PPC_DFP dfp;
925fcf5ef2aSThomas Huth     uint32_t t_short = 0;
92664b8574eSMark Cave-Ayland     ppc_vsr_t vt;
927fcf5ef2aSThomas Huth     dfp_prepare_decimal64(&dfp, 0, b, env);
928fcf5ef2aSThomas Huth     decimal32FromNumber((decimal32 *)&t_short, &dfp.b, &dfp.context);
929fcf5ef2aSThomas Huth     decimal32ToNumber((decimal32 *)&t_short, &dfp.t);
930fcf5ef2aSThomas Huth 
931fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT_short(&dfp);
932fcf5ef2aSThomas Huth     dfp_check_for_OX(&dfp);
933fcf5ef2aSThomas Huth     dfp_check_for_UX(&dfp);
934fcf5ef2aSThomas Huth     dfp_check_for_XX(&dfp);
935fcf5ef2aSThomas Huth 
93664b8574eSMark Cave-Ayland     vt.VsrD(1) = (uint64_t)t_short;
93764b8574eSMark Cave-Ayland     set_dfp64(t, &vt);
938fcf5ef2aSThomas Huth }
939fcf5ef2aSThomas Huth 
helper_DRDPQ(CPUPPCState * env,ppc_fprp_t * t,ppc_fprp_t * b)940c8ef4d1eSLuis Pires void helper_DRDPQ(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b)
941fcf5ef2aSThomas Huth {
942fcf5ef2aSThomas Huth     struct PPC_DFP dfp;
943fcf5ef2aSThomas Huth     dfp_prepare_decimal128(&dfp, 0, b, env);
94464b8574eSMark Cave-Ayland     decimal64FromNumber((decimal64 *)&dfp.vt.VsrD(1), &dfp.b, &dfp.context);
94564b8574eSMark Cave-Ayland     decimal64ToNumber((decimal64 *)&dfp.vt.VsrD(1), &dfp.t);
946fcf5ef2aSThomas Huth 
947fcf5ef2aSThomas Huth     dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp);
948fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT_long(&dfp);
949fcf5ef2aSThomas Huth     dfp_check_for_OX(&dfp);
950fcf5ef2aSThomas Huth     dfp_check_for_UX(&dfp);
951fcf5ef2aSThomas Huth     dfp_check_for_XX(&dfp);
952fcf5ef2aSThomas Huth 
95364b8574eSMark Cave-Ayland     dfp.vt.VsrD(0) = dfp.vt.VsrD(1) = 0;
954474c2e93SMark Cave-Ayland     dfp_finalize_decimal64(&dfp);
95564b8574eSMark Cave-Ayland     set_dfp128(t, &dfp.vt);
956fcf5ef2aSThomas Huth }
957fcf5ef2aSThomas Huth 
958fcf5ef2aSThomas Huth #define DFP_HELPER_CFFIX(op, size)                                             \
959d9acba31SMark Cave-Ayland void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b)               \
960fcf5ef2aSThomas Huth {                                                                              \
961fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                        \
96264b8574eSMark Cave-Ayland     ppc_vsr_t vb;                                                              \
963fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, 0, b, env);                                \
96464b8574eSMark Cave-Ayland     get_dfp64(&vb, b);                                                         \
96564b8574eSMark Cave-Ayland     decNumberFromInt64(&dfp.t, (int64_t)vb.VsrD(1));                           \
966474c2e93SMark Cave-Ayland     dfp_finalize_decimal##size(&dfp);                                          \
967fcf5ef2aSThomas Huth     CFFIX_PPs(&dfp);                                                           \
968fcf5ef2aSThomas Huth                                                                                \
969f6d4c423SMark Cave-Ayland     set_dfp##size(t, &dfp.vt);                                                 \
970fcf5ef2aSThomas Huth }
971fcf5ef2aSThomas Huth 
CFFIX_PPs(struct PPC_DFP * dfp)972fcf5ef2aSThomas Huth static void CFFIX_PPs(struct PPC_DFP *dfp)
973fcf5ef2aSThomas Huth {
974fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT(dfp);
975fcf5ef2aSThomas Huth     dfp_check_for_XX(dfp);
976fcf5ef2aSThomas Huth }
977fcf5ef2aSThomas Huth 
978c8ef4d1eSLuis Pires DFP_HELPER_CFFIX(DCFFIX, 64)
979c8ef4d1eSLuis Pires DFP_HELPER_CFFIX(DCFFIXQ, 128)
980fcf5ef2aSThomas Huth 
helper_DCFFIXQQ(CPUPPCState * env,ppc_fprp_t * t,ppc_avr_t * b)981d39b2cc7SLuis Pires void helper_DCFFIXQQ(CPUPPCState *env, ppc_fprp_t *t, ppc_avr_t *b)
982d39b2cc7SLuis Pires {
983d39b2cc7SLuis Pires     struct PPC_DFP dfp;
984d39b2cc7SLuis Pires 
985d39b2cc7SLuis Pires     dfp_prepare_decimal128(&dfp, NULL, NULL, env);
986d39b2cc7SLuis Pires     decNumberFromInt128(&dfp.t, (uint64_t)b->VsrD(1), (int64_t)b->VsrD(0));
987d39b2cc7SLuis Pires     dfp_finalize_decimal128(&dfp);
988d39b2cc7SLuis Pires     CFFIX_PPs(&dfp);
989d39b2cc7SLuis Pires 
990d39b2cc7SLuis Pires     set_dfp128(t, &dfp.vt);
991d39b2cc7SLuis Pires }
992d39b2cc7SLuis Pires 
993fcf5ef2aSThomas Huth #define DFP_HELPER_CTFIX(op, size)                                            \
994d9acba31SMark Cave-Ayland void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b)              \
995fcf5ef2aSThomas Huth {                                                                             \
996fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                       \
997fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, 0, b, env);                               \
998fcf5ef2aSThomas Huth                                                                               \
999fcf5ef2aSThomas Huth     if (unlikely(decNumberIsSpecial(&dfp.b))) {                               \
1000fcf5ef2aSThomas Huth         uint64_t invalid_flags = FP_VX | FP_VXCVI;                            \
1001fcf5ef2aSThomas Huth         if (decNumberIsInfinite(&dfp.b)) {                                    \
100264b8574eSMark Cave-Ayland             dfp.vt.VsrD(1) = decNumberIsNegative(&dfp.b) ? INT64_MIN :        \
100364b8574eSMark Cave-Ayland                                                            INT64_MAX;         \
1004fcf5ef2aSThomas Huth         } else { /* NaN */                                                    \
100564b8574eSMark Cave-Ayland             dfp.vt.VsrD(1) = INT64_MIN;                                       \
1006fcf5ef2aSThomas Huth             if (decNumberIsSNaN(&dfp.b)) {                                    \
1007fcf5ef2aSThomas Huth                 invalid_flags |= FP_VXSNAN;                                   \
1008fcf5ef2aSThomas Huth             }                                                                 \
1009fcf5ef2aSThomas Huth         }                                                                     \
1010fcf5ef2aSThomas Huth         dfp_set_FPSCR_flag(&dfp, invalid_flags, FP_VE);                       \
1011fcf5ef2aSThomas Huth     } else if (unlikely(decNumberIsZero(&dfp.b))) {                           \
101264b8574eSMark Cave-Ayland         dfp.vt.VsrD(1) = 0;                                                   \
1013fcf5ef2aSThomas Huth     } else {                                                                  \
1014fcf5ef2aSThomas Huth         decNumberToIntegralExact(&dfp.b, &dfp.b, &dfp.context);               \
101564b8574eSMark Cave-Ayland         dfp.vt.VsrD(1) = decNumberIntegralToInt64(&dfp.b, &dfp.context);      \
1016fcf5ef2aSThomas Huth         if (decContextTestStatus(&dfp.context, DEC_Invalid_operation)) {      \
101764b8574eSMark Cave-Ayland             dfp.vt.VsrD(1) = decNumberIsNegative(&dfp.b) ? INT64_MIN :        \
101864b8574eSMark Cave-Ayland                                                            INT64_MAX;         \
1019fcf5ef2aSThomas Huth             dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FP_VE);                \
1020fcf5ef2aSThomas Huth         } else {                                                              \
1021fcf5ef2aSThomas Huth             dfp_check_for_XX(&dfp);                                           \
1022fcf5ef2aSThomas Huth         }                                                                     \
1023fcf5ef2aSThomas Huth     }                                                                         \
1024fcf5ef2aSThomas Huth                                                                               \
102564b8574eSMark Cave-Ayland     set_dfp64(t, &dfp.vt);                                                    \
1026fcf5ef2aSThomas Huth }
1027fcf5ef2aSThomas Huth 
1028c8ef4d1eSLuis Pires DFP_HELPER_CTFIX(DCTFIX, 64)
1029c8ef4d1eSLuis Pires DFP_HELPER_CTFIX(DCTFIXQ, 128)
1030fcf5ef2aSThomas Huth 
helper_DCTFIXQQ(CPUPPCState * env,ppc_avr_t * t,ppc_fprp_t * b)1031328747f3SLuis Pires void helper_DCTFIXQQ(CPUPPCState *env, ppc_avr_t *t, ppc_fprp_t *b)
1032328747f3SLuis Pires {
1033328747f3SLuis Pires     struct PPC_DFP dfp;
1034328747f3SLuis Pires     dfp_prepare_decimal128(&dfp, 0, b, env);
1035328747f3SLuis Pires 
1036328747f3SLuis Pires     if (unlikely(decNumberIsSpecial(&dfp.b))) {
1037328747f3SLuis Pires         uint64_t invalid_flags = FP_VX | FP_VXCVI;
1038328747f3SLuis Pires         if (decNumberIsInfinite(&dfp.b)) {
1039328747f3SLuis Pires             if (decNumberIsNegative(&dfp.b)) {
1040328747f3SLuis Pires                 dfp.vt.VsrD(0) = INT64_MIN;
1041328747f3SLuis Pires                 dfp.vt.VsrD(1) = 0;
1042328747f3SLuis Pires             } else {
1043328747f3SLuis Pires                 dfp.vt.VsrD(0) = INT64_MAX;
1044328747f3SLuis Pires                 dfp.vt.VsrD(1) = UINT64_MAX;
1045328747f3SLuis Pires             }
1046328747f3SLuis Pires         } else { /* NaN */
1047328747f3SLuis Pires             dfp.vt.VsrD(0) = INT64_MIN;
1048328747f3SLuis Pires             dfp.vt.VsrD(1) = 0;
1049328747f3SLuis Pires             if (decNumberIsSNaN(&dfp.b)) {
1050328747f3SLuis Pires                 invalid_flags |= FP_VXSNAN;
1051328747f3SLuis Pires             }
1052328747f3SLuis Pires         }
1053328747f3SLuis Pires         dfp_set_FPSCR_flag(&dfp, invalid_flags, FP_VE);
1054328747f3SLuis Pires     } else if (unlikely(decNumberIsZero(&dfp.b))) {
1055328747f3SLuis Pires         dfp.vt.VsrD(0) = 0;
1056328747f3SLuis Pires         dfp.vt.VsrD(1) = 0;
1057328747f3SLuis Pires     } else {
1058328747f3SLuis Pires         decNumberToIntegralExact(&dfp.b, &dfp.b, &dfp.context);
1059328747f3SLuis Pires         decNumberIntegralToInt128(&dfp.b, &dfp.context,
1060328747f3SLuis Pires                 &dfp.vt.VsrD(1), &dfp.vt.VsrD(0));
1061328747f3SLuis Pires         if (decContextTestStatus(&dfp.context, DEC_Invalid_operation)) {
1062328747f3SLuis Pires             if (decNumberIsNegative(&dfp.b)) {
1063328747f3SLuis Pires                 dfp.vt.VsrD(0) = INT64_MIN;
1064328747f3SLuis Pires                 dfp.vt.VsrD(1) = 0;
1065328747f3SLuis Pires             } else {
1066328747f3SLuis Pires                 dfp.vt.VsrD(0) = INT64_MAX;
1067328747f3SLuis Pires                 dfp.vt.VsrD(1) = UINT64_MAX;
1068328747f3SLuis Pires             }
1069328747f3SLuis Pires             dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FP_VE);
1070328747f3SLuis Pires         } else {
1071328747f3SLuis Pires             dfp_check_for_XX(&dfp);
1072328747f3SLuis Pires         }
1073328747f3SLuis Pires     }
1074328747f3SLuis Pires 
1075328747f3SLuis Pires     set_dfp128_to_avr(t, &dfp.vt);
1076328747f3SLuis Pires }
1077328747f3SLuis Pires 
dfp_set_bcd_digit_64(ppc_vsr_t * t,uint8_t digit,unsigned n)10781ea80bf7SMark Cave-Ayland static inline void dfp_set_bcd_digit_64(ppc_vsr_t *t, uint8_t digit,
1079fcf5ef2aSThomas Huth                                         unsigned n)
1080fcf5ef2aSThomas Huth {
10811ea80bf7SMark Cave-Ayland     t->VsrD(1) |= ((uint64_t)(digit & 0xF) << (n << 2));
1082fcf5ef2aSThomas Huth }
1083fcf5ef2aSThomas Huth 
dfp_set_bcd_digit_128(ppc_vsr_t * t,uint8_t digit,unsigned n)10841ea80bf7SMark Cave-Ayland static inline void dfp_set_bcd_digit_128(ppc_vsr_t *t, uint8_t digit,
1085fcf5ef2aSThomas Huth                                          unsigned n)
1086fcf5ef2aSThomas Huth {
10871ea80bf7SMark Cave-Ayland     t->VsrD((n & 0x10) ? 0 : 1) |=
1088fcf5ef2aSThomas Huth         ((uint64_t)(digit & 0xF) << ((n & 15) << 2));
1089fcf5ef2aSThomas Huth }
1090fcf5ef2aSThomas Huth 
dfp_set_sign_64(ppc_vsr_t * t,uint8_t sgn)10911ea80bf7SMark Cave-Ayland static inline void dfp_set_sign_64(ppc_vsr_t *t, uint8_t sgn)
1092fcf5ef2aSThomas Huth {
10931ea80bf7SMark Cave-Ayland     t->VsrD(1) <<= 4;
10941ea80bf7SMark Cave-Ayland     t->VsrD(1) |= (sgn & 0xF);
1095fcf5ef2aSThomas Huth }
1096fcf5ef2aSThomas Huth 
dfp_set_sign_128(ppc_vsr_t * t,uint8_t sgn)10971ea80bf7SMark Cave-Ayland static inline void dfp_set_sign_128(ppc_vsr_t *t, uint8_t sgn)
1098fcf5ef2aSThomas Huth {
10991ea80bf7SMark Cave-Ayland     t->VsrD(0) <<= 4;
11001ea80bf7SMark Cave-Ayland     t->VsrD(0) |= (t->VsrD(1) >> 60);
11011ea80bf7SMark Cave-Ayland     t->VsrD(1) <<= 4;
11021ea80bf7SMark Cave-Ayland     t->VsrD(1) |= (sgn & 0xF);
1103fcf5ef2aSThomas Huth }
1104fcf5ef2aSThomas Huth 
1105fcf5ef2aSThomas Huth #define DFP_HELPER_DEDPD(op, size)                                        \
1106d9acba31SMark Cave-Ayland void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b,          \
1107d9acba31SMark Cave-Ayland                  uint32_t sp)                                             \
1108fcf5ef2aSThomas Huth {                                                                         \
1109fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                   \
1110fcf5ef2aSThomas Huth     uint8_t digits[34];                                                   \
1111fcf5ef2aSThomas Huth     int i, N;                                                             \
1112fcf5ef2aSThomas Huth                                                                           \
1113fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, 0, b, env);                           \
1114fcf5ef2aSThomas Huth                                                                           \
1115fcf5ef2aSThomas Huth     decNumberGetBCD(&dfp.b, digits);                                      \
111664b8574eSMark Cave-Ayland     dfp.vt.VsrD(0) = dfp.vt.VsrD(1) = 0;                                  \
1117fcf5ef2aSThomas Huth     N = dfp.b.digits;                                                     \
1118fcf5ef2aSThomas Huth                                                                           \
1119fcf5ef2aSThomas Huth     for (i = 0; (i < N) && (i < (size)/4); i++) {                         \
11201ea80bf7SMark Cave-Ayland         dfp_set_bcd_digit_##size(&dfp.vt, digits[N - i - 1], i);          \
1121fcf5ef2aSThomas Huth     }                                                                     \
1122fcf5ef2aSThomas Huth                                                                           \
1123fcf5ef2aSThomas Huth     if (sp & 2) {                                                         \
1124fcf5ef2aSThomas Huth         uint8_t sgn;                                                      \
1125fcf5ef2aSThomas Huth                                                                           \
1126fcf5ef2aSThomas Huth         if (decNumberIsNegative(&dfp.b)) {                                \
1127fcf5ef2aSThomas Huth             sgn = 0xD;                                                    \
1128fcf5ef2aSThomas Huth         } else {                                                          \
1129fcf5ef2aSThomas Huth             sgn = ((sp & 1) ? 0xF : 0xC);                                 \
1130fcf5ef2aSThomas Huth         }                                                                 \
11311ea80bf7SMark Cave-Ayland         dfp_set_sign_##size(&dfp.vt, sgn);                                \
1132fcf5ef2aSThomas Huth     }                                                                     \
1133fcf5ef2aSThomas Huth                                                                           \
1134f6d4c423SMark Cave-Ayland     set_dfp##size(t, &dfp.vt);                                            \
1135fcf5ef2aSThomas Huth }
1136fcf5ef2aSThomas Huth 
1137a2329747SLuis Pires DFP_HELPER_DEDPD(DDEDPD, 64)
1138a2329747SLuis Pires DFP_HELPER_DEDPD(DDEDPDQ, 128)
1139fcf5ef2aSThomas Huth 
dfp_get_bcd_digit_64(ppc_vsr_t * t,unsigned n)11401ea80bf7SMark Cave-Ayland static inline uint8_t dfp_get_bcd_digit_64(ppc_vsr_t *t, unsigned n)
1141fcf5ef2aSThomas Huth {
11421ea80bf7SMark Cave-Ayland     return t->VsrD(1) >> ((n << 2) & 63) & 15;
1143fcf5ef2aSThomas Huth }
1144fcf5ef2aSThomas Huth 
dfp_get_bcd_digit_128(ppc_vsr_t * t,unsigned n)11451ea80bf7SMark Cave-Ayland static inline uint8_t dfp_get_bcd_digit_128(ppc_vsr_t *t, unsigned n)
1146fcf5ef2aSThomas Huth {
11471ea80bf7SMark Cave-Ayland     return t->VsrD((n & 0x10) ? 0 : 1) >> ((n << 2) & 63) & 15;
1148fcf5ef2aSThomas Huth }
1149fcf5ef2aSThomas Huth 
dfp_invalid_op_vxcvi_64(struct PPC_DFP * dfp)11503ecec4c0SVíctor Colombo static inline void dfp_invalid_op_vxcvi_64(struct PPC_DFP *dfp)
11513ecec4c0SVíctor Colombo {
11523ecec4c0SVíctor Colombo     /* TODO: fpscr is incorrectly not being saved to env */
11533ecec4c0SVíctor Colombo     dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXCVI, FPSCR_VE);
11543ecec4c0SVíctor Colombo     if ((dfp->env->fpscr & FP_VE) == 0) {
11553ecec4c0SVíctor Colombo         dfp->vt.VsrD(1) = 0x7c00000000000000; /* QNaN */
11563ecec4c0SVíctor Colombo     }
11573ecec4c0SVíctor Colombo }
11583ecec4c0SVíctor Colombo 
11593ecec4c0SVíctor Colombo 
dfp_invalid_op_vxcvi_128(struct PPC_DFP * dfp)11603ecec4c0SVíctor Colombo static inline void dfp_invalid_op_vxcvi_128(struct PPC_DFP *dfp)
11613ecec4c0SVíctor Colombo {
11623ecec4c0SVíctor Colombo     /* TODO: fpscr is incorrectly not being saved to env */
11633ecec4c0SVíctor Colombo     dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXCVI, FPSCR_VE);
11643ecec4c0SVíctor Colombo     if ((dfp->env->fpscr & FP_VE) == 0) {
11653ecec4c0SVíctor Colombo         dfp->vt.VsrD(0) = 0x7c00000000000000; /* QNaN */
11663ecec4c0SVíctor Colombo         dfp->vt.VsrD(1) = 0x0;
11673ecec4c0SVíctor Colombo     }
11683ecec4c0SVíctor Colombo }
11693ecec4c0SVíctor Colombo 
1170fcf5ef2aSThomas Huth #define DFP_HELPER_ENBCD(op, size)                                           \
1171d9acba31SMark Cave-Ayland void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b,             \
1172d9acba31SMark Cave-Ayland                  uint32_t s)                                                 \
1173fcf5ef2aSThomas Huth {                                                                            \
1174fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                      \
1175fcf5ef2aSThomas Huth     uint8_t digits[32];                                                      \
1176fcf5ef2aSThomas Huth     int n = 0, offset = 0, sgn = 0, nonzero = 0;                             \
1177fcf5ef2aSThomas Huth                                                                              \
1178fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, 0, b, env);                              \
1179fcf5ef2aSThomas Huth                                                                              \
1180fcf5ef2aSThomas Huth     decNumberZero(&dfp.t);                                                   \
1181fcf5ef2aSThomas Huth                                                                              \
1182fcf5ef2aSThomas Huth     if (s) {                                                                 \
11831ea80bf7SMark Cave-Ayland         uint8_t sgnNibble = dfp_get_bcd_digit_##size(&dfp.vb, offset++);     \
1184fcf5ef2aSThomas Huth         switch (sgnNibble) {                                                 \
1185fcf5ef2aSThomas Huth         case 0xD:                                                            \
1186fcf5ef2aSThomas Huth         case 0xB:                                                            \
1187fcf5ef2aSThomas Huth             sgn = 1;                                                         \
1188fcf5ef2aSThomas Huth             break;                                                           \
1189fcf5ef2aSThomas Huth         case 0xC:                                                            \
1190fcf5ef2aSThomas Huth         case 0xF:                                                            \
1191fcf5ef2aSThomas Huth         case 0xA:                                                            \
1192fcf5ef2aSThomas Huth         case 0xE:                                                            \
1193fcf5ef2aSThomas Huth             sgn = 0;                                                         \
1194fcf5ef2aSThomas Huth             break;                                                           \
1195fcf5ef2aSThomas Huth         default:                                                             \
11963ecec4c0SVíctor Colombo             dfp_invalid_op_vxcvi_##size(&dfp);                               \
11973ecec4c0SVíctor Colombo             set_dfp##size(t, &dfp.vt);                                       \
1198fcf5ef2aSThomas Huth             return;                                                          \
1199fcf5ef2aSThomas Huth         }                                                                    \
1200fcf5ef2aSThomas Huth         }                                                                    \
1201fcf5ef2aSThomas Huth                                                                              \
1202fcf5ef2aSThomas Huth     while (offset < (size) / 4) {                                            \
1203fcf5ef2aSThomas Huth         n++;                                                                 \
12041ea80bf7SMark Cave-Ayland         digits[(size) / 4 - n] = dfp_get_bcd_digit_##size(&dfp.vb,           \
120564b8574eSMark Cave-Ayland                                                           offset++);         \
1206fcf5ef2aSThomas Huth         if (digits[(size) / 4 - n] > 10) {                                   \
12073ecec4c0SVíctor Colombo             dfp_invalid_op_vxcvi_##size(&dfp);                               \
12083ecec4c0SVíctor Colombo             set_dfp##size(t, &dfp.vt);                                       \
1209fcf5ef2aSThomas Huth             return;                                                          \
1210fcf5ef2aSThomas Huth         } else {                                                             \
1211fcf5ef2aSThomas Huth             nonzero |= (digits[(size) / 4 - n] > 0);                         \
1212fcf5ef2aSThomas Huth         }                                                                    \
1213fcf5ef2aSThomas Huth     }                                                                        \
1214fcf5ef2aSThomas Huth                                                                              \
1215fcf5ef2aSThomas Huth     if (nonzero) {                                                           \
1216fcf5ef2aSThomas Huth         decNumberSetBCD(&dfp.t, digits + ((size) / 4) - n, n);               \
1217fcf5ef2aSThomas Huth     }                                                                        \
1218fcf5ef2aSThomas Huth                                                                              \
1219fcf5ef2aSThomas Huth     if (s && sgn)  {                                                         \
1220fcf5ef2aSThomas Huth         dfp.t.bits |= DECNEG;                                                \
1221fcf5ef2aSThomas Huth     }                                                                        \
1222474c2e93SMark Cave-Ayland     dfp_finalize_decimal##size(&dfp);                                        \
1223fcf5ef2aSThomas Huth     dfp_set_FPRF_from_FRT(&dfp);                                             \
1224f6d4c423SMark Cave-Ayland     set_dfp##size(t, &dfp.vt);                                               \
1225fcf5ef2aSThomas Huth }
1226fcf5ef2aSThomas Huth 
1227a2329747SLuis Pires DFP_HELPER_ENBCD(DENBCD, 64)
1228a2329747SLuis Pires DFP_HELPER_ENBCD(DENBCDQ, 128)
1229fcf5ef2aSThomas Huth 
1230fcf5ef2aSThomas Huth #define DFP_HELPER_XEX(op, size)                               \
1231d9acba31SMark Cave-Ayland void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \
1232fcf5ef2aSThomas Huth {                                                              \
1233fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                        \
123464b8574eSMark Cave-Ayland     ppc_vsr_t vt;                                              \
1235fcf5ef2aSThomas Huth                                                                \
1236fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, 0, b, env);                \
1237fcf5ef2aSThomas Huth                                                                \
1238fcf5ef2aSThomas Huth     if (unlikely(decNumberIsSpecial(&dfp.b))) {                \
1239fcf5ef2aSThomas Huth         if (decNumberIsInfinite(&dfp.b)) {                     \
124064b8574eSMark Cave-Ayland             vt.VsrD(1) = -1;                                   \
1241fcf5ef2aSThomas Huth         } else if (decNumberIsSNaN(&dfp.b)) {                  \
124264b8574eSMark Cave-Ayland             vt.VsrD(1) = -3;                                   \
1243fcf5ef2aSThomas Huth         } else if (decNumberIsQNaN(&dfp.b)) {                  \
124464b8574eSMark Cave-Ayland             vt.VsrD(1) = -2;                                   \
1245fcf5ef2aSThomas Huth         } else {                                               \
1246*52d9ffd8SPierrick Bouvier             g_assert_not_reached();                            \
1247fcf5ef2aSThomas Huth         }                                                      \
124864b8574eSMark Cave-Ayland         set_dfp64(t, &vt);                                     \
1249fcf5ef2aSThomas Huth     } else {                                                   \
1250fcf5ef2aSThomas Huth         if ((size) == 64) {                                    \
125164b8574eSMark Cave-Ayland             vt.VsrD(1) = dfp.b.exponent + 398;                 \
1252fcf5ef2aSThomas Huth         } else if ((size) == 128) {                            \
125364b8574eSMark Cave-Ayland             vt.VsrD(1) = dfp.b.exponent + 6176;                \
1254fcf5ef2aSThomas Huth         } else {                                               \
1255*52d9ffd8SPierrick Bouvier             g_assert_not_reached();                            \
1256fcf5ef2aSThomas Huth         }                                                      \
125764b8574eSMark Cave-Ayland         set_dfp64(t, &vt);                                     \
1258fcf5ef2aSThomas Huth     }                                                          \
1259fcf5ef2aSThomas Huth }
1260fcf5ef2aSThomas Huth 
1261c8ef4d1eSLuis Pires DFP_HELPER_XEX(DXEX, 64)
1262c8ef4d1eSLuis Pires DFP_HELPER_XEX(DXEXQ, 128)
1263fcf5ef2aSThomas Huth 
dfp_set_raw_exp_64(ppc_vsr_t * t,uint64_t raw)12641ea80bf7SMark Cave-Ayland static void dfp_set_raw_exp_64(ppc_vsr_t *t, uint64_t raw)
1265fcf5ef2aSThomas Huth {
12661ea80bf7SMark Cave-Ayland     t->VsrD(1) &= 0x8003ffffffffffffULL;
12671ea80bf7SMark Cave-Ayland     t->VsrD(1) |= (raw << (63 - 13));
1268fcf5ef2aSThomas Huth }
1269fcf5ef2aSThomas Huth 
dfp_set_raw_exp_128(ppc_vsr_t * t,uint64_t raw)12701ea80bf7SMark Cave-Ayland static void dfp_set_raw_exp_128(ppc_vsr_t *t, uint64_t raw)
1271fcf5ef2aSThomas Huth {
12721ea80bf7SMark Cave-Ayland     t->VsrD(0) &= 0x80003fffffffffffULL;
12731ea80bf7SMark Cave-Ayland     t->VsrD(0) |= (raw << (63 - 17));
1274fcf5ef2aSThomas Huth }
1275fcf5ef2aSThomas Huth 
1276fcf5ef2aSThomas Huth #define DFP_HELPER_IEX(op, size)                                          \
1277d9acba31SMark Cave-Ayland void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a,          \
1278d9acba31SMark Cave-Ayland                  ppc_fprp_t *b)                                           \
1279fcf5ef2aSThomas Huth {                                                                         \
1280fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                                   \
128164b8574eSMark Cave-Ayland     uint64_t raw_qnan, raw_snan, raw_inf, max_exp;                        \
128264b8574eSMark Cave-Ayland     ppc_vsr_t va;                                                         \
1283fcf5ef2aSThomas Huth     int bias;                                                             \
12846a8fbb9bSMark Cave-Ayland     int64_t exp;                                                          \
1285fcf5ef2aSThomas Huth                                                                           \
128664b8574eSMark Cave-Ayland     get_dfp64(&va, a);                                                    \
128764b8574eSMark Cave-Ayland     exp = (int64_t)va.VsrD(1);                                            \
1288fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, 0, b, env);                           \
1289fcf5ef2aSThomas Huth                                                                           \
1290fcf5ef2aSThomas Huth     if ((size) == 64) {                                                   \
1291fcf5ef2aSThomas Huth         max_exp = 767;                                                    \
1292fcf5ef2aSThomas Huth         raw_qnan = 0x1F00;                                                \
1293fcf5ef2aSThomas Huth         raw_snan = 0x1F80;                                                \
1294fcf5ef2aSThomas Huth         raw_inf = 0x1E00;                                                 \
1295fcf5ef2aSThomas Huth         bias = 398;                                                       \
1296fcf5ef2aSThomas Huth     } else if ((size) == 128) {                                           \
1297fcf5ef2aSThomas Huth         max_exp = 12287;                                                  \
1298fcf5ef2aSThomas Huth         raw_qnan = 0x1f000;                                               \
1299fcf5ef2aSThomas Huth         raw_snan = 0x1f800;                                               \
1300fcf5ef2aSThomas Huth         raw_inf = 0x1e000;                                                \
1301fcf5ef2aSThomas Huth         bias = 6176;                                                      \
1302fcf5ef2aSThomas Huth     } else {                                                              \
1303*52d9ffd8SPierrick Bouvier         g_assert_not_reached();                                           \
1304fcf5ef2aSThomas Huth     }                                                                     \
1305fcf5ef2aSThomas Huth                                                                           \
1306fcf5ef2aSThomas Huth     if (unlikely((exp < 0) || (exp > max_exp))) {                         \
130764b8574eSMark Cave-Ayland         dfp.vt.VsrD(0) = dfp.vb.VsrD(0);                                  \
130864b8574eSMark Cave-Ayland         dfp.vt.VsrD(1) = dfp.vb.VsrD(1);                                  \
1309fcf5ef2aSThomas Huth         if (exp == -1) {                                                  \
13101ea80bf7SMark Cave-Ayland             dfp_set_raw_exp_##size(&dfp.vt, raw_inf);                     \
1311fcf5ef2aSThomas Huth         } else if (exp == -3) {                                           \
13121ea80bf7SMark Cave-Ayland             dfp_set_raw_exp_##size(&dfp.vt, raw_snan);                    \
1313fcf5ef2aSThomas Huth         } else {                                                          \
13141ea80bf7SMark Cave-Ayland             dfp_set_raw_exp_##size(&dfp.vt, raw_qnan);                    \
1315fcf5ef2aSThomas Huth         }                                                                 \
1316fcf5ef2aSThomas Huth     } else {                                                              \
1317fcf5ef2aSThomas Huth         dfp.t = dfp.b;                                                    \
1318fcf5ef2aSThomas Huth         if (unlikely(decNumberIsSpecial(&dfp.t))) {                       \
1319fcf5ef2aSThomas Huth             dfp.t.bits &= ~DECSPECIAL;                                    \
1320fcf5ef2aSThomas Huth         }                                                                 \
1321fcf5ef2aSThomas Huth         dfp.t.exponent = exp - bias;                                      \
1322474c2e93SMark Cave-Ayland         dfp_finalize_decimal##size(&dfp);                                 \
1323fcf5ef2aSThomas Huth     }                                                                     \
1324f6d4c423SMark Cave-Ayland     set_dfp##size(t, &dfp.vt);                                            \
1325fcf5ef2aSThomas Huth }
1326fcf5ef2aSThomas Huth 
1327afdc9310SLuis Pires DFP_HELPER_IEX(DIEX, 64)
1328afdc9310SLuis Pires DFP_HELPER_IEX(DIEXQ, 128)
1329fcf5ef2aSThomas Huth 
dfp_clear_lmd_from_g5msb(uint64_t * t)1330fcf5ef2aSThomas Huth static void dfp_clear_lmd_from_g5msb(uint64_t *t)
1331fcf5ef2aSThomas Huth {
1332fcf5ef2aSThomas Huth 
1333fcf5ef2aSThomas Huth     /* The most significant 5 bits of the PowerPC DFP format combine bits  */
1334fcf5ef2aSThomas Huth     /* from the left-most decimal digit (LMD) and the biased exponent.     */
1335fcf5ef2aSThomas Huth     /* This  routine clears the LMD bits while preserving the exponent     */
1336fcf5ef2aSThomas Huth     /*  bits.  See "Figure 80: Encoding of bits 0:4 of the G field for     */
1337fcf5ef2aSThomas Huth     /*  Finite Numbers" in the Power ISA for additional details.           */
1338fcf5ef2aSThomas Huth 
1339fcf5ef2aSThomas Huth     uint64_t g5msb = (*t >> 58) & 0x1F;
1340fcf5ef2aSThomas Huth 
1341fcf5ef2aSThomas Huth     if ((g5msb >> 3) < 3) { /* LMD in [0-7] ? */
1342fcf5ef2aSThomas Huth        *t &= ~(7ULL << 58);
1343fcf5ef2aSThomas Huth     } else {
1344fcf5ef2aSThomas Huth        switch (g5msb & 7) {
1345fcf5ef2aSThomas Huth        case 0:
1346fcf5ef2aSThomas Huth        case 1:
1347fcf5ef2aSThomas Huth            g5msb = 0;
1348fcf5ef2aSThomas Huth            break;
1349fcf5ef2aSThomas Huth        case 2:
1350fcf5ef2aSThomas Huth        case 3:
1351fcf5ef2aSThomas Huth            g5msb = 0x8;
1352fcf5ef2aSThomas Huth            break;
1353fcf5ef2aSThomas Huth        case 4:
1354fcf5ef2aSThomas Huth        case 5:
1355fcf5ef2aSThomas Huth            g5msb = 0x10;
1356fcf5ef2aSThomas Huth            break;
1357fcf5ef2aSThomas Huth        case 6:
1358fcf5ef2aSThomas Huth            g5msb = 0x1E;
1359fcf5ef2aSThomas Huth            break;
1360fcf5ef2aSThomas Huth        case 7:
1361fcf5ef2aSThomas Huth            g5msb = 0x1F;
1362fcf5ef2aSThomas Huth            break;
1363fcf5ef2aSThomas Huth        }
1364fcf5ef2aSThomas Huth 
1365fcf5ef2aSThomas Huth         *t &= ~(0x1fULL << 58);
1366fcf5ef2aSThomas Huth         *t |= (g5msb << 58);
1367fcf5ef2aSThomas Huth     }
1368fcf5ef2aSThomas Huth }
1369fcf5ef2aSThomas Huth 
1370fcf5ef2aSThomas Huth #define DFP_HELPER_SHIFT(op, size, shift_left)                      \
1371d9acba31SMark Cave-Ayland void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a,    \
1372fcf5ef2aSThomas Huth                  uint32_t sh)                                       \
1373fcf5ef2aSThomas Huth {                                                                   \
1374fcf5ef2aSThomas Huth     struct PPC_DFP dfp;                                             \
1375fcf5ef2aSThomas Huth     unsigned max_digits = ((size) == 64) ? 16 : 34;                 \
1376fcf5ef2aSThomas Huth                                                                     \
1377fcf5ef2aSThomas Huth     dfp_prepare_decimal##size(&dfp, a, 0, env);                     \
1378fcf5ef2aSThomas Huth                                                                     \
1379fcf5ef2aSThomas Huth     if (sh <= max_digits) {                                         \
1380fcf5ef2aSThomas Huth                                                                     \
1381fcf5ef2aSThomas Huth         decNumber shd;                                              \
1382fcf5ef2aSThomas Huth         unsigned special = dfp.a.bits & DECSPECIAL;                 \
1383fcf5ef2aSThomas Huth                                                                     \
1384fcf5ef2aSThomas Huth         if (shift_left) {                                           \
1385fcf5ef2aSThomas Huth             decNumberFromUInt32(&shd, sh);                          \
1386fcf5ef2aSThomas Huth         } else {                                                    \
1387fcf5ef2aSThomas Huth             decNumberFromInt32(&shd, -((int32_t)sh));               \
1388fcf5ef2aSThomas Huth         }                                                           \
1389fcf5ef2aSThomas Huth                                                                     \
1390fcf5ef2aSThomas Huth         dfp.a.bits &= ~DECSPECIAL;                                  \
1391fcf5ef2aSThomas Huth         decNumberShift(&dfp.t, &dfp.a, &shd, &dfp.context);         \
1392fcf5ef2aSThomas Huth                                                                     \
1393fcf5ef2aSThomas Huth         dfp.t.bits |= special;                                      \
1394fcf5ef2aSThomas Huth         if (special && (dfp.t.digits >= max_digits)) {              \
1395fcf5ef2aSThomas Huth             dfp.t.digits = max_digits - 1;                          \
1396fcf5ef2aSThomas Huth         }                                                           \
1397fcf5ef2aSThomas Huth                                                                     \
1398474c2e93SMark Cave-Ayland         dfp_finalize_decimal##size(&dfp);                           \
1399fcf5ef2aSThomas Huth     } else {                                                        \
1400fcf5ef2aSThomas Huth         if ((size) == 64) {                                         \
140164b8574eSMark Cave-Ayland             dfp.vt.VsrD(1) = dfp.va.VsrD(1) &                       \
140264b8574eSMark Cave-Ayland                              0xFFFC000000000000ULL;                 \
140364b8574eSMark Cave-Ayland             dfp_clear_lmd_from_g5msb(&dfp.vt.VsrD(1));              \
1404fcf5ef2aSThomas Huth         } else {                                                    \
140564b8574eSMark Cave-Ayland             dfp.vt.VsrD(0) = dfp.va.VsrD(0) &                       \
1406fcf5ef2aSThomas Huth                              0xFFFFC00000000000ULL;                 \
140764b8574eSMark Cave-Ayland             dfp_clear_lmd_from_g5msb(&dfp.vt.VsrD(0));              \
140864b8574eSMark Cave-Ayland             dfp.vt.VsrD(1) = 0;                                     \
1409fcf5ef2aSThomas Huth         }                                                           \
1410fcf5ef2aSThomas Huth     }                                                               \
1411fcf5ef2aSThomas Huth                                                                     \
1412f6d4c423SMark Cave-Ayland     set_dfp##size(t, &dfp.vt);                                      \
1413fcf5ef2aSThomas Huth }
1414fcf5ef2aSThomas Huth 
1415a2329747SLuis Pires DFP_HELPER_SHIFT(DSCLI, 64, 1)
1416a2329747SLuis Pires DFP_HELPER_SHIFT(DSCLIQ, 128, 1)
1417a2329747SLuis Pires DFP_HELPER_SHIFT(DSCRI, 64, 0)
1418a2329747SLuis Pires DFP_HELPER_SHIFT(DSCRIQ, 128, 0)
141938d3690bSMatheus Ferst 
helper_CDTBCD(target_ulong s)14206b924d4aSMatheus Ferst target_ulong helper_CDTBCD(target_ulong s)
14216b924d4aSMatheus Ferst {
14226b924d4aSMatheus Ferst     uint64_t res = 0;
14236b924d4aSMatheus Ferst     uint32_t dec32, declets;
14246b924d4aSMatheus Ferst     uint8_t bcd[6];
14256b924d4aSMatheus Ferst     int i, w, sh;
14266b924d4aSMatheus Ferst     decNumber a;
14276b924d4aSMatheus Ferst 
14286b924d4aSMatheus Ferst     for (w = 1; w >= 0; w--) {
14296b924d4aSMatheus Ferst         res <<= 32;
14306b924d4aSMatheus Ferst         declets = extract64(s, 32 * w, 20);
14316b924d4aSMatheus Ferst         if (declets) {
14326b924d4aSMatheus Ferst             /* decimal32 with zero exponent and word "w" declets */
14336b924d4aSMatheus Ferst             dec32 = (0x225ULL << 20) | declets;
14346b924d4aSMatheus Ferst             decimal32ToNumber((decimal32 *)&dec32, &a);
14356b924d4aSMatheus Ferst             decNumberGetBCD(&a, bcd);
14366b924d4aSMatheus Ferst             for (i = 0; i < a.digits; i++) {
14376b924d4aSMatheus Ferst                 sh = 4 * (a.digits - 1 - i);
14386b924d4aSMatheus Ferst                 res |= (uint64_t)bcd[i] << sh;
14396b924d4aSMatheus Ferst             }
14406b924d4aSMatheus Ferst         }
14416b924d4aSMatheus Ferst     }
14426b924d4aSMatheus Ferst 
14436b924d4aSMatheus Ferst     return res;
14446b924d4aSMatheus Ferst }
14456b924d4aSMatheus Ferst 
helper_CBCDTD(target_ulong s)144638d3690bSMatheus Ferst target_ulong helper_CBCDTD(target_ulong s)
144738d3690bSMatheus Ferst {
144838d3690bSMatheus Ferst     uint64_t res = 0;
144938d3690bSMatheus Ferst     uint32_t dec32;
145038d3690bSMatheus Ferst     uint8_t bcd[6];
145138d3690bSMatheus Ferst     int w, i, offs;
145238d3690bSMatheus Ferst     decNumber a;
145338d3690bSMatheus Ferst     decContext context;
145438d3690bSMatheus Ferst 
145538d3690bSMatheus Ferst     decContextDefault(&context, DEC_INIT_DECIMAL32);
145638d3690bSMatheus Ferst 
145738d3690bSMatheus Ferst     for (w = 1; w >= 0; w--) {
145838d3690bSMatheus Ferst         res <<= 32;
145938d3690bSMatheus Ferst         decNumberZero(&a);
146038d3690bSMatheus Ferst         /* Extract each BCD field of word "w" */
146138d3690bSMatheus Ferst         for (i = 5; i >= 0; i--) {
146238d3690bSMatheus Ferst             offs = 4 * (5 - i) + 32 * w;
146338d3690bSMatheus Ferst             bcd[i] = extract64(s, offs, 4);
146438d3690bSMatheus Ferst             if (bcd[i] > 9) {
146538d3690bSMatheus Ferst                 /*
146638d3690bSMatheus Ferst                  * If the field value is greater than 9, the results are
146738d3690bSMatheus Ferst                  * undefined. We could use a fixed value like 0 or 9, but
146838d3690bSMatheus Ferst                  * an and with 9 seems to better match the hardware behavior.
146938d3690bSMatheus Ferst                  */
147038d3690bSMatheus Ferst                 bcd[i] &= 9;
147138d3690bSMatheus Ferst             }
147238d3690bSMatheus Ferst         }
147338d3690bSMatheus Ferst 
147438d3690bSMatheus Ferst         /* Create a decNumber with the BCD values and convert to decimal32 */
147538d3690bSMatheus Ferst         decNumberSetBCD(&a, bcd, 6);
147638d3690bSMatheus Ferst         decimal32FromNumber((decimal32 *)&dec32, &a, &context);
147738d3690bSMatheus Ferst 
147838d3690bSMatheus Ferst         /* Extract the two declets from the decimal32 value */
147938d3690bSMatheus Ferst         res |= dec32 & 0xfffff;
148038d3690bSMatheus Ferst     }
148138d3690bSMatheus Ferst 
148238d3690bSMatheus Ferst     return res;
148338d3690bSMatheus Ferst }
1484