Add qemu 2.4.0
[kvmfornfv.git] / qemu / target-alpha / vax_helper.c
1 /*
2  *  Helpers for vax floating point instructions.
3  *
4  *  Copyright (c) 2007 Jocelyn Mayer
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "cpu.h"
21 #include "exec/helper-proto.h"
22 #include "fpu/softfloat.h"
23
24 #define FP_STATUS (env->fp_status)
25
26
27 /* F floating (VAX) */
28 static uint64_t float32_to_f(float32 fa)
29 {
30     uint64_t r, exp, mant, sig;
31     CPU_FloatU a;
32
33     a.f = fa;
34     sig = ((uint64_t)a.l & 0x80000000) << 32;
35     exp = (a.l >> 23) & 0xff;
36     mant = ((uint64_t)a.l & 0x007fffff) << 29;
37
38     if (exp == 255) {
39         /* NaN or infinity */
40         r = 1; /* VAX dirty zero */
41     } else if (exp == 0) {
42         if (mant == 0) {
43             /* Zero */
44             r = 0;
45         } else {
46             /* Denormalized */
47             r = sig | ((exp + 1) << 52) | mant;
48         }
49     } else {
50         if (exp >= 253) {
51             /* Overflow */
52             r = 1; /* VAX dirty zero */
53         } else {
54             r = sig | ((exp + 2) << 52);
55         }
56     }
57
58     return r;
59 }
60
61 static float32 f_to_float32(CPUAlphaState *env, uintptr_t retaddr, uint64_t a)
62 {
63     uint32_t exp, mant_sig;
64     CPU_FloatU r;
65
66     exp = ((a >> 55) & 0x80) | ((a >> 52) & 0x7f);
67     mant_sig = ((a >> 32) & 0x80000000) | ((a >> 29) & 0x007fffff);
68
69     if (unlikely(!exp && mant_sig)) {
70         /* Reserved operands / Dirty zero */
71         dynamic_excp(env, retaddr, EXCP_OPCDEC, 0);
72     }
73
74     if (exp < 3) {
75         /* Underflow */
76         r.l = 0;
77     } else {
78         r.l = ((exp - 2) << 23) | mant_sig;
79     }
80
81     return r.f;
82 }
83
84 uint32_t helper_f_to_memory(uint64_t a)
85 {
86     uint32_t r;
87     r =  (a & 0x00001fffe0000000ull) >> 13;
88     r |= (a & 0x07ffe00000000000ull) >> 45;
89     r |= (a & 0xc000000000000000ull) >> 48;
90     return r;
91 }
92
93 uint64_t helper_memory_to_f(uint32_t a)
94 {
95     uint64_t r;
96     r =  ((uint64_t)(a & 0x0000c000)) << 48;
97     r |= ((uint64_t)(a & 0x003fffff)) << 45;
98     r |= ((uint64_t)(a & 0xffff0000)) << 13;
99     if (!(a & 0x00004000)) {
100         r |= 0x7ll << 59;
101     }
102     return r;
103 }
104
105 /* ??? Emulating VAX arithmetic with IEEE arithmetic is wrong.  We should
106    either implement VAX arithmetic properly or just signal invalid opcode.  */
107
108 uint64_t helper_addf(CPUAlphaState *env, uint64_t a, uint64_t b)
109 {
110     float32 fa, fb, fr;
111
112     fa = f_to_float32(env, GETPC(), a);
113     fb = f_to_float32(env, GETPC(), b);
114     fr = float32_add(fa, fb, &FP_STATUS);
115     return float32_to_f(fr);
116 }
117
118 uint64_t helper_subf(CPUAlphaState *env, uint64_t a, uint64_t b)
119 {
120     float32 fa, fb, fr;
121
122     fa = f_to_float32(env, GETPC(), a);
123     fb = f_to_float32(env, GETPC(), b);
124     fr = float32_sub(fa, fb, &FP_STATUS);
125     return float32_to_f(fr);
126 }
127
128 uint64_t helper_mulf(CPUAlphaState *env, uint64_t a, uint64_t b)
129 {
130     float32 fa, fb, fr;
131
132     fa = f_to_float32(env, GETPC(), a);
133     fb = f_to_float32(env, GETPC(), b);
134     fr = float32_mul(fa, fb, &FP_STATUS);
135     return float32_to_f(fr);
136 }
137
138 uint64_t helper_divf(CPUAlphaState *env, uint64_t a, uint64_t b)
139 {
140     float32 fa, fb, fr;
141
142     fa = f_to_float32(env, GETPC(), a);
143     fb = f_to_float32(env, GETPC(), b);
144     fr = float32_div(fa, fb, &FP_STATUS);
145     return float32_to_f(fr);
146 }
147
148 uint64_t helper_sqrtf(CPUAlphaState *env, uint64_t t)
149 {
150     float32 ft, fr;
151
152     ft = f_to_float32(env, GETPC(), t);
153     fr = float32_sqrt(ft, &FP_STATUS);
154     return float32_to_f(fr);
155 }
156
157
158 /* G floating (VAX) */
159 static uint64_t float64_to_g(float64 fa)
160 {
161     uint64_t r, exp, mant, sig;
162     CPU_DoubleU a;
163
164     a.d = fa;
165     sig = a.ll & 0x8000000000000000ull;
166     exp = (a.ll >> 52) & 0x7ff;
167     mant = a.ll & 0x000fffffffffffffull;
168
169     if (exp == 2047) {
170         /* NaN or infinity */
171         r = 1; /* VAX dirty zero */
172     } else if (exp == 0) {
173         if (mant == 0) {
174             /* Zero */
175             r = 0;
176         } else {
177             /* Denormalized */
178             r = sig | ((exp + 1) << 52) | mant;
179         }
180     } else {
181         if (exp >= 2045) {
182             /* Overflow */
183             r = 1; /* VAX dirty zero */
184         } else {
185             r = sig | ((exp + 2) << 52);
186         }
187     }
188
189     return r;
190 }
191
192 static float64 g_to_float64(CPUAlphaState *env, uintptr_t retaddr, uint64_t a)
193 {
194     uint64_t exp, mant_sig;
195     CPU_DoubleU r;
196
197     exp = (a >> 52) & 0x7ff;
198     mant_sig = a & 0x800fffffffffffffull;
199
200     if (!exp && mant_sig) {
201         /* Reserved operands / Dirty zero */
202         dynamic_excp(env, retaddr, EXCP_OPCDEC, 0);
203     }
204
205     if (exp < 3) {
206         /* Underflow */
207         r.ll = 0;
208     } else {
209         r.ll = ((exp - 2) << 52) | mant_sig;
210     }
211
212     return r.d;
213 }
214
215 uint64_t helper_g_to_memory(uint64_t a)
216 {
217     uint64_t r;
218     r =  (a & 0x000000000000ffffull) << 48;
219     r |= (a & 0x00000000ffff0000ull) << 16;
220     r |= (a & 0x0000ffff00000000ull) >> 16;
221     r |= (a & 0xffff000000000000ull) >> 48;
222     return r;
223 }
224
225 uint64_t helper_memory_to_g(uint64_t a)
226 {
227     uint64_t r;
228     r =  (a & 0x000000000000ffffull) << 48;
229     r |= (a & 0x00000000ffff0000ull) << 16;
230     r |= (a & 0x0000ffff00000000ull) >> 16;
231     r |= (a & 0xffff000000000000ull) >> 48;
232     return r;
233 }
234
235 uint64_t helper_addg(CPUAlphaState *env, uint64_t a, uint64_t b)
236 {
237     float64 fa, fb, fr;
238
239     fa = g_to_float64(env, GETPC(), a);
240     fb = g_to_float64(env, GETPC(), b);
241     fr = float64_add(fa, fb, &FP_STATUS);
242     return float64_to_g(fr);
243 }
244
245 uint64_t helper_subg(CPUAlphaState *env, uint64_t a, uint64_t b)
246 {
247     float64 fa, fb, fr;
248
249     fa = g_to_float64(env, GETPC(), a);
250     fb = g_to_float64(env, GETPC(), b);
251     fr = float64_sub(fa, fb, &FP_STATUS);
252     return float64_to_g(fr);
253 }
254
255 uint64_t helper_mulg(CPUAlphaState *env, uint64_t a, uint64_t b)
256 {
257     float64 fa, fb, fr;
258
259     fa = g_to_float64(env, GETPC(), a);
260     fb = g_to_float64(env, GETPC(), b);
261     fr = float64_mul(fa, fb, &FP_STATUS);
262     return float64_to_g(fr);
263 }
264
265 uint64_t helper_divg(CPUAlphaState *env, uint64_t a, uint64_t b)
266 {
267     float64 fa, fb, fr;
268
269     fa = g_to_float64(env, GETPC(), a);
270     fb = g_to_float64(env, GETPC(), b);
271     fr = float64_div(fa, fb, &FP_STATUS);
272     return float64_to_g(fr);
273 }
274
275 uint64_t helper_sqrtg(CPUAlphaState *env, uint64_t a)
276 {
277     float64 fa, fr;
278
279     fa = g_to_float64(env, GETPC(), a);
280     fr = float64_sqrt(fa, &FP_STATUS);
281     return float64_to_g(fr);
282 }
283
284 uint64_t helper_cmpgeq(CPUAlphaState *env, uint64_t a, uint64_t b)
285 {
286     float64 fa, fb;
287
288     fa = g_to_float64(env, GETPC(), a);
289     fb = g_to_float64(env, GETPC(), b);
290
291     if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
292         return 0x4000000000000000ULL;
293     } else {
294         return 0;
295     }
296 }
297
298 uint64_t helper_cmpgle(CPUAlphaState *env, uint64_t a, uint64_t b)
299 {
300     float64 fa, fb;
301
302     fa = g_to_float64(env, GETPC(), a);
303     fb = g_to_float64(env, GETPC(), b);
304
305     if (float64_le(fa, fb, &FP_STATUS)) {
306         return 0x4000000000000000ULL;
307     } else {
308         return 0;
309     }
310 }
311
312 uint64_t helper_cmpglt(CPUAlphaState *env, uint64_t a, uint64_t b)
313 {
314     float64 fa, fb;
315
316     fa = g_to_float64(env, GETPC(), a);
317     fb = g_to_float64(env, GETPC(), b);
318
319     if (float64_lt(fa, fb, &FP_STATUS)) {
320         return 0x4000000000000000ULL;
321     } else {
322         return 0;
323     }
324 }
325
326 uint64_t helper_cvtqf(CPUAlphaState *env, uint64_t a)
327 {
328     float32 fr = int64_to_float32(a, &FP_STATUS);
329     return float32_to_f(fr);
330 }
331
332 uint64_t helper_cvtgf(CPUAlphaState *env, uint64_t a)
333 {
334     float64 fa;
335     float32 fr;
336
337     fa = g_to_float64(env, GETPC(), a);
338     fr = float64_to_float32(fa, &FP_STATUS);
339     return float32_to_f(fr);
340 }
341
342 uint64_t helper_cvtgq(CPUAlphaState *env, uint64_t a)
343 {
344     float64 fa = g_to_float64(env, GETPC(), a);
345     return float64_to_int64_round_to_zero(fa, &FP_STATUS);
346 }
347
348 uint64_t helper_cvtqg(CPUAlphaState *env, uint64_t a)
349 {
350     float64 fr;
351     fr = int64_to_float64(a, &FP_STATUS);
352     return float64_to_g(fr);
353 }