#include "fpi.h"

/*
* the following routines depend on memory format, not the machine
*/

void
fpis2i(Internal *i, void *v)
{
       Single *s = v;

       i->s = (*s & 0x80000000) ? 1: 0;
       if((*s & ~0x80000000) == 0){
               SetZero(i);
               return;
       }
       i->e = ((*s>>23) & 0x00FF) - SingleExpBias + ExpBias;
       i->h = (*s & 0x007FFFFF)<<(1+NGuardBits);
       i->l = 0;
       if(i->e)
               i->h |= HiddenBit;
       else
               i->e++;
}

void
fpid2i(Internal *i, void *v)
{
       Double *d = v;

       i->s = (d->h & 0x80000000) ? 1: 0;
       i->e = (d->h>>20) & 0x07FF;
       i->h = ((d->h & 0x000FFFFF)<<(4+NGuardBits))|((d->l>>25) & 0x7F);
       i->l = (d->l & 0x01FFFFFF)<<NGuardBits;
       if(i->e)
               i->h |= HiddenBit;
       else
               i->e++;
}

void
fpiw2i(Internal *i, void *v)
{
       Word w, word = *(Word*)v;
       short e;

       if(word < 0){
               i->s = 1;
               word = -word;
       }
       else
               i->s = 0;
       if(word == 0){
               SetZero(i);
               return;
       }
       if(word > 0){
               for (e = 0, w = word; w; w >>= 1, e++)
                       ;
       } else
               e = 32;
       if(e > FractBits){
               i->h = word>>(e - FractBits);
               i->l = (word & ((1<<(e - FractBits)) - 1))<<(2*FractBits - e);
       }
       else {
               i->h = word<<(FractBits - e);
               i->l = 0;
       }
       i->e = (e - 1) + ExpBias;
}

void
fpii2s(void *v, Internal *i)
{
       short e;
       Single *s = (Single*)v;

       fpiround(i);
       if(i->h & HiddenBit)
               i->h &= ~HiddenBit;
       else
               i->e--;
       *s = i->s ? 0x80000000: 0;
       e = i->e;
       if(e < ExpBias){
               if(e <= (ExpBias - SingleExpBias))
                       return;
               e = SingleExpBias - (ExpBias - e);
       }
       else  if(e >= (ExpBias + (SingleExpMax-SingleExpBias))){
               *s |= SingleExpMax<<23;
               return;
       }
       else
               e = SingleExpBias + (e - ExpBias);
       *s |= (e<<23)|(i->h>>(1+NGuardBits));
}

void
fpii2d(void *v, Internal *i)
{
       Double *d = (Double*)v;

       fpiround(i);
       if(i->h & HiddenBit)
               i->h &= ~HiddenBit;
       else
               i->e--;
       i->l = ((i->h & GuardMask)<<25)|(i->l>>NGuardBits);
       i->h >>= NGuardBits;
       d->h = i->s ? 0x80000000: 0;
       d->h |= (i->e<<20)|((i->h & 0x00FFFFFF)>>4);
       d->l = (i->h<<28)|i->l;
}

void
fpii2w(Word *word, Internal *i)
{
       Word w;
       short e;

       fpiround(i);
       e = (i->e - ExpBias) + 1;
       if(e <= 0)
               w = 0;
       else if(e > 31)
               w = 0x7FFFFFFF;
       else if(e > FractBits)
               w = (i->h<<(e - FractBits))|(i->l>>(2*FractBits - e));
       else
               w = i->h>>(FractBits-e);
       if(i->s)
               w = -w;
       *word = w;
}