qemu/target/openrisc/fpu_helper.c
<<
>>
Prefs
   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
  27static 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
  56static 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
  70uint64_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
  82uint32_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
  94uint64_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
 106uint32_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)                                                  \
 121uint64_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                                                                          \
 132uint32_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
 143FLOAT_CALC(add)
 144FLOAT_CALC(sub)
 145FLOAT_CALC(mul)
 146FLOAT_CALC(div)
 147FLOAT_CALC(rem)
 148#undef FLOAT_CALC
 149
 150
 151uint64_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
 164uint32_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)                                                   \
 179uint64_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                                                                          \
 190uint32_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
 201FLOAT_CMP(le)
 202FLOAT_CMP(eq)
 203FLOAT_CMP(lt)
 204#undef FLOAT_CMP
 205
 206
 207#define FLOAT_CMPNE(name)                                                 \
 208uint64_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                                                                          \
 219uint32_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
 230FLOAT_CMPNE(ne)
 231#undef FLOAT_CMPNE
 232
 233#define FLOAT_CMPGT(name)                                                 \
 234uint64_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                                                                          \
 245uint32_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}
 255FLOAT_CMPGT(gt)
 256#undef FLOAT_CMPGT
 257
 258#define FLOAT_CMPGE(name)                                                 \
 259uint64_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                                                                          \
 270uint32_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
 281FLOAT_CMPGE(ge)
 282#undef FLOAT_CMPGE
 283