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