aboutsummaryrefslogtreecommitdiff
path: root/riscv/insns/fcvtmod_w_d.h
blob: e39400d27e9e075ffa159bdb79c86423dd170962 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
require_extension('D');
require_extension(EXT_ZFA);
require_fp;
uint64_t a = FRS1_D.v;

uint32_t sign = signF64UI(a);
uint32_t exp  = expF64UI(a);
uint64_t frac = fracF64UI(a);

bool inexact = false;
bool invalid = false;

if (exp == 0) {
  inexact = (frac != 0);
  frac = 0;
} else if (exp == 0x7ff) {
  /* inf or NaN */
  invalid = true;
  frac = 0;
} else {
  int true_exp = exp - 1023;
  int shift = true_exp - 52;

  /* Restore implicit bit.  */
  frac |= 1ull << 52;

  /* Shift the fraction into place.  */
  if (shift >= 64) {
    /* The fraction is shifted out entirely.  */
    frac = 0;
  } else  if ((shift >= 0) && (shift < 64)) {
    /* The number is so large we must shift the fraction left.  */
    frac <<= shift;
  } else if ((shift > -64) && (shift < 0)) {
    /* Normal case -- shift right and notice if bits shift out.  */
    inexact = (frac << (64 + shift)) != 0;
    frac >>= -shift;
  } else {
    /* The fraction is shifted out entirely.  */
    frac = 0;
    inexact = true;
  }

  /* Handle overflows */
  if (true_exp > 31 || frac > (sign ? 0x80000000ull : 0x7fffffff)) {
    /* Overflow, for which this operation raises invalid.  */
    invalid = true;
    inexact = false;  /* invalid takes precedence */
  }

  /* Honor the sign.  */
  if (sign) {
    frac = -frac;
  }
}

WRITE_RD(sext32(frac));
STATE.fflags->write(STATE.fflags->read() |
		    (inexact ? softfloat_flag_inexact : 0) |
		    (invalid ? softfloat_flag_invalid : 0));