qemu/target/alpha/vax_helper.c
<<
>>
Prefs
   1/*
   2 *  Helpers for vax floating point instructions.
   3 *
   4 *  Copyright (c) 2007 Jocelyn Mayer
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2.1 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "cpu.h"
  22#include "exec/exec-all.h"
  23#include "exec/helper-proto.h"
  24#include "fpu/softfloat.h"
  25
  26#define FP_STATUS (env->fp_status)
  27
  28
  29/* F floating (VAX) */
  30static uint64_t float32_to_f(float32 fa)
  31{
  32    uint64_t r, exp, mant, sig;
  33    CPU_FloatU a;
  34
  35    a.f = fa;
  36    sig = ((uint64_t)a.l & 0x80000000) << 32;
  37    exp = (a.l >> 23) & 0xff;
  38    mant = ((uint64_t)a.l & 0x007fffff) << 29;
  39
  40    if (exp == 255) {
  41        /* NaN or infinity */
  42        r = 1; /* VAX dirty zero */
  43    } else if (exp == 0) {
  44        if (mant == 0) {
  45            /* Zero */
  46            r = 0;
  47        } else {
  48            /* Denormalized */
  49            r = sig | ((exp + 1) << 52) | mant;
  50        }
  51    } else {
  52        if (exp >= 253) {
  53            /* Overflow */
  54            r = 1; /* VAX dirty zero */
  55        } else {
  56            r = sig | ((exp + 2) << 52);
  57        }
  58    }
  59
  60    return r;
  61}
  62
  63static float32 f_to_float32(CPUAlphaState *env, uintptr_t retaddr, uint64_t a)
  64{
  65    uint32_t exp, mant_sig;
  66    CPU_FloatU r;
  67
  68    exp = ((a >> 55) & 0x80) | ((a >> 52) & 0x7f);
  69    mant_sig = ((a >> 32) & 0x80000000) | ((a >> 29) & 0x007fffff);
  70
  71    if (unlikely(!exp && mant_sig)) {
  72        /* Reserved operands / Dirty zero */
  73        dynamic_excp(env, retaddr, EXCP_OPCDEC, 0);
  74    }
  75
  76    if (exp < 3) {
  77        /* Underflow */
  78        r.l = 0;
  79    } else {
  80        r.l = ((exp - 2) << 23) | mant_sig;
  81    }
  82
  83    return r.f;
  84}
  85
  86uint32_t helper_f_to_memory(uint64_t a)
  87{
  88    uint32_t r;
  89    r =  (a & 0x00001fffe0000000ull) >> 13;
  90    r |= (a & 0x07ffe00000000000ull) >> 45;
  91    r |= (a & 0xc000000000000000ull) >> 48;
  92    return r;
  93}
  94
  95uint64_t helper_memory_to_f(uint32_t a)
  96{
  97    uint64_t r;
  98    r =  ((uint64_t)(a & 0x0000c000)) << 48;
  99    r |= ((uint64_t)(a & 0x003fffff)) << 45;
 100    r |= ((uint64_t)(a & 0xffff0000)) << 13;
 101    if (!(a & 0x00004000)) {
 102        r |= 0x7ll << 59;
 103    }
 104    return r;
 105}
 106
 107/* ??? Emulating VAX arithmetic with IEEE arithmetic is wrong.  We should
 108   either implement VAX arithmetic properly or just signal invalid opcode.  */
 109
 110uint64_t helper_addf(CPUAlphaState *env, uint64_t a, uint64_t b)
 111{
 112    float32 fa, fb, fr;
 113
 114    fa = f_to_float32(env, GETPC(), a);
 115    fb = f_to_float32(env, GETPC(), b);
 116    fr = float32_add(fa, fb, &FP_STATUS);
 117    return float32_to_f(fr);
 118}
 119
 120uint64_t helper_subf(CPUAlphaState *env, uint64_t a, uint64_t b)
 121{
 122    float32 fa, fb, fr;
 123
 124    fa = f_to_float32(env, GETPC(), a);
 125    fb = f_to_float32(env, GETPC(), b);
 126    fr = float32_sub(fa, fb, &FP_STATUS);
 127    return float32_to_f(fr);
 128}
 129
 130uint64_t helper_mulf(CPUAlphaState *env, uint64_t a, uint64_t b)
 131{
 132    float32 fa, fb, fr;
 133
 134    fa = f_to_float32(env, GETPC(), a);
 135    fb = f_to_float32(env, GETPC(), b);
 136    fr = float32_mul(fa, fb, &FP_STATUS);
 137    return float32_to_f(fr);
 138}
 139
 140uint64_t helper_divf(CPUAlphaState *env, uint64_t a, uint64_t b)
 141{
 142    float32 fa, fb, fr;
 143
 144    fa = f_to_float32(env, GETPC(), a);
 145    fb = f_to_float32(env, GETPC(), b);
 146    fr = float32_div(fa, fb, &FP_STATUS);
 147    return float32_to_f(fr);
 148}
 149
 150uint64_t helper_sqrtf(CPUAlphaState *env, uint64_t t)
 151{
 152    float32 ft, fr;
 153
 154    ft = f_to_float32(env, GETPC(), t);
 155    fr = float32_sqrt(ft, &FP_STATUS);
 156    return float32_to_f(fr);
 157}
 158
 159
 160/* G floating (VAX) */
 161static uint64_t float64_to_g(float64 fa)
 162{
 163    uint64_t r, exp, mant, sig;
 164    CPU_DoubleU a;
 165
 166    a.d = fa;
 167    sig = a.ll & 0x8000000000000000ull;
 168    exp = (a.ll >> 52) & 0x7ff;
 169    mant = a.ll & 0x000fffffffffffffull;
 170
 171    if (exp == 2047) {
 172        /* NaN or infinity */
 173        r = 1; /* VAX dirty zero */
 174    } else if (exp == 0) {
 175        if (mant == 0) {
 176            /* Zero */
 177            r = 0;
 178        } else {
 179            /* Denormalized */
 180            r = sig | ((exp + 1) << 52) | mant;
 181        }
 182    } else {
 183        if (exp >= 2045) {
 184            /* Overflow */
 185            r = 1; /* VAX dirty zero */
 186        } else {
 187            r = sig | ((exp + 2) << 52);
 188        }
 189    }
 190
 191    return r;
 192}
 193
 194static float64 g_to_float64(CPUAlphaState *env, uintptr_t retaddr, uint64_t a)
 195{
 196    uint64_t exp, mant_sig;
 197    CPU_DoubleU r;
 198
 199    exp = (a >> 52) & 0x7ff;
 200    mant_sig = a & 0x800fffffffffffffull;
 201
 202    if (!exp && mant_sig) {
 203        /* Reserved operands / Dirty zero */
 204        dynamic_excp(env, retaddr, EXCP_OPCDEC, 0);
 205    }
 206
 207    if (exp < 3) {
 208        /* Underflow */
 209        r.ll = 0;
 210    } else {
 211        r.ll = ((exp - 2) << 52) | mant_sig;
 212    }
 213
 214    return r.d;
 215}
 216
 217uint64_t helper_g_to_memory(uint64_t a)
 218{
 219    uint64_t r;
 220    r =  (a & 0x000000000000ffffull) << 48;
 221    r |= (a & 0x00000000ffff0000ull) << 16;
 222    r |= (a & 0x0000ffff00000000ull) >> 16;
 223    r |= (a & 0xffff000000000000ull) >> 48;
 224    return r;
 225}
 226
 227uint64_t helper_memory_to_g(uint64_t a)
 228{
 229    uint64_t r;
 230    r =  (a & 0x000000000000ffffull) << 48;
 231    r |= (a & 0x00000000ffff0000ull) << 16;
 232    r |= (a & 0x0000ffff00000000ull) >> 16;
 233    r |= (a & 0xffff000000000000ull) >> 48;
 234    return r;
 235}
 236
 237uint64_t helper_addg(CPUAlphaState *env, uint64_t a, uint64_t b)
 238{
 239    float64 fa, fb, fr;
 240
 241    fa = g_to_float64(env, GETPC(), a);
 242    fb = g_to_float64(env, GETPC(), b);
 243    fr = float64_add(fa, fb, &FP_STATUS);
 244    return float64_to_g(fr);
 245}
 246
 247uint64_t helper_subg(CPUAlphaState *env, uint64_t a, uint64_t b)
 248{
 249    float64 fa, fb, fr;
 250
 251    fa = g_to_float64(env, GETPC(), a);
 252    fb = g_to_float64(env, GETPC(), b);
 253    fr = float64_sub(fa, fb, &FP_STATUS);
 254    return float64_to_g(fr);
 255}
 256
 257uint64_t helper_mulg(CPUAlphaState *env, uint64_t a, uint64_t b)
 258{
 259    float64 fa, fb, fr;
 260
 261    fa = g_to_float64(env, GETPC(), a);
 262    fb = g_to_float64(env, GETPC(), b);
 263    fr = float64_mul(fa, fb, &FP_STATUS);
 264    return float64_to_g(fr);
 265}
 266
 267uint64_t helper_divg(CPUAlphaState *env, uint64_t a, uint64_t b)
 268{
 269    float64 fa, fb, fr;
 270
 271    fa = g_to_float64(env, GETPC(), a);
 272    fb = g_to_float64(env, GETPC(), b);
 273    fr = float64_div(fa, fb, &FP_STATUS);
 274    return float64_to_g(fr);
 275}
 276
 277uint64_t helper_sqrtg(CPUAlphaState *env, uint64_t a)
 278{
 279    float64 fa, fr;
 280
 281    fa = g_to_float64(env, GETPC(), a);
 282    fr = float64_sqrt(fa, &FP_STATUS);
 283    return float64_to_g(fr);
 284}
 285
 286uint64_t helper_cmpgeq(CPUAlphaState *env, uint64_t a, uint64_t b)
 287{
 288    float64 fa, fb;
 289
 290    fa = g_to_float64(env, GETPC(), a);
 291    fb = g_to_float64(env, GETPC(), b);
 292
 293    if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
 294        return 0x4000000000000000ULL;
 295    } else {
 296        return 0;
 297    }
 298}
 299
 300uint64_t helper_cmpgle(CPUAlphaState *env, uint64_t a, uint64_t b)
 301{
 302    float64 fa, fb;
 303
 304    fa = g_to_float64(env, GETPC(), a);
 305    fb = g_to_float64(env, GETPC(), b);
 306
 307    if (float64_le(fa, fb, &FP_STATUS)) {
 308        return 0x4000000000000000ULL;
 309    } else {
 310        return 0;
 311    }
 312}
 313
 314uint64_t helper_cmpglt(CPUAlphaState *env, uint64_t a, uint64_t b)
 315{
 316    float64 fa, fb;
 317
 318    fa = g_to_float64(env, GETPC(), a);
 319    fb = g_to_float64(env, GETPC(), b);
 320
 321    if (float64_lt(fa, fb, &FP_STATUS)) {
 322        return 0x4000000000000000ULL;
 323    } else {
 324        return 0;
 325    }
 326}
 327
 328uint64_t helper_cvtqf(CPUAlphaState *env, uint64_t a)
 329{
 330    float32 fr = int64_to_float32(a, &FP_STATUS);
 331    return float32_to_f(fr);
 332}
 333
 334uint64_t helper_cvtgf(CPUAlphaState *env, uint64_t a)
 335{
 336    float64 fa;
 337    float32 fr;
 338
 339    fa = g_to_float64(env, GETPC(), a);
 340    fr = float64_to_float32(fa, &FP_STATUS);
 341    return float32_to_f(fr);
 342}
 343
 344uint64_t helper_cvtgq(CPUAlphaState *env, uint64_t a)
 345{
 346    float64 fa = g_to_float64(env, GETPC(), a);
 347    return float64_to_int64_round_to_zero(fa, &FP_STATUS);
 348}
 349
 350uint64_t helper_cvtqg(CPUAlphaState *env, uint64_t a)
 351{
 352    float64 fr;
 353    fr = int64_to_float64(a, &FP_STATUS);
 354    return float64_to_g(fr);
 355}
 356