1996a729fSBastian Koppelmann /* 2996a729fSBastian Koppelmann * TriCore emulation for qemu: fpu helper. 3996a729fSBastian Koppelmann * 4996a729fSBastian Koppelmann * Copyright (c) 2016 Bastian Koppelmann University of Paderborn 5996a729fSBastian Koppelmann * 6996a729fSBastian Koppelmann * This library is free software; you can redistribute it and/or 7996a729fSBastian Koppelmann * modify it under the terms of the GNU Lesser General Public 8996a729fSBastian Koppelmann * License as published by the Free Software Foundation; either 9996a729fSBastian Koppelmann * version 2 of the License, or (at your option) any later version. 10996a729fSBastian Koppelmann * 11996a729fSBastian Koppelmann * This library is distributed in the hope that it will be useful, 12996a729fSBastian Koppelmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 13996a729fSBastian Koppelmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14996a729fSBastian Koppelmann * Lesser General Public License for more details. 15996a729fSBastian Koppelmann * 16996a729fSBastian Koppelmann * You should have received a copy of the GNU Lesser General Public 17996a729fSBastian Koppelmann * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18996a729fSBastian Koppelmann */ 19996a729fSBastian Koppelmann 20996a729fSBastian Koppelmann #include "qemu/osdep.h" 21996a729fSBastian Koppelmann #include "cpu.h" 22996a729fSBastian Koppelmann #include "exec/helper-proto.h" 23996a729fSBastian Koppelmann 24996a729fSBastian Koppelmann #define ADD_NAN 0x7cf00001 25996a729fSBastian Koppelmann #define DIV_NAN 0x7fc00008 26996a729fSBastian Koppelmann #define MUL_NAN 0x7fc00002 27996a729fSBastian Koppelmann #define FPU_FS PSW_USB_C 28996a729fSBastian Koppelmann #define FPU_FI PSW_USB_V 29996a729fSBastian Koppelmann #define FPU_FV PSW_USB_SV 30996a729fSBastian Koppelmann #define FPU_FZ PSW_USB_AV 31996a729fSBastian Koppelmann #define FPU_FU PSW_USB_SAV 32996a729fSBastian Koppelmann 33996a729fSBastian Koppelmann /* we don't care about input_denormal */ 34996a729fSBastian Koppelmann static inline uint8_t f_get_excp_flags(CPUTriCoreState *env) 35996a729fSBastian Koppelmann { 36996a729fSBastian Koppelmann return get_float_exception_flags(&env->fp_status) 37996a729fSBastian Koppelmann & (float_flag_invalid 38996a729fSBastian Koppelmann | float_flag_overflow 39996a729fSBastian Koppelmann | float_flag_underflow 40996a729fSBastian Koppelmann | float_flag_output_denormal 41996a729fSBastian Koppelmann | float_flag_divbyzero 42996a729fSBastian Koppelmann | float_flag_inexact); 43996a729fSBastian Koppelmann } 44996a729fSBastian Koppelmann 45996a729fSBastian Koppelmann static inline bool f_is_denormal(float32 arg) 46996a729fSBastian Koppelmann { 47996a729fSBastian Koppelmann return float32_is_zero_or_denormal(arg) && !float32_is_zero(arg); 48996a729fSBastian Koppelmann } 49996a729fSBastian Koppelmann 50baf410dcSBastian Koppelmann static void f_update_psw_flags(CPUTriCoreState *env, uint8_t flags) 51996a729fSBastian Koppelmann { 52996a729fSBastian Koppelmann uint8_t some_excp = 0; 53996a729fSBastian Koppelmann set_float_exception_flags(0, &env->fp_status); 54996a729fSBastian Koppelmann 55996a729fSBastian Koppelmann if (flags & float_flag_invalid) { 56996a729fSBastian Koppelmann env->FPU_FI = 1 << 31; 57996a729fSBastian Koppelmann some_excp = 1; 58996a729fSBastian Koppelmann } 59996a729fSBastian Koppelmann 60996a729fSBastian Koppelmann if (flags & float_flag_overflow) { 61996a729fSBastian Koppelmann env->FPU_FV = 1 << 31; 62996a729fSBastian Koppelmann some_excp = 1; 63996a729fSBastian Koppelmann } 64996a729fSBastian Koppelmann 65996a729fSBastian Koppelmann if (flags & float_flag_underflow || flags & float_flag_output_denormal) { 66996a729fSBastian Koppelmann env->FPU_FU = 1 << 31; 67996a729fSBastian Koppelmann some_excp = 1; 68996a729fSBastian Koppelmann } 69996a729fSBastian Koppelmann 70996a729fSBastian Koppelmann if (flags & float_flag_divbyzero) { 71996a729fSBastian Koppelmann env->FPU_FZ = 1 << 31; 72996a729fSBastian Koppelmann some_excp = 1; 73996a729fSBastian Koppelmann } 74996a729fSBastian Koppelmann 75996a729fSBastian Koppelmann if (flags & float_flag_inexact || flags & float_flag_output_denormal) { 76996a729fSBastian Koppelmann env->PSW |= 1 << 26; 77996a729fSBastian Koppelmann some_excp = 1; 78996a729fSBastian Koppelmann } 79996a729fSBastian Koppelmann 80996a729fSBastian Koppelmann env->FPU_FS = some_excp; 81996a729fSBastian Koppelmann } 82baf410dcSBastian Koppelmann 83baf410dcSBastian Koppelmann #define FADD_SUB(op) \ 84baf410dcSBastian Koppelmann uint32_t helper_f##op(CPUTriCoreState *env, uint32_t r1, uint32_t r2) \ 85baf410dcSBastian Koppelmann { \ 86baf410dcSBastian Koppelmann float32 arg1 = make_float32(r1); \ 87baf410dcSBastian Koppelmann float32 arg2 = make_float32(r2); \ 88baf410dcSBastian Koppelmann uint32_t flags; \ 89baf410dcSBastian Koppelmann float32 f_result; \ 90baf410dcSBastian Koppelmann \ 91baf410dcSBastian Koppelmann f_result = float32_##op(arg2, arg1, &env->fp_status); \ 92baf410dcSBastian Koppelmann flags = f_get_excp_flags(env); \ 93baf410dcSBastian Koppelmann if (flags) { \ 94baf410dcSBastian Koppelmann /* If the output is a NaN, but the inputs aren't, \ 95baf410dcSBastian Koppelmann we return a unique value. */ \ 96baf410dcSBastian Koppelmann if ((flags & float_flag_invalid) \ 97baf410dcSBastian Koppelmann && !float32_is_any_nan(arg1) \ 98baf410dcSBastian Koppelmann && !float32_is_any_nan(arg2)) { \ 99baf410dcSBastian Koppelmann f_result = ADD_NAN; \ 100baf410dcSBastian Koppelmann } \ 101baf410dcSBastian Koppelmann f_update_psw_flags(env, flags); \ 102baf410dcSBastian Koppelmann } else { \ 103baf410dcSBastian Koppelmann env->FPU_FS = 0; \ 104baf410dcSBastian Koppelmann } \ 105baf410dcSBastian Koppelmann return (uint32_t)f_result; \ 106baf410dcSBastian Koppelmann } 107baf410dcSBastian Koppelmann FADD_SUB(add) 108baf410dcSBastian Koppelmann FADD_SUB(sub) 109daab3f7fSBastian Koppelmann 110daab3f7fSBastian Koppelmann uint32_t helper_fmul(CPUTriCoreState *env, uint32_t r1, uint32_t r2) 111daab3f7fSBastian Koppelmann { 112daab3f7fSBastian Koppelmann uint32_t flags; 113daab3f7fSBastian Koppelmann float32 arg1 = make_float32(r1); 114daab3f7fSBastian Koppelmann float32 arg2 = make_float32(r2); 115daab3f7fSBastian Koppelmann float32 f_result; 116daab3f7fSBastian Koppelmann 117daab3f7fSBastian Koppelmann f_result = float32_mul(arg1, arg2, &env->fp_status); 118daab3f7fSBastian Koppelmann 119daab3f7fSBastian Koppelmann flags = f_get_excp_flags(env); 120daab3f7fSBastian Koppelmann if (flags) { 121daab3f7fSBastian Koppelmann /* If the output is a NaN, but the inputs aren't, 122daab3f7fSBastian Koppelmann we return a unique value. */ 123daab3f7fSBastian Koppelmann if ((flags & float_flag_invalid) 124daab3f7fSBastian Koppelmann && !float32_is_any_nan(arg1) 125daab3f7fSBastian Koppelmann && !float32_is_any_nan(arg2)) { 126daab3f7fSBastian Koppelmann f_result = MUL_NAN; 127daab3f7fSBastian Koppelmann } 128daab3f7fSBastian Koppelmann f_update_psw_flags(env, flags); 129daab3f7fSBastian Koppelmann } else { 130daab3f7fSBastian Koppelmann env->FPU_FS = 0; 131daab3f7fSBastian Koppelmann } 132daab3f7fSBastian Koppelmann return (uint32_t)f_result; 133daab3f7fSBastian Koppelmann 134daab3f7fSBastian Koppelmann } 135446ee5b2SBastian Koppelmann 136446ee5b2SBastian Koppelmann uint32_t helper_fdiv(CPUTriCoreState *env, uint32_t r1, uint32_t r2) 137446ee5b2SBastian Koppelmann { 138446ee5b2SBastian Koppelmann uint32_t flags; 139446ee5b2SBastian Koppelmann float32 arg1 = make_float32(r1); 140446ee5b2SBastian Koppelmann float32 arg2 = make_float32(r2); 141446ee5b2SBastian Koppelmann float32 f_result; 142446ee5b2SBastian Koppelmann 143446ee5b2SBastian Koppelmann f_result = float32_div(arg1, arg2 , &env->fp_status); 144446ee5b2SBastian Koppelmann 145446ee5b2SBastian Koppelmann flags = f_get_excp_flags(env); 146446ee5b2SBastian Koppelmann if (flags) { 147446ee5b2SBastian Koppelmann /* If the output is a NaN, but the inputs aren't, 148446ee5b2SBastian Koppelmann we return a unique value. */ 149446ee5b2SBastian Koppelmann if ((flags & float_flag_invalid) 150446ee5b2SBastian Koppelmann && !float32_is_any_nan(arg1) 151446ee5b2SBastian Koppelmann && !float32_is_any_nan(arg2)) { 152446ee5b2SBastian Koppelmann f_result = DIV_NAN; 153446ee5b2SBastian Koppelmann } 154446ee5b2SBastian Koppelmann f_update_psw_flags(env, flags); 155446ee5b2SBastian Koppelmann } else { 156446ee5b2SBastian Koppelmann env->FPU_FS = 0; 157446ee5b2SBastian Koppelmann } 158446ee5b2SBastian Koppelmann 159446ee5b2SBastian Koppelmann return (uint32_t)f_result; 160446ee5b2SBastian Koppelmann } 161743cd09dSBastian Koppelmann 162743cd09dSBastian Koppelmann uint32_t helper_fcmp(CPUTriCoreState *env, uint32_t r1, uint32_t r2) 163743cd09dSBastian Koppelmann { 164743cd09dSBastian Koppelmann uint32_t result, flags; 165743cd09dSBastian Koppelmann float32 arg1 = make_float32(r1); 166743cd09dSBastian Koppelmann float32 arg2 = make_float32(r2); 167743cd09dSBastian Koppelmann 168743cd09dSBastian Koppelmann set_flush_inputs_to_zero(0, &env->fp_status); 169743cd09dSBastian Koppelmann 170743cd09dSBastian Koppelmann result = 1 << (float32_compare_quiet(arg1, arg2, &env->fp_status) + 1); 171743cd09dSBastian Koppelmann result |= f_is_denormal(arg1) << 4; 172743cd09dSBastian Koppelmann result |= f_is_denormal(arg2) << 5; 173743cd09dSBastian Koppelmann 174743cd09dSBastian Koppelmann flags = f_get_excp_flags(env); 175743cd09dSBastian Koppelmann if (flags) { 176743cd09dSBastian Koppelmann f_update_psw_flags(env, flags); 177743cd09dSBastian Koppelmann } else { 178743cd09dSBastian Koppelmann env->FPU_FS = 0; 179743cd09dSBastian Koppelmann } 180743cd09dSBastian Koppelmann 181743cd09dSBastian Koppelmann set_flush_inputs_to_zero(1, &env->fp_status); 182743cd09dSBastian Koppelmann return result; 183743cd09dSBastian Koppelmann } 1840d4c3b80SBastian Koppelmann 1850d4c3b80SBastian Koppelmann uint32_t helper_ftoi(CPUTriCoreState *env, uint32_t arg) 1860d4c3b80SBastian Koppelmann { 1870d4c3b80SBastian Koppelmann float32 f_arg = make_float32(arg); 1880d4c3b80SBastian Koppelmann int32_t result, flags; 1890d4c3b80SBastian Koppelmann 1900d4c3b80SBastian Koppelmann result = float32_to_int32(f_arg, &env->fp_status); 1910d4c3b80SBastian Koppelmann 1920d4c3b80SBastian Koppelmann flags = f_get_excp_flags(env); 1930d4c3b80SBastian Koppelmann if (flags) { 1940d4c3b80SBastian Koppelmann if (float32_is_any_nan(f_arg)) { 1950d4c3b80SBastian Koppelmann result = 0; 1960d4c3b80SBastian Koppelmann } 1970d4c3b80SBastian Koppelmann f_update_psw_flags(env, flags); 1980d4c3b80SBastian Koppelmann } else { 1990d4c3b80SBastian Koppelmann env->FPU_FS = 0; 2000d4c3b80SBastian Koppelmann } 2010d4c3b80SBastian Koppelmann return (uint32_t)result; 2020d4c3b80SBastian Koppelmann } 2030d4c3b80SBastian Koppelmann 2040d4c3b80SBastian Koppelmann uint32_t helper_itof(CPUTriCoreState *env, uint32_t arg) 2050d4c3b80SBastian Koppelmann { 2060d4c3b80SBastian Koppelmann float32 f_result; 2070d4c3b80SBastian Koppelmann uint32_t flags; 2080d4c3b80SBastian Koppelmann f_result = int32_to_float32(arg, &env->fp_status); 2090d4c3b80SBastian Koppelmann 2100d4c3b80SBastian Koppelmann flags = f_get_excp_flags(env); 2110d4c3b80SBastian Koppelmann if (flags) { 2120d4c3b80SBastian Koppelmann f_update_psw_flags(env, flags); 2130d4c3b80SBastian Koppelmann } else { 2140d4c3b80SBastian Koppelmann env->FPU_FS = 0; 2150d4c3b80SBastian Koppelmann } 2160d4c3b80SBastian Koppelmann return (uint32_t)f_result; 2170d4c3b80SBastian Koppelmann } 218