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