diff --git a/include/_float.h b/include/_float.h new file mode 100644 index 000000000..9bef30b40 --- /dev/null +++ b/include/_float.h @@ -0,0 +1,54 @@ + +#ifndef _FLOAT_H_ +#define _FLOAT_H_ + +/* ieee754 32bit format: + * + * sign + * / /exponent/mantissa + * 3 32222222 22211111111110000000000 + * 1 09876543 21098765432109876543210 + * + * The sign is stored in bit 31. + * The exponent can be computed from bits 23-30 by subtracting 127. (128 = 2^1) + * The mantissa is stored in bits 0-22. + * An invisible leading bit (i.e. it is not actually stored) with value 1.0 + * is placed in front, then bit 23 has a value of 1/2, bit 22 has value 1/4 etc. + * As a result, the mantissa has a value between 1.0 and 2. + * + * 1.0 = exp=127, mantissa=0 + * + * If the exponent reaches -127 (binary 00000000), the leading 1 is no longer + * used to enable gradual underflow. + * + */ +typedef struct { + unsigned char exponent; /* msb is the sign */ + unsigned char mantissa[3]; /* msb is lsb of exponent */ +} FLOAT754; + +/* we dont wanna seriously use double precision eh? ;=P */ +/* #define double float */ + +/* string to/from float conversion functions */ +char *_ftoa(char *buf, float n); + +/* string conversion functions, these use the exponential form */ +char * __fastcall__ _ftostr(char *d, float s); /* for vsprintf */ +float __fastcall__ _strtof(char *d); + +/* beware, this is not standard */ +#ifndef M_PI +#define M_PI 3.14159265358979323846f +#endif + +/* degrees to radiants */ +#define deg2rad(_fs, _n) ((_fs / _n) * (2.0f * M_PI)) +/* radiants to degrees deg = (rad / (2 * pi)) * 256 */ +#define rad2deg(_rad, _n) ((_rad / (2.0f * M_PI)) * _n) + +/* resets fp-libs in Turbo-C and M$-C */ +#define _fpreset() + +#endif /* _FLOAT_H_ */ + diff --git a/include/math.h b/include/math.h new file mode 100644 index 000000000..7fa5d81c8 --- /dev/null +++ b/include/math.h @@ -0,0 +1,58 @@ + +#ifndef _MATH_H_ +#define _MATH_H_ + +#include "_float.h" + +/* double pow(double x, double y); */ +float __fastcall__ powf(float f, float a); /* C99 */ + +/* double sin(double x); */ +float __fastcall__ sinf(float s); /* C99 */ + +/* double cos(double x); */ +float __fastcall__ cosf(float s); /* C99 */ + +/* double log(double x); */ +float __fastcall__ logf(float x); /* C99 */ + +/* double exp(double x); */ +float __fastcall__ expf(float x); /* C99 */ + +/* double sqrt(double x); */ +float __fastcall__ sqrtf(float x); /* C99 */ + +/* double tan(double x); */ +float __fastcall__ tanf(float x); /* C99 */ + +/* double atan(double x); */ +float __fastcall__ atanf(float x); /* C99 */ + +/* double fabs(double x); */ +float __fastcall__ fabsf(float x); /* C99 */ + +/* double round(double x); */ /* C99 */ +float __fastcall__ roundf(float x); /* C99 */ + +/* double trunc(double x); */ /* C99 */ +float __fastcall__ truncf(float x); /* C99 */ + +/* double ceil(double x) */ +float __fastcall__ ceilf(float x); /* C99 */ + +/* double fmod(double x, double y); */ +float __fastcall__ fmodf(float x, float y); + +/* double floor(double x); */ +float __fastcall__ floorf(float x); + +/* beware, this is not standard */ +#ifndef M_PI +#define M_PI 3.14159265358979323846f +#endif + +/* FIXME */ +float __fastcall__ _fatan2(float x, float y); + +#endif /* _MATH_H_ */ + diff --git a/libsrc/Makefile b/libsrc/Makefile index 8a4f11414..65607cbd0 100644 --- a/libsrc/Makefile +++ b/libsrc/Makefile @@ -177,8 +177,12 @@ endif SRCDIRS = $(SRCDIR) +SRCDIRS += float/softfloat \ + float/softmath + ifeq ($(TARGET),$(filter $(TARGET),$(CBMS))) SRCDIRS += cbm + SRCDIRS += float/cbmkernal endif ifeq ($(TARGET),$(filter $(TARGET),$(GEOS))) diff --git a/libsrc/c64/extra/fp754kernal.s b/libsrc/c64/extra/fp754kernal.s new file mode 100644 index 000000000..f9ef3261c --- /dev/null +++ b/libsrc/c64/extra/fp754kernal.s @@ -0,0 +1,70 @@ + +; import/overload stubs for the C64 kernal floating point implementation + + .import ___cbmkernal_afloat + .import ___cbmkernal_aufloat + .import ___cbmkernal_axfloat + .import ___cbmkernal_axufloat + .import ___cbmkernal_eaxfloat + .import ___cbmkernal_eaxufloat + .import ___cbmkernal_feaxint + .import ___cbmkernal_feaxlong + .import ___cbmkernal_fbnegeax + .import ___cbmkernal_fnegeax + .import ___cbmkernal_ftosaddeax + .import ___cbmkernal_ftossubeax + .import ___cbmkernal_ftosrsubeax + .import ___cbmkernal_ftosdiveax + .import ___cbmkernal_ftosmuleax + .import ___cbmkernal_ftoseqeax + .import ___cbmkernal_ftosneeax + .import ___cbmkernal_ftosgteax + .import ___cbmkernal_ftoslteax + .import ___cbmkernal_ftosgeeax + .import ___cbmkernal_ftosleeax + + .export afloat := ___cbmkernal_afloat + .export aufloat := ___cbmkernal_aufloat + .export axfloat := ___cbmkernal_axfloat + .export axufloat := ___cbmkernal_axufloat + .export eaxfloat := ___cbmkernal_eaxfloat + .export eaxufloat := ___cbmkernal_eaxufloat + .export feaxint := ___cbmkernal_feaxint + .export feaxlong := ___cbmkernal_feaxlong + .export fbnegeax := ___cbmkernal_fbnegeax + .export fnegeax := ___cbmkernal_fnegeax + .export ftosaddeax := ___cbmkernal_ftosaddeax + .export ftossubeax := ___cbmkernal_ftossubeax + .export ftosrsubeax := ___cbmkernal_ftosrsubeax + .export ftosdiveax := ___cbmkernal_ftosdiveax + .export ftosmuleax := ___cbmkernal_ftosmuleax + .export ftoseqeax := ___cbmkernal_ftoseqeax + .export ftosneeax := ___cbmkernal_ftosneeax + .export ftosgteax := ___cbmkernal_ftosgteax + .export ftoslteax := ___cbmkernal_ftoslteax + .export ftosgeeax := ___cbmkernal_ftosgeeax + .export ftosleeax := ___cbmkernal_ftosleeax + + .import ___cbmkernal_powf + .import ___cbmkernal_sinf + .import ___cbmkernal_cosf + .import ___cbmkernal_logf + .import ___cbmkernal_expf + .import ___cbmkernal_sqrtf + .import ___cbmkernal_tanf + .import ___cbmkernal_atanf + .import ___cbmkernal_fabsf + .import ___cbmkernal_roundf + .import ___cbmkernal_truncf + + .export _powf := ___cbmkernal_powf + .export _sinf := ___cbmkernal_sinf + .export _cosf := ___cbmkernal_cosf + .export _logf := ___cbmkernal_logf + .export _expf := ___cbmkernal_expf + .export _sqrtf := ___cbmkernal_sqrtf + .export _tanf := ___cbmkernal_tanf + .export _atanf := ___cbmkernal_atanf + .export _fabsf := ___cbmkernal_fabsf + .export _roundf := ___cbmkernal_roundf + .export _truncf := ___cbmkernal_truncf diff --git a/libsrc/float/cbmkernal/cbmfp-vic20.inc b/libsrc/float/cbmkernal/cbmfp-vic20.inc new file mode 100644 index 000000000..6ffb952d3 --- /dev/null +++ b/libsrc/float/cbmkernal/cbmfp-vic20.inc @@ -0,0 +1,63 @@ + +FAC_EXPONENT = $61 +FAC_MANTISSA0 = $62 +FAC_MANTISSA1 = $63 +FAC_MANTISSA2 = $64 +FAC_MANTISSA3 = $65 +FAC_SIGN = $66 + +ARG_EXPONENT = $69 +ARG_MANTISSA0 = $6a +ARG_MANTISSA1 = $6b +ARG_MANTISSA2 = $6c +ARG_MANTISSA3 = $6d +ARG_SIGN = $6e + +FAC_SIGN_COMPARE = $6f +FAC_ROUNDING = $70 + +; addresses of the floating point routines in CBM BASIC V2 + +; the following are the addresses in the VIC-20 ROM - the library can probably be +; used with other CBM targets just by adjusting these addresses + +BASIC_FAC_Not = $ced4 ; in/out: FAC ; yup, c64 & vic are this different +BASIC_FAC_Cos = $e261 ; in/out: FAC +BASIC_FAC_Sin = $e268 ; in/out: FAC +BASIC_FAC_Tan = $e2b1 ; in/out: FAC +BASIC_FAC_Atn = $e30b ; in/out: FAC +BASIC_FAC_Rnd = $e094 ; in/out: FAC +BASIC_FAC_Int = $dccc ; in/out: FAC +BASIC_FAC_Sqr = $df71 ; in/out: FAC +BASIC_FAC_Exp = $dfed ; in/out: FAC +BASIC_FAC_Log = $d9ea ; in/out: FAC +BASIC_FAC_Round = $dc1b ; in/out: FAC +BASIC_FAC_Sgn = $dc39 ; in/out: FAC +BASIC_FAC_Abs = $dc58 ; in/out: FAC + +BASIC_ARG_FAC_Or = $cfe6 ; in: ARG,FAC out:FAC +BASIC_ARG_FAC_And = $cfe9 ; in: ARG,FAC out:FAC +BASIC_ARG_FAC_Sub = $d853 ; in: ARG,FAC out:FAC +BASIC_ARG_FAC_Add = $d86a ; in: ARG,FAC out:FAC +BASIC_ARG_FAC_Mul = $da2b ; in: ARG,FAC out:FAC +BASIC_ARG_FAC_Div = $db12 ; in: ARG,FAC out:FAC +BASIC_ARG_FAC_Pow = $df7b ; in: ARG,FAC out:FAC + +BASIC_u8_to_FAC = $d3a2 ; y: value +BASIC_s8_to_FAC = $dc3c ; a: value +BASIC_u16_to_FAC = $dc49 ; a/y:lo/hi value (sta $62 sty $63 sec ldx#$90 jsr...) +BASIC_s16_to_FAC = $d395 ; a/y:lo/hi value + +BASIC_FAC_to_u16 = $dc9b ; in:FAC out: y/a:lo/hi value + +BASIC_string_to_FAC = $d7b5 ; in: $22/$23 ptr to str,a=strlen out: FAC value +BASIC_FAC_to_string = $dddd ; in: FAC value out: str at $0100 a/y ptr to str + +BASIC_LoadARG = $da8c ; a/y:lo/hi ptr to 5-byte float +BASIC_LoadFAC = $dba2 ; a/y:lo/hi ptr to 5-byte float + +BASIC_FAC_testsgn = $dc2b ; in: FAC(x1) out: a=0 (x1=0) a=1 (x1>0) a=255 (x1<0) +BASIC_FAC_cmp = $dc5b ; in: FAC(x1) a/y ptr lo/hi to x2 out: a=0 (x1=x2) a=1 (x1>x2) a=255 (x1 float + .export ___cbmkernal_afloat +___cbmkernal_afloat: + jmp __ctof + +; 8bit unsigned -> float + .export ___cbmkernal_aufloat +___cbmkernal_aufloat: + jmp __utof + +; 16bit signed -> float + .export ___cbmkernal_axfloat +___cbmkernal_axfloat: + jmp __itof + +; 16bit unsigned -> float + .export ___cbmkernal_axufloat +___cbmkernal_axufloat: + jmp __stof + +; FIXME: this might be more accurate when done directly in one step (but the +; kernal can not do this for 32bit) +; 32bit signed -> float + .importzp sreg, tmp1 + .import pusheax + + .export ___cbmkernal_eaxfloat +___cbmkernal_eaxfloat: + + sta tmp1 + + lda sreg + pha + lda sreg+1 + pha + + ; get lower 16bit + lda tmp1 + + ; convert lower 16 bit + jsr __stof + jsr pusheax ; push eax to stack + + ; / 65536 + ldx #$00 + lda #$80 + sta sreg + lda #$47 + sta sreg+1 + + jsr __fdiv + jsr pusheax ; push eax to stack + + ; get higher 16bit + pla + tax + pla + ; convert higher 16 bit + jsr __itof + + jsr __fadd + + jsr pusheax ; push eax to stack + + ; * 65536 + ldx #$00 + lda #$80 + sta sreg + lda #$47 + sta sreg+1 + + jmp __fmul + +; FIXME: this might be more accurate when done directly in one step (but the +; kernal can not do this for 32bit) +; 32bit unsigned -> float + .importzp sreg, tmp1 + .import pusheax + + .export ___cbmkernal_eaxufloat +___cbmkernal_eaxufloat: + + sta tmp1 + + lda sreg + pha + lda sreg+1 + pha + + ; get lower 16bit + lda tmp1 + + ; convert lower 16 bit + jsr __stof + jsr pusheax ; push eax to stack + + ; / 65536 + ldx #$00 + lda #$80 + sta sreg + lda #$47 + sta sreg+1 + + jsr __fdiv + jsr pusheax ; push eax to stack + + ; get higher 16bit + pla + tax + pla + ; convert higher 16 bit + jsr __stof + + jsr __fadd + + jsr pusheax ; push eax to stack + + ; * 65536 + ldx #$00 + lda #$80 + sta sreg + lda #$47 + sta sreg+1 + + jmp __fmul + +;-------------------------------------------------------------- + + .import __ftoi + +; float -> 16bit int + .export ___cbmkernal_feaxint +___cbmkernal_feaxint: + jmp __ftoi + +; FIXME: this might be more accurate when done directly in one step (but the +; kernal can not do this for 32bit) +; float -> 32bit int + .importzp tmp1, tmp2 + .export ___cbmkernal_feaxlong +___cbmkernal_feaxlong: + + jsr pusheax + + ; primary = primary / 65536 + jsr pusheax ; push eax to stack + ldx #$00 + lda #$80 + sta sreg + lda #$47 + sta sreg+1 + jsr __fdiv ; primary / TOS + ; convert result to int and save + jsr __ftoi + sta tmp1 + stx tmp2 + ; convert back to float + jsr __stof + ; primary = primary * 65536 + jsr pusheax ; push eax to stack + ldx #$00 + lda #$80 + sta sreg + lda #$47 + sta sreg+1 + jsr __fmul ; primary * TOS + ; substract the result from the total number to get the rest + jsr __fsub + ; convert rest to int + jsr __ftoi + + ldy tmp2 + sty sreg+1 + ldy tmp1 + sty sreg + rts + +;-------------------------------------------------------------- + .import __fnot + .import __fneg + +; binary negate (not) for the ! operator. returns a bool! + .export ___cbmkernal_fbnegeax + .import bnegax +___cbmkernal_fbnegeax: +; FIXME: why does this not work with __fnot? + jsr __ftoi + jmp bnegax + + .export ___cbmkernal_fnegeax +___cbmkernal_fnegeax: + jmp __fneg + +;-------------------------------------------------------------- +; math ops + + .import __fadd + .import __fsub + .import __fdiv + .import __fmul + +; Primary = TOS + Primary (like tosaddeax) + .export ___cbmkernal_ftosaddeax +___cbmkernal_ftosaddeax: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + + ; FAC: ieee float is in A/X/sreg/sreg+1 + jmp __fadd + + .export ___cbmkernal_ftossubeax +___cbmkernal_ftossubeax: + jmp __fsub + .export ___cbmkernal_ftosdiveax +___cbmkernal_ftosdiveax: + jmp __fdiv + .export ___cbmkernal_ftosmuleax +___cbmkernal_ftosmuleax: + jmp __fmul + + .import __frsub +; Primary = Primary - TOS + .export ___cbmkernal_ftosrsubeax +___cbmkernal_ftosrsubeax: + jmp __frsub + +;-------------------------------------------------------------- + + .import __fcmp + + ; test for equal + .export ___cbmkernal_ftoseqeax +___cbmkernal_ftoseqeax: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + jsr __fcmp + ; a=0 (==) / a=1 (>) / a=255 (<) + cmp #0 + beq @equal + lda #0 + tax + rts +@equal: + ldx #0 + lda #1 + rts + + ; test for not equal + .export ___cbmkernal_ftosneeax +___cbmkernal_ftosneeax: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + jsr __fcmp + ; a=0 (==) / a=1 (>) / a=255 (<) + cmp #0 + beq @equal + ldx #0 + lda #1 + rts +@equal: + lda #0 + tax + rts + + ; Test for greater than + .export ___cbmkernal_ftosgteax +___cbmkernal_ftosgteax: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + jsr __fcmp + ; a=0 (==) / a=1 (>) / a=255 (<) + cmp #255 + bne @biggerorequal + ; less + ldx #0 + lda #1 + rts +@biggerorequal: + lda #0 + tax + rts + + ; Test for less than + .export ___cbmkernal_ftoslteax +___cbmkernal_ftoslteax: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + jsr __fcmp + ; a=0 (==) / a=1 (>) / a=255 (<) + cmp #1 + beq @bigger + lda #0 + tax + rts +@bigger: + ldx #0 + lda #1 + rts + + ; Test for greater than or equal to + .export ___cbmkernal_ftosgeeax +___cbmkernal_ftosgeeax: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + jsr __fcmp + ; a=0 (==) / a=1 (>) / a=255 (<) + cmp #1 + beq @bigger + ; less than or equal + ldx #0 + lda #1 + rts +@bigger: + lda #0 + tax + rts + + ; Test for less than or equal to + .export ___cbmkernal_ftosleeax +___cbmkernal_ftosleeax: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + jsr __fcmp + ; a=0 (==) / a=1 (>) / a=255 (<) + cmp #255 + beq @smaller + ; greater than or equal + ldx #0 + lda #1 + rts +@smaller: + lda #0 + tax + rts + +;-------------------------------------------------------------- +; math.h + + .import __fpow + .import __fsin + .import __fcos + .import __flog + .import __fexp + .import __fsqr + .import __ftan + .import __fatn + .import __fabs + .import __fround + .import __fint + + .export ___cbmkernal_powf +___cbmkernal_powf: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + jmp __fpow + + .export ___cbmkernal_sinf +___cbmkernal_sinf: + ; arg0: a/x/sreg/sreg+1 + jmp __fsin + + .export ___cbmkernal_cosf +___cbmkernal_cosf: + ; arg0: a/x/sreg/sreg+1 + jmp __fcos + + .export ___cbmkernal_logf +___cbmkernal_logf: + ; arg0: a/x/sreg/sreg+1 + jmp __flog + + .export ___cbmkernal_expf +___cbmkernal_expf: + ; arg0: a/x/sreg/sreg+1 + jmp __fexp + + .export ___cbmkernal_sqrtf +___cbmkernal_sqrtf: + ; arg0: a/x/sreg/sreg+1 + jmp __fsqr + + .export ___cbmkernal_tanf +___cbmkernal_tanf: + ; arg0: a/x/sreg/sreg+1 + jmp __ftan + + .export ___cbmkernal_atanf +___cbmkernal_atanf: + ; arg0: a/x/sreg/sreg+1 + jmp __fatn + + .export ___cbmkernal_fabsf +___cbmkernal_fabsf: + ; arg0: a/x/sreg/sreg+1 + jmp __fabs + + ; roundf rounds to the "nearest integer", "away from zero". that means + ; For example, round(0.5) is 1.0, and round(-0.5) is -1.0. + .export ___cbmkernal_roundf +___cbmkernal_roundf: + ; arg0: a/x/sreg/sreg+1 +; jmp __fround + + ; primary = primary + 0.5 + jsr pusheax ; push eax to stack + +; ldy #$00 +; sty sreg +; lda #$00 +; sta sreg +; ldx #0 + + bit sreg+1 + bpl @plus + + ; $3effffff + lda #$3e + sta sreg+1 + ldx #$ff + txa + sta sreg + + jsr __fadd + jmp __fint +@plus: + + ; $3fffffff + lda #$3f + sta sreg+1 + ldx #0 + txa + sta sreg + + jsr __fadd + jmp __fint + + .export ___cbmkernal_truncf +___cbmkernal_truncf: + ; arg0: a/x/sreg/sreg+1 + jmp __fint diff --git a/libsrc/float/cbmkernal/cbmfp.h b/libsrc/float/cbmkernal/cbmfp.h new file mode 100644 index 000000000..a384fa08e --- /dev/null +++ b/libsrc/float/cbmkernal/cbmfp.h @@ -0,0 +1,124 @@ + +#ifndef _CBMFS_H_ +#define _CBMFS_H_ + + +/* + + format used in basic-variables + + we dont use this format, although it saves one byte per variable, since that + removes the need of constantly converting between both formats. (someday + we may use an entire different (not cbm-specific), more accurate, format anyway) + + sign + exponent / /mantissa + 33333333 3 3222222222111111111110000000000 + 98765432 1 0987654321098765432109876543210 + + (the above seems to match wozniacs format) + + * The exponent can be computed from bits 39-32 by subtracting 129 (!) + */ +typedef struct { + unsigned char exponent; + unsigned char mantissa[4]; +} FLOATBAS; + +/* CBM format used in floating-point akku + * + * this format can be directly used with most CBM BASIC routines + * + * exponent mantissa sign + * 44444444 33333333332222222222111111111100 00000000 + * 76543210 98765432109876543210987654321098 76543210 + * + * truncated to 32bit: + * + * exponent mantissa sign + * 33222222 2222111111111100 00000000 + * 10987654 3210987654321098 76543210 + * + * The exponent can be computed from bits 47-40 by subtracting 129 (!) (130 = 2^1) + * MSB of the Mantissa must always be 1, if it is 0 the value is 0 + * + * 1.0 = exp=129, mantissa=$80 + * + */ +typedef struct { + unsigned char exponent; + unsigned char mantissa[4]; + unsigned char sign; +} FLOATFAC; + +/* integer conversion functions */ +float __fastcall__ _ctof(char v); /* afloat */ +float __fastcall__ _utof(unsigned char v); /* aufloat */ +float __fastcall__ _itof(int v); /* axfloat */ +float __fastcall__ _stof(unsigned short v); /* axufloat */ + +int __fastcall__ _ftoi(float f); /* feaxint */ + +/* compare two floats, returns 0 if f = a, 1 if f < a, 255 if f > a */ +unsigned char __fastcall__ _fcmp(float f, float a); /* ftos..eax */ + +/* arithmetic functions */ +float __fastcall__ _fadd(float f, float a); /* ftosaddeax */ +float __fastcall__ _fsub(float f, float a); /* ftossubeax */ +float __fastcall__ _fmul(float f, float a); /* ftosmuleax */ +float __fastcall__ _fdiv(float f, float a); /* ftosdiveax */ + +/* math functions */ +float __fastcall__ _fpow(float f, float a); /* math.h powf */ +float __fastcall__ _fsin(float s); /* math.h sinf */ +float __fastcall__ _fcos(float s); /* math.h cosf */ + +float __fastcall__ _flog(float s); /* math.h logf */ +float __fastcall__ _fexp(float s); /* math.h expf */ +float __fastcall__ _fsqr(float s); /* math.h sqrtf */ + +float __fastcall__ _ftan(float s); /* math.h tanf */ +float __fastcall__ _fatn(float s); /* math.h atanf */ + +float __fastcall__ _fabs(float s); /* math.h fabsf */ + +float __fastcall__ _fint(float s); /* math.h truncf */ /* truncate decimal fraction */ +float __fastcall__ _fround(float s); /* math.h roundf */ /* rounding */ + +/* logical functions */ +float __fastcall__ _fand(float f, float a); +float __fastcall__ _for(float f, float a); +float __fastcall__ _fnot(float f); + +/* misc */ +float __fastcall__ _frnd(float s); /* random number */ +float __fastcall__ _fsgn(float s); /* "signum" returns 1 if positive, 0 if 0, -1 if negative */ + +float __fastcall__ _fneg(float f); /* negate (flip sign) FIXME: fnegeax */ + +unsigned char __fastcall__ _ftestsgn(float f); /* FIXME */ + +#if 0 +typedef struct { + unsigned char exponent; + FLOATBAS coffs[8]; /* ? */ +} FLOATPOLY; + +#define fpoly FLOATPOLY + +/* polynom1 f(x)=a1+a2*x^2+a3*x^3+...+an*x^n */ +void _fpoly1(float *d,fpoly *a,float *x); +/* polynom2 f(x)=a1+a2*x^3+a3*x^5+...+an*x^(2n-1) */ +void _fpoly2(float *d,fpoly *a,float *x); + +#endif + +/* + todo: + + acos,asin,ceil,cosh,fmod,hypot,ldexp,log10,modf,poly,pow10,sinh + tanh,cabs,_matherr,matherr, + +*/ + +#endif diff --git a/libsrc/float/cbmkernal/cbmfp.inc b/libsrc/float/cbmkernal/cbmfp.inc new file mode 100644 index 000000000..962902d85 --- /dev/null +++ b/libsrc/float/cbmkernal/cbmfp.inc @@ -0,0 +1,64 @@ + +FAC_EXPONENT = $61 +FAC_MANTISSA0 = $62 +FAC_MANTISSA1 = $63 +FAC_MANTISSA2 = $64 +FAC_MANTISSA3 = $65 +FAC_SIGN = $66 + +ARG_EXPONENT = $69 +ARG_MANTISSA0 = $6a +ARG_MANTISSA1 = $6b +ARG_MANTISSA2 = $6c +ARG_MANTISSA3 = $6d +ARG_SIGN = $6e + +FAC_SIGN_COMPARE = $6f +FAC_ROUNDING = $70 + +; addresses of the floating point routines in CBM BASIC V2 + +; the following are the addresses in the C64 ROM - the library can probably be +; used with other CBM targets just by adjusting these addresses + +BASIC_FAC_Not = $aed4 ; in/out: FAC +BASIC_FAC_Cos = $e264 ; in/out: FAC +BASIC_FAC_Sin = $e26b ; in/out: FAC +BASIC_FAC_Tan = $e2b4 ; in/out: FAC +BASIC_FAC_Atn = $e30e ; in/out: FAC +BASIC_FAC_Rnd = $e097 ; in/out: FAC +BASIC_FAC_Int = $bccc ; in/out: FAC +BASIC_FAC_Sqr = $bf71 ; in/out: FAC +BASIC_FAC_Exp = $bfed ; in/out: FAC +BASIC_FAC_Log = $b9ea ; in/out: FAC +BASIC_FAC_Round = $bc1b ; in/out: FAC +BASIC_FAC_Sgn = $bc39 ; in/out: FAC "signum" returns 1 if positive, 0 if 0, -1 if negative +BASIC_FAC_Abs = $bc58 ; in/out: FAC + +BASIC_ARG_FAC_Or = $afe6 ; in: ARG,FAC out:FAC +BASIC_ARG_FAC_And = $afe9 ; in: ARG,FAC out:FAC +BASIC_ARG_FAC_Sub = $b853 ; in: ARG,FAC out:FAC +BASIC_ARG_FAC_Add = $b86a ; in: ARG,FAC out:FAC +BASIC_ARG_FAC_Mul = $ba2b ; in: ARG,FAC out:FAC +BASIC_ARG_FAC_Div = $bb12 ; in: ARG,FAC out:FAC +BASIC_ARG_FAC_Pow = $bf7b ; in: ARG,FAC out:FAC + +BASIC_u8_to_FAC = $b3a2 ; y: value +BASIC_s8_to_FAC = $bc3c ; a: value +BASIC_u16_to_FAC = $bc49 ; a/y:lo/hi value (sta $62 sty $63 sec ldx#$90 jsr...) +BASIC_s16_to_FAC = $b395 ; a/y:lo/hi value + +BASIC_FAC_to_u16 = $bc9b ; in:FAC out: y/a:lo/hi value + +BASIC_string_to_FAC = $b7b5 ; in: $22/$23 ptr to str,a=strlen out: FAC value +BASIC_FAC_to_string = $bddd ; in: FAC value out: str at $0100 a/y ptr to str + +BASIC_LoadARG = $ba8c ; a/y:lo/hi ptr to 5-byte float +BASIC_LoadFAC = $bba2 ; a/y:lo/hi ptr to 5-byte float + +BASIC_FAC_testsgn = $bc2b ; in: FAC(x1) out: a=0 (x1=0) a=1 (x1>0) a=255 (x1<0) +BASIC_FAC_cmp = $bc5b ; in: FAC(x1) a/y ptr lo/hi to x2 out: a=0 (x1=x2) a=1 (x1>x2) a=255 (x1 $ff or $7f + and FAC_MANTISSA0 ; bit7 of mantissa is always 1 + sta sreg ; 1 + + ldx FAC_MANTISSA1 ; 2 + lda FAC_MANTISSA2 ; 3 +.endif +.if BINARYFORMAT = BINARYFORMAT_IEEE754 + ; return float in a/x/sreg/sreg+1 + lda FAC_EXPONENT + sec + sbc #2 + sta sreg+1 ; 0 + + lda FAC_MANTISSA0 + asl + sta sreg ; 1 + + lda FAC_SIGN ; either $ff or $00 + asl + ror sreg+1 ; exp + ror sreg ; mantissa msb + + + ldx FAC_MANTISSA1 ; 2 + lda FAC_MANTISSA2 ; 3 lsb + +.endif + rts + +;; store float in memory +;; in: dest. pointer (a/x), float in FAC +;__float_fac_to_float: ; UNUSED +; sta ptr1 +; stx ptr1+1 +; ldy #$00 +; lda FAC_EXPONENT +; sta (ptr1),y +; iny +; lda FAC_MANTISSA0 +; sta (ptr1),y +; iny +; lda FAC_MANTISSA1 +; sta (ptr1),y +; iny +; lda FAC_MANTISSA2 +; sta (ptr1),y +; iny +; lda FAC_MANTISSA3 +; sta (ptr1),y +; iny +; lda FAC_SIGN +; sta (ptr1),y +; rts + +;; store packed float in memory +;; in: dest. pointer (a/x), float in FAC +;__float_fac_to_float_packed: ; UNUSED +; sta ptr1 +; stx ptr1+1 +; ldy #4 +; lda FAC_MANTISSA3 +; sta (ptr1),y +; dey +; lda FAC_MANTISSA2 +; sta (ptr1),y +; dey +; lda FAC_MANTISSA1 +; sta (ptr1),y +; dey +;; use the MSB of the mantissa for the sign +; lda FAC_SIGN +; ora #$7f +; and FAC_MANTISSA0 +; sta (ptr1),y +; dey +; lda FAC_EXPONENT +; sta (ptr1),y +; rts + +;; store packed float in memory +;; in: dest. pointer (a/x), float in ARG +__float_arg_to_float_packed: + sta ptr1 + stx ptr1+1 + ldy #4 + lda ARG_MANTISSA3 + sta (ptr1),y + dey + lda ARG_MANTISSA2 + sta (ptr1),y + dey + lda ARG_MANTISSA1 + sta (ptr1),y + dey +; use the MSB of the mantissa for the sign + lda ARG_SIGN + ora #$7f + and ARG_MANTISSA0 + sta (ptr1),y + dey + lda ARG_EXPONENT + sta (ptr1),y + rts + +;--------------------------------------------------------------------------------------------- +.if 1 = 1 + .export __ftostr + .importzp ptr1 + .import popax, ldeaxysp, incsp4 + +; convert float to string +; char* __fastcall__ _ftostr(char *d, float s); +;-> char* __fastcall__ _ftostr(char *d, unsigned long s); + +__ftostr: + jsr ___float_float_to_fac + jsr __float_fac_to_str + +___float_strbuf_to_string: + jsr popax ; ptr to string +__float_strbuf_to_string: + sta ptr1 + stx ptr1+1 + ldy #$00 + ldx #$00 + + ; if next char is a minus, copy it + lda $0100,x + cmp #'-' + bne @s0 + sta (ptr1),y + iny + inx +@s0: + + ; if next char is a space, skip it + lda $0100,x + cmp #' ' + bne @s1 + inx +@s1: + + ; if next char is a dot, copy a '0' to buffer + lda $0100,x + cmp #'.' + bne @s2 + lda #'0' + sta (ptr1),y + iny +@s2: + ; FIXME: we should handle the scientific notation somehow + ; FIXME: we should handle very small numbers somehow (display 0) +@l: + lda $0100,x + sta (ptr1),y + beq @s + inx + iny + bne @l +@s: + lda ptr1 + ldx ptr1+1 + rts +.endif + .export __strtof + +; convert a string to a float +; float __fastcall__ _strtof(char *d); +;-> unsigned long __fastcall__ _strtof(char *d); +__strtof: + jsr ___float_str_to_fac + jmp ___float_fac_to_float + + .export __ctof + +; convert char to float +; float __fastcall__ _ctof(char v); +;-> unsigned long __fastcall__ _ctof(char v); + __ctof: + jsr ___float_s8_to_fac + jmp ___float_fac_to_float + + .export __utof + +; convert unsigned char to float +; float __fastcall__ _utof(unsigned char v); +;-> unsigned long __fastcall__ _utof(unsigned char v); + __utof: + jsr ___float_u8_to_fac + jmp ___float_fac_to_float + + .export __stof + +; convert short to float +; float __fastcall__ _stof(unsigned short v); +;-> unsigned long __fastcall__ _stof(unsigned short v); + __stof: + jsr ___float_u16_to_fac + jmp ___float_fac_to_float + + .export __itof + +; convert integer to float +; float __fastcall__ _itof(int v); +;-> unsigned long __fastcall__ _itof(int v); + __itof: + ;a: low x: high + jsr ___float_s16_to_fac + jmp ___float_fac_to_float + + .export __ftoi + +; convert float to integer +; int __fastcall__ _ftoi(float f); +;-> int __fastcall__ _ftoi(unsigned long f); + __ftoi: + jsr ___float_float_to_fac + jmp __float_fac_to_u16 + +;--------------------------------------------------------------------------------------------- +; these functions take one arg (in FAC) and return result (in FAC) aswell +;--------------------------------------------------------------------------------------------- + +.macro __ffunc1 addr + jsr ___float_float_to_fac + __enable_basic_if_needed + jsr addr + __disable_basic_if_needed + jmp ___float_fac_to_float +.endmacro + + .export __fabs, __fatn, __fcos, __fexp, __fint, __flog + .export __frnd, __fsgn, __fsin, __fsqr, __ftan, __fnot, __fround + +__fabs: __ffunc1 BASIC_FAC_Abs +__fatn: __ffunc1 BASIC_FAC_Atn +__fcos: __ffunc1 BASIC_FAC_Cos +__fexp: __ffunc1 BASIC_FAC_Exp +;__ffre: __ffunc1 BASIC_FAC_Fre +__fint: __ffunc1 BASIC_FAC_Int ; truncate fractions +__flog: __ffunc1 BASIC_FAC_Log +;__fpos: __ffunc1 BASIC_FAC_Pos +__frnd: __ffunc1 BASIC_FAC_Rnd ; random numbers +__fsgn: __ffunc1 BASIC_FAC_Sgn ;"signum" returns 1 if positive, 0 if 0, -1 if negative +__fsin: __ffunc1 BASIC_FAC_Sin +__fsqr: __ffunc1 BASIC_FAC_Sqr +__ftan: __ffunc1 BASIC_FAC_Tan +__fnot: __ffunc1 BASIC_FAC_Not +__fround: __ffunc1 BASIC_FAC_Round ; rounding + +;--------------------------------------------------------------------------------------------- +; these functions take two args (in FAC and ARG) and return result (in FAC) +;--------------------------------------------------------------------------------------------- + +__float_ret2: + + ;jsr __basicoff +.if .defined(__C64__) + ldx #$36 + stx $01 + cli +.endif + jmp ___float_fac_to_float ; also pops pointer to float + +.macro __ffunc2a addr + jsr ___float_float_to_fac_arg + __enable_basic_if_needed + lda FAC_EXPONENT + jsr addr + jmp __float_ret2 +.endmacro + +.macro __ffunc2b addr + jsr ___float_float_to_fac_arg + __enable_basic_if_needed + jsr addr + jmp __float_ret2 +.endmacro + +.macro __ffunc2c addr + jsr ___float_float_to_fac_arg + jsr __float_swap_fac_arg + __enable_basic_if_needed + lda FAC_EXPONENT + jsr addr + jmp __float_ret2 +.endmacro + + .export __fadd, __fsub, __fmul, __fdiv, __fpow + +; float __fastcall__ _fadd(float f, float a); +;-> unsigned long __fastcall__ _fadd(unsigned long f, unsigned long a); +__fadd: __ffunc2a BASIC_ARG_FAC_Add +__fsub: __ffunc2a BASIC_ARG_FAC_Sub +__fmul: __ffunc2a BASIC_ARG_FAC_Mul +__fdiv: __ffunc2a BASIC_ARG_FAC_Div +__fpow: __ffunc2a BASIC_ARG_FAC_Pow + + .export __fand, __for + +__fand: __ffunc2b BASIC_ARG_FAC_And +__for: __ffunc2b BASIC_ARG_FAC_Or + + .export __frsub +__frsub: __ffunc2c BASIC_ARG_FAC_Sub + +__float_ret3: + ;jsr __basicoff +.if .defined(__C64__) + ldx #$36 + stx $01 + cli +.endif + ldx #0 + rts + + .bss + +tempfloat: + .res 5 + + .SEGMENT "LOWCODE" + + .export __fcmp + +__fcmp: + jsr ___float_float_to_fac_arg + lda #tempfloat + jsr __float_arg_to_float_packed + lda #tempfloat +___float_cmp_fac_arg: + __enable_basic_if_needed + ; in: FAC=(x1) a/y= ptr lo/hi to x2 + jsr BASIC_FAC_cmp + ; a=0 (==) / a=1 (>) / a=255 (<) + jmp __float_ret3 + + .export __ftestsgn + +__ftestsgn: + jsr ___float_float_to_fac +;___float_testsgn_fac: + __enable_basic_if_needed + ; in: FAC(x1) + jsr BASIC_FAC_testsgn + jmp __float_ret3 + +___float_testsgn_fac: + lda FAC_EXPONENT + beq @s + lda FAC_SIGN + rol a + lda #$ff + bcs @s + lda #$01 +@s: + rts + +___float_testsgn_arg: + lda ARG_EXPONENT + beq @s + lda ARG_SIGN + rol a + lda #$ff + bcs @s + lda #$01 +@s: + rts + +;--------------------------------------------------------------------------------------------- +; polynom1 f(x)=a1+a2*x^2+a3*x^3+...+an*x^n +;--------------------------------------------------------------------------------------------- + .export __fpoly1 + .import popax +__fpoly1: + jsr ___float_float_to_fac + ;jsr popya + jsr popax + tay + txa + __enable_basic_if_needed + jsr BASIC_FAC_Poly1 + jmp __float_ret2 + +;--------------------------------------------------------------------------------------------- +; polynom2 f(x)=a1+a2*x^3+a3*x^5+...+an*x^(2n-1) +;--------------------------------------------------------------------------------------------- + .export __fpoly2 + .import popax +__fpoly2: + jsr ___float_float_to_fac + ;jsr popya + jsr popax + tay + txa + __enable_basic_if_needed + jsr BASIC_FAC_Poly1 + jmp __float_ret2 + +;--------------------------------------------------------------------------------------------- + +__float_atn_fac: + __enable_basic_if_needed + jsr BASIC_FAC_Atn + __return_with_cleanup +__float_div_fac_arg: + __enable_basic_if_needed + lda FAC_EXPONENT + jsr BASIC_ARG_FAC_Div + __return_with_cleanup +__float_add_fac_arg: + __enable_basic_if_needed + lda FAC_EXPONENT + jsr BASIC_ARG_FAC_Add + __return_with_cleanup + +__float_swap_fac_arg: ; only used in ATAN2 + lda FAC_EXPONENT + ldx ARG_EXPONENT + stx FAC_EXPONENT + sta ARG_EXPONENT + lda FAC_MANTISSA0 + ldx ARG_MANTISSA0 + stx FAC_MANTISSA0 + sta ARG_MANTISSA0 + lda FAC_MANTISSA1 + ldx ARG_MANTISSA1 + stx FAC_MANTISSA1 + sta ARG_MANTISSA1 + lda FAC_MANTISSA2 + ldx ARG_MANTISSA2 + stx FAC_MANTISSA2 + sta ARG_MANTISSA2 + lda FAC_MANTISSA3 + ldx ARG_MANTISSA3 + stx FAC_MANTISSA3 + sta ARG_MANTISSA3 + lda FAC_SIGN + ldx ARG_SIGN + stx FAC_SIGN + sta ARG_SIGN + rts + + .export __fneg +__fneg: + jsr ___float_float_to_fac + + lda FAC_EXPONENT + beq @sk + lda FAC_SIGN + eor #$FF + sta FAC_SIGN +@sk: + jmp ___float_fac_to_float + + +__f_pi2: .byte $81,$80+$49,$0f,$da,$a1,$00 +__f_pi: .byte $82,$80+$49,$0f,$da,$a1,$00 +__f_1pi2: .byte $83,$80+$16,$cb,$e3,$f9,$00 + + .export __fatan2 + +; float _fatan2(float x, float y) +;-> unsigned long _fatan2(unsigned long x, unsigned long y) +__fatan2: + + jsr ___float_float_to_fac_arg + + jsr ___float_testsgn_arg + beq @s11 ; =0 + bpl @s12 ; <0 + ; arg>0 + ; a=atn(y/x) + jsr __float_swap_fac_arg + jsr __float_div_fac_arg + jsr __float_atn_fac + jmp __float_ret2 +@s12: ; arg<0 + ; a=atn(y/x)+pi + jsr __float_swap_fac_arg + jsr __float_div_fac_arg + jsr __float_atn_fac + lda #<__f_pi + ldx #>__f_pi + jsr __float_float_to_arg + jsr __float_add_fac_arg + jmp __float_ret2 + +@s11: ; arg=0 + jsr ___float_testsgn_fac + beq @s21 ; =0 + bpl @s22 ; <0 + ; fac >0 + ; a= 0.5*pi + lda #<__f_pi2 + ldx #>__f_pi2 + jsr __float_float_to_fac + jmp __float_ret2 + ; fac =0 +@s21: + ; a= 0 + lda #$00 + sta FAC_MANTISSA0 + jmp __float_ret2 + ; fac <0 +@s22: + ; a= 1.5*pi + lda #<__f_1pi2 + ldx #>__f_1pi2 + jsr __float_float_to_fac + jmp __float_ret2 + diff --git a/libsrc/float/ieee754/_ftostr.c b/libsrc/float/ieee754/_ftostr.c new file mode 100644 index 000000000..48640f180 --- /dev/null +++ b/libsrc/float/ieee754/_ftostr.c @@ -0,0 +1,97 @@ + +#include +#include + +char buffer[32]; + +char * __fastcall__ _ftostr(char *d, float s) +{ + float f; + unsigned char *p; + char *bp, *buf; + int exp; + unsigned long mantissa; + unsigned long val; + int sign; + unsigned char n; + static char digits[10]={0,1,2,3,4,5,6,7,8,9}; + + unsigned long mantissa_mod = 1000000000; + unsigned long mantissa_rest; + + if (d == NULL) { + buf = bp = &buffer[0]; + } else { + buf = bp = d; + } + + f = s; + p = (unsigned char*)&f; + +// printf("%02x %02x %02x %02x\n", p[3], p[2], p[1], p[0]); + + sign = (p[3] & 0x80) ? 1 : 0; + exp = ((p[3] << 1) & 0xfe) | ((p[2] >> 7) & 1); + exp -= 127; + mantissa = p[2] & 0x7f; + mantissa <<=8; + mantissa |= p[1]; + mantissa <<=8; + mantissa |= p[0]; + + *bp++ = sign ? '-' : ' '; + + *bp++ = '1'; + *bp++ = '.'; + + val = 0xff; +// printf("mantissa: %ld\n", mantissa); + mantissa_rest = mantissa; + for (n = 0; n < 10; n++) { +// printf("n:%2d rest:%ld mod:%ld\n", n, mantissa_rest, mantissa_mod); + if ((mantissa_mod <= mantissa_rest) && (mantissa_rest > 0)) { + val = mantissa_rest / mantissa_mod; +// printf("n:%2d val:%ld\n", n, val); +// *bp++ = digits[(int)val]; + *bp++ = '0' + val; + mantissa_rest -= (val * mantissa_mod); + } + mantissa_mod /= 10; + } + if (val == 0xff) { + *bp++ = '0'; + } + +// *bp++ = 'e'; +// *bp++ = 0; + *bp++ = '*'; + *bp++ = '2'; + *bp++ = '^'; + +// printf("exp: %ld\n", exp); + mantissa_mod = 1000; + if (exp < 0) { + mantissa_rest = -1 * exp; + *bp++ = '-'; + } else { + mantissa_rest = exp; + } + val = 0xff; + for (n = 0; n < 10; n++) { +// printf("n:%2d rest:%ld mod:%ld\n", n, mantissa_rest, mantissa_mod); + if ((mantissa_mod <= mantissa_rest) && (mantissa_rest > 0)) { + val = mantissa_rest / mantissa_mod; +// printf("n:%2d val:%ld\n", n, val); +// *bp++ = digits[(int)val]; + *bp++ = '0' + val; + mantissa_rest -= (val * mantissa_mod); + } + mantissa_mod /= 10; + } + if (val == 0xff) { + *bp++ = '0'; + } + *bp++ = 0; + + return buf; +} diff --git a/libsrc/float/ieee754/afloat.s b/libsrc/float/ieee754/afloat.s new file mode 100644 index 000000000..d88ccbb26 --- /dev/null +++ b/libsrc/float/ieee754/afloat.s @@ -0,0 +1,7 @@ + + .include "ieee754.inc" + + .export afloat +afloat: + ; FIXME + rts diff --git a/libsrc/float/ieee754/aufloat.s b/libsrc/float/ieee754/aufloat.s new file mode 100644 index 000000000..f8bd735f4 --- /dev/null +++ b/libsrc/float/ieee754/aufloat.s @@ -0,0 +1,7 @@ + + .include "ieee754.inc" + + .export aufloat +aufloat: + ; FIXME + rts diff --git a/libsrc/float/ieee754/axfloat.s b/libsrc/float/ieee754/axfloat.s new file mode 100644 index 000000000..3af00ab8c --- /dev/null +++ b/libsrc/float/ieee754/axfloat.s @@ -0,0 +1,7 @@ + + .include "ieee754.inc" + + .export axfloat +axfloat: + ; FIXME + rts diff --git a/libsrc/float/ieee754/axufloat.s b/libsrc/float/ieee754/axufloat.s new file mode 100644 index 000000000..7aaea0e3b --- /dev/null +++ b/libsrc/float/ieee754/axufloat.s @@ -0,0 +1,7 @@ + + .include "ieee754.inc" + + .export axufloat +axufloat: + ; FIXME + rts diff --git a/libsrc/float/ieee754/eaxfloat.s b/libsrc/float/ieee754/eaxfloat.s new file mode 100644 index 000000000..3c91178e1 --- /dev/null +++ b/libsrc/float/ieee754/eaxfloat.s @@ -0,0 +1,7 @@ + + .include "ieee754.inc" + + .export eaxfloat +eaxfloat: + ; FIXME + rts diff --git a/libsrc/float/ieee754/eaxufloat.s b/libsrc/float/ieee754/eaxufloat.s new file mode 100644 index 000000000..d03f471cc --- /dev/null +++ b/libsrc/float/ieee754/eaxufloat.s @@ -0,0 +1,7 @@ + + .include "ieee754.inc" + + .export eaxufloat +eaxufloat: + ; FIXME + rts diff --git a/libsrc/float/ieee754/fbnegeax.s b/libsrc/float/ieee754/fbnegeax.s new file mode 100644 index 000000000..bc88e6548 --- /dev/null +++ b/libsrc/float/ieee754/fbnegeax.s @@ -0,0 +1,7 @@ + + .include "ieee754.inc" + + .export fbnegeax +fbnegeax: + ; FIXME + rts diff --git a/libsrc/float/ieee754/feaxint.s b/libsrc/float/ieee754/feaxint.s new file mode 100644 index 000000000..9b6f63888 --- /dev/null +++ b/libsrc/float/ieee754/feaxint.s @@ -0,0 +1,8 @@ + + .include "ieee754.inc" + +; float -> 16bit int + .export feaxint +feaxint: + ; FIXME + rts diff --git a/libsrc/float/ieee754/feaxlong.s b/libsrc/float/ieee754/feaxlong.s new file mode 100644 index 000000000..4d6138dc5 --- /dev/null +++ b/libsrc/float/ieee754/feaxlong.s @@ -0,0 +1,8 @@ + + .include "ieee754.inc" + +; float -> 32bit long + .export feaxlong +feaxlong: + ; FIXME + rts diff --git a/libsrc/float/ieee754/ftosaddeax.s b/libsrc/float/ieee754/ftosaddeax.s new file mode 100644 index 000000000..0a5287e84 --- /dev/null +++ b/libsrc/float/ieee754/ftosaddeax.s @@ -0,0 +1,637 @@ + + .include "ieee754.inc" + + .importzp sp, sreg, tmp1 + .import addysp1 + .import addysp + .import popax + +; Primary = TOS + Primary (like tosaddeax) + .export ftosaddeax +;ftosaddeax: + ; FIXME +; rts + +; CC65 runtime: long add + +; ; EAX = TOS + EAX +; +; ;tosadd0ax: +; ldy #$00 +; sty sreg +; sty sreg+1 +; +; ;tosaddeax: +; clc +; ldy #0 +; adc (sp),y ; lo byte +; iny +; +; sta tmp1 ; use as temp storage +; txa +; adc (sp),y ; byte 1 +; tax +; iny +; +; lda sreg +; adc (sp),y ; byte 2 +; sta sreg +; iny +; +; lda sreg+1 +; adc (sp),y ; byte 3 +; sta sreg+1 +; lda tmp1 ; load byte 0 +; jmp addysp1 ; drop TOS + + +; found at https://github.com/CrashAndSideburns/6502ieee754/blob/main/arithmetic/addition.s + +;addition: +ftosaddeax: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + + lda #0 + sta SIGN_ONE + sta SIGN_TWO + + ; Pull 2 LSBs of second parameter off of stack. + pha + lda sreg+1 + ASL + STA MANTISSA_TWO + 3 + lda sreg+0 + ROL + STA MANTISSA_TWO + 2 + + ; Pull MSB of mantissa off of stack and shift exponent LSB into carry. + tax + ROL + STA MANTISSA_TWO + 1 + + ; Pull MSB off of stack, shift in exponent LSB, store sign. + PLA + ROL + STA EXPONENT_TWO + ROL SIGN_TWO + + ;----------------- + + ; Pull 2 LSBs of first parameter off of stack. + ldy #0 + lda (sp),y ; lsb + ASL + STA MANTISSA_ONE + 3 + iny + lda (sp),y + ROL + STA MANTISSA_ONE + 2 + + ; Pull MSB of mantissa off of stack and shift exponent LSB into carry. + iny + lda (sp),y + ROL + STA MANTISSA_ONE + 1 + + ; Pull MSB off of stack, shift in exponent LSB, store sign. + iny + lda (sp),y ; msb + ROL + STA EXPONENT_ONE + ROL SIGN_ONE + + + ; Add implicit 1 to mantissas if appropriate. +@add_second_implicit_bit: + LDA EXPONENT_TWO + CMP #$00 + BEQ @add_first_implicit_bit + SEC + ROR MANTISSA_TWO + 1 + ROR MANTISSA_TWO + 2 + ROR MANTISSA_TWO + 3 + +@add_first_implicit_bit: + LDA EXPONENT_ONE + CMP #$00 + BEQ @manage_special_values + SEC + ROR MANTISSA_ONE + 1 + ROR MANTISSA_ONE + 2 + ROR MANTISSA_ONE + 3 + +@manage_special_values: + ; Check if first parameter has exponent #$ff. + ; If it does, first parameter is some special quantity. + ; If not, check if second parameter has epxonent #$ff. + ; If it does, then it is special and the first parameter is not, so propagate. + ; If neither parameter is special, move on to aligning mantissas. + LDA EXPONENT_ONE + CMP #$ff + BEQ @first_parameter_special + LDA EXPONENT_TWO + CMP #$ff + BEQ @propagate_second_parameter + JMP @align_mantissas + +@first_parameter_special: + ; Exponent is non-zero, so an implicit 1 has been added to mantissa. + ; Unless the mantissa with added implicit 1 is $800000, return first param. + ; If the mantissa is precisely $800000, first param is ±∞. + LDA MANTISSA_ONE + 1 + CMP #$80 + BNE @propagate_first_parameter + LDA MANTISSA_ONE + 2 + CMP #$00 + BNE @propagate_first_parameter + LDA MANTISSA_ONE + 3 + CMP #$00 + BEQ @first_parameter_infinite + +@propagate_first_parameter: + ; Shift out implicit bit, shift exponent and sign through. + ; Push return value onto stack. + ; Push return address onto stack. + ; Return from subroutine. + ASL MANTISSA_ONE + 1 + LSR SIGN_ONE + ROR EXPONENT_ONE + ROR MANTISSA_ONE + 1 + +; LDA EXPONENT_ONE +; PHA +; LDA MANTISSA_ONE + 1 +; PHA +; LDA MANTISSA_ONE + 2 +; PHA +; LDA MANTISSA_ONE + 3 +; PHA + +; LDA $01 +; PHA +; LDA $00 +; PHA + + LDA EXPONENT_ONE + sta sreg+1 + LDA MANTISSA_ONE + 1 + sta sreg+0 + LDX MANTISSA_ONE + 2 + LDA MANTISSA_ONE + 3 +; ldx #$43 +; lda #$21 + jmp addysp1 ; drop TOS + + RTS + +@first_parameter_infinite: + ; Check if second parameter is also ±∞. + ; If second param is not special, propagate infinity. + ; If second param is NaN, propagate NaN. + LDA EXPONENT_TWO + CMP #$ff + BNE @propagate_first_parameter + LDA MANTISSA_TWO + 1 + CMP #$80 + BNE @propagate_second_parameter + LDA MANTISSA_TWO + 2 + CMP #$00 + BNE @propagate_second_parameter + LDA MANTISSA_TWO + 3 + CMP #$00 + BNE @propagate_second_parameter + +@adding_infinities: + ; First and second parameters are both ±∞. + ; Check if they have opposite sign. + ; (+∞)+(-∞) = (-∞)+(+∞) = NaN. + ; If they have opposite sign, return a NaN. + ; Otherwise, return the first parameter. + LDA SIGN_ONE + EOR SIGN_TWO + BEQ @propagate_first_parameter +; LDA #$ff +; PHA +; PHA +; PHA +; PHA + + LDA #$ff + sta sreg+1 + sta sreg + tax + jmp addysp1 ; drop TOS + +; LDA $01 +; PHA +; LDA $00 +; PHA + + RTS + +@propagate_second_parameter: + ; Shift out implicit bit, shift exponent and sign through. + ; Push return value onto stack. + ; Push return address onto stack. + ; Return from subroutine. + ASL MANTISSA_TWO + 1 + LSR SIGN_TWO + ROR EXPONENT_TWO + ROR MANTISSA_TWO + 1 + +; LDA EXPONENT_TWO +; PHA +; LDA MANTISSA_TWO + 1 +; PHA +; LDA MANTISSA_TWO + 2 +; PHA +; LDA MANTISSA_TWO + 3 +; PHA + +; LDA $01 +; PHA +; LDA $00 +; PHA + + LDA EXPONENT_TWO + sta sreg+1 + LDA MANTISSA_TWO + 1 + sta sreg + LDX MANTISSA_TWO + 2 + LDA MANTISSA_TWO + 3 + jmp addysp1 ; drop TOS + + RTS + +@align_mantissas: + ; Check if the mantissas differ by 25 or more. + ; If they do, propagate the parameter with the larger mantissa. + ; If they don't, shift the mantissa of the smaller parameter right. + SEC + LDA EXPONENT_TWO + SBC EXPONENT_ONE + BCC @first_difference_underflow + CMP #25 + BCS @propagate_second_parameter +@first_difference_underflow: + SEC + LDA EXPONENT_ONE + SBC EXPONENT_TWO + BCC @second_difference_underflow + CMP #25 + BCS @propagate_first_parameter +@second_difference_underflow: + CMP #$00 + BEQ @apply_signs + TAX + BPL @shift_second_mantissa +@shift_first_mantissa: + LSR MANTISSA_ONE + 1 + ROR MANTISSA_ONE + 2 + ROR MANTISSA_ONE + 3 + ROR MANTISSA_ONE + 4 + ROR MANTISSA_ONE + 5 + ROR MANTISSA_ONE + 6 + INX + CPX #$00 + BNE @shift_first_mantissa + + LDA EXPONENT_TWO + STA EXPONENT_ONE + JMP @apply_signs +@shift_second_mantissa: + LSR MANTISSA_TWO + 1 + ROR MANTISSA_TWO + 2 + ROR MANTISSA_TWO + 3 + ROR MANTISSA_TWO + 4 + ROR MANTISSA_TWO + 5 + ROR MANTISSA_TWO + 6 + DEX + CPX #$00 + BNE @shift_second_mantissa + +@apply_signs: + ; Check the signs of both floats. + ; If a float has a 1 sign bit, take the 2's complement of the mantissa. +@negate_first_mantissa: + LDA SIGN_ONE + CMP #$00 + BEQ @negate_second_mantissa + LDA MANTISSA_ONE + EOR #$ff + STA MANTISSA_ONE + LDA MANTISSA_ONE + 1 + EOR #$ff + STA MANTISSA_ONE + 1 + LDA MANTISSA_ONE + 2 + EOR #$ff + STA MANTISSA_ONE + 2 + LDA MANTISSA_ONE + 3 + EOR #$ff + STA MANTISSA_ONE + 3 + LDA MANTISSA_ONE + 4 + EOR #$ff + STA MANTISSA_ONE + 4 + LDA MANTISSA_ONE + 5 + EOR #$ff + STA MANTISSA_ONE + 5 + LDA MANTISSA_ONE + 6 + EOR #$ff + CLC + ADC #$01 + STA MANTISSA_ONE + 6 + LDA MANTISSA_ONE + 5 + ADC #$00 + STA MANTISSA_ONE + 5 + LDA MANTISSA_ONE + 4 + ADC #$00 + STA MANTISSA_ONE + 4 + LDA MANTISSA_ONE + 3 + ADC #$00 + STA MANTISSA_ONE + 3 + LDA MANTISSA_ONE + 2 + ADC #$00 + STA MANTISSA_ONE + 2 + LDA MANTISSA_ONE + 1 + ADC #$00 + STA MANTISSA_ONE + 1 + LDA MANTISSA_ONE + ADC #$00 + STA MANTISSA_ONE +@negate_second_mantissa: + LDA SIGN_TWO + CMP #$00 + BEQ @sum_mantissas + LDA MANTISSA_TWO + EOR #$ff + STA MANTISSA_TWO + LDA MANTISSA_TWO + 1 + EOR #$ff + STA MANTISSA_TWO + 1 + LDA MANTISSA_TWO + 2 + EOR #$ff + STA MANTISSA_TWO + 2 + LDA MANTISSA_TWO + 3 + EOR #$ff + STA MANTISSA_TWO + 3 + LDA MANTISSA_TWO + 4 + EOR #$ff + STA MANTISSA_TWO + 4 + LDA MANTISSA_TWO + 5 + EOR #$ff + STA MANTISSA_TWO + 5 + LDA MANTISSA_TWO + 6 + EOR #$ff + CLC + ADC #$01 + STA MANTISSA_TWO + 6 + LDA MANTISSA_TWO + 5 + ADC #$00 + STA MANTISSA_TWO + 5 + LDA MANTISSA_TWO + 4 + ADC #$00 + STA MANTISSA_TWO + 4 + LDA MANTISSA_TWO + 3 + ADC #$00 + STA MANTISSA_TWO + 3 + LDA MANTISSA_TWO + 2 + ADC #$00 + STA MANTISSA_TWO + 2 + LDA MANTISSA_TWO + 1 + ADC #$00 + STA MANTISSA_TWO + 1 + LDA MANTISSA_TWO + ADC #$00 + STA MANTISSA_TWO + +@sum_mantissas: + ; Sum the mantissas to obtain the mantissa of the return float. + ; Check if the resultant mantissa has a 1 MSB. + ; If it does, set the result sign to 1 and take the 2's complement of the mantissa. + ; If it doesn't, move on to normalising the resultant mantissa. + CLC + LDA MANTISSA_ONE + 6 + ADC MANTISSA_TWO + 6 + STA MANTISSA_ONE + 6 + LDA MANTISSA_ONE + 5 + ADC MANTISSA_TWO + 5 + STA MANTISSA_ONE + 5 + LDA MANTISSA_ONE + 4 + ADC MANTISSA_TWO + 4 + STA MANTISSA_ONE + 4 + LDA MANTISSA_ONE + 3 + ADC MANTISSA_TWO + 3 + STA MANTISSA_ONE + 3 + LDA MANTISSA_ONE + 2 + ADC MANTISSA_TWO + 2 + STA MANTISSA_ONE + 2 + LDA MANTISSA_ONE + 1 + ADC MANTISSA_TWO + 1 + STA MANTISSA_ONE + 1 + LDA MANTISSA_ONE + ADC MANTISSA_TWO + STA MANTISSA_ONE + + AND #$80 + CMP #$00 + BEQ @positive_sum + + LDA MANTISSA_ONE + EOR #$ff + STA MANTISSA_ONE + LDA MANTISSA_ONE + 1 + EOR #$ff + STA MANTISSA_ONE + 1 + LDA MANTISSA_ONE + 2 + EOR #$ff + STA MANTISSA_ONE + 2 + LDA MANTISSA_ONE + 3 + EOR #$ff + STA MANTISSA_ONE + 3 + LDA MANTISSA_ONE + 4 + EOR #$ff + STA MANTISSA_ONE + 4 + LDA MANTISSA_ONE + 5 + EOR #$ff + STA MANTISSA_ONE + 5 + LDA MANTISSA_ONE + 6 + EOR #$ff + CLC + ADC #$01 + STA MANTISSA_ONE + 6 + LDA MANTISSA_ONE + 5 + ADC #$00 + STA MANTISSA_ONE + 5 + LDA MANTISSA_ONE + 4 + ADC #$00 + STA MANTISSA_ONE + 4 + LDA MANTISSA_ONE + 3 + ADC #$00 + STA MANTISSA_ONE + 3 + LDA MANTISSA_ONE + 2 + ADC #$00 + STA MANTISSA_ONE + 2 + LDA MANTISSA_ONE + 1 + ADC #$00 + STA MANTISSA_ONE + 1 + LDA MANTISSA_ONE + ADC #$00 + STA MANTISSA_ONE + LDA #$01 + STA SIGN_ONE + JMP @normalise_mantissa +@positive_sum: + LDA #$00 + STA SIGN_ONE + +@normalise_mantissa: + ; Now that the new mantissa has been computed, normalise it. + ; Check if the LSB of the byte before the MSB of the mantissa is 1. + ; If it is, shift the mantissa down and increment the mantissa. + ; If it isn't, move on to checking if we must shift left. + LDA MANTISSA_ONE + AND #$01 + CMP #$01 + BNE @no_overflow + LSR MANTISSA_ONE + ROR MANTISSA_ONE + 1 + ROR MANTISSA_ONE + 2 + ROR MANTISSA_ONE + 3 + ROR MANTISSA_ONE + 4 + ROR MANTISSA_ONE + 5 + ROR MANTISSA_ONE + 6 + INC EXPONENT_ONE + JMP @round + +@no_overflow: + ; Check if the MSB of the mantissa is 1. + ; If it is, move on to rounding. + ; If it isn't, shift mantissa left and decrement exponent until MSB is 1 or exponent is 0. + LDA MANTISSA_ONE + 1 + AND #$80 + CMP #$80 + BEQ @round + LDA EXPONENT_ONE + CMP #$00 + BEQ @round + ASL MANTISSA_ONE + 6 + ROL MANTISSA_ONE + 5 + ROL MANTISSA_ONE + 4 + ROL MANTISSA_ONE + 3 + ROL MANTISSA_ONE + 2 + ROL MANTISSA_ONE + 1 + ROL MANTISSA_ONE + DEC EXPONENT_ONE + JMP @no_overflow + +@round: + ; Check if we have already produced ±∞ in the event that we decide not to round. + ; If we have, return ±∞. + ; If we haven't, check if the MSB of the byte after the mantissa is 0. + ; If it is, return, trucating the subsequent bits. + ; If it isn't, check if any subsequent bits are 1. + ; If any are, round up. + ; If none are, check if the LSB of the mantissa is 1. + ; If it is, round up. + ; If it isn't, return. + LDA EXPONENT_ONE + CMP #$ff + BEQ @return_infinity + LDA MANTISSA_ONE + 4 + AND #$80 + CMP #$00 + BEQ @return + LDA MANTISSA_ONE + 4 + AND #$7f + CMP #$00 + BNE @round_up + LDA MANTISSA_ONE + 5 + CMP #$00 + BNE @round_up + LDA MANTISSA_ONE + 6 + CMP #$00 + BNE @round_up + LDA MANTISSA_ONE + 3 + AND #$01 + CMP #$00 + BEQ @return + +@round_up: + ; Increment the mantissa by 1. + ; If the increment doesn't overflow, return. + ; If it does, shift the mantissa right and increment the exponent. + ; Check if incrementing the exponent left us with an exponent of #$ff. + ; If it did, return ±∞. + ; If it didn't, round again. + CLC + LDA MANTISSA_ONE + 3 + ADC #$01 + STA MANTISSA_ONE + 3 + LDA MANTISSA_ONE + 2 + ADC #$00 + STA MANTISSA_ONE + 2 + LDA MANTISSA_ONE + 1 + ADC #$00 + STA MANTISSA_ONE + 1 + BCC @return + ROL MANTISSA_ONE + 1 + ROL MANTISSA_ONE + 2 + ROL MANTISSA_ONE + 3 + ROL MANTISSA_ONE + 4 + ROL MANTISSA_ONE + 5 + ROL MANTISSA_ONE + 6 + INC EXPONENT_ONE + LDA EXPONENT_ONE + CMP #$ff + BEQ @return_infinity + JMP @round + +@return_infinity: + ; If we have to return ±∞ due to an over/underflow, clear the mantissa. + LDA #$00 + STA MANTISSA_ONE + 1 + STA MANTISSA_ONE + 2 + STA MANTISSA_ONE + 3 +@return: + ; Shift out implicit bit, shift exponent and sign through. + ; Push return value onto stack. + ; Push return address onto stack. + ; Return from subroutine. + LDA EXPONENT_ONE + CMP #$00 + BNE @return_normal + LSR MANTISSA_ONE + 1 + ROR MANTISSA_ONE + 2 + ROR MANTISSA_ONE + 3 + BCS @round_up +@return_normal: + ASL MANTISSA_ONE + 1 + LSR SIGN_ONE + ROR EXPONENT_ONE + ROR MANTISSA_ONE + 1 + +; LDA EXPONENT_ONE +; PHA +; LDA MANTISSA_ONE + 1 +; PHA +; LDA MANTISSA_ONE + 2 +; PHA +; LDA MANTISSA_ONE + 3 +; PHA + +; LDA $01 +; PHA +; LDA $00 +; PHA + + LDA EXPONENT_ONE + sta sreg+1 + LDA MANTISSA_ONE + 1 + sta sreg + LDX MANTISSA_ONE + 2 + LDA MANTISSA_ONE + 3 + jmp addysp1 ; drop TOS + + RTS + diff --git a/libsrc/float/ieee754/ftosdiveax.s b/libsrc/float/ieee754/ftosdiveax.s new file mode 100644 index 000000000..f878c8295 --- /dev/null +++ b/libsrc/float/ieee754/ftosdiveax.s @@ -0,0 +1,12 @@ + + .include "ieee754.inc" + + .importzp sp, sreg, tmp1 + .import addysp1 + .import addysp + .import popax + + .export ftosdiveax +ftosdiveax: + ; FIXME + rts diff --git a/libsrc/float/ieee754/ftoseqeax.s b/libsrc/float/ieee754/ftoseqeax.s new file mode 100644 index 000000000..2d0cb2a71 --- /dev/null +++ b/libsrc/float/ieee754/ftoseqeax.s @@ -0,0 +1,8 @@ + .include "ieee754.inc" + + .export ftoseqeax +ftoseqeax: + ; FIXME + lda #0 + tax + rts diff --git a/libsrc/float/ieee754/ftosgeeax.s b/libsrc/float/ieee754/ftosgeeax.s new file mode 100644 index 000000000..f0651e61b --- /dev/null +++ b/libsrc/float/ieee754/ftosgeeax.s @@ -0,0 +1,8 @@ + .include "ieee754.inc" + + .export ftosgeeax +ftosgeeax: + ; FIXME + lda #0 + tax + rts diff --git a/libsrc/float/ieee754/ftosgteax.s b/libsrc/float/ieee754/ftosgteax.s new file mode 100644 index 000000000..8857911b3 --- /dev/null +++ b/libsrc/float/ieee754/ftosgteax.s @@ -0,0 +1,8 @@ + .include "ieee754.inc" + + .export ftosgteax +ftosgteax: + ; FIXME + lda #0 + tax + rts diff --git a/libsrc/float/ieee754/ftosleeax.s b/libsrc/float/ieee754/ftosleeax.s new file mode 100644 index 000000000..fe719560a --- /dev/null +++ b/libsrc/float/ieee754/ftosleeax.s @@ -0,0 +1,8 @@ + .include "ieee754.inc" + + .export ftosleeax +ftosleeax: + ; FIXME + lda #0 + tax + rts diff --git a/libsrc/float/ieee754/ftoslteax.s b/libsrc/float/ieee754/ftoslteax.s new file mode 100644 index 000000000..39fbb50d1 --- /dev/null +++ b/libsrc/float/ieee754/ftoslteax.s @@ -0,0 +1,8 @@ + .include "ieee754.inc" + + .export ftoslteax +ftoslteax: + ; FIXME + lda #0 + tax + rts diff --git a/libsrc/float/ieee754/ftosmuleax.s b/libsrc/float/ieee754/ftosmuleax.s new file mode 100644 index 000000000..1f28e7d39 --- /dev/null +++ b/libsrc/float/ieee754/ftosmuleax.s @@ -0,0 +1,12 @@ + + .include "ieee754.inc" + + .importzp sp, sreg, tmp1 + .import addysp1 + .import addysp + .import popax + + .export ftosmuleax +ftosmuleax: + ; FIXME + rts diff --git a/libsrc/float/ieee754/ftosneeax.s b/libsrc/float/ieee754/ftosneeax.s new file mode 100644 index 000000000..9026c9b6d --- /dev/null +++ b/libsrc/float/ieee754/ftosneeax.s @@ -0,0 +1,8 @@ + .include "ieee754.inc" + + .export ftosneeax +ftosneeax: + ; FIXME + lda #0 + tax + rts diff --git a/libsrc/float/ieee754/ftossubeax.s b/libsrc/float/ieee754/ftossubeax.s new file mode 100644 index 000000000..e5bd636d4 --- /dev/null +++ b/libsrc/float/ieee754/ftossubeax.s @@ -0,0 +1,43 @@ + + .importzp sp, sreg, tmp1 + .import addysp1 + .import addysp + .import popax + + .include "ieee754.inc" + + .import ftosaddeax + + .export ftossubeax +ftossubeax: + ; FIXME + rts + +; found at https://github.com/CrashAndSideburns/6502ieee754/blob/main/arithmetic/addition.s +; subtraction: + + ; Pull MSB of second parameter off of stack, flip sign bit, and push back to stack. + ; Proceed to addition. +; TSX +; TXA +; CLC +; ADC #$05 +; TAX +; TXS +; PLA +; EOR #$80 +; PHA +; TXA +; SEC +; SBC #$05 +; TAX +; TXS + + pha + ldy #3 + lda (sp),y ; msb + eor #$80 + sta (sp),y ; msb + pla + + jmp ftosaddeax diff --git a/libsrc/float/ieee754/ieee754.inc b/libsrc/float/ieee754/ieee754.inc new file mode 100644 index 000000000..bc612046a --- /dev/null +++ b/libsrc/float/ieee754/ieee754.inc @@ -0,0 +1,7 @@ +SIGN_ONE = $e2 +EXPONENT_ONE = $e3 +MANTISSA_ONE = $e4 ; e4, e5, e6, e7, e8, e9, ea (7 bytes) + +SIGN_TWO = $eb +EXPONENT_TWO = $ec +MANTISSA_TWO = $ed diff --git a/libsrc/float/readme.md b/libsrc/float/readme.md new file mode 100644 index 000000000..e62c13749 --- /dev/null +++ b/libsrc/float/readme.md @@ -0,0 +1,324 @@ + +## cc65 floating point support + +The current main goal is to implement IEEE754 support *in the compiler*, using +the "float" datatype as the common 32bit float. + +*** ANYTHING ELSE COMES LATER *** + +You can not use any of this to write software yet. Don't bother. This is for +people who want to help pushing the floating point support further. + +You can however try the current state of development. You should be able to +build small (and slow...) programs that use floats on any supported target. + +- Build the compiler/toolchain/libs from this fptest branch. +- Now you can build and run the samples and/or tests. +``` + samples/floattest.c + samples/mandelfloat.c + samples/mathtest.c + samples/tgisincos.c +``` +full math.h is available for C64 when linking agains fp754kernal.o (see below) + +### Further info + +- Right now by default all targets will use the Berkeley Softfloat Library. This + solves the annoying "chicken and egg" problem of having to implement the float + support both in the compiler and in the target library at the same time, before + anything can be tested properly. Fortunately that also means we can use the + simulator for running test programs, and test changes in the compiler using + our test bench, and that against a library that is known to somewhat work + correctly :) +- The default library also contains a collection of math functions (which i + dubbed "softmath"), which may fill the gap until more targets have specific + wrappers and/or a generic math library (in assembly) was written. +- The default library can be overridden by linking an override file, similar to + how you can use the soft80 implementation for conio. Right now such override + files are provided for the C64 (c64-fp754kernal.o) and VIC20 + (vic20-fp754kernal.o). The samples will automatically use the overrides. + +### WANTED + +- For the time being, i will not look at writing IEEE754 functions in assembly. + Please see below for more info on what is needed to do this, should you be + interested in doing this. Please contact me before you are putting work into + this, so we can discuss some things and prevent anyone wasting time :) + +- It might be possible to produce a similar kernal- or OS- wrapper override file + as the C64 one for other targets (or port the C64 one to other CBM targets). + - If you create a new one, keep in mind that the compiler *right now* will + currently work with IEEE754 floats, which your library calls must also work + with (which will involve converting forth and back to whatever other format + at runtime), and there is no easy way tp change that. + +### Roadmap + +- Test/Fix using the Softfloat lib some more, fix as much tests as possible +- When all obvious tests have been created and work OK, we can merge + - for the failing tests, create "negative" cases + +After the merge, the following things can be done more or less independent from +each other (not necessarily by me :)): + +- implement IEEE754 library + - for generic support this will be the best compromise for standard compliance + and speed, but will take more RAM than alternatives. + - Once implemented, it will work for all targets. + +- implement support for native FP routines + - Some targets have FP routines in ROM (or OS) that can be used instead of + providing our own in the library. This may or may not save RAM, and may or + may not be faster than the default library. + - The wrapper library must implement conversion from/to 32bit IEEE754 + +- implement support for native FP formats + - for this the wrappers in fp.c must be used in the compiler at all places. + - also we must *implement* the native format on the host in fp.c + - if the native format uses a different number of bytes than 4 for its native + format, we must add support for this in the compiler at various places + - last not least a wrapper library that uses the native format must be created + - it is not unlikely that we will need extra tests for the native format + +## The Compiler + +NOT WORKING YET: + + /test/val/float-basic-var-var.c +=, -= + + /test/val/float-basic-var-intvar.c +=, -= + /test/val/float-basic-var-intconst.c *, /, +=, -=, *=, /= + + /test/val/float-basic-intvar-const.c +=, -=, *=, /= + /test/val/float-basic-intvar-var.c +=, /= + /test/val/float-basic-intconst-var.c *, / + + /test/val/float-cmp-const-intvar.c + /test/val/float-cmp-intvar-const.c + /test/val/float-cmp-var-intvar.c + +- float values written as "12.34f" work, but "12.34" does not - should it? + +TODO: + +- more tests are needed + - warnings + - errors + - register variables + - more/all tests should check local/global/register variables + +### Files & Functions + +#### assignment.c + + src/cc65/assignment.c + +``` +OpAssignArithmetic Parse an "=" or "op=" operation for arithmetic lhs +OpAddSubAssign Parse a "+=" or "-=" operation +``` + +#### codegen.c + + src/cc65/codegen.c + src/cc65/codegen.h + +``` +g_getimmed Load a constant into the primary register +g_getstatic Fetch an static memory cell into the primary register +g_getlocal Fetch specified local object (local var) into the primary register +g_putstatic +g_reglong +g_regfloat Make sure, the value in the primary register a float. Convert if necessary +g_typeadjust +g_typecast Cast the value in the primary register to the operand size that is flagged by the lhs value +oper Encode a binary operation. +g_push +g_push_float Push the primary register or a constant value onto the stack +g_inc +g_dec +g_defdata +g_defdata_float + +(see below) g_add, g_sub, g_mul, g_div, g_neg, g_bneg +(see below) g_eq, g_ne, g_lt, g_gt, g_le, g_ge +(invalid) g_mod, g_or, g_xor, g_and, g_asr, g_asl +``` +#### datatype.c + + src/cc65/datatype.c + +``` +ArithmeticConvert Perform the usual arithmetic conversions for binary operators. +``` + +#### expr.c + + src/cc65/expr.c + +``` +LimitExprValue +parseadd +parsesub +``` + +#### fp.c + + src/common/fp.c (OK) + src/common/fp.h (OK) + +wrapper for doing floating point operations on target floats + +``` +FP_D_As32bitRaw converts double into 32bit (float) and then returns its raw content as a 32bit int +``` + +#### initdata.c + + src/cc65/initdata.c + +``` +DefineData Output a data definition for the given expression +``` + +#### loadexpr.c + + src/cc65/loadexpr.c + +``` +LoadExpr Load an expression into the primary register if it is not already there. +``` + +#### locals.c + + src/cc65/locals.c (OK?) + +``` +ParseAutoDecl Parse the declarator of an auto variable. +``` + +#### scanner.c + + src/cc65/scanner.c (OK?) + +``` +NumericConst Parse a numeric constant +``` + +Note: Scanner fixes should be directly promoted to upstream. Any differences in + this branch should be related to debugging/logging. + +#### typeconv.c + + src/cc65/typeconv.c (OK?) + +``` +DoConversion Emit code to convert the given expression to a new type +``` + +-------------------------------------------------------------------------------- + +## The Library + +### variants + +The floating point support calls library functions for any operations on non +constant values. + +#### softfloat + +This is a Port of "Berkeley SoftFloat Release 2c". It is currently used by +default for all targets. + +#### softmath + +Contains a collection of math functions, (hopefully) enough to completely +implement math.h in C. This is currently used by default for all targets. + +#### cbmkernal + +This is a wrapper to the CBM kernal functions. This is fairly complete, +including math functions. To use this, link against c64-fp754kernal.o. The c64 +samples will do this by default. + +#### ieee754 + +This should become a freestanding IEEE754 library, which can completely replace +the softfloat (and softmath) library. + +- basically everything missing except addition/substraction + - compare functions are missing + - mul, div functions are missing + - type conversion functions are missing + +-------------------------------------------------------------------------------- + +### runtime functions + +These must be available in the runtime library. +``` +func description softfloat cbmfp 754 codegen.c + +aufloat Primary 8bit unsigned -> float - * - g_regfloat +afloat Primary 8bit signed -> float - * - g_regfloat +axufloat Primary 16bit unsigned -> float * * - g_regfloat +axfloat Primary 16bit signed -> float * * - g_regfloat +eaxufloat Primary 32bit unsigned -> float * * - g_regfloat +eaxfloat Primary 32bit signed -> float * * - g_regfloat + +feaxint Primary float -> 16bit int - * - g_regint +feaxlong Primary float -> 32bit long - * - g_reglong + +ftosaddeax Primary = TOS + Primary * * ? g_add +ftossubeax Primary = TOS - Primary * * ? g_sub +ftosrsubeax Primary = Primary - TOS * * - g_rsub +ftosmuleax Primary = TOS * Primary * * - g_mul +ftosdiveax Primary = TOS / Primary * * - g_div + +fnegeax Primary = -Primary * * - g_neg +fbnegeax Primary = !Primary (return bool!) * * - g_bneg + +ftosgeeax Test for greater than or equal to * * - g_ge +ftosgteax Test for greater than * * - g_gt +ftosleeax Test for less than or equal to * * - g_le +ftoslteax Test for less than * * - g_lt +ftosneeax Test for not equal * * - g_ne +ftoseqeax Test for equal * * - g_eq +``` +### math.h functions + +These are optional, required for standard libm. +``` +func description softmath cbmfp 754 + +float powf(float f, float a) * * - +float sinf(float s) * * - +float cosf(float s) * * - +float logf(float x) * * - +float expf(float x) * * - +float sqrtf(float x) * * - +float tanf(float x) * * - +float atanf(float x) * * - +float fabsf(float x) * * - +float roundf(float x) * * - +float truncf(float x) * * - +float ceilf(float x) * - - +float floorf(float x) * - - +float fmodf(float x, float y) * - - +``` + +### extra functions + +Optional utility functions. +``` +func description softfloat cbmfp 754 + +char *_ftostr(char *d, float s) * * ? for printf family +float _strtof(char *d) - * - for scanf family +``` + +-------------------------------------------------------------------------------- + +- https://www.geeksforgeeks.org/ieee-standard-754-floating-point-numbers/ +- https://www.h-schmidt.net/FloatConverter/IEEE754.html diff --git a/libsrc/float/softfloat/6502-CC65.h b/libsrc/float/softfloat/6502-CC65.h new file mode 100644 index 000000000..d2e4eaae6 --- /dev/null +++ b/libsrc/float/softfloat/6502-CC65.h @@ -0,0 +1,70 @@ + +#undef DOUBLES // implement double precision floats + +/*---------------------------------------------------------------------------- +| One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined. +*----------------------------------------------------------------------------*/ +#define LITTLEENDIAN + +/*---------------------------------------------------------------------------- +| The macro `BITS64' can be defined to indicate that 64-bit integer types are +| supported by the compiler. +*----------------------------------------------------------------------------*/ +#undef BITS64 + +/*---------------------------------------------------------------------------- +| Each of the following `typedef's defines the most convenient type that holds +| integers of at least as many bits as specified. For example, `uint8' should +| be the most convenient type that can hold unsigned integers of as many as +| 8 bits. The `flag' type must be able to hold either a 0 or 1. For most +| implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed +| to the same as `int'. +*----------------------------------------------------------------------------*/ +typedef unsigned char flag; +typedef unsigned char uint8; +typedef signed char int8; +typedef unsigned short uint16; +typedef signed short int16; +typedef unsigned long uint32; +typedef signed long int32; +#ifdef BITS64 +typedef unsigned long long int uint64; +typedef signed long long int int64; +#endif + +/*---------------------------------------------------------------------------- +| Each of the following `typedef's defines a type that holds integers +| of _exactly_ the number of bits specified. For instance, for most +| implementation of C, `bits16' and `sbits16' should be `typedef'ed to +| `unsigned short int' and `signed short int' (or `short int'), respectively. +*----------------------------------------------------------------------------*/ +typedef unsigned char bits8; +typedef signed char sbits8; +typedef unsigned short bits16; +typedef signed short sbits16; +typedef unsigned long bits32; +typedef signed long sbits32; +#ifdef BITS64 +typedef unsigned long long int bits64; +typedef signed long long int sbits64; +#endif + +#ifdef BITS64 +/*---------------------------------------------------------------------------- +| The `LIT64' macro takes as its argument a textual integer literal and +| if necessary ``marks'' the literal as having a 64-bit integer type. +| For example, the GNU C Compiler (`gcc') requires that 64-bit literals be +| appended with the letters `LL' standing for `long long', which is `gcc's +| name for the 64-bit integer type. Some compilers may allow `LIT64' to be +| defined as the identity macro: `#define LIT64( a ) a'. +*----------------------------------------------------------------------------*/ +#define LIT64( a ) a##LL +#endif + +/*---------------------------------------------------------------------------- +| The macro `INLINE' can be used before functions that should be inlined. If +| a compiler does not support explicit inlining, this macro should be defined +| to be `static'. +*----------------------------------------------------------------------------*/ +#define INLINE static + diff --git a/libsrc/float/softfloat/README.txt b/libsrc/float/softfloat/README.txt new file mode 100644 index 000000000..1d7c4908f --- /dev/null +++ b/libsrc/float/softfloat/README.txt @@ -0,0 +1,83 @@ + +Package Overview for Berkeley SoftFloat Release 2c + +John R. Hauser +2015 January 30 + + +---------------------------------------------------------------------------- +Overview + +Berkeley SoftFloat is a software implementation of binary floating-point +that conforms to the IEEE Standard for Floating-Point Arithmetic. +Release 2c updates an older version of SoftFloat that has for most purposes +been supplanted by Release 3 or later. For the latest version of SoftFloat, +see Web page `http://www.jhauser.us/arithmetic/SoftFloat.html'. + +SoftFloat is distributed in the form of C source code. For Release 2c, +compiling the SoftFloat sources generates two things: + +-- A SoftFloat object file (typically `softfloat.o') containing the complete + set of IEC/IEEE floating-point routines. + +-- A `timesoftfloat' program for evaluating the speed of the SoftFloat + routines. (The SoftFloat module is linked into this program.) + +This version of the SoftFloat package is documented in four text files: + + SoftFloat.txt Documentation for using the SoftFloat functions. + SoftFloat-source.txt Documentation for compiling SoftFloat. + SoftFloat-history.txt History of major changes to SoftFloat. + timesoftfloat.txt Documentation for using `timesoftfloat'. + +Other files in the package comprise the source code for SoftFloat. + +Please be aware that some work is involved in porting this software to other +targets. It is not just a matter of getting `make' to complete without +error messages. You should not attempt to compile this release of SoftFloat +without first reading both `SoftFloat.txt' and `SoftFloat-source.txt'. +Depending on your needs, you may find that newer versions of SoftFloat are +less work to port. + + +---------------------------------------------------------------------------- +Legal Notice + +SoftFloat was written by John R. Hauser. Release 2c of SoftFloat was made +possible in part by the International Computer Science Institute, located +at Suite 600, 1947 Center Street, Berkeley, California 94704. Funding +was partially provided by the National Science Foundation under grant +MIP-9311980. The original version of this code was written as part of a +project to build a fixed-point vector processor in collaboration with the +University of California at Berkeley, overseen by Profs. Nelson Morgan and +John Wawrzynek. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TOLERATE ALL LOSSES, COSTS, OR +OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE WITHOUT RECOMPENSE FROM JOHN +HAUSER OR THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE, +OR INCURRED BY ANYONE DUE TO A DERIVATIVE WORK THEY CREATE USING ANY PART OF +THE SOFTWARE. + +The following are expressly permitted, even for commercial purposes: +(1) distribution of SoftFloat in whole or in part, as long as this and +other legal notices remain and are prominent, and provided also that, for a +partial distribution, prominent notice is given that it is a subset of the +original; and +(2) inclusion or use of SoftFloat in whole or in part in a derivative +work, provided that the use restrictions above are met and the minimal +documentation requirements stated in the source code are satisfied. + + +---------------------------------------------------------------------------- +Contact Information + +At the time of this writing, the most up-to-date information about SoftFloat +and the latest release can be found at the Web page `http://www.jhauser.us/ +arithmetic/SoftFloat.html'. + diff --git a/libsrc/float/softfloat/SoftFloat.txt b/libsrc/float/softfloat/SoftFloat.txt new file mode 100644 index 000000000..079233174 --- /dev/null +++ b/libsrc/float/softfloat/SoftFloat.txt @@ -0,0 +1,389 @@ + +Berkeley SoftFloat Release 2c General Documentation + +John R. Hauser +2015 January 30 + + +---------------------------------------------------------------------------- +Introduction + +Berkeley SoftFloat is a software implementation of binary floating-point +that conforms to the IEEE Standard for Floating-Point Arithmetic. For +Release 2c of SoftFloat, as many as four formats are supported: 32-bit +single-precision, 64-bit double-precision, 80-bit double-extended-precision, +and 128-bit quadruple-precision. All operations required by the older 1985 +version of the IEEE Standard are implemented, except for conversions to and +from decimal. + +This document gives information about the types defined and the routines +implemented by this release of SoftFloat. It does not attempt to define or +explain the IEEE Floating-Point Standard. Details about the standard are +available elsewhere. + + +---------------------------------------------------------------------------- +Limitations + +SoftFloat is written in C and is designed to work with other C code. The +SoftFloat header files assume an ISO/ANSI-style C compiler. No attempt +has been made to accomodate compilers that are not ISO-conformant. In +particular, the distributed header files will not be acceptable to any +compiler that does not recognize function prototypes. + +Support for the 80-bit double-extended-precision and 128-bit quadruple- +precision formats depends on a C compiler that implements 64-bit integer +arithmetic. If the largest integer format supported by the C compiler is +32 bits, SoftFloat is limited to only 32-bit single-precision and 64-bit +double-precision. When that is the case, all references in this document +to 80-bit double-extended-precision, 128-bit quadruple-precision, and 64-bit +integers should be ignored. + + +---------------------------------------------------------------------------- +Contents + + Introduction + Limitations + Contents + Legal Notice + Types and Functions + Rounding Modes + Double-Extended-Precision Rounding Precision + Exceptions and Exception Flags + Function Details + Conversion Functions + Basic Arithmetic Functions + Remainder Functions + Round-to-Integer Functions + Comparison Functions + Signaling NaN Test Functions + Raise-Exception Function + Contact Information + + + +---------------------------------------------------------------------------- +Legal Notice + +SoftFloat was written by John R. Hauser. Release 2c of SoftFloat was made +possible in part by the International Computer Science Institute, located +at Suite 600, 1947 Center Street, Berkeley, California 94704. Funding +was partially provided by the National Science Foundation under grant +MIP-9311980. The original version of this code was written as part of a +project to build a fixed-point vector processor in collaboration with the +University of California at Berkeley, overseen by Profs. Nelson Morgan and +John Wawrzynek. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TOLERATE ALL LOSSES, COSTS, OR +OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE WITHOUT RECOMPENSE FROM JOHN +HAUSER OR THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE, +OR INCURRED BY ANYONE DUE TO A DERIVATIVE WORK THEY CREATE USING ANY PART OF +THE SOFTWARE. + +The following are expressly permitted, even for commercial purposes: +(1) distribution of SoftFloat in whole or in part, as long as this and +other legal notices remain and are prominent, and provided also that, for a +partial distribution, prominent notice is given that it is a subset of the +original; and +(2) inclusion or use of SoftFloat in whole or in part in a derivative +work, provided that the use restrictions above are met and the minimal +documentation requirements stated in the source code are satisfied. + + +---------------------------------------------------------------------------- +Types and Functions + +When 64-bit integers are supported by the compiler, the `softfloat.h' header +file defines four types: `float32' (32-bit single-precision), `float64' +(64-bit double-precision), `floatx80' (80-bit double-extended-precision), +and `float128' (128-bit quadruple-precision). The `float32' and `float64' +types are defined in terms of 32-bit and 64-bit integer types, respectively, +while the `float128' type is defined as a structure of two 64-bit integers, +taking into account the byte order of the particular machine being used. +The `floatx80' type is defined as a structure containing one 16-bit and one +64-bit integer, with the machine's byte order again determining the order +within the structure. + +When 64-bit integers are _not_ supported by the compiler, the `softfloat.h' +header file defines only two types: `float32' and `float64'. Because +the ISO/ANSI C Standard guarantees at least one built-in integer type of +32 bits, the `float32' type is identified with an appropriate integer type. +The `float64' type is defined as a structure of two 32-bit integers, with +the machine's byte order determining the order of the fields. + +In either case, the types in `softfloat.h' are defined such that if a system +implements the usual C `float' and `double' types according to the IEEE +Standard, then the `float32' and `float64' types should be indistinguishable +in memory from the native `float' and `double' types. (On the other hand, +when `float32' or `float64' values are placed in processor registers by +the compiler, the type of registers used may differ from those used for the +native `float' and `double' types.) + +SoftFloat implements the following arithmetic operations: + +-- Conversions among all the floating-point formats, and also between + integers (32-bit and 64-bit) and any of the floating-point formats. + +-- The usual add, subtract, multiply, divide, and square root operations for + all floating-point formats. + +-- For each format, the floating-point remainder operation defined by the + IEEE Standard. + +-- For each floating-point format, a "round to integer" operation that + rounds to the nearest integer value in the same format. (The floating- + point formats can hold integer values, of course.) + +-- Comparisons between two values in the same floating-point format. + +The only functions required by the 1985 IEEE Standard that are not provided +are conversions to and from decimal. + + +---------------------------------------------------------------------------- +Rounding Modes + +All four rounding modes prescribed by the 1985 IEEE Standard are implemented +for all operations that require rounding. The rounding mode is selected +by the global variable `float_rounding_mode'. This variable may be set +to one of the values `float_round_nearest_even', `float_round_to_zero', +`float_round_down', or `float_round_up'. The rounding mode is initialized +to nearest/even. + + +---------------------------------------------------------------------------- +Double-Extended-Precision Rounding Precision + +For 80-bit double-extended-precision (`floatx80') only, the rounding +precision of the basic arithmetic operations is controlled by the global +variable `floatx80_rounding_precision'. The operations affected are: + + floatx80_add floatx80_sub floatx80_mul floatx80_div floatx80_sqrt + +When `floatx80_rounding_precision' is set to its default value of 80, +these operations are rounded (as usual) to the full precision of the 80-bit +double-extended-precision format. Setting `floatx80_rounding_precision' to +32 or to 64 causes the operations listed to be rounded to reduced precision +equivalent to 32-bit single-precision (`float32') or to 64-bit double- +precision (`float64'), respectively. When rounding to reduced precision, +additional bits in the result significand beyond the rounding point are set +to zero. The consequences of setting `floatx80_rounding_precision' to a +value other than 32, 64, or 80 is not specified. Operations other than the +ones listed above are not affected by `floatx80_rounding_precision'. + + +---------------------------------------------------------------------------- +Exceptions and Exception Flags + +All five exception flags required by the IEEE Standard are implemented. +Each flag is stored as a separate bit in the global variable +`float_exception_flags'. The positions of the exception flag bits within +this variable are determined by the bit masks `float_flag_inexact', +`float_flag_underflow', `float_flag_overflow', `float_flag_divbyzero', and +`float_flag_invalid'. The exception flags variable is initialized to all 0, +meaning no exceptions. + +An individual exception flag can be cleared with the statement + + float_exception_flags &= ~ float_flag_; + +where `' is the appropriate name. To raise a floating-point +exception, the SoftFloat function `float_raise' should be used (see below). + +In the terminology of the IEEE Standard, SoftFloat can detect tininess +for underflow either before or after rounding. The choice is made by +the global variable `float_detect_tininess', which can be set to either +`float_tininess_before_rounding' or `float_tininess_after_rounding'. +Detecting tininess after rounding is better because it results in fewer +spurious underflow signals. The other option is provided for compatibility +with some systems. Like most systems, SoftFloat always detects loss of +accuracy for underflow as an inexact result. + + +---------------------------------------------------------------------------- +Function Details + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Conversion Functions + +All conversions among the floating-point formats are supported, as are all +conversions between a floating-point format and 32-bit and 64-bit signed +integers. The complete set of conversion functions is: + + int32_to_float32 int64_to_float32 + int32_to_float64 int64_to_float64 + int32_to_floatx80 int64_to_floatx80 + int32_to_float128 int64_to_float128 + + float32_to_int32 float32_to_int64 + float64_to_int32 float64_to_int64 + floatx80_to_int32 floatx80_to_int64 + float128_to_int32 float128_to_int64 + + float32_to_float64 float32_to_floatx80 float32_to_float128 + float64_to_float32 float64_to_floatx80 float64_to_float128 + floatx80_to_float32 floatx80_to_float64 floatx80_to_float128 + float128_to_float32 float128_to_float64 float128_to_floatx80 + +Each conversion function takes one operand of the appropriate type and +returns one result. Conversions from a smaller to a larger floating-point +format are always exact and so require no rounding. Conversions from 32-bit +integers to 64-bit double-precision and larger formats are also exact, and +likewise for conversions from 64-bit integers to 80-bit double-extended- +precision and 128-bit quadruple-precision. + +Conversions from floating-point to integer raise the invalid exception if +the source value cannot be rounded to a representable integer of the desired +size (32 or 64 bits). If the floating-point operand is a NaN, the largest +positive integer is returned. Otherwise, if the conversion overflows, the +largest integer with the same sign as the operand is returned. + +On conversions to integer, if the floating-point operand is not already +an integer value, the operand is rounded according to the current rounding +mode as specified by `float_rounding_mode'. Because C (and perhaps other +languages) require that conversions to integers be rounded toward zero, the +following functions are provided for improved speed and convenience: + + float32_to_int32_round_to_zero float32_to_int64_round_to_zero + float64_to_int32_round_to_zero float64_to_int64_round_to_zero + floatx80_to_int32_round_to_zero floatx80_to_int64_round_to_zero + float128_to_int32_round_to_zero float128_to_int64_round_to_zero + +These variant functions ignore `float_rounding_mode' and always round toward +zero. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Basic Arithmetic Functions + +The following basic arithmetic functions are provided: + + float32_add float32_sub float32_mul float32_div float32_sqrt + float64_add float64_sub float64_mul float64_div float64_sqrt + floatx80_add floatx80_sub floatx80_mul floatx80_div floatx80_sqrt + float128_add float128_sub float128_mul float128_div float128_sqrt + +Each function takes two operands, except for `sqrt' which takes only one. +The operands and result are all of the same type. + +Rounding of the 80-bit double-extended-precision (`floatx80') functions is +affected by the `floatx80_rounding_precision' variable, as explained above +in the section _Double-Extended-Precision Rounding Precision_. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Remainder Functions + +For each format, SoftFloat implements the remainder function according to +the IEEE Standard. The remainder functions are: + + float32_rem + float64_rem + floatx80_rem + float128_rem + +Each remainder function takes two operands. The operands and result are all +of the same type. Given operands x and y, the remainder functions return +the value x - n*y, where n is the integer closest to x/y. If x/y is exactly +halfway between two integers, n is the even integer closest to x/y. The +remainder functions are always exact and so require no rounding. + +Depending on the relative magnitudes of the operands, the remainder +functions can take considerably longer to execute than the other SoftFloat +functions. This is inherent in the remainder operation itself and is not a +flaw in the SoftFloat implementation. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Round-to-Integer Functions + +For each format, SoftFloat implements the round-to-integer function +specified by the IEEE Standard. The functions are: + + float32_round_to_int + float64_round_to_int + floatx80_round_to_int + float128_round_to_int + +Each function takes a single floating-point operand and returns a result of +the same type. (Note that the result is not an integer type.) The operand +is rounded to an exact integer according to the current rounding mode, and +the resulting integer value is returned in the same floating-point format. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Comparison Functions + +The following floating-point comparison functions are provided: + + float32_eq float32_le float32_lt + float64_eq float64_le float64_lt + floatx80_eq floatx80_le floatx80_lt + float128_eq float128_le float128_lt + +Each function takes two operands of the same type and returns a 1 or 0 +representing either _true_ or _false_. The abbreviation `eq' stands for +"equal" (=); `le' stands for "less than or equal" (<=); and `lt' stands for +"less than" (<). + +The usual greater-than (>), greater-than-or-equal (>=), and not-equal (!=) +functions are easily obtained using the functions provided. The not-equal +function is just the logical complement of the equal function. The greater- +than-or-equal function is identical to the less-than-or-equal function with +the operands reversed, and the greater-than function is identical to the +less-than function with the operands reversed. + +The IEEE Standard specifies that the less-than-or-equal and less-than +functions raise the invalid exception if either input is any kind of NaN. +The equal functions, on the other hand, are defined not to raise the invalid +exception on quiet NaNs. For completeness, SoftFloat provides the following +additional functions: + + float32_eq_signaling float32_le_quiet float32_lt_quiet + float64_eq_signaling float64_le_quiet float64_lt_quiet + floatx80_eq_signaling floatx80_le_quiet floatx80_lt_quiet + float128_eq_signaling float128_le_quiet float128_lt_quiet + +The `signaling' equal functions are identical to the standard functions +except that the invalid exception is raised for any NaN input. Likewise, +the `quiet' comparison functions are identical to their counterparts except +that the invalid exception is not raised for quiet NaNs. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Signaling NaN Test Functions + +The following functions test whether a floating-point value is a signaling +NaN: + + float32_is_signaling_nan + float64_is_signaling_nan + floatx80_is_signaling_nan + float128_is_signaling_nan + +The functions take one operand and return 1 if the operand is a signaling +NaN and 0 otherwise. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Raise-Exception Function + +SoftFloat provides a function for raising floating-point exceptions: + + float_raise + +The function takes a mask indicating the set of exceptions to raise. No +result is returned. In addition to setting the specified exception flags, +this function may cause a trap or abort appropriate for the current system. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +---------------------------------------------------------------------------- +Contact Information + +At the time of this writing, the most up-to-date information about SoftFloat +and the latest release can be found at the Web page `http://www.jhauser.us/ +arithmetic/SoftFloat.html'. + diff --git a/libsrc/float/softfloat/history.txt b/libsrc/float/softfloat/history.txt new file mode 100644 index 000000000..daabf0e61 --- /dev/null +++ b/libsrc/float/softfloat/history.txt @@ -0,0 +1,65 @@ + +History of Major Changes to Berkeley SoftFloat, up to Release 2c + +John R. Hauser +2015 January 31 + + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Release 2c (2015 January) + +-- Fixed mistakes affecting some 64-bit processors. + +-- Further improved the documentation and the wording for the legal + restrictions on using SoftFloat. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Release 2b (2002 May) + +-- Made minor updates to the documentation, including improved wording for + the legal restrictions on using SoftFloat. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Release 2a (1998 December) + +-- Added functions to convert between 64-bit integers (int64) and all + supported floating-point formats. + +-- Fixed a bug in all 64-bit-version square root functions except + `float32_sqrt' that caused the result sometimes to be off by 1 unit in + the last place (1 ulp) from what it should be. (Bug discovered by Paul + Donahue.) + +-- Improved the Makefiles. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Release 2 (1997 June) + +-- Created the 64-bit (bits64) version, adding the floatx80 and float128 + formats. + +-- Changed the source directory structure, splitting the sources into a + `bits32' and a `bits64' version. Renamed `environment.h' to `milieu.h' + to avoid confusion with environment variables. + +-- Fixed a small error that caused `float64_round_to_int' often to round the + wrong way in nearest/even mode when the operand was between 2^20 and 2^21 + and halfway between two integers. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Release 1a (1996 July) + +-- Corrected a mistake that caused borderline underflow cases not to raise + the underflow flag when they should have. (Problem reported by Doug + Priest.) + +-- Added the `float_detect_tininess' variable to control whether tininess is + detected before or after rounding. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Release 1 (1996 July) + +-- Original release. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/libsrc/float/softfloat/macros.h b/libsrc/float/softfloat/macros.h new file mode 100644 index 000000000..00fcc8cfb --- /dev/null +++ b/libsrc/float/softfloat/macros.h @@ -0,0 +1,644 @@ + +/*============================================================================ + +This C source fragment is part of the Berkeley SoftFloat IEEE Floating-Point +Arithmetic Package, Release 2c, by John R. Hauser. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TOLERATE ALL LOSSES, COSTS, OR OTHER +PROBLEMS THEY INCUR DUE TO THE SOFTWARE WITHOUT RECOMPENSE FROM JOHN HAUSER OR +THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE, AND WHO FURTHERMORE EFFECTIVELY +INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE +(possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR OTHER +PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE, OR +INCURRED BY ANYONE DUE TO A DERIVATIVE WORK THEY CREATE USING ANY PART OF THE +SOFTWARE. + +Derivative works require also that (1) the source code for the derivative work +includes prominent notice that the work is derivative, and (2) the source code +includes prominent notice of these three paragraphs for those parts of this +code that are retained. + +=============================================================================*/ + +/*---------------------------------------------------------------------------- +| Shifts `a' right by the number of bits given in `count'. If any nonzero +| bits are shifted off, they are "jammed" into the least significant bit of +| the result by setting the least significant bit to 1. The value of `count' +| can be arbitrarily large; in particular, if `count' is greater than 32, the +| result will be either 0 or 1, depending on whether `a' is zero or nonzero. +| The result is stored in the location pointed to by `zPtr'. +*----------------------------------------------------------------------------*/ + +INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr ) +{ + bits32 z; + + if ( count == 0 ) { + z = a; + } + else if ( count < 32 ) { + z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 ); + } + else { + z = ( a != 0 ); + } + *zPtr = z; + +} + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Shifts the 64-bit value formed by concatenating `a0' and `a1' right by the +| number of bits given in `count'. Any bits shifted off are lost. The value +| of `count' can be arbitrarily large; in particular, if `count' is greater +| than 64, the result will be 0. The result is broken into two 32-bit pieces +| which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shift64Right( + bits32 a0, bits32 a1, int16 count, bits32 *z0Ptr, bits32 *z1Ptr ) +{ + bits32 z0, z1; + int8 negCount = ( - count ) & 31; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 32 ) { + z1 = ( a0<>count ); + z0 = a0>>count; + } + else { + z1 = ( count < 64 ) ? ( a0>>( count & 31 ) ) : 0; + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} +#endif + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Shifts the 64-bit value formed by concatenating `a0' and `a1' right by the +| number of bits given in `count'. If any nonzero bits are shifted off, they +| are "jammed" into the least significant bit of the result by setting the +| least significant bit to 1. The value of `count' can be arbitrarily large; +| in particular, if `count' is greater than 64, the result will be either 0 +| or 1, depending on whether the concatenation of `a0' and `a1' is zero or +| nonzero. The result is broken into two 32-bit pieces which are stored at +| the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shift64RightJamming( + bits32 a0, bits32 a1, int16 count, bits32 *z0Ptr, bits32 *z1Ptr ) +{ + bits32 z0, z1; + int8 negCount = ( - count ) & 31; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 32 ) { + z1 = ( a0<>count ) | ( ( a1<>count; + } + else { + if ( count == 32 ) { + z1 = a0 | ( a1 != 0 ); + } + else if ( count < 64 ) { + z1 = ( a0>>( count & 31 ) ) | ( ( ( a0<>count ); + z0 = a0>>count; + } + else { + if ( count == 32 ) { + z2 = a1; + z1 = a0; + } + else { + a2 |= a1; + if ( count < 64 ) { + z2 = a0<>( count & 31 ); + } + else { + z2 = ( count == 64 ) ? a0 : ( a0 != 0 ); + z1 = 0; + } + } + z0 = 0; + } + z2 |= ( a2 != 0 ); + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} +#endif + +/*---------------------------------------------------------------------------- +| Shifts the 64-bit value formed by concatenating `a0' and `a1' left by the +| number of bits given in `count'. Any bits shifted off are lost. The value +| of `count' must be less than 32. The result is broken into two 32-bit +| pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shortShift64Left( + bits32 a0, bits32 a1, int16 count, bits32 *z0Ptr, bits32 *z1Ptr ) +{ + + *z1Ptr = a1<>( ( - count ) & 31 ) ); + +} + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Shifts the 96-bit value formed by concatenating `a0', `a1', and `a2' left +| by the number of bits given in `count'. Any bits shifted off are lost. +| The value of `count' must be less than 32. The result is broken into three +| 32-bit pieces which are stored at the locations pointed to by `z0Ptr', +| `z1Ptr', and `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shortShift96Left( + bits32 a0, + bits32 a1, + bits32 a2, + int16 count, + bits32 *z0Ptr, + bits32 *z1Ptr, + bits32 *z2Ptr + ) +{ + bits32 z0, z1, z2; + int8 negCount; + + z2 = a2<>negCount; + z0 |= a1>>negCount; + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} +#endif + +/*---------------------------------------------------------------------------- +| Adds the 64-bit value formed by concatenating `a0' and `a1' to the 64-bit +| value formed by concatenating `b0' and `b1'. Addition is modulo 2^64, so +| any carry out is lost. The result is broken into two 32-bit pieces which +| are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + add64( + bits32 a0, bits32 a1, bits32 b0, bits32 b1, bits32 *z0Ptr, bits32 *z1Ptr ) +{ + bits32 z1; + + z1 = a1 + b1; + *z1Ptr = z1; + *z0Ptr = a0 + b0 + ( z1 < a1 ); + +} + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Adds the 96-bit value formed by concatenating `a0', `a1', and `a2' to the +| 96-bit value formed by concatenating `b0', `b1', and `b2'. Addition is +| modulo 2^96, so any carry out is lost. The result is broken into three +| 32-bit pieces which are stored at the locations pointed to by `z0Ptr', +| `z1Ptr', and `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + add96( + bits32 a0, + bits32 a1, + bits32 a2, + bits32 b0, + bits32 b1, + bits32 b2, + bits32 *z0Ptr, + bits32 *z1Ptr, + bits32 *z2Ptr + ) +{ + bits32 z0, z1, z2; + int8 carry0, carry1; + + z2 = a2 + b2; + carry1 = ( z2 < a2 ); + z1 = a1 + b1; + carry0 = ( z1 < a1 ); + z0 = a0 + b0; + z1 += carry1; + z0 += ( z1 < carry1 ); + z0 += carry0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} +#endif + +/*---------------------------------------------------------------------------- +| Subtracts the 64-bit value formed by concatenating `b0' and `b1' from the +| 64-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo +| 2^64, so any borrow out (carry out) is lost. The result is broken into two +| 32-bit pieces which are stored at the locations pointed to by `z0Ptr' and +| `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + sub64( + bits32 a0, bits32 a1, bits32 b0, bits32 b1, bits32 *z0Ptr, bits32 *z1Ptr ) +{ + + *z1Ptr = a1 - b1; + *z0Ptr = a0 - b0 - ( a1 < b1 ); + +} + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Subtracts the 96-bit value formed by concatenating `b0', `b1', and `b2' from +| the 96-bit value formed by concatenating `a0', `a1', and `a2'. Subtraction +| is modulo 2^96, so any borrow out (carry out) is lost. The result is broken +| into three 32-bit pieces which are stored at the locations pointed to by +| `z0Ptr', `z1Ptr', and `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + sub96( + bits32 a0, + bits32 a1, + bits32 a2, + bits32 b0, + bits32 b1, + bits32 b2, + bits32 *z0Ptr, + bits32 *z1Ptr, + bits32 *z2Ptr + ) +{ + bits32 z0, z1, z2; + int8 borrow0, borrow1; + + z2 = a2 - b2; + borrow1 = ( a2 < b2 ); + z1 = a1 - b1; + borrow0 = ( a1 < b1 ); + z0 = a0 - b0; + z0 -= ( z1 < borrow1 ); + z1 -= borrow1; + z0 -= borrow0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} +#endif + +/*---------------------------------------------------------------------------- +| Multiplies `a' by `b' to obtain a 64-bit product. The product is broken +| into two 32-bit pieces which are stored at the locations pointed to by +| `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void mul32To64( bits32 a, bits32 b, bits32 *z0Ptr, bits32 *z1Ptr ) +{ + bits16 aHigh, aLow, bHigh, bLow; + bits32 z0, zMiddleA, zMiddleB, z1; + + aLow = a; + aHigh = a>>16; + bLow = b; + bHigh = b>>16; + z1 = ( (bits32) aLow ) * bLow; + zMiddleA = ( (bits32) aLow ) * bHigh; + zMiddleB = ( (bits32) aHigh ) * bLow; + z0 = ( (bits32) aHigh ) * bHigh; + zMiddleA += zMiddleB; + z0 += ( ( (bits32) ( zMiddleA < zMiddleB ) )<<16 ) + ( zMiddleA>>16 ); + zMiddleA <<= 16; + z1 += zMiddleA; + z0 += ( z1 < zMiddleA ); + *z1Ptr = z1; + *z0Ptr = z0; + +} + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Multiplies the 64-bit value formed by concatenating `a0' and `a1' by `b' +| to obtain a 96-bit product. The product is broken into three 32-bit pieces +| which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and +| `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + mul64By32To96( + bits32 a0, + bits32 a1, + bits32 b, + bits32 *z0Ptr, + bits32 *z1Ptr, + bits32 *z2Ptr + ) +{ + bits32 z0, z1, z2, more1; + + mul32To64( a1, b, &z1, &z2 ); + mul32To64( a0, b, &z0, &more1 ); + add64( z0, more1, 0, z1, &z0, &z1 ); + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} +#endif + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Multiplies the 64-bit value formed by concatenating `a0' and `a1' to the +| 64-bit value formed by concatenating `b0' and `b1' to obtain a 128-bit +| product. The product is broken into four 32-bit pieces which are stored at +| the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + mul64To128( + bits32 a0, + bits32 a1, + bits32 b0, + bits32 b1, + bits32 *z0Ptr, + bits32 *z1Ptr, + bits32 *z2Ptr, + bits32 *z3Ptr + ) +{ + bits32 z0, z1, z2, z3; + bits32 more1, more2; + + mul32To64( a1, b1, &z2, &z3 ); + mul32To64( a1, b0, &z1, &more2 ); + add64( z1, more2, 0, z2, &z1, &z2 ); + mul32To64( a0, b0, &z0, &more1 ); + add64( z0, more1, 0, z1, &z0, &z1 ); + mul32To64( a0, b1, &more1, &more2 ); + add64( more1, more2, 0, z2, &more1, &z2 ); + add64( z0, z1, 0, more1, &z0, &z1 ); + *z3Ptr = z3; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} +#endif + +/*---------------------------------------------------------------------------- +| Returns an approximation to the 32-bit integer quotient obtained by dividing +| `b' into the 64-bit value formed by concatenating `a0' and `a1'. The +| divisor `b' must be at least 2^31. If q is the exact quotient truncated +| toward zero, the approximation returned lies between q and q + 2 inclusive. +| If the exact quotient q is larger than 32 bits, the maximum positive 32-bit +| unsigned integer is returned. +*----------------------------------------------------------------------------*/ + +static bits32 estimateDiv64To32( bits32 a0, bits32 a1, bits32 b ) +{ + bits32 b0, b1; + bits32 rem0, rem1, term0, term1; + bits32 z; + + if ( b <= a0 ) return 0xFFFFFFFF; + b0 = b>>16; + z = ( b0<<16 <= a0 ) ? 0xFFFF0000 : ( a0 / b0 )<<16; + mul32To64( b, z, &term0, &term1 ); + sub64( a0, a1, term0, term1, &rem0, &rem1 ); + while ( ( (sbits32) rem0 ) < 0 ) { + z -= 0x10000; + b1 = b<<16; + add64( rem0, rem1, b0, b1, &rem0, &rem1 ); + } + rem0 = ( rem0<<16 ) | ( rem1>>16 ); + z |= ( b0<<16 <= rem0 ) ? 0xFFFF : rem0 / b0; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns an approximation to the square root of the 32-bit significand given +| by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of +| `aExp' (the least significant bit) is 1, the integer returned approximates +| 2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp' +| is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either +| case, the approximation returned lies strictly within +/-2 of the exact +| value. +*----------------------------------------------------------------------------*/ + +static bits32 estimateSqrt32( int16 aExp, bits32 a ) +{ + static const bits16 sqrtOddAdjustments[] = { + 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, + 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67 + }; + static const bits16 sqrtEvenAdjustments[] = { + 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E, + 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002 + }; + int8 index; + bits32 z; + + index = ( a>>27 ) & 15; + if ( aExp & 1 ) { + z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ]; + z = ( ( a / z )<<14 ) + ( z<<15 ); + a >>= 1; + } + else { + z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ]; + z = a / z + z; + z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 ); + if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 ); + } + return ( ( estimateDiv64To32( a, 0, z ) )>>1 ) + ( z>>1 ); + +} + +/*---------------------------------------------------------------------------- +| Returns the number of leading 0 bits before the most-significant 1 bit of +| `a'. If `a' is zero, 32 is returned. +*----------------------------------------------------------------------------*/ + +static int8 countLeadingZeros32( bits32 a ) +{ + static const int8 countLeadingZerosHigh[] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + int8 shiftCount; + + shiftCount = 0; + if ( a < 0x10000 ) { + shiftCount += 16; + a <<= 16; + } + if ( a < 0x1000000 ) { + shiftCount += 8; + a <<= 8; + } + shiftCount += countLeadingZerosHigh[ a>>24 ]; + return shiftCount; + +} + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Returns 1 if the 64-bit value formed by concatenating `a0' and `a1' is +| equal to the 64-bit value formed by concatenating `b0' and `b1'. Otherwise, +| returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag eq64( bits32 a0, bits32 a1, bits32 b0, bits32 b1 ) +{ + + return ( a0 == b0 ) && ( a1 == b1 ); + +} +#endif + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Returns 1 if the 64-bit value formed by concatenating `a0' and `a1' is less +| than or equal to the 64-bit value formed by concatenating `b0' and `b1'. +| Otherwise, returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag le64( bits32 a0, bits32 a1, bits32 b0, bits32 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) ); + +} +#endif + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Returns 1 if the 64-bit value formed by concatenating `a0' and `a1' is less +| than the 64-bit value formed by concatenating `b0' and `b1'. Otherwise, +| returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag lt64( bits32 a0, bits32 a1, bits32 b0, bits32 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) ); + +} +#endif + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Returns 1 if the 64-bit value formed by concatenating `a0' and `a1' is not +| equal to the 64-bit value formed by concatenating `b0' and `b1'. Otherwise, +| returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag ne64( bits32 a0, bits32 a1, bits32 b0, bits32 b1 ) +{ + + return ( a0 != b0 ) || ( a1 != b1 ); + +} +#endif + diff --git a/libsrc/float/softfloat/milieu.h b/libsrc/float/softfloat/milieu.h new file mode 100644 index 000000000..427c284e9 --- /dev/null +++ b/libsrc/float/softfloat/milieu.h @@ -0,0 +1,38 @@ + +/*============================================================================ + +This C header file template is part of the Berkeley SoftFloat IEEE Floating- +Point Arithmetic Package, Release 2c, by John R. Hauser. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TOLERATE ALL LOSSES, COSTS, OR OTHER +PROBLEMS THEY INCUR DUE TO THE SOFTWARE WITHOUT RECOMPENSE FROM JOHN HAUSER OR +THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE, AND WHO FURTHERMORE EFFECTIVELY +INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE +(possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR OTHER +PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE, OR +INCURRED BY ANYONE DUE TO A DERIVATIVE WORK THEY CREATE USING ANY PART OF THE +SOFTWARE. + +Derivative works require also that (1) the source code for the derivative work +includes prominent notice that the work is derivative, and (2) the source code +includes prominent notice of these three paragraphs for those parts of this +code that are retained. + +=============================================================================*/ + +/*---------------------------------------------------------------------------- +| Include common integer types and flags. +*----------------------------------------------------------------------------*/ +#include "6502-CC65.h" + +/*---------------------------------------------------------------------------- +| Symbolic Boolean literals. +*----------------------------------------------------------------------------*/ +enum { + FALSE = 0, + TRUE = 1 +}; + diff --git a/libsrc/float/softfloat/softfloat-wrapper.s b/libsrc/float/softfloat/softfloat-wrapper.s new file mode 100644 index 000000000..d600e2117 --- /dev/null +++ b/libsrc/float/softfloat/softfloat-wrapper.s @@ -0,0 +1,179 @@ + + .importzp sreg, tmp1 + + .import _int32_to_float32 + +;------------------------------------------------------------------------------ +; conversions: to float + + ; 16bit signed -> float + .export axfloat +axfloat: + ; FIXME + ; sign extend to 32bit + ldy #$ff + cpx #$80 + bcs @sk + ldy #$00 +@sk: + sty sreg + sty sreg+1 + jmp _int32_to_float32 + + ; 16bit unsigned -> float + .export axufloat +axufloat: + ; FIXME + ldy #0 + sty sreg + sty sreg+1 + jmp _int32_to_float32 + + ; 32bit signed -> float + .export eaxfloat +eaxfloat: + ; FIXME + jmp _int32_to_float32 + + ; 32bit unsigned -> float + .export eaxufloat +eaxufloat: + ; FIXME + jmp _int32_to_float32 + +;------------------------------------------------------------------------------ +; conversions: from float + + .import _float32_to_int32 + .import _float32_to_int32_round_to_zero + + ; float -> 16bit int + .export feaxint +feaxint: + ; FIXME + jmp _float32_to_int32_round_to_zero +; jmp _float32_to_int32 + ; float -> 32bit int + .export feaxlong +feaxlong: + jmp _float32_to_int32_round_to_zero +; jmp _float32_to_int32 + +;------------------------------------------------------------------------------ +; the ! operator, returns a bool (int) + .export fbnegeax +fbnegeax: + stx tmp1 + ora tmp1 + ora sreg + ora sreg+1 + beq @ret1 ; is = 0 + ; return 0 + lda #0 + tax + rts +@ret1: + lda #1 + ldx #0 + rts + + .import _float32_mul + ; arg0: a/x/sreg/sreg+1 + .export fnegeax +fnegeax: + pha +; txa +; pha + lda sreg+1 + eor #$80 ; sign bit + sta sreg+1 +; lda sreg+0 +; eor #$ff ; sign bit +; sta sreg+0 +; txa +; eor #$ff ; sign bit +; tax +; pla +; tax + pla +; eor #$ff ; sign bit + rts + + + .import _float32_add + .import _float32_sub + .import _float32_mul + .import _float32_div + + .export ftosaddeax +ftosaddeax: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + jmp _float32_add + .export ftossubeax +ftossubeax: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + jmp _float32_sub + .export ftosmuleax +ftosmuleax: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + jmp _float32_mul + .export ftosdiveax +ftosdiveax: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + jmp _float32_div + + .import _float32_rsub + .export ftosrsubeax +ftosrsubeax: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + jmp _float32_rsub + + .import _float32_eq + .import _float32_le + .import _float32_lt + + ; test for equal + .export ftoseqeax +ftoseqeax: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + jmp _float32_eq + + ; test for not equal + .export ftosneeax +ftosneeax: + ; arg0: a/x/sreg/sreg+1 + ; arg1: (sp),y (y=0..3) + jsr _float32_eq + eor #1 + rts + + + ; Test for less than or equal to + .export ftosleeax +ftosleeax: + jmp _float32_le + + .export ftosgteax +ftosgteax: + jsr _float32_le + eor #1 + rts + + ; Test for less than + .export ftoslteax +ftoslteax: + jmp _float32_lt + + ; Test for "not less than" -> "equal or greater than" + ; Test for greater than or equal to + .export ftosgeeax +ftosgeeax: + jsr _float32_lt + eor #1 + rts diff --git a/libsrc/float/softfloat/softfloat.c b/libsrc/float/softfloat/softfloat.c new file mode 100644 index 000000000..4adb4beb7 --- /dev/null +++ b/libsrc/float/softfloat/softfloat.c @@ -0,0 +1,2295 @@ + +/*============================================================================ + +This C source file is part of the Berkeley SoftFloat IEEE Floating-Point +Arithmetic Package, Release 2c, by John R. Hauser. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TOLERATE ALL LOSSES, COSTS, OR OTHER +PROBLEMS THEY INCUR DUE TO THE SOFTWARE WITHOUT RECOMPENSE FROM JOHN HAUSER OR +THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE, AND WHO FURTHERMORE EFFECTIVELY +INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE +(possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR OTHER +PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE, OR +INCURRED BY ANYONE DUE TO A DERIVATIVE WORK THEY CREATE USING ANY PART OF THE +SOFTWARE. + +Derivative works require also that (1) the source code for the derivative work +includes prominent notice that the work is derivative, and (2) the source code +includes prominent notice of these three paragraphs for those parts of this +code that are retained. + +=============================================================================*/ + +#include "milieu.h" +#include "softfloat.h" + +/*---------------------------------------------------------------------------- +| Floating-point rounding mode and exception flags. +*----------------------------------------------------------------------------*/ +int8 float_rounding_mode = float_round_nearest_even; +int8 float_exception_flags = 0; + +/*---------------------------------------------------------------------------- +| Primitive arithmetic functions, including multi-word arithmetic, and +| division and square root approximations. (Can be specialized to target if +| desired.) +*----------------------------------------------------------------------------*/ +#include "macros.h" + +/*---------------------------------------------------------------------------- +| Functions and definitions to determine: (1) whether tininess for underflow +| is detected before or after rounding by default, (2) what (if anything) +| happens when exceptions are raised, (3) how signaling NaNs are distinguished +| from quiet NaNs, (4) the default generated quiet NaNs, and (4) how NaNs +| are propagated from function inputs to output. These details are target- +| specific. +*----------------------------------------------------------------------------*/ +#include "specialize.h" + +/*---------------------------------------------------------------------------- +| Returns the fraction bits of the single-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE bits32 extractFloat32Frac( float32 a ) +{ + + return a & 0x007FFFFF; + +} + +/*---------------------------------------------------------------------------- +| Returns the exponent bits of the single-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE int16 extractFloat32Exp( float32 a ) +{ + + return ( a>>23 ) & 0xFF; + +} + +/*---------------------------------------------------------------------------- +| Returns the sign bit of the single-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE flag extractFloat32Sign( float32 a ) +{ + + return a>>31; + +} + +/*---------------------------------------------------------------------------- +| Normalizes the subnormal single-precision floating-point value represented +| by the denormalized significand `aSig'. The normalized exponent and +| significand are stored at the locations pointed to by `zExpPtr' and +| `zSigPtr', respectively. +*----------------------------------------------------------------------------*/ + +static void + normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( aSig ) - 8; + *zSigPtr = aSig<>7; + zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + if ( zSig == 0 ) zExp = 0; + return packFloat32( zSign, zExp, zSig ); + +} + +/*---------------------------------------------------------------------------- +| Takes an abstract floating-point value having sign `zSign', exponent `zExp', +| and significand `zSig', and returns the proper single-precision floating- +| point value corresponding to the abstract input. This routine is just like +| `roundAndPackFloat32' except that `zSig' does not have to be normalized. +| Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the "true" +| floating-point exponent. +*----------------------------------------------------------------------------*/ + +static float32 + normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( zSig ) - 1; + return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<>20 ) & 0x7FF; + +} + +/*---------------------------------------------------------------------------- +| Returns the sign bit of the double-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE flag extractFloat64Sign( float64 a ) +{ + + return a.high>>31; + +} +#endif + +/*---------------------------------------------------------------------------- +| Normalizes the subnormal double-precision floating-point value represented +| by the denormalized significand formed by the concatenation of `aSig0' and +| `aSig1'. The normalized exponent is stored at the location pointed to by +| `zExpPtr'. The most significant 21 bits of the normalized significand are +| stored at the location pointed to by `zSig0Ptr', and the least significant +| 32 bits of the normalized significand are stored at the location pointed to +| by `zSig1Ptr'. +*----------------------------------------------------------------------------*/ + +#ifdef DOUBLES +static void + normalizeFloat64Subnormal( + bits32 aSig0, + bits32 aSig1, + int16 *zExpPtr, + bits32 *zSig0Ptr, + bits32 *zSig1Ptr + ) +{ + int8 shiftCount; + + if ( aSig0 == 0 ) { + shiftCount = countLeadingZeros32( aSig1 ) - 11; + if ( shiftCount < 0 ) { + *zSig0Ptr = aSig1>>( - shiftCount ); + *zSig1Ptr = aSig1<<( shiftCount & 31 ); + } + else { + *zSig0Ptr = aSig1<>( - shiftCount ); + } + if ( aSigExtra ) float_exception_flags |= float_flag_inexact; + roundingMode = float_rounding_mode; + if ( roundingMode == float_round_nearest_even ) { + if ( (sbits32) aSigExtra < 0 ) { + ++z; + if ( (bits32) ( aSigExtra<<1 ) == 0 ) z &= ~1; + } + if ( aSign ) z = - z; + } + else { + aSigExtra = ( aSigExtra != 0 ); + if ( aSign ) { + z += ( roundingMode == float_round_down ) & aSigExtra; + z = - z; + } + else { + z += ( roundingMode == float_round_up ) & aSigExtra; + } + } + } + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the 32-bit two's complement integer format. The conversion is +| performed according to the IEEE Standard for Floating-Point Arithmetic, +| except that the conversion is always rounded toward zero. If `a' is a NaN, +| the largest positive integer is returned. Otherwise, if the conversion +| overflows, the largest integer with the same sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int32 float32_to_int32_round_to_zero( float32 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits32 aSig; + int32 z; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + shiftCount = aExp - 0x9E; + if ( 0 <= shiftCount ) { + if ( a != 0xCF000000 ) { + float_raise( float_flag_invalid ); + if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF; + } + return (sbits32) 0x80000000; + } + else if ( aExp <= 0x7E ) { + if ( aExp | aSig ) float_exception_flags |= float_flag_inexact; + return 0; + } + aSig = ( aSig | 0x00800000 )<<8; + z = aSig>>( - shiftCount ); + if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) { + float_exception_flags |= float_flag_inexact; + } + if ( aSign ) z = - z; + return z; + +} + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the double-precision floating-point format. The conversion is +| performed according to the IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float32_to_float64( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 aSig, zSig0, zSig1; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a ) ); + return packFloat64( aSign, 0x7FF, 0, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( aSign, 0, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + shift64Right( aSig, 0, 3, &zSig0, &zSig1 ); + return packFloat64( aSign, aExp + 0x380, zSig0, zSig1 ); + +} +#endif + +/*---------------------------------------------------------------------------- +| Rounds the single-precision floating-point value `a' to an integer, +| and returns the result as a single-precision floating-point value. The +| operation is performed according to the IEEE Standard for Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 __fastcall__ float32_round_to_int( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 lastBitMask, roundBitsMask; + int8 roundingMode; + float32 z; + + aExp = extractFloat32Exp( a ); + if ( 0x96 <= aExp ) { + if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) { + return propagateFloat32NaN( a, a ); + } + return a; + } + if ( aExp <= 0x7E ) { + if ( (bits32) ( a<<1 ) == 0 ) return a; + float_exception_flags |= float_flag_inexact; + aSign = extractFloat32Sign( a ); + switch ( float_rounding_mode ) { + case float_round_nearest_even: + if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) { + return packFloat32( aSign, 0x7F, 0 ); + } + break; + case float_round_down: + return aSign ? 0xBF800000 : 0; + case float_round_up: + return aSign ? 0x80000000 : 0x3F800000; + } + return packFloat32( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x96 - aExp; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = float_rounding_mode; + if ( roundingMode == float_round_nearest_even ) { + z += lastBitMask>>1; + if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z += roundBitsMask; + } + } + z &= ~ roundBitsMask; + if ( z != a ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the absolute values of the single-precision +| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated +| before being returned. `zSign' is ignored if the result is a NaN. The +| addition is performed according to the IEEE Standard for Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +static float32 addFloat32Sigs( float32 a, float32 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 6; + bSig <<= 6; + if ( 0 < expDiff ) { + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x20000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x20000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + zExp = bExp; + } + else { + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); + zSig = 0x40000000 + aSig + bSig; + zExp = aExp; + goto roundAndPack; + } + aSig |= 0x20000000; + zSig = ( aSig + bSig )<<1; + --zExp; + if ( (sbits32) zSig < 0 ) { + zSig = aSig + bSig; + ++zExp; + } + roundAndPack: + return roundAndPackFloat32( zSign, zExp, zSig ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the absolute values of the single- +| precision floating-point values `a' and `b'. If `zSign' is 1, the +| difference is negated before being returned. `zSign' is ignored if the +| result is a NaN. The subtraction is performed according to the IEEE +| Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float32 subFloat32Sigs( float32 a, float32 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 7; + bSig <<= 7; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b ); + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloat32( float_rounding_mode == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return packFloat32( zSign ^ 1, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x40000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + bSig |= 0x40000000; + bBigger: + zSig = bSig - aSig; + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x40000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + aSig |= 0x40000000; + aBigger: + zSig = aSig - bSig; + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat32( zSign, zExp, zSig ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the single-precision floating-point values +| `a' and `b'. The operation is performed according to the IEEE Standard for +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 __fastcall__ float32_add( float32 a, float32 b ) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return addFloat32Sigs( a, b, aSign ); + } + else { + return subFloat32Sigs( a, b, aSign ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the single-precision floating-point values +| `a' and `b'. The operation is performed according to the IEEE Standard for +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +#if 0 +float32 __fastcall__ float32_sub( float32 b, float32 a ) // swapped +#else +float32 __fastcall__ float32_sub( float32 a, float32 b ) // original +#endif +{ +#if 1 + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return subFloat32Sigs( a, b, aSign ); + } + else { + return addFloat32Sigs( a, b, aSign ); + } +#else + b = b; + return a; +#endif +} + +float32 __fastcall__ float32_rsub( float32 b, float32 a ) // swapped +{ +#if 1 + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return subFloat32Sigs( a, b, aSign ); + } + else { + return addFloat32Sigs( a, b, aSign ); + } +#else + b = b; + return a; +#endif +} + +/*---------------------------------------------------------------------------- +| Returns the result of multiplying the single-precision floating-point values +| `a' and `b'. The operation is performed according to the IEEE Standard for +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 __fastcall__ float32_mul( float32 a, float32 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig0, zSig1; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b ); + } + if ( ( bExp | bSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x7F; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + mul32To64( aSig, bSig, &zSig0, &zSig1 ); + zSig0 |= ( zSig1 != 0 ); + if ( 0 <= (sbits32) ( zSig0<<1 ) ) { + zSig0 <<= 1; + --zExp; + } + return roundAndPackFloat32( zSign, zExp, zSig0 ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of dividing the single-precision floating-point value `a' +| by the corresponding value `b'. The operation is performed according to the +| IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_div( float32 a, float32 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig, rem0, rem1, term0, term1; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b ); + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + float_raise( float_flag_invalid ); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return packFloat32( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + float_raise( float_flag_divbyzero ); + return packFloat32( zSign, 0xFF, 0 ); + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x7D; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + if ( bSig <= ( aSig + aSig ) ) { + aSig >>= 1; + ++zExp; + } + zSig = estimateDiv64To32( aSig, 0, bSig ); + if ( ( zSig & 0x3F ) <= 2 ) { + mul32To64( bSig, zSig, &term0, &term1 ); + sub64( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits32) rem0 < 0 ) { + --zSig; + add64( rem0, rem1, 0, bSig, &rem0, &rem1 ); + } + zSig |= ( rem1 != 0 ); + } + return roundAndPackFloat32( zSign, zExp, zSig ); + +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the single-precision floating-point value `a' +| with respect to the corresponding value `b'. The operation is performed +| according to the IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 __fastcall__ float32_rem( float32 a, float32 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits32 aSig, bSig, q, /*allZero,*/ alternateASig; + sbits32 sigMean; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b ); + } + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return a; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + expDiff = aExp - bExp; + aSig = ( aSig | 0x00800000 )<<8; + bSig = ( bSig | 0x00800000 )<<8; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + aSig >>= 1; + } + q = ( bSig <= aSig ); + if ( q ) aSig -= bSig; + expDiff -= 32; + while ( 0 < expDiff ) { + q = estimateDiv64To32( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + aSig = - ( ( bSig>>2 ) * q ); + expDiff -= 30; + } + expDiff += 32; + if ( 0 < expDiff ) { + q = estimateDiv64To32( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + q >>= 32 - expDiff; + bSig >>= 2; + aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; + } + else { + aSig >>= 2; + bSig >>= 2; + } + do { + alternateASig = aSig; + ++q; + aSig -= bSig; + } while ( 0 <= (sbits32) aSig ); + sigMean = aSig + alternateASig; + if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { + aSig = alternateASig; + } + zSign = ( (sbits32) aSig < 0 ); + if ( zSign ) aSig = - aSig; + return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig ); + +} + +/*---------------------------------------------------------------------------- +| Returns the square root of the single-precision floating-point value `a'. +| The operation is performed according to the IEEE Standard for Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 __fastcall__ float32_sqrt( float32 a ) +{ + flag aSign; + int16 aExp, zExp; + bits32 aSig, zSig, rem0, rem1, term0, term1; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, 0 ); + if ( ! aSign ) return a; + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( aSign ) { + if ( ( aExp | aSig ) == 0 ) return a; + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return 0; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E; + aSig = ( aSig | 0x00800000 )<<8; + zSig = estimateSqrt32( aExp, aSig ) + 2; + if ( ( zSig & 0x7F ) <= 5 ) { + if ( zSig < 2 ) { + zSig = 0x7FFFFFFF; + goto roundAndPack; + } + else { + aSig >>= aExp & 1; + mul32To64( zSig, zSig, &term0, &term1 ); + sub64( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits32) rem0 < 0 ) { + --zSig; + shortShift64Left( 0, zSig, 1, &term0, &term1 ); + term1 |= 1; + add64( rem0, rem1, term0, term1, &rem0, &rem1 ); + } + zSig |= ( ( rem0 | rem1 ) != 0 ); + } + } + shift32RightJamming( zSig, 1, &zSig ); + roundAndPack: + return roundAndPackFloat32( 0, zExp, zSig ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag __fastcall__ float32_eq( float32 a, float32 b ) +{ + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than or +| equal to the corresponding value `b', and 0 otherwise. The comparison is +| performed according to the IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag __fastcall__ float32_le( float32 a, float32 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag __fastcall__ float32_lt( float32 a, float32 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag __fastcall__ float32_eq_signaling( float32 a, float32 b ) +{ + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than or +| equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +| cause an exception. Otherwise, the comparison is performed according to the +| IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag __fastcall__ float32_le_quiet( float32 a, float32 b ) +{ + flag aSign, bSign; + /*int16 aExp, bExp;*/ + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. Otherwise, the comparison is performed according to the IEEE +| Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag __fastcall__ float32_lt_quiet( float32 a, float32 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the 32-bit two's complement integer format. The conversion is +| performed according to the IEEE Standard for Floating-Point Arithmetic--- +| which means in particular that the conversion is rounded according to the +| current rounding mode. If `a' is a NaN, the largest positive integer is +| returned. Otherwise, if the conversion overflows, the largest integer with +| the same sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int32 float64_to_int32( float64 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits32 aSig0, aSig1, absZ, aSigExtra; + int32 z; + int8 roundingMode; + + aSig1 = extractFloat64Frac1( a ); + aSig0 = extractFloat64Frac0( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + shiftCount = aExp - 0x413; + if ( 0 <= shiftCount ) { + if ( 0x41E < aExp ) { + if ( ( aExp == 0x7FF ) && ( aSig0 | aSig1 ) ) aSign = 0; + goto invalid; + } + shortShift64Left( + aSig0 | 0x00100000, aSig1, shiftCount, &absZ, &aSigExtra ); + if ( 0x80000000 < absZ ) goto invalid; + } + else { + aSig1 = ( aSig1 != 0 ); + if ( aExp < 0x3FE ) { + aSigExtra = aExp | aSig0 | aSig1; + absZ = 0; + } + else { + aSig0 |= 0x00100000; + aSigExtra = ( aSig0<<( shiftCount & 31 ) ) | aSig1; + absZ = aSig0>>( - shiftCount ); + } + } + roundingMode = float_rounding_mode; + if ( roundingMode == float_round_nearest_even ) { + if ( (sbits32) aSigExtra < 0 ) { + ++absZ; + if ( (bits32) ( aSigExtra<<1 ) == 0 ) absZ &= ~1; + } + z = aSign ? - absZ : absZ; + } + else { + aSigExtra = ( aSigExtra != 0 ); + if ( aSign ) { + z = - ( absZ + + ( ( roundingMode == float_round_down ) & aSigExtra ) ); + } + else { + z = absZ + ( ( roundingMode == float_round_up ) & aSigExtra ); + } + } + z = (sbits32) z; + if ( ( aSign ^ ( z < 0 ) ) && z ) { + invalid: + float_raise( float_flag_invalid ); + return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + } + if ( aSigExtra ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the 32-bit two's complement integer format. The conversion is +| performed according to the IEEE Standard for Floating-Point Arithmetic, +| except that the conversion is always rounded toward zero. If `a' is a NaN, +| the largest positive integer is returned. Otherwise, if the conversion +| overflows, the largest integer with the same sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int32 float64_to_int32_round_to_zero( float64 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits32 aSig0, aSig1, absZ, aSigExtra; + int32 z; + + aSig1 = extractFloat64Frac1( a ); + aSig0 = extractFloat64Frac0( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + shiftCount = aExp - 0x413; + if ( 0 <= shiftCount ) { + if ( 0x41E < aExp ) { + if ( ( aExp == 0x7FF ) && ( aSig0 | aSig1 ) ) aSign = 0; + goto invalid; + } + shortShift64Left( + aSig0 | 0x00100000, aSig1, shiftCount, &absZ, &aSigExtra ); + } + else { + if ( aExp < 0x3FF ) { + if ( aExp | aSig0 | aSig1 ) { + float_exception_flags |= float_flag_inexact; + } + return 0; + } + aSig0 |= 0x00100000; + aSigExtra = ( aSig0<<( shiftCount & 31 ) ) | aSig1; + absZ = aSig0>>( - shiftCount ); + } + z = aSign ? - absZ : absZ; + z = (sbits32) z; + if ( ( aSign ^ ( z < 0 ) ) && z ) { + invalid: + float_raise( float_flag_invalid ); + return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + } + if ( aSigExtra ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the single-precision floating-point format. The conversion is +| performed according to the IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float64_to_float32( float64 a ) +{ + flag aSign; + int16 aExp; + bits32 aSig0, aSig1, zSig; + bits32 allZero; + + aSig1 = extractFloat64Frac1( a ); + aSig0 = extractFloat64Frac0( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig0 | aSig1 ) { + return commonNaNToFloat32( float64ToCommonNaN( a ) ); + } + return packFloat32( aSign, 0xFF, 0 ); + } + shift64RightJamming( aSig0, aSig1, 22, &allZero, &zSig ); + if ( aExp ) zSig |= 0x40000000; + return roundAndPackFloat32( aSign, aExp - 0x381, zSig ); + +} + +/*---------------------------------------------------------------------------- +| Rounds the double-precision floating-point value `a' to an integer, +| and returns the result as a double-precision floating-point value. The +| operation is performed according to the IEEE Standard for Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_round_to_int( float64 a ) +{ + flag aSign; + int16 aExp; + bits32 lastBitMask, roundBitsMask; + int8 roundingMode; + float64 z; + + aExp = extractFloat64Exp( a ); + if ( 0x413 <= aExp ) { + if ( 0x433 <= aExp ) { + if ( ( aExp == 0x7FF ) + && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) ) { + return propagateFloat64NaN( a, a ); + } + return a; + } + lastBitMask = 1; + lastBitMask = ( lastBitMask<<( 0x432 - aExp ) )<<1; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = float_rounding_mode; + if ( roundingMode == float_round_nearest_even ) { + if ( lastBitMask ) { + add64( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low ); + if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; + } + else { + if ( (sbits32) z.low < 0 ) { + ++z.high; + if ( (bits32) ( z.low<<1 ) == 0 ) z.high &= ~1; + } + } + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat64Sign( z ) + ^ ( roundingMode == float_round_up ) ) { + add64( z.high, z.low, 0, roundBitsMask, &z.high, &z.low ); + } + } + z.low &= ~ roundBitsMask; + } + else { + if ( aExp <= 0x3FE ) { + if ( ( ( (bits32) ( a.high<<1 ) ) | a.low ) == 0 ) return a; + float_exception_flags |= float_flag_inexact; + aSign = extractFloat64Sign( a ); + switch ( float_rounding_mode ) { + case float_round_nearest_even: + if ( ( aExp == 0x3FE ) + && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) + ) { + return packFloat64( aSign, 0x3FF, 0, 0 ); + } + break; + case float_round_down: + return + aSign ? packFloat64( 1, 0x3FF, 0, 0 ) + : packFloat64( 0, 0, 0, 0 ); + case float_round_up: + return + aSign ? packFloat64( 1, 0, 0, 0 ) + : packFloat64( 0, 0x3FF, 0, 0 ); + } + return packFloat64( aSign, 0, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x413 - aExp; + roundBitsMask = lastBitMask - 1; + z.low = 0; + z.high = a.high; + roundingMode = float_rounding_mode; + if ( roundingMode == float_round_nearest_even ) { + z.high += lastBitMask>>1; + if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) { + z.high &= ~ lastBitMask; + } + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat64Sign( z ) + ^ ( roundingMode == float_round_up ) ) { + z.high |= ( a.low != 0 ); + z.high += roundBitsMask; + } + } + z.high &= ~ roundBitsMask; + } + if ( ( z.low != a.low ) || ( z.high != a.high ) ) { + float_exception_flags |= float_flag_inexact; + } + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the absolute values of the double-precision +| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated +| before being returned. `zSign' is ignored if the result is a NaN. The +| addition is performed according to the IEEE Standard for Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +static float64 addFloat64Sigs( float64 a, float64 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; + int16 expDiff; + + aSig1 = extractFloat64Frac1( a ); + aSig0 = extractFloat64Frac0( a ); + aExp = extractFloat64Exp( a ); + bSig1 = extractFloat64Frac1( b ); + bSig0 = extractFloat64Frac0( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) { + if ( aExp == 0x7FF ) { + if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig0 |= 0x00100000; + } + shift64ExtraRightJamming( + bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FF ) { + if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b ); + return packFloat64( zSign, 0x7FF, 0, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig0 |= 0x00100000; + } + shift64ExtraRightJamming( + aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 ); + zExp = bExp; + } + else { + if ( aExp == 0x7FF ) { + if ( aSig0 | aSig1 | bSig0 | bSig1 ) { + return propagateFloat64NaN( a, b ); + } + return a; + } + add64( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + if ( aExp == 0 ) return packFloat64( zSign, 0, zSig0, zSig1 ); + zSig2 = 0; + zSig0 |= 0x00200000; + zExp = aExp; + goto shiftRight1; + } + aSig0 |= 0x00100000; + add64( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + --zExp; + if ( zSig0 < 0x00200000 ) goto roundAndPack; + ++zExp; + shiftRight1: + shift64ExtraRightJamming( zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); + roundAndPack: + return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the absolute values of the double- +| precision floating-point values `a' and `b'. If `zSign' is 1, the +| difference is negated before being returned. `zSign' is ignored if the +| result is a NaN. The subtraction is performed according to the IEEE +| Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float64 subFloat64Sigs( float64 a, float64 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1; + int16 expDiff; + float64 z; + + aSig1 = extractFloat64Frac1( a ); + aSig0 = extractFloat64Frac0( a ); + aExp = extractFloat64Exp( a ); + bSig1 = extractFloat64Frac1( b ); + bSig0 = extractFloat64Frac0( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + shortShift64Left( aSig0, aSig1, 10, &aSig0, &aSig1 ); + shortShift64Left( bSig0, bSig1, 10, &bSig0, &bSig1 ); + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FF ) { + if ( aSig0 | aSig1 | bSig0 | bSig1 ) { + return propagateFloat64NaN( a, b ); + } + float_raise( float_flag_invalid ); + z.low = float64_default_nan_low; + z.high = float64_default_nan_high; + return z; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig0 < aSig0 ) goto aBigger; + if ( aSig0 < bSig0 ) goto bBigger; + if ( bSig1 < aSig1 ) goto aBigger; + if ( aSig1 < bSig1 ) goto bBigger; + return packFloat64( float_rounding_mode == float_round_down, 0, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FF ) { + if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b ); + return packFloat64( zSign ^ 1, 0x7FF, 0, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig0 |= 0x40000000; + } + shift64RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); + bSig0 |= 0x40000000; + bBigger: + sub64( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 ); + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FF ) { + if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig0 |= 0x40000000; + } + shift64RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 ); + aSig0 |= 0x40000000; + aBigger: + sub64( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat64( zSign, zExp - 10, zSig0, zSig1 ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the double-precision floating-point values +| `a' and `b'. The operation is performed according to the IEEE Standard for +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_add( float64 a, float64 b ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return addFloat64Sigs( a, b, aSign ); + } + else { + return subFloat64Sigs( a, b, aSign ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the double-precision floating-point values +| `a' and `b'. The operation is performed according to the IEEE Standard for +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_sub( float64 a, float64 b ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return subFloat64Sigs( a, b, aSign ); + } + else { + return addFloat64Sigs( a, b, aSign ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of multiplying the double-precision floating-point values +| `a' and `b'. The operation is performed according to the IEEE Standard for +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_mul( float64 a, float64 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3; + float64 z; + + aSig1 = extractFloat64Frac1( a ); + aSig0 = extractFloat64Frac0( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig1 = extractFloat64Frac1( b ); + bSig0 = extractFloat64Frac0( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( ( aSig0 | aSig1 ) + || ( ( bExp == 0x7FF ) && ( bSig0 | bSig1 ) ) ) { + return propagateFloat64NaN( a, b ); + } + if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid; + return packFloat64( zSign, 0x7FF, 0, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b ); + if ( ( aExp | aSig0 | aSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = float64_default_nan_low; + z.high = float64_default_nan_high; + return z; + } + return packFloat64( zSign, 0x7FF, 0, 0 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat64( zSign, 0, 0, 0 ); + normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) return packFloat64( zSign, 0, 0, 0 ); + normalizeFloat64Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + zExp = aExp + bExp - 0x400; + aSig0 |= 0x00100000; + shortShift64Left( bSig0, bSig1, 12, &bSig0, &bSig1 ); + mul64To128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 ); + add64( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 ); + zSig2 |= ( zSig3 != 0 ); + if ( 0x00200000 <= zSig0 ) { + shift64ExtraRightJamming( + zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); + ++zExp; + } + return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of dividing the double-precision floating-point value `a' +| by the corresponding value `b'. The operation is performed according to the +| IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_div( float64 a, float64 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; + bits32 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + float64 z; + + aSig1 = extractFloat64Frac1( a ); + aSig0 = extractFloat64Frac0( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig1 = extractFloat64Frac1( b ); + bSig0 = extractFloat64Frac0( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, b ); + if ( bExp == 0x7FF ) { + if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b ); + goto invalid; + } + return packFloat64( zSign, 0x7FF, 0, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b ); + return packFloat64( zSign, 0, 0, 0 ); + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) { + if ( ( aExp | aSig0 | aSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = float64_default_nan_low; + z.high = float64_default_nan_high; + return z; + } + float_raise( float_flag_divbyzero ); + return packFloat64( zSign, 0x7FF, 0, 0 ); + } + normalizeFloat64Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat64( zSign, 0, 0, 0 ); + normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + zExp = aExp - bExp + 0x3FD; + shortShift64Left( aSig0 | 0x00100000, aSig1, 11, &aSig0, &aSig1 ); + shortShift64Left( bSig0 | 0x00100000, bSig1, 11, &bSig0, &bSig1 ); + if ( le64( bSig0, bSig1, aSig0, aSig1 ) ) { + shift64Right( aSig0, aSig1, 1, &aSig0, &aSig1 ); + ++zExp; + } + zSig0 = estimateDiv64To32( aSig0, aSig1, bSig0 ); + mul64By32To96( bSig0, bSig1, zSig0, &term0, &term1, &term2 ); + sub96( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 ); + while ( (sbits32) rem0 < 0 ) { + --zSig0; + add96( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 ); + } + zSig1 = estimateDiv64To32( rem1, rem2, bSig0 ); + if ( ( zSig1 & 0x3FF ) <= 4 ) { + mul64By32To96( bSig0, bSig1, zSig1, &term1, &term2, &term3 ); + sub96( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits32) rem1 < 0 ) { + --zSig1; + add96( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + shift64ExtraRightJamming( zSig0, zSig1, 0, 11, &zSig0, &zSig1, &zSig2 ); + return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 ); + +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the double-precision floating-point value `a' +| with respect to the corresponding value `b'. The operation is performed +| according to the IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_rem( float64 a, float64 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits32 aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2; + bits32 allZero, alternateASig0, alternateASig1, sigMean1; + sbits32 sigMean0; + float64 z; + + aSig1 = extractFloat64Frac1( a ); + aSig0 = extractFloat64Frac0( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig1 = extractFloat64Frac1( b ); + bSig0 = extractFloat64Frac0( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + if ( aExp == 0x7FF ) { + if ( ( aSig0 | aSig1 ) + || ( ( bExp == 0x7FF ) && ( bSig0 | bSig1 ) ) ) { + return propagateFloat64NaN( a, b ); + } + goto invalid; + } + if ( bExp == 0x7FF ) { + if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = float64_default_nan_low; + z.high = float64_default_nan_high; + return z; + } + normalizeFloat64Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return a; + normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + expDiff = aExp - bExp; + if ( expDiff < -1 ) return a; + shortShift64Left( + aSig0 | 0x00100000, aSig1, 11 - ( expDiff < 0 ), &aSig0, &aSig1 ); + shortShift64Left( bSig0 | 0x00100000, bSig1, 11, &bSig0, &bSig1 ); + q = le64( bSig0, bSig1, aSig0, aSig1 ); + if ( q ) sub64( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); + expDiff -= 32; + while ( 0 < expDiff ) { + q = estimateDiv64To32( aSig0, aSig1, bSig0 ); + q = ( 4 < q ) ? q - 4 : 0; + mul64By32To96( bSig0, bSig1, q, &term0, &term1, &term2 ); + shortShift96Left( term0, term1, term2, 29, &term1, &term2, &allZero ); + shortShift64Left( aSig0, aSig1, 29, &aSig0, &allZero ); + sub64( aSig0, 0, term1, term2, &aSig0, &aSig1 ); + expDiff -= 29; + } + if ( -32 < expDiff ) { + q = estimateDiv64To32( aSig0, aSig1, bSig0 ); + q = ( 4 < q ) ? q - 4 : 0; + q >>= - expDiff; + shift64Right( bSig0, bSig1, 8, &bSig0, &bSig1 ); + expDiff += 24; + if ( expDiff < 0 ) { + shift64Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); + } + else { + shortShift64Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 ); + } + mul64By32To96( bSig0, bSig1, q, &term0, &term1, &term2 ); + sub64( aSig0, aSig1, term1, term2, &aSig0, &aSig1 ); + } + else { + shift64Right( aSig0, aSig1, 8, &aSig0, &aSig1 ); + shift64Right( bSig0, bSig1, 8, &bSig0, &bSig1 ); + } + do { + alternateASig0 = aSig0; + alternateASig1 = aSig1; + ++q; + sub64( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); + } while ( 0 <= (sbits32) aSig0 ); + add64( + aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 ); + if ( ( sigMean0 < 0 ) + || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) { + aSig0 = alternateASig0; + aSig1 = alternateASig1; + } + zSign = ( (sbits32) aSig0 < 0 ); + if ( zSign ) sub64( 0, 0, aSig0, aSig1, &aSig0, &aSig1 ); + return + normalizeRoundAndPackFloat64( aSign ^ zSign, bExp - 4, aSig0, aSig1 ); + +} + +/*---------------------------------------------------------------------------- +| Returns the square root of the double-precision floating-point value `a'. +| The operation is performed according to the IEEE Standard for Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_sqrt( float64 a ) +{ + flag aSign; + int16 aExp, zExp; + bits32 aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0; + bits32 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + float64 z; + + aSig1 = extractFloat64Frac1( a ); + aSig0 = extractFloat64Frac0( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, a ); + if ( ! aSign ) return a; + goto invalid; + } + if ( aSign ) { + if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a; + invalid: + float_raise( float_flag_invalid ); + z.low = float64_default_nan_low; + z.high = float64_default_nan_high; + return z; + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat64( 0, 0, 0, 0 ); + normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE; + aSig0 |= 0x00100000; + shortShift64Left( aSig0, aSig1, 11, &term0, &term1 ); + zSig0 = ( estimateSqrt32( aExp, term0 )>>1 ) + 1; + if ( zSig0 == 0 ) zSig0 = 0x7FFFFFFF; + doubleZSig0 = zSig0 + zSig0; + shortShift64Left( aSig0, aSig1, 9 - ( aExp & 1 ), &aSig0, &aSig1 ); + mul32To64( zSig0, zSig0, &term0, &term1 ); + sub64( aSig0, aSig1, term0, term1, &rem0, &rem1 ); + while ( (sbits32) rem0 < 0 ) { + --zSig0; + doubleZSig0 -= 2; + add64( rem0, rem1, 0, doubleZSig0 | 1, &rem0, &rem1 ); + } + zSig1 = estimateDiv64To32( rem1, 0, doubleZSig0 ); + if ( ( zSig1 & 0x1FF ) <= 5 ) { + if ( zSig1 == 0 ) zSig1 = 1; + mul32To64( doubleZSig0, zSig1, &term1, &term2 ); + sub64( rem1, 0, term1, term2, &rem1, &rem2 ); + mul32To64( zSig1, zSig1, &term2, &term3 ); + sub96( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits32) rem1 < 0 ) { + --zSig1; + shortShift64Left( 0, zSig1, 1, &term2, &term3 ); + term3 |= 1; + term2 |= doubleZSig0; + add96( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + shift64ExtraRightJamming( zSig0, zSig1, 0, 10, &zSig0, &zSig1, &zSig2 ); + return roundAndPackFloat64( 0, zExp, zSig0, zSig1, zSig2 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float64_eq( float64 a, float64 b ) +{ + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) + && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) + && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits32) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than +| or equal to the corresponding value `b', and 0 otherwise. The comparison is +| performed according to the IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float64_le( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) + && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) + && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits32) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le64( b.high, b.low, a.high, a.low ) + : le64( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float64_lt( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) + && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) + && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits32) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt64( b.high, b.low, a.high, a.low ) + : lt64( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float64_eq_signaling( float64 a, float64 b ) +{ + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) + && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) + && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits32) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than or +| equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +| cause an exception. Otherwise, the comparison is performed according to the +| IEEE Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float64_le_quiet( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) + && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) + && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits32) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le64( b.high, b.low, a.high, a.low ) + : le64( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. Otherwise, the comparison is performed according to the IEEE +| Standard for Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float64_lt_quiet( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) + && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) + && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits32) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt64( b.high, b.low, a.high, a.low ) + : lt64( a.high, a.low, b.high, b.low ); + +} +#endif diff --git a/libsrc/float/softfloat/softfloat.h b/libsrc/float/softfloat/softfloat.h new file mode 100644 index 000000000..b71de03ff --- /dev/null +++ b/libsrc/float/softfloat/softfloat.h @@ -0,0 +1,134 @@ + +#ifndef SOFTFLOAT_H_ +#define SOFTFLOAT_H_ + +/*============================================================================ + +This C header file template is part of the Berkeley SoftFloat IEEE Floating- +Point Arithmetic Package, Release 2c, by John R. Hauser. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TOLERATE ALL LOSSES, COSTS, OR OTHER +PROBLEMS THEY INCUR DUE TO THE SOFTWARE WITHOUT RECOMPENSE FROM JOHN HAUSER OR +THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE, AND WHO FURTHERMORE EFFECTIVELY +INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE +(possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR OTHER +PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE, OR +INCURRED BY ANYONE DUE TO A DERIVATIVE WORK THEY CREATE USING ANY PART OF THE +SOFTWARE. + +Derivative works require also that (1) the source code for the derivative work +includes prominent notice that the work is derivative, and (2) the source code +includes prominent notice of these three paragraphs for those parts of this +code that are retained. + +=============================================================================*/ + +/*---------------------------------------------------------------------------- +| Software IEEE floating-point types. +*----------------------------------------------------------------------------*/ +typedef unsigned long float32; +typedef struct { + unsigned long high, low; +} float64; + +/*---------------------------------------------------------------------------- +| Software IEEE floating-point underflow tininess-detection mode. +*----------------------------------------------------------------------------*/ +extern signed char float_detect_tininess; +enum { + float_tininess_after_rounding = 0, + float_tininess_before_rounding = 1 +}; + +/*---------------------------------------------------------------------------- +| Software IEEE floating-point rounding mode. +*----------------------------------------------------------------------------*/ +extern signed char float_rounding_mode; +enum { + float_round_nearest_even = 0, + float_round_to_zero = 1, + float_round_down = 2, + float_round_up = 3 +}; + +/*---------------------------------------------------------------------------- +| Software IEEE floating-point exception flags. +*----------------------------------------------------------------------------*/ +extern signed char float_exception_flags; +enum { + float_flag_inexact = 1, + float_flag_underflow = 2, + float_flag_overflow = 4, + float_flag_divbyzero = 8, + float_flag_invalid = 16 +}; + +/*---------------------------------------------------------------------------- +| Routine to raise any or all of the software IEEE floating-point exception +| flags. +*----------------------------------------------------------------------------*/ +void float_raise( signed char ); + +/*---------------------------------------------------------------------------- +| Software IEEE integer-to-floating-point conversion routines. +*----------------------------------------------------------------------------*/ +float32 int32_to_float32( int32 ); +float64 int32_to_float64( int32 ); + +/*---------------------------------------------------------------------------- +| Software IEEE single-precision conversion routines. +*----------------------------------------------------------------------------*/ +int32 float32_to_int32( float32 ); +int32 float32_to_int32_round_to_zero( float32 ); +float64 float32_to_float64( float32 ); + +/*---------------------------------------------------------------------------- +| Software IEEE single-precision operations. +*----------------------------------------------------------------------------*/ +float32 __fastcall__ float32_round_to_int( float32 ); +float32 __fastcall__ float32_add( float32, float32 ); +float32 __fastcall__ float32_sub( float32, float32 ); +float32 __fastcall__ float32_rsub( float32, float32 ); +float32 __fastcall__ float32_mul( float32, float32 ); +float32 __fastcall__ float32_div( float32, float32 ); +float32 __fastcall__ float32_rem( float32, float32 ); +float32 __fastcall__ float32_sqrt( float32 ); +unsigned char __fastcall__ float32_eq( float32, float32 ); +unsigned char __fastcall__ float32_le( float32, float32 ); +unsigned char __fastcall__ float32_lt( float32, float32 ); +unsigned char __fastcall__ float32_eq_signaling( float32, float32 ); +unsigned char __fastcall__ float32_le_quiet( float32, float32 ); +unsigned char __fastcall__ float32_lt_quiet( float32, float32 ); +unsigned char __fastcall__ float32_is_signaling_nan( float32 ); + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Software IEEE double-precision conversion routines. +*----------------------------------------------------------------------------*/ +signed short float64_to_int32( float64 ); +signed short float64_to_int32_round_to_zero( float64 ); +float32 float64_to_float32( float64 ); + +/*---------------------------------------------------------------------------- +| Software IEEE double-precision operations. +*----------------------------------------------------------------------------*/ +float64 float64_round_to_int( float64 ); +float64 float64_add( float64, float64 ); +float64 float64_sub( float64, float64 ); +float64 float64_mul( float64, float64 ); +float64 float64_div( float64, float64 ); +float64 float64_rem( float64, float64 ); +float64 float64_sqrt( float64 ); +unsigned char float64_eq( float64, float64 ); +unsigned char float64_le( float64, float64 ); +unsigned char float64_lt( float64, float64 ); +unsigned char float64_eq_signaling( float64, float64 ); +unsigned char float64_le_quiet( float64, float64 ); +unsigned char float64_lt_quiet( float64, float64 ); +unsigned char float64_is_signaling_nan( float64 ); +#endif + +#endif /* SOFTFLOAT_H_ */ diff --git a/libsrc/float/softfloat/softloat-ftostr.c b/libsrc/float/softfloat/softloat-ftostr.c new file mode 100644 index 000000000..2479005e3 --- /dev/null +++ b/libsrc/float/softfloat/softloat-ftostr.c @@ -0,0 +1,98 @@ + +#include +#include + +//#define DEBUG_VALUE + +// This is really a terrible function that should get completely rewritten and +// tested by someone who knows what he is doing =P +char *_ftostr(char *buffer, float f) { + signed long intpart; + float fracpart; + float f1, f2; + signed long n0; + int is_negative; + unsigned long raw_value = *((unsigned long*)(&f)); + + is_negative = (raw_value & 0x80000000) ? 1 : 0; // very hacky indeed + + if (!is_negative) { + intpart = (signed long)(f); + } else { + intpart = (signed long)(f); + intpart = -intpart; + } + + f2 = intpart; +#if 0 + if (!is_negative) { + if (f2 > f) { + if (intpart > 0) { + --intpart; + } + } + } else { + if (f2 > f) { + if (intpart > 0) { + --intpart; + } + } +// ++intpart; + } + + if (!is_negative) { + if (intpart < 0) { + intpart *= -1; + } + } else { + if (intpart < 0) { + intpart *= -1; + } + } +#endif + f2 = intpart; + if (!is_negative) { + fracpart = f - f2; + } else { + fracpart = (-f) - f2; + } + + f1 = 10000.0f; + + f1 = f1 * fracpart; + + n0 = (signed long)f1; +#if 0 + // caution: make sure fracpart can never be negative + if (n0 < 0) { + n0 *= -1; + } +#endif +// printf("n0:%ld\n",n0); +#ifdef DEBUG_VALUE + if (n0 >= 1000) { + sprintf(buffer, "<0x%08lx:%s%ld.%ld>", raw_value, is_negative ? "-" : "", intpart, n0); + } else if (n0 >= 100) { + sprintf(buffer, "<0x%08lx:%s%ld.0%ld>", raw_value, is_negative ? "-" : "", intpart, n0); + } else if (n0 >= 10) { + sprintf(buffer, "<0x%08lx:%s%ld.00%ld>", raw_value, is_negative ? "-" : "", intpart, n0); + } else if (n0 >= 1) { + sprintf(buffer, "<0x%08lx:%s%ld.000%ld>", raw_value, is_negative ? "-" : "", intpart, n0); + } else { + sprintf(buffer, "<0x%08lx:%s%ld.0000>", raw_value, is_negative ? "-" : "", intpart); + } +#else + if (n0 >= 1000) { + sprintf(buffer, "%s%ld.%ld", is_negative ? "-" : "", intpart, n0); + } else if (n0 >= 100) { + sprintf(buffer, "%s%ld.0%ld", is_negative ? "-" : "", intpart, n0); + } else if (n0 >= 10) { + sprintf(buffer, "%s%ld.00%ld", is_negative ? "-" : "", intpart, n0); + } else if (n0 >= 1) { + sprintf(buffer, "%s%ld.000%ld", is_negative ? "-" : "", intpart, n0); + } else { + sprintf(buffer, "%s%ld.0000", is_negative ? "-" : "", intpart); + } +#endif + return &buffer[0]; +} diff --git a/libsrc/float/softfloat/source.txt b/libsrc/float/softfloat/source.txt new file mode 100644 index 000000000..ed14355a7 --- /dev/null +++ b/libsrc/float/softfloat/source.txt @@ -0,0 +1,400 @@ + +Berkeley SoftFloat Release 2c Source Documentation + +John R. Hauser +2015 January 30 + + +---------------------------------------------------------------------------- +Introduction + +Berkeley SoftFloat is a software implementation of binary floating-point +that conforms to the IEEE Standard for Floating-Point Arithmetic. +Release 2c of SoftFloat can support four floating-point formats: 32-bit +single-precision, 64-bit double-precision, 80-bit double-extended-precision, +and 128-bit quadruple-precision. All operations required by the older 1985 +version of the IEEE Standard are implemented, except for conversions to and +from decimal. SoftFloat is distributed in the form of C source code, so a +C compiler is needed to compile the code. Support for the 80-bit double- +extended-precision and 128-bit quadruple-precision formats is dependent on +the C compiler implementing a 64-bit integer type. + +This document gives information needed for compiling and/or porting this +SoftFloat release. + +The source code for SoftFloat is intended to be relatively machine- +independent and should be compilable using most any ISO/ANSI C compiler. At +the time of this writing, SoftFloat has been successfully compiled with the +GNU C Compiler (`gcc') for several platforms. + + +---------------------------------------------------------------------------- +Limitations + +As supplied, SoftFloat requires an ISO/ANSI-style C compiler. No attempt +has been made to accomodate compilers that are not ISO-conformant. Older +"K&R-style" compilers are not adequate for compiling SoftFloat. All testing +I have done so far has been with the GNU C Compiler. Compilation with other +compilers should be possible but has not been tested by me. + +The SoftFloat sources assume that source code file names can be longer than +8 characters. In order to compile under an MS-DOS-type system, many of the +source files will need to be renamed, and the source and Makefiles edited +appropriately. Once compiled, the SoftFloat binary does not depend on the +existence of long file names. + +The underlying machine is assumed to be binary with a word size that is a +power of 2. Bytes are 8 bits. Arithmetic on signed integers must modularly +wrap around on overflows (as is already required for unsigned integers +in C). + +Support for the 80-bit double-extended-precision and 128-bit quadruple- +precision formats depends on the C compiler implementing a 64-bit integer +type. If the largest integer type supported by the C compiler is 32 bits, +SoftFloat is limited to the 32-bit single-precision and 64-bit double- +precision formats. + + +---------------------------------------------------------------------------- +Contents + + Introduction + Limitations + Contents + Legal Notice + SoftFloat Source Directory Structure + SoftFloat Source Files + processors/*.h + softfloat/bits*/*/softfloat.h + softfloat/bits*/*/milieu.h + softfloat/bits*/*/softfloat-specialize + softfloat/bits*/softfloat-macros + softfloat/bits*/softfloat.c + Steps to Creating a `softfloat.o' + Making `softfloat.o' a Library + Testing SoftFloat + Timing SoftFloat + Compiler Options and Efficiency + Processor-Specific Optimization of `softfloat.c' Using `softfloat-macros' + Contact Information + + + +---------------------------------------------------------------------------- +Legal Notice + +SoftFloat was written by John R. Hauser. Release 2c of SoftFloat was made +possible in part by the International Computer Science Institute, located +at Suite 600, 1947 Center Street, Berkeley, California 94704. Funding +was partially provided by the National Science Foundation under grant +MIP-9311980. The original version of this code was written as part of a +project to build a fixed-point vector processor in collaboration with the +University of California at Berkeley, overseen by Profs. Nelson Morgan and +John Wawrzynek. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TOLERATE ALL LOSSES, COSTS, OR +OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE WITHOUT RECOMPENSE FROM JOHN +HAUSER OR THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE, +OR INCURRED BY ANYONE DUE TO A DERIVATIVE WORK THEY CREATE USING ANY PART OF +THE SOFTWARE. + +The following are expressly permitted, even for commercial purposes: +(1) distribution of SoftFloat in whole or in part, as long as this and +other legal notices remain and are prominent, and provided also that, for a +partial distribution, prominent notice is given that it is a subset of the +original; and +(2) inclusion or use of SoftFloat in whole or in part in a derivative +work, provided that the use restrictions above are met and the minimal +documentation requirements stated in the source code are satisfied. + + +---------------------------------------------------------------------------- +SoftFloat Source Directory Structure + +Because SoftFloat is targeted to multiple platforms, its source code +is slightly scattered between target-specific and target-independent +directories and files. The directory structure is as follows: + + processors + softfloat + bits64 + templates + 386-Win32-GCC + SPARC-Solaris-GCC + bits32 + templates + 386-Win32-GCC + SPARC-Solaris-GCC + +The two topmost directories and their contents are: + + softfloat - Most of the source code needed for SoftFloat. + processors - Target-specific header files that are not specific to + SoftFloat. + +The `softfloat' directory is further split into two parts: + + bits64 - SoftFloat implementation using 64-bit integers. + bits32 - SoftFloat implementation using only 32-bit integers. + +Within these directories are subdirectories for each of the targeted +platforms. The SoftFloat source code is distributed with targets +`386-Win32-GCC' and `SPARC-Solaris-GCC' (and perhaps others) already +prepared for both the 32-bit and 64-bit implementations. Source files +that are not within these target-specific subdirectories are intended to be +target-independent. + +The naming convention used for the target-specific directories is +`--'. The names of the supplied +target directories should be interpreted as follows: + + : + 386 - Intel 386-compatible processor. + SPARC - SPARC processor (as used by Sun computers). + : + Win32 - Microsoft Win32 executable. + Solaris - Sun Solaris executable. + : + GCC - GNU C Compiler. + +You do not need to maintain this convention if you do not want to. + +Alongside the supplied target-specific directories is a `templates' +directory containing a set of "generic" target-specific source files. A +new target directory can be created by copying the `templates' directory and +editing the files inside. (Complete instructions for porting SoftFloat to +a new target are in the section _Steps to Creating a `softfloat.o'_.) Note +that the `templates' directory will not work as a target directory without +some editing. To avoid confusion, it would be wise to refrain from editing +the files inside `templates' directly. + + +---------------------------------------------------------------------------- +SoftFloat Source Files + +The purpose of each source file is described below. In the following, +the `*' symbol is used in place of the name of a specific target, such as +`386-Win32-GCC' or `SPARC-Solaris-GCC', or in place of some other text, as +in `bits*' for either `bits32' or `bits64'. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +processors/*.h + +The target-specific `processors' header file defines integer types +of various sizes, and also defines certain C preprocessor macros that +characterize the target. The two examples supplied are `386-GCC.h' and +`SPARC-GCC.h'. The naming convention used for processor header files is +`-.h'. + +If 64-bit integers are supported by the compiler, the macro name `BITS64' +should be defined here along with the corresponding 64-bit integer +types. In addition, the function-like macro `LIT64' must be defined for +constructing 64-bit integer literals (constants). The `LIT64' macro is used +consistently in the SoftFloat code to annotate 64-bit literals. + +If `BITS64' is not defined, only the 32-bit version of SoftFloat can be +compiled. If `BITS64' _is_ defined, either can be compiled. + +If an inlining attribute (such as an `inline' keyword) is provided by the +compiler, the macro `INLINE' should be defined to the appropriate keyword. +If not, `INLINE' can be set to the keyword `static'. The `INLINE' macro +appears in the SoftFloat source code before every function that should +be inlined by the compiler. SoftFloat depends on inlining to obtain +good speed. Even if inlining cannot be forced with a language keyword, +the compiler may still be able to perform inlining on its own as an +optimization. If a command-line option is needed to convince the compiler +to perform this optimization, this should be assured in the Makefile. (See +the section _Compiler Options and Efficiency_ below.) + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +softfloat/bits*/*/softfloat.h + +The target-specific `softfloat.h' header file defines the SoftFloat +interface as seen by clients. + +Unlike the actual function definitions in `softfloat.c', the declarations +in `softfloat.h' do not use any of the types defined by the `processors' +header file. This is done so that clients will not have to include the +`processors' header file in order to use SoftFloat. Nevertheless, the +target-specific declarations in `softfloat.h' must match what `softfloat.c' +expects. For example, if `int32' is defined as `int' in the `processors' +header file, then in `softfloat.h' the output of `float32_to_int32' should +be stated as `int', although in `softfloat.c' it is given in target- +independent form as `int32'. + +For the `bits64' implementation of SoftFloat, the macro names `FLOATX80' +and `FLOAT128' must be defined in order for the 80-bit double-extended- +precision and 128-bit quadruple-precision formats to be enabled in the +code. Conversely, either or both of these larger formats can be disabled by +simply removing the `#define' of the respective macro. When a format is not +enabled, none of the functions that either input or output the format are +defined, and no space is taken up in `softfloat.o' by such functions. There +is no provision for disabling the usual 32-bit single-precision and 64-bit +double-precision formats. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +softfloat/bits*/*/milieu.h + +The target-specific `milieu.h' header file provides declarations that are +needed to compile SoftFloat. In addition, deviations from ISO/ANSI C by +the compiler (such as names not properly declared in system header files) +are corrected in this header if possible. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +softfloat/bits*/*/softfloat-specialize + +This target-specific C source fragment defines: + +-- whether tininess for underflow is detected before or after rounding by + default; +-- what (if anything) special happens when exceptions are raised; +-- how signaling NaNs are distinguished from quiet NaNs; +-- the default generated quiet NaNs; and +-- how NaNs are propagated from function inputs to output. + +These details are not decided by the IEEE Standard. This fragment is +included verbatim within `softfloat.c' when SoftFloat is compiled. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +softfloat/bits*/softfloat-macros + +This target-independent C source fragment defines a number of arithmetic +functions used as primitives within the `softfloat.c' source. Most of +the functions defined here are intended to be inlined for efficiency. +This fragment is included verbatim within `softfloat.c' when SoftFloat is +compiled. + +Target-specific variations on this file are possible. See the section +_Processor-Specific Optimization of `softfloat.c' Using `softfloat-macros'_ +below. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +softfloat/bits*/softfloat.c + +The target-independent `softfloat.c' source file contains the body of the +SoftFloat implementation. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +The inclusion of the files above within each other (using `#include') can be +shown graphically as follows: + + softfloat/bits*/softfloat.c + softfloat/bits*/*/milieu.h + processors/*.h + softfloat/bits*/*/softfloat.h + softfloat/bits*/*/softfloat-specialize + softfloat/bits*/softfloat-macros + +Note in particular that `softfloat.c' does not include the `processors' +header file directly. Rather, `softfloat.c' includes the target-specific +`milieu.h' header file, which in turn includes the appropriate processor +header file. + + +---------------------------------------------------------------------------- +Steps to Creating a `softfloat.o' + +Porting and/or compiling SoftFloat involves the following steps: + +1. If one does not already exist, create an appropriate `.h' file in the + `processors' directory. + +2. If `BITS64' is defined in the `processors' header file, choose whether + to compile the 32-bit or 64-bit implementation of SoftFloat. If + `BITS64' is not defined, your only choice is the 32-bit implementation. + The remaining steps occur within either the `bits32' or `bits64' + subdirectories. + +3. If one does not already exist, create an appropriate target-specific + subdirectory by copying the given `templates' directory. + +4. In the target-specific subdirectory, edit the files `softfloat-specialize' + and `softfloat.h' to define the desired exception handling functions + and mode control values. In the `softfloat.h' header file, ensure also + that all declarations give the proper target-specific type (such as + `int' or `long') corresponding to the target-independent type used in + `softfloat.c' (such as `int32'). None of the type names declared in the + `processors' header file should appear in `softfloat.h'. + +5. In the target-specific subdirectory, edit the files `milieu.h' and + `Makefile' to reflect the current environment. + +6. In the target-specific subdirectory, execute `make'. + +For the targets that are supplied, if the expected compiler is available +(usually `gcc'), it should only be necessary to execute `make' in the +target-specific subdirectory. + + +---------------------------------------------------------------------------- +Making `softfloat.o' a Library + +SoftFloat is not made into a software library by the supplied Makefile. +If desired, `softfloat.o' can easily be put into its own library (typically +`softfloat.a' or `libsoftfloat.a') using the usual system tool (in UNIX, +`ar'). + + +---------------------------------------------------------------------------- +Testing SoftFloat + +SoftFloat can be tested using the `testsoftfloat' program by the same +author. The `testsoftfloat' program is part of the TestFloat package +available at the Web page `http://www.jhauser.us/arithmetic/TestFloat.html'. + + +---------------------------------------------------------------------------- +Timing SoftFloat + +A program called `timesoftfloat' for timing the SoftFloat functions is +included with the SoftFloat source code. Compiling `timesoftfloat' should +pose no difficulties once `softfloat.o' exists. The supplied Makefile +will create a `timesoftfloat' executable by default after generating +`softfloat.o'. See `timesoftfloat.txt' for documentation about using +`timesoftfloat'. + + +---------------------------------------------------------------------------- +Compiler Options and Efficiency + +In order to get good speed with SoftFloat, it is important that the compiler +inline the routines that have been marked `INLINE' in the code. Even if +inlining cannot be forced by an appropriate definition of the `INLINE' +macro, the compiler may still be able to perform inlining on its own as +an optimization. In that case, the Makefile should be edited to give the +compiler whatever option is required to cause it to inline small functions. + + +---------------------------------------------------------------------------- +Processor-Specific Optimization of `softfloat.c' Using `softfloat-macros' + +The `softfloat-macros' source fragment defines arithmetic functions used +as primitives by `softfloat.c'. This file has been written in a target- +independent form. For a given target, it may be possible to improve on +these functions using target-specific and/or non-ISO-C features (such +as `asm' statements). For example, one of the "macro" functions takes +two word-size integers and returns their full product in two words. +This operation can be done directly in hardware on many processors; but +because it is not available through standard C, the function defined in +`softfloat-macros' uses four multiplications to achieve the same result. + +To address these shortcomings, a customized version of `softfloat-macros' +can be created in any of the target-specific subdirectories. A simple +modification to the target's Makefile should be sufficient to ensure that +the custom version is used instead of the generic one. + + +---------------------------------------------------------------------------- +Contact Information + +At the time of this writing, the most up-to-date information about SoftFloat +and the latest release can be found at the Web page `http://www.jhauser.us/ +arithmetic/SoftFloat.html'. + diff --git a/libsrc/float/softfloat/specialize.h b/libsrc/float/softfloat/specialize.h new file mode 100644 index 000000000..37633796c --- /dev/null +++ b/libsrc/float/softfloat/specialize.h @@ -0,0 +1,241 @@ + +/*============================================================================ + +This C source fragment is part of the Berkeley SoftFloat IEEE Floating-Point +Arithmetic Package, Release 2c, by John R. Hauser. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TOLERATE ALL LOSSES, COSTS, OR OTHER +PROBLEMS THEY INCUR DUE TO THE SOFTWARE WITHOUT RECOMPENSE FROM JOHN HAUSER OR +THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE, AND WHO FURTHERMORE EFFECTIVELY +INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE +(possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR OTHER +PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE, OR +INCURRED BY ANYONE DUE TO A DERIVATIVE WORK THEY CREATE USING ANY PART OF THE +SOFTWARE. + +Derivative works require also that (1) the source code for the derivative work +includes prominent notice that the work is derivative, and (2) the source code +includes prominent notice of these three paragraphs for those parts of this +code that are retained. + +=============================================================================*/ + +/*---------------------------------------------------------------------------- +| Underflow tininess-detection mode, statically initialized to default value. +| (The declaration in `softfloat.h' must match the `int8' type here.) +*----------------------------------------------------------------------------*/ +int8 float_detect_tininess = float_tininess_after_rounding; + +/*---------------------------------------------------------------------------- +| Raises the exceptions specified by `flags'. Floating-point traps can be +| defined here if desired. It is currently not possible for such a trap +| to substitute a result value. If traps are not implemented, this routine +| should be simply `float_exception_flags |= flags;'. +*----------------------------------------------------------------------------*/ + +void float_raise( int8 flags ) +{ + + float_exception_flags |= flags; + +} + +/*---------------------------------------------------------------------------- +| Internal canonical NaN format. +*----------------------------------------------------------------------------*/ +typedef struct { + flag sign; + bits32 high, low; +} commonNaNT; + +/*---------------------------------------------------------------------------- +| The pattern for a default generated single-precision NaN. +*----------------------------------------------------------------------------*/ +enum { + float32_default_nan = 0xFFFFFFFF +}; + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is a NaN; +| otherwise returns 0. +*----------------------------------------------------------------------------*/ + +flag float32_is_nan( float32 a ) +{ + + return ( 0xFF000000 < (bits32) ( a<<1 ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is a signaling +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +flag float32_is_signaling_nan( float32 a ) +{ + + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); + +} + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point NaN +| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +| exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT *float32ToCommonNaN( float32 a ) +{ + static commonNaNT z; + + if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a>>31; + z.low = 0; + z.high = a<<9; + return &z; +} +#endif + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the single- +| precision floating-point format. +*----------------------------------------------------------------------------*/ + +static float32 commonNaNToFloat32( commonNaNT *a ) +{ + + return ( ( (bits32) a->sign )<<31 ) | 0x7FC00000 | ( a->high>>9 ); + +} +#endif + +/*---------------------------------------------------------------------------- +| Takes two single-precision floating-point values `a' and `b', one of which +| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +| signaling NaN, the invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static float32 propagateFloat32NaN( float32 a, float32 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = float32_is_nan( a ); + aIsSignalingNaN = float32_is_signaling_nan( a ); + bIsNaN = float32_is_nan( b ); + bIsSignalingNaN = float32_is_signaling_nan( b ); + a |= 0x00400000; + b |= 0x00400000; + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +#ifdef DOUBLES +/*---------------------------------------------------------------------------- +| The pattern for a default generated double-precision NaN. The `high' and +| `low' values hold the most- and least-significant bits, respectively. +*----------------------------------------------------------------------------*/ +enum { + float64_default_nan_high = 0xFFFFFFFF, + float64_default_nan_low = 0xFFFFFFFF +}; + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is a NaN; +| otherwise returns 0. +*----------------------------------------------------------------------------*/ + +flag float64_is_nan( float64 a ) +{ + + return + ( 0xFFE00000 <= (bits32) ( a.high<<1 ) ) + && ( a.low || ( a.high & 0x000FFFFF ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is a signaling +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +flag float64_is_signaling_nan( float64 a ) +{ + + return + ( ( ( a.high>>19 ) & 0xFFF ) == 0xFFE ) + && ( a.low || ( a.high & 0x0007FFFF ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point NaN +| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +| exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT float64ToCommonNaN( float64 a ) +{ + commonNaNT z; + + if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a.high>>31; + shortShift64Left( a.high, a.low, 12, &z.high, &z.low ); + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the double- +| precision floating-point format. +*----------------------------------------------------------------------------*/ + +static float64 commonNaNToFloat64( commonNaNT a ) +{ + float64 z; + + shift64Right( a.high, a.low, 12, &z.high, &z.low ); + z.high |= ( ( (bits32) a.sign )<<31 ) | 0x7FF80000; + return z; + +} + +/*---------------------------------------------------------------------------- +| Takes two double-precision floating-point values `a' and `b', one of which +| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +| signaling NaN, the invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static float64 propagateFloat64NaN( float64 a, float64 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = float64_is_nan( a ); + aIsSignalingNaN = float64_is_signaling_nan( a ); + bIsNaN = float64_is_nan( b ); + bIsSignalingNaN = float64_is_signaling_nan( b ); + a.high |= 0x00080000; + b.high |= 0x00080000; + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +#endif + diff --git a/libsrc/float/softmath/readme.txt b/libsrc/float/softmath/readme.txt new file mode 100644 index 000000000..d0d849cb4 --- /dev/null +++ b/libsrc/float/softmath/readme.txt @@ -0,0 +1,4 @@ + +This is a collection of various math related functions found in math.h. All +functions are single precision (only), and are rather selected for their +compactness than speed. diff --git a/libsrc/float/softmath/softmath-atanf.c b/libsrc/float/softmath/softmath-atanf.c new file mode 100644 index 000000000..ca24e3c69 --- /dev/null +++ b/libsrc/float/softmath/softmath-atanf.c @@ -0,0 +1,72 @@ + +#include + +#if 1 +/* atan(x)= x(c1 + c2*x**2 + c3*x**4)/(c4 + c5*x**2 + c6*x**4 + x**6) + + Accurate to about 13.7 decimal digits over the range [0, pi/12]. */ +float _atan(float x) +{ + const float c1= 48.70107004404898384f; + const float c2= 49.5326263772254345f; + const float c3= 9.40604244231624f; + const float c4= 48.70107004404996166f; + const float c5= 65.7663163908956299f; + const float c6= 21.587934067020262f; + + float x2; + x2 = x * x; + return (x * (c1 + x2 * (c2 + x2 * c3)) / (c4 + x2 * (c5 + x2 * (c6 + x2)))); +} + +#define TAN_SIXTHPI 0.009138776996f +#define TAN_TWELFTHPI 0.004569293096f + +float atanf(float x) +{ + float y; + int complement= 0; // true if arg was >1 + int region= 0; // true depending on region arg is in + int sign= 0; // true if arg was < 0 + + if (x < 0.0f ) { +// x = -x; +// x = x * -1.0f; + x = -1.0f * x; + sign = 1; // arctan(-x)=-arctan(x) + } + if (x > 1.0f) { + x = 1.0f / x; // keep arg between 0 and 1 + complement = 1; + } + if (x > TAN_TWELFTHPI) { + /* FIXME: reduce arg to under tan(pi/12) */ +#if 1 + float n, m; + n = (TAN_SIXTHPI * x) + 1.0f; + m = (x - TAN_SIXTHPI); +// x = (x - TAN_SIXTHPI) / (1.0f + (TAN_SIXTHPI * x)); + x = m / n; +#else + x = fmodf(x, TAN_SIXTHPI); +#endif + region = 1; + } + + y = _atan(x); + + if (region) { y += (M_PI / 6.0f); } /* correct for region we're in */ + if (complement) { y= (M_PI / 2.0f) - y; } /* correct for 1/x */ + if (sign) { y =- y; } /* correct for negative arg */ + return y; +} +#endif + +#if 0 +float atanf(float x) +{ + x = x; + return 0.0f; +} +#endif + diff --git a/libsrc/float/softmath/softmath-ceilf.c b/libsrc/float/softmath/softmath-ceilf.c new file mode 100644 index 000000000..0f279826b --- /dev/null +++ b/libsrc/float/softmath/softmath-ceilf.c @@ -0,0 +1,14 @@ + +#include + +/* FIXME: this is really too simple */ +float ceilf(float x) +{ + int n = (int) x; + + if (n >= x) { + return n; + } + + return n + 1; +} diff --git a/libsrc/float/softmath/softmath-cosf.c b/libsrc/float/softmath/softmath-cosf.c new file mode 100644 index 000000000..d322df09d --- /dev/null +++ b/libsrc/float/softmath/softmath-cosf.c @@ -0,0 +1,67 @@ + +/* nicked from https://github.com/AZHenley/cosine/blob/master/cosine.c */ + +/* +MIT License + +Copyright (c) 2020 Austin Henley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include + +#define RUNTERMS 8 +float cosf(float x) +{ + int i; + int div; + float num; + float result = 1.0f; + float inter = 1.0f; + float comp; + float den; + + div = (int)(x / M_PI); + + x = x - (div * M_PI); + + num = x * x; + for (i = 1; i <= RUNTERMS; i++) { + comp = 2.0f * i; + den = comp * (comp - 1.0f); + inter *= num / den; + if (i % 2 == 0) { + result += inter; + } else { + result -= inter; + } + } + + if (div % 2 != 0) { + return result * -1.0f; + } + return result; +} + +#if 0 +float cosf(float x) { + return sinf(x + (M_PI / 2.0)); +} +#endif diff --git a/libsrc/float/softmath/softmath-expf.c b/libsrc/float/softmath/softmath-expf.c new file mode 100644 index 000000000..fd4545e6f --- /dev/null +++ b/libsrc/float/softmath/softmath-expf.c @@ -0,0 +1,73 @@ + +#include + +#if 1 + +/* natural logarithm of 2 */ +#define LN2 0.693147180559945309417f + +// #include +// char abuf[100]; +// char abuf2[100]; +// char abuf3[100]; + +float expf(float x) +{ + float p; + int i; + int k; + // float i; + // float k; + + float r; + float tn; + float x0 = fabsf(x); // FIXME: somehow this doesnt work! + + if (x == 0) { + return 1; + } + x0 = fabsf(x); +// printf("x:%s x0:%s\n", _ftostr(abuf3, x), _ftostr(abuf, x0)); + + k = ceilf((x0 / LN2) - 0.5f); + p = (float)(1 << (int)k); + r = x0 - (LN2 * (float)k); // internal error + tn = 1.0f; +// printf("k:%s tn:%s r:%s\n", _ftostr(abuf3, k), _ftostr(abuf, tn), _ftostr(abuf2, r )); + + for (i = 14; i > 0; --i) { + //tn = tn * (r / (float)i) + 1.0f; + float tmp; + tmp = (r / (float)i); + tn = tn * tmp; + tn = tn + 1.0f; +// printf("i:%d tn:%s tmp:%s\n", i, _ftostr(abuf, tn), _ftostr(abuf2, tmp )); + } + + p *= tn; + + if (x < 0) { + return 1.0f / p; + } + return p; +} +#endif + +#if 0 +static float expf(float n) { + int a = 0, b = n > 0; + float c = 1, d = 1, e = 1; + for (b || (n = -n); e + .00001 < (e += (d *= n) / (c *= ++a));); // "Floating point type is currently unsupported" +// for (b || (n = -n); e + .00001 < (e = e + (d *= n) / (c *= ++a));); // "Floating point type is currently unsupported" + // approximately 15 iterations + return b ? e : 1 / e; +} +#endif + +#if 0 +float expf(float x) +{ + x = x; + return 0.0f; +} +#endif diff --git a/libsrc/float/softmath/softmath-fabsf.c b/libsrc/float/softmath/softmath-fabsf.c new file mode 100644 index 000000000..99cdcfa22 --- /dev/null +++ b/libsrc/float/softmath/softmath-fabsf.c @@ -0,0 +1,6 @@ + +#include + +float fabsf(float x) { + return x < 0.0f ? -x : x; +} diff --git a/libsrc/float/softmath/softmath-floorf.c b/libsrc/float/softmath/softmath-floorf.c new file mode 100644 index 000000000..558a46fc1 --- /dev/null +++ b/libsrc/float/softmath/softmath-floorf.c @@ -0,0 +1,17 @@ + +#include + +/* FIXME: this is really too simple */ +float ffloor(float x) +{ + signed long n; + float d; + + n = (signed long)x; + d = (float)n; + + if (x >= 0) { + return d; + } + return d - 1; +} diff --git a/libsrc/float/softmath/softmath-fmodf.c b/libsrc/float/softmath/softmath-fmodf.c new file mode 100644 index 000000000..bb59e2359 --- /dev/null +++ b/libsrc/float/softmath/softmath-fmodf.c @@ -0,0 +1,9 @@ + +#include + +float fmodf(float x, float y) +{ + float res; + res = x / y; + return x - (truncf(res) * y); +} diff --git a/libsrc/float/softmath/softmath-logf.c b/libsrc/float/softmath/softmath-logf.c new file mode 100644 index 000000000..e124c3032 --- /dev/null +++ b/libsrc/float/softmath/softmath-logf.c @@ -0,0 +1,130 @@ +#include + +/* natural logarithm */ + +#if 1 +/*#define LOGBASE 10*/ +#define LOGBASE 2 /* e=2.7182818... */ +float logf(float x) +{ + int i; + float alpha; + float save; + float ans; + + alpha = (x-1)/(x+1); + ans = alpha; + save = ans * alpha * alpha; + + for (i = 2 ; i <= LOGBASE ; i++) { + ans += (1.0/(float)(2*i-1)) * save; + save = save * alpha * alpha; + } + + return 2.0*ans; +} +#endif + +#if 0 +static int msb(int a) +{ + unsigned int r = 0; + + while(a >>= 1) { + r++; + } + return r; +} + +float logf(float y) +{ + float result; + int log2; + float divisor, x; + + log2 = msb((int)y); + divisor = (float)(1 << log2); + x = y / divisor; + + result = -1.7417939f + (2.8212026f + (-1.4699568f + (0.44717955f - 0.056570851f * x) * x) * x) * x; + result += ((float)log2) * 0.69314718f; // ln(2) = 0.69314718 + + return result; +} +#endif + +#if 0 +float logf(float x) +{ + + // ASSUMING: + // - non-denormalized numbers i.e. x > 2^−126 + // - integer is 32 bit. float is IEEE 32 bit. + + // INSPIRED BY: + // - https://stackoverflow.com/a/44232045 + // - http://mathonweb.com/help_ebook/html/algorithms.htm#ln + // - https://en.wikipedia.org/wiki/Fast_inverse_square_root + + // FORMULA: + // x = m * 2^p => + // ln(x) = ln(m) + ln(2)p, + + // first normalize the value to between 1.0 and 2.0 + // assuming normalized IEEE float + // sign exp frac + // 0b 0 [00000000] 00000000000000000000000 + // value = (-1)^s * M * 2 ^ (exp-127) + // + // exp = 127 for x = 1, + // so 2^(exp-127) is the multiplier + + // evil floating point bit level hacking + unsigned long bx = * (unsigned long *) (&x); + + // extract exp, since x>0, sign bit must be 0 + unsigned long ex = bx >> 23; + signed long t = (signed long)ex-(signed long)127; + unsigned long s = (t < 0) ? (-t) : t; + + // reinterpret back to float + // 127 << 23 = 1065353216 + // 0b11111111111111111111111 = 8388607 + bx = 1065353216 | (bx & 8388607); + x = * (float *) (&bx); + + + // use remez algorithm to find approximation between [1,2] + // - see this answer https://stackoverflow.com/a/44232045 + // - or this usage of C++/boost's remez implementation + // https://computingandrecording.wordpress.com/2017/04/24/ + // e.g. + // boost::math::tools::remez_minimax approx( + // [](const double& x) { return log(x); }, + // 4, 0, 1, 2, false, 0, 0, 64); + // + // 4th order is: + // { -1.74178, 2.82117, -1.46994, 0.447178, -0.0565717 } + // + // 3rd order is: + // { -1.49278, 2.11263, -0.729104, 0.10969 } + + return + + /* less accurate */ + -1.49278+(2.11263+(-0.729104+0.10969*x)*x)*x + + /* OR more accurate */ + // -1.7417939+(2.8212026+(-1.4699568+(0.44717955-0.056570851*x)*x)*x)*x + + /* compensate for the ln(2)s. ln(2)=0.6931471806 */ + + 0.6931471806*t; +} +#endif + +#if 0 +float logf(float y) +{ + return 0.0f; +} +#endif diff --git a/libsrc/float/softmath/softmath-powf.c b/libsrc/float/softmath/softmath-powf.c new file mode 100644 index 000000000..76a74d4aa --- /dev/null +++ b/libsrc/float/softmath/softmath-powf.c @@ -0,0 +1,7 @@ + +#include + +float powf(float x, float y) +{ + return expf(x * logf(y)); +} diff --git a/libsrc/float/softmath/softmath-roundf.c b/libsrc/float/softmath/softmath-roundf.c new file mode 100644 index 000000000..9aaa8f3ce --- /dev/null +++ b/libsrc/float/softmath/softmath-roundf.c @@ -0,0 +1,11 @@ + +#include + +/* FIXME: this is really too simple */ +float roundf(float x) +{ + if (x > 0.0f) { + return (float)((signed long)(x + 0.5f)); + } + return (float)((signed long)(x - 0.5f)); +} diff --git a/libsrc/float/softmath/softmath-sinf.c b/libsrc/float/softmath/softmath-sinf.c new file mode 100644 index 000000000..10bc42768 --- /dev/null +++ b/libsrc/float/softmath/softmath-sinf.c @@ -0,0 +1,6 @@ + +#include + +float sinf(float x) { + return cosf(x - (M_PI / 2.0)); +} diff --git a/libsrc/float/softmath/softmath-sqrtf.c b/libsrc/float/softmath/softmath-sqrtf.c new file mode 100644 index 000000000..7307f97fd --- /dev/null +++ b/libsrc/float/softmath/softmath-sqrtf.c @@ -0,0 +1,90 @@ +#if 1 +static float powerOfTen(int num) +{ + int i; +// float rst = 1.0f; + float rst; + rst = 1.0f; + if(num >= 0) { + for(i = 0; i < num ; ++i) { + // rst *= 10.0; + rst = rst * 10.0f; + } + } else { + for(i = 0; i < (0 - num); ++i) { + // rst *= 0.1; + rst = rst * 0.1f; + } + } + + return rst; +} + +#define MAXDIGITS 8 +float sqrtf(float a) +{ +// float rst = 0.0f; + float rst; +// float z = a; + float z; + signed int i; +// float j = 1.0f; + float j; + float power; + rst = 0.0f; + z = a; + j = 1.0f; + for(i = MAXDIGITS ; i > 0 ; i--) { + power = powerOfTen(i); + // value must be bigger then 0 + if(z - (( 2.0f * rst ) + ( j * power)) * ( j * power) >= 0) { + while( z - (( 2.0f * rst ) + ( j * power)) * ( j * power) >= 0) { + //j++; + j = j + 1.0f; + if(j >= 10.0f) { + break; + } + } + //j--; //correct the extra value by minus one to j + j = j - 1.0f; + //z -= (( 2.0f * rst ) + ( j * power)) * ( j * power); //find value of z + z = z - (( 2.0f * rst ) + ( j * power)) * ( j * power); //find value of z + + //rst += j * power; // find sum of a + rst = rst + (j * power); // find sum of a + j = 1.0f; + } + } + + for(i = 0 ; i >= 0 - MAXDIGITS ; i--) { + power = powerOfTen(i); + if(z - (( 2.0f * rst ) + ( j * power))*( j * power) >= 0) { + while( z - (( 2.0f * rst ) + ( j * power))*( j * power) >= 0) { + //j++; + j = j + 1.0f; + if(j >= 10.0f) { + break; + } + } + //j--; //correct the extra value by minus one to j + j = j - 1.0f; + //z -= (( 2.0f * rst ) + ( j * power))*( j * power); //find value of z + z = z - (( 2.0f * rst ) + ( j * power)) * ( j * power); //find value of z + //rst += j * power; // find sum of a + rst = rst + (j * power); // find sum of a + j = 1.0f; + } + } + + // find the number on each digit + return rst; +} +#endif + +#if 0 +float sqrtf(float a) +{ + a = a; + return 0.0f; +} +#endif diff --git a/libsrc/float/softmath/softmath-tanf.c b/libsrc/float/softmath/softmath-tanf.c new file mode 100644 index 000000000..6f8f7ddfb --- /dev/null +++ b/libsrc/float/softmath/softmath-tanf.c @@ -0,0 +1,52 @@ + +#include + +#if 1 +/* The input argument is in radians. Note that the function + computes tan(pi*x/4), NOT tan(x); it's up to the range + reduction algorithm that calls this to scale things properly. + + Algorithm: + tan(x)= x(c1 + c2*x**2 + c3*x**4)/(c4 + c5*x**2 + c6*x**4 + x**6) + + Accurate to about 14 decimal digits over the range [0, pi/4]. */ +static float _tan(float x) +{ + const float c1=-34287.4662577359568109624f; + const float c2= 2566.7175462315050423295f; + const float c3=- 26.5366371951731325438f; + const float c4=-43656.1579281292375769579f; + const float c5= 12244.4839556747426927793f; + const float c6=- 336.611376245464339493f; + + float x2; + + x2 = x * x; + return (x * (c1 + x2 * (c2 + x2 * c3)) / (c4 + x2 * (c5 + x2 * (c6 + x2)))); +} + +float tanf(float x){ + int octant; + + x = fmodf(x, (2.0f * M_PI)); + octant=(int)(x * (4.0f / M_PI)); + switch (octant){ + case 0: return _tan(x * (4.0f / M_PI)); + case 1: return 1.0f / _tan(((M_PI / 2.0f) - x) * (4.0f / M_PI)); + case 2: return -1.0f / _tan((x - (M_PI / 2.0f)) * (4.0f / M_PI)); + case 3: return - _tan((M_PI - x) * (4.0f / M_PI)); + case 4: return _tan((x - M_PI) * (4.0f / M_PI)); + case 5: return 1.0f / _tan(((3.0f * M_PI / 2.0f) - x) * (4.0f / M_PI)); + case 6: return -1.0f / _tan((x - (3.0f * M_PI / 2.0f)) * (4.0f / M_PI)); + case 7: return - _tan(((2.0f * M_PI)-x) * (4.0f / M_PI)); + } +} +#endif + +#if 0 +float tanf(float x) +{ + x = x; + return 0.0f; +} +#endif diff --git a/libsrc/float/softmath/softmath-truncf.c b/libsrc/float/softmath/softmath-truncf.c new file mode 100644 index 000000000..996dda29d --- /dev/null +++ b/libsrc/float/softmath/softmath-truncf.c @@ -0,0 +1,8 @@ + +#include + +/* FIXME: this is really too simple */ +float truncf(float x) +{ + return (float)((signed long)x); +} diff --git a/libsrc/vic20/extra/fp754kernal.s b/libsrc/vic20/extra/fp754kernal.s new file mode 100644 index 000000000..768cfd60f --- /dev/null +++ b/libsrc/vic20/extra/fp754kernal.s @@ -0,0 +1,66 @@ + +; import/overload stubs for the VIC20 kernal floating point implementation + + .import ___cbmkernal_afloat + .import ___cbmkernal_aufloat + .import ___cbmkernal_axfloat + .import ___cbmkernal_axufloat + .import ___cbmkernal_eaxfloat + .import ___cbmkernal_eaxufloat + .import ___cbmkernal_feaxint + .import ___cbmkernal_feaxlong + .import ___cbmkernal_fbnegeax + .import ___cbmkernal_ftosaddeax + .import ___cbmkernal_ftossubeax + .import ___cbmkernal_ftosdiveax + .import ___cbmkernal_ftosmuleax + .import ___cbmkernal_ftoseqeax + .import ___cbmkernal_ftosneeax + .import ___cbmkernal_ftosgteax + .import ___cbmkernal_ftoslteax + .import ___cbmkernal_ftosgeeax + .import ___cbmkernal_ftosleeax + + .export afloat := ___cbmkernal_afloat + .export aufloat := ___cbmkernal_aufloat + .export axfloat := ___cbmkernal_axfloat + .export axufloat := ___cbmkernal_axufloat + .export eaxfloat := ___cbmkernal_eaxfloat + .export eaxufloat := ___cbmkernal_eaxufloat + .export feaxint := ___cbmkernal_feaxint + .export feaxlong := ___cbmkernal_feaxlong + .export fbnegeax := ___cbmkernal_fbnegeax + .export ftosaddeax := ___cbmkernal_ftosaddeax + .export ftossubeax := ___cbmkernal_ftossubeax + .export ftosdiveax := ___cbmkernal_ftosdiveax + .export ftosmuleax := ___cbmkernal_ftosmuleax + .export ftoseqeax := ___cbmkernal_ftoseqeax + .export ftosneeax := ___cbmkernal_ftosneeax + .export ftosgteax := ___cbmkernal_ftosgteax + .export ftoslteax := ___cbmkernal_ftoslteax + .export ftosgeeax := ___cbmkernal_ftosgeeax + .export ftosleeax := ___cbmkernal_ftosleeax + + .import ___cbmkernal_powf + .import ___cbmkernal_sinf + .import ___cbmkernal_cosf + .import ___cbmkernal_logf + .import ___cbmkernal_expf + .import ___cbmkernal_sqrtf + .import ___cbmkernal_tanf + .import ___cbmkernal_atanf + .import ___cbmkernal_fabsf + .import ___cbmkernal_roundf + .import ___cbmkernal_truncf + + .export _powf := ___cbmkernal_powf + .export _sinf := ___cbmkernal_sinf + .export _cosf := ___cbmkernal_cosf + .export _logf := ___cbmkernal_logf + .export _expf := ___cbmkernal_expf + .export _sqrtf := ___cbmkernal_sqrtf + .export _tanf := ___cbmkernal_tanf + .export _atanf := ___cbmkernal_atanf + .export _fabsf := ___cbmkernal_fabsf + .export _roundf := ___cbmkernal_roundf + .export _truncf := ___cbmkernal_truncf diff --git a/samples/Makefile b/samples/Makefile index 0e5292306..2e094761e 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -164,9 +164,11 @@ EXELIST_apple2 = \ checkversion \ diodemo \ enumdevdir \ + floattest \ gunzip65 \ hello \ mandelbrot \ + mandelfloat \ mousedemo \ multdemo \ ovrldemo \ @@ -180,9 +182,11 @@ EXELIST_apple2enh = $(EXELIST_apple2) EXELIST_atari = \ ascii \ checkversion \ + floattest \ gunzip65 \ hello \ mandelbrot \ + mandelfloat \ mousedemo \ multdemo \ ovrldemo \ @@ -202,8 +206,10 @@ EXELIST_atari5200 = \ EXELIST_atmos = \ ascii \ checkversion \ + floattest \ hello \ mandelbrot \ + mandelfloat \ sieve \ terminal \ tgidemo @@ -215,24 +221,30 @@ EXELIST_c64 = \ ascii \ checkversion \ enumdevdir \ + floattest \ gunzip65 \ hello \ mandelbrot \ + mandelfloat \ + mathtest \ mousedemo \ multdemo \ ovrldemo \ sieve \ terminal \ tinyshell \ - tgidemo + tgidemo \ + tgisincos EXELIST_c128 = \ ascii \ checkversion \ enumdevdir \ + floattest \ gunzip65 \ hello \ mandelbrot \ + mandelfloat \ mousedemo \ sieve \ terminal \ @@ -249,8 +261,10 @@ EXELIST_c16 = \ EXELIST_cbm510 = \ ascii \ checkversion \ + floattest \ gunzip65 \ hello \ + mandelfloat \ mousedemo \ terminal \ tinyshell \ @@ -259,8 +273,10 @@ EXELIST_cbm510 = \ EXELIST_cbm610 = \ ascii \ checkversion \ + floattest \ gunzip65 \ hello \ + mandelfloat \ terminal \ tinyshell \ sieve @@ -273,9 +289,11 @@ EXELIST_cx16 = \ ascii \ checkversion \ enumdevdir \ + floattest \ gunzip65 \ hello \ mandelbrot \ + mandelfloat \ mousedemo \ sieve \ tinyshell \ @@ -311,7 +329,9 @@ EXELIST_pet = \ ascii \ checkversion \ enumdevdir \ + floattest \ hello \ + mandelfloat \ tinyshell \ sieve @@ -319,8 +339,10 @@ EXELIST_plus4 = \ ascii \ checkversion \ enumdevdir \ + floattest \ gunzip65 \ hello \ + mandelfloat \ terminal \ tinyshell \ sieve @@ -343,9 +365,11 @@ EXELIST_kim1 = \ EXELIST_telestrat = \ ascii \ checkversion \ + floattest \ gunzip65 \ hello \ mandelbrot \ + mandelfloat \ sieve \ tgidemo @@ -353,8 +377,10 @@ EXELIST_vic20 = \ ascii \ checkversion \ enumdevdir \ + floattest \ hello \ mandelbrot \ + mandelfloat \ sieve \ tgidemo @@ -447,6 +473,22 @@ ovrldemo: overlaydemo.o OVERLAYLIST := $(foreach I,1 2 3,multdemo.$I ovrldemo.$I) +# link float examples against the (much faster) kernal lib, if available +ifeq ($(SYS),c64) +floattest: override CFLAGS += -D DYN_DRV=0 +floattest: floattest.o + $(LD) $(LDFLAGS) -o $@ -C c64.cfg -m $@.map $^ c64-fp754kernal.o $(SYS).lib +mandelfloat.o: override CFLAGS += -D DYN_DRV=0 +mandelfloat: mandelfloat.o + $(LD) $(LDFLAGS) -o $@ -C c64.cfg -m $@.map $^ c64-fp754kernal.o $(SYS).lib +mathtest.o: override CFLAGS += -D DYN_DRV=0 +mathtest: mathtest.o + $(LD) $(LDFLAGS) -o $@ -C c64.cfg -m $@.map $^ c64-fp754kernal.o $(SYS).lib +tgisincos.o: override CFLAGS += -D DYN_DRV=0 +tgisincos: tgisincos.o + $(LD) $(LDFLAGS) -o $@ -C c64.cfg -m $@.map $^ c64-fp754kernal.o $(SYS).lib +endif + # -------------------------------------------------------------------------- # TGI programs on the VIC-20 need a special ld65 configuration file. diff --git a/samples/floattest.c b/samples/floattest.c new file mode 100644 index 000000000..e252d3483 --- /dev/null +++ b/samples/floattest.c @@ -0,0 +1,36 @@ +#include +#include + +#include <_float.h> + +char buf[100]; + +// quick check to see if printing float value works +void constants(void) +{ + printf("-100.0 %15s\n", _ftostr(buf, -100.0f)); + printf(" -10.0 %15s\n", _ftostr(buf, -10.0f)); + printf(" -1.0 %15s\n", _ftostr(buf, -1.0f)); + printf(" -0.1 %15s\n", _ftostr(buf, -0.1f)); + printf(" -0.01 %15s\n", _ftostr(buf, -0.01f)); + printf(" -0.001 %15s\n", _ftostr(buf, -0.001f)); + printf(" -0.0001 %15s\n", _ftostr(buf, -0.0001f)); + printf(" -0.00001 %15s\n", _ftostr(buf, -0.00001f)); + printf(" 0.0 %15s\n", _ftostr(buf, 0.0f)); + printf(" 0.1 %15s\n", _ftostr(buf, 0.1f)); + printf(" 0.01 %15s\n", _ftostr(buf, 0.01f)); + printf(" 0.001 %15s\n", _ftostr(buf, 0.001f)); + printf(" 0.0001 %15s\n", _ftostr(buf, 0.0001f)); + printf(" 0.00001 %15s\n", _ftostr(buf, 0.00001f)); + printf(" 1.0 %15s\n", _ftostr(buf, 1.0f)); + printf(" 10.0 %15s\n", _ftostr(buf, 10.0f)); + printf(" 100.0 %15s\n", _ftostr(buf, 100.0f)); + printf("\n"); +// cgetc(); +} + +int main(void) +{ + constants(); + return 0; +} diff --git a/samples/mandelfloat.c b/samples/mandelfloat.c new file mode 100644 index 000000000..353df2422 --- /dev/null +++ b/samples/mandelfloat.c @@ -0,0 +1,74 @@ + +/* + * $ cl65 -o mandelfloat.prg mandelfloat.c + * + * use the CBM kernal fp routines like this: + * + * $ cl65 -o mandelfloat.prg mandelfloat.c c64-fp488kernal.o + * + */ + + +#include +#include + +#define MAX_ITER 40 + +#define XRES 20 +#define YRES 20 + +#define XMIN -2.25f +#define XMAX 2.25f +#define YMIN -2.25f +#define YMAX 2.25f + +// FIXME: Invalid operands for binary operator '-' +// #define XRANGE (XMAX - XMIN) +// #define YRANGE (YMAX - YMIN) +#define XRANGE 4.5f +#define YRANGE 4.5f + +#define XSTEP (XRANGE / XRES) +#define YSTEP (YRANGE / YRES) + +char *colortab = ".+*#%$=-"; + +void color(int iterations) { + if (iterations >= MAX_ITER) { + putchar(' '); + } else { + putchar(colortab[iterations & 7]); + } +} + +float x, y; /* Coordinates of the current point in the complex plane. */ +float u, v; /* Coordinates of the iterated point. */ +unsigned char i, j; /* Pixel counters */ +unsigned char k; /* Iteration counter */ + +float u, v; +float u2, v2; + +int main(void) +{ + for (j = 0; j < YRES; j++) { + y = YMIN + j * YSTEP; + for(i = 0; i < XRES; i++) { + + u = 0.0f; + v = 0.0f; + u2 = 0.0f; + v2 = 0.0f; + x = i * XSTEP + XMIN; + /* iterate the point */ + for (k = 1; (k < MAX_ITER) && ((u2 + v2) < 4.0f); ++k) { + v = 2.0f * u * v + y; + u = u2 - v2 + x; + u2 = u * u; + v2 = v * v; + }; + color(k); + } + putchar('\n'); + } +} diff --git a/samples/mathtest.c b/samples/mathtest.c new file mode 100644 index 000000000..7d90a2aa1 --- /dev/null +++ b/samples/mathtest.c @@ -0,0 +1,218 @@ +#include +#include +#include + +#ifdef __CC65__ +#include // for cgetc +#else +#define cgetc() +char *_ftostr(char *d, float s); +#endif + +#ifdef __SIM6502__ +#define cgetc() +#endif + +char buf[100]; + +/* +float __fastcall__ sinf(float s); +float __fastcall__ cosf(float s); +float __fastcall__ tanf(float x); +float __fastcall__ atanf(float x); +*/ + +float atanvalues[8]= { + 0.50f, // 0.46 + -1.50f, // -0.98 +}; + +void sincostanatan(void) +{ + int n; + float angle = 0.0; +// float angle = -M_PI; + printf("sinus:\n"); + angle = 0.0; + for (n = 0; n < 18; n++) { + printf("%15s ", _ftostr(buf, angle)); + printf("%15s", _ftostr(buf, sinf(angle))); + printf("\n"); +// angle += (M_PI / 8); Error: Invalid left operand for binary operator '+=' + angle = angle + ((M_PI * 2.0f) / 16); + } + printf("\n"); cgetc(); + printf("cosinus:\n"); + angle = 0.0; + for (n = 0; n < 18; n++) { + printf("%15s ", _ftostr(buf, angle)); + printf("%15s", _ftostr(buf, cosf(angle))); + printf("\n"); +// angle += (M_PI / 8); Error: Invalid left operand for binary operator '+=' + angle = angle + ((M_PI * 2.0f) / 16); + } + printf("\n"); cgetc(); + printf("tangens:\n"); + angle = 0.0; + for (n = 0; n < 18; n++) { + printf("%15s ", _ftostr(buf, angle)); + printf("%15s", _ftostr(buf, tanf(angle))); + printf("\n"); +// angle += (M_PI / 8); Error: Invalid left operand for binary operator '+=' + angle = angle + ((M_PI * 2.0f) / 16); + } + printf("\n"); cgetc(); + printf("atan:\n"); + angle = 0.0; + for (n = 0; n < 2; n++) { + printf("%15s ", _ftostr(buf, atanvalues[n])); + printf("%15s", _ftostr(buf, atanf(atanvalues[n]))); + printf("\n"); + } + printf("\n"); cgetc(); +} + +/* +float __fastcall__ roundf(float x); +float __fastcall__ truncf(float x); +float __fastcall__ fabsf(float x); +*/ + +float roundtruncvals[22] = { + 2.0f, + 1.9f, + 1.5f, + 1.4f, + 1.1f, + 1.0f, + 0.9f, + 0.5f, // 1.0 + 0.4f, + 0.1f, + 0.0f, + -0.1f, + -0.4f, + -0.5f, // -1.0 + -0.501f, // -1.0 + -0.9f, + -1.0f, + -1.1f, + -1.4f, + -1.5f, + -1.5001f, + -1.9f, +// -2.0f, +// -2.1f, +}; + +void roundtruncabs(void) +{ + int n; + printf("round/trunc:\n"); + for (n = 0; n < 21; n++) { + printf("%12s", _ftostr(buf, roundtruncvals[n])); + printf("%12s", _ftostr(buf, roundf(roundtruncvals[n]))); + printf("%12s", _ftostr(buf, truncf(roundtruncvals[n]))); + printf("\n"); + } + printf("\n"); cgetc(); + printf("abs/ceil:\n"); + for (n = 0; n < 21; n++) { + printf("%12s", _ftostr(buf, roundtruncvals[n])); + printf("%12s", _ftostr(buf, fabsf(roundtruncvals[n]))); + printf("%12s", _ftostr(buf, ceilf(roundtruncvals[n]))); + printf("\n"); + } + printf("\n"); cgetc(); +} + +/* +float __fastcall__ powf(float f, float a); +float __fastcall__ sqrtf(float x); +*/ +float powvals0[8] = { + 2, + 10, + 2, + 10 +}; + +float powvals1[8] = { + 3, + 3, + 4, + 4 +}; + +float sqrtvals[8] = { + 9, + 2, + 1, + 16, + 0, + 4, + 5, + 6 +}; + +void powersqrt(void) +{ + int n; + printf("pow:\n"); + for (n = 0; n < 4; n++) { + printf("%12s", _ftostr(buf, powvals0[n])); + printf("%12s", _ftostr(buf, powvals1[n])); + printf("%12s", _ftostr(buf, powf(powvals0[n], powvals1[n]))); + printf("\n"); + } + printf("sqrt:\n"); + for (n = 0; n < 8; n++) { + printf("%12s", _ftostr(buf, sqrtvals[n])); + printf("%12s", _ftostr(buf, sqrtf(sqrtvals[n]))); + printf("\n"); + } + printf("\n"); cgetc(); +} + +/* +float __fastcall__ logf(float x); +float __fastcall__ expf(float x); +*/ +float logvals[8] = { + 1.0f, // 0 + 5.6f, // 1.72 + 10.0f, // 2.302585 +}; + +float expvals[8] = { + 12.0f, // 162754.79 + 5.0f, // 148.413159 + 4.0f, // 54.598150 + 3.0f, // 20.085537 +}; + +void logexp(void) +{ + int n; + printf("log:\n"); + for (n = 0; n < 3; n++) { + printf("%12s", _ftostr(buf, logvals[n])); + printf("%12s", _ftostr(buf, logf(logvals[n]))); + printf("\n"); + } + printf("exp:\n"); + for (n = 0; n < 4; n++) { + printf("%12s", _ftostr(buf, expvals[n])); + printf("%12s", _ftostr(buf, expf(expvals[n]))); + printf("\n"); + } + printf("\n"); cgetc(); +} + +int main(void) +{ + roundtruncabs(); + sincostanatan(); + logexp(); + powersqrt(); +} diff --git a/samples/readme.txt b/samples/readme.txt index 1a5b1c9ff..1e5202a90 100644 --- a/samples/readme.txt +++ b/samples/readme.txt @@ -81,6 +81,18 @@ Platforms: Runs on all platforms that have TGI support: Apple ][, Atari, C64, C128, Oric Atmos and Telestrat, GEOS, and NES. +----------------------------------------------------------------------------- +Name: mandelfloat +Description: A very simple mandelbrot calculator, which uses floats and out- + puts the result to console. +Platforms: Runs on all platforms that have putchar(); + +----------------------------------------------------------------------------- +Name: mathtest +Description: Uses the floating point math.h functions to plot some more or + less interesting pattern +Platforms: Runs on all platforms that have putchar(); + ----------------------------------------------------------------------------- Name: mousedemo Description: Shows how to use the mouse. diff --git a/samples/tgisincos.c b/samples/tgisincos.c new file mode 100644 index 000000000..3cc6cdd83 --- /dev/null +++ b/samples/tgisincos.c @@ -0,0 +1,362 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +char buf[100]; // for ftostr +char buf2[100]; // for ftostr +char buf3[100]; // for ftostr + + +#ifndef DYN_DRV +# define DYN_DRV 1 +#endif + +#define COLOR_BACK TGI_COLOR_BLACK +#define COLOR_FORE TGI_COLOR_WHITE + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* Driver stuff */ +static unsigned MaxX; +static unsigned MaxY; +static unsigned AspectRatio; + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + +static void CheckError (const char* S) +{ + unsigned char Error = tgi_geterror (); + + if (Error != TGI_ERR_OK) { + printf ("%s: %u\n", S, Error); + if (doesclrscrafterexit ()) { + cgetc (); + } + exit (EXIT_FAILURE); + } +} + +#if DYN_DRV +static void DoWarning (void) +/* Warn the user that the dynamic TGI driver is needed for this program */ +{ + printf ("Warning: This program needs the TGI\n" + "driver on disk! Press 'y' if you have\n" + "it - any other key exits.\n"); + if (tolower (cgetc ()) != 'y') { + exit (EXIT_SUCCESS); + } + printf ("OK. Please wait patiently...\n"); +} +#endif + +static const unsigned char Palette[2] = { TGI_COLOR_WHITE, TGI_COLOR_BLUE }; + +#if 1 +int XRes, YRes; +float xf, xfMin, xfMax, xfDelta, yf, yfMin, yfMax, yfDelta; +float radiusf, zf, zScale; +int x,y; +// unsigned char YMax; +int YMax; +unsigned int XResHalf; +float yfMinSquare; + +float yfD; +float a; +float b; +float yfSquare; + +int xoff = 0; +int yoff = 0; + +void Dosincos(void) { +#if 1 + tgi_setpalette (Palette); + tgi_setcolor (COLOR_FORE); + tgi_clear (); +#endif + /* Get stuff from the graph lib */ + XRes = tgi_getmaxx() + 1; +// XRes = 320; + YRes = tgi_getmaxy() + 1; +// YRes = 200; + YMax = YRes - 1; + + + + /* Compute and draw a 3d function. */ + yfMin = -144.0f; + yfMax = 144.0f; + yf = 0; +// printf("yf:%s\n", _ftostr(buf, yf)); +// printf("min:%s\n", _ftostr(buf, yfMin)); +// printf("max:%s\n", _ftostr(buf, yfMax)); + + yfDelta = 2.25f; + zScale = -10.0f; + + XResHalf = XRes * 0.5f; + yfMinSquare = yfMin * yfMin; + + yoff = 20; + xoff = 0; + +// for( yf = yfMin; yf < yfMax; yf += yfDelta) { // FIXME +// for( yf = yfMin; yf < yfMax; yf = yf + yfDelta) { // FIXME + for( yf = yfMin; yf < yfMax; yf = yfDelta + yf ) { // FIXME +// printf("yf:%s min:%s max:%s\n", _ftostr(buf, yf), _ftostr(buf2, yfMin), _ftostr(buf3, yfMax)); +#if 0 + float yfD; + float a; + float b; + float yfSquare; +#endif + +#if 0 + /* add some very fake perspective */ + yoff++; + xoff--; +#endif +// xfMax = sqrtf( yfMinSquare - yf * yf); + xfMax = sqrtf( yfMinSquare - (yf * yf)); + xfMin = -xfMax; // trigger fnegeax + xfDelta = 1.0f; + + // Constant terms from the inner loop + yfD = yf / yfDelta; + a = XResHalf + yfD; +// b= YMax + yfD - 90; + b= YMax + yfD - 90.0f; + + yfSquare = yf * yf; + +// for( xf = xfMin; xf < xfMax; xf += xfDelta) { + for( xf = xfMin; xf < xfMax; xf = xf + xfDelta) { +// printf("xf:%s xfmax:%s\n", _ftostr(buf2, xf), _ftostr(buf3, xfMax)); + + radiusf = .0327f * sqrtf( (xf * xf) + yfSquare); + + zf = zScale * (cosf(7.7f * radiusf) + + cosf(8.5f * radiusf) + + cosf(9.3f * radiusf)); + + + /* Scale to screen coordinates */ + x = 1.0f * ( xf + a); + x += xoff; + + y = 0.8f * ( b - zf); + y += yoff; +//printf("x: %d y: %d\n", x, y); + if( y > 0 && y < YRes) { + + tgi_setpixel( x, y); + + /* Clear horizon under y. */ + if( y < YMax) { + tgi_setcolor (COLOR_BACK); + tgi_line( x, y + 1, x, YMax); + tgi_setcolor (COLOR_FORE); + } + } + } + } + cgetc(); +} +#endif + +/* + +5 dim xp, yp, r, fl, xr, yr, x, y, f +6 dim ad, yq, xl, q +7 m7 = 504 + e4 = 40 +8 yl = 200 + n1 = -1 + n5 = 0.5 + nh = 900 + eh = 100 + hs = 160 + sf = 3136 + vz = 196 + s = 1 + a = 7872 +10 dim bi(7), mi(319), ma(319), l(3000), p(30,120) + +11 for t = 0 to 7 + bi(7-t) = s + s = s + s + next : rem bit table +13 for t = 0 to yl + if (7 and t) = 0 then a = a + 320 +14 l(t) = a + next : rem line addr table +15 for x = 0 to 319 + mi(x) = yl + ma(x) = n1 + next : rem min/max buffer + +19 for y = 30 to 0 step n1 + yq = y * y + xp = int(4 * sqr(nh - yq) + n5) +20 for x= 0 to xp + r = sqr(x * x / sf + yq /vz) +21 f = cos(r) - cos(3 * r) / 3 + cos(5 * r) / 5 - cos(7 * r) / 7 + p(y, x) = int(e4 * f + n5) +22 fl = 0 + xp = hs + x - y + yp = eh + y + y - p(y, x) +23 if mi(xp) > yp then mi(xp) = yp: fl = 1 +24 if ma(xp) < yp then ma(xp) = yp: fl = 1 +25 if fl = 0 or yp < z or yp >= yl then 27 +26 ad = l(yp) + (xp and m7) + (yp and 7) + poke ad, peek(ad) or bi(xp and 7) +27 fl = 0 + xp = hs - x - y +28 if mi(xp) > yp then mi(xp) = yp: fl = 1 +29 if ma(xp) < yp then ma(xp) = yp: fl = 1 +30 if fl = 0 or yp < z or yp >= yl then 32 +31 ad = l(yp) + (xp and m7) + (yp and 7) + poke ad, peek(ad) or bi(xp and 7) +32 next + next + +33 for y = -1 to -30 step n1 + yq = y * y + xp = int(4 * sqr(nh - yq) + n5) +35 for x = 0 to xp +36 fl = 0 + xp = hs + x - y + yp = eh + y + y - p(-y,x) +37 if mi(xp) > yp then mi(xp) = yp: fl = 1 +38 if ma(xp) < yp then ma(xp) = yp: fl = 1 +39 if fl = 0 or yp < z or yp >= yl then 41 +40 ad = l(yp) + (xp and m7) + (yp and 7) + poke ad, peek(ad) or bi(xp and 7) +41 fl = 0 + xp = hs - x - y +42 if mi(xp) > yp then mi(xp) = yp: fl = 1 +43 if ma(xp) < yp then ma(xp) = yp: fl = 1 +44 if fl = 0 or yp < z or yp >= yl then 46 +45 ad = l(yp) + (xp and m7) + (yp and 7) + poke ad, peek(ad) or bi(xp and 7) +46 next + next +*/ + +int mi[320]; +int ma[320]; + +int x, y; +int xp, yp; +int yq; +float r; +float f; +int p[30][120]; +unsigned char fl; + +void DoHat(void) { + + tgi_setpalette (Palette); + tgi_setcolor (COLOR_FORE); + tgi_clear (); + + for (x = 0; x < 320; x++) { + mi[x] = 200; + ma[x] = -1; + } + + for (y = 30; y >= 0; y--) { + yq = y * y; +// xp = (int) (4.0f * sqrtf(900.0f - yq) + 0.5f); // Error: Invalid operands for binary operator '-' + xp = (int) (4.0f * sqrtf((float)(900 - yq)) + 0.5f); + + for (x = 0; x < xp; x++) { + r = sqrtf((float)x * (float)x / 3136.0f + (float)yq / 196.0f); + f = cosf(r) - cosf(3.0f * r) / 3.0f + cosf(5.0f * r) / 5.0f - cosf(7.0f * r) / 7.0f; + p[y][x] = (int)((40.0f * f) + 0.5f); + fl = 0; + xp = 160 + x - y; + yp = 100 + y + y - p[y][x]; + if (mi[xp] > yp) { mi[xp] = yp; fl = 1; } + if (ma[xp] < yp) { ma[xp] = yp; fl = 1; } + if (!((fl == 0) || (yp < 0) || (yp >= 200))) { + tgi_setpixel( xp, yp); + } + fl = 0; + xp = 160 - x - y; + + if (mi[xp] > yp) { mi[xp] = yp; fl = 1; } + if (ma[xp] < yp) { ma[xp] = yp; fl = 1; } + if (!((fl == 0) || (yp < 0) || (yp >= 200))) { + tgi_setpixel( xp, yp); + } + } + } + cgetc(); +} + +int main (void) +{ + unsigned char Border; + +#if 1 + +#if DYN_DRV + /* Warn the user that the tgi driver is needed */ + DoWarning (); + + /* Load and initialize the driver */ + tgi_load_driver (tgi_stddrv); + CheckError ("tgi_load_driver"); +#else + /* Install the driver */ + tgi_install (tgi_static_stddrv); + CheckError ("tgi_install"); +#endif + + tgi_init (); + CheckError ("tgi_init"); + + /* Get stuff from the driver */ + MaxX = tgi_getmaxx (); + MaxY = tgi_getmaxy (); + AspectRatio = tgi_getaspectratio (); + + /* Set the palette, set the border color */ + Border = bordercolor (COLOR_BLACK); +#endif + /* Do graphics stuff */ + Dosincos(); +// DoHat(); + +#if DYN_DRV + /* Unload the driver */ + tgi_unload (); +#else + /* Uninstall the driver */ + tgi_uninstall (); +#endif + + /* Reset the border */ + (void) bordercolor (Border); + + /* Done */ + printf ("Done\n"); + return EXIT_SUCCESS; +} diff --git a/src/cc65/assignment.c b/src/cc65/assignment.c index e51dde9ab..0093dc7fa 100644 --- a/src/cc65/assignment.c +++ b/src/cc65/assignment.c @@ -31,7 +31,7 @@ /* */ /*****************************************************************************/ - +//#define DEBUG /* cc65 */ #include "asmcode.h" @@ -48,7 +48,13 @@ #include "typecmp.h" #include "typeconv.h" - +#ifdef DEBUG +#define LOG(x) printf x +#define FIXME(x) printf x +#else +#define LOG(x) +#define FIXME(x) +#endif /*****************************************************************************/ /* Code */ @@ -451,6 +457,8 @@ static void OpAssignArithmetic (const GenDesc* Gen, ExprDesc* Expr, const char* unsigned Flags; int MustScale; + LOG(("OpAssignArithmetic '%s' (Gen=%p)\n", Op, Gen)); + ED_Init (&Expr2); Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR; @@ -465,7 +473,9 @@ static void OpAssignArithmetic (const GenDesc* Gen, ExprDesc* Expr, const char* PushAddr (Expr); if (Gen == 0) { - +// printf("OpAssignArithmetic (gen=0) 1 lhs: %s rhs: %s\n", +// (TypeOf (Expr->Type) == CF_FLOAT) ? "float" : "int", +// (TypeOf (Expr2.Type) == CF_FLOAT) ? "float" : "int"); /* Read the expression on the right side of the '=' */ MarkedExprWithCheck (hie1, &Expr2); @@ -477,8 +487,11 @@ static void OpAssignArithmetic (const GenDesc* Gen, ExprDesc* Expr, const char* /* If necessary, load the value into the primary register */ LoadExpr (CF_NONE, &Expr2); + LOG(("OpAssignArithmetic '%s' (0) 2 lhs: %s rhs: %s\n", + Op, + (TypeOf (Expr->Type) == CF_FLOAT) ? "float" : "int", + (TypeOf (Expr2.Type) == CF_FLOAT) ? "float" : "int")); } else { - /* Load the original value if necessary */ LoadExpr (CF_NONE, Expr); @@ -489,8 +502,14 @@ static void OpAssignArithmetic (const GenDesc* Gen, ExprDesc* Expr, const char* /* Read the expression on the right side of the '=' or 'op=' */ MarkedExprWithCheck (hie1, &Expr2); - /* The rhs must be an integer (or a float, but we don't support that yet */ - if (!IsClassInt (Expr2.Type)) { + LOG(("OpAssignArithmetic '%s' (!=0) 2 lhs: %s rhs: %s\n", + Op, + (TypeOf (Expr->Type) == CF_FLOAT) ? "float" : "int", + (TypeOf (Expr2.Type) == CF_FLOAT) ? "float" : "int")); + + + /* The rhs must be an integer or a float */ + if (!IsClassInt (Expr2.Type) && !IsClassFloat (Expr2.Type)) { Error ("Invalid right operand for binary operator '%s'", Op); /* Continue. Wrong code will be generated, but the compiler won't ** break, so this is the best error recovery. @@ -523,9 +542,19 @@ static void OpAssignArithmetic (const GenDesc* Gen, ExprDesc* Expr, const char* /* Special handling for add and sub - some sort of a hack, but short code */ if (Gen->Func == g_add) { - g_inc (Flags | CF_CONST, Expr2.IVal); + LOG(("OpAssignArithmetic '%s' gen g_add\n", Op)); + if (IsClassFloat (Expr2.Type)) { + g_inc (Flags | CF_CONST, FP_D_As32bitRaw(Expr2.V.FVal)); + } else { + g_inc (Flags | CF_CONST, Expr2.IVal); + } } else if (Gen->Func == g_sub) { - g_dec (Flags | CF_CONST, Expr2.IVal); + LOG(("OpAssignArithmetic '%s' gen g_sub\n", Op)); + if (IsClassFloat (Expr2.Type)) { + g_dec (Flags | CF_CONST, FP_D_As32bitRaw(Expr2.V.FVal)); + } else { + g_dec (Flags | CF_CONST, Expr2.IVal); + } } else { if (!ED_IsUneval (Expr)) { if (Expr2.IVal == 0 && !ED_IsUneval (Expr)) { @@ -605,6 +634,8 @@ void OpAssign (const GenDesc* Gen, ExprDesc* Expr, const char* Op) { const Type* ltype = Expr->Type; + LOG(("OpAssign\n")); + ExprDesc Expr2; ED_Init (&Expr2); Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR; @@ -677,8 +708,9 @@ void OpAddSubAssign (const GenDesc* Gen, ExprDesc *Expr, const char* Op) return; } - /* There must be an integer or pointer on the left side */ - if (!IsClassInt (Expr->Type) && !IsTypePtr (Expr->Type)) { + LOG(("OpAddSubAssign '%s'\n", Op)); + /* There must be an integer, pointer or float on the left side */ + if (!IsClassInt (Expr->Type) && !IsTypePtr (Expr->Type) && !IsTypeFloat (Expr->Type)) { Error ("Invalid left operand for binary operator '%s'", Op); /* Continue. Wrong code will be generated, but the compiler won't ** break, so this is the best error recovery. @@ -706,11 +738,9 @@ void OpAddSubAssign (const GenDesc* Gen, ExprDesc *Expr, const char* Op) ED_Init (&Expr2); Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR; - /* Evaluate the rhs. We expect an integer here, since float is not - ** supported - */ + /* Evaluate the rhs. We expect an integer or float here */ hie1 (&Expr2); - if (!IsClassInt (Expr2.Type)) { + if (!IsClassInt (Expr2.Type) && !IsClassFloat (Expr2.Type)) { Error ("Invalid right operand for binary operator '%s'", Op); /* Continue. Wrong code will be generated, but the compiler won't ** break, so this is the best error recovery. @@ -721,7 +751,10 @@ void OpAddSubAssign (const GenDesc* Gen, ExprDesc *Expr, const char* Op) lflags |= CG_TypeOf (Expr->Type) | CG_AddrModeFlags (Expr) | CF_FORCECHAR; rflags |= CG_TypeOf (Expr2.Type) | CF_FORCECHAR; + LOG(("OpAddSubAssign '%s' lflags:%04x rflags:%04x\n", Op, lflags, rflags)); + if (ED_IsConstAbs (&Expr2)) { + LOG(("OpAddSubAssign '%s' result is constant\n", Op)); /* The resulting value is a constant */ rflags |= CF_CONST; lflags |= CF_CONST; @@ -731,6 +764,7 @@ void OpAddSubAssign (const GenDesc* Gen, ExprDesc *Expr, const char* Op) Expr2.IVal *= CheckedSizeOf (Indirect (Expr->Type)); } } else { + LOG(("OpAddSubAssign '%s' result is not constant\n", Op)); /* Not constant, load into the primary */ LoadExpr (CF_NONE, &Expr2); @@ -756,19 +790,40 @@ void OpAddSubAssign (const GenDesc* Gen, ExprDesc *Expr, const char* Op) ** static variable, register variable, pooled literal or code ** label location. */ - if (Gen->Tok == TOK_PLUS_ASSIGN) { - g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); + if (IsClassFloat (Expr->Type)) { + LOG(("OpAddSubAssign '%s' abs, float %08x (IVal:%08lx)\n", Op, FP_D_As32bitRaw(Expr2.V.FVal), Expr2.IVal)); + /* FIXME: what about the case when expr2 is NOT float? */ + if (Gen->Tok == TOK_PLUS_ASSIGN) { + g_addeqstatic (lflags, Expr->Name, Expr->IVal, FP_D_As32bitRaw(Expr2.V.FVal)); + } else { + g_subeqstatic (lflags, Expr->Name, Expr->IVal, FP_D_As32bitRaw(Expr2.V.FVal)); + } } else { - g_subeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); + LOG(("OpAddSubAssign '%s' abs, int\n", Op)); + if (Gen->Tok == TOK_PLUS_ASSIGN) { + g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); + } else { + g_subeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); + } } break; case E_LOC_STACK: /* Value on the stack */ - if (Gen->Tok == TOK_PLUS_ASSIGN) { - g_addeqlocal (lflags, Expr->IVal, Expr2.IVal); + if (IsClassFloat (Expr->Type)) { + LOG(("OpAddSubAssign '%s' stack, float\n", Op)); + if (Gen->Tok == TOK_PLUS_ASSIGN) { + g_addeqlocal (lflags, Expr->IVal, FP_D_As32bitRaw(Expr2.V.FVal)); + } else { + g_subeqlocal (lflags, Expr->IVal, FP_D_As32bitRaw(Expr2.V.FVal)); + } } else { - g_subeqlocal (lflags, Expr->IVal, Expr2.IVal); + LOG(("OpAddSubAssign '%s' stack, int\n", Op)); + if (Gen->Tok == TOK_PLUS_ASSIGN) { + g_addeqlocal (lflags, Expr->IVal, Expr2.IVal); + } else { + g_subeqlocal (lflags, Expr->IVal, Expr2.IVal); + } } break; diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index 69dcc1c6c..05eca7f9a 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -31,7 +31,7 @@ /* */ /*****************************************************************************/ - +//#define DEBUG #include #include @@ -44,6 +44,7 @@ #include "attrib.h" #include "check.h" #include "cpu.h" +#include "fp.h" #include "shift.h" #include "strbuf.h" #include "xmalloc.h" @@ -80,19 +81,30 @@ /* Helpers */ /*****************************************************************************/ +#ifdef DEBUG +#define LOG(x) printf x +#define FIXME(x) printf x +#define ASMLOG(x) AddCodeLine x +#else +#define LOG(x) +#define FIXME(x) +#define ASMLOG(x) +#endif -static void typeerror (unsigned type) + +static void _typeerror (char *func, int line, unsigned type) /* Print an error message about an invalid operand type */ { /* Special handling for floats here: */ if ((type & CF_TYPEMASK) == CF_FLOAT) { - Fatal ("Floating point type is currently unsupported"); + Fatal ("%s:%d Floating point type is currently unsupported", func, line); } else { - Internal ("Invalid type in CF flags: %04X, type = %u", type, type & CF_TYPEMASK); + Internal ("%s:%d Invalid type in CF flags: %04X, type = %u", func, line, type, type & CF_TYPEMASK); } } +#define typeerror(t) _typeerror(__FILE__, __LINE__, t) static void CheckLocalOffs (unsigned Offs) @@ -699,13 +711,28 @@ void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes) /* Fetching memory cells */ /*****************************************************************************/ - - -void g_getimmed (unsigned Flags, uintptr_t Val, long Offs) +#ifdef DEBUG +//#define g_getimmed(a,b,c) _g_getimmed((a),(b),(c),(__FILE__),(__FUNCTION__),(__LINE__)) +// void _g_getimmed(unsigned Flags, uintptr_t Val, long Offs, char *file, const char *func, int line) +#define g_getimmed(a,b,c) _g_getimmed((a),(b),(c)) +void _g_getimmed(unsigned Flags, uintptr_t Val, long Offs) +#else +#define g_getimmed(a,b,c) _g_getimmed((a),(b),(c)) +void _g_getimmed(unsigned Flags, uintptr_t Val, long Offs) +#endif /* Load a constant into the primary register */ { unsigned char B1, B2, B3, B4; +// LOG(("file:%s\n", file ? file : "null")); +// LOG(("func:%s\n", func ? func : "null")); + +// LOG(("g_getimmed %s:%d:%s Flags:%04x Val: %08x Offs:%04x\n", +// file ? file : "null", line, func ? func : "null", Flags, Val, Offs)); + LOG(("g_getimmed Flags:%04x Val: %08lx Offs:%04lx\n", + Flags, Val, Offs)); + ASMLOG(("nop ;> g_getimmed Flags:%04x Val: %08lx Offs:%04lx\n", + Flags, Val, Offs)); if ((Flags & CF_CONST) != 0) { @@ -713,16 +740,25 @@ void g_getimmed (unsigned Flags, uintptr_t Val, long Offs) switch (Flags & CF_TYPEMASK) { case CF_CHAR: + LOG(("g_getimmed CF_CHAR Val: %08lx\n", Val)); + ASMLOG(("nop\t; g_getimmed CF_CHAR %08lx\n", Val)); // FIXME: remove if ((Flags & CF_FORCECHAR) != 0) { AddCodeLine ("lda #$%02X", (unsigned char) Val); break; } /* FALL THROUGH */ case CF_INT: + LOG(("g_getimmed CF_INT Val: %08lx\n", Val)); + ASMLOG(("nop\t; g_getimmed CF_INT %08lx\n", Val)); // FIXME: remove AddCodeLine ("ldx #$%02X", (unsigned char) (Val >> 8)); AddCodeLine ("lda #$%02X", (unsigned char) Val); break; + case CF_FLOAT: /* FIXME float - handle like long here */ + /* CAUTION: make sure Val contains the float value in raw binary format */ + LOG(("g_getimmed CF_FLOAT Val: %08lx\n", Val)); + ASMLOG(("nop\t; g_getimmed FLOAT %08lx\n", Val)); // FIXME: remove + /* fall through */ case CF_LONG: /* Split the value into 4 bytes */ B1 = (unsigned char) (Val >> 0); @@ -757,6 +793,7 @@ void g_getimmed (unsigned Flags, uintptr_t Val, long Offs) AddCodeLine ("ldx #>(%s)", Label); } + ASMLOG(("nop ;< g_getimmed\n")); } @@ -767,6 +804,9 @@ void g_getstatic (unsigned flags, uintptr_t label, long offs) /* Create the correct label name */ const char* lbuf = GetLabelName (flags, label, offs); + LOG(("g_getstatic flags:%04x offs:%04lx label:%04lx\n", flags, offs, label)); + ASMLOG(("nop ; g_getstatic flags:%04x offs:%04lx label:%04lx\n", flags, offs, label)); + /* Check the size and generate the correct load operation */ switch (flags & CF_TYPEMASK) { @@ -795,6 +835,8 @@ void g_getstatic (unsigned flags, uintptr_t label, long offs) } break; + case CF_FLOAT: /* FIXME: float - can we really use the same as LONG? */ + /* FIXME: float - what is the CF_TEST about? */ case CF_LONG: if (flags & CF_TEST) { AddCodeLine ("lda %s+3", lbuf); @@ -820,7 +862,7 @@ void g_getstatic (unsigned flags, uintptr_t label, long offs) void g_getlocal (unsigned Flags, int Offs) -/* Fetch specified local object (local var). */ +/* Fetch specified local object (local var) into the primary register */ { Offs -= StackPtr; switch (Flags & CF_TYPEMASK) { @@ -855,6 +897,8 @@ void g_getlocal (unsigned Flags, int Offs) } break; + case CF_FLOAT: /* FIXME: float - can we really use the same as LONG? */ + case CF_LONG: CheckLocalOffs (Offs + 3); AddCodeLine ("ldy #$%02X", (unsigned char) (Offs+3)); @@ -876,6 +920,7 @@ void g_getind (unsigned Flags, unsigned Offs) ** into the primary register */ { + LOG(("g_getind flags:%04x offs:%04x\n", Flags, Offs)); /* If the offset is greater than 255, add the part that is > 255 to ** the primary. This way we get an easy addition and use the low byte ** as the offset @@ -909,6 +954,8 @@ void g_getind (unsigned Flags, unsigned Offs) } break; + case CF_FLOAT: /* FIXME: float - can we really use the same as LONG here? */ + case CF_LONG: AddCodeLine ("ldy #$%02X", Offs+3); AddCodeLine ("jsr ldeaxidx"); @@ -1058,6 +1105,8 @@ void g_putstatic (unsigned flags, uintptr_t label, long offs) AddCodeLine ("stx %s+1", lbuf); break; + case CF_FLOAT: /* FIXME: float - can we really use the same as LONG? */ + case CF_LONG: AddCodeLine ("sta %s", lbuf); AddCodeLine ("stx %s+1", lbuf); @@ -1078,6 +1127,7 @@ void g_putstatic (unsigned flags, uintptr_t label, long offs) void g_putlocal (unsigned Flags, int Offs, long Val) /* Put data into local object. */ { + LOG(("g_putlocal Flags:%04x Offs:%d val: %ld\n", Flags, Offs, Val)); Offs -= StackPtr; CheckLocalOffs (Offs); switch (Flags & CF_TYPEMASK) { @@ -1121,6 +1171,9 @@ void g_putlocal (unsigned Flags, int Offs, long Val) } break; + case CF_FLOAT: /* FIXME: float - can we use the same as LONG here? */ + ASMLOG(("nop ; g_putlocal")); // FIXME: remove + /* fall through */ case CF_LONG: if (Flags & CF_CONST) { g_getimmed (Flags, Val, 0); @@ -1271,6 +1324,9 @@ static void g_regchar (unsigned to) ** and convert it to an int (whose representation is irrelevent of signedness). */ { + LOG(("g_regchar flags: %04x\n", to)); + ASMLOG(("nop ; g_regchar flags: %04x\n", to)); // FIXME:remove + /* Since char is the smallest type supported here, we never need any info ** about the original type to "promote from it". However, we have to make ** sure the entire AX contains the correct char value as an int, since we @@ -1284,12 +1340,13 @@ static void g_regchar (unsigned to) } - void g_regint (unsigned from) /* Convert the value in the primary register to an int (whose representation ** is irrelevent of signedness). */ { + LOG(("g_regint flags: %04x\n", from)); + ASMLOG(("nop ; g_regint flags: %04x\n", from)); // FIXME:remove switch (from & CF_TYPEMASK) { case CF_CHAR: @@ -1316,18 +1373,24 @@ void g_regint (unsigned from) case CF_LONG: break; + /* FIXME: float */ + case CF_FLOAT: + AddCodeLine ("jsr feaxint"); + break; + default: typeerror (from); } } - void g_reglong (unsigned from) /* Convert the value in the primary register to a long (whose representation ** is irrelevent of signedness). */ { + LOG(("g_reglong flags: %04x\n", from)); + ASMLOG(("nop ; g_reglong flags: %04x\n", from)); switch (from & CF_TYPEMASK) { case CF_CHAR: @@ -1375,12 +1438,61 @@ void g_reglong (unsigned from) case CF_LONG: break; + /* FIXME: float */ + case CF_FLOAT: + AddCodeLine ("jsr feaxlong"); + break; + default: typeerror (from); } } +void g_regfloat (unsigned from) +/* Convert the value in the primary register to a float */ +{ + LOG(("g_regfloat flags: %04x\n", from)); + ASMLOG(("nop ; g_regfloat flags: %04x\n", from)); + switch (from & CF_TYPEMASK) { + + case CF_CHAR: + if (from & CF_FORCECHAR) { + /* Conversion is from char */ + if (from & CF_UNSIGNED) { + AddCodeLine ("jsr aufloat"); + } else { + AddCodeLine ("jsr afloat"); + } + break; + } + /* FALLTHROUGH */ + + case CF_INT: + if (from & CF_UNSIGNED) { + AddCodeLine ("jsr axufloat"); + } else { + AddCodeLine ("jsr axfloat"); + } + break; + + case CF_LONG: + if (from & CF_UNSIGNED) { + AddCodeLine ("jsr eaxufloat"); + } else { + AddCodeLine ("jsr eaxfloat"); + } + break; + + case CF_FLOAT: + /* do nothing */ + break; + + default: + typeerror (from); + } +} + static unsigned g_intpromotion (unsigned flags) /* Return new flags for integral promotions for types smaller than int. */ @@ -1424,6 +1536,36 @@ unsigned g_typeadjust (unsigned lhs, unsigned rhs) unsigned ltype = lhs & CF_TYPEMASK; unsigned rtype = rhs & CF_TYPEMASK; + /* Result is const if both operands are const. */ + unsigned const_flag = (lhs & CF_CONST) & (rhs & CF_CONST); + + LOG((">g_typeadjust ltype:%02x rtype:%02x\n", ltype, rtype)); // FIXME: remove + ASMLOG(("nop ;>g_typeadjust ltype:%02x rtype:%02x", ltype, rtype)); // FIXME: remove + + /* FIXME: float - this is much much more complicated */ + if (ltype == CF_FLOAT && rtype == CF_FLOAT) { +// g_regfloat (rhs); + LOG((" Operate on ints ** 1 --> Operate on unsigneds ** 2 --> Operate on longs ** 3 --> Operate on unsigned longs +** 4 --> Operate on floats (CAUTION: Val must be a float in raw binary format) */ { + int n = 0; + ASMLOG(("nop ; oper(%2x,%lx)", Flags, Val)); // FIXME: remove /* Determine the offset into the array */ - if (Flags & CF_UNSIGNED) { - ++Subs; - } - if ((Flags & CF_TYPEMASK) == CF_LONG) { - Subs += 2; + if (Flags & CF_FLOAT) { + n = OPER_IDX_FLOAT; + } else { + if (Flags & CF_UNSIGNED) { + n = 1; /* odd means unsigned */ + } + if ((Flags & CF_TYPEMASK) == CF_LONG) { + n += 2; + } } /* Load the value if it is not already in the primary */ if (Flags & CF_CONST) { /* Load value */ + ASMLOG(("nop ; oper(%2x,%lx)", Flags, Val)); // FIXME: remove g_getimmed (Flags, Val, 0); } - /* Output the operation */ - AddCodeLine ("jsr %s", *Subs); - + if (Subs[n] == NULL) { + Internal("oper Subs NULL (%d)", n); + } else { + /* Output the operation */ + AddCodeLine ("jsr %s", Subs[n]); + } /* The operation will pop it's argument */ pop (Flags); } @@ -2399,18 +2649,20 @@ void g_test (unsigned flags) void g_push (unsigned flags, unsigned long val) /* Push the primary register or a constant value onto the stack */ { - if (flags & CF_CONST && (flags & CF_TYPEMASK) != CF_LONG) { + if (flags & CF_CONST && ((flags & CF_TYPEMASK) < CF_LONG)) { /* We have a constant 8 or 16 bit value */ if ((flags & CF_TYPEMASK) == CF_CHAR && (flags & CF_FORCECHAR)) { /* Handle as 8 bit value */ + ASMLOG(("nop ; g_push 8bit const")); // FIXME: remove AddCodeLine ("lda #$%02X", (unsigned char) val); AddCodeLine ("jsr pusha"); } else { /* Handle as 16 bit value */ + ASMLOG(("nop ; g_push 16bit const")); // FIXME: remove g_getimmed (flags, val, 0); AddCodeLine ("jsr pushax"); } @@ -2420,8 +2672,10 @@ void g_push (unsigned flags, unsigned long val) /* Value is not 16 bit or not constant */ if (flags & CF_CONST) { /* Constant 32 bit value, load into eax */ + ASMLOG(("nop ; g_push load val into eax")); // FIXME: remove g_getimmed (flags, val, 0); } + ASMLOG(("nop ; g_push value")); // FIXME: remove /* Push the primary register */ switch (flags & CF_TYPEMASK) { @@ -2437,6 +2691,11 @@ void g_push (unsigned flags, unsigned long val) AddCodeLine ("jsr pushax"); break; + case CF_FLOAT: + /* FIXME: float - handle like long here */ + AddCodeLine ("jsr pusheax"); + break; + case CF_LONG: AddCodeLine ("jsr pusheax"); break; @@ -2452,6 +2711,50 @@ void g_push (unsigned flags, unsigned long val) push (flags); } +/* FIXME: float */ +void g_push_float (unsigned flags, double val) +/* Push the primary register or a constant value onto the stack */ +{ +// LOG(("g_push_float flags:%04x val:%f\n", flags, val)); + /* Push the primary register */ + switch (flags & CF_TYPEMASK) { + + case CF_FLOAT: /* FIXME: float - handle like long here */ + /* Value is not 16 bit or not constant */ +// if (flags & CF_CONST) + { +// float f = val; +#if 0 + uintptr_t *p = &val; /* FIXME: float - we shouldnt do this :) */ + /* Constant 32 bit value, load into eax */ + LOG(("g_push_float flags:%04x f:%p\n", flags, *p)); + g_getimmed (flags | CF_CONST, *p, 0); // ?? FIXME +#endif +#if 0 + uint32_t *p = ((uint32_t*)&val); /* FIXME: float - we shouldnt do this :) */ + /* Constant 32 bit value, load into eax */ + LOG(("g_push_float flags:%04x f:%p\n", flags, *p)); + AddCodeLine ("nop ; g_push_float"); // FIXME: remove + g_getimmed (flags | CF_CONST, *p, 0); // ?? FIXME +#endif +// g_getimmed (0x41,*p,0); +#if 1 + LOG(("g_push_float flags:%04x\n", flags)); + ASMLOG(("nop ; g_push_float")); // FIXME: remove + g_getimmed (flags | CF_CONST, FP_D_As32bitRaw(FP_D_Make(val)), 0); // ?? FIXME +#endif + } + AddCodeLine ("jsr pusheax"); + break; + + default: + typeerror (flags); + + } + + /* Adjust the stack offset */ + push (flags); +} void g_swap (unsigned flags) @@ -2650,14 +2953,19 @@ void g_stackcheck (void) void g_add (unsigned flags, unsigned long val) /* Primary = TOS + Primary */ { - static const char* const ops[4] = { - "tosaddax", "tosaddax", "tosaddeax", "tosaddeax" + static const char* const ops[OPER_IDX_NUM] = { + "tosaddax", + "tosaddax", /* unsigned */ + "tosaddeax", + "tosaddeax", /* unsigned, 32bit */ + "ftosaddeax" /* float, 32bit */ }; if (flags & CF_CONST) { flags &= ~CF_FORCECHAR; /* Handle chars as ints */ g_push (flags & ~CF_CONST, 0); } + ASMLOG(("nop ; g_add(flags:%2x,val:%lx)", flags, val)); // FIXME: remove oper (flags, val, ops); } @@ -2666,14 +2974,19 @@ void g_add (unsigned flags, unsigned long val) void g_sub (unsigned flags, unsigned long val) /* Primary = TOS - Primary */ { - static const char* const ops[4] = { - "tossubax", "tossubax", "tossubeax", "tossubeax" + static const char* const ops[OPER_IDX_NUM] = { + "tossubax", + "tossubax", /* unsigned */ + "tossubeax", + "tossubeax", /* unsigned, 32bit */ + "ftossubeax" /* float, 32bit */ }; if (flags & CF_CONST) { flags &= ~CF_FORCECHAR; /* Handle chars as ints */ g_push (flags & ~CF_CONST, 0); } + ASMLOG(("nop ; g_sub(flags:%2x,val:%lx)", flags, val)); // FIXME: remove oper (flags, val, ops); } @@ -2682,9 +2995,14 @@ void g_sub (unsigned flags, unsigned long val) void g_rsub (unsigned flags, unsigned long val) /* Primary = Primary - TOS */ { - static const char* const ops[4] = { - "tosrsubax", "tosrsubax", "tosrsubeax", "tosrsubeax" + static const char* const ops[OPER_IDX_NUM] = { + "tosrsubax", + "tosrsubax", + "tosrsubeax", + "tosrsubeax", + "ftosrsubeax" }; + ASMLOG(("nop ; g_rsub(flags:%2x,val:%lx)", flags, val)); // FIXME: remove oper (flags, val, ops); } @@ -2693,12 +3011,18 @@ void g_rsub (unsigned flags, unsigned long val) void g_mul (unsigned flags, unsigned long val) /* Primary = TOS * Primary */ { - static const char* const ops[4] = { - "tosmulax", "tosumulax", "tosmuleax", "tosumuleax" + static const char* const ops[OPER_IDX_NUM] = { + "tosmulax", + "tosumulax", + "tosmuleax", + "tosumuleax", + "ftosmuleax" }; + LOG(("g_mul flags:%04x val:%ld\n", flags, val)); + /* Do strength reduction if the value is constant and a power of two */ - if (flags & CF_CONST) { + if ((flags & CF_CONST) && ((flags & CF_TYPEMASK) != CF_FLOAT)) { /* Deal with negative values if it's signed multiplication */ int Negation = (flags & CF_UNSIGNED) == 0 && (long)val < 0; @@ -2706,6 +3030,7 @@ void g_mul (unsigned flags, unsigned long val) /* Check if we can use shift instead of multiplication */ if (p2 == 0 || (p2 > 0 && IS_Get (&CodeSizeFactor) >= (Negation ? 100 : 0))) { + LOG(("g_mul doing strength reduction\n")); /* Generate a shift instead */ g_asl (flags, p2); @@ -2801,6 +3126,8 @@ void g_mul (unsigned flags, unsigned long val) } break; + case CF_FLOAT: /* FIXME: float: is it the right thing here to do the same as LONG? */ + case CF_LONG: break; @@ -2815,6 +3142,7 @@ void g_mul (unsigned flags, unsigned long val) g_push (flags & ~CF_CONST, 0); } + ASMLOG(("nop ; g_mul(flags:%2x,val:%lx)", flags, val)); // FIXME: remove /* Use long way over the stack */ oper (flags, val, ops); @@ -2825,98 +3153,109 @@ void g_mul (unsigned flags, unsigned long val) void g_div (unsigned flags, unsigned long val) /* Primary = TOS / Primary */ { - static const char* const ops[4] = { - "tosdivax", "tosudivax", "tosdiveax", "tosudiveax" + static const char* const ops[OPER_IDX_NUM] = { + "tosdivax", + "tosudivax", + "tosdiveax", + "tosudiveax", + "ftosdiveax" }; + LOG(("g_div flags:%04x val:%ld\n", flags, val)); + ASMLOG(("nop ; g_div(flags:%2x,val:%lx)", flags, val)); // FIXME: remove + /* Do strength reduction if the value is constant and a power of two */ if (flags & CF_CONST) { - /* Deal with negative values as well as different sizes */ - int Negation = (flags & CF_UNSIGNED) == 0 && (long)val < 0; - unsigned long NegatedVal = 0UL - val; - int p2 = PowerOf2 (Negation ? NegatedVal : val); + if ((flags & CF_TYPEMASK) != CF_FLOAT) { + /* Deal with negative values as well as different sizes */ + int Negation = (flags & CF_UNSIGNED) == 0 && (long)val < 0; + unsigned long NegatedVal = 0UL - val; + int p2 = PowerOf2 (Negation ? NegatedVal : val); - /* Generate a shift instead */ - if ((flags & CF_UNSIGNED) != 0 && p2 > 0) { - g_asr (flags, p2); - return; - } + LOG(("g_div doing strength reduction\n")); - /* Check if we can afford using shift instead of multiplication at the - ** cost of code size */ - if (p2 == 0 || (p2 > 0 && IS_Get (&CodeSizeFactor) >= (Negation ? 200 : 170))) { - /* Generate a conditional shift instead */ - if (p2 > 0) { - unsigned int DoShiftLabel = GetLocalLabel (); - unsigned int EndLabel = GetLocalLabel (); - unsigned long MaskedVal = Negation ? val : NegatedVal; + /* Generate a shift instead */ + if ((flags & CF_UNSIGNED) != 0 && p2 > 0) { + g_asr (flags, p2); + return; + } - /* GitHub #169 - if abs(expr) < abs(val), the result is always 0. - ** First, check whether expr >= 0 and skip to the shift if true. - */ - switch (flags & CF_TYPEMASK) { - case CF_CHAR: - if (flags & CF_FORCECHAR) { - MaskedVal &= 0xFF; - AddCodeLine ("cmp #$00"); + /* Check if we can afford using shift instead of multiplication at the + ** cost of code size */ + if (p2 == 0 || (p2 > 0 && IS_Get (&CodeSizeFactor) >= (Negation ? 200 : 170))) { + /* Generate a conditional shift instead */ + if (p2 > 0) { + unsigned int DoShiftLabel = GetLocalLabel (); + unsigned int EndLabel = GetLocalLabel (); + unsigned long MaskedVal = Negation ? val : NegatedVal; + + /* GitHub #169 - if abs(expr) < abs(val), the result is always 0. + ** First, check whether expr >= 0 and skip to the shift if true. + */ + switch (flags & CF_TYPEMASK) { + case CF_CHAR: + if (flags & CF_FORCECHAR) { + MaskedVal &= 0xFF; + AddCodeLine ("cmp #$00"); + AddCodeLine ("bpl %s", LocalLabelName (DoShiftLabel)); + break; + } + /* FALLTHROUGH */ + + case CF_INT: + MaskedVal &= 0xFFFF; + AddCodeLine ("cpx #$00"); AddCodeLine ("bpl %s", LocalLabelName (DoShiftLabel)); break; + + case CF_LONG: + MaskedVal &= 0xFFFFFFFF; + AddCodeLine ("ldy sreg+1"); + AddCodeLine ("bpl %s", LocalLabelName (DoShiftLabel)); + break; + + default: + typeerror (flags); + break; } - /* FALLTHROUGH */ + /* Second, check whether expr <= -asb(val) and skip to the + ** shift if true. The original content of expr has to be saved + ** before the checking comparison and restored after that, as + ** the content in Primary register will be destroyed. + ** The result of the comparison is a boolean. We can store + ** it in the Carry flag with a LSR and branch on it later. + */ + g_save (flags); + g_le (flags | CF_UNSIGNED, MaskedVal); + AddCodeLine ("lsr a"); + g_restore (flags); + AddCodeLine ("bcs %s", LocalLabelName (DoShiftLabel)); - case CF_INT: - MaskedVal &= 0xFFFF; - AddCodeLine ("cpx #$00"); - AddCodeLine ("bpl %s", LocalLabelName (DoShiftLabel)); - break; + /* The result is 0. We can just load 0 and skip the shifting. */ + g_getimmed (flags | CF_ABSOLUTE, 0, 0); - case CF_LONG: - MaskedVal &= 0xFFFFFFFF; - AddCodeLine ("ldy sreg+1"); - AddCodeLine ("bpl %s", LocalLabelName (DoShiftLabel)); - break; + /* TODO: replace with BEQ? Would it be optimized? */ + g_jump (EndLabel); - default: - typeerror (flags); - break; + /* Do the shift. The sign of the result may need to be corrected + ** later. + */ + g_defcodelabel (DoShiftLabel); + g_asr (flags, p2); + g_defcodelabel (EndLabel); } - /* Second, check whether expr <= -asb(val) and skip to the - ** shift if true. The original content of expr has to be saved - ** before the checking comparison and restored after that, as - ** the content in Primary register will be destroyed. - ** The result of the comparison is a boolean. We can store - ** it in the Carry flag with a LSR and branch on it later. + + /* Negate the result as long as val < 0, even if val == -1 and no + ** shift was generated. */ - g_save (flags); - g_le (flags | CF_UNSIGNED, MaskedVal); - AddCodeLine ("lsr a"); - g_restore (flags); - AddCodeLine ("bcs %s", LocalLabelName (DoShiftLabel)); + if (Negation) { + g_neg (flags); + } - /* The result is 0. We can just load 0 and skip the shifting. */ - g_getimmed (flags | CF_ABSOLUTE, 0, 0); - - /* TODO: replace with BEQ? Would it be optimized? */ - g_jump (EndLabel); - - /* Do the shift. The sign of the result may need to be corrected - ** later. - */ - g_defcodelabel (DoShiftLabel); - g_asr (flags, p2); - g_defcodelabel (EndLabel); + /* Done */ + return; } - - /* Negate the result as long as val < 0, even if val == -1 and no - ** shift was generated. - */ - if (Negation) { - g_neg (flags); - } - - /* Done */ - return; } /* If we go here, we didn't emit code. Push the lhs on stack and fall @@ -2936,11 +3275,17 @@ void g_div (unsigned flags, unsigned long val) void g_mod (unsigned flags, unsigned long val) /* Primary = TOS % Primary */ { - static const char* const ops[4] = { - "tosmodax", "tosumodax", "tosmodeax", "tosumodeax" + static const char* const ops[OPER_IDX_NUM] = { + "tosmodax", + "tosumodax", + "tosmodeax", + "tosumodeax", + NULL /* modulo is invalid for float */ }; int p2; + ASMLOG(("nop ; g_mod(flags:%2x,val:%lx)", flags, val)); // FIXME: remove + /* Check if we can do some cost reduction */ if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = PowerOf2 (val)) >= 0) { /* We can do that with an AND operation */ @@ -2961,8 +3306,8 @@ void g_mod (unsigned flags, unsigned long val) void g_or (unsigned flags, unsigned long val) /* Primary = TOS | Primary */ { - static const char* const ops[4] = { - "tosorax", "tosorax", "tosoreax", "tosoreax" + static const char* const ops[OPER_IDX_NUM] = { + "tosorax", "tosorax", "tosoreax", "tosoreax", NULL }; /* If the right hand side is const, the lhs is not on stack but still @@ -3021,6 +3366,7 @@ void g_or (unsigned flags, unsigned long val) flags &= ~CF_FORCECHAR; g_push (flags & ~CF_CONST, 0); } + ASMLOG(("nop ; g_or(flags:%2x,val:%lx)", flags, val)); // FIXME: remove /* Use long way over the stack */ oper (flags, val, ops); @@ -3031,8 +3377,8 @@ void g_or (unsigned flags, unsigned long val) void g_xor (unsigned flags, unsigned long val) /* Primary = TOS ^ Primary */ { - static const char* const ops[4] = { - "tosxorax", "tosxorax", "tosxoreax", "tosxoreax" + static const char* const ops[OPER_IDX_NUM] = { + "tosxorax", "tosxorax", "tosxoreax", "tosxoreax", NULL }; @@ -3089,6 +3435,7 @@ void g_xor (unsigned flags, unsigned long val) flags &= ~CF_FORCECHAR; g_push (flags & ~CF_CONST, 0); } + ASMLOG(("nop ; g_xor(flags:%2x,val:%lx)", flags, val)); // FIXME: remove /* Use long way over the stack */ oper (flags, val, ops); @@ -3099,8 +3446,8 @@ void g_xor (unsigned flags, unsigned long val) void g_and (unsigned Flags, unsigned long Val) /* Primary = TOS & Primary */ { - static const char* const ops[4] = { - "tosandax", "tosandax", "tosandeax", "tosandeax" + static const char* const ops[OPER_IDX_NUM] = { + "tosandax", "tosandax", "tosandeax", "tosandeax", NULL }; /* If the right hand side is const, the lhs is not on stack but still @@ -3181,6 +3528,7 @@ void g_and (unsigned Flags, unsigned long Val) Flags &= ~CF_FORCECHAR; g_push (Flags & ~CF_CONST, 0); } + ASMLOG(("nop ; g_and(flags:%2x,val:%lx)", Flags, Val)); // FIXME: remove /* Use long way over the stack */ oper (Flags, Val, ops); @@ -3191,8 +3539,8 @@ void g_and (unsigned Flags, unsigned long Val) void g_asr (unsigned flags, unsigned long val) /* Primary = TOS >> Primary */ { - static const char* const ops[4] = { - "tosasrax", "tosshrax", "tosasreax", "tosshreax" + static const char* const ops[OPER_IDX_NUM] = { + "tosasrax", "tosshrax", "tosasreax", "tosshreax", NULL }; /* If the right hand side is const, the lhs is not on stack, but still @@ -3363,6 +3711,7 @@ void g_asr (unsigned flags, unsigned long val) flags &= ~CF_FORCECHAR; g_push (flags & ~CF_CONST, 0); } + ASMLOG(("nop ; g_asr(flags:%2x,val:%lx)", flags, val)); // FIXME: remove /* Use long way over the stack */ oper (flags, val, ops); @@ -3373,8 +3722,8 @@ void g_asr (unsigned flags, unsigned long val) void g_asl (unsigned flags, unsigned long val) /* Primary = TOS << Primary */ { - static const char* const ops[4] = { - "tosaslax", "tosshlax", "tosasleax", "tosshleax" + static const char* const ops[OPER_IDX_NUM] = { + "tosaslax", "tosshlax", "tosasleax", "tosshleax", NULL }; /* If the right hand side is const, the lhs is not on stack, but still @@ -3487,6 +3836,7 @@ void g_asl (unsigned flags, unsigned long val) flags &= ~CF_FORCECHAR; g_push (flags & ~CF_CONST, 0); } + ASMLOG(("nop ; g_asl(flags:%2x,val:%lx)", flags, val)); // FIXME: remove /* Use long way over the stack */ oper (flags, val, ops); @@ -3516,6 +3866,11 @@ void g_neg (unsigned Flags) AddCodeLine ("jsr negeax"); break; + /* FIXME: float */ + case CF_FLOAT: + AddCodeLine ("jsr fnegeax"); + break; + default: typeerror (Flags); } @@ -3540,6 +3895,11 @@ void g_bneg (unsigned flags) AddCodeLine ("jsr bnegeax"); break; + /* FIXME: float */ + case CF_FLOAT: + AddCodeLine ("jsr fbnegeax"); + break; + default: typeerror (flags); } @@ -3575,8 +3935,13 @@ void g_com (unsigned Flags) void g_inc (unsigned flags, unsigned long val) -/* Increment the primary register by a given number */ +/* Increment the primary register by a given number + if flags contain CF_FLOAT, then val can be a raw binary float. +*/ { + LOG(("g_inc flags:%04x val:%08lx\n", flags, val)); + ASMLOG(("nop ; g_inc flags:%04x val:%08lx", flags, val)); + /* Don't inc by zero */ if (val == 0) { return; @@ -3665,6 +4030,12 @@ void g_inc (unsigned flags, unsigned long val) } break; + /* FIXME: float */ + case CF_FLOAT: + ASMLOG(("nop ; g_inc float")); + g_add (flags | CF_CONST, val); + break; + default: typeerror (flags); @@ -3674,7 +4045,9 @@ void g_inc (unsigned flags, unsigned long val) void g_dec (unsigned flags, unsigned long val) -/* Decrement the primary register by a given number */ +/* Decrement the primary register by a given number + if flags contain CF_FLOAT, then val can be a raw binary float. +*/ { /* Don't dec by zero */ if (val == 0) { @@ -3757,6 +4130,11 @@ void g_dec (unsigned flags, unsigned long val) } break; + /* FIXME: float */ + case CF_FLOAT: + g_sub (flags | CF_CONST, val); + break; + default: typeerror (flags); @@ -3776,12 +4154,16 @@ void g_dec (unsigned flags, unsigned long val) void g_eq (unsigned flags, unsigned long val) /* Test for equal */ { - static const char* const ops[4] = { - "toseqax", "toseqax", "toseqeax", "toseqeax" + static const char* const ops[OPER_IDX_NUM] = { + "toseqax", + "toseqax", + "toseqeax", + "toseqeax", + "ftoseqeax" }; unsigned L; - + LOG(("g_eq flags:%04x val:%ld\n", flags, val)); /* If the right hand side is const, the lhs is not on stack but still ** in the primary register. */ @@ -3809,6 +4191,10 @@ void g_eq (unsigned flags, unsigned long val) case CF_LONG: break; + /* FIXME: float */ + case CF_FLOAT: + break; + default: typeerror (flags); } @@ -3820,6 +4206,10 @@ void g_eq (unsigned flags, unsigned long val) flags &= ~CF_FORCECHAR; g_push (flags & ~CF_CONST, 0); } + else { + LOG(("g_ee rhs not const\n")); + } + ASMLOG(("nop ; g_eq(flags:%2x,val:%lx)", flags, val)); // FIXME: remove /* Use long way over the stack */ oper (flags, val, ops); @@ -3830,8 +4220,12 @@ void g_eq (unsigned flags, unsigned long val) void g_ne (unsigned flags, unsigned long val) /* Test for not equal */ { - static const char* const ops[4] = { - "tosneax", "tosneax", "tosneeax", "tosneeax" + static const char* const ops[OPER_IDX_NUM] = { + "tosneax", + "tosneax", + "tosneeax", + "tosneeax", + "ftosneeax" }; unsigned L; @@ -3863,6 +4257,10 @@ void g_ne (unsigned flags, unsigned long val) case CF_LONG: break; + /* FIXME: float */ + case CF_FLOAT: + break; + default: typeerror (flags); } @@ -3874,6 +4272,7 @@ void g_ne (unsigned flags, unsigned long val) flags &= ~CF_FORCECHAR; g_push (flags & ~CF_CONST, 0); } + ASMLOG(("nop ; g_ne(flags:%2x,val:%lx)", flags, val)); // FIXME: remove /* Use long way over the stack */ oper (flags, val, ops); @@ -3884,11 +4283,16 @@ void g_ne (unsigned flags, unsigned long val) void g_lt (unsigned flags, unsigned long val) /* Test for less than */ { - static const char* const ops[4] = { - "tosltax", "tosultax", "toslteax", "tosulteax" + static const char* const ops[OPER_IDX_NUM] = { + "tosltax", + "tosultax", + "toslteax", + "tosulteax", + "ftoslteax" }; unsigned Label; + ASMLOG(("nop ; g_lt(flags:%2x,val:%lx)", flags, val)); // FIXME: remove /* If the right hand side is const, the lhs is not on stack but still ** in the primary register. @@ -3979,6 +4383,10 @@ void g_lt (unsigned flags, unsigned long val) AddCodeLine ("rol a"); return; + /* FIXME: float */ + case CF_FLOAT: + break; + default: typeerror (flags); } @@ -4023,6 +4431,10 @@ void g_lt (unsigned flags, unsigned long val) /* This one is too costly */ break; + /* FIXME: float */ + case CF_FLOAT: + break; + default: typeerror (flags); } @@ -4046,10 +4458,15 @@ void g_lt (unsigned flags, unsigned long val) void g_le (unsigned flags, unsigned long val) /* Test for less than or equal to */ { - static const char* const ops[4] = { - "tosleax", "tosuleax", "tosleeax", "tosuleeax" + static const char* const ops[OPER_IDX_NUM] = { + "tosleax", + "tosuleax", + "tosleeax", + "tosuleeax", + "ftosleeax" }; + ASMLOG(("nop ; g_le(flags:%2x,val:%lx)", flags, val)); // FIXME: remove /* If the right hand side is const, the lhs is not on stack but still ** in the primary register. @@ -4140,6 +4557,10 @@ void g_le (unsigned flags, unsigned long val) } return; + /* FIXME: float */ + case CF_FLOAT: + break; + default: typeerror (flags); } @@ -4161,10 +4582,15 @@ void g_le (unsigned flags, unsigned long val) void g_gt (unsigned flags, unsigned long val) /* Test for greater than */ { - static const char* const ops[4] = { - "tosgtax", "tosugtax", "tosgteax", "tosugteax" + static const char* const ops[OPER_IDX_NUM] = { + "tosgtax", + "tosugtax", + "tosgteax", + "tosugteax", + "ftosgteax" }; + ASMLOG(("nop ; g_gt(flags:%2x,val:%lx)", flags, val)); // FIXME: remove /* If the right hand side is const, the lhs is not on stack but still ** in the primary register. @@ -4279,6 +4705,11 @@ void g_gt (unsigned flags, unsigned long val) } return; + /* FIXME: float */ + case CF_FLOAT: + ASMLOG(("nop ; g_gt CF_FLOAT")); // FIXME: remove + break; + default: typeerror (flags); } @@ -4300,12 +4731,17 @@ void g_gt (unsigned flags, unsigned long val) void g_ge (unsigned flags, unsigned long val) /* Test for greater than or equal to */ { - static const char* const ops[4] = { - "tosgeax", "tosugeax", "tosgeeax", "tosugeeax" + static const char* const ops[OPER_IDX_NUM] = { + "tosgeax", + "tosugeax", + "tosgeeax", + "tosugeeax", + "ftosgeeax" }; unsigned Label; + ASMLOG(("nop ; g_ge(flags:%2x,val:%lx)", flags, val)); // FIXME: remove /* If the right hand side is const, the lhs is not on stack but still ** in the primary register. @@ -4363,6 +4799,10 @@ void g_ge (unsigned flags, unsigned long val) AddCodeLine ("rol a"); return; + /* FIXME: float */ + case CF_FLOAT: + break; + default: typeerror (flags); } @@ -4392,6 +4832,10 @@ void g_ge (unsigned flags, unsigned long val) AddCodeLine ("jsr boolge"); return; + /* FIXME: float */ + case CF_FLOAT: + break; + default: typeerror (flags); } @@ -4436,6 +4880,10 @@ void g_ge (unsigned flags, unsigned long val) /* This one is too costly */ break; + /* FIXME: float */ + case CF_FLOAT: + break; + default: typeerror (flags); } @@ -4488,7 +4936,12 @@ void g_defdata (unsigned flags, uintptr_t val, long offs) case CF_LONG: AddDataLine ("\t.dword\t$%08"PRIXPTR, val & 0xFFFFFFFF); break; - +#if 0 + case CF_FLOAT: + /* FIXME: float */ + AddDataLine ("\t.dword\t$%08"PRIXPTR"\t; float", val & 0xFFFFFFFF); + break; +#endif default: typeerror (flags); break; @@ -4506,7 +4959,56 @@ void g_defdata (unsigned flags, uintptr_t val, long offs) } } +void g_defdata_float (unsigned flags, uintptr_t val, long offs) +/* Define data with the size given in flags */ +{ + LOG(("g_defdata_float flags:%04x val:%f offs:%04lx\n", flags, (float)val, offs)); + if (flags & CF_CONST) { + /* Numeric constant */ + switch (flags & CF_TYPEMASK) { + + case CF_CHAR: + typeerror (flags); + break; + + case CF_INT: + typeerror (flags); + break; + + case CF_LONG: + typeerror (flags); + break; + + case CF_FLOAT: + /* FIXME: float */ +// AddDataLine ("\t.float\t%f", (float)(val & 0xFFFFFFFF)); +// AddDataLine ("\t.dword\t$%08"PRIXPTR"\t; float", val & 0xFFFFFFFF); + { + /* FIXME: float - convert to binary format, this is super NOGO :) */ +// float f = (float)(val); + unsigned char *p = (unsigned char*)&val; + AddDataLine ("\t.dword\t$%02x%02x%02x%02x\t; float", + p[3],p[2],p[1],p[0]); + } + break; + + default: + typeerror (flags); + break; + + } + + } else { + + /* Create the correct label name */ + const char* Label = GetLabelName (flags, val, offs); + + /* Labels are always 16 bit */ + AddDataLine ("\t.addr\t%s\t; float", Label); + + } +} void g_defbytes (const void* Bytes, unsigned Count) /* Output a row of bytes as a constant */ @@ -4617,10 +5119,13 @@ void g_initstatic (unsigned InitLabel, unsigned VarLabel, unsigned Size) AddCodeLine ("bne %s", LocalLabelName (CodeLabel)); } else { /* Use the easy way here: memcpy() */ + ASMLOG(("nop ; g_initstatic")); // FIXME: remove g_getimmed (CF_STATIC, VarLabel, 0); AddCodeLine ("jsr pushax"); + ASMLOG(("nop ; g_initstatic")); // FIXME: remove g_getimmed (CF_STATIC, InitLabel, 0); AddCodeLine ("jsr pushax"); + ASMLOG(("nop ; g_initstatic")); // FIXME: remove g_getimmed (CF_INT | CF_UNSIGNED | CF_CONST, Size, 0); AddCodeLine ("jsr %s", GetLabelName (CF_EXTERNAL, (uintptr_t) "memcpy", 0)); } diff --git a/src/cc65/codegen.h b/src/cc65/codegen.h index 8e04b45e4..5f09aa252 100644 --- a/src/cc65/codegen.h +++ b/src/cc65/codegen.h @@ -218,6 +218,10 @@ void g_reglong (unsigned from); ** is irrelevent of signedness). */ +void g_regfloat (unsigned from); +/* Convert the value in the primary register to a float +*/ + unsigned g_typeadjust (unsigned lhs, unsigned rhs); /* Adjust the integer operands before doing a binary operation. lhs is a flags ** value, that corresponds to the value on TOS, rhs corresponds to the value @@ -274,8 +278,15 @@ void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes); /*****************************************************************************/ - -void g_getimmed (unsigned Flags, uintptr_t Val, long Offs); +#ifdef DEBUG +// #define g_getimmed(a,b,c) _g_getimmed((a),(b),(c),(__FILE__),(__FUNCTION__),(__LINE__)) +// void _g_getimmed(unsigned Flags, uintptr_t Val, long Offs, char *file, const char *func, int line); +#define g_getimmed(a,b,c) _g_getimmed((a),(b),(c)) +void _g_getimmed (unsigned Flags, uintptr_t Val, long Offs); +#else +#define g_getimmed(a,b,c) _g_getimmed((a),(b),(c)) +void _g_getimmed (unsigned Flags, uintptr_t Val, long Offs); +#endif /* Load a constant into the primary register */ void g_getstatic (unsigned Flags, uintptr_t Label, long Offs); @@ -396,6 +407,8 @@ void g_test (unsigned flags); void g_push (unsigned flags, unsigned long val); /* Push the primary register or a constant value onto the stack */ +void g_push_float (unsigned flags, double val); +/* Push the primary register or a constant value onto the stack */ void g_swap (unsigned flags); /* Swap the primary register and the top of the stack. flags give the type @@ -467,6 +480,8 @@ void g_res (unsigned n); void g_defdata (unsigned flags, uintptr_t val, long offs); /* Define data with the size given in flags */ +void g_defdata_float (unsigned flags, uintptr_t val, long offs); +/* Define data with the size given in flags */ void g_defbytes (const void* bytes, unsigned count); /* Output a row of bytes as a constant */ diff --git a/src/cc65/datatype.c b/src/cc65/datatype.c index 4d6cb25a5..f21a51d4a 100644 --- a/src/cc65/datatype.c +++ b/src/cc65/datatype.c @@ -668,14 +668,23 @@ const Type* ArithmeticConvert (const Type* lhst, const Type* rhst) ** of the result. This pattern is called the usual arithmetic conversions. */ + if (IsTypeFloat (lhst) && IsTypeFloat (rhst)) { + /* FIXME: float - this needs much more special handling */ + return type_float; + } + if (IsTypeFloat (lhst)) { + /* FIXME: float - this needs much more special handling */ + return type_float; + } + if (IsTypeFloat (rhst)) { + /* FIXME: float - this needs much more special handling */ + return type_float; + } + /* There are additional rules for floating point types that we don't bother with, since ** floating point types are not (yet) supported. ** The integral promotions are performed on both operands. */ - if (IsClassFloat(lhst) || IsClassFloat(rhst)) { - Error ("Floating point arithmetic not supported."); - return type_long; - } lhst = IntPromotion (lhst); rhst = IntPromotion (rhst); diff --git a/src/cc65/expr.c b/src/cc65/expr.c index f6c681db8..5a4ae48b6 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -4,7 +4,7 @@ ** 2020-11-20, Greg King */ - +//#define DEBUG #include #include @@ -41,7 +41,13 @@ #include "typeconv.h" #include "expr.h" - +#ifdef DEBUG +#define LOG(x) printf x +#define FIXME(x) printf x +#else +#define LOG(x) +#define FIXME(x) +#endif /*****************************************************************************/ /* Data */ @@ -326,8 +332,14 @@ void LimitExprValue (ExprDesc* Expr, int WarnOverflow) Expr->IVal = (uint8_t)Expr->IVal; break; + /* FIXME: float */ + case T_FLOAT: + case T_DOUBLE: + Expr->V.FVal.V = (double)Expr->V.FVal.V; + break; + default: - Internal ("hie_internal: constant result type %s\n", GetFullTypeName (Expr->Type)); + Internal ("hie_internal: constant result type '%s' not implemented.\n", GetFullTypeName (Expr->Type)); } } @@ -487,6 +499,8 @@ static void DoInc (ExprDesc* Expr, unsigned KeepResult) /* Get the increment value in bytes */ Val = IsTypePtr (Expr->Type) ? CheckedSizeOf (Expr->Type + 1) : 1; + LOG(("DoInc Val:%d KeepResult:%d\n", Val, KeepResult)); + /* Special treatment is needed for bit-fields */ if (IsTypeFragBitField (Expr->Type)) { DoIncDecBitField (Expr, Val, KeepResult); @@ -1898,6 +1912,44 @@ static void UnaryOp (ExprDesc* Expr) /* Get the expression */ hie10 (Expr); +#if 0 + /* We can only handle integer types */ + if (!IsClassInt (Expr->Type) + && !IsClassFloat (Expr->Type) /* FIXME: float */ + ) { + Error ("Argument must have integer type"); + ED_MakeConstAbsInt (Expr, 1); + } + + /* Check for a constant numeric expression */ + if (ED_IsConstAbs (Expr)) { + /* Value is numeric */ + + /* FIXME: float ---- start new code */ + if (IsClassFloat (Expr->Type)) { + switch (Tok) { + case TOK_MINUS: Expr->V.FVal = FP_D_Mul(Expr->V.FVal, FP_D_FromInt(-1)); break; + case TOK_PLUS: break; + default: Internal ("Unexpected token: %d", Tok); + } + } + else { + /* FIXME: float ---- end new code */ + switch (Tok) { + case TOK_MINUS: Expr->IVal = -Expr->IVal; break; + case TOK_PLUS: break; + case TOK_COMP: Expr->IVal = ~Expr->IVal; break; + default: Internal ("Unexpected token: %d", Tok); + } + + /* Adjust the type of the expression */ + Expr->Type = IntPromotion (Expr->Type); + } + + /* Limit the calculated value to the range of its type */ + LimitExprValue (Expr, 1); + +#else /* Check for a constant numeric expression */ if (ED_IsConstAbs (Expr)) { @@ -1929,20 +1981,25 @@ static void UnaryOp (ExprDesc* Expr) LimitExprValue (Expr, 1); } +#endif } else { unsigned Flags; - +#if 0 /* If not constant, we can only handle integer types */ if (!IsClassInt (Expr->Type)) { Error ("Non-constant argument must have integer type"); ED_MakeConstAbsInt (Expr, 1); } - +#endif /* Value is not constant */ LoadExpr (CF_NONE, Expr); /* Adjust the type of the expression */ - Expr->Type = IntPromotion (Expr->Type); + /* FIXME: float */ + if (!IsClassFloat (Expr->Type)) { + Expr->Type = IntPromotion (Expr->Type); + } +// Expr->Type = IntPromotion (Expr->Type); TypeConversion (Expr, Expr->Type); /* Get code generation flags */ @@ -1981,6 +2038,7 @@ void hie10 (ExprDesc* Expr) case TOK_PLUS: case TOK_MINUS: case TOK_COMP: + /* FIXME: whats with floats? */ UnaryOp (Expr); break; @@ -2124,8 +2182,9 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ unsigned ltype, type; int lconst; /* Left operand is a constant */ int rconst; /* Right operand is a constant */ + int floatop = 0; - +//LOG(("hie_internal\n")); ExprWithCheck (hienext, Expr); *UsedGen = 0; @@ -2138,16 +2197,35 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ /* Tell the caller that we handled it's ops */ *UsedGen = 1; + /* FIXME: float ---start new code*/ + /* Remember the operator token, then skip it */ + Tok = CurTok.Tok; + NextToken (); + + switch (Tok) { + case TOK_STAR: + case TOK_DIV: + floatop = 1; + break; + default: + break; + } + + /* FIXME: float ---start end code*/ + /* All operators that call this function expect an int on the lhs */ - if (!IsClassInt (Expr->Type)) { - Error ("Integer expression expected"); + if (!IsClassInt (Expr->Type) && + /* FIXME: float */ + !(floatop && IsClassFloat (Expr->Type)) + ) { + Error ("LHS Integer expression expected (hie_internal)"); /* To avoid further errors, make Expr a valid int expression */ ED_MakeConstAbsInt (Expr, 1); } - /* Remember the operator token, then skip it */ - Tok = CurTok.Tok; - NextToken (); +// /* Remember the operator token, then skip it */ +// Tok = CurTok.Tok; +// NextToken (); /* Get the lhs on stack */ GetCodePos (&Mark1); @@ -2160,12 +2238,19 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ ** it's a constant, since we will exchange both operands. */ if ((Gen->Flags & GEN_COMM) == 0) { - g_push (ltype | CF_CONST, Expr->IVal); + if (ltype == CF_FLOAT) { + LOG(("hie_internal push left side const (float)\n")); + g_push (ltype | CF_CONST, FP_D_As32bitRaw(Expr->V.FVal)); + } else { + LOG(("hie_internal push left side const (int)\n")); + g_push (ltype | CF_CONST, Expr->IVal); + } } } else { /* Value not constant */ LoadExpr (CF_NONE, Expr); GetCodePos (&Mark2); + LOG(("hie_internal push left side var\n")); g_push (ltype, 0); } @@ -2180,10 +2265,13 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ } /* Check the type of the rhs */ - if (!IsClassInt (Expr2.Type)) { - Error ("Integer expression expected"); + if (!IsClassInt (Expr2.Type) && + /* FIXME: float */ + !(floatop && IsClassFloat (Expr2.Type)) + ) { + Error ("RHS Integer expression expected (hie_internal)"); } - + LOG(("hie_internal lconst:%d rconst:%d\n", lconst, rconst)); /* Check for const operands */ if (lconst && rconst) { @@ -2191,58 +2279,115 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ unsigned long Val1 = Expr->IVal; unsigned long Val2 = Expr2.IVal; + LOG(("hie_internal lhs is const and rhs is const")); + /* Both operands are constant, remove the generated code */ RemoveCode (&Mark1); /* Get the type of the result */ Expr->Type = ArithmeticConvert (Expr->Type, Expr2.Type); - /* Handle the op differently for signed and unsigned types */ - switch (Tok) { - case TOK_OR: - Expr->IVal = (Val1 | Val2); - break; - case TOK_XOR: - Expr->IVal = (Val1 ^ Val2); - break; - case TOK_AND: - Expr->IVal = (Val1 & Val2); - break; - case TOK_STAR: - Expr->IVal = (Val1 * Val2); - break; - case TOK_DIV: - if (Val2 == 0) { - if (!ED_IsUneval (Expr)) { - Warning ("Division by zero"); + /* FIXME: float --- newcode start */ +LOG(("hie_internal Expr->Type:%s Expr2->Type:%s\n", + (IsClassFloat (Expr->Type) == CF_FLOAT) ? "float" : "int", + (IsClassFloat (Expr2.Type) == CF_FLOAT) ? "float" : "int" + )); +LOG(("hie_internal Expr->Type:%s Expr2->Type:%s\n", + (Expr->Type == type_float) ? "float" : "int", + (Expr2.Type == type_float) ? "float" : "int" + )); + + /* FIXME: float */ + /* FIXME: right now this works only when both rhs and lhs are float, + this must be extended to handle mixed operations */ +// if ((IsClassFloat (Expr->Type) == CF_FLOAT) && +// (IsClassFloat (Expr2.Type) == CF_FLOAT)) { + if ((ltype == CF_FLOAT) || + (Expr2.Type == type_float)) { + /* Evaluate the result for float operands */ + Double Val1; + Double Val2; + LOG(("hie_internal float X float %d %d\n", Expr->IVal, Expr2.IVal)); + if (ltype == CF_FLOAT) { + Val1 = Expr->V.FVal; + } else { + Val1 = FP_D_FromInt(Expr->IVal); + } + if (CG_TypeOf (Expr2.Type) == CF_FLOAT) { + Val2 = Expr2.V.FVal; + } else { + Val2 = FP_D_FromInt(Expr2.IVal); + } + LOG(("hie_internal float X float %f %f\n", Expr->V.FVal.V, Expr2.V.FVal.V)); + + switch (Tok) { + case TOK_DIV: +#if 0 // TODO + if (Val2 == 0.0f) { + Error ("Division by zero"); + Expr->V.FVal = FP_D_FromInt(0); + } else +#endif + { + Expr->V.FVal = FP_D_Div(Val1, Val2); } - Expr->IVal = 0xFFFFFFFF; - } else { - /* Handle signed and unsigned operands differently */ - if (IsSignSigned (Expr->Type)) { - Expr->IVal = ((long)Val1 / (long)Val2); + break; + case TOK_STAR: + Expr->V.FVal = FP_D_Mul(Val1, Val2); + break; + default: + Internal ("hie_internal: got token 0x%X\n", Tok); + } + /* FIXME: float --- newcode end */ + } else { + LOG(("hie_internal (un)signed int X signed int\n")); + /* Handle the op differently for signed and unsigned types */ + switch (Tok) { + case TOK_OR: + Expr->IVal = (Val1 | Val2); + break; + case TOK_XOR: + Expr->IVal = (Val1 ^ Val2); + break; + case TOK_AND: + Expr->IVal = (Val1 & Val2); + break; + case TOK_STAR: + Expr->IVal = (Val1 * Val2); + break; + case TOK_DIV: + if (Val2 == 0) { + if (!ED_IsUneval (Expr)) { + Warning ("Division by zero"); + } + Expr->IVal = 0xFFFFFFFF; } else { - Expr->IVal = (Val1 / Val2); + /* Handle signed and unsigned operands differently */ + if (IsSignSigned (Expr->Type)) { + Expr->IVal = ((long)Val1 / (long)Val2); + } else { + Expr->IVal = (Val1 / Val2); + } } - } - break; - case TOK_MOD: - if (Val2 == 0) { - if (!ED_IsUneval (Expr)) { - Warning ("Modulo operation with zero"); - } - Expr->IVal = 0; - } else { - /* Handle signed and unsigned operands differently */ - if (IsSignSigned (Expr->Type)) { - Expr->IVal = ((long)Val1 % (long)Val2); + break; + case TOK_MOD: + if (Val2 == 0) { + if (!ED_IsUneval (Expr)) { + Warning ("Modulo operation with zero"); + } + Expr->IVal = 0; } else { - Expr->IVal = (Val1 % Val2); + /* Handle signed and unsigned operands differently */ + if (IsSignSigned (Expr->Type)) { + Expr->IVal = ((long)Val1 % (long)Val2); + } else { + Expr->IVal = (Val1 % Val2); + } } - } - break; - default: - Internal ("hie_internal: got token 0x%X\n", Tok); + break; + default: + Internal ("hie_internal: got token 0x%X\n", Tok); + } } /* Limit the calculated value to the range of its type */ @@ -2255,6 +2400,7 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ ** returned without this modification). This allows more efficient operations, ** but does not affect correctness for the same reasons explained in g_typeadjust. */ + LOG(("hie_internal lhs is const, rhs is not const\n")); if (ltype == CF_INT && Expr->IVal >= 0 && Expr->IVal < 256) { ltype = CF_CHAR | CF_UNSIGNED; } @@ -2272,13 +2418,20 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ } else { ltype |= CF_PRIMARY; /* Value is in register */ } + LOG(("hie_internal swap lhs/rhs\n")); /* Determine the type of the operation result. */ type |= g_typeadjust (ltype, rtype); Expr->Type = ArithmeticConvert (Expr->Type, Expr2.Type); /* Generate code */ - Gen->Func (type, Expr->IVal); + if (CG_TypeOf (Expr->Type) == CF_FLOAT) { + LOG(("hie_internal lhs is not const, rhs is const\n")); + Gen->Func (type, FP_D_As32bitRaw(Expr->V.FVal)); + } else { + LOG(("hie_internal lhs is not const, rhs is const\n")); + Gen->Func (type, Expr->IVal); + } /* We have an rvalue in the primary now */ ED_FinalizeRValLoad (Expr); @@ -2291,33 +2444,120 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ */ unsigned rtype = CG_TypeOf (Expr2.Type); type = 0; + LOG(("hie_internal ?2 ltype:%4x rconst: %d rtype:%4x\n", ltype, rconst, rtype)); if (rconst) { /* As above, but for the RHS. */ if (rtype == CF_INT && Expr2.IVal >= 0 && Expr2.IVal < 256) { rtype = CF_CHAR | CF_UNSIGNED; } /* Second value is constant - check for div */ - type |= CF_CONST; - rtype |= CF_CONST; - if (Expr2.IVal == 0 && !ED_IsUneval (Expr)) { - if (Tok == TOK_DIV) { - Warning ("Division by zero"); - } else if (Tok == TOK_MOD) { - Warning ("Modulo operation with zero"); + LOG(("rtype float is %x\n", CF_FLOAT)); + if (rtype == CF_FLOAT) { + // FIXME add respective checks for float + FIXME(("FIXME: add div checks for float\n")); + } else { + if (Expr2.IVal == 0 && !ED_IsUneval (Expr)) { + if (Tok == TOK_DIV) { + Warning ("Division by zero"); + } else if (Tok == TOK_MOD) { + Warning ("Modulo operation with zero"); + } } } + type |= CF_CONST; + rtype |= CF_CONST; + if ((Gen->Flags & GEN_NOPUSH) != 0) { + FIXME(("hie_internal ?2 removing code\n")); RemoveCode (&Mark2); ltype |= CF_PRIMARY; /* Value is in register */ } } + LOG(("hie_internal ?2a ltype:%4x rconst: %d rtype:%4x\n", ltype, rconst, rtype)); /* Determine the type of the operation result. */ type |= g_typeadjust (ltype, rtype); + LOG(("hie_internal ?2b ltype:%4x rconst: %d rtype:%4x type:%04x .Expr.Type:%04x Expr2.Type:%04x\n", ltype, rconst, rtype, type, TypeOf (Expr->Type), TypeOf (Expr2.Type))); Expr->Type = ArithmeticConvert (Expr->Type, Expr2.Type); + LOG(("hie_internal ?2c Expr->Type:%4x\n", TypeOf (Expr->Type))); /* Generate code */ - Gen->Func (type, Expr2.IVal); + if (CG_TypeOf (Expr2.Type) == CF_FLOAT) { +#if 0 + Gen->Func (type, FP_D_As32bitRaw(Expr2.V.FVal)); +#else + // right side is float + LOG(("hie_internal ?2 rhs float:%x\n", FP_D_As32bitRaw(Expr2.V.FVal))); + if (((ltype & CF_TYPEMASK) != CF_FLOAT) && (!(rtype & CF_CONST))) { + // left side is not float, right side is non-constant float + LOG(("hie_internal ?2 lhs not float: %ld ltype const?:%d\n", Expr->IVal, ltype & CF_CONST)); +#if 1 + RemoveCode (&Mark2); + LoadExpr(ltype, Expr); + /* Adjust lhs primary if needed */ +// type = typeadjust (&Expr2, Expr, 0); +// type = typeadjust (Expr, &Expr2, 1); +// Expr->Type = type_float; + g_regfloat(ltype); +// g_push_float(type & ~CF_CONST, FP_D_As32bitRaw(FP_D_FromInt(Expr->IVal))); +// g_push_float(type & ~CF_CONST, 0); +// RemoveCode (&Mark2); + g_push(type, 0); + LoadExpr(CF_FLOAT, &Expr2); + // left side is not float, right side is float + Gen->Func (type, FP_D_As32bitRaw(Expr2.V.FVal)); +#else + if (lconst) { + LOG(("hie_internal lhs int const\n")); +#if 1 + // lhs is constant + RemoveCode (&Mark2); + LoadExpr(ltype, Expr); + // /* Adjust lhs primary if needed */ + // // type = typeadjust (&Expr2, Expr, 0); + type = typeadjust (Expr, &Expr2, 1); + // // Expr->Type = type_float; + // g_regfloat(type); + // // g_push_float(type & ~CF_CONST, FP_D_As32bitRaw(FP_D_FromInt(Expr->IVal))); + // // g_push_float(type & ~CF_CONST, 0); + // // RemoveCode (&Mark2); + // g_push(type, 0); + // LoadExpr(CF_FLOAT, &Expr2); + // left side is not float, right side is float + Gen->Func (type, FP_D_As32bitRaw(Expr2.V.FVal)); +#endif + } else { + LOG(("hie_internal lhs int var\n")); +#if 1 + RemoveCode (&Mark2); + LoadExpr(ltype, Expr); + /* Adjust lhs primary if needed */ + // type = typeadjust (&Expr2, Expr, 0); + // type = typeadjust (Expr, &Expr2, 1); + // Expr->Type = type_float; + g_regfloat(ltype); + // g_push_float(type & ~CF_CONST, FP_D_As32bitRaw(FP_D_FromInt(Expr->IVal))); + // g_push_float(type & ~CF_CONST, 0); + // RemoveCode (&Mark2); + g_push(type, 0); + LoadExpr(CF_FLOAT, &Expr2); + // left side is not float, right side is float + Gen->Func (type, FP_D_As32bitRaw(Expr2.V.FVal)); +#endif + } +#endif + } else { + // left side is float, right side is float + LOG(("hie_internal ?2 lhs is float: %08x\n", FP_D_As32bitRaw(Expr2.V.FVal))); + Gen->Func (type, FP_D_As32bitRaw(Expr2.V.FVal)); + } +// Gen->Func (CF_FLOAT, FP_D_As32bitRaw(Expr2.V.FVal)); +// Gen->Func (type, Expr2.IVal); +#endif + } else { + // right side is not float + Gen->Func (type, Expr2.IVal); + } /* We have an rvalue in the primary now */ ED_FinalizeRValLoad (Expr); @@ -2342,6 +2582,8 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ unsigned ltype; int rconst; /* Operand is a constant */ + int flags = 0; +// LOG(("hie_compare\n")); ExprWithCheck (hienext, Expr); @@ -2369,7 +2611,12 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ if (ED_IsConstAbs (Expr)) { /* Numeric constant value */ GetCodePos (&Mark2); - g_push (ltype | CF_CONST, Expr->IVal); + LOG(("hie_compare Numeric constant value iVal:%ld FVal:%f\n", Expr->IVal, Expr->V.FVal.V)); + if (ltype == CF_FLOAT) { + g_push_float (ltype | CF_CONST, Expr->V.FVal.V); + } else { + g_push (ltype | CF_CONST, Expr->IVal); + } } else { /* Value not numeric constant */ LoadExpr (CF_NONE, Expr); @@ -2379,7 +2626,49 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ /* Get the right hand side */ MarkedExprWithCheck (hienext, &Expr2); +//printf("Expr: %d Expr2: %d\n", (CG_TypeOf (Expr->Type) == CF_FLOAT), (CG_TypeOf (Expr2.Type) == CF_FLOAT)); +#if 1 + if (CG_TypeOf (Expr2.Type) == CF_FLOAT) { + if (ltype != CF_FLOAT) { + /* left hand is NOT a float (but a constant), right IS a float (but not necessarily constant) */ + LOG(("hie_compare check lhs const vs rhs float\n")); + if (ED_IsConstAbs (&Expr2)) { +#if 1 // for rhs const + RemoveCode (&Mark2); /* Remove pushed value from stack */ + /* Load lhs into the primary */ + LoadExpr (CF_NONE, Expr); + // convert lhs to float + g_regfloat (CF_FLOAT); + g_push (CF_FLOAT, 0); /* --> stack */ + /* Load rhs into the primary */ + LoadExpr (CF_FLOAT, &Expr2); + // /* Adjust rhs primary if needed */ + // flags = typeadjust (Expr, &Expr2, 0); + ltype = CF_FLOAT; +#endif + } else { +#if 1 // for rhs variable + RemoveCode (&Mark2); /* Remove pushed value from stack */ + /* Load lhs into the primary */ + LoadExpr (CF_NONE, Expr); + /* Adjust lhs primary if needed */ + flags = typeadjust (Expr, &Expr2, 0); + // // convert lhs to float + g_regfloat (flags); + g_push (CF_FLOAT, 0); /* --> stack */ + // flags = typeadjust (Expr, &Expr2, 0); + // flags |= CF_FLOAT; + /* Load rhs into the primary */ + LoadExpr (CF_NONE, &Expr2); + /* Adjust rhs primary if needed */ + flags = typeadjust (Expr, &Expr2, 0); + ltype = CF_FLOAT; +#endif + } + } + } +#endif /* If rhs is a function, convert it to the address of the function */ if (IsTypeFunc (Expr2.Type)) { Expr2.Type = AddressOf (Expr2.Type); @@ -2391,12 +2680,15 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ /* Not numeric constant, load into the primary */ LoadExpr (CF_NONE, &Expr2); } + else { + LOG(("hie_compare rhs is constant value iVal:%ld FVal:%f\n", Expr2.IVal, Expr2.V.FVal.V)); + } /* Check if operands have allowed types for this operation */ if (!IsRelationType (Expr->Type) || !IsRelationType (Expr2.Type)) { /* Output only one message even if both sides are wrong */ TypeCompatibilityDiagnostic (Expr->Type, Expr2.Type, 1, - "Comparing types '%s' with '%s' is invalid"); + "a Comparing types '%s' with '%s' is invalid"); /* Avoid further errors */ ED_MakeConstAbsInt (Expr, 0); ED_MakeConstAbsInt (&Expr2, 0); @@ -2415,13 +2707,13 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ /* Make sure, the types are compatible */ if (IsClassInt (Expr->Type)) { - if (!IsClassInt (Expr2.Type) && !ED_IsNullPtr (Expr)) { + if (!IsClassInt (Expr2.Type) && !IsClassFloat (Expr2.Type) && !ED_IsNullPtr (Expr)) { if (IsClassPtr (Expr2.Type)) { TypeCompatibilityDiagnostic (Expr->Type, PtrConversion (Expr2.Type), 0, "Comparing integer '%s' with pointer '%s'"); } else { TypeCompatibilityDiagnostic (Expr->Type, Expr2.Type, 1, - "Comparing types '%s' with '%s' is invalid"); + "b Comparing types '%s' with '%s' is invalid"); } } } else if (IsClassPtr (Expr->Type)) { @@ -2438,7 +2730,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ "Comparing pointer type '%s' with integer type '%s'"); } else { TypeCompatibilityDiagnostic (Expr->Type, Expr2.Type, 1, - "Comparing types '%s' with '%s' is invalid"); + "c Comparing types '%s' with '%s' is invalid"); } } } @@ -2446,7 +2738,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ /* Check for numeric constant operands */ if ((ED_IsEntityAddr (Expr) && ED_IsNullPtr (&Expr2)) || (ED_IsNullPtr (Expr) && ED_IsEntityAddr (&Expr2))) { - + LOG(("hie_compare numeric constant operands\n")); /* Object addresses are inequal to null pointer */ Expr->IVal = (Tok != TOK_EQ); if (ED_IsNullPtr (&Expr2)) { @@ -2469,6 +2761,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ if (ED_CodeRangeIsEmpty (&Expr2)) { /* Both operands are static, remove the load code */ + LOG(("hie_compare remove code\n")); RemoveCode (&Mark1); } else { /* Drop pushed lhs */ @@ -2479,10 +2772,11 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ } else if (ED_IsEntityAddr (Expr) && ED_IsEntityAddr (&Expr2) && Expr->Sym == Expr2.Sym) { - /* Evaluate the result for static addresses */ unsigned long Val1 = Expr->IVal; unsigned long Val2 = Expr2.IVal; + LOG(("hie_compare static addresses\n")); + switch (Tok) { case TOK_EQ: Expr->IVal = (Val1 == Val2); break; case TOK_NE: Expr->IVal = (Val1 != Val2); break; @@ -2513,38 +2807,98 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ } else if (ED_IsConstAbs (Expr) && rconst) { /* Both operands are numeric constant, remove the generated code */ + LOG(("hie_compare remove code\n")); RemoveCode (&Mark1); + LOG(("hie_compare (Both operands are numeric constant) (float %ld:%ld) (int %ld:%ld)\n", + (signed long)FP_D_ToFloat(Expr->V.FVal), + (signed long)FP_D_ToFloat(Expr2.V.FVal), + Expr->IVal, Expr2.IVal + )); - /* Determine if this is a signed or unsigned compare */ - if (IsClassInt (Expr->Type) && IsSignSigned (Expr->Type) && - IsClassInt (Expr2.Type) && IsSignSigned (Expr2.Type)) { - - /* Evaluate the result for signed operands */ - signed long Val1 = Expr->IVal; - signed long Val2 = Expr2.IVal; - switch (Tok) { - case TOK_EQ: Expr->IVal = (Val1 == Val2); break; - case TOK_NE: Expr->IVal = (Val1 != Val2); break; - case TOK_LT: Expr->IVal = (Val1 < Val2); break; - case TOK_LE: Expr->IVal = (Val1 <= Val2); break; - case TOK_GE: Expr->IVal = (Val1 >= Val2); break; - case TOK_GT: Expr->IVal = (Val1 > Val2); break; - default: Internal ("hie_compare: got token 0x%X\n", Tok); + if ((CG_TypeOf (Expr->Type) == CF_FLOAT) || (CG_TypeOf (Expr2.Type) == CF_FLOAT)) { + /* at least one of the operands is a float */ + if ((CG_TypeOf (Expr->Type) == CF_FLOAT) && + (CG_TypeOf (Expr2.Type) == CF_FLOAT)) { + LOG(("FIXME: comparing float constant with float constant\n")); + /* compare float vs float */ + float Val1 = (float)FP_D_ToFloat(Expr->V.FVal); + float Val2 = (float)FP_D_ToFloat(Expr2.V.FVal); + switch (Tok) { + case TOK_EQ: Expr->IVal = (Val1 == Val2); break; + case TOK_NE: Expr->IVal = (Val1 != Val2); break; + case TOK_LT: Expr->IVal = (Val1 < Val2); break; + case TOK_LE: Expr->IVal = (Val1 <= Val2); break; + case TOK_GE: Expr->IVal = (Val1 >= Val2); break; + case TOK_GT: Expr->IVal = (Val1 > Val2); break; + default: Internal ("hie_compare: got token 0x%X\n", Tok); + } + LOG(("FIXME: float:%ld float:%ld res:%d\n", (long)Val1, (long)Val2, Expr->IVal)); + } else if (CG_TypeOf (Expr2.Type) == CF_FLOAT) { + LOG(("FIXME: comparing non float constant with float constant\n")); + /* FIXME: compare non float vs float */ + signed long Val1 = Expr->IVal; + float Val2 = (float)FP_D_ToFloat(Expr2.V.FVal); + switch (Tok) { + case TOK_EQ: Expr->IVal = (Val1 == Val2); break; + case TOK_NE: Expr->IVal = (Val1 != Val2); break; + case TOK_LT: Expr->IVal = (Val1 < Val2); break; + case TOK_LE: Expr->IVal = (Val1 <= Val2); break; + case TOK_GE: Expr->IVal = (Val1 >= Val2); break; + case TOK_GT: Expr->IVal = (Val1 > Val2); break; + default: Internal ("hie_compare: got token 0x%X\n", Tok); + } + LOG(("FIXME: int:%ld float:%ld res:%d\n", Val1, (long)Val2, Expr->IVal)); + } else { + LOG(("FIXME: comparing float constant with non float constant\n")); + /* FIXME: compare float vs non float */ + float Val1 = (float)FP_D_ToFloat(Expr->V.FVal); + signed long Val2 = Expr2.IVal; + switch (Tok) { + case TOK_EQ: Expr->IVal = (Val1 == Val2); break; + case TOK_NE: Expr->IVal = (Val1 != Val2); break; + case TOK_LT: Expr->IVal = (Val1 < Val2); break; + case TOK_LE: Expr->IVal = (Val1 <= Val2); break; + case TOK_GE: Expr->IVal = (Val1 >= Val2); break; + case TOK_GT: Expr->IVal = (Val1 > Val2); break; + default: Internal ("hie_compare: got token 0x%X\n", Tok); + } + LOG(("FIXME: float:%ld int:%ld res:%d\n", (long)Val1, Val2, Expr->IVal)); } - } else { - /* Evaluate the result for unsigned operands */ - unsigned long Val1 = Expr->IVal; - unsigned long Val2 = Expr2.IVal; - switch (Tok) { - case TOK_EQ: Expr->IVal = (Val1 == Val2); break; - case TOK_NE: Expr->IVal = (Val1 != Val2); break; - case TOK_LT: Expr->IVal = (Val1 < Val2); break; - case TOK_LE: Expr->IVal = (Val1 <= Val2); break; - case TOK_GE: Expr->IVal = (Val1 >= Val2); break; - case TOK_GT: Expr->IVal = (Val1 > Val2); break; - default: Internal ("hie_compare: got token 0x%X\n", Tok); + LOG(("hie_compare: not float\n")); + + /* Determine if this is a signed or unsigned compare */ + if (IsClassInt (Expr->Type) && IsSignSigned (Expr->Type) && + IsClassInt (Expr2.Type) && IsSignSigned (Expr2.Type)) { + + /* Evaluate the result for signed operands */ + signed long Val1 = Expr->IVal; + signed long Val2 = Expr2.IVal; + switch (Tok) { + case TOK_EQ: Expr->IVal = (Val1 == Val2); break; + case TOK_NE: Expr->IVal = (Val1 != Val2); break; + case TOK_LT: Expr->IVal = (Val1 < Val2); break; + case TOK_LE: Expr->IVal = (Val1 <= Val2); break; + case TOK_GE: Expr->IVal = (Val1 >= Val2); break; + case TOK_GT: Expr->IVal = (Val1 > Val2); break; + default: Internal ("hie_compare: got token 0x%X\n", Tok); + } + + } else { + + /* Evaluate the result for unsigned operands */ + unsigned long Val1 = Expr->IVal; + unsigned long Val2 = Expr2.IVal; + switch (Tok) { + case TOK_EQ: Expr->IVal = (Val1 == Val2); break; + case TOK_NE: Expr->IVal = (Val1 != Val2); break; + case TOK_LT: Expr->IVal = (Val1 < Val2); break; + case TOK_LE: Expr->IVal = (Val1 <= Val2); break; + case TOK_GE: Expr->IVal = (Val1 >= Val2); break; + case TOK_GT: Expr->IVal = (Val1 > Val2); break; + default: Internal ("hie_compare: got token 0x%X\n", Tok); + } } } @@ -2557,12 +2911,17 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ WarnConstCompareResult (Expr); } else { + /* at least one side of the expression is not constant */ /* Determine the signedness of the operands */ int LeftSigned = IsSignSigned (Expr->Type); int RightSigned = IsSignSigned (Expr2.Type); int CmpSigned = IsClassInt (Expr->Type) && IsClassInt (Expr2.Type) && IsSignSigned (ArithmeticConvert (Expr->Type, Expr2.Type)); + LOG(("hie_compare Determine the signedness of the operands\n")); + + LOG(("hie_compare LeftSigned:%d RightSigned:%d CmpSigned:%d %x %x\n", + LeftSigned, RightSigned, CmpSigned, Expr2.IVal, Expr->IVal)); /* If the right hand side is constant, and the generator function ** expects the lhs in the primary, remove the push of the primary @@ -2572,6 +2931,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ if (rconst) { flags |= CF_CONST; if ((Gen->Flags & GEN_NOPUSH) != 0) { + LOG(("hie_compare remove code\n")); RemoveCode (&Mark2); ltype |= CF_PRIMARY; /* Value is in register */ } @@ -2579,6 +2939,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ /* Determine the type of the operation. */ if (IsRankChar (Expr->Type) && rconst && (!LeftSigned || RightSigned)) { + LOG(("hie_compare 1\n")); /* Left side is unsigned char, right side is constant. ** Determine the minimum and maximum values @@ -2663,6 +3024,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ } else if (IsRankChar (Expr->Type) && IsRankChar (Expr2.Type) && GetSignedness (Expr->Type) == GetSignedness (Expr2.Type)) { + LOG(("hie_compare 2\n")); /* Both are chars with the same signedness. We can encode the ** operation as a char operation. @@ -2677,9 +3039,24 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ } } else { + /* generic case */ unsigned rtype = CG_TypeOf (Expr2.Type) | (flags & CF_CONST); - flags |= g_typeadjust (ltype, rtype); + LOG(("hie_compare 3a: %d:%d %x:%x\n", + CG_TypeOf (Expr->Type) == CF_FLOAT, CG_TypeOf (Expr2.Type) == CF_FLOAT, + ltype, rtype)); + if (CG_TypeOf (Expr->Type) == CF_FLOAT) { + /* left is float */ + flags |= CF_FLOAT; + } else if (CG_TypeOf (Expr2.Type) == CF_FLOAT) { + /* right is float */ + } else { + flags |= g_typeadjust (ltype, rtype); + } + LOG(("hie_compare 3b: %d:%d %x:%x\n", + CG_TypeOf (Expr->Type) == CF_FLOAT, CG_TypeOf (Expr2.Type) == CF_FLOAT, + ltype, rtype)); } + LOG(("hie_compare rconst:%d CmpSigned:%d \n", rconst, CmpSigned)); /* If the comparison is made as unsigned types and the right is a ** constant, we may be able to change the compares to something more @@ -2687,55 +3064,76 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ */ if (!CmpSigned && rconst) { - switch (Tok) { + /* FIXME: float --- startcode end */ + if (Expr2.Type == type_float) { + LOG(("FIXME: special cases for comparison with float constant\n")); + } else { + /* FIXME: float --- newcode end */ - case TOK_LT: - if (Expr2.IVal == 1) { - /* An unsigned compare to one means that the value - ** must be zero. - */ - GenFunc = g_eq; - Expr2.IVal = 0; - } - break; + switch (Tok) { - case TOK_LE: - if (Expr2.IVal == 0) { - /* An unsigned compare to zero means that the value - ** must be zero. - */ - GenFunc = g_eq; - } - break; + case TOK_LT: + if (Expr2.IVal == 1) { + /* An unsigned compare to one means that the value + ** must be zero. + */ + GenFunc = g_eq; + Expr2.IVal = 0; + } + break; - case TOK_GE: - if (Expr2.IVal == 1) { - /* An unsigned compare to one means that the value - ** must not be zero. - */ - GenFunc = g_ne; - Expr2.IVal = 0; - } - break; + case TOK_LE: + if (Expr2.IVal == 0) { + /* An unsigned compare to zero means that the value + ** must be zero. + */ + GenFunc = g_eq; + } + break; - case TOK_GT: - if (Expr2.IVal == 0) { - /* An unsigned compare to zero means that the value - ** must not be zero. - */ - GenFunc = g_ne; - } - break; + case TOK_GE: + if (Expr2.IVal == 1) { + /* An unsigned compare to one means that the value + ** must not be zero. + */ + GenFunc = g_ne; + Expr2.IVal = 0; + } + break; - default: - break; + case TOK_GT: + if (Expr2.IVal == 0) { + /* An unsigned compare to zero means that the value + ** must not be zero. + */ + GenFunc = g_ne; + } + break; + default: + break; + + } } - } - /* Generate code */ - GenFunc (flags, Expr2.IVal); + /* FIXME: float --- startcode end */ + if (IsClassFloat(Expr2.Type)) { +// if (Expr2.Type == type_float) { + /* Generate code */ + LOG(("hie_compare generate code for Expr2 as float (flags:$%02x)\n", flags)); + GenFunc (flags, FP_D_As32bitRaw(Expr2.V.FVal)); + } else if (IsClassFloat(Expr->Type)) { + /* Generate code */ + LOG(("hie_compare generate code for Expr as float (flags:$%02x)\n", flags)); + GenFunc (flags, FP_D_As32bitRaw(FP_D_FromInt(Expr2.IVal))); + } else { + /* Generate code */ + LOG(("hie_compare generate code for Expr2 as int (=%d) (flags:$%02x)\n", Expr2.IVal, flags)); + GenFunc (flags, Expr2.IVal); + } + LOG(("hie_compare generate code done\n")); + /* FIXME: float --- newcode end */ /* The result is an rvalue in the primary */ ED_FinalizeRValLoad (Expr); @@ -2750,6 +3148,7 @@ Done: Expr->Type = type_bool; /* Propagate viral flags */ ED_PropagateFrom (Expr, &Expr2); } +// LOG(("hie_compare generate end\n")); } @@ -2764,7 +3163,7 @@ static void hie9 (ExprDesc *Expr) { TOK_INVALID, 0, 0 } }; int UsedGen; - +// LOG(("hie9\n")); hie_internal (hie9_ops, Expr, hie10, &UsedGen); } @@ -2812,6 +3211,7 @@ static void parseadd (ExprDesc* Expr, int DoArrayRef) ** - (integer)(base + offset) * 1 + (pointer)numeric */ if (ED_IsQuasiConst (Expr)) { + LOG(("parseadd lhs is const\n")); /* The left hand side is a constant of some sort. Good. Get rhs */ ExprWithCheck (DoArrayRef ? hie0 : hie9, &Expr2); @@ -2819,6 +3219,7 @@ static void parseadd (ExprDesc* Expr, int DoArrayRef) /* Right hand side is constant. Get the rhs type */ rhst = Expr2.Type; if (ED_IsQuasiConst (&Expr2)) { + LOG(("parseadd lhs and rhs are const\n")); /* Both expressions are constants. Check for pointer arithmetic */ if (IsClassPtr (lhst) && IsClassInt (rhst)) { @@ -2834,7 +3235,27 @@ static void parseadd (ExprDesc* Expr, int DoArrayRef) } else if (!DoArrayRef && IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer addition */ flags = CF_INT; + } else if (!DoArrayRef && IsClassFloat (lhst) && IsClassFloat (rhst)) { + /* FIXME: float addition (const + const) */ + LOG(("%s:%d float addition (float const + float const)\n", __FILE__, __LINE__)); + /* Integer addition */ + flags = CF_FLOAT; +#if 1 + } else if (!DoArrayRef && IsClassFloat (lhst) && IsClassInt (rhst)) { + /* FIXME: float addition (const + const int) */ + LOG(("%s:%d float addition (float const + const int)\n", __FILE__, __LINE__)); + /* Integer addition */ + flags = CF_FLOAT; +#endif +#if 1 + } else if (!DoArrayRef && IsClassInt (lhst) && IsClassFloat (rhst)) { + /* FIXME: float addition (const int + const) */ + LOG(("%s:%d float addition (const int + float const)\n", __FILE__, __LINE__)); + /* Integer addition */ + flags = CF_FLOAT; +#endif } else { + LOG(("%s:%d OOPS\n", __FILE__, __LINE__)); /* OOPS */ AddDone = -1; /* Avoid further errors */ @@ -2843,24 +3264,55 @@ static void parseadd (ExprDesc* Expr, int DoArrayRef) if (!AddDone) { /* Do constant calculation if we can */ - if (ED_IsAbs (&Expr2) && - (ED_IsAbs (Expr) || lscale == 1)) { - if (IsClassInt (lhst) && IsClassInt (rhst)) { - Expr->Type = ArithmeticConvert (Expr->Type, Expr2.Type); - } - Expr->IVal = Expr->IVal * lscale + Expr2.IVal * rscale; + if (!DoArrayRef && IsClassFloat (lhst) && IsClassFloat (rhst)) { + /* float + float */ + /* FIXME: float - this is probably completely wrong */ + Expr->V.FVal.V = Expr->V.FVal.V + Expr2.V.FVal.V; + Expr->Type = type_float; + //Expr->Type = ArithmeticConvert (Expr->Type, Expr2.Type); AddDone = 1; - } else if (ED_IsAbs (Expr) && - (ED_IsAbs (&Expr2) || rscale == 1)) { - if (IsClassInt (lhst) && IsClassInt (rhst)) { - Expr2.Type = ArithmeticConvert (Expr2.Type, Expr->Type); - } - Expr2.IVal = Expr->IVal * lscale + Expr2.IVal * rscale; - /* Adjust the flags */ - Expr2.Flags |= Expr->Flags & ~E_MASK_KEEP_SUBEXPR; - /* Get the symbol and the name */ - *Expr = Expr2; + LOG(("%s:%d parseadd (float const + float const) res:%f\n", __FILE__, __LINE__, Expr->V.FVal.V)); +#if 1 + } else if (!DoArrayRef && IsClassFloat (lhst) && IsClassInt (rhst)) { + /* float + int */ + /* FIXME: float - this is probably completely wrong */ + Expr->V.FVal.V = Expr->V.FVal.V + Expr2.IVal; + Expr->Type = type_float; + //Expr->Type = ArithmeticConvert (Expr->Type, Expr2.Type); AddDone = 1; + LOG(("%s:%d parseadd (float const + int const) res:%f\n", __FILE__, __LINE__, Expr->V.FVal.V)); +#endif +#if 1 + } else if (!DoArrayRef && IsClassInt (lhst) && IsClassFloat (rhst)) { + /* int + float */ + /* FIXME: float - this is probably completely wrong */ + Expr->V.FVal.V = Expr->IVal + Expr2.V.FVal.V; + Expr->Type = type_float; + //Expr->Type = ArithmeticConvert (Expr->Type, Expr2.Type); + AddDone = 1; + LOG(("%s:%d parseadd (int const + float const) res:%f\n", __FILE__, __LINE__, Expr->V.FVal.V)); +#endif + } else { + /* integer + integer */ + if (ED_IsAbs (&Expr2) && + (ED_IsAbs (Expr) || lscale == 1)) { + if (IsClassInt (lhst) && IsClassInt (rhst)) { + Expr->Type = ArithmeticConvert (Expr->Type, Expr2.Type); + } + Expr->IVal = Expr->IVal * lscale + Expr2.IVal * rscale; + AddDone = 1; + } else if (ED_IsAbs (Expr) && + (ED_IsAbs (&Expr2) || rscale == 1)) { + if (IsClassInt (lhst) && IsClassInt (rhst)) { + Expr2.Type = ArithmeticConvert (Expr2.Type, Expr->Type); + } + Expr2.IVal = Expr->IVal * lscale + Expr2.IVal * rscale; + /* Adjust the flags */ + Expr2.Flags |= Expr->Flags & ~E_MASK_KEEP_SUBEXPR; + /* Get the symbol and the name */ + *Expr = Expr2; + AddDone = 1; + } } } @@ -2961,27 +3413,50 @@ static void parseadd (ExprDesc* Expr, int DoArrayRef) } else if (!DoArrayRef && IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer addition */ flags |= typeadjust (Expr, &Expr2, 1); + } else if (!DoArrayRef && IsClassFloat (lhst) && IsClassFloat (rhst)) { + /* Float const + float var addition */ + LOG(("%s:%d parseadd float addition (const + var)\n", __FILE__, __LINE__)); + flags |= typeadjust (Expr, &Expr2, 1); +#if 1 + } else if (!DoArrayRef && IsClassFloat (lhst) && IsClassInt (rhst)) { +//printf("const 1\n"); + /* Float const + int var addition */ + LOG(("%s:%d parseadd float addition (float const + int var)\n", __FILE__, __LINE__)); + flags |= typeadjust (Expr, &Expr2, 1); +#endif + } else if (!DoArrayRef && IsClassInt (lhst) && IsClassFloat (rhst)) { + /* FIXME: int const + Float var addition */ + LOG(("%s:%d parseadd float addition (int const + float var)\n", __FILE__, __LINE__)); + RemoveCode (&Mark); + LoadExpr (CF_FLOAT, &Expr2); + //flags |= typeadjust (Expr, &Expr2, 0); + flags |= CF_FLOAT; } else { /* OOPS */ + LOG(("%s:%d OOPS\n", __FILE__, __LINE__)); AddDone = -1; } /* Generate the code for the add */ if (!AddDone) { - if (ED_IsAbs (Expr) && - Expr->IVal >= 0 && - Expr->IVal * lscale < 256) { - /* Numeric constant */ - g_inc (flags, Expr->IVal * lscale); - AddDone = 1; + if (!IsClassFloat (lhst) && !IsClassFloat (rhst)) { + if (ED_IsAbs (Expr) && + Expr->IVal >= 0 && + Expr->IVal * lscale < 256) { + LOG(("%s:%d call g_inc for integer\n", __FILE__, __LINE__)); + /* Numeric constant */ + g_inc (flags, Expr->IVal * lscale); + AddDone = 1; + } } } - + LOG(("%s:%d AddDone:%d\n", __FILE__, __LINE__, AddDone)); if (!AddDone) { if (ED_IsLocQuasiConst (&Expr2) && !IsTypeBitField (Expr2.Type) && rscale == 1 && CheckedSizeOf (rhst) == SIZEOF_CHAR) { + LOG(("%s:%d char\n", __FILE__, __LINE__)); /* Change the order back */ RemoveCode (&Mark); /* Load lhs */ @@ -2996,8 +3471,28 @@ static void parseadd (ExprDesc* Expr, int DoArrayRef) } } else if (ED_IsAbs (Expr)) { /* Numeric constant */ - g_inc (flags, Expr->IVal * lscale); + LOG(("%s:%d parseadd lhs is numeric constant\n", __FILE__, __LINE__)); + if (CG_TypeOf (Expr->Type) == CF_FLOAT) { + // lhs = float + LOG(("%s:%d parseadd lhs const float\n", __FILE__, __LINE__)); + Double res = FP_D_Mul(Expr->V.FVal, FP_D_FromInt(lscale)); + g_inc (flags, FP_D_As32bitRaw(res)); + } else { + // lhs = int + LOG(("%s:%d parseadd lhs const int:%d\n", __FILE__, __LINE__, Expr->IVal)); + if (CG_TypeOf (Expr2.Type) == CF_FLOAT) { + // lhs = int, rhs float + LOG(("%s:%d parseadd rhs float:%08x\n", __FILE__, __LINE__, FP_D_As32bitRaw(FP_D_FromInt(Expr->IVal * lscale)))); + g_inc (flags, FP_D_As32bitRaw(FP_D_FromInt(Expr->IVal * lscale))); + Expr->Type = Expr2.Type; // HACK! + } else { + // lhs = int, rhs int + LOG(("%s:%d parseadd rhs int:%d\n", __FILE__, __LINE__, Expr->IVal)); + g_inc (flags, Expr->IVal * lscale); + } + } } else if (lscale == 1) { + LOG(("%s:%d addr\n", __FILE__, __LINE__)); if (ED_IsLocStack (Expr)) { /* Constant address */ g_addaddr_local (flags, Expr->IVal); @@ -3005,6 +3500,7 @@ static void parseadd (ExprDesc* Expr, int DoArrayRef) g_addaddr_static (flags, Expr->Name, Expr->IVal); } } else { + LOG(("%s:%d call long way\n", __FILE__, __LINE__)); /* Since we do already have rhs in the primary, if lhs is ** not a numeric constant, and the scale factor is not one ** (no scaling), we must take the long way over the stack. @@ -3055,13 +3551,53 @@ static void parseadd (ExprDesc* Expr, int DoArrayRef) } else if (!DoArrayRef && IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer addition */ flags = typeadjust (Expr, &Expr2, 1); + } else if (!DoArrayRef && IsClassFloat (lhst) && IsClassFloat (rhst)) { + /* FIXME: float - what to do here exactly? */ + LOG(("%s:%d float addition (Expr2.V.FVal.V:%f)\n", __FILE__, __LINE__, Expr2.V.FVal.V)); + /* Float addition (float variable + float constant) */ + /*flags = typeadjust (Expr, &Expr2, 1);*/ + flags |= CF_FLOAT; + Expr->Type = Expr2.Type; +#if 1 + } else if (!DoArrayRef && IsClassInt (lhst) && IsClassFloat (rhst)) { + /* FIXME: float - what to do here exactly? */ + LOG(("%s:%d float addition (Expr2.V.FVal.V:%f)\n", __FILE__, __LINE__, Expr2.V.FVal.V)); + /* Float addition (int variable + float constant) */ + /* adjust lhs */ + flags = typeadjust (Expr, &Expr2, 1); +// flags |= CF_FLOAT; +// Expr->Type = Expr2.Type; +#endif +#if 1 + } else if (!DoArrayRef && IsClassFloat (lhst) && IsClassInt (rhst)) { + /* FIXME: float - what to do here exactly? */ + LOG(("%s:%d float addition (Expr2.V.FVal.V:%f)\n", __FILE__, __LINE__, Expr2.V.FVal.V)); + /* Float addition (float variable + int constant) */ + /*flags = typeadjust (Expr, &Expr2, 1);*/ + flags |= CF_FLOAT; + // Expr->Type = Expr2.Type; +// g_push(CF_FLOAT, 0); + /* Load lhs */ + // flags = typeadjust (Expr, &Expr2, 0); +#endif } else { /* OOPS */ + LOG(("%s:%d OOPS\n", __FILE__, __LINE__)); AddDone = -1; } - /* Generate code for the add */ - g_inc (flags | CF_CONST, Expr2.IVal); + /* add rhs constant value */ + if (flags & CF_FLOAT) { + /* FIXME: float - what to do here exactly? */ + if (IsClassInt (rhst)) { + g_inc (flags | CF_CONST, FP_D_As32bitRaw(FP_D_FromInt(Expr2.IVal))); + } else { + g_inc (flags | CF_CONST, FP_D_As32bitRaw(Expr2.V.FVal)); + } + } else { + /* Generate code for the add */ + g_inc (flags | CF_CONST, Expr2.IVal); + } } else { @@ -3105,8 +3641,47 @@ static void parseadd (ExprDesc* Expr, int DoArrayRef) LoadExpr (CF_NONE, &Expr2); /* Adjust rhs primary if needed */ flags = typeadjust (Expr, &Expr2, 0); + } else if (!DoArrayRef && IsClassFloat (lhst) && IsClassFloat (rhst)) { + /* FIXME: float - what to do here exactly? */ + LOG(("%s:%d float addition (Expr2.V.FVal.V:%f)\n", __FILE__, __LINE__, Expr2.V.FVal.V)); + /* Float addition */ + /* flags = typeadjust (Expr, &Expr2, 0); */ + flags |= CF_FLOAT; + /* Load rhs into the primary */ + LoadExpr (CF_NONE, &Expr2); +#if 1 + } else if (!DoArrayRef && IsClassFloat (lhst) && IsClassInt (rhst)) { + /* FIXME: float - what to do here exactly? */ + LOG(("%s:%d float+int addition (Expr2.V.FVal.V:%f)\n", __FILE__, __LINE__, Expr2.V.FVal.V)); + /* Float addition (float + integer) */ +// flags = typeadjust (Expr, &Expr2, 0); +// flags |= CF_FLOAT; + /* Load rhs into the primary */ + LoadExpr (CF_NONE, &Expr2); + /* Adjust rhs primary if needed */ + flags = typeadjust (Expr, &Expr2, 0); +#endif +#if 1 + } else if (!DoArrayRef && IsClassInt (lhst) && IsClassFloat (rhst)) { + /* FIXME: float - what to do here exactly? */ + LOG(("%s:%d int+float addition (Expr2.V.FVal.V:%f)\n", __FILE__, __LINE__, Expr2.V.FVal.V)); + /* Float addition (integer + float) */ + RemoveCode (&Mark); /* Remove pushed value from stack */ + /* Adjust lhs primary if needed */ + flags = typeadjust (Expr, &Expr2, 0); + // convert lhs to float + // g_regfloat (flags); + g_push (CF_FLOAT, 0); /* --> stack */ +// flags = typeadjust (Expr, &Expr2, 0); +// flags |= CF_FLOAT; + /* Load rhs into the primary */ + LoadExpr (CF_NONE, &Expr2); + /* Adjust rhs primary if needed */ + flags = typeadjust (Expr, &Expr2, 0); +#endif } else { /* OOPS */ + LOG(("%s:%d OOPS\n", __FILE__, __LINE__)); AddDone = -1; /* We can't just goto End as that would leave the stack unbalanced */ } @@ -3314,31 +3889,67 @@ static void parsesub (ExprDesc* Expr) } else if (ED_IsQuasiConst (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) { + LOG(("parsesub: rhs is const\n")); + /* Right hand side is constant. Check left hand side. */ if (ED_IsQuasiConst (Expr)) { + LOG(("parsesub: lhs and rhs are const\n")); + /* Both sides are constant. Check for pointer arithmetic */ if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Pointer subtraction. We've got the scale factor and flags above */ } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer subtraction. We'll adjust the types later */ +#if 1 + } else if (IsClassFloat (lhst) && IsClassFloat (rhst)) { + /* Float subtraction. We'll adjust the types later */ + } else if (IsClassFloat (lhst) && IsClassInt (rhst)) { + /* Float/Int subtraction. We'll adjust the types later */ + } else if (IsClassInt (lhst) && IsClassFloat (rhst)) { + /* Int/Float subtraction. We'll adjust the types later */ +#endif } else { /* OOPS */ Error ("Invalid operands for binary operator '-'"); } - /* We can't make all subtraction expressions constant */ - if (ED_IsConstAbs (&Expr2)) { - Expr->IVal -= Expr2.IVal * rscale; - /* No runtime code */ - SubDone = 1; - } else if (rscale == 1 && Expr->Sym == Expr2.Sym) { - /* The result is the diff of the offsets */ - Expr->IVal -= Expr2.IVal; - /* Get rid of unneeded bases and flags etc. */ - ED_MakeConstAbs (Expr, Expr->IVal, Expr->Type); - /* No runtime code */ - SubDone = 1; + if (!IsClassFloat (lhst) && !IsClassFloat (rhst)) { + LOG(("parsesub const int - const int\n")); + /* We can't make all subtraction expressions constant */ + if (ED_IsConstAbs (&Expr2)) { + Expr->IVal -= Expr2.IVal * rscale; + /* No runtime code */ + SubDone = 1; + } else if (rscale == 1 && Expr->Sym == Expr2.Sym) { + /* The result is the diff of the offsets */ + Expr->IVal -= Expr2.IVal; + /* Get rid of unneeded bases and flags etc. */ + ED_MakeConstAbs (Expr, Expr->IVal, Expr->Type); + /* No runtime code */ + SubDone = 1; + } + } else if (IsClassFloat (lhst) && IsClassInt (rhst)) { + LOG(("parsesub const float - const int\n")); + if (ED_IsConstAbs (&Expr2)) { + Expr->V.FVal = FP_D_Sub(Expr->V.FVal, FP_D_FromInt(Expr2.IVal)); + /* No runtime code */ + SubDone = 1; + } + } else if (IsClassInt (lhst) && IsClassFloat (rhst)) { + LOG(("parsesub const int - const float\n")); + if (ED_IsConstAbs (&Expr2)) { + Expr->V.FVal = FP_D_Sub(FP_D_FromInt(Expr->IVal), Expr2.V.FVal); + /* No runtime code */ + SubDone = 1; + } + } else if (IsClassFloat (lhst) && IsClassFloat (rhst)) { + LOG(("FIXME: parsesub const float - const float\n")); + if (ED_IsConstAbs (&Expr2)) { + Expr->V.FVal = FP_D_Sub(Expr->V.FVal, Expr2.V.FVal); + /* No runtime code */ + SubDone = 1; + } } if (SubDone) { @@ -3353,20 +3964,38 @@ static void parsesub (ExprDesc* Expr) /* The result is always an rvalue */ ED_MarkExprAsRVal (Expr); } else { + /* NOTE: float always uses this codepath right now */ if (ED_IsConstAbs (&Expr2)) { /* Remove pushed value from stack */ RemoveCode (&Mark2); if (IsClassInt (lhst)) { /* Adjust the types */ flags = typeadjust (Expr, &Expr2, 1); + /* Do the subtraction */ + g_dec (flags | CF_CONST, Expr2.IVal * rscale); + } + else if (IsClassFloat (lhst)) { + /* Adjust the types */ + flags = typeadjust (Expr, &Expr2, 1); + if (rscale != 1) { + Internal("scale != 1 for float"); + } + /* Do the subtraction */ + g_dec (flags | CF_CONST, FP_D_As32bitRaw(Expr2.V.FVal)); + } + else { + /* Do the subtraction */ + g_dec (flags | CF_CONST, Expr2.IVal * rscale); } - /* Do the subtraction */ - g_dec (flags | CF_CONST, Expr2.IVal * rscale); } else { if (IsClassInt (lhst)) { /* Adjust the types */ flags = typeadjust (Expr, &Expr2, 0); } + else if (IsClassFloat (lhst)) { + /* Adjust the types */ + flags = typeadjust (Expr, &Expr2, 0); + } /* Load rhs into the primary */ LoadExpr (CF_NONE, &Expr2); g_scale (CG_TypeOf (rhst), rscale); @@ -3378,12 +4007,26 @@ static void parsesub (ExprDesc* Expr) } } else { + LOG(("parsesub: lhs not const, rhs is const\n")); /* Left hand side is not constant, right hand side is */ if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Pointer subtraction. We've got the scale factor and flags above */ } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer subtraction. We'll adjust the types later */ +#if 1 + } else if (IsClassFloat (lhst) && IsClassFloat (rhst)) { + /* Float subtraction. We'll adjust the types later */ + LOG(("parsesub: float - float\n")); + } else if (IsClassFloat (lhst) && IsClassInt (rhst)) { + /* Float/Int subtraction. We'll adjust the types later */ + LOG(("parsesub: float - int\n")); + flags = CF_FLOAT; + } else if (IsClassInt (lhst) && IsClassFloat (rhst)) { + /* Int/Float subtraction. We'll adjust the types later */ + LOG(("parsesub: int - float\n")); + flags = CF_FLOAT; +#endif } else { /* OOPS */ Error ("Invalid operands for binary operator '-'"); @@ -3391,19 +4034,57 @@ static void parsesub (ExprDesc* Expr) } if (ED_IsConstAbs (&Expr2)) { + /* rhs is constant */ /* Remove pushed value from stack */ RemoveCode (&Mark2); if (IsClassInt (lhst)) { + // lhs is integer, rhs is constant + LOG(("parsesub: lhst int\n")); /* Adjust the types */ flags = typeadjust (Expr, &Expr2, 1); + /* Do the subtraction */ + if (IsClassFloat(rhst)) { + g_dec (flags | CF_CONST, FP_D_As32bitRaw(Expr2.V.FVal)); + } else { + g_dec (flags | CF_CONST, Expr2.IVal * rscale); + } + } + else if (IsClassFloat (lhst)) { + // lhs is float, rhs is constant + LOG(("parsesub: lhst float\n")); + /* Do the subtraction */ + if (IsClassFloat(rhst)) { + LOG(("parsesub: rhst const float %f\n", Expr2.V.FVal.V)); + flags = typeadjust (&Expr2, Expr, 1); +// flags = typeadjust (Expr, &Expr2, 1); + g_dec (flags | CF_CONST, FP_D_As32bitRaw(Expr2.V.FVal)); + } else { + LOG(("parsesub: rhst const int: %d\n", Expr2.IVal * rscale)); + /* Adjust rhs type */ + LoadExpr(CF_FLOAT, Expr); + if (rscale != 1) { + Internal("scale != 1 for float"); + } + g_dec (flags | CF_CONST, FP_D_As32bitRaw(FP_D_FromInt(Expr2.IVal * rscale))); +// g_dec (flags | CF_CONST, Expr2.IVal * rscale); + } +// g_dec (flags | CF_CONST, FP_D_As32bitRaw(Expr2.V.FVal)); + } + else { + /* Do the subtraction */ + g_dec (flags | CF_CONST, Expr2.IVal * rscale); } - /* Do the subtraction */ - g_dec (flags | CF_CONST, Expr2.IVal * rscale); } else { if (IsClassInt (lhst)) { + LOG(("non const int sub 1\n")); /* Adjust the types */ flags = typeadjust (Expr, &Expr2, 0); } + else if (IsClassFloat (lhst)) { + LOG(("non const float sub 2\n")); + /* Adjust the types */ + flags = typeadjust (Expr, &Expr2, 1); + } /* Load rhs into the primary */ LoadExpr (CF_NONE, &Expr2); g_scale (CG_TypeOf (rhst), rscale); @@ -3416,6 +4097,7 @@ static void parsesub (ExprDesc* Expr) } } else { + LOG(("parsesub: rhs not const\n")); /* We'll use the pushed lhs on stack instead of the original source */ ED_FinalizeRValLoad (Expr); @@ -3430,6 +4112,34 @@ static void parsesub (ExprDesc* Expr) } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Adjust operand types */ flags = typeadjust (Expr, &Expr2, 0); + } else if (IsClassFloat (lhst) && IsClassFloat (rhst)) { + /* Float substraction */ + /* FIXME: float - what to do here exactly? */ + LOG(("%s:%d parsesub float - float var\n", __FILE__, __LINE__)); + /* Adjust operand types */ + /*flags = typeadjust (Expr, &Expr2, 0);*/ + flags = CF_FLOAT; + } else if (IsClassFloat (lhst) && IsClassInt (rhst)) { + /* Float substraction */ + /* FIXME: float - what to do here exactly? */ + LOG(("%s:%d parsesub float - int var\n", __FILE__, __LINE__)); +#if 1 + /* Adjust operand types */ + flags = typeadjust (Expr, &Expr2, 0); + //flags = CF_FLOAT; +#endif + } else if (IsClassInt (lhst) && IsClassFloat (rhst)) { + /* Float substraction */ + /* FIXME: float - what to do here exactly? */ + LOG(("FIXME: %s:%d parsesub int - float var\n", __FILE__, __LINE__)); +#if 1 + /* Remove pushed value from stack */ + RemoveCode (&Mark2); + flags = typeadjust (&Expr2, Expr, 0); + g_push (CF_FLOAT, 0); /* --> stack */ + LoadExpr (CF_FLOAT, &Expr2); /* --> primary register */ +#endif + } else { /* OOPS */ Error ("Invalid operands for binary operator '-'"); @@ -3442,8 +4152,12 @@ static void parsesub (ExprDesc* Expr) ED_FinalizeRValLoad (Expr); } - /* Result type is either a pointer or an integer */ - Expr->Type = StdConversion (Expr->Type); + if (IsClassFloat (lhst) || IsClassFloat (rhst)) { + Expr->Type = type_float; + } else { + /* Result type is either a pointer or an integer */ + Expr->Type = StdConversion (Expr->Type); + } /* Condition code not set */ ED_MarkAsUntested (Expr); @@ -4094,6 +4808,9 @@ static void hieQuest (ExprDesc* Expr) } else if (IsTypeVoid (Expr2.Type) && IsTypeVoid (Expr3.Type)) { /* Result type is void */ ResultType = TypeDup (type_void); + } else if (IsTypeFloat (Expr2.Type) && IsTypeFloat (Expr3.Type)) { + /* Result type is float */ + ResultType = TypeDup (type_float); } else { if (IsClassStruct (Expr2.Type) && IsClassStruct (Expr3.Type) && TypeCmp (Expr2.Type, Expr3.Type).C == TC_IDENTICAL) { diff --git a/src/cc65/initdata.c b/src/cc65/initdata.c index 82cebefc2..db654b7e8 100644 --- a/src/cc65/initdata.c +++ b/src/cc65/initdata.c @@ -31,10 +31,11 @@ /* */ /*****************************************************************************/ - +//#define DEBUG #include #include +#include #include #include @@ -66,7 +67,13 @@ #include "typeconv.h" #include "initdata.h" - +#ifdef DEBUG +#define LOG(x) printf x +#define FIXME(x) printf x +#else +#define LOG(x) +#define FIXME(x) +#endif /*****************************************************************************/ /* Data */ @@ -165,34 +172,48 @@ static void ClosingCurlyBraces (unsigned BracesExpected) static void DefineData (ExprDesc* Expr) /* Output a data definition for the given expression */ { + int isfloat = (CG_TypeOf (Expr->Type) == CF_FLOAT); + + LOG(("%s:%d DefineData IVal: %ld V.FVal: %f isfloat:%d %d\n", __FILE__, __LINE__, + Expr->IVal, (double)(Expr->V.FVal.V), isfloat, ED_GetLoc (Expr))); switch (ED_GetLoc (Expr)) { case E_LOC_NONE: /* Immediate numeric value with no storage */ - g_defdata (CF_IMM | CG_TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0); + /* FIXME: float */ + if (isfloat) { + g_defdata_float (CF_IMM | CG_TypeOf (Expr->Type) | CF_CONST, FP_D_As32bitRaw(Expr->V.FVal), 0); + } else { + g_defdata (CF_IMM | CG_TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0); + } break; - +/* FIXME: float - other cases */ case E_LOC_ABS: + if (isfloat) { printf("%s:%d FIXME: E_LOC_ABS\n", __FILE__, __LINE__); exit(-1); } /* Absolute numeric address */ g_defdata (CF_ABSOLUTE | CG_TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0); break; case E_LOC_GLOBAL: + if (isfloat) { printf("%s:%d FIXME: E_LOC_GLOBAL\n", __FILE__, __LINE__); exit(-1); } /* Global variable */ g_defdata (CF_EXTERNAL, Expr->Name, Expr->IVal); break; case E_LOC_STATIC: + if (isfloat) { printf("%s:%d FIXME: E_LOC_STATIC\n", __FILE__, __LINE__); exit(-1); } /* Static variable */ g_defdata (CF_STATIC, Expr->Name, Expr->IVal); break; case E_LOC_LITERAL: + if (isfloat) { printf("%s:%d FIXME: E_LOC_LITERAL\n", __FILE__, __LINE__); exit(-1); } /* Literal in the literal pool */ g_defdata (CF_LITERAL, Expr->Name, Expr->IVal); break; case E_LOC_REGISTER: + if (isfloat) { printf("%s:%d FIXME: E_LOC_REGISTER\n", __FILE__, __LINE__); exit(-1); } /* Register variable. Taking the address is usually not ** allowed. */ @@ -203,6 +224,7 @@ static void DefineData (ExprDesc* Expr) break; case E_LOC_CODE: + if (isfloat) { printf("%s:%d FIXME: E_LOC_CODE\n", __FILE__, __LINE__); exit(-1); } /* Code label location */ g_defdata (CF_CODE, Expr->Name, Expr->IVal); break; diff --git a/src/cc65/loadexpr.c b/src/cc65/loadexpr.c index d06ca9437..d09cabdc2 100644 --- a/src/cc65/loadexpr.c +++ b/src/cc65/loadexpr.c @@ -31,7 +31,9 @@ /* */ /*****************************************************************************/ +//#define DEBUG +#include /* cc65 */ #include "codegen.h" @@ -41,7 +43,13 @@ #include "global.h" #include "loadexpr.h" - +#ifdef DEBUG +#define LOG(x) printf x +#define FIXME(x) printf x +#else +#define LOG(x) +#define FIXME(x) +#endif /*****************************************************************************/ /* Code */ @@ -52,6 +60,7 @@ static void LoadAddress (unsigned Flags, ExprDesc* Expr) /* Load the primary register with some address value. */ { + LOG(("LoadAddress flags:%04x\n", Flags)); switch (ED_GetLoc (Expr)) { case E_LOC_ABS: @@ -119,6 +128,7 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr) ** unfortunately. */ { + /*LOG(("LoadExpr flags:%4x\n", Flags));*/ if (!ED_IsAddrExpr (Expr)) { /* Lvalue. If this is a bit field its type is unsigned. But if the @@ -171,57 +181,88 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr) } /* Load the content of Expr */ + /*LOG(("LoadExpr ED_GetLoc:%04x\n", ED_GetLoc (Expr)));*/ switch (ED_GetLoc (Expr)) { case E_LOC_NONE: + /* FIXME: float */ + /*LOG(("LoadExpr E_LOC_NONE (%s)\n", (CG_TypeOf (Expr->Type) == CF_FLOAT) ? "float" : "integer"));*/ /* Immediate number constant */ - g_getimmed (Flags | CF_IMM | CG_TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0); + if (CG_TypeOf (Expr->Type) == CF_FLOAT) { + g_getimmed (Flags | CF_IMM | CG_TypeOf (Expr->Type) | CF_CONST, FP_D_As32bitRaw(Expr->V.FVal), 0); + } else { + g_getimmed (Flags | CF_IMM | CG_TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0); + } break; case E_LOC_ABS: + LOG(("LoadExpr E_LOC_ABS (%s)\n", (CG_TypeOf (Expr->Type) == CF_FLOAT) ? "float" : "integer")); + if (CG_TypeOf (Expr->Type) == CF_FLOAT) { printf("%s:%d FIXME: E_LOC_ABS\n", __FILE__, __LINE__); exit(-1); } /* Absolute numeric addressed variable */ g_getstatic (Flags | CF_ABSOLUTE, Expr->IVal, 0); break; case E_LOC_GLOBAL: - /* Global variable */ + /* LOG(("LoadExpr E_LOC_GLOBAL (%s)\n", (CG_TypeOf (Expr->Type) == CF_FLOAT) ? "float" : "integer")); */ + /* if (CG_TypeOf (Expr->Type) == CF_FLOAT) { printf("%s:%d FIXME: E_LOC_GLOBAL\n", __FILE__, __LINE__); exit(-1); } */ + /* Global variable, offset in IVal */ g_getstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->IVal); break; case E_LOC_STATIC: - /* Static variable */ + /* LOG(("LoadExpr E_LOC_STATIC (%s)\n", (CG_TypeOf (Expr->Type) == CF_FLOAT) ? "float" : "integer")); */ + /* if (CG_TypeOf (Expr->Type) == CF_FLOAT) { printf("%s:%d FIXME: E_LOC_STATIC\n", __FILE__, __LINE__); exit(-1); } */ + /* Static variable, offset in IVal */ g_getstatic (Flags | CF_STATIC, Expr->Name, Expr->IVal); break; case E_LOC_LITERAL: - /* Literal in the literal pool */ + /* LOG(("LoadExpr E_LOC_LITERAL (%s)\n", (CG_TypeOf (Expr->Type) == CF_FLOAT) ? "float" : "integer")); */ + /* if (CG_TypeOf (Expr->Type) == CF_FLOAT) { printf("%s:%d FIXME: E_LOC_LITERAL\n", __FILE__, __LINE__); exit(-1); } */ + /* Literal in the literal pool, offset in IVal */ g_getstatic (Flags | CF_LITERAL, Expr->Name, Expr->IVal); break; case E_LOC_REGISTER: - /* Register variable */ + /* LOG(("LoadExpr E_LOC_REGISTER (%s)\n", (CG_TypeOf (Expr->Type) == CF_FLOAT) ? "float" : "integer")); */ + /* if (CG_TypeOf (Expr->Type) == CF_FLOAT) { printf("%s:%d FIXME: E_LOC_REGISTER\n", __FILE__, __LINE__); exit(-1); } */ + /* Register variable, offset in IVal */ g_getstatic (Flags | CF_REGVAR, Expr->Name, Expr->IVal); break; case E_LOC_CODE: - /* Code label location */ + /* LOG(("LoadExpr E_LOC_CODE (%s)\n", (CG_TypeOf (Expr->Type) == CF_FLOAT) ? "float" : "integer")); */ + /* if (CG_TypeOf (Expr->Type) == CF_FLOAT) { printf("%s:%d FIXME: E_LOC_CODE\n", __FILE__, __LINE__); exit(-1); } */ + /* Code label location, offset in IVal */ g_getstatic (Flags | CF_CODE, Expr->Name, Expr->IVal); break; case E_LOC_STACK: - /* Value on the stack */ + /* LOG(("LoadExpr E_LOC_STACK (%s)\n", (CG_TypeOf (Expr->Type) == CF_FLOAT) ? "float" : "integer")); */ + /* if (CG_TypeOf (Expr->Type) == CF_FLOAT) { printf("%s:%d FIXME: E_LOC_STACK\n", __FILE__, __LINE__); exit(-1); } */ + /* Fetch value on the stack (with offset in IVal) */ g_getlocal (Flags, Expr->IVal); break; case E_LOC_PRIMARY: + /*LOG(("LoadExpr E_LOC_PRIMARY (%s)\n", (CG_TypeOf (Expr->Type) == CF_FLOAT) ? "float" : "integer"));*/ + /*if (CG_TypeOf (Expr->Type) == CF_FLOAT) { printf("%s:%d FIXME: E_LOC_PRIMARY\n", __FILE__, __LINE__); exit(-1); }*/ /* The primary register */ - if (Expr->IVal != 0) { - /* We have an expression in the primary plus a constant - ** offset. Adjust the value in the primary accordingly. - */ - g_inc (Flags | CF_CONST, Expr->IVal); + if (CG_TypeOf (Expr->Type) == CF_FLOAT) { + /* FIXME: float */ + Flags |= CF_FLOAT; + if (Expr->V.FVal.V != 0.0f) { + g_inc (Flags | CF_CONST, FP_D_As32bitRaw(Expr->V.FVal)); + } + } else { + if (Expr->IVal != 0) { + /* We have an expression in the primary plus a constant + ** offset. Adjust the value in the primary accordingly. + */ + g_inc (Flags | CF_CONST, Expr->IVal); - /* We might want to clear the offset, but we can't */ + /* We might want to clear the offset, but we can't */ + } } if (Flags & CF_TEST) { g_test (Flags); @@ -229,7 +270,9 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr) break; case E_LOC_EXPR: - /* Reference to address in primary with offset in Expr */ + /*LOG(("LoadExpr E_LOC_EXPR (%s)\n", (CG_TypeOf (Expr->Type) == CF_FLOAT) ? "float" : "integer"));*/ + /*if (CG_TypeOf (Expr->Type) == CF_FLOAT) { printf("%s:%d FIXME: E_LOC_EXPR\n", __FILE__, __LINE__); exit(-1); }*/ + /* Reference to address in primary with offset in IVal */ g_getind (Flags, Expr->IVal); /* Since the content in primary is now overwritten with the diff --git a/src/cc65/locals.c b/src/cc65/locals.c index 34d762324..4fa4a6a17 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -31,7 +31,7 @@ /* */ /*****************************************************************************/ - +//#define DEBUG /* common */ #include "xmalloc.h" @@ -57,7 +57,13 @@ #include "typeconv.h" #include "input.h" - +#ifdef DEBUG +#define LOG(x) printf x +#define FIXME(x) printf x +#else +#define LOG(x) +#define FIXME(x) +#endif /*****************************************************************************/ /* Code */ @@ -199,6 +205,8 @@ static void ParseAutoDecl (Declarator* Decl) /* Get the size of the variable */ unsigned Size = SizeOf (Decl->Type); + LOG(("ParseAutoDecl SIze:%d IsCompound:%d\n", Size, IsCompound)); + /* Check if this is a variable on the stack or in static memory */ if (IS_Get (&StaticLocals) == 0) { @@ -275,7 +283,20 @@ static void ParseAutoDecl (Declarator* Decl) } /* Push the value */ - g_push (Flags | CG_TypeOf (Sym->Type), Expr.IVal); + if (CG_TypeOf (Sym->Type) == CF_FLOAT) { +#if defined(_MSC_VER) +#pragma warning( push ) +#pragma warning( disable : 4244 ) // conversion from double to float +#endif + /* FIXME: float */ + LOG(("ParseAutoDecl Expr.V.FVal.V: %f\n", Expr.V.FVal.V)); + g_push_float (Flags | CG_TypeOf (Sym->Type), Expr.V.FVal.V); +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif + } else { + g_push (Flags | CG_TypeOf (Sym->Type), Expr.IVal); + } /* This has to be done at sequence point */ DoDeferred (SQP_KEEP_NONE, &Expr); diff --git a/src/cc65/scanner.c b/src/cc65/scanner.c index 6b5235679..8f36b1e90 100644 --- a/src/cc65/scanner.c +++ b/src/cc65/scanner.c @@ -31,7 +31,7 @@ /* */ /*****************************************************************************/ - +//#define DEBUG #include #include @@ -62,7 +62,13 @@ #include "standard.h" #include "symtab.h" - +#ifdef DEBUG +#define LOG(x) printf x +#define FIXME(x) printf x +#else +#define LOG(x) +#define FIXME(x) +#endif /*****************************************************************************/ /* data */ @@ -696,6 +702,8 @@ static void NumericConst (void) /* Float constant */ Double FVal = FP_D_FromInt (IVal); /* Convert to double */ + LOG(("NumericConst start IVal:%ld FVal: %f\n", IVal, FVal.V)); + /* Check for a fractional part and read it */ if (SB_Peek (&Src) == '.') { @@ -771,6 +779,8 @@ static void NumericConst (void) } } + LOG(("NumericConst end FVal: %f\n", FVal.V)); + /* Check for a suffix and determine the type of the constant */ if (toupper (SB_Peek (&Src)) == 'F') { SB_Skip (&Src); @@ -788,7 +798,7 @@ static void NumericConst (void) NextTok.Tok = TOK_FCONST; } - + LOG(("NumericConst exit IsFloat:%d IVal: %ld FVal: %f\n", IsFloat, NextTok.IVal, NextTok.FVal.V)); /* We don't need the string buffer any longer */ SB_Done (&Src); } diff --git a/src/cc65/typeconv.c b/src/cc65/typeconv.c index 6e9fad69a..5987696cd 100644 --- a/src/cc65/typeconv.c +++ b/src/cc65/typeconv.c @@ -31,7 +31,7 @@ /* */ /*****************************************************************************/ - +//#define DEBUG /* common */ #include "shift.h" @@ -47,7 +47,13 @@ #include "typecmp.h" #include "typeconv.h" - +#ifdef DEBUG +#define LOG(x) printf x +#define FIXME(x) printf x +#else +#define LOG(x) +#define FIXME(x) +#endif /*****************************************************************************/ /* Code */ @@ -97,7 +103,10 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType, int Explicit) /* lvalue? */ if (ED_IsLVal (Expr)) { - + LOG(("DoConversion 1 Old: %s New: %s\n", + (IsTypeFloat (OldType)) ? "float" : "int", + (IsTypeFloat (NewType)) ? "float" : "int" + )); /* We have an lvalue. If the new size is smaller than the old one, ** we don't need to do anything. The compiler will generate code ** to load only the portion of the value that is actually needed. @@ -106,7 +115,10 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType, int Explicit) ** If both sizes are equal, do also leave the value alone. ** If the new size is larger, we must convert the value. */ - if (NewBits > OldBits) { + if ((NewBits > OldBits) || + /* FIXME: float */ + /* when either side is float, emit the call to the conversion code */ + (IsTypeFloat (OldType) || IsTypeFloat (NewType))) { /* Load the value into the primary */ LoadExpr (CF_NONE, Expr); @@ -116,12 +128,27 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType, int Explicit) /* Value is now in primary and an rvalue */ ED_FinalizeRValLoad (Expr); } - + LOG(("DoConversion 1 done\n")); } else if (ED_IsConstAbs (Expr)) { + LOG(("DoConversion 2 Old: %s New: %s\n", + (IsTypeFloat (OldType)) ? "float" : "int", + (IsTypeFloat (NewType)) ? "float" : "int" + )); /* A cast of a constant numeric value to another type. Be sure ** to handle sign extension correctly. */ + /* FIXME: float --- start of new code */ + /* convert from float to (signed) long first */ + if (IsTypeFloat (OldType) && !IsTypeFloat (NewType)) { + OldBits = 32; + Expr->IVal = FP_D_ToLong(Expr->V.FVal); + LOG(("DoConversion 2 new ival: %ld\n", Expr->IVal)); + } else if (!IsTypeFloat (OldType) && IsTypeFloat (NewType)) { + OldBits = 0; + Expr->V.FVal = FP_D_FromInt(Expr->IVal); + LOG(("DoConversion 2 new fval: %f\n", Expr->V.FVal.V)); + } /* If this is a floating point constant, convert to integer, ** and warn if precision is discarded. @@ -133,11 +160,13 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType, int Explicit) } Expr->IVal = IVal; } + /* FIXME: float --- end of new code */ /* Check if the new datatype will have a smaller range. If it ** has a larger range, things are OK, since the value is ** internally already represented by a long. */ + LOG(("DoConversion 2 NewBits: %d OldBits: %d\n", NewBits, OldBits)); if (NewBits <= OldBits) { long OldVal = Expr->IVal; @@ -157,6 +186,12 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType, int Explicit) } } + if (IsTypeFloat (NewType)) { + LOG(("DoConversion 2 new fval: %f\n", Expr->V.FVal.V)); + } else { + LOG(("DoConversion 2 new ival: %ld\n", Expr->IVal)); + } + /* Do the integer constant <-> absolute address conversion if necessary */ if (IsClassPtr (NewType)) { Expr->Flags &= ~E_MASK_LOC; @@ -167,12 +202,19 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType, int Explicit) } } else { + LOG(("DoConversion 3 Old: %s New: %s\n", + (IsTypeFloat (OldType)) ? "float" : "int", + (IsTypeFloat (NewType)) ? "float" : "int" + )); /* The value is not a constant. If the sizes of the types are ** not equal, add conversion code. Be sure to convert chars ** correctly. */ - if (OldBits != NewBits) { + if ((OldBits != NewBits) || + /* FIXME: float */ + /* when either side is float, emit the call to the conversion code */ + (IsTypeFloat (OldType) || IsTypeFloat (NewType))) { /* Load the value into the primary */ LoadExpr (CF_NONE, Expr); @@ -198,14 +240,17 @@ void TypeConversion (ExprDesc* Expr, const Type* NewType) ** impossible. */ { + LOG(("TypeConversion\n")); #if 0 /* Debugging */ - printf ("Expr:\n=======================================\n"); + LOG(("=======================================\n")); + LOG(("Expr:\n---------------------------------------\n")); PrintExprDesc (stdout, Expr); - printf ("Type:\n=======================================\n"); + LOG(("\nType:\n---------------------------------------\n")); PrintType (stdout, NewType); - printf ("\n"); + LOG(("\n"); PrintRawType (stdout, NewType); + LOG(("=======================================\n")); #endif /* First, do some type checking */ typecmp_t Result = TYPECMP_INITIALIZER; diff --git a/src/common/fp.c b/src/common/fp.c index 0682f9f9e..dabfba241 100644 --- a/src/common/fp.c +++ b/src/common/fp.c @@ -45,6 +45,7 @@ #include +#include /* common */ #include "fp.h" @@ -189,7 +190,11 @@ Double FP_D_FromInt (long Val) return D; } - +long FP_D_ToLong (Double Val) +/* Convert a floating point variable into a long */ +{ + return (long)Val.V; +} double FP_D_ToFloat (Double Val) /* Convert a Double into a native double */ @@ -236,3 +241,22 @@ Double FP_D_Div (Double Left, Double Right) D.V = Left.V / Right.V; return D; } + +#if defined(_MSC_VER) +#pragma warning( push ) +#pragma warning( disable : 4244 ) // conversion from double to float +#endif +uint32_t FP_D_As32bitRaw(Double Val) +/* converts double into 32bit (float) and then returns its raw content as a 32bit int */ +{ + static float f; + uint32_t *lptr; + uint32_t lval; + f = Val.V; + lptr = (uint32_t *)&f; + lval = *lptr; + return lval; +} +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif diff --git a/src/common/fp.h b/src/common/fp.h index 4e89e2316..e3c5abc4c 100644 --- a/src/common/fp.h +++ b/src/common/fp.h @@ -52,6 +52,7 @@ #include +#include @@ -92,7 +93,7 @@ Float FP_F_Make (float Val); Float FP_F_FromInt (long Val); /* Convert an integer into a floating point variable */ -float FP_F_ToFloat (Float Val); +float FP_F_ToFloat (Float Val); /* FIXME: better name */ /* Convert a Float into a native float */ Float FP_F_Add (Float Left, Float Right); @@ -118,8 +119,9 @@ Double FP_D_Make (double Val); Double FP_D_FromInt (long Val); /* Convert an integer into a floating point variable */ +long FP_D_ToLong (Double Val); -double FP_D_ToFloat (Double Val); +double FP_D_ToFloat (Double Val); /* FIXME: better name */ /* Convert a Double into a native double */ Double FP_D_Add (Double Left, Double Right); @@ -134,7 +136,8 @@ Double FP_D_Mul (Double Left, Double Right); Double FP_D_Div (Double Left, Double Right); /* Divide two floats */ - +uint32_t FP_D_As32bitRaw(Double Val); +/* converts double into 32bit (float) and then returns its raw content as a 32bit int */ /* End of fp.h */ diff --git a/test/todo/Makefile b/test/todo/Makefile index 062b899ce..bdd59b9c7 100644 --- a/test/todo/Makefile +++ b/test/todo/Makefile @@ -50,13 +50,28 @@ define PRG_template $(WORKDIR)/%.$1.$2.prg: %.c | $(WORKDIR) $(if $(QUIET),echo todo/$$*.$1.$2.prg) - $(CC65) -t sim$2 $$(CC65FLAGS) -$1 -o $$(@:.prg=.s) $$< $(NULLERR) + $(CC65) -t sim$2 $$(CC65FLAGS) --add-source -$1 -o $$(@:.prg=.s) $$< $(NULLERR) $(CA65) -t sim$2 -o $$(@:.prg=.o) $$(@:.prg=.s) $(NULLERR) $(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR) $(NOT) $(SIM65) $(SIM65FLAGS) $$@ $(NULLOUT) endef # PRG_template +# HACK! for some reason the test does NOT fail in this particular config +$(WORKDIR)/inline-asm-1489.Osr.65c02.prg: inline-asm-1489.c | $(WORKDIR) + $(if $(QUIET),echo todo/inline-asm-1489.Osr.65c02.prg) + $(CC65) -t sim65c02 $$(CC65FLAGS) --add-source -Osr -o $(@:.prg=.s) $< $(NULLERR) + $(CA65) -t sim65c02 -o $(@:.prg=.o) $(@:.prg=.s) $(NULLERR) + $(LD65) -t sim65c02 -o $@ $(@:.prg=.o) sim65c02.lib $(NULLERR) + $(SIM65) $(SIM65FLAGS) $@ $(NULLOUT) + +$(WORKDIR)/inline-asm-1489.Os.65c02.prg: inline-asm-1489.c | $(WORKDIR) + $(if $(QUIET),echo todo/inline-asm-1489.Os.65c02.prg) + $(CC65) -t sim65c02 $$(CC65FLAGS) --add-source -Os -o $(@:.prg=.s) $< $(NULLERR) + $(CA65) -t sim65c02 -o $(@:.prg=.o) $(@:.prg=.s) $(NULLERR) + $(LD65) -t sim65c02 -o $@ $(@:.prg=.o) sim65c02.lib $(NULLERR) + $(SIM65) $(SIM65FLAGS) $@ $(NULLOUT) + $(foreach option,$(OPTIONS),$(eval $(call PRG_template,$(option),6502))) $(foreach option,$(OPTIONS),$(eval $(call PRG_template,$(option),65c02))) diff --git a/test/val/float-basic-const-const.c b/test/val/float-basic-const-const.c new file mode 100644 index 000000000..8bcb9f610 --- /dev/null +++ b/test/val/float-basic-const-const.c @@ -0,0 +1,126 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf(" (ok)"); + printf("\n"); + } else { + printf(" (failed) !!!\n"); + result++; + } +} + +void constconst(void) +{ + printf("\n*** constant vs constant\n\n"); + + // addition + printf("\nconstant + constant\n\n"); + fp1 = 0.1f; + fp2 = 0.2f; + fp3 = 0.1f + 0.2f; + + printf(" 0x%08lx [0x3dcccccd] %s (0.1)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf(" 0x%08lx [0x3e4ccccd] %s (0.2)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + printf("fp3:0x%08lx [0x3e99999a] %s (0.3)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "3e99999a"); + + // substraction + printf("\nconstant - constant\n\n"); + fp1 = 0.1f; + fp2 = 0.2f; + fp3 = 0.1f - 0.2f; + + printf(" 0x%08lx [0x3dcccccd] %s (0.1)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf(" 0x%08lx [0x3e4ccccd] %s (0.2)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + printf("fp3:0x%08lx [0xbdcccccd] %s (-0.1)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "bdcccccd"); + + fp3 = 0.3f - 0.1f; + printf("fp3:0x%08lx [0x3e4ccccd] %s (0.2)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "3e4ccccd"); + fp3 = 0.1f - 0.3f; + printf("fp3:0x%08lx [0xbe4ccccd] %s (-0.2)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "be4ccccd"); + + // multiplication + printf("\nconstant * constant\n\n"); + fp1 = 0.1f; + fp2 = 0.2f; + fp3 = 0.1f * 5.0f; + + printf(" 0x%08lx [0x3dcccccd] %s (0.1)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf(" 0x%08lx [0x3e4ccccd] %s (0.2)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + printf("fp3:0x%08lx [0x3f000000] %s (0.5)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "3f000000"); + + // division + printf("\nconstant / constant\n\n"); + fp1 = 0.1f; + fp2 = 0.2f; + fp3 = 0.1f / 0.2f; + + printf(" 0x%08lx [0x3dcccccd] %s (0.1)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf(" 0x%08lx [0x3e4ccccd] %s (0.2)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + printf("fp3:0x%08lx [0x3f000000] %s (0.5)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "3f000000"); +} + +int main(void) +{ + float fp2 = 43.21f; + + printf("*** float-basic-const-const ***\n"); + printf("fp1:0x%08lx [0x414570a4] %s (12.340000)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf("fp2:0x%08lx [0x422cd70a] %s (43.209999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + + constconst(); + WAIT(); + + printf("\nfloat-basic-const-const (res:%d)\n", result); + return result; +} diff --git a/test/val/float-basic-const-intconst.c b/test/val/float-basic-const-intconst.c new file mode 100644 index 000000000..4eceb3b28 --- /dev/null +++ b/test/val/float-basic-const-intconst.c @@ -0,0 +1,131 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +#if 1 +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf(" (ok)"); + printf("\n"); + } else { + printf(" (failed) !!!\n"); + result++; + } +} + +void constintconst(void) +{ + printf("\n*** float constant vs int constant\n\n"); + + // addition + printf("\nconstant + constant\n\n"); + fp1 = 0.1f; + fp2 = 0.2f; + fp3 = 0.2f + 2; + + printf(" 0x%08lx [0x3dcccccd] %s (0.1)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf(" 0x%08lx [0x3e4ccccd] %s (0.2)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + printf("fp3:0x%08lx [0x400ccccd] %s (2.2)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "400ccccd"); + + // substraction + printf("\nconstant - constant\n\n"); + fp1 = 0.1f; + fp2 = 0.2f; + fp3 = 0.1f - 2; + + printf("fp3:0x%08lx [0xbff33333] %s (-1.9)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "bff33333"); + + fp3 = 0.3f - 1; + printf("fp3:0x%08lx [0xbf333333] %s (-0.7)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "bf333333"); + + // multiplication + printf("\nconstant * constant\n\n"); + fp1 = 0.1f; + fp2 = 0.2f; + fp3 = 0.1f * 5; + + printf("fp3:0x%08lx [0x3f000000] %s (0.5)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "3f000000"); + + // division + printf("\nconstant / constant\n\n"); + fp1 = 0.1f; + fp2 = 0.2f; + fp3 = 0.1f / 2; + + printf("fp3:0x%08lx [0x3d4ccccd] %s (0.05)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "3d4ccccd"); +} + +int main(void) +{ + float fp2 = 43.21f; + + printf("*** float-basic-const-intconst ***\n"); + printf("fp1:0x%08lx [0x414570a4] %s (12.340000)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf("fp2:0x%08lx [0x422cd70a] %s (43.209999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + + constintconst(); + WAIT(); + + printf("\nfloat-basic-const-intconst (res:%d)\n", result); + return result; +} +#else +int main(void) +{ + fp1 = 0.1f; + fp2 = 0.2f; + fp3 = 0.1f - 2; // 2.1 + + printf(" 0x%08lx [0x3dcccccd] %s (0.1)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf(" 0x%08lx [0x3e4ccccd] %s (0.2)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + printf("fp3:0x%08lx [?] %s (2.1)\n", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + return result; +} +#endif diff --git a/test/val/float-basic-const-intvar.c b/test/val/float-basic-const-intvar.c new file mode 100644 index 000000000..af680325d --- /dev/null +++ b/test/val/float-basic-const-intvar.c @@ -0,0 +1,109 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf(" (ok)"); + printf("\n"); + } else { + printf(" (failed) !!!\n"); + result++; + } +} + +void constintvar(void) +{ + printf("\nfloat constant vs int variable\n\n"); + + var_sint = 64; + fp3 = 16.75f + var_sint; + printf("addition: %s+%d=%s\n", _ftostr(buf, 16.75f), var_sint, _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0x42a18000] %s (80.75)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "42a18000"); + + var_sint = 16; + fp3 = 18.5f - var_sint; + printf("substraction: %s-%d=%s\n", _ftostr(buf, 8.5f), var_sint, _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0x40200000] %s (2.5)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "40200000"); + var_sint = 13; + fp3 = 20.6f - var_sint; + printf("fp3:0x%08lx [0x40f33334] %s (7.6)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "40f33334"); + var_sint = 13; + fp3 = 10.2f - var_sint; + printf("fp3:0x%08lx [0xc0333334] %s (-2.8)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "c0333334"); + + + var_sint = 2; + fp3 = 16.25f * var_sint; + printf("multiplication: %s*%d=%s\n", _ftostr(buf, 16.25f), var_sint, _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0x42020000] %s (32.5)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "42020000"); + + + var_sint = 2; + fp3 = 16.2f / var_sint; + printf("division: %s/%d=%s\n", _ftostr(buf, 16.2f), var_sint, _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0x4101999a] %s (8.1)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "4101999a"); +} + +int main(void) +{ + float fp2 = 43.21f; + + printf("float-basic-const-intvar\n"); + printf("fp1:0x%08lx [0x414570a4] %s (12.340000)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf("fp2:0x%08lx [0x422cd70a] %s (43.209999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + + constintvar(); + WAIT(); + + printf("\nfloat-basic-const-intvar (res:%d)\n", result); + return result; +} diff --git a/test/val/float-basic-const-var.c b/test/val/float-basic-const-var.c new file mode 100644 index 000000000..f15e5bfaa --- /dev/null +++ b/test/val/float-basic-const-var.c @@ -0,0 +1,111 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf(" (ok)"); + printf("\n"); + } else { + printf(" (failed) !!!\n"); + result++; + } +} + +// when making sub tests work, remove them here and uncomment them in val/float-basic.c +void constvar(void) +{ + printf("\nconstant vs variable\n\n"); + + fp2 = 64.25f; + fp3 = 16.75f + fp2; + printf("addition: %s+%s=%s\n", _ftostr(buf, 16.75f), _ftostr(buf2, fp2), _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0x42a20000] %s (81.0)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "42a20000"); + + fp2 = 16.25f; + fp3 = 8.5f - fp2; + printf("substraction: %s-%s=%s\n", _ftostr(buf, 8.5f), _ftostr(buf2, fp2), _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0xc0f80000] %s (-7.75)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "c0f80000"); + + fp1 = 0.1f; + fp2 = 0.3f; + fp3 = 0.3f - fp1; + printf("fp3:0x%08lx [0x3e4cccce] %s (0.2)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "3e4cccce"); + fp3 = 0.1f - fp2; + printf("fp3:0x%08lx [0xbe4cccce] %s (-0.2)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "be4cccce"); + + fp2 = 2.25f; + fp3 = 16.25f * fp2; + printf("multiplication: %s*%s=%s\n", _ftostr(buf, 16.25f), _ftostr(buf2, fp2), _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0x42124000] %s (36.5625)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "42124000"); + + fp2 = 2.5f; + fp3 = 16.2f / fp2; + printf("division: %s/%s=%s\n", _ftostr(buf, 16.2f), _ftostr(buf2, fp2), _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0x40cf5c2a] %s (6.48)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "40cf5c2a"); + + +} + +int main(void) +{ + float fp2 = 43.21f; + + printf("float-basic-const-var\n"); + printf("fp1:0x%08lx [0x414570a4] %s (12.340000)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf("fp2:0x%08lx [0x422cd70a] %s (43.209999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + + constvar(); + WAIT(); + + printf("\nfloat-basic-const-var (res:%d)\n", result); + return result; +} diff --git a/test/val/float-basic-intconst-const.c b/test/val/float-basic-intconst-const.c new file mode 100644 index 000000000..83ed36190 --- /dev/null +++ b/test/val/float-basic-intconst-const.c @@ -0,0 +1,126 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf(" (ok)"); + printf("\n"); + } else { + printf(" (failed) !!!\n"); + result++; + } +} + +void intconstconst(void) +{ + printf("\n*** int constant vs constant\n\n"); + + // addition + printf("\nconstant + constant\n\n"); + fp1 = 0.1f; + fp2 = 5; + fp3 = 5 + 0.5f; + + printf(" 0x%08lx [0x3dcccccd] %s (0.1)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf(" 0x%08lx [0x3e4ccccd] %s (5.0)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + printf("fp3:0x%08lx [0x40b00000] %s (5.5)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "40b00000"); + + // substraction + printf("\nconstant - constant\n\n"); + fp1 = 0.1f; + fp2 = 5; + fp3 = 5 - 0.2f; + + printf(" 0x%08lx [0x3dcccccd] %s (0.1)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf(" 0x%08lx [0x3e4ccccd] %s (5.0)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + printf("fp3:0x%08lx [0x4099999a] %s (4.8)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "4099999a"); + + fp3 = 5 - 1.1f; + printf("fp3:0x%08lx [0x4079999a] %s (3.9)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "4079999a"); + fp3 = 5 - 2.3f; + printf("fp3:0x%08lx [0x402ccccd] %s (2.7)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "402ccccd"); + + // multiplication + printf("\nconstant * constant\n\n"); + fp1 = 0.1f; + fp2 = 5; + fp3 = 5 * 5.0f; + + printf(" 0x%08lx [0x3dcccccd] %s (0.1)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf(" 0x%08lx [0x3e4ccccd] %s (5.0)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + printf("fp3:0x%08lx [0x41c80000] %s (25.0)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "41c80000"); + + // division + printf("\nconstant / constant\n\n"); + fp1 = 0.1f; + fp2 = 5; + fp3 = 5 / 0.2f; + + printf(" 0x%08lx [0x3dcccccd] %s (0.1)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf(" 0x%08lx [0x3e4ccccd] %s (5.0)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + printf("fp3:0x%08lx [0x41c80000] %s (25.0)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "41c80000"); +} + +int main(void) +{ + float fp2 = 43.21f; + + printf("*** float-basic-intconst-const ***\n"); + printf("fp1:0x%08lx [0x414570a4] %s (12.340000)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf("fp2:0x%08lx [0x422cd70a] %s (43.209999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + + intconstconst(); + WAIT(); + + printf("\nfloat-basic-intconst-const (res:%d)\n", result); + return result; +} diff --git a/test/val/float-basic-intconst-var.c b/test/val/float-basic-intconst-var.c new file mode 100644 index 000000000..30e1b8e0d --- /dev/null +++ b/test/val/float-basic-intconst-var.c @@ -0,0 +1,128 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; +int i; + +unsigned char var_char; +unsigned int var_int; +float var_float; + +#if 1 +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + printf("[%s:%s]", temp, str); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf(" (ok)"); + } else { + printf(" (failed) !!! "); + result++; + } + printf("result:%d\n", result); +} + +void SKIPPEDtest1(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + printf(" (SKIPPED:%s:%s)\n", temp, str); +} + +void intconstvar(void) +{ + + var_float = 11.123f; +#if 1 + fp1 = 47; + printf("fp1:0x%08lx [?] %s (47)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + fp1 = var_float; + printf("fp1:0x%08lx [?] %s (11.123)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + + /* addition */ + fp1 = 47 + var_float; + printf("fp1:0x%08lx [?] %s (58.123)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42687df4"); + + + fp1 = 47 - var_float; + printf("fp1:0x%08lx [?] %s (35.877)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "420f820c"); +#endif +#if 0 // compiles, but wrong result + fp1 = 47 * var_float; + printf("fp1:0x%08lx [?] %s (522.781)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42687df4"); +#endif +#if 0 // Internal compiler error + fp1 = 47 / var_float; + printf("fp1:0x%08lx [?] %s (58.123)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42687df4"); +#endif +} + +int main(void) +{ + float fp2 = 43.21f; + + printf("*** float-basic-intconst-var ***\n"); + printf("fp1:0x%08lx [0x414570a4] %s (12.340000)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf("fp2:0x%08lx [0x422cd70a] %s (43.209999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + + intconstvar(); + WAIT(); + + printf("\nfloat-basic-intconst-var (res:%d)\n", result); + return result; +} +#else +int main(void) +{ + // fp1 = 47 * var_float; + // printf("fp1:0x%08lx [?] %s (522.781)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + + fp1 = 47 / var_float; + printf("fp1:0x%08lx [?] %s (58.123)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + + return result; +} +#endif diff --git a/test/val/float-basic-intvar-const.c b/test/val/float-basic-intvar-const.c new file mode 100644 index 000000000..cb2f1aa16 --- /dev/null +++ b/test/val/float-basic-intvar-const.c @@ -0,0 +1,177 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; +int i; + +unsigned char var_char; +unsigned int var_int; +float var_float; + +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + printf("[%s:%s]", temp, str); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf(" (ok)"); + } else { + printf(" (failed) !!! "); + result++; + } + printf("result:%d\n", result); +} + +void test2(unsigned int i, unsigned int exp) +{ + if (i == exp) { +// printf(" (ok)"); + } else { + printf(" (failed) !!! "); + result++; + } + printf("result:%d\n", result); +} + +void SKIPPEDtest1(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + printf(" (SKIPPED:%s:%s)\n", temp, str); +} + +void intvarconst(void) +{ + var_int = 47; +#if 1 + fp1 = var_int; + printf("fp1:0x%08lx [42687df4] %s (47)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + fp1 = 11.123f; + printf("fp1:0x%08lx [42687df4] %s (11.123)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + + printf("int var + float const\n"); + + /* addition */ + var_char = 42; + fp1 = var_char + 23.123f; + printf("fp1:0x%08lx [0x42823efa] %s (65.123)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42823efa"); + + fp1 = var_int + 11.123f; + printf("fp1:0x%08lx [42687df4] %s (58.123)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42687df4"); +#endif + /* subtraction */ +#if 1 // gives wrong result + fp1 = var_int - 11.123f; + printf("fp1:0x%08lx [420f820c] %s (35.877)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "420f820c"); +#endif +#if 1 + /* multiplication */ + fp1 = var_int * 11.123f; + printf("fp1:0x%08lx [4402b1fc] %s (522.781)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "4402b1fc"); + + /* division */ + fp1 = var_int / 11.123f; + printf("fp1:0x%08lx [4087371f] %s (4.2254)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "4087371f"); +#endif +} + +unsigned int i1; + +void intvarconst2(void) +{ + var_int = 47; +#if 1 + i1 = var_int; + printf("i1: %d (47)\n", i1); +#endif + + printf("int var X= float const\n"); + + /* addition */ +#if 0 // gives wrong result + i1 = var_int; + i1 += 11.123f; + printf("i1: %d (58)\n", i1); + test2(i1, 58); +#endif + /* subtraction */ +#if 0 // gives wrong result + i1 = var_int; + i1 -= 11.123f; + printf("i1: %d (35)\n", i1); + test2(i1, 35); +#endif +#if 0 // internal compiler error + /* multiplication */ + i1 = var_int; + i1 *= 11.123f; + printf("i1: %d (522)\n", i1); + test2(i1, 522); +#endif +#if 0 // internal compiler error + /* division */ + i1 = var_int; + i1 /= 11.123f; + printf("i1: %d (4)\n", i1); + test2(i1, 4); +#endif +} + +int main(void) +{ + float fp2 = 43.21f; + + printf("*** float-basic-intvar-const ***\n"); + printf("fp1:0x%08lx [0x414570a4] %s (12.340000)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf("fp2:0x%08lx [0x422cd70a] %s (43.209999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + + intvarconst(); + intvarconst2(); + WAIT(); + + printf("\nfloat-basic-intvar-const (res:%d)\n", result); + return result; +} diff --git a/test/val/float-basic-intvar-var.c b/test/val/float-basic-intvar-var.c new file mode 100644 index 000000000..48ed9631c --- /dev/null +++ b/test/val/float-basic-intvar-var.c @@ -0,0 +1,175 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; +int i; + +unsigned char var_char; +unsigned int var_int; +float var_float; + +#if 1 +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + printf("[%s:%s]", temp, str); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf(" (ok)"); + } else { + printf(" (failed) !!! "); + result++; + } + printf("result:%d\n", result); +} + +void test2(unsigned int i, unsigned int exp) +{ + if (i == exp) { +// printf(" (ok)"); + } else { + printf(" (failed) !!! "); + result++; + } + printf("result:%d\n", result); +} + +void SKIPPEDtest1(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + printf(" (SKIPPED:%s:%s)\n", temp, str); +} + +void intfloat(void) +{ + var_int = 47; + var_float = 11.123f; +#if 1 + fp1 = var_int; + printf("fp1:0x%08lx [42687df4] %s (47)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + fp1 = var_float; + printf("fp1:0x%08lx [42687df4] %s (11.123)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + + /* addition */ + fp1 = var_int + var_float; + printf("fp1:0x%08lx [42687df4] %s (58.123)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42687df4"); + + fp1 = var_int - var_float; + printf("fp1:0x%08lx [420f820c] %s (35.877)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "420f820c"); +#endif +#if 1 + fp1 = var_int * var_float; + printf("fp1:0x%08lx [4402b1fc] %s (522.781)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "4402b1fc"); +#endif +#if 1 + fp1 = var_int / var_float; + printf("fp1:0x%08lx [4087371f] %s (4.225)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "4087371f"); +#endif + +} + +unsigned int i1; + +void intfloat2(void) +{ + printf("int X= float var\n"); + var_int = 47; + var_float = 11.123f; + + i1 = var_int; + printf("i1: %d (47)\n", i1); + + /* addition */ + i1 = var_int; + i1 += var_float; + printf("i1: %d (58)\n", i1); + test2(i1, 58); +#if 1 + i1 = var_int; + i1 -= var_float; + printf("i1: %d (36)\n", i1); + test2(i1, 36); +#endif +#if 0 // internal compiler error + i1 = var_int; + i1 *= var_float; + printf("i1: %d (522)\n", i1); + test2(i1, 522); +#endif +#if 0 // internal compiler error + i1 = var_int; + i1 /= var_float; + printf("i1: %d (4)\n", i1); + test2(i1, 4); +#endif + +} + +int main(void) +{ + float fp2 = 43.21f; + + printf("*** float-basic-intvar-var ***\n"); + printf("fp1:0x%08lx [0x414570a4] %s (12.340000)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf("fp2:0x%08lx [0x422cd70a] %s (43.209999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + + intfloat(); + intfloat2(); + WAIT(); + + printf("\nfloat-basic-intvar-var (res:%d)\n", result); + return result; +} +#else +int main(void) +{ + var_int = 47; + var_float = 11.123f; + fp1 = var_int * var_float; + printf("fp1:0x%08lx [42687df4] %s (58.123)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + return result; +} +#endif diff --git a/test/val/float-basic-var-const.c b/test/val/float-basic-var-const.c new file mode 100644 index 000000000..909d3f944 --- /dev/null +++ b/test/val/float-basic-var-const.c @@ -0,0 +1,222 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +#if 1 +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + printf("[%s:%s]",temp,str); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf(" (ok)"); + printf("\n"); + } else { + printf(" (failed) !!!\n"); + result++; + } +} + +#if 1 +void varconst(void) +{ + printf("\n*** variable vs constant\n\n"); + /* addition, variable + constant */ + fp1 = 64.75f; + fp3 = fp1 + 2.25f; + printf("addition: %s+%s=%s\n", _ftostr(buf, fp3), _ftostr(buf3, 0.05f), _ftostr(buf2, fp1)); + printf(" fp3:0x%08lx [0x42860000] %s (exp:67.0)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "42860000"); + + /* subtraction, variable - constant */ + fp1 = 16.25f; + fp3 = fp1 - 8.5f; + printf("substraction: %s-%s=%s\n", _ftostr(buf, fp1), _ftostr(buf2, 8.5f), _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0x40f80000] %s (exp:7.75)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "40f80000"); + + fp1 = 0.1f; + fp2 = 0.3f; + fp3 = fp2 - 0.1f; + printf("fp3:0x%08lx [0x3e4cccce] %s (0.2)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "3e4cccce"); + fp3 = fp1 - 0.3f; + printf("fp3:0x%08lx [0xbe4cccce] %s (-0.2)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "be4cccce"); + + /* multiplication, variable * constant */ + fp1 = 16.25f; + fp3 = fp1 * 2.5f; + printf("multiplication: %s*%s=%s\n", _ftostr(buf, fp1), _ftostr(buf2, 2.3f), _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0x42228000] %s (exp:40.625)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "42228000"); + + /* division, variable / constant */ + fp1 = 32.5f; + fp3 = fp1 / 2.5f; + printf("division: %s/%s=%s\n", _ftostr(buf, fp1), _ftostr(buf2, 2.3f), _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0x41500000] %s (exp:13.0)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "41500000"); +} + +void varconst2(void) +{ + printf("\n*** variable vs constant\n\n"); + + /* addition, variable + constant */ + fp1 = 64.75f; + fp1 += 2.25f; + printf("addition: %s+%s=%s\n", _ftostr(buf, 64.75f), _ftostr(buf3, 2.25f), _ftostr(buf2, fp1)); + printf(" fp1:0x%08lx [0x42860000] %s (exp:67.0)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42860000"); + + /* subtraction, variable - constant */ + fp1 = 16.25f; + fp1 -= 8.5f; + printf("substraction: %s-%s=%s\n", _ftostr(buf, 16.25f), _ftostr(buf2, 8.5f), _ftostr(buf3, fp1)); + printf(" fp1:0x%08lx [0x40f80000] %s (exp:7.75)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "40f80000"); + + fp1 = 0.3f; + fp1 -= 0.1f; + printf("fp1:0x%08lx [0x3e4cccce] %s (0.2)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "3e4cccce"); + + fp1 = 0.1f; + fp1 -= 0.3f; + printf("fp1:0x%08lx [0xbe4cccce] %s (-0.2)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "be4cccce"); + + /* multiplication, variable * constant */ + fp1 = 16.25f; + fp1 *= 2.5f; + printf("multiplication: %s*%s=%s\n", _ftostr(buf, 16.25f), _ftostr(buf2, 2.5f), _ftostr(buf3, fp1)); + printf(" fp1:0x%08lx [0x42228000] %s (exp:40.625)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42228000"); + + /* division, variable / constant */ + fp1 = 32.5f; + fp1 /= 2.5f; + printf("division: %s/%s=%s\n", _ftostr(buf, 32.5f), _ftostr(buf2, 2.5f), _ftostr(buf3, fp1)); + printf(" fp1:0x%08lx [0x41500000] %s (exp:13.0)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "41500000"); +} +#endif + +void varconst3(void) +{ + float localfp3; + float localfp2; + float localfp1; + float localfp4; + float localfp5; + printf("\n*** local variable vs constant\n\n"); +#if 1 // compiles, wrong result + /* addition, variable + constant */ + localfp1 = 64.75f; + localfp1 += 2.25f; + printf("addition: %s+%s=%s\n", _ftostr(buf, 64.75f), _ftostr(buf3, 2.25f), _ftostr(buf2, localfp1)); + printf(" localfp1:0x%08lx [0x42860000] %s (exp:67.0)", *((uint32_t*)&localfp1), _ftostr(buf, localfp1)); + test1(localfp1, "42860000"); +#endif +#if 1 // compiles, wrong result + /* subtraction, variable - constant */ + localfp1 = 16.25f; + localfp1 -= 8.5f; + printf("substraction: %s-%s=%s\n", _ftostr(buf, 16.25f), _ftostr(buf2, 8.5f), _ftostr(buf3, localfp1)); + printf(" localfp1:0x%08lx [0x40f80000] %s (exp:7.75)", *((uint32_t*)&localfp1), _ftostr(buf, localfp1)); + test1(localfp1, "40f80000"); + + localfp1 = 0.3f; + localfp1 -= 0.1f; + printf("localfp1:0x%08lx [0x3e4cccce] %s (0.2)", *((uint32_t*)&localfp1), _ftostr(buf, localfp1)); + test1(localfp1, "3e4cccce"); + + localfp1 = 0.1f; + localfp1 -= 0.3f; + printf("localfp1:0x%08lx [0xbe4cccce] %s (-0.2)", *((uint32_t*)&localfp1), _ftostr(buf, localfp1)); + test1(localfp1, "be4cccce"); +#endif +#if 1 + /* multiplication, variable * constant */ + localfp1 = 16.25f; + localfp1 *= 2.5f; + printf("multiplication: %s*%s=%s\n", _ftostr(buf, 16.25f), _ftostr(buf2, 2.5f), _ftostr(buf3, localfp1)); + printf(" localfp1:0x%08lx [0x42228000] %s (exp:40.625)", *((uint32_t*)&localfp1), _ftostr(buf, localfp1)); + test1(localfp1, "42228000"); + + /* division, variable / constant */ + localfp1 = 32.5f; + localfp1 /= 2.5f; + printf("division: %s/%s=%s\n", _ftostr(buf, 32.5f), _ftostr(buf2, 2.5f), _ftostr(buf3, localfp1)); + printf(" localfp1:0x%08lx [0x41500000] %s (exp:13.0)", *((uint32_t*)&localfp1), _ftostr(buf, localfp1)); + test1(localfp1, "41500000"); +#endif +} + +int main(void) +{ + float fp2 = 43.21f; + + printf("float-basic-var-const\n"); + + printf("fp1:0x%08lx [0x414570a4] %s (12.340000)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf("fp2:0x%08lx [0x422cd70a] %s (43.209999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + + varconst(); + varconst2(); + varconst3(); + WAIT(); + + printf("\nfloat-basic-var-const (res:%d)\n", result); + return result; +} +#else +int main(void) +{ + fp1 = 16.25f; + fp3 = fp1 - 8.5f; + printf("substraction: %s-%s=%s\n", _ftostr(buf, fp1), _ftostr(buf2, 8.5f), _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0x40f80000] %s (exp:7.75)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + return result; +} +#endif diff --git a/test/val/float-basic-var-intconst.c b/test/val/float-basic-var-intconst.c new file mode 100644 index 000000000..ed1d5ba31 --- /dev/null +++ b/test/val/float-basic-var-intconst.c @@ -0,0 +1,167 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; +int i; + +unsigned char var_char; +unsigned int var_int; +float var_float; + +#if 1 +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + printf("[%s:%s]", temp, str); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf(" (ok)"); + } else { + printf(" (failed) !!! "); + result++; + } + printf("result:%d\n", result); +} + +void SKIPPEDtest1(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + printf(" (SKIPPED:%s:%s)\n", temp, str); +} + +void varintconst(void) +{ + + var_float = 11.123f; + + fp1 = 47; + printf("fp1:0x%08lx [42687df4] %s (47)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + fp1 = var_float; + printf("fp1:0x%08lx [42687df4] %s (11.123)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + + /* addition */ + fp1 = var_float + 47; + printf("fp1:0x%08lx [42687df4] %s (58.123)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42687df4"); +#if 1 + fp1 = var_float - 47; + printf("fp1:0x%08lx [c20f820c] %s (-35.877)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "c20f820c"); +#endif +#if 0 // works but gives wrong result + fp1 = var_float * 47; + printf("fp1:0x%08lx [42687df4] %s (522.781)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42687df4"); +#endif +#if 0 // works but gives wrong result + fp1 = var_float / 47; + printf("fp1:0x%08lx [42687df4] %s (0.2367)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42687df4"); +#endif + +} + +void varintconst2(void) +{ + + var_float = 11.123f; + + printf("float *= int const\n"); + + fp1 = 47; + printf("fp1:0x%08lx [42687df4] %s (47)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + fp1 = var_float; + printf("fp1:0x%08lx [42687df4] %s (11.123)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + +#if 0 // works but gives wrong result + /* addition */ + fp1 = var_float; + fp1 += 47; + printf("fp1:0x%08lx [42687df4] %s (58.123)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42687df4"); +#endif +#if 0 // works but gives wrong result + fp1 = var_float; + fp1 -= 47; + printf("fp1:0x%08lx [42687df4] %s (-35.877)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42687df4"); +#endif +#if 0 // works but gives wrong result + fp1 = var_float; + fp1 *= 47; + printf("fp1:0x%08lx [42687df4] %s (522.781)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42687df4"); +#endif +#if 0 // works but gives wrong result + fp1 = var_float; + fp1 /= 47; + printf("fp1:0x%08lx [42687df4] %s (0.2367)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42687df4"); +#endif + +} + +int main(void) +{ + float fp2 = 43.21f; + + printf("*** float-basic-var-intconst ***\n"); + printf("fp1:0x%08lx [0x414570a4] %s (12.340000)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf("fp2:0x%08lx [0x422cd70a] %s (43.209999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + + varintconst(); + varintconst2(); + WAIT(); + + printf("\nfloat-basic-var-intconst (res:%d)\n", result); + return result; +} +#else +int main(void) +{ + fp1 = var_float - 47; + printf("fp1:0x%08lx [c20f820c] %s (-35.877)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + fp1 = var_float - 47.0f; + printf("fp1:0x%08lx [c20f820c] %s (-35.877)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + return result; +} +#endif diff --git a/test/val/float-basic-var-intvar.c b/test/val/float-basic-var-intvar.c new file mode 100644 index 000000000..02362dab8 --- /dev/null +++ b/test/val/float-basic-var-intvar.c @@ -0,0 +1,152 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; +int i; + +unsigned char var_char; +unsigned int var_int; +float var_float; + +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + printf("[%s:%s]", temp, str); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf(" (ok)"); + } else { + printf(" (failed) !!! "); + result++; + } + printf("result:%d\n", result); +} + +void SKIPPEDtest1(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + printf(" (SKIPPED:%s:%s)\n", temp, str); +} + +void intvar(void) +{ + + var_int = 47; + var_float = 11.123f; + fp1 = var_int; + printf("fp1:0x%08lx [42687df4] %s (47)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + fp1 = var_float; + printf("fp1:0x%08lx [42687df4] %s (11.123)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + + /* addition */ + fp1 = var_float + var_int; + printf("fp1:0x%08lx [42687df4] %s (58.123)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42687df4"); + + fp1 = var_float - var_int; + printf("fp1:0x%08lx [c20f820c] %s (-35.877)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "c20f820c"); + + fp1 = var_float * var_int; + printf("fp1:0x%08lx [4402b1fc] %s (522.781)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "4402b1fc"); + + fp1 = var_float / var_int; + printf("fp1:0x%08lx [3e7256e3] %s (0.2367)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "3e7256e3"); +} + +void intvar2(void) +{ + + var_int = 47; + var_float = 11.123f; + + printf("float var *= int var\n"); + + fp1 = var_int; + printf("fp1:0x%08lx [42687df4] %s (47)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + fp1 = var_float; + printf("fp1:0x%08lx [42687df4] %s (11.123)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + +#if 0 // compiles, but wrong result + /* addition */ + fp1 = var_float; + fp1 += var_int; + printf("fp1:0x%08lx [42687df4] %s (58.123)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42687df4"); +#endif +#if 0 // compiles, but wrong result + /* subtraction */ + fp1 = var_float; + fp1 -= var_int; + printf("fp1:0x%08lx [42687df4] %s (-35.877)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42687df4"); +#endif + /* multiplication */ + fp1 = var_float; + fp1 *= var_int; + printf("fp1:0x%08lx [4402b1fc] %s (522.781)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "4402b1fc"); + + /* division */ + fp1 = var_float; + fp1 /= var_int; + printf("fp1:0x%08lx [3e7256e3] %s (0.2367)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "3e7256e3"); +} + +int main(void) +{ + float fp2 = 43.21f; + + printf("*** float-basic-var-intvar ***\n"); + printf("fp1:0x%08lx [0x414570a4] %s (12.340000)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf("fp2:0x%08lx [0x422cd70a] %s (43.209999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + + intvar(); + intvar2(); + WAIT(); + + printf("\nfloat-basic-var-intvar (res:%d)\n", result); + return result; +} diff --git a/test/val/float-basic-var-var.c b/test/val/float-basic-var-var.c new file mode 100644 index 000000000..0b21eb091 --- /dev/null +++ b/test/val/float-basic-var-var.c @@ -0,0 +1,179 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +#if 1 +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf(" (ok)"); + printf("\n"); + } else { + printf(" (failed) !!!\n"); + result++; + } +} + +void varvar(void) +{ + printf("\nvariable vs variable\n\n"); + + /* addition, variable + variable */ + fp1 = 16.5f; + fp2 = 64.25f; + fp3 = fp1 + fp2; // = 80.75f + printf("addition: %s+%s=%s\n", _ftostr(buf, fp1), _ftostr(buf2, fp2), _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0x42a18000] %s (exp:80.75)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "42a18000"); + + /* subtraction, variable - variable */ + fp1 = 64.25f; + fp2 = 16.5f; + fp3 = fp1 - fp2; + printf("substraction: %s-%s=%s\n", _ftostr(buf, fp1), _ftostr(buf2, fp2), _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0x423f0000] %s (exp:47.75)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "423f0000"); + + fp1 = 0.1f; + fp2 = 0.3f; + + fp3 = fp2 - fp1; + printf("fp3:0x%08lx [0x3e4cccce] %s (0.2)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "3e4cccce"); + fp3 = fp1 - fp2; + printf("fp3:0x%08lx [0xbe4cccce] %s (-0.2)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "be4cccce"); + + /* multiplication, variable * variable */ + fp1 = 8.5f; + fp2 = 2.25f; + fp3 = fp1 * fp2; + printf("multiplication: %s*%s=%s\n", _ftostr(buf, fp1), _ftostr(buf2, fp2), _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0x41990000] %s (exp:19.125)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "41990000"); + + /* division, variable / variable */ + fp1 = 16.25f; + fp2 = 2.5f; + fp3 = fp1 / fp2; + printf("division: %s/%s=%s\n", _ftostr(buf, fp1), _ftostr(buf2, fp2), _ftostr(buf3, fp3)); + printf(" fp3:0x%08lx [0x40d00000] %s (exp:6.5)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "40d00000"); +} + +void varvar2(void) +{ + printf("\nvariable vs variable\n\n"); + +#if 0 // compiles, but wrong result + /* addition, variable + variable */ + fp1 = 16.5f; + fp2 = 64.25f; + fp1 += fp2; // = 80.75f + printf("addition: %s+%s=%s\n", _ftostr(buf, 16.5f), _ftostr(buf2, fp2), _ftostr(buf3, fp1)); + printf(" fp1:0x%08lx [0x42a18000] %s (exp:80.75)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42a18000"); +#endif +#if 0 // compiles, but wrong result + /* subtraction, variable - variable */ + fp1 = 64.25f; + fp2 = 16.5f; + fp1 -= fp2; + printf("substraction: %s-%s=%s\n", _ftostr(buf, 64.25f), _ftostr(buf2, fp2), _ftostr(buf3, fp1)); + printf(" fp1:0x%08lx [0x423f0000] %s (exp:47.75)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "423f0000"); + + fp1 = 0.3f; + fp2 = 0.1f; + fp1 -= fp2; + printf("fp1:0x%08lx [0x3e4cccce] %s (0.2)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "3e4cccce"); + + fp1 = 0.1f; + fp2 = 0.1f; + fp1 -= fp2; + printf("fp1:0x%08lx [0xbe4cccce] %s (-0.2)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "be4cccce"); +#endif + /* multiplication, variable * variable */ + fp1 = 8.5f; + fp2 = 2.25f; + fp1 *= fp2; + printf("multiplication: %s*%s=%s\n", _ftostr(buf, 8.5f), _ftostr(buf2, fp2), _ftostr(buf3, fp1)); + printf(" fp1:0x%08lx [0x41990000] %s (exp:19.125)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "41990000"); + + /* division, variable / variable */ + fp1 = 16.25f; + fp2 = 2.5f; + fp1 /= fp2; + printf("division: %s/%s=%s\n", _ftostr(buf, 16.25f), _ftostr(buf2, fp2), _ftostr(buf3, fp1)); + printf(" fp1:0x%08lx [0x40d00000] %s (exp:6.5)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "40d00000"); +} + +int main(void) +{ + float fp2 = 43.21f; + + printf("float-basic-var-var\n"); + printf("fp1:0x%08lx [0x414570a4] %s (12.340000)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf("fp2:0x%08lx [0x422cd70a] %s (43.209999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + + varvar(); + varvar2(); + WAIT(); + + printf("\nfloat-basic-var-var (res:%d)\n", result); + return result; +} +#else +int main(void) +{ + fp1 = 16.5f; + fp2 = 64.25f; + fp1 += fp2; // = 80.75f + return result; +} +#endif diff --git a/test/val/float-bnegate.c b/test/val/float-bnegate.c new file mode 100644 index 000000000..573348bfc --- /dev/null +++ b/test/val/float-bnegate.c @@ -0,0 +1,105 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf("(ok)"); + printf("\n"); + } else { + printf(" (failed)\n"); + result++; + } +} + +void test2(long n, long val) +{ + if (n == val) { +// printf("(ok)"); + printf("\n"); + } else { + printf(" (failed)\n"); + result++; + } +} + +int main(void) +{ + float fp2 = 43.21f; + + printf("float-binary negate (not)\n"); + printf("fp1:0x%08lx [0x414570a4] %s (12.340000)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf("fp2:0x%08lx [0x422cd70a] %s (43.209999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + + fp1 = 0.0f; + fp2 = !fp1; + var_sint = !fp1; + fp3 = !fp2; + printf("fp2 0x%08lx [0x3f800000] %s (!0=1) %d", *((uint32_t*)&fp2), _ftostr(buf, fp2), var_sint); + test1(fp2, "3f800000"); + printf("fp3 0x%08lx [0x00000000] %s (!1=0)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "00000000"); + + fp1 = 12.6f; + fp2 = !fp1; + var_sint = !fp1; + fp3 = !fp2; + printf("fp2 0x%08lx [0x00000000] %s (!12.6f=0) %d", *((uint32_t*)&fp2), _ftostr(buf, fp2), var_sint); + test1(fp2, "00000000"); + printf("fp3 0x%08lx [0x3f800000] %s (!0=1)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "3f800000"); + + fp1 = -12.6f; + fp2 = !fp1; + var_sint = !fp1; + fp3 = !fp2; + printf("fp2 0x%08lx [0x00000000] %s (!-12.6f=0) %d", *((uint32_t*)&fp2), _ftostr(buf, fp2), var_sint); + test1(fp2, "00000000"); + printf("fp3 0x%08lx [0x3f800000] %s (!0=1)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "3f800000"); + + printf("float-binary negate (res:%d)\n", result); + return result; +} diff --git a/test/val/float-cmp-const-const.c b/test/val/float-cmp-const-const.c new file mode 100644 index 000000000..1d27c676f --- /dev/null +++ b/test/val/float-cmp-const-const.c @@ -0,0 +1,80 @@ + +// test comparison operations + +#include +#include +#include + +#include <_float.h> + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +float fp1, fp2, fp3, fp4; + +char buf[0x30]; +char buf2[0x30]; +char buf3[0x30]; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +#define expect(msg, exp, val) \ + printf("%s %s%s\n", \ + msg, \ + val ? "true" : "false", \ + (exp != val) ? " (failed)" : ""); \ + if (exp != val) { \ + result++; \ + } + +void constconst(void) +{ + printf("const vs const\n"); + + expect("1.5f == 1.6f is", 0, (1.5f == 1.6f)); + expect("1.6f == 1.5f is", 0, (1.6f == 1.5f)); + expect("1.6f == 1.6f is", 1, (1.6f == 1.6f)); + + expect("1.5f != 1.6f is", 1, (1.5f != 1.6f)); + expect("1.6f != 1.5f is", 1, (1.6f != 1.5f)); + expect("1.6f != 1.6f is", 0, (1.6f != 1.6f)); + + expect("1.5f < 1.6f is", 1, (1.5f < 1.6f)); + expect("1.6f < 1.5f is", 0, (1.6f < 1.5f)); + expect("1.6f < 1.6f is", 0, (1.6f < 1.6f)); + + expect("1.5f > 1.6f is", 0, (1.5f > 1.6f)); + expect("1.6f > 1.5f is", 1, (1.6f > 1.5f)); + expect("1.6f > 1.6f is", 0, (1.6f > 1.6f)); + + expect("1.5f <= 1.6f is", 1, (1.5f <= 1.6f)); + expect("1.6f <= 1.5f is", 0, (1.6f <= 1.5f)); + expect("1.6f <= 1.6f is", 1, (1.6f <= 1.6f)); + + expect("1.5f >= 1.6f is", 0, (1.5f >= 1.6f)); + expect("1.6f >= 1.5f is", 1, (1.6f >= 1.5f)); + expect("1.6f >= 1.6f is", 1, (1.6f >= 1.6f)); +} + +//------------------------------------------------------------------------- + +int main(void) +{ + printf("float-cmp-const-const\n"); + + constconst(); + + printf("float-cmp-const-const (res: %d)\n", result); + return result; +} diff --git a/test/val/float-cmp-const-intconst.c b/test/val/float-cmp-const-intconst.c new file mode 100644 index 000000000..972a14542 --- /dev/null +++ b/test/val/float-cmp-const-intconst.c @@ -0,0 +1,80 @@ + +// test comparison operations + +#include +#include +#include + +#include <_float.h> + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +float fp1, fp2, fp3, fp4; + +char buf[0x30]; +char buf2[0x30]; +char buf3[0x30]; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +#define expect(msg, exp, val) \ + printf("%s %s%s\n", \ + msg, \ + val ? "true" : "false", \ + (exp != val) ? " (failed)" : ""); \ + if (exp != val) { \ + result++; \ + } + +void constintconst(void) +{ + printf("const vs int const\n"); + + expect("10.0f == 20 is", 0, (10.0f == 20)); + expect("20.0f == 10 is", 0, (20.0f == 10)); + expect("20.0f == 20 is", 1, (20.0f == 20)); + + expect("10.0f != 20 is", 1, (10.0f != 20)); + expect("20.0f != 10 is", 1, (20.0f != 10)); + expect("20.0f != 20 is", 0, (20.0f != 20)); + + expect("10.0f < 20 is", 1, (10.0f < 20)); + expect("20.0f < 10 is", 0, (20.0f < 10)); + expect("20.0f < 20 is", 0, (20.0f < 20)); + + expect("10.0f > 20 is", 0, (10.0f > 20)); + expect("20.0f > 10 is", 1, (20.0f > 10)); + expect("20.0f > 20 is", 0, (20.0f > 20)); + + expect("10.0f <= 20 is", 1, (10.0f <= 20)); + expect("20.0f <= 10 is", 0, (20.0f <= 10)); + expect("20.0f <= 20 is", 1, (20.0f <= 20)); + + expect("10.0f >= 20 is", 0, (10.0f >= 20)); + expect("20.0f >= 10 is", 1, (20.0f >= 10)); + expect("20.0f >= 20 is", 1, (20.0f >= 20)); +} + +//------------------------------------------------------------------------- + +int main(void) +{ + printf("float-cmp-const-intconst\n"); + + constintconst(); + + printf("float-cmp-const-intconst (res: %d)\n", result); + return result; +} diff --git a/test/val/float-cmp-const-intvar.c b/test/val/float-cmp-const-intvar.c new file mode 100644 index 000000000..99edfd678 --- /dev/null +++ b/test/val/float-cmp-const-intvar.c @@ -0,0 +1,85 @@ + +// test comparison operations + +#include +#include +#include + +#include <_float.h> + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +float fp1, fp2, fp3, fp4; + +char buf[0x30]; +char buf2[0x30]; +char buf3[0x30]; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +#define expect(msg, exp, val) \ + printf("%s %s%s\n", \ + msg, \ + val ? "true" : "false", \ + (exp != val) ? " (failed)" : ""); \ + if (exp != val) { \ + result++; \ + } + +int i1 = 10; +int i2 = 20; + +void constintvar(void) +{ + printf("const vs int var\n"); + +#if 0 // compiles but produces wrong results + expect("10.0f == 20 is", 0, (10.0f == i2)); + expect("20.0f == 10 is", 0, (20.0f == i1)); + expect("20.0f == 20 is", 1, (20.0f == i2)); + + expect("10.0f != 20 is", 1, (10.0f != i2)); + expect("20.0f != 10 is", 1, (20.0f != i1)); + expect("20.0f != 20 is", 0, (20.0f != i2)); + + expect("10.0f < 20 is", 1, (10.0f < i2)); + expect("20.0f < 10 is", 0, (20.0f < i1)); + expect("20.0f < 20 is", 0, (20.0f < i2)); + + expect("10.0f > 20 is", 0, (10.0f > i2)); + expect("20.0f > 10 is", 1, (20.0f > i1)); + expect("20.0f > 20 is", 0, (20.0f > i2)); + + expect("10.0f <= 20 is", 1, (10.0f <= i2)); + expect("20.0f <= 10 is", 0, (20.0f <= i1)); + expect("20.0f <= 20 is", 1, (20.0f <= i2)); + + expect("10.0f >= 20 is", 0, (10.0f >= i2)); + expect("20.0f >= 10 is", 1, (20.0f >= i1)); + expect("20.0f >= 20 is", 1, (20.0f >= i2)); +#endif +} + +//------------------------------------------------------------------------- + +int main(void) +{ + printf("float-cmp-const-intvar\n"); + + constintvar(); + + printf("float-cmp-const-intvar (res: %d)\n", result); + return result; +} diff --git a/test/val/float-cmp-const-var.c b/test/val/float-cmp-const-var.c new file mode 100644 index 000000000..f16d67857 --- /dev/null +++ b/test/val/float-cmp-const-var.c @@ -0,0 +1,83 @@ + +// test comparison operations + +#include +#include +#include + +#include <_float.h> + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +float fp1, fp2, fp3, fp4; + +char buf[0x30]; +char buf2[0x30]; +char buf3[0x30]; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +#define expect(msg, exp, val) \ + printf("%s %s%s\n", \ + msg, \ + val ? "true" : "false", \ + (exp != val) ? " (failed)" : ""); \ + if (exp != val) { \ + result++; \ + } + +void constvar(void) +{ + printf("const vs var\n"); + + expect("1.5f == 1.6f is", 0, (1.5f == fp1)); + expect("1.6f == 1.5f is", 0, (1.6f == fp2)); + expect("1.6f == 1.6f is", 1, (1.6f == fp1)); + + expect("1.5f != 1.6f is", 1, (1.5f != fp1)); + expect("1.6f != 1.5f is", 1, (1.6f != fp2)); + expect("1.6f != 1.6f is", 0, (1.6f != fp1)); + + expect("1.5f < 1.6f is", 1, (1.5f < fp1)); + expect("1.6f < 1.5f is", 0, (1.6f < fp2)); + expect("1.6f < 1.6f is", 0, (1.6f < fp1)); + + expect("1.5f > 1.6f is", 0, (1.5f > fp1)); + expect("1.6f > 1.5f is", 1, (1.6f > fp2)); + expect("1.6f > 1.6f is", 0, (1.6f > fp1)); + + expect("1.5f <= 1.6f is", 1, (1.5f <= fp1)); + expect("1.6f <= 1.5f is", 0, (1.6f <= fp2)); + expect("1.6f <= 1.6f is", 1, (1.6f <= fp1)); + + expect("1.5f >= 1.6f is", 0, (1.5f >= fp1)); + expect("1.6f >= 1.5f is", 1, (1.6f >= fp2)); + expect("1.6f >= 1.6f is", 1, (1.6f >= fp1)); + +} + +//------------------------------------------------------------------------- + +int main(void) +{ + printf("float-cmp-const-var\n"); + + fp1 = 1.6f; + fp2 = 1.5f; + constvar(); + + printf("float-cmp-const-var (res: %d)\n", result); + return result; +} diff --git a/test/val/float-cmp-intconst-const.c b/test/val/float-cmp-intconst-const.c new file mode 100644 index 000000000..51d698662 --- /dev/null +++ b/test/val/float-cmp-intconst-const.c @@ -0,0 +1,81 @@ + +// test comparison operations + +#include +#include +#include + +#include <_float.h> + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +float fp1, fp2, fp3, fp4; + +char buf[0x30]; +char buf2[0x30]; +char buf3[0x30]; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +#define expect(msg, exp, val) \ + printf("%s %s%s\n", \ + msg, \ + val ? "true" : "false", \ + (exp != val) ? " (failed)" : ""); \ + if (exp != val) { \ + result++; \ + } + + +void intconstconst(void) +{ + printf("int const vs const\n"); + + expect("10 == 20.0f is", 0, (10 == 20.0f)); + expect("20 == 10.0f is", 0, (20 == 10.0f)); + expect("20 == 20.0f is", 1, (20 == 20.0f)); + + expect("10 != 20.0f is", 1, (10 != 20.0f)); + expect("20 != 10.0f is", 1, (20 != 10.0f)); + expect("20 != 20.0f is", 0, (20 != 20.0f)); + + expect("10 < 20.0f is", 1, (10 < 20.0f)); + expect("20 < 10.0f is", 0, (20 < 10.0f)); + expect("20 < 20.0f is", 0, (20 < 20.0f)); + + expect("10 > 20.0f is", 0, (10 > 20.0f)); + expect("20 > 10.0f is", 1, (20 > 10.0f)); + expect("20 > 20.0f is", 0, (20 > 20.0f)); + + expect("10 <= 20.0f is", 1, (10 <= 20.0f)); + expect("20 <= 10.0f is", 0, (20 <= 10.0f)); + expect("20 <= 20.0f is", 1, (20 <= 20.0f)); + + expect("10 >= 20.0f is", 0, (10 >= 20.0f)); + expect("20 >= 10.0f is", 1, (20 >= 10.0f)); + expect("20 >= 20.0f is", 1, (20 >= 20.0f)); +} + +//------------------------------------------------------------------------- + +int main(void) +{ + printf("float-cmp-intconst-const\n"); + + intconstconst(); + + printf("float-cmp-intconst-const (res: %d)\n", result); + return result; +} diff --git a/test/val/float-cmp-intconst-var.c b/test/val/float-cmp-intconst-var.c new file mode 100644 index 000000000..1181637b9 --- /dev/null +++ b/test/val/float-cmp-intconst-var.c @@ -0,0 +1,99 @@ + +// test comparison operations + +#include +#include +#include + +#include <_float.h> + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +float fp1, fp2, fp3, fp4; + +char buf[0x30]; +char buf2[0x30]; +char buf3[0x30]; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +#define expect(msg, exp, val, fval) \ + printf("%s %d:%d:%s%s (is:%d want:%d fval:%s)\n", \ + msg, val, exp, \ + val ? "true" : "false", \ + (exp != val) ? " (failed)" : "", \ + val, exp, _ftostr(buf, fval) \ + ); \ + if (exp != val) { \ + result++; \ + } + +//------------------------------------------------------------------------- + +void seperate(void) +{ + int res; + fp1 = 10.0f; + fp2 = 20.0f; +// res = (20.0f == fp2); // works + res = (20 == fp2); // fails + printf("res:%d\n", res); +} + +void intconstvar(void) +{ + printf("int const vs var\n"); + + fp1 = 10.0f; + fp2 = 20.0f; + +#if 1 + expect("10 == 20 is", 0, (10 == fp2), fp2); + expect("20 == 10 is", 0, (20 == fp1), fp1); + expect("20 == 20 is", 1, (20 == fp2), fp2); + + expect("10 != 20 is", 1, (10 != fp2), fp2); + expect("20 != 10 is", 1, (20 != fp1), fp1); + expect("20 != 20 is", 0, (20 != fp2), fp2); + + expect("10 < 20 is", 1, (10 < fp2), fp2); + expect("20 < 10 is", 0, (20 < fp1), fp1); + expect("20 < 20 is", 0, (20 < fp2), fp2); + + expect("10 > 20 is", 0, (10 > fp2), fp2); + expect("20 > 10 is", 1, (20 > fp1), fp1); + expect("20 > 20 is", 0, (20 > fp2), fp2); + + expect("10 <= 20 is", 1, (10 <= fp2), fp2); + expect("20 <= 10 is", 0, (20 <= fp1), fp1); + expect("20 <= 20 is", 1, (20 <= fp2), fp2); + + expect("10 >= 20 is", 0, (10 >= fp2), fp2); + expect("20 >= 10 is", 1, (20 >= fp1), fp1); + expect("20 >= 20 is", 1, (20 >= fp2), fp2); +#endif + +} + +int main(void) +{ + printf("float-cmp-intconst-var\n"); + + seperate(); + intconstvar(); + + printf("float-cmp-intconst-var (res: %d)\n", result); + return result; +} diff --git a/test/val/float-cmp-intvar-const.c b/test/val/float-cmp-intvar-const.c new file mode 100644 index 000000000..ab004d5d1 --- /dev/null +++ b/test/val/float-cmp-intvar-const.c @@ -0,0 +1,85 @@ + +// test comparison operations + +#include +#include +#include + +#include <_float.h> + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +float fp1, fp2, fp3, fp4; + +char buf[0x30]; +char buf2[0x30]; +char buf3[0x30]; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +#define expect(msg, exp, val) \ + printf("%s %s%s\n", \ + msg, \ + val ? "true" : "false", \ + (exp != val) ? " (failed)" : ""); \ + if (exp != val) { \ + result++; \ + } + +int i1 = 10; +int i2 = 20; + +void intvarconst(void) +{ + printf("int var vs const\n"); + +#if 0 // internal compiler error + expect("10 == 20.0f is", 0, (i1 == 20.0f)); + expect("20 == 10.0f is", 0, (i2 == 10.0f)); + expect("20 == 20.0f is", 1, (i2 == 20.0f)); + + expect("10 != 20.0f is", 1, (i1 != 20.0f)); + expect("20 != 10.0f is", 1, (i2 != 10.0f)); + expect("20 != 20.0f is", 0, (i2 != 20.0f)); + + expect("10 < 20.0f is", 1, (i1 < 20.0f)); + expect("20 < 10.0f is", 0, (i2 < 10.0f)); + expect("20 < 20.0f is", 0, (i2 < 20.0f)); + + expect("10 > 20.0f is", 0, (i1 > 20.0f)); + expect("20 > 10.0f is", 1, (i2 > 10.0f)); + expect("20 > 20.0f is", 0, (i2 > 20.0f)); + + expect("10 <= 20.0f is", 1, (i1 <= 20.0f)); + expect("20 <= 10.0f is", 0, (i2 <= 10.0f)); + expect("20 <= 20.0f is", 1, (i2 <= 20.0f)); + + expect("10 >= 20.0f is", 0, (i1 >= 20.0f)); + expect("20 >= 10.0f is", 1, (i2 >= 10.0f)); + expect("20 >= 20.0f is", 1, (i2 >= 20.0f)); +#endif +} + +//------------------------------------------------------------------------- + +int main(void) +{ + printf("float-cmp-intvar-const\n"); + + intvarconst(); + + printf("float-cmp-intvar-const (res: %d)\n", result); + return result; +} diff --git a/test/val/float-cmp-intvar-var.c b/test/val/float-cmp-intvar-var.c new file mode 100644 index 000000000..be44cea73 --- /dev/null +++ b/test/val/float-cmp-intvar-var.c @@ -0,0 +1,102 @@ + +// test comparison operations + +#include +#include +#include + +#include <_float.h> + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +float fp1, fp2, fp3, fp4; + +char buf[0x30]; +char buf2[0x30]; +char buf3[0x30]; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +#define expect(msg, exp, val, fval) \ + printf("%s %d:%d:%s%s (is:%d want:%d fval:%s)\n", \ + msg, val, exp, \ + val ? "true" : "false", \ + (exp != val) ? " (failed)" : "", \ + val, exp, _ftostr(buf, fval) \ + ); \ + if (exp != val) { \ + result++; \ + } + +//------------------------------------------------------------------------- + +void seperate(void) +{ + int res; + fp1 = 10.0f; + fp2 = 20.0f; +// res = (20.0f == fp2); // works + res = (20 == fp2); // fails + printf("res:%d\n", res); +} + +int i1 = 10; +int i2 = 20; + +void intvarvar(void) +{ + printf("int const vs var\n"); + + fp1 = 10.0f; + fp2 = 20.0f; + +#if 1 + expect("10 == 20 is", 0, (i1 == fp2), fp2); + expect("20 == 10 is", 0, (i2 == fp1), fp1); + expect("20 == 20 is", 1, (i2 == fp2), fp2); + + expect("10 != 20 is", 1, (i1 != fp2), fp2); + expect("20 != 10 is", 1, (i2 != fp1), fp1); + expect("20 != 20 is", 0, (i2 != fp2), fp2); + + expect("10 < 20 is", 1, (i1 < fp2), fp2); + expect("20 < 10 is", 0, (i2 < fp1), fp1); + expect("20 < 20 is", 0, (i2 < fp2), fp2); + + expect("10 > 20 is", 0, (i1 > fp2), fp2); + expect("20 > 10 is", 1, (i2 > fp1), fp1); + expect("20 > 20 is", 0, (i2 > fp2), fp2); + + expect("10 <= 20 is", 1, (i1 <= fp2), fp2); + expect("20 <= 10 is", 0, (i2 <= fp1), fp1); + expect("20 <= 20 is", 1, (i2 <= fp2), fp2); + + expect("10 >= 20 is", 0, (i1 >= fp2), fp2); + expect("20 >= 10 is", 1, (i2 >= fp1), fp1); + expect("20 >= 20 is", 1, (i2 >= fp2), fp2); +#endif + +} + +int main(void) +{ + printf("float-cmp-intvar-var\n"); + + seperate(); + intvarvar(); + + printf("float-cmp-intvar-var (res: %d)\n", result); + return result; +} diff --git a/test/val/float-cmp-var-const.c b/test/val/float-cmp-var-const.c new file mode 100644 index 000000000..7742e15c9 --- /dev/null +++ b/test/val/float-cmp-var-const.c @@ -0,0 +1,87 @@ + +// test comparison operations + +#include +#include +#include + +#include <_float.h> + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +float fp1, fp2, fp3, fp4; + +char buf[0x30]; +char buf2[0x30]; +char buf3[0x30]; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +#define expect(msg, exp, val) \ + printf("%s %s%s (is:%d want:%d)\n", \ + msg, \ + val ? "true" : "false", \ + (exp != val) ? " (failed)" : "", \ + exp, val \ + ); \ + if (exp != val) { \ + result++; \ + } + +//------------------------------------------------------------------------- +// float variable vs float constant + +void varconst(void) +{ + printf("var vs const\n"); + + fp1 = 1.6f; + fp2 = 1.5f; + + expect("1.5f == 1.6f is", 0, (fp2 == 1.6f)); + expect("1.6f == 1.5f is", 0, (fp1 == 1.5f)); + expect("1.6f == 1.6f is", 1, (fp1 == 1.6f)); + + expect("1.5f != 1.6f is", 1, (fp2 != 1.6f)); + expect("1.6f != 1.5f is", 1, (fp1 != 1.5f)); + expect("1.6f != 1.6f is", 0, (fp1 != 1.6f)); + + expect("1.5f < 1.6f is", 1, (fp2 < 1.6f)); + expect("1.6f < 1.5f is", 0, (fp1 < 1.5f)); + expect("1.6f < 1.6f is", 0, (fp1 < 1.6f)); + + expect("1.5f > 1.6f is", 0, (fp2 > 1.6f)); + expect("1.6f > 1.5f is", 1, (fp1 > 1.5f)); + expect("1.6f > 1.6f is", 0, (fp1 > 1.6f)); + + expect("1.5f <= 1.6f is", 1, (fp2 <= 1.6f)); + expect("1.6f <= 1.5f is", 0, (fp1 <= 1.5f)); + expect("1.6f <= 1.6f is", 1, (fp1 <= 1.6f)); + + expect("1.5f >= 1.6f is", 0, (fp2 >= 1.6f)); + expect("1.6f >= 1.5f is", 1, (fp1 >= 1.5f)); + expect("1.6f >= 1.6f is", 1, (fp1 >= 1.6f)); + +} + +int main(void) +{ + printf("float-cmp-var-const\n"); + + varconst(); + + printf("float-cmp-var-const (res: %d)\n", result); + return result; +} diff --git a/test/val/float-cmp-var-intconst.c b/test/val/float-cmp-var-intconst.c new file mode 100644 index 000000000..fc93ccf41 --- /dev/null +++ b/test/val/float-cmp-var-intconst.c @@ -0,0 +1,86 @@ + +// test comparison operations + +#include +#include +#include + +#include <_float.h> + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +float fp1, fp2, fp3, fp4; + +char buf[0x30]; +char buf2[0x30]; +char buf3[0x30]; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +#define expect(msg, exp, val, fval) \ + printf("%s %d:%d:%s%s (is:%d want:%d fval:%s)\n", \ + msg, val, exp, \ + val ? "true" : "false", \ + (exp != val) ? " (failed)" : "", \ + val, exp, _ftostr(buf, fval) \ + ); \ + if (exp != val) { \ + result++; \ + } + +//------------------------------------------------------------------------- + +void varintconst(void) +{ + printf("var vs int const\n"); + + fp1 = 10.0f; + fp2 = 20.0f; + + expect("10 == 20 is", 0, (fp1 == 20), fp1); + expect("20 == 10 is", 0, (fp2 == 10), fp2); + expect("20 == 20 is", 1, (fp2 == 20), fp2); + + expect("10 != 20 is", 1, (fp1 != 20), fp1); + expect("20 != 10 is", 1, (fp2 != 10), fp2); + expect("20 != 20 is", 0, (fp2 != 20), fp2); + + expect("10 < 20 is", 1, (fp1 < 20), fp1); + expect("20 < 10 is", 0, (fp2 < 10), fp2); + expect("20 < 20 is", 0, (fp2 < 20), fp2); + + expect("10 > 20 is", 0, (fp1 > 20), fp1); + expect("20 > 10 is", 1, (fp2 > 10), fp2); + expect("20 > 20 is", 0, (fp2 > 20), fp2); + + expect("10 <= 20 is", 1, (fp1 <= 20), fp1); + expect("20 <= 10 is", 0, (fp2 <= 10), fp2); + expect("20 <= 20 is", 1, (fp2 <= 20), fp2); + + expect("10 >= 20 is", 0, (fp1 >= 20), fp1); + expect("20 >= 10 is", 1, (fp2 >= 10), fp2); + expect("20 >= 20 is", 1, (fp2 >= 20), fp2); + +} + +int main(void) +{ + printf("float-cmp-var-intconst\n"); + + varintconst(); + + printf("float-cmp-var-intconst (res: %d)\n", result); + return result; +} diff --git a/test/val/float-cmp-var-intvar.c b/test/val/float-cmp-var-intvar.c new file mode 100644 index 000000000..d4737ebae --- /dev/null +++ b/test/val/float-cmp-var-intvar.c @@ -0,0 +1,89 @@ + +// test comparison operations + +#include +#include +#include + +#include <_float.h> + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +float fp1, fp2, fp3, fp4; + +char buf[0x30]; +char buf2[0x30]; +char buf3[0x30]; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +#define expect(msg, exp, val, fval, ival) \ + printf("%s %d:%d:%s%s (is:%d want:%d fval:%s ival:%d)\n", \ + msg, val, exp, \ + val ? "true" : "false", \ + (exp != val) ? " (failed)" : "", \ + val, exp, _ftostr(buf, fval), ival \ + ); \ + if (exp != val) { \ + result++; \ + } + +//------------------------------------------------------------------------- + +int i1 = 10; +int i2 = 20; + +void varintvar(void) +{ + printf("var vs int var\n"); + + fp1 = 10.0f; + fp2 = 20.0f; +#if 0 // works but gives wrong results + expect("10 == 20 is", 0, (fp1 == i2), fp1, i2); + expect("20 == 10 is", 0, (fp2 == i1), fp2, i1); + expect("20 == 20 is", 1, (fp2 == i2), fp2, i2); + + expect("10 != 20 is", 1, (fp1 != i2), fp1, i2); + expect("20 != 10 is", 1, (fp2 != i1), fp2, i1); + expect("20 != 20 is", 0, (fp2 != i2), fp2, i2); + + expect("10 < 20 is", 1, (fp1 < i2), fp1, i2); + expect("20 < 10 is", 0, (fp2 < i1), fp2, i1); + expect("20 < 20 is", 0, (fp2 < i2), fp2, i2); + + expect("10 > 20 is", 0, (fp1 > i2), fp1, i2); + expect("20 > 10 is", 1, (fp2 > i1), fp2, i1); + expect("20 > 20 is", 0, (fp2 > i2), fp2, i2); + + expect("10 <= 20 is", 1, (fp1 <= i2), fp1, i2); + expect("20 <= 10 is", 0, (fp2 <= i1), fp2, i1); + expect("20 <= 20 is", 1, (fp2 <= i2), fp2, i2); + + expect("10 >= 20 is", 0, (fp1 >= i2), fp1, i2); + expect("20 >= 10 is", 1, (fp2 >= i1), fp2, i1); + expect("20 >= 20 is", 1, (fp2 >= i2), fp2, i2); +#endif +} + +int main(void) +{ + printf("float-cmp-var-intvar\n"); + + varintvar(); + + printf("float-cmp-var-intvar (res: %d)\n", result); + return result; +} diff --git a/test/val/float-cmp-var-var.c b/test/val/float-cmp-var-var.c new file mode 100644 index 000000000..3b453efb4 --- /dev/null +++ b/test/val/float-cmp-var-var.c @@ -0,0 +1,89 @@ + +// test comparison operations + +#include +#include +#include + +#include <_float.h> + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +float fp1, fp2, fp3, fp4; + +char buf[0x30]; +char buf2[0x30]; +char buf3[0x30]; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +#define expect(msg, exp, val) \ + printf("%s %s%s\n", \ + msg, \ + val ? "true" : "false", \ + (exp != val) ? " (failed)" : ""); \ + if (exp != val) { \ + result++; \ + } + +//------------------------------------------------------------------------- +// float variable vs float variable +void varvar(void) +{ + printf("var vs var\n"); + + fp1 = 1.6f; + fp2 = 1.5f; + fp3 = 1.6f; + fp4 = 1.5f; + + expect("1.5f == 1.6f is", 0, (fp2 == fp3)); + expect("1.6f == 1.5f is", 0, (fp1 == fp4)); + expect("1.6f == 1.6f is", 1, (fp1 == fp3)); + + expect("1.5f != 1.6f is", 1, (fp2 != fp3)); + expect("1.6f != 1.5f is", 1, (fp1 != fp4)); + expect("1.6f != 1.6f is", 0, (fp1 != fp3)); + + expect("1.5f < 1.6f is", 1, (fp2 < fp3)); + expect("1.6f < 1.5f is", 0, (fp1 < fp4)); + expect("1.6f < 1.6f is", 0, (fp1 < fp3)); + + expect("1.5f > 1.6f is", 0, (fp2 > fp3)); + expect("1.6f > 1.5f is", 1, (fp1 > fp4)); + expect("1.6f > 1.6f is", 0, (fp1 > fp3)); + + expect("1.5f <= 1.6f is", 1, (fp2 <= fp3)); + expect("1.6f <= 1.5f is", 0, (fp1 <= fp4)); + expect("1.6f <= 1.6f is", 1, (fp1 <= fp3)); + + expect("1.5f >= 1.6f is", 0, (fp2 >= fp3)); + expect("1.6f >= 1.5f is", 1, (fp1 >= fp4)); + expect("1.6f >= 1.6f is", 1, (fp1 >= fp3)); + +} + +int main(void) +{ + printf("float-cmp-var-var\n"); + + fp1 = 1.6f; + fp2 = 1.5f; + + varvar(); + + printf("float-cmp-var-var (res: %d)\n", result); + return result; +} diff --git a/test/val/float-conv-float-to-char.c b/test/val/float-conv-float-to-char.c new file mode 100644 index 000000000..6479b0cae --- /dev/null +++ b/test/val/float-conv-float-to-char.c @@ -0,0 +1,74 @@ + +// test basic type conversions + +#define TEST_8 +#define TEST_16 +#define TEST_32 + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +void test2(long n, long val) +{ + if (n == val) { +// printf("(ok)"); + printf("\n"); + } else { + printf(" (failed) !!!\n"); + result++; + } +} + +void varvar(void) +{ + + printf("\nconversions (float variable to integer variable)\n"); + fp1 = -12.3f; + fp2 = 19.9f; + + var_uchar = (unsigned char)fp2; + printf("fp2 0x%08lx %s (19.9) uchar:%u (exp:19)", *((uint32_t*)&fp2), _ftostr(buf, fp2), (int)var_uchar); + test2(var_uchar, 19); +} + +int main(void) +{ + + printf("float-conv-float-to-char\n"); + + varvar(); + WAIT(); + + printf("\nfloat-conv (res:%d)\n", result); + return result; +} diff --git a/test/val/float-conv-float-to-schar.c b/test/val/float-conv-float-to-schar.c new file mode 100644 index 000000000..5fea93b6d --- /dev/null +++ b/test/val/float-conv-float-to-schar.c @@ -0,0 +1,73 @@ + +// test basic type conversions + +#define TEST_8 +#define TEST_16 +#define TEST_32 + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +void test2(long n, long val) +{ + if (n == val) { +// printf("(ok)"); + printf("\n"); + } else { + printf(" (failed) !!!\n"); + result++; + } +} + +void varvar(void) +{ + + printf("\nconversions (float variable to integer variable)\n"); + fp1 = -12.3f; + + var_schar = (signed char)fp1; + printf("fp1 0x%08lx %s (-12.3) schar:%d (exp:-12)", *((uint32_t*)&fp1), _ftostr(buf, fp1), (int)var_schar); + test2(var_schar, -12); +} + +int main(void) +{ + + printf("float-conv-float-to-schar\n"); + + varvar(); + WAIT(); + + printf("\nfloat-conv (res:%d)\n", result); + return result; +} diff --git a/test/val/float-conv.c b/test/val/float-conv.c new file mode 100644 index 000000000..9cb267e08 --- /dev/null +++ b/test/val/float-conv.c @@ -0,0 +1,219 @@ + +// test basic type conversions + +#define TEST_8 +#define TEST_16 +#define TEST_32 + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf("(ok)"); + printf("\n"); + } else { + printf(" (failed) !!!\n"); + result++; + } +} + +void test2(long n, long val) +{ + if (n == val) { +// printf("(ok)"); + printf("\n"); + } else { + printf(" (failed) !!!\n"); + result++; + } +} + +void constvar(void) +{ + // conversions + printf("\nconversions (integer constant to float variable)\n"); +#ifdef TEST_8 + fp1 = -12; + fp2 = 199; + printf("fp1 0x%08lx [exp:0xc1400000] %s (-12)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "c1400000"); + printf("fp2 0x%08lx [exp:0x43470000] %s (199)", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + test1(fp2, "43470000"); +#endif +#ifdef TEST_16 + fp1 = -4711; + fp2 = 42000U; + printf("fp1 0x%08lx [exp:0xc5933800] %s (-4711)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "c5933800"); + printf("fp2 0x%08lx [exp:0x47241000] %s (42000)", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + test1(fp2, "47241000"); +#endif +#ifdef TEST_32 + fp1 = -321198; + fp2 = 3200098; + printf("fp1 0x%08lx [exp:0xc89cd5c0] %s (-321198)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "c89cd5c0"); + printf("fp2 0x%08lx [exp:0x4a435188] %s (3200098)", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + test1(fp2, "4a435188"); +#endif + + printf("\nconversions (float constant to integer variable)\n"); +#ifdef TEST_8 + var_schar = (signed char)12.3f; + printf("%s (12.3) schar:%d (exp:12)", _ftostr(buf, 12.3f), (int)var_schar); + test2(var_schar, 12); + var_uchar = (unsigned char)19.9f; + printf("%s (19.9) uchar:%u (exp:19)", _ftostr(buf, 19.9f), (int)var_uchar); + test2(var_uchar, 19); +#endif +#ifdef TEST_16 + var_sint = (signed short)1234.5f; + printf("%s (1234.5) sint:%d (exp:1234)", _ftostr(buf, 1234.5f), var_sint); + test2(var_sint, 1234); + var_uint = (unsigned short)1999.9f; + printf("%s (1999.9) uint:%u (exp:1999)", _ftostr(buf, 1999.9f), var_uint); + test2(var_uint, 1999); +#endif +#ifdef TEST_32 + var_slong = (signed long)123456.5f; + printf("%s (123456.5f) slong:%ld (exp:123456)", _ftostr(buf, 123456.5f), var_slong); + test2(var_slong, 123456); + var_ulong = (unsigned long)199988.9f; + printf("%s (199988.9) ulong:%lu (exp:199988)", _ftostr(buf, 199988.9f), var_ulong); + test2(var_ulong, 199988); +#endif +} + +void varvar(void) +{ + float fp2 = 43.21f; + + printf("\nconversions (integer variable to float variable)\n"); + var_schar = -12; + fp1 = var_schar; + var_uchar = 199; + fp2 = var_uchar; + printf("fp1 0x%08lx [exp:0xc1400000] %s (-12)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "c1400000"); + printf("fp2 0x%08lx [exp:0x43470000] %s (199)", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + test1(fp2, "43470000"); + var_sint = -4711; + fp1 = var_sint; + var_uint = 42000U; + fp2 = var_uint; + printf("fp1 0x%08lx [exp:0xc5933800] %s (-4711)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "c5933800"); + printf("fp2 0x%08lx [exp:0x47241000] %s (42000)", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + test1(fp2, "47241000"); + var_slong = -4711456; + fp1 = var_slong; + var_ulong = 42000456; + fp2 = var_ulong; + printf("fp1 0x%08lx [exp:0xca8fc840] %s (-4711456)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "ca8fc840"); + printf("fp2 0x%08lx [exp:0x4c203812] %s (42000456)", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + test1(fp2, "4c203812"); + + WAIT(); + + printf("\nconversions (float variable to integer variable)\n"); + fp1 = 12.3f; + var_schar = (signed char)fp1; + printf("fp1 0x%08lx %s (12.3) schar:%d (exp:12)", *((uint32_t*)&fp1), _ftostr(buf, fp1), (int)var_schar); + test2(var_schar, 12); + + fp1 = -12.3f; + var_schar = (signed char)fp1; + printf("fp1 0x%08lx %s (-12.3) schar:%d (exp:-12)", *((uint32_t*)&fp1), _ftostr(buf, fp1), (int)var_schar); + test2(var_schar, -12); + + fp2 = 19.9f; + var_uchar = (unsigned char)fp2; + printf("fp2 0x%08lx %s (19.9) uchar:%u (exp:19)", *((uint32_t*)&fp2), _ftostr(buf, fp2), (int)var_uchar); + test2(var_uchar, 19); + + fp1 = 1234.5f; + var_sint = (signed short)fp1; + printf("fp1 0x%08lx %s (1234.5) sint:%d (exp:1234)", *((uint32_t*)&fp1), _ftostr(buf, fp1), var_sint); + test2(var_sint, 1234); + + fp1 = -1234.5f; + var_sint = (signed short)fp1; + printf("fp1 0x%08lx %s (-1234.5) sint:%d (exp:-1234)", *((uint32_t*)&fp1), _ftostr(buf, fp1), var_sint); + test2(var_sint, -1234); + + fp2 = 1999.9f; + var_uint = (unsigned short)fp2; + printf("fp2 0x%08lx %s (1999.9) uint:%u (exp:1999)", *((uint32_t*)&fp2), _ftostr(buf, fp2), var_uint); + test2(var_uint, 1999); + + fp1 = 123456.5f; + var_slong = (signed long)fp1; + printf("fp1 0x%08lx %s (123456.5) slong:%ld (exp:123456)", *((uint32_t*)&fp1), _ftostr(buf, fp1), var_slong); + test2(var_slong, 123456); + + fp1 = -123456.5f; + var_slong = (signed long)fp1; + printf("fp1 0x%08lx %s (-123456.5) slong:%ld (exp:-123456)", *((uint32_t*)&fp1), _ftostr(buf, fp1), var_slong); + test2(var_slong, -123456); + + fp2 = 199988.9f; + var_ulong = (unsigned long)fp2; + printf("fp2 0x%08lx %s (199988.9) ulong:%lu (exp:199988)", *((uint32_t*)&fp2), _ftostr(buf, fp2), var_ulong); + test2(var_ulong, 199988); +} + +int main(void) +{ + + printf("float-conv\n"); + + constvar(); + WAIT(); + varvar(); + WAIT(); + + printf("\nfloat-conv (res:%d)\n", result); + return result; +} diff --git a/test/val/float-minimal.c b/test/val/float-minimal.c new file mode 100644 index 000000000..ff2f93a08 --- /dev/null +++ b/test/val/float-minimal.c @@ -0,0 +1,151 @@ + +// test minimal float support. +// this should test everything that does NOT require linking a library +// - float literals in code are recognized as such +// - float variables are converted into the float binary format +// - taking address from float and assigning via pointer works + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 42.01002f; +float fp2; // non initialized +float *fp_p; // non initialized + +uintptr_t p; + +float fp3; +float fp4 = 23.12f; + +char buf[0x20]; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { + printf("\n"); + } else { + printf(" (failed)\n"); + result++; + } +} + +void references(void) { + float fp2 = 23.1234f; + + printf("fp2:0x%08lx [exp:0x41b8fcb9] %s (23.1234)", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + test1(fp2, "41b8fcb9"); + printf("fp4:0x%08lx [exp:0x41b8f5c3] %s (23.12)", *((uint32_t*)&fp4), _ftostr(buf, fp4)); + test1(fp4, "41b8f5c3"); + + printf("(global) get address, read via ptr\n"); + // get address of global (works) + p = (uintptr_t)&fp1; + fp_p = (float*)p; + // read fp via pointer and assign local + fp2 = *fp_p; + + printf("fp1:0x%08lx [exp:0x42280a43] %s (42.01002)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "42280a43"); + printf("fp2:0x%08lx [exp:0x42280a43] %s (42.01002)", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + test1(fp2, "42280a43"); + + printf("(local) get address, read via ptr\n"); + fp2 = 23.1234f; + + // get address of local + p = (uintptr_t)&fp2; + fp_p = (float*)p; + // read fp via pointer and assign global + fp3 = *fp_p; + + printf("fp2:0x%08lx [exp:0x41b8fcb9] %s (23.1234)", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + test1(fp2, "41b8fcb9"); + printf("fp3:0x%08lx [exp:0x41b8fcb9] %s (23.1234)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "41b8fcb9"); +} + +void testprinting(void) +{ + static float a,b; + printf("\ntestprinting:\n\n"); + + a = 1.0f; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + b = 0.10f; + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + printf("\n"); + + a = 0.00012f; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + b = 10.0f; + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + printf("\n"); + + a = 40000.0f; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + b = 10.0f; + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + printf("\n"); + + a = -40000.0f; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + b = 10.0f; + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + a = b * a; printf("0x%08lx %s\n", *((uint32_t*)&a), _ftostr(buf, a) ); + printf("\n"); +} + +int main(void) +{ + printf("float-minimal\n"); + + printf("sizeof (float): %d\n", (int)sizeof(float)); + + references(); + WAIT(); + testprinting(); + WAIT(); + + printf("float-minimal (res:%d)\n", result); + return result; +} diff --git a/test/val/float-mixed.c b/test/val/float-mixed.c new file mode 100644 index 000000000..7cf1746f7 --- /dev/null +++ b/test/val/float-mixed.c @@ -0,0 +1,117 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; +int i; + +unsigned char var_char; +unsigned int var_int; +float var_float; + +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + printf("[%s:%s]", temp, str); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf(" (ok)"); + } else { + printf(" (failed) !!! "); + result++; + } + printf("result:%d\n", result); +} + +void SKIPPEDtest1(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + printf(" (SKIPPED:%s:%s)\n", temp, str); +} + +void test(void) +{ + + printf("floatconst + intvar * floatconst\n"); + var_char = 3; + fp1 = 2.0f + var_char * 0.2f; + printf("fp1:0x%08lx [0x40266666] %s (2.5997)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "40266666"); + + var_char = 4; + fp1 = var_char * 2.0f + 3.0f; + fp2 = 3.0f + var_char * 2.0f; + printf(" fp1:0x%08lx [0x41300000] %s (exp:11)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf(" fp2:0x%08lx [0x41300000] %s (exp:11)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + test1(fp1, "41300000"); + test1(fp2, "41300000"); + + printf("floatconst / intconst, intconst / floatconst\n"); + fp1 = ( (20.0f / 4.5f)); + fp2 = ( (4.5f / 20.0f)); + printf(" fp1:0x%08lx [0x408e38e4] %s (exp:4.444445)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "408e38e4"); + printf(" fp2:0x%08lx [0x3e666666] %s (exp:0.225000)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + test1(fp2, "3e666666"); + + fp1 = ((20 / 4.5f)); // 4.44 + fp2 = ((4.5f / 20)); // 0.225 + printf(" fp1:0x%08lx [0x408e38e4] %s (exp:4.444445)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "408e38e4"); + printf(" fp2:0x%08lx [0x3e666666] %s (exp:0.225000)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + test1(fp2, "3e666666"); + +} + +int main(void) +{ + float fp2 = 43.21f; + + printf("*** float-mixed ***\n"); + printf("fp1:0x%08lx [0x414570a4] %s (12.340000)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf("fp2:0x%08lx [0x422cd70a] %s (43.209999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + + test(); + WAIT(); + + printf("\nfloat-mixed (res:%d)\n", result); + return result; +} diff --git a/test/val/float-negate.c b/test/val/float-negate.c new file mode 100644 index 000000000..096a2b306 --- /dev/null +++ b/test/val/float-negate.c @@ -0,0 +1,108 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 1.0f; +float fp2 = 200.0f; // aliased by variable in main +float fp3 = 3.0f; +float fp4 = 4.0f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf("(ok)"); + printf("\n"); + } else { + printf(" (failed)\n"); + result++; + } +} + +void test2(long n, long val) +{ + if (n == val) { +// printf("(ok)"); + printf("\n"); + } else { + printf(" (failed)\n"); + result++; + } +} + +int main(void) +{ + float fp2 = 2.00f; + + printf("float negate (minus)\n"); + + printf("fp1:0x%08lx [0x3f800000] %s (1.0)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "3f800000"); + printf("fp2:0x%08lx [0x40000000] %s (2.0)", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + test1(fp2, "40000000"); + + var_sint = -fp1; + fp3 = -fp2; + fp2 = -fp1; + printf("fp2 0x%08lx [0xbf800000] %s (-1.0) %d", *((uint32_t*)&fp2), _ftostr(buf, fp2), var_sint); + test1(fp2, "bf800000"); + printf("fp3 0x%08lx [0xc0000000] %s (-2.0)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "c0000000"); + + fp1 = 12.6f; + fp2 = -fp1; + var_sint = -fp1; + fp3 = -fp2; + printf("fp2 0x%08lx [0xc149999a] %s (-12.6) %d", *((uint32_t*)&fp2), _ftostr(buf, fp2), var_sint); + test1(fp2, "c149999a"); + printf("fp3 0x%08lx [0x4149999a] %s (12.6)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "4149999a"); + + fp1 = -12.6f; + fp2 = -fp1; + var_sint = -fp1; + fp3 = -fp2; + printf("fp2 0x%08lx [0x4149999a] %s (12.6) %d", *((uint32_t*)&fp2), _ftostr(buf, fp2), var_sint); + test1(fp2, "4149999a"); + printf("fp3 0x%08lx [0xc149999a] %s (-12.6)", *((uint32_t*)&fp3), _ftostr(buf, fp3)); + test1(fp3, "c149999a"); + + printf("float minus (res:%d)\n", result); + return result; +} diff --git a/test/val/float-ternary.c b/test/val/float-ternary.c new file mode 100644 index 000000000..aa546b882 --- /dev/null +++ b/test/val/float-ternary.c @@ -0,0 +1,90 @@ + +// test basic arithmetic operations + +#ifdef CONIO +#include +#define WAIT() cgetc() +#else +#define WAIT() +#endif + +#include +#include +#include +#include + +#include <_float.h> + +float fp1 = 12.34f; +float fp2; // non initialized +float fp3, fp4 = 55.55f; + +char buf[0x20]; +char buf2[0x20]; +char buf3[0x20]; + +unsigned long l1,l2; + +signed char var_schar; +unsigned char var_uchar; +signed int var_sint; +unsigned int var_uint; +signed long var_slong; +unsigned long var_ulong; + +int result = 0; + +// returns 1 if value in f matches the string +// the string is a hex value without leading "0x" +int compare(float f, char *str) +{ + char temp[12]; + sprintf(temp, "%08lx", *((uint32_t*)&f)); + return (strcmp(temp, str) == 0) ? 1 : 0; +} + +void test1(float f, char *str) +{ + if (compare(f, str)) { +// printf("(ok)"); + printf("\n"); + } else { + printf(" (failed)\n"); + result++; + } +} + +void test2(long n, long val) +{ + if (n == val) { +// printf("(ok)"); + printf("\n"); + } else { + printf(" (failed)\n"); + result++; + } +} + +int main(void) +{ + float fp2 = 43.21f; + + printf("float-ternary\n"); + printf("fp1:0x%08lx [0x414570a4] %s (12.340000)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + printf("fp2:0x%08lx [0x422cd70a] %s (43.209999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2)); + + fp1 = (fp2 == 2.5f) ? 1.5f : 0.5f; + + printf("fp1 0x%08lx [0x3f000000] %s (0.5)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "3f000000"); + + fp2 = 2.5f; + + fp1 = (fp2 == 2.5f) ? 1.5f : 0.5f; + + printf("fp1 0x%08lx [0x3fc00000] %s (1.5)", *((uint32_t*)&fp1), _ftostr(buf, fp1)); + test1(fp1, "3fc00000"); + + printf("float-ternary (res:%d)\n", result); + return result; +} diff --git a/test/val/inline-asm-1489.c b/test/val/inline-asm-1489.c index a531c7405..ec7597e01 100644 --- a/test/val/inline-asm-1489.c +++ b/test/val/inline-asm-1489.c @@ -42,10 +42,10 @@ int res = 0; void dotest1a(uint8_t *s, uint8_t *d) { - printf("dotest1a\n"); + printf("dotest1a (and 0x3f)\n"); while (*s != 0) { *d = (testasm1(*s)); -// printf("%04x:%02x\n",d,*d); + printf("%04x:%02x\n",d,*d); d++; s++; } @@ -53,9 +53,10 @@ void dotest1a(uint8_t *s, uint8_t *d) void dotest1b(uint8_t *s, uint8_t *d) { - printf("dotest1b\n"); + printf("dotest1b (and 0x3f)\n"); while (*s != 0) { *d = (testasm2(*s)); + printf("%04x:%02x\n",d,*d); d++; s++; }