xref: /qemu/target/openrisc/fpu_helper.c (revision 5b5695073b1d8eda14f8253a1750193d98a42ae8)
15b569507SJia Liu /*
25b569507SJia Liu  * OpenRISC float helper routines
35b569507SJia Liu  *
45b569507SJia Liu  * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
55b569507SJia Liu  *                         Feng Gao <gf91597@gmail.com>
65b569507SJia Liu  *
75b569507SJia Liu  * This library is free software; you can redistribute it and/or
85b569507SJia Liu  * modify it under the terms of the GNU Lesser General Public
95b569507SJia Liu  * License as published by the Free Software Foundation; either
105b569507SJia Liu  * version 2 of the License, or (at your option) any later version.
115b569507SJia Liu  *
125b569507SJia Liu  * This library is distributed in the hope that it will be useful,
135b569507SJia Liu  * but WITHOUT ANY WARRANTY; without even the implied warranty of
145b569507SJia Liu  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
155b569507SJia Liu  * Lesser General Public License for more details.
165b569507SJia Liu  *
175b569507SJia Liu  * You should have received a copy of the GNU Lesser General Public
185b569507SJia Liu  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
195b569507SJia Liu  */
205b569507SJia Liu 
215b569507SJia Liu #include "cpu.h"
225b569507SJia Liu #include "helper.h"
235b569507SJia Liu #include "exception.h"
245b569507SJia Liu 
255b569507SJia Liu static inline uint32_t ieee_ex_to_openrisc(OpenRISCCPU *cpu, int fexcp)
265b569507SJia Liu {
275b569507SJia Liu     int ret = 0;
285b569507SJia Liu     if (fexcp) {
295b569507SJia Liu         if (fexcp & float_flag_invalid) {
305b569507SJia Liu             cpu->env.fpcsr |= FPCSR_IVF;
315b569507SJia Liu             ret = 1;
325b569507SJia Liu         }
335b569507SJia Liu         if (fexcp & float_flag_overflow) {
345b569507SJia Liu             cpu->env.fpcsr |= FPCSR_OVF;
355b569507SJia Liu             ret = 1;
365b569507SJia Liu         }
375b569507SJia Liu         if (fexcp & float_flag_underflow) {
385b569507SJia Liu             cpu->env.fpcsr |= FPCSR_UNF;
395b569507SJia Liu             ret = 1;
405b569507SJia Liu         }
415b569507SJia Liu         if (fexcp & float_flag_divbyzero) {
425b569507SJia Liu             cpu->env.fpcsr |= FPCSR_DZF;
435b569507SJia Liu             ret = 1;
445b569507SJia Liu         }
455b569507SJia Liu         if (fexcp & float_flag_inexact) {
465b569507SJia Liu             cpu->env.fpcsr |= FPCSR_IXF;
475b569507SJia Liu             ret = 1;
485b569507SJia Liu         }
495b569507SJia Liu     }
505b569507SJia Liu 
515b569507SJia Liu     return ret;
525b569507SJia Liu }
535b569507SJia Liu 
545b569507SJia Liu static inline void update_fpcsr(OpenRISCCPU *cpu)
555b569507SJia Liu {
565b569507SJia Liu     int tmp = ieee_ex_to_openrisc(cpu,
575b569507SJia Liu                               get_float_exception_flags(&cpu->env.fp_status));
585b569507SJia Liu 
595b569507SJia Liu     SET_FP_CAUSE(cpu->env.fpcsr, tmp);
605b569507SJia Liu     if ((GET_FP_ENABLE(cpu->env.fpcsr) & tmp) &&
615b569507SJia Liu         (cpu->env.fpcsr & FPCSR_FPEE)) {
625b569507SJia Liu         helper_exception(&cpu->env, EXCP_FPE);
635b569507SJia Liu     } else {
645b569507SJia Liu         UPDATE_FP_FLAGS(cpu->env.fpcsr, tmp);
655b569507SJia Liu     }
665b569507SJia Liu }
675b569507SJia Liu 
685b569507SJia Liu uint64_t HELPER(itofd)(CPUOpenRISCState *env, uint64_t val)
695b569507SJia Liu {
705b569507SJia Liu     uint64_t itofd;
715b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
725b569507SJia Liu 
735b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);
745b569507SJia Liu     itofd = int32_to_float64(val, &cpu->env.fp_status);
755b569507SJia Liu     update_fpcsr(cpu);
765b569507SJia Liu 
775b569507SJia Liu     return itofd;
785b569507SJia Liu }
795b569507SJia Liu 
805b569507SJia Liu uint32_t HELPER(itofs)(CPUOpenRISCState *env, uint32_t val)
815b569507SJia Liu {
825b569507SJia Liu     uint32_t itofs;
835b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
845b569507SJia Liu 
855b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);
865b569507SJia Liu     itofs = int32_to_float32(val, &cpu->env.fp_status);
875b569507SJia Liu     update_fpcsr(cpu);
885b569507SJia Liu 
895b569507SJia Liu     return itofs;
905b569507SJia Liu }
915b569507SJia Liu 
925b569507SJia Liu uint64_t HELPER(ftoid)(CPUOpenRISCState *env, uint64_t val)
935b569507SJia Liu {
945b569507SJia Liu     uint64_t ftoid;
955b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
965b569507SJia Liu 
975b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);
985b569507SJia Liu     ftoid = float32_to_int64(val, &cpu->env.fp_status);
995b569507SJia Liu     update_fpcsr(cpu);
1005b569507SJia Liu 
1015b569507SJia Liu     return ftoid;
1025b569507SJia Liu }
1035b569507SJia Liu 
1045b569507SJia Liu uint32_t HELPER(ftois)(CPUOpenRISCState *env, uint32_t val)
1055b569507SJia Liu {
1065b569507SJia Liu     uint32_t ftois;
1075b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
1085b569507SJia Liu 
1095b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);
1105b569507SJia Liu     ftois = float32_to_int32(val, &cpu->env.fp_status);
1115b569507SJia Liu     update_fpcsr(cpu);
1125b569507SJia Liu 
1135b569507SJia Liu     return ftois;
1145b569507SJia Liu }
1155b569507SJia Liu 
1165b569507SJia Liu #define FLOAT_OP(name, p) void helper_float_##_##p(void)
1175b569507SJia Liu 
1185b569507SJia Liu #define FLOAT_CALC(name)                                                  \
1195b569507SJia Liu uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env,               \
1205b569507SJia Liu                                      uint64_t fdt0, uint64_t fdt1)        \
1215b569507SJia Liu {                                                                         \
1225b569507SJia Liu     uint64_t result;                                                      \
1235b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));                    \
1245b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);                    \
1255b569507SJia Liu     result = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status);           \
1265b569507SJia Liu     update_fpcsr(cpu);                                                    \
1275b569507SJia Liu     return result;                                                        \
1285b569507SJia Liu }                                                                         \
1295b569507SJia Liu                                                                           \
1305b569507SJia Liu uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env,               \
1315b569507SJia Liu                                      uint32_t fdt0, uint32_t fdt1)        \
1325b569507SJia Liu {                                                                         \
1335b569507SJia Liu     uint32_t result;                                                      \
1345b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));                    \
1355b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);                    \
1365b569507SJia Liu     result = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status);           \
1375b569507SJia Liu     update_fpcsr(cpu);                                                    \
1385b569507SJia Liu     return result;                                                        \
1395b569507SJia Liu }                                                                         \
1405b569507SJia Liu 
1415b569507SJia Liu FLOAT_CALC(add)
1425b569507SJia Liu FLOAT_CALC(sub)
1435b569507SJia Liu FLOAT_CALC(mul)
1445b569507SJia Liu FLOAT_CALC(div)
1455b569507SJia Liu FLOAT_CALC(rem)
1465b569507SJia Liu #undef FLOAT_CALC
1475b569507SJia Liu 
1485b569507SJia Liu #define FLOAT_TERNOP(name1, name2)                                        \
1495b569507SJia Liu uint64_t helper_float_ ## name1 ## name2 ## _d(CPUOpenRISCState *env,     \
1505b569507SJia Liu                                                uint64_t fdt0,             \
1515b569507SJia Liu                                                uint64_t fdt1)             \
1525b569507SJia Liu {                                                                         \
1535b569507SJia Liu     uint64_t result, temp, hi, lo;                                        \
1545b569507SJia Liu     uint32_t val1, val2;                                                  \
1555b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));                    \
1565b569507SJia Liu     hi = env->fpmaddhi;                                                   \
1575b569507SJia Liu     lo = env->fpmaddlo;                                                   \
1585b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);                    \
1595b569507SJia Liu     result = float64_ ## name1(fdt0, fdt1, &cpu->env.fp_status);          \
1605b569507SJia Liu     lo &= 0xffffffff;                                                     \
1615b569507SJia Liu     hi &= 0xffffffff;                                                     \
1625b569507SJia Liu     temp = (hi << 32) | lo;                                               \
1635b569507SJia Liu     result = float64_ ## name2(result, temp, &cpu->env.fp_status);        \
1645b569507SJia Liu     val1 = result >> 32;                                                  \
1655b569507SJia Liu     val2 = (uint32_t) (result & 0xffffffff);                              \
1665b569507SJia Liu     update_fpcsr(cpu);                                                    \
1675b569507SJia Liu     cpu->env.fpmaddlo = val2;                                             \
1685b569507SJia Liu     cpu->env.fpmaddhi = val1;                                             \
1695b569507SJia Liu     return 0;                                                             \
1705b569507SJia Liu }                                                                         \
1715b569507SJia Liu                                                                           \
1725b569507SJia Liu uint32_t helper_float_ ## name1 ## name2 ## _s(CPUOpenRISCState *env,     \
1735b569507SJia Liu                                             uint32_t fdt0, uint32_t fdt1) \
1745b569507SJia Liu {                                                                         \
1755b569507SJia Liu     uint64_t result, temp, hi, lo;                                        \
1765b569507SJia Liu     uint32_t val1, val2;                                                  \
1775b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));                    \
1785b569507SJia Liu     hi = cpu->env.fpmaddhi;                                               \
1795b569507SJia Liu     lo = cpu->env.fpmaddlo;                                               \
1805b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);                    \
1815b569507SJia Liu     result = float64_ ## name1(fdt0, fdt1, &cpu->env.fp_status);          \
1825b569507SJia Liu     temp = (hi << 32) | lo;                                               \
1835b569507SJia Liu     result = float64_ ## name2(result, temp, &cpu->env.fp_status);        \
1845b569507SJia Liu     val1 = result >> 32;                                                  \
1855b569507SJia Liu     val2 = (uint32_t) (result & 0xffffffff);                              \
1865b569507SJia Liu     update_fpcsr(cpu);                                                    \
1875b569507SJia Liu     cpu->env.fpmaddlo = val2;                                             \
1885b569507SJia Liu     cpu->env.fpmaddhi = val1;                                             \
1895b569507SJia Liu     return 0;                                                             \
1905b569507SJia Liu }
1915b569507SJia Liu 
1925b569507SJia Liu FLOAT_TERNOP(mul, add)
1935b569507SJia Liu #undef FLOAT_TERNOP
1945b569507SJia Liu 
1955b569507SJia Liu 
1965b569507SJia Liu #define FLOAT_CMP(name)                                                   \
1975b569507SJia Liu uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env,               \
1985b569507SJia Liu                                      uint64_t fdt0, uint64_t fdt1)        \
1995b569507SJia Liu {                                                                         \
2005b569507SJia Liu     int res;                                                              \
2015b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));                    \
2025b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);                    \
2035b569507SJia Liu     res = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status);              \
2045b569507SJia Liu     update_fpcsr(cpu);                                                    \
2055b569507SJia Liu     return res;                                                           \
2065b569507SJia Liu }                                                                         \
2075b569507SJia Liu                                                                           \
2085b569507SJia Liu uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env,               \
2095b569507SJia Liu                                              uint32_t fdt0, uint32_t fdt1)\
2105b569507SJia Liu {                                                                         \
2115b569507SJia Liu     int res;                                                              \
2125b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));                    \
2135b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);                    \
2145b569507SJia Liu     res = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status);              \
2155b569507SJia Liu     update_fpcsr(cpu);                                                    \
2165b569507SJia Liu     return res;                                                           \
2175b569507SJia Liu }
2185b569507SJia Liu 
2195b569507SJia Liu FLOAT_CMP(le)
2205b569507SJia Liu FLOAT_CMP(eq)
2215b569507SJia Liu FLOAT_CMP(lt)
2225b569507SJia Liu #undef FLOAT_CMP
2235b569507SJia Liu 
2245b569507SJia Liu 
2255b569507SJia Liu #define FLOAT_CMPNE(name)                                                 \
2265b569507SJia Liu uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env,               \
2275b569507SJia Liu                                      uint64_t fdt0, uint64_t fdt1)        \
2285b569507SJia Liu {                                                                         \
2295b569507SJia Liu     int res;                                                              \
2305b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));                    \
2315b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);                    \
2325b569507SJia Liu     res = !float64_eq_quiet(fdt0, fdt1, &cpu->env.fp_status);             \
2335b569507SJia Liu     update_fpcsr(cpu);                                                    \
2345b569507SJia Liu     return res;                                                           \
2355b569507SJia Liu }                                                                         \
2365b569507SJia Liu                                                                           \
2375b569507SJia Liu uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env,               \
2385b569507SJia Liu                                      uint32_t fdt0, uint32_t fdt1)        \
2395b569507SJia Liu {                                                                         \
2405b569507SJia Liu     int res;                                                              \
2415b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));                    \
2425b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);                    \
2435b569507SJia Liu     res = !float32_eq_quiet(fdt0, fdt1, &cpu->env.fp_status);             \
2445b569507SJia Liu     update_fpcsr(cpu);                                                    \
2455b569507SJia Liu     return res;                                                           \
2465b569507SJia Liu }
2475b569507SJia Liu 
2485b569507SJia Liu FLOAT_CMPNE(ne)
2495b569507SJia Liu #undef FLOAT_CMPNE
2505b569507SJia Liu 
2515b569507SJia Liu #define FLOAT_CMPGT(name)                                                 \
2525b569507SJia Liu uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env,               \
2535b569507SJia Liu                                      uint64_t fdt0, uint64_t fdt1)        \
2545b569507SJia Liu {                                                                         \
2555b569507SJia Liu     int res;                                                              \
2565b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));                    \
2575b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);                    \
2585b569507SJia Liu     res = !float64_le(fdt0, fdt1, &cpu->env.fp_status);                   \
2595b569507SJia Liu     update_fpcsr(cpu);                                                    \
2605b569507SJia Liu     return res;                                                           \
2615b569507SJia Liu }                                                                         \
2625b569507SJia Liu                                                                           \
2635b569507SJia Liu uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env,               \
2645b569507SJia Liu                                      uint32_t fdt0, uint32_t fdt1)        \
2655b569507SJia Liu {                                                                         \
2665b569507SJia Liu     int res;                                                              \
2675b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));                    \
2685b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);                    \
2695b569507SJia Liu     res = !float32_le(fdt0, fdt1, &cpu->env.fp_status);                   \
2705b569507SJia Liu     update_fpcsr(cpu);                                                    \
2715b569507SJia Liu     return res;                                                           \
2725b569507SJia Liu }
2735b569507SJia Liu FLOAT_CMPGT(gt)
2745b569507SJia Liu #undef FLOAT_CMPGT
2755b569507SJia Liu 
2765b569507SJia Liu #define FLOAT_CMPGE(name)                                                 \
2775b569507SJia Liu uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env,               \
2785b569507SJia Liu                                      uint64_t fdt0, uint64_t fdt1)        \
2795b569507SJia Liu {                                                                         \
2805b569507SJia Liu     int res;                                                              \
2815b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));                    \
2825b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);                    \
2835b569507SJia Liu     res = !float64_lt(fdt0, fdt1, &cpu->env.fp_status);                   \
2845b569507SJia Liu     update_fpcsr(cpu);                                                    \
2855b569507SJia Liu     return res;                                                           \
2865b569507SJia Liu }                                                                         \
2875b569507SJia Liu                                                                           \
2885b569507SJia Liu uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env,               \
2895b569507SJia Liu                                      uint32_t fdt0, uint32_t fdt1)        \
2905b569507SJia Liu {                                                                         \
2915b569507SJia Liu     int res;                                                              \
2925b569507SJia Liu     OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));                    \
2935b569507SJia Liu     set_float_exception_flags(0, &cpu->env.fp_status);                    \
2945b569507SJia Liu     res = !float32_lt(fdt0, fdt1, &cpu->env.fp_status);                   \
2955b569507SJia Liu     update_fpcsr(cpu);                                                    \
2965b569507SJia Liu     return res;                                                           \
2975b569507SJia Liu }
2985b569507SJia Liu 
2995b569507SJia Liu FLOAT_CMPGE(ge)
3005b569507SJia Liu #undef FLOAT_CMPGE
301