Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1126 savelij 1
/* aplfloat.c */
2
/*****************************************************************************/
3
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
4
/*                                                                           */
5
/* AS                                                                        */
6
/*                                                                           */
7
/* APPLE<->IEEE Floating Point Conversion on host                            */
8
/*                                                                           */
9
/*****************************************************************************/
10
 
11
#include "stdinc.h"
12
#include <errno.h>
13
 
14
#include "errmsg.h"
15
#include "asmerr.h"
16
#include "strcomp.h"
17
#include "ieeefloat.h"
18
#include "aplfloat.h"
19
 
20
/*!------------------------------------------------------------------------
21
 * \fn     Double_2_apl4(Double inp, Word *p_dest)
22
 * \brief  convert from host to Apple II 4 byte float format
23
 * \param  inp value to dispose
24
 * \param  p_dest where to dispose
25
 * \return 0 or error code
26
 * ------------------------------------------------------------------------ */
27
 
28
int Double_2_apl4(Double inp, Word *p_dest)
29
{
30
  Word sign;
31
  Integer exponent;
32
  LongWord mantissa, fraction;
33
  Boolean round_up;
34
 
35
  /* Dissect IEEE number.  (Absolute of) mantissa is already in range 2.0 > M >= 1.0,
36
     unless denormal. NaN and Infinity cannot be represented: */
37
 
38
  ieee8_dissect(&sign, &exponent, &mantissa, &fraction, inp);
39
  if (exponent == 2047)
40
    return EINVAL;
41
 
42
  /* (3) Denormalize small numbers: */
43
 
44
#if 0
45
  printf("0x%08x 0x%08x\n", (unsigned)mantissa, (unsigned)fraction);
46
#endif
47
  while ((exponent < -128) && (mantissa || fraction))
48
  {
49
    mantissa++;
50
    fraction = ((fraction >> 1) & 0x7ffffful) | ((mantissa & 1) ? 0x800000ul : 0x000000ul);
51
    mantissa = (mantissa >> 1) & 0x1fffffful;
52
  }
53
 
54
  /* Two's Complement of mantissa. Note mantissa afterwards has 30 bits, including sign: */
55
 
56
  if (sign)
57
  {
58
    fraction = fraction ^ 0x00fffffful;
59
    mantissa = mantissa ^ 0x7ffffffful;
60
    if (++fraction >= 0x01000000ul)
61
    {
62
      fraction = 0;
63
      mantissa = (mantissa + 1) & 0x7ffffffful;
64
 
65
    }
66
  }
67
 
68
  /* Normalize, so that topmost bits of mantissa are unequal.  This happens
69
     for powers of two, after negating:  */
70
 
71
  switch ((mantissa >> 28) & 3)
72
  {
73
    case 0:
74
    case 3:
75
      exponent--;
76
      mantissa = ((mantissa << 1) & 0x7ffffffeul) | ((fraction >> 23) & 1);
77
      fraction = (fraction << 1) & 0xfffffful;
78
      break;
79
  }
80
 
81
  /* (4) Round mantissa.  The mantissa currently has 30 bits, and - including sign - we
82
         will use 24 of them.  So the "half LSB" bit to look at is bit 5: */
83
 
84
  if (mantissa & 0x20) /* >= 0.5 */
85
  {
86
    if ((mantissa & 0x1f) || fraction) /* > 0.5 */
87
      round_up = True;
88
    else /* == 0.5 */
89
      round_up = !!(mantissa & 0x40); /* round towards even */
90
  }
91
  else /* < 0.5 */
92
    round_up = False;
93
 
94
  if (round_up)
95
  {
96
    LongWord new_mantissa = mantissa + 0x40;
97
 
98
    /* overflow during round-up? */
99
 
100
    if ((new_mantissa ^ mantissa) & 0x40000000ul)
101
    {
102
      /* arithmetic right shift, preserving sign */
103
      mantissa = (mantissa & 0x40000000ul) | ((mantissa >> 1) & 0x3ffffffful);
104
      exponent++;
105
    }
106
    mantissa += 0x40;
107
  }
108
 
109
  /* After knowing final exponent, check for overflow: */
110
 
111
  if (exponent > 127)
112
    return E2BIG;
113
 
114
  /* (5) mantissa zero means exponent is also zero */
115
 
116
  if (!mantissa)
117
    exponent = 0;
118
 
119
  /* (7) Assemble: */
120
 
121
  p_dest[0] = (((exponent + 128) << 8) & 0xff00ul) | ((mantissa >> 22) & 0x00fful);
122
  p_dest[1] = (mantissa >> 6) & 0xfffful;
123
  return 0;
124
}
125
 
126
/*!------------------------------------------------------------------------
127
 * \fn     check_apl_fp_dispose_result(int ret, const struct sStrComp *p_arg)
128
 * \brief  check the result of Double_2... and throw associated error messages
129
 * \param  ret return code
130
 * \param  p_arg associated source argument
131
 * ------------------------------------------------------------------------ */
132
 
133
Boolean check_apl_fp_dispose_result(int ret, const struct sStrComp *p_arg)
134
{
135
  switch (ret)
136
  {
137
    case 0:
138
      return True;
139
    case E2BIG:
140
      WrStrErrorPos(ErrNum_OverRange, p_arg);
141
      return False;
142
    default:
143
      WrXErrorPos(ErrNum_InvArg, "INF/NaN", &p_arg->Pos);
144
      return False;
145
  }
146
}