Subversion Repositories pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

  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. }
  241.