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 150 uint64_t helper_float_madd_d(CPUOpenRISCState *env, uint64_t a, 151 uint64_t b, uint64_t c) 152 { 153 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); 154 uint64_t result; 155 set_float_exception_flags(0, &cpu->env.fp_status); 156 /* Note that or1ksim doesn't use merged operation. */ 157 result = float64_mul(b, c, &cpu->env.fp_status); 158 result = float64_add(result, a, &cpu->env.fp_status); 159 update_fpcsr(cpu); 160 return result; 161 } 162 163 uint32_t helper_float_madd_s(CPUOpenRISCState *env, uint32_t a, 164 uint32_t b, uint32_t c) 165 { 166 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); 167 uint32_t result; 168 set_float_exception_flags(0, &cpu->env.fp_status); 169 /* Note that or1ksim doesn't use merged operation. */ 170 result = float32_mul(b, c, &cpu->env.fp_status); 171 result = float32_add(result, a, &cpu->env.fp_status); 172 update_fpcsr(cpu); 173 return result; 174 } 175 176 177 #define FLOAT_CMP(name) \ 178 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ 179 uint64_t fdt0, uint64_t fdt1) \ 180 { \ 181 int res; \ 182 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 183 set_float_exception_flags(0, &cpu->env.fp_status); \ 184 res = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status); \ 185 update_fpcsr(cpu); \ 186 return res; \ 187 } \ 188 \ 189 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ 190 uint32_t fdt0, uint32_t fdt1)\ 191 { \ 192 int res; \ 193 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 194 set_float_exception_flags(0, &cpu->env.fp_status); \ 195 res = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status); \ 196 update_fpcsr(cpu); \ 197 return res; \ 198 } 199 200 FLOAT_CMP(le) 201 FLOAT_CMP(eq) 202 FLOAT_CMP(lt) 203 #undef FLOAT_CMP 204 205 206 #define FLOAT_CMPNE(name) \ 207 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ 208 uint64_t fdt0, uint64_t fdt1) \ 209 { \ 210 int res; \ 211 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 212 set_float_exception_flags(0, &cpu->env.fp_status); \ 213 res = !float64_eq_quiet(fdt0, fdt1, &cpu->env.fp_status); \ 214 update_fpcsr(cpu); \ 215 return res; \ 216 } \ 217 \ 218 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ 219 uint32_t fdt0, uint32_t fdt1) \ 220 { \ 221 int res; \ 222 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 223 set_float_exception_flags(0, &cpu->env.fp_status); \ 224 res = !float32_eq_quiet(fdt0, fdt1, &cpu->env.fp_status); \ 225 update_fpcsr(cpu); \ 226 return res; \ 227 } 228 229 FLOAT_CMPNE(ne) 230 #undef FLOAT_CMPNE 231 232 #define FLOAT_CMPGT(name) \ 233 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ 234 uint64_t fdt0, uint64_t fdt1) \ 235 { \ 236 int res; \ 237 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 238 set_float_exception_flags(0, &cpu->env.fp_status); \ 239 res = !float64_le(fdt0, fdt1, &cpu->env.fp_status); \ 240 update_fpcsr(cpu); \ 241 return res; \ 242 } \ 243 \ 244 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ 245 uint32_t fdt0, uint32_t fdt1) \ 246 { \ 247 int res; \ 248 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 249 set_float_exception_flags(0, &cpu->env.fp_status); \ 250 res = !float32_le(fdt0, fdt1, &cpu->env.fp_status); \ 251 update_fpcsr(cpu); \ 252 return res; \ 253 } 254 FLOAT_CMPGT(gt) 255 #undef FLOAT_CMPGT 256 257 #define FLOAT_CMPGE(name) \ 258 uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ 259 uint64_t fdt0, uint64_t fdt1) \ 260 { \ 261 int res; \ 262 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 263 set_float_exception_flags(0, &cpu->env.fp_status); \ 264 res = !float64_lt(fdt0, fdt1, &cpu->env.fp_status); \ 265 update_fpcsr(cpu); \ 266 return res; \ 267 } \ 268 \ 269 uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ 270 uint32_t fdt0, uint32_t fdt1) \ 271 { \ 272 int res; \ 273 OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ 274 set_float_exception_flags(0, &cpu->env.fp_status); \ 275 res = !float32_lt(fdt0, fdt1, &cpu->env.fp_status); \ 276 update_fpcsr(cpu); \ 277 return res; \ 278 } 279 280 FLOAT_CMPGE(ge) 281 #undef FLOAT_CMPGE 282