Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1186 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
#include <string.h>
14
 
15
#include "errmsg.h"
16
#include "asmerr.h"
17
#include "strcomp.h"
18
#include "as_float.h"
19
#include "aplfloat.h"
20
 
21
/*!------------------------------------------------------------------------
22
 * \fn     as_float_2_apl4(as_float_t inp, Word *p_dest)
23
 * \brief  convert from host to Apple II 4 byte float format
24
 * \param  inp value to dispose
25
 * \param  p_dest where to dispose
26
 * \return 0 or error code (<0)
27
 * ------------------------------------------------------------------------ */
28
 
29
int as_float_2_apl4(as_float_t inp, Word *p_dest)
30
{
31
  Boolean round_up;
32
  as_float_dissect_t dissect;
33
 
34
  /* Dissect number: */
35
 
36
  as_float_dissect(&dissect, inp);
37
 
38
  /* NaN and Infinity cannot be represented: */
39
 
40
  if ((dissect.fp_class == AS_FP_NAN)
41
   || (dissect.fp_class == AS_FP_INFINITE))
42
    return -EINVAL;
43
 
44
  /* (3) Denormalize small numbers: */
45
 
46
  while ((dissect.exponent < -128) && !as_float_mantissa_is_zero(&dissect))
47
  {
48
    dissect.exponent++;
49
    as_float_mantissa_shift_right(dissect.mantissa, 0, dissect.mantissa_bits);
50
  }
51
 
52
  /* Build Two's complement.  Note the sign becomes part of the
53
     mantissa, which is afterwards one bit longer: */
54
 
55
  as_float_mantissa_twos_complement(&dissect);
56
 
57
  /* Normalize, so that topmost bits of mantissa are unequal.  This happens
58
     for powers of two, after negating: */
59
 
60
  switch (as_float_mantissa_extract(&dissect, 0, 2))
61
  {
62
    case 0:
63
    case 3:
64
      if (dissect.exponent > -128)
65
      {
66
        dissect.exponent--;
67
        as_float_mantissa_shift_left(dissect.mantissa, 0, dissect.mantissa_bits);
68
      }
69
      break;
70
  }
71
 
72
  /* (4) Round mantissa.  We will use 24 of them.  So the "half LSB" bit
73
         to look at is bit 24, seen from left: */
74
 
75
  if (as_float_get_mantissa_bit(dissect.mantissa, dissect.mantissa_bits, 24))
76
  {
77
    if (!as_float_mantissa_is_zero_from(&dissect, 25)) /* > 0.5 */
78
      round_up = True;
79
    else /* == 0.5 */
80
      round_up = as_float_get_mantissa_bit(dissect.mantissa, dissect.mantissa_bits, 23);
81
  }
82
  else /* < 0.5 */
83
    round_up = False;
84
 
85
  if (round_up)
86
  {
87
    as_float_mant_t round_sum;
88
 
89
    (void)as_float_mantissa_add_bit(round_sum, dissect.mantissa, 24, dissect.mantissa_bits);
90
 
91
    /* overflow during round-up? */
92
 
93
    if ((round_sum[0] ^ dissect.mantissa[0]) & 0x80000000ul)
94
    {
95
      dissect.exponent++;
96
      /* Arithmetic right shift of signed number to preserve sign: */
97
      as_float_mantissa_shift_right(round_sum, as_float_get_mantissa_bit(dissect.mantissa, dissect.mantissa_bits, 0), dissect.mantissa_bits);
98
    }
99
 
100
    memcpy(dissect.mantissa, round_sum, sizeof(dissect.mantissa));
101
  }
102
 
103
  /* After knowing final exponent, check for overflow: */
104
 
105
  if (dissect.exponent > 127)
106
    return -E2BIG;
107
 
108
  /* (5) mantissa zero means exponent is also zero */
109
 
110
  if (as_float_mantissa_is_zero(&dissect))
111
    dissect.exponent = 0;
112
 
113
  /* (7) Assemble: */
114
 
115
  p_dest[0] = (((dissect.exponent + 128) << 8) & 0xff00ul)
116
            | as_float_mantissa_extract(&dissect, 0, 8);
117
  p_dest[1] = as_float_mantissa_extract(&dissect, 8, 16);
118
 
119
  return 0;
120
}