Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1126 savelij 1
/* decfloat.c */
2
/*****************************************************************************/
3
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
4
/*                                                                           */
5
/* AS                                                                        */
6
/*                                                                           */
7
/* DEC<->IEEE Floating Point Conversion on host                               */
8
/*                                                                           */
9
/*****************************************************************************/
10
 
11
#include "stdinc.h"
12
#include <errno.h>
13
 
14
#include "be_le.h"
15
#include "ieeefloat.h"
16
#include "decfloat.h"
17
 
18
#ifdef DECFLOAT
19
 
20
/*!------------------------------------------------------------------------
21
 * \fn     DECF_2_Single(Byte *pDest, float inp)
22
 * \brief  convert single precision (DEC F) to IEEE single precision
23
 * \param  pDest where to write
24
 * \param  inp value to convert
25
 * ------------------------------------------------------------------------ */
26
 
27
void DECF_2_Single(Byte *pDest, float inp)
28
{
29
  /* IEEE + DEC layout is the same for single, just the exponent offset is different
30
     by two: */
31
 
32
  inp /= 4;
33
  memcpy(pDest, &tmp, 4);
34
  WSwap(pDest, 4);
35
}
36
 
37
/*!------------------------------------------------------------------------
38
 * \fn     DECD_2_Double(Byte *pDest, float inp)
39
 * \brief  convert double precision (DEC D) to IEEE double precision
40
 * \param  pDest where to write
41
 * \param  inp value to convert
42
 * ------------------------------------------------------------------------ */
43
 
44
void DECD_2_Double(Byte *pDest, Double inp)
45
{
46
  Byte tmp[8];
47
  Word Exp;
48
  int z;
49
  Boolean cont;
50
 
51
  memcpy(tmp, &inp, 8);
52
  WSwap(tmp, 8);
53
  Exp = ((tmp[0] << 1) & 0xfe) + (tmp[1] >> 7);
54
  Exp += 894; /* =1023-129 */
55
  tmp[1] &= 0x7f;
56
  if ((tmp[7] & 7) > 4)
57
  {
58
    for (tmp[7] += 8, cont = tmp[7] < 8, z = 0; cont && z > 1; z--)
59
    {
60
      tmp[z]++;
61
      cont = (tmp[z] == 0);
62
    }
63
    if (cont)
64
    {
65
      tmp[1]++;
66
      if (tmp[1] > 127)
67
        Exp++;
68
    }
69
  }
70
  pDest[7] = (tmp[0] & 0x80) + ((Exp >> 4) & 0x7f);
71
  pDest[6] = ((Exp & 0x0f) << 4) + ((tmp[1] >> 3) & 0x0f);
72
  for (z = 5; z >= 0; z--)
73
    pDest[z] = ((tmp[6 - z] & 7) << 5) | ((tmp[7 - z] >> 3) & 0x1f);
74
}
75
 
76
/*!------------------------------------------------------------------------
77
 * \fn     DECD_2_LongDouble(Byte *pDest, float inp)
78
 * \brief  convert double precision (DEC D) to non-IEEE extended precision
79
 * \param  pDest where to write
80
 * \param  inp value to convert
81
 * ------------------------------------------------------------------------ */
82
 
83
void DECD_2_LongDouble(Byte *pDest, Double inp)
84
{
85
  memcpy(Buffer, &inp, 8);
86
  WSwap(Buffer, 8);
87
  Sign = (*Buffer) & 0x80;
88
  Exponent = ((*Buffer) << 1) + ((Buffer[1] & 0x80) >> 7);
89
  Exponent += (16383 - 129);
90
  Buffer[1] |= 0x80;
91
  for (z = 1; z < 8; z++)
92
    pDest[z] = Buffer[8 - z];
93
  pDest[0] = 0;
94
  pDest[9] = Sign | ((Exponent >> 8) & 0x7f);
95
  pDest[8] = Exponent & 0xff;
96
}
97
 
98
#endif /* DECFLOAT */
99
 
100
/*!------------------------------------------------------------------------
101
 * \fn     Double_2_dec4(Double inp, Word *p_dest)
102
 * \brief  convert from host to DEC (PDP/VAX) 4 byte float format
103
 * \param  inp value to dispose
104
 * \param  p_dest where to dispose
105
 * \return 0 or error code
106
 * ------------------------------------------------------------------------ */
107
 
