View Single Post
Old 16 August 2020, 02:39   #6
alkis
Registered User

 
Join Date: Dec 2010
Location: Athens/Greece
Age: 50
Posts: 579
Ok, this is a working draft
Very very lightly tested, seems to work. Also fixed a bug or two on the initial C code that I found.

Code:
#include <stdio.h>
#include <stdint.h>


uint32_t rol(uint32_t x, uint32_t n) {
  //return (x >> n % 32) | (x << (32-n) % 32);
  return (x << n ) | (x >> (32-n));
}

uint32_t ror(uint32_t x, uint32_t n) {
  //return (x >> n % 32) | (x << (32-n) % 32);
  return (x >> n ) | (x << (32-n));
}


float ffptieee(const uint32_t val)
{
	uint32_t x = val;
	union {
		float f;
		uint32_t i;
	} _fcast;

	x = x + x;		// delete mantissa high bit
	if (x == 0) {
		// if zero, branch zero as finished
          _fcast.i = 0;
          return _fcast.f;
	}

	uint8_t k = x & 0xff;

	k ^= 0x80;	// to two's complement exponent
        k >>= 1;	// form 8-bit exponent
        if (k & 0x40)   // do an actual ASR here
          k |= 0x80;    // if previous leftmost bit was 1, do the now leftmost bit 1 as well
        
        
	k -= 0x82;	// adjust 64 to 127 and excessize

	x = (x & ~0xff) | k;

	x = (x << 16) | (x >> 16);	// swap for high byte placement
	x = rol(x, 7);	// set sign+exp in high byte
	_fcast.i = x;

	return _fcast.f;
}


uint32_t ffpfieee(float val) {
  union {
    float f;
    uint32_t i;
  } _fcast;

  _fcast.f = val;

  uint32_t x = _fcast.i;

  x = (x << 16) | (x >> 16);  // swap
  x = ror(x, 7);

  uint8_t k = x & 0xff;

  k ^= 0x80;

  uint8_t orig_k=k;
  uint8_t b = k & 0x80;
  k+=k;
  uint8_t a = k & 0x80;
  if (a != b) {
    //printf("Overflow? (a=%d b=%d)\n", a, b);
    if (k < orig_k) {
      //printf("Carry must be set\n");
      if ((k != 0x7C) && (k != 0x7E)) {
        //printf("Need to implement FFPTOVF (k=%02X)\n", k);
        //x &= 0xFFFFFEFF;  // clear sign bit out
        //if (!x)... no need for code, all branches lead to 0
        return 0;
      } else {
        k+= 0x80+(2<<1)+1;
        x = ror(x, 1);
        if (k)
          return x;
        return 0;
      }
    } else {
      // FFPOVLW, EXPONENT HIGH - CHECK FOR EXPONENT TOO HIGH, INFINITY, OR NAN
      if (k == 0xFE) {
        x >>= 9;
        if (x) {
          // NaN
          return 0;
        } else {
          // INF
          if (x & 0x100) 
            x = 0xFFFFFFFF;
          else
            x = 0xFFFFFF7F;
          return x;
        }
      } else {
        // EXPHI
        if (x & 0x100) 
          x = 0xFFFFFFFF;
        else
          x = 0xFFFFFF7F;
        return x;
      }
    }
  }
  // BVS.S     FFPOVF    BRANCH WILL NOT FIT

  k+=(2<<1)+1;
  b = k & 0x80;
  if (a == 0 && b) {
    // EXPHI
    if (x & 0x100) 
      x = 0xFFFFFFFF;
    else
      x = 0xFFFFFF7F;
    return x;
  }
  // BVS.S     EXPHI     BRANCH EXPONENT TOO LARGE (OVERFLOW)

  k ^= 0x80;

  x = (x & 0xFFFFFF00) | k;
  x = ror(x, 1);
  return x;
}

int main(int argc, char *argv[]) {
  union {
    float f;
    uint32_t i;
  } _fcast, g;

  for (int i = -5; i <= 5; ++i) {
    float f = i*1;
    _fcast.f = f;
    uint32_t ffp = ffpfieee(f);
    g.f = ffptieee(ffp);
    printf("%f %f FFP: %08X %08X (%08X) ", f, ffptieee(ffp), ffp, _fcast.i, g.i);
    if (_fcast.i != g.i)
      printf(" Mismatch\n");
    else
      printf("\n");
  }
  /* for (int i = 0; i < 10; ++i) { */
  /*   float f = i/10.f; */
  /*   _fcast.f = f; */
  /*   printf("$%08X, ", _fcast.i); */
  /* } */
  /* printf("\n"); */
  
  return 0;
}
alkis is offline  
 
Page generated in 0.04462 seconds with 11 queries