Subversion Repositories pentevo

Rev

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

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