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 "qemu/osdep.h" 22 #include "cpu.h" 23 #include "exec/helper-proto.h" 24 #include "exception.h" 25 26 static inline uint32_t ieee_ex_to_openrisc(OpenRISCCPU *cpu, int fexcp) 27 { 28 int ret = 0; 29 if (fexcp) { 30 if (fexcp & float_flag_invalid) { 31 cpu->env.fpcsr |= FPCSR_IVF; 32 ret = 1; 33 } 34 if (fexcp & float_flag_overflow) { 35 cpu->env.fpcsr |= FPCSR_OVF; 36 ret = 1; 37 } 38 if (fexcp & float_flag_underflow) { 39 cpu->env.fpcsr |= FPCSR_UNF; 40 ret = 1; 41 } 42 if (fexcp & float_flag_divbyzero) { 43 cpu->env.fpcsr |= FPCSR_DZF; 44 ret = 1; 45 } 46 if (fexcp & float_flag_inexact) { 47 cpu->env.fpcsr |= FPCSR_IXF; 48 ret = 1; 49 } 50 } 51 52 return ret; 53 } 54 55 static inline void update_fpcsr(OpenRISCCPU *cpu) 56 { 57 int tmp = ieee_ex_to_openrisc(cpu, 58 get_float_exception_flags(&cpu->env.fp_status)); 59 60 SET_FP_CAUSE(cpu->env.fpcsr, tmp); 61 if ((GET_FP_ENABLE(cpu->env.fpcsr) & tmp) && 62 (cpu->env.fpcsr & FPCSR_FPEE)) { 63 helper_exception(&cpu->env, EXCP_FPE); 64 } else { 65 UPDATE_FP_FLAGS(cpu->env.fpcsr, tmp); 66 } 67 } 68 69 uint64_t HELPER(itofd)(CPUOpenRISCState *env, uint64_t val) 70 { 71 uint64_t itofd; 72 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); 73 74 set_float_exception_flags(0, &cpu->env.fp_status); 75 itofd = int32_to_float64(val, &cpu->env.fp_status); 76 update_fpcsr(cpu); 77 78 return itofd; 79 } 80 81 uint32_t HELPER(itofs)(CPUOpenRISCState *env, uint32_t val) 82 { 83 uint32_t itofs; 84 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); 85 86 set_float_exception_flags(0, &cpu->env.fp_status); 87 itofs = int32_to_float32(val, &cpu->env.fp_status); 88 update_fpcsr(cpu); 89 90 return itofs; 91 } 92 93 uint64_t HELPER(ftoid)(CPUOpenRISCState *env, uint64_t val) 94 { 95 uint64_t ftoid; 96 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); 97 98 set_float_exception_flags(0, &cpu->env.fp_status); 99 ftoid = float32_to_int64(val, &cpu->env.fp_status); 100 update_fpcsr(cpu); 101 102 return ftoid; 103 } 104 105 uint32_t HELPER(ftois)(CPUOpenRISCState *env, uint32_t val) 106 { 107 uint32_t ftois; 108 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); 109 110 set_float_exception_flags(0, &cpu->env.fp_status); 111 ftois = float32_to_int32(val, &cpu->env.fp_status); 112 update_fpcsr(cpu); 113 114 return ftois; 115 } 116 117 #define FLOAT_OP(name, p) void helper_float_##_##p(void) 118 119 #define FLOAT_CALC(name) \ 120 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ 121 uint64_t fdt0, uint64_t fdt1) \ 122 { \ 123 uint64_t result; \ 124 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 125 set_float_exception_flags(0, &cpu->env.fp_status); \ 126 result = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status); \ 127 update_fpcsr(cpu); \ 128 return result; \ 129 } \ 130 \ 131 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ 132 uint32_t fdt0, uint32_t fdt1) \ 133 { \ 134 uint32_t result; \ 135 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 136 set_float_exception_flags(0, &cpu->env.fp_status); \ 137 result = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status); \ 138 update_fpcsr(cpu); \ 139 return result; \ 140 } \ 141 142 FLOAT_CALC(add) 143 FLOAT_CALC(sub) 144 FLOAT_CALC(mul) 145 FLOAT_CALC(div) 146 FLOAT_CALC(rem) 147 #undef FLOAT_CALC 148 149 #define FLOAT_TERNOP(name1, name2) \ 150 uint64_t helper_float_ ## name1 ## name2 ## _d(CPUOpenRISCState *env, \ 151 uint64_t fdt0, \ 152 uint64_t fdt1) \ 153 { \ 154 uint64_t result, temp, hi, lo; \ 155 uint32_t val1, val2; \ 156 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 157 hi = env->fpmaddhi; \ 158 lo = env->fpmaddlo; \ 159 set_float_exception_flags(0, &cpu->env.fp_status); \ 160 result = float64_ ## name1(fdt0, fdt1, &cpu->env.fp_status); \ 161 lo &= 0xffffffff; \ 162 hi &= 0xffffffff; \ 163 temp = (hi << 32) | lo; \ 164 result = float64_ ## name2(result, temp, &cpu->env.fp_status); \ 165 val1 = result >> 32; \ 166 val2 = (uint32_t) (result & 0xffffffff); \ 167 update_fpcsr(cpu); \ 168 cpu->env.fpmaddlo = val2; \ 169 cpu->env.fpmaddhi = val1; \ 170 return 0; \ 171 } \ 172 \ 173 uint32_t helper_float_ ## name1 ## name2 ## _s(CPUOpenRISCState *env, \ 174 uint32_t fdt0, uint32_t fdt1) \ 175 { \ 176 uint64_t result, temp, hi, lo; \ 177 uint32_t val1, val2; \ 178 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 179 hi = cpu->env.fpmaddhi; \ 180 lo = cpu->env.fpmaddlo; \ 181 set_float_exception_flags(0, &cpu->env.fp_status); \ 182 result = float64_ ## name1(fdt0, fdt1, &cpu->env.fp_status); \ 183 temp = (hi << 32) | lo; \ 184 result = float64_ ## name2(result, temp, &cpu->env.fp_status); \ 185 val1 = result >> 32; \ 186 val2 = (uint32_t) (result & 0xffffffff); \ 187 update_fpcsr(cpu); \ 188 cpu->env.fpmaddlo = val2; \ 189 cpu->env.fpmaddhi = val1; \ 190 return 0; \ 191 } 192 193 FLOAT_TERNOP(mul, add) 194 #undef FLOAT_TERNOP 195 196 197 #define FLOAT_CMP(name) \ 198 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ 199 uint64_t fdt0, uint64_t fdt1) \ 200 { \ 201 int res; \ 202 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 203 set_float_exception_flags(0, &cpu->env.fp_status); \ 204 res = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status); \ 205 update_fpcsr(cpu); \ 206 return res; \ 207 } \ 208 \ 209 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ 210 uint32_t fdt0, uint32_t fdt1)\ 211 { \ 212 int res; \ 213 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 214 set_float_exception_flags(0, &cpu->env.fp_status); \ 215 res = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status); \ 216 update_fpcsr(cpu); \ 217 return res; \ 218 } 219 220 FLOAT_CMP(le) 221 FLOAT_CMP(eq) 222 FLOAT_CMP(lt) 223 #undef FLOAT_CMP 224 225 226 #define FLOAT_CMPNE(name) \ 227 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ 228 uint64_t fdt0, uint64_t fdt1) \ 229 { \ 230 int res; \ 231 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 232 set_float_exception_flags(0, &cpu->env.fp_status); \ 233 res = !float64_eq_quiet(fdt0, fdt1, &cpu->env.fp_status); \ 234 update_fpcsr(cpu); \ 235 return res; \ 236 } \ 237 \ 238 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ 239 uint32_t fdt0, uint32_t fdt1) \ 240 { \ 241 int res; \ 242 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 243 set_float_exception_flags(0, &cpu->env.fp_status); \ 244 res = !float32_eq_quiet(fdt0, fdt1, &cpu->env.fp_status); \ 245 update_fpcsr(cpu); \ 246 return res; \ 247 } 248 249 FLOAT_CMPNE(ne) 250 #undef FLOAT_CMPNE 251 252 #define FLOAT_CMPGT(name) \ 253 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ 254 uint64_t fdt0, uint64_t fdt1) \ 255 { \ 256 int res; \ 257 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 258 set_float_exception_flags(0, &cpu->env.fp_status); \ 259 res = !float64_le(fdt0, fdt1, &cpu->env.fp_status); \ 260 update_fpcsr(cpu); \ 261 return res; \ 262 } \ 263 \ 264 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ 265 uint32_t fdt0, uint32_t fdt1) \ 266 { \ 267 int res; \ 268 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 269 set_float_exception_flags(0, &cpu->env.fp_status); \ 270 res = !float32_le(fdt0, fdt1, &cpu->env.fp_status); \ 271 update_fpcsr(cpu); \ 272 return res; \ 273 } 274 FLOAT_CMPGT(gt) 275 #undef FLOAT_CMPGT 276 277 #define FLOAT_CMPGE(name) \ 278 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ 279 uint64_t fdt0, uint64_t fdt1) \ 280 { \ 281 int res; \ 282 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 283 set_float_exception_flags(0, &cpu->env.fp_status); \ 284 res = !float64_lt(fdt0, fdt1, &cpu->env.fp_status); \ 285 update_fpcsr(cpu); \ 286 return res; \ 287 } \ 288 \ 289 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ 290 uint32_t fdt0, uint32_t fdt1) \ 291 { \ 292 int res; \ 293 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 294 set_float_exception_flags(0, &cpu->env.fp_status); \ 295 res = !float32_lt(fdt0, fdt1, &cpu->env.fp_status); \ 296 update_fpcsr(cpu); \ 297 return res; \ 298 } 299 300 FLOAT_CMPGE(ge) 301 #undef FLOAT_CMPGE 302