]> Git Repo - qemu.git/blob - target-ppc/dfp_helper.c
target-ppc: Introduce DFP Add
[qemu.git] / target-ppc / dfp_helper.c
1 /*
2  *  PowerPC Decimal Floating Point (DPF) emulation helpers for QEMU.
3  *
4  *  Copyright (c) 2014 IBM Corporation.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "cpu.h"
21 #include "exec/helper-proto.h"
22
23 #define DECNUMDIGITS 34
24 #include "libdecnumber/decContext.h"
25 #include "libdecnumber/decNumber.h"
26 #include "libdecnumber/dpd/decimal32.h"
27 #include "libdecnumber/dpd/decimal64.h"
28 #include "libdecnumber/dpd/decimal128.h"
29
30 #if defined(HOST_WORDS_BIGENDIAN)
31 #define HI_IDX 0
32 #define LO_IDX 1
33 #else
34 #define HI_IDX 1
35 #define LO_IDX 0
36 #endif
37
38 struct PPC_DFP {
39     CPUPPCState *env;
40     uint64_t t64[2], a64[2], b64[2];
41     decNumber t, a, b;
42     decContext context;
43     uint8_t crbf;
44 };
45
46 static void dfp_prepare_rounding_mode(decContext *context, uint64_t fpscr)
47 {
48     enum rounding rnd;
49
50     switch ((fpscr >> 32) & 0x7) {
51     case 0:
52         rnd = DEC_ROUND_HALF_EVEN;
53         break;
54     case 1:
55         rnd = DEC_ROUND_DOWN;
56         break;
57     case 2:
58          rnd = DEC_ROUND_CEILING;
59          break;
60     case 3:
61          rnd = DEC_ROUND_FLOOR;
62          break;
63     case 4:
64          rnd = DEC_ROUND_HALF_UP;
65          break;
66     case 5:
67          rnd = DEC_ROUND_HALF_DOWN;
68          break;
69     case 6:
70          rnd = DEC_ROUND_UP;
71          break;
72     case 7:
73          rnd = DEC_ROUND_05UP;
74          break;
75     default:
76         g_assert_not_reached();
77     }
78
79     decContextSetRounding(context, rnd);
80 }
81
82 static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a,
83                 uint64_t *b, CPUPPCState *env)
84 {
85     decContextDefault(&dfp->context, DEC_INIT_DECIMAL64);
86     dfp_prepare_rounding_mode(&dfp->context, env->fpscr);
87     dfp->env = env;
88
89     if (a) {
90         dfp->a64[0] = *a;
91         decimal64ToNumber((decimal64 *)dfp->a64, &dfp->a);
92     } else {
93         dfp->a64[0] = 0;
94         decNumberZero(&dfp->a);
95     }
96
97     if (b) {
98         dfp->b64[0] = *b;
99         decimal64ToNumber((decimal64 *)dfp->b64, &dfp->b);
100     } else {
101         dfp->b64[0] = 0;
102         decNumberZero(&dfp->b);
103     }
104 }
105
106 static void dfp_prepare_decimal128(struct PPC_DFP *dfp, uint64_t *a,
107                 uint64_t *b, CPUPPCState *env)
108 {
109     decContextDefault(&dfp->context, DEC_INIT_DECIMAL128);
110     dfp_prepare_rounding_mode(&dfp->context, env->fpscr);
111     dfp->env = env;
112
113     if (a) {
114         dfp->a64[0] = a[HI_IDX];
115         dfp->a64[1] = a[LO_IDX];
116         decimal128ToNumber((decimal128 *)dfp->a64, &dfp->a);
117     } else {
118         dfp->a64[0] = dfp->a64[1] = 0;
119         decNumberZero(&dfp->a);
120     }
121
122     if (b) {
123         dfp->b64[0] = b[HI_IDX];
124         dfp->b64[1] = b[LO_IDX];
125         decimal128ToNumber((decimal128 *)dfp->b64, &dfp->b);
126     } else {
127         dfp->b64[0] = dfp->b64[1] = 0;
128         decNumberZero(&dfp->b);
129     }
130 }
131
132 #define FP_FX       (1ull << FPSCR_FX)
133 #define FP_FEX      (1ull << FPSCR_FEX)
134 #define FP_OX       (1ull << FPSCR_OX)
135 #define FP_OE       (1ull << FPSCR_OE)
136 #define FP_UX       (1ull << FPSCR_UX)
137 #define FP_UE       (1ull << FPSCR_UE)
138 #define FP_XX       (1ull << FPSCR_XX)
139 #define FP_XE       (1ull << FPSCR_XE)
140 #define FP_ZX       (1ull << FPSCR_ZX)
141 #define FP_ZE       (1ull << FPSCR_ZE)
142 #define FP_VX       (1ull << FPSCR_VX)
143 #define FP_VXSNAN   (1ull << FPSCR_VXSNAN)
144 #define FP_VXISI    (1ull << FPSCR_VXISI)
145 #define FP_VXIMZ    (1ull << FPSCR_VXIMZ)
146 #define FP_VXZDZ    (1ull << FPSCR_VXZDZ)
147 #define FP_VXIDI    (1ull << FPSCR_VXIDI)
148 #define FP_VXVC     (1ull << FPSCR_VXVC)
149 #define FP_VXCVI    (1ull << FPSCR_VXCVI)
150 #define FP_VE       (1ull << FPSCR_VE)
151 #define FP_FI       (1ull << FPSCR_FI)
152
153 static void dfp_set_FPSCR_flag(struct PPC_DFP *dfp, uint64_t flag,
154                 uint64_t enabled)
155 {
156     dfp->env->fpscr |= (flag | FP_FX);
157     if (dfp->env->fpscr & enabled) {
158         dfp->env->fpscr |= FP_FEX;
159     }
160 }
161
162 static void dfp_set_FPRF_from_FRT_with_context(struct PPC_DFP *dfp,
163                 decContext *context)
164 {
165     uint64_t fprf = 0;
166
167     /* construct FPRF */
168     switch (decNumberClass(&dfp->t, context)) {
169     case DEC_CLASS_SNAN:
170         fprf = 0x01;
171         break;
172     case DEC_CLASS_QNAN:
173         fprf = 0x11;
174         break;
175     case DEC_CLASS_NEG_INF:
176         fprf = 0x09;
177         break;
178     case DEC_CLASS_NEG_NORMAL:
179         fprf = 0x08;
180         break;
181     case DEC_CLASS_NEG_SUBNORMAL:
182         fprf = 0x18;
183         break;
184     case DEC_CLASS_NEG_ZERO:
185         fprf = 0x12;
186         break;
187     case DEC_CLASS_POS_ZERO:
188         fprf = 0x02;
189         break;
190     case DEC_CLASS_POS_SUBNORMAL:
191         fprf = 0x14;
192         break;
193     case DEC_CLASS_POS_NORMAL:
194         fprf = 0x04;
195         break;
196     case DEC_CLASS_POS_INF:
197         fprf = 0x05;
198         break;
199     default:
200         assert(0); /* should never get here */
201     }
202     dfp->env->fpscr &= ~(0x1F << 12);
203     dfp->env->fpscr |= (fprf << 12);
204 }
205
206 static void dfp_set_FPRF_from_FRT(struct PPC_DFP *dfp)
207 {
208     dfp_set_FPRF_from_FRT_with_context(dfp, &dfp->context);
209 }
210
211 static void dfp_check_for_OX(struct PPC_DFP *dfp)
212 {
213     if (dfp->context.status & DEC_Overflow) {
214         dfp_set_FPSCR_flag(dfp, FP_OX, FP_OE);
215     }
216 }
217
218 static void dfp_check_for_UX(struct PPC_DFP *dfp)
219 {
220     if (dfp->context.status & DEC_Underflow) {
221         dfp_set_FPSCR_flag(dfp, FP_UX, FP_UE);
222     }
223 }
224
225 static void dfp_check_for_XX(struct PPC_DFP *dfp)
226 {
227     if (dfp->context.status & DEC_Inexact) {
228         dfp_set_FPSCR_flag(dfp, FP_XX | FP_FI, FP_XE);
229     }
230 }
231
232 static void dfp_check_for_VXSNAN(struct PPC_DFP *dfp)
233 {
234     if (dfp->context.status & DEC_Invalid_operation) {
235         if (decNumberIsSNaN(&dfp->a) || decNumberIsSNaN(&dfp->b)) {
236             dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXSNAN, FP_VE);
237         }
238     }
239 }
240
241 static void dfp_check_for_VXISI(struct PPC_DFP *dfp, int testForSameSign)
242 {
243     if (dfp->context.status & DEC_Invalid_operation) {
244         if (decNumberIsInfinite(&dfp->a) && decNumberIsInfinite(&dfp->b)) {
245             int same = decNumberClass(&dfp->a, &dfp->context) ==
246                        decNumberClass(&dfp->b, &dfp->context);
247             if ((same && testForSameSign) || (!same && !testForSameSign)) {
248                 dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXISI, FP_VE);
249             }
250         }
251     }
252 }
253
254 static void dfp_check_for_VXISI_add(struct PPC_DFP *dfp)
255 {
256     dfp_check_for_VXISI(dfp, 0);
257 }
258
259 #define DFP_HELPER_TAB(op, dnop, postprocs, size)                              \
260 void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b)      \
261 {                                                                              \
262     struct PPC_DFP dfp;                                                        \
263     dfp_prepare_decimal##size(&dfp, a, b, env);                                \
264     dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context);                                \
265     decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \
266     postprocs(&dfp);                                                           \
267     if (size == 64) {                                                          \
268         t[0] = dfp.t64[0];                                                     \
269     } else if (size == 128) {                                                  \
270         t[0] = dfp.t64[HI_IDX];                                                \
271         t[1] = dfp.t64[LO_IDX];                                                \
272     }                                                                          \
273 }
274
275 static void ADD_PPs(struct PPC_DFP *dfp)
276 {
277     dfp_set_FPRF_from_FRT(dfp);
278     dfp_check_for_OX(dfp);
279     dfp_check_for_UX(dfp);
280     dfp_check_for_XX(dfp);
281     dfp_check_for_VXSNAN(dfp);
282     dfp_check_for_VXISI_add(dfp);
283 }
284
285 DFP_HELPER_TAB(dadd, decNumberAdd, ADD_PPs, 64)
286 DFP_HELPER_TAB(daddq, decNumberAdd, ADD_PPs, 128)
This page took 0.039814 seconds and 4 git commands to generate.