Add qemu 2.4.0
[kvmfornfv.git] / qemu / target-openrisc / fpu_helper.c
1 /*
2  * OpenRISC float helper routines
3  *
4  * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
5  *                         Feng Gao <gf91597@gmail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "cpu.h"
22 #include "exec/helper-proto.h"
23 #include "exception.h"
24
25 static inline uint32_t ieee_ex_to_openrisc(OpenRISCCPU *cpu, int fexcp)
26 {
27     int ret = 0;
28     if (fexcp) {
29         if (fexcp & float_flag_invalid) {
30             cpu->env.fpcsr |= FPCSR_IVF;
31             ret = 1;
32         }
33         if (fexcp & float_flag_overflow) {
34             cpu->env.fpcsr |= FPCSR_OVF;
35             ret = 1;
36         }
37         if (fexcp & float_flag_underflow) {
38             cpu->env.fpcsr |= FPCSR_UNF;
39             ret = 1;
40         }
41         if (fexcp & float_flag_divbyzero) {
42             cpu->env.fpcsr |= FPCSR_DZF;
43             ret = 1;
44         }
45         if (fexcp & float_flag_inexact) {
46             cpu->env.fpcsr |= FPCSR_IXF;
47             ret = 1;
48         }
49     }
50
51     return ret;
52 }
53
54 static inline void update_fpcsr(OpenRISCCPU *cpu)
55 {
56     int tmp = ieee_ex_to_openrisc(cpu,
57                               get_float_exception_flags(&cpu->env.fp_status));
58
59     SET_FP_CAUSE(cpu->env.fpcsr, tmp);
60     if ((GET_FP_ENABLE(cpu->env.fpcsr) & tmp) &&
61         (cpu->env.fpcsr & FPCSR_FPEE)) {
62         helper_exception(&cpu->env, EXCP_FPE);
63     } else {
64         UPDATE_FP_FLAGS(cpu->env.fpcsr, tmp);
65     }
66 }
67
68 uint64_t HELPER(itofd)(CPUOpenRISCState *env, uint64_t val)
69 {
70     uint64_t itofd;
71     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
72
73     set_float_exception_flags(0, &cpu->env.fp_status);
74     itofd = int32_to_float64(val, &cpu->env.fp_status);
75     update_fpcsr(cpu);
76
77     return itofd;
78 }
79
80 uint32_t HELPER(itofs)(CPUOpenRISCState *env, uint32_t val)
81 {
82     uint32_t itofs;
83     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
84
85     set_float_exception_flags(0, &cpu->env.fp_status);
86     itofs = int32_to_float32(val, &cpu->env.fp_status);
87     update_fpcsr(cpu);
88
89     return itofs;
90 }
91
92 uint64_t HELPER(ftoid)(CPUOpenRISCState *env, uint64_t val)
93 {
94     uint64_t ftoid;
95     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
96
97     set_float_exception_flags(0, &cpu->env.fp_status);
98     ftoid = float32_to_int64(val, &cpu->env.fp_status);
99     update_fpcsr(cpu);
100
101     return ftoid;
102 }
103
104 uint32_t HELPER(ftois)(CPUOpenRISCState *env, uint32_t val)
105 {
106     uint32_t ftois;
107     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
108
109     set_float_exception_flags(0, &cpu->env.fp_status);
110     ftois = float32_to_int32(val, &cpu->env.fp_status);
111     update_fpcsr(cpu);
112
113     return ftois;
114 }
115
116 #define FLOAT_OP(name, p) void helper_float_##_##p(void)
117
118 #define FLOAT_CALC(name)                                                  \
119 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env,               \
120                                      uint64_t fdt0, uint64_t fdt1)        \
121 {                                                                         \
122     uint64_t result;                                                      \
123     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
124     set_float_exception_flags(0, &cpu->env.fp_status);                    \
125     result = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status);           \
126     update_fpcsr(cpu);                                                    \
127     return result;                                                        \
128 }                                                                         \
129                                                                           \
130 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env,               \
131                                      uint32_t fdt0, uint32_t fdt1)        \
132 {                                                                         \
133     uint32_t result;                                                      \
134     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
135     set_float_exception_flags(0, &cpu->env.fp_status);                    \
136     result = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status);           \
137     update_fpcsr(cpu);                                                    \
138     return result;                                                        \
139 }                                                                         \
140
141 FLOAT_CALC(add)
142 FLOAT_CALC(sub)
143 FLOAT_CALC(mul)
144 FLOAT_CALC(div)
145 FLOAT_CALC(rem)
146 #undef FLOAT_CALC
147
148 #define FLOAT_TERNOP(name1, name2)                                        \
149 uint64_t helper_float_ ## name1 ## name2 ## _d(CPUOpenRISCState *env,     \
150                                                uint64_t fdt0,             \
151                                                uint64_t fdt1)             \
152 {                                                                         \
153     uint64_t result, temp, hi, lo;                                        \
154     uint32_t val1, val2;                                                  \
155     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
156     hi = env->fpmaddhi;                                                   \
157     lo = env->fpmaddlo;                                                   \
158     set_float_exception_flags(0, &cpu->env.fp_status);                    \
159     result = float64_ ## name1(fdt0, fdt1, &cpu->env.fp_status);          \
160     lo &= 0xffffffff;                                                     \
161     hi &= 0xffffffff;                                                     \
162     temp = (hi << 32) | lo;                                               \
163     result = float64_ ## name2(result, temp, &cpu->env.fp_status);        \
164     val1 = result >> 32;                                                  \
165     val2 = (uint32_t) (result & 0xffffffff);                              \
166     update_fpcsr(cpu);                                                    \
167     cpu->env.fpmaddlo = val2;                                             \
168     cpu->env.fpmaddhi = val1;                                             \
169     return 0;                                                             \
170 }                                                                         \
171                                                                           \
172 uint32_t helper_float_ ## name1 ## name2 ## _s(CPUOpenRISCState *env,     \
173                                             uint32_t fdt0, uint32_t fdt1) \
174 {                                                                         \
175     uint64_t result, temp, hi, lo;                                        \
176     uint32_t val1, val2;                                                  \
177     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
178     hi = cpu->env.fpmaddhi;                                               \
179     lo = cpu->env.fpmaddlo;                                               \
180     set_float_exception_flags(0, &cpu->env.fp_status);                    \
181     result = float64_ ## name1(fdt0, fdt1, &cpu->env.fp_status);          \
182     temp = (hi << 32) | lo;                                               \
183     result = float64_ ## name2(result, temp, &cpu->env.fp_status);        \
184     val1 = result >> 32;                                                  \
185     val2 = (uint32_t) (result & 0xffffffff);                              \
186     update_fpcsr(cpu);                                                    \
187     cpu->env.fpmaddlo = val2;                                             \
188     cpu->env.fpmaddhi = val1;                                             \
189     return 0;                                                             \
190 }
191
192 FLOAT_TERNOP(mul, add)
193 #undef FLOAT_TERNOP
194
195
196 #define FLOAT_CMP(name)                                                   \
197 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env,               \
198                                      uint64_t fdt0, uint64_t fdt1)        \
199 {                                                                         \
200     int res;                                                              \
201     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
202     set_float_exception_flags(0, &cpu->env.fp_status);                    \
203     res = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status);              \
204     update_fpcsr(cpu);                                                    \
205     return res;                                                           \
206 }                                                                         \
207                                                                           \
208 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env,               \
209                                              uint32_t fdt0, uint32_t fdt1)\
210 {                                                                         \
211     int res;                                                              \
212     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
213     set_float_exception_flags(0, &cpu->env.fp_status);                    \
214     res = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status);              \
215     update_fpcsr(cpu);                                                    \
216     return res;                                                           \
217 }
218
219 FLOAT_CMP(le)
220 FLOAT_CMP(eq)
221 FLOAT_CMP(lt)
222 #undef FLOAT_CMP
223
224
225 #define FLOAT_CMPNE(name)                                                 \
226 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env,               \
227                                      uint64_t fdt0, uint64_t fdt1)        \
228 {                                                                         \
229     int res;                                                              \
230     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
231     set_float_exception_flags(0, &cpu->env.fp_status);                    \
232     res = !float64_eq_quiet(fdt0, fdt1, &cpu->env.fp_status);             \
233     update_fpcsr(cpu);                                                    \
234     return res;                                                           \
235 }                                                                         \
236                                                                           \
237 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env,               \
238                                      uint32_t fdt0, uint32_t fdt1)        \
239 {                                                                         \
240     int res;                                                              \
241     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
242     set_float_exception_flags(0, &cpu->env.fp_status);                    \
243     res = !float32_eq_quiet(fdt0, fdt1, &cpu->env.fp_status);             \
244     update_fpcsr(cpu);                                                    \
245     return res;                                                           \
246 }
247
248 FLOAT_CMPNE(ne)
249 #undef FLOAT_CMPNE
250
251 #define FLOAT_CMPGT(name)                                                 \
252 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env,               \
253                                      uint64_t fdt0, uint64_t fdt1)        \
254 {                                                                         \
255     int res;                                                              \
256     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
257     set_float_exception_flags(0, &cpu->env.fp_status);                    \
258     res = !float64_le(fdt0, fdt1, &cpu->env.fp_status);                   \
259     update_fpcsr(cpu);                                                    \
260     return res;                                                           \
261 }                                                                         \
262                                                                           \
263 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env,               \
264                                      uint32_t fdt0, uint32_t fdt1)        \
265 {                                                                         \
266     int res;                                                              \
267     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
268     set_float_exception_flags(0, &cpu->env.fp_status);                    \
269     res = !float32_le(fdt0, fdt1, &cpu->env.fp_status);                   \
270     update_fpcsr(cpu);                                                    \
271     return res;                                                           \
272 }
273 FLOAT_CMPGT(gt)
274 #undef FLOAT_CMPGT
275
276 #define FLOAT_CMPGE(name)                                                 \
277 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env,               \
278                                      uint64_t fdt0, uint64_t fdt1)        \
279 {                                                                         \
280     int res;                                                              \
281     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
282     set_float_exception_flags(0, &cpu->env.fp_status);                    \
283     res = !float64_lt(fdt0, fdt1, &cpu->env.fp_status);                   \
284     update_fpcsr(cpu);                                                    \
285     return res;                                                           \
286 }                                                                         \
287                                                                           \
288 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env,               \
289                                      uint32_t fdt0, uint32_t fdt1)        \
290 {                                                                         \
291     int res;                                                              \
292     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);                         \
293     set_float_exception_flags(0, &cpu->env.fp_status);                    \
294     res = !float32_lt(fdt0, fdt1, &cpu->env.fp_status);                   \
295     update_fpcsr(cpu);                                                    \
296     return res;                                                           \
297 }
298
299 FLOAT_CMPGE(ge)
300 #undef FLOAT_CMPGE