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