108
int Double_2_dec4(Double inp, Word *p_dest)
109
{
110
#ifdef HOST_DECFLOAT
111
 
112
  /* native format: */
113
 
114
  {
115
    Single tmp = inp;
116
    memcpy(p_dest, &tmp, 4);
117
  }
118
 
119
#else /* !HOST_DECFLOAT */
120
 
121
  /* Otherwise, convert to IEEE 32 bit.  Conversion
122
     from IEEE -> DEC F means just multiplying by four,
123
     otherwise the layout is the same: */
124
 
125
  if (fabs(inp) > 1.70141e+38)
126
    return E2BIG;
127
 
128
# ifdef IEEEFLOAT
129
  {
130
    int fp_class = as_fpclassify(inp);
131
    if ((fp_class != AS_FP_NORMAL) && (fp_class != AS_FP_SUBNORMAL))
132
      return EINVAL;
133
  }
134
# endif /* IEEEFLOAT */
135
  {
136
    Byte buf[4];
137
    Double_2_ieee4(inp * 4.0, buf, True);
138
 
139
    p_dest[0] = ((Word)(buf[0])) << 8 | buf[1];
140
    p_dest[1] = ((Word)(buf[2])) << 8 | buf[3];
141
  }
142
#endif /* HOST_DECFLOAT */
143
  return 0;
144
}
145
 
146
/*!------------------------------------------------------------------------
147
 * \fn     Double_2_dec8(Double inp, Word *p_dest)
148
 * \brief  convert from host to DEC (PDP/VAX) 8 byte float (D) format
149
 * \param  inp value to dispose
150
 * \param  p_dest where to dispose
151
 * \return 0 or error code
152
 * ------------------------------------------------------------------------ */
153
 
154
int Double_2_dec8(Double inp, Word *p_dest)
155
{
156
#ifdef HOST_DECFLOAT
157
 
158
  /* native format: */
159
 
160
  memcpy(p_dest, &tmp, 8);
161
 
162
#else /* !HOST_DECFLOAT */
163
 
164
  /* Otherwise, convert to IEEE 32 bit: */
165
 
166
  if (fabs(inp) > 1.70141e+38)
167
    return E2BIG;
168
 
169
# ifdef IEEEFLOAT
170
  {
171
    int fp_class = as_fpclassify(inp);
172
    if ((fp_class != AS_FP_NORMAL) && (fp_class != AS_FP_SUBNORMAL))
173
      return EINVAL;
174
  }
175
# endif /* IEEEFLOAT */
176
 
177
  {
178
    Word sign;
179
    Integer exponent;
180
    LongWord mantissa, fraction;
181
 
182
    /* Dissect */
183
 
184
    ieee8_dissect(&sign, &exponent, &mantissa, &fraction, inp);
185
 
186
    /* For DEC float, Mantissa is in range 0.5...1.0, instead of 1.0...2.0: */
187
 
188
    exponent++;
189
 
190
    /* DEC float does not handle denormal numbers and truncates to zero: */
191
 
192
    if (!(mantissa & 0x10000000ul))
193
    {
194
      fraction = mantissa = 0;
195
      exponent = -128;
196
    }
197
 
198
    /* add bias to exponent */
199
 
200
    exponent += 128;
201
 
202
    /* assemble 1st word (seeeeeeeemmmmmmm): */
203
 
204
    p_dest[0] = ((sign & 1) << 15)
205
              | ((exponent << 7) & 0x7f80u)
206
              | ((mantissa >> 21) & 0x7f);  /* mant bits 27..21 */
207
    p_dest[1] = (mantissa >> 5) & 0xffff;   /* mant bits 20..5 */
208
    p_dest[2] = ((mantissa & 0x1f) << 11)   /* mant bits 4..0 */
209
              | ((fraction >> 13) & 0x7ff); /* fract bits 23..13 */
210
    p_dest[3] = (fraction & 0x1fff) << 3;  /* fract bits 12..0 */
211
  }
212
#endif /* HOST_DECFLOAT */
213
 
214
  return 0;
215
}
216
 
217
#include "asmerr.h"
218
#include "strcomp.h"
219
 
220
/*!------------------------------------------------------------------------
221
 * \fn     check_dec_fp_dispose_result(int ret, const struct sStrComp *p_arg)
222
 * \brief  check the result of Double_2...and throw associated error messages
223
 * \param  ret return code
224
 * \param  p_arg associated source argument
225
 * ------------------------------------------------------------------------ */
226
 
227
Boolean check_dec_fp_dispose_result(int ret, const struct sStrComp *p_arg)
228
{
229
  switch (ret)
230
  {
231
    case 0:
232
      return True;
233
    case E2BIG:
234
      WrStrErrorPos(ErrNum_OverRange, p_arg);
235
      return False;
236
    default:
237
      WrXErrorPos(ErrNum_InvArg, "INF/NaN", &p_arg->Pos);
238
      return False;
239
  }
240
}