1
0
mirror of https://github.com/cc65/cc65.git synced 2025-02-20 14:29:03 +00:00

beginning of float libraries and test programs

This commit is contained in:
mrdudz 2022-06-20 01:54:03 +02:00
parent 1fb7c896b4
commit 00fabb8caf
62 changed files with 4843 additions and 0 deletions

3
test/float/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.bin
*.prg

197
test/float/Makefile Normal file
View File

@ -0,0 +1,197 @@
OPT=
FILES=\
quick.prg \
\
float-minimal.prg \
float-minimal.bin \
float-minimal.woz.bin \
\
float-basic.prg \
float-basic.bin \
float-basic.woz.bin \
\
float-basic-cmp.prg \
float-basic-cmp.bin \
float-basic-cmp.woz.bin
#
# floattest.prg
##############################################################################
HEADER=\
include/_float.h \
include/math.h
CBMRUNTIME=\
cbmkernal/float.s \
cbmkernal/ftoa.c \
cbmkernal/ffloor.c \
cbmkernal/cc65wrapper.s
IEEERUNTIME=\
ieee754/feaxint.s \
ieee754/feaxlong.s \
ieee754/fbnegeax.s \
ieee754/eaxufloat.s \
ieee754/eaxfloat.s \
ieee754/axufloat.s \
ieee754/axfloat.s \
ieee754/aufloat.s \
ieee754/afloat.s \
ieee754/ftosaddeax.s \
ieee754/ftossubeax.s \
ieee754/ftosdiveax.s \
ieee754/ftosmuleax.s \
ieee754/ftoseqeax.s \
ieee754/ftosneeax.s \
ieee754/ftosgteax.s \
ieee754/ftoslteax.s \
ieee754/ftosgeeax.s \
ieee754/ftosleeax.s \
ieee754/_ftostr.c
WOZRUNTIME=\
woz/feaxint.s \
woz/feaxlong.s \
woz/fbnegeax.s \
woz/eaxufloat.s \
woz/eaxfloat.s \
woz/axufloat.s \
woz/axfloat.s \
woz/aufloat.s \
woz/afloat.s \
woz/ftosaddeax.s \
woz/ftossubeax.s \
woz/ftosdiveax.s \
woz/ftosmuleax.s \
woz/ftoseqeax.s \
woz/ftosneeax.s \
woz/ftosgteax.s \
woz/ftoslteax.s \
woz/ftosgeeax.s \
woz/ftosleeax.s \
woz/_ftostr.c \
woz/wozfp.s
##############################################################################
all: $(FILES)
float-minimal.s: float-minimal.c $(HEADER) $(IEEERUNTIME)
cc65 $(OPT) -t sim6502 -I ./include --add-source -o float-minimal.s float-minimal.c
float-minimal.bin: float-minimal.s $(HEADER) $(IEEERUNTIME)
cl65 $(OPT) -t sim6502 -I ./include -o float-minimal.bin float-minimal.s $(IEEERUNTIME)
float-basic.s: float-basic.c $(HEADER) $(IEEERUNTIME)
cc65 $(OPT) -t sim6502 -I ./include --add-source -o float-basic.s float-basic.c
float-basic.bin: float-basic.s $(HEADER) $(IEEERUNTIME)
cl65 $(OPT) -t sim6502 -I ./include -o float-basic.bin float-basic.s $(IEEERUNTIME)
float-basic-cmp.s: float-basic-cmp.c $(HEADER) $(IEEERUNTIME)
cc65 $(OPT) -t sim6502 -I ./include --add-source -o float-basic-cmp.s float-basic-cmp.c
float-basic-cmp.bin: float-basic-cmp.s $(HEADER) $(IEEERUNTIME)
cl65 $(OPT) -t sim6502 -I ./include -o float-basic-cmp.bin float-basic-cmp.s $(IEEERUNTIME)
###############################################################################
float-minimal.woz.s: float-minimal.c $(HEADER) $(WOZRUNTIME)
cc65 $(OPT) -t sim6502 -I ./include --add-source -o float-minimal.woz.s float-minimal.c
float-minimal.woz.bin: float-minimal.woz.s $(HEADER) $(WOZRUNTIME)
cl65 $(OPT) -t sim6502 -I ./include -o float-minimal.woz.bin float-minimal.woz.s $(WOZRUNTIME)
float-basic.woz.s: float-basic.c $(HEADER) $(WOZRUNTIME)
cc65 $(OPT) -t sim6502 -I ./include --add-source -o float-basic.woz.s float-basic.c
float-basic.woz.bin: float-basic.woz.s $(HEADER) $(WOZRUNTIME)
cl65 $(OPT) -t sim6502 -I ./include -o float-basic.woz.bin float-basic.woz.s $(WOZRUNTIME)
float-basic-cmp.woz.s: float-basic-cmp.c $(HEADER) $(WOZRUNTIME)
cc65 $(OPT) -t sim6502 -I ./include --add-source -o float-basic-cmp.woz.s float-basic-cmp.c
float-basic-cmp.woz.bin: float-basic-cmp.woz.s $(HEADER) $(WOZRUNTIME)
cl65 $(OPT) -t sim6502 -I ./include -o float-basic-cmp.woz.bin float-basic-cmp.woz.s $(WOZRUNTIME)
###############################################################################
float-minimal.c64.s: float-minimal.c $(HEADER) $(CBMRUNTIME)
cc65 $(OPT) -DCONIO -t c64 -I ./include -I ./cbmkernal --add-source -o float-minimal.c64.s float-minimal.c
float-minimal.prg: float-minimal.c64.s $(HEADER) $(CBMRUNTIME)
cl65 $(OPT) -t c64 -I ./include -I ./cbmkernal -o float-minimal.prg float-minimal.c64.s $(CBMRUNTIME)
float-basic.c64.s: float-basic.c $(HEADER) $(CBMRUNTIME)
cc65 $(OPT) -DCONIO -t c64 -I ./include -I ./cbmkernal --add-source -o float-basic.c64.s float-basic.c
float-basic.prg: float-basic.c64.s $(HEADER) $(CBMRUNTIME)
cl65 $(OPT) -t c64 -I ./include -I ./cbmkernal -o float-basic.prg float-basic.c64.s $(CBMRUNTIME)
float-basic-cmp.c64.s: float-basic-cmp.c $(HEADER) $(CBMRUNTIME)
cc65 $(OPT) -DCONIO -t c64 -I ./include -I ./cbmkernal --add-source -o float-basic-cmp.c64.s float-basic-cmp.c
float-basic-cmp.prg: float-basic-cmp.c64.s $(HEADER) $(CBMRUNTIME)
cl65 $(OPT) -t c64 -I ./include -I ./cbmkernal -o float-basic-cmp.prg float-basic-cmp.c64.s $(CBMRUNTIME)
floattest.c64.s: floattest.c $(HEADER) $(CBMRUNTIME)
cc65 $(OPT) -DCONIO -t c64 -I ./include -I ./cbmkernal --add-source -o floattest.c64.s floattest.c
floattest.prg: floattest.c64.s $(HEADER) $(CBMRUNTIME)
cl65 $(OPT) -t c64 -I ./include -I ./cbmkernal -o floattest.prg floattest.c64.s $(CBMRUNTIME)
quick.c64.s: quick.c $(HEADER) $(CBMRUNTIME)
cc65 $(OPT) -DCONIO -t c64 -I ./include -I ./cbmkernal --add-source -o quick.c64.s quick.c
quick.prg: quick.c64.s $(HEADER) $(CBMRUNTIME)
cl65 $(OPT) -t c64 -I ./include -I ./cbmkernal -o quick.prg quick.c64.s $(CBMRUNTIME)
runquick: quick.prg
x64sc -autostartprgmode 1 quick.prg
###############################################################################
gccminimal: float-minimal.c gccstubs.c
gcc -I ./include "-D__fastcall__= " -o minimal float-minimal.c gccstubs.c -lm
gccbasic: float-basic.c gccstubs.c
gcc -I ./include "-D__fastcall__= " -o basic float-basic.c gccstubs.c -lm
gccbasiccmp: float-basic-cmp.c gccstubs.c
gcc -I ./include "-D__fastcall__= " -o basiccmp float-basic-cmp.c gccstubs.c -lm
gccfloattest: floattest.c gccstubs.c
gcc -I ./include "-D__fastcall__= " -o floattest floattest.c gccstubs.c -lm
rungcc: gccminimal gccbasic gccbasiccmp gccfloattest
./minimal
./basic
./basiccmp
./floattest
###############################################################################
runminimal: float-minimal.bin
sim65 float-minimal.bin
runbasic: float-basic.bin
sim65 float-basic.bin
runbasiccmp: float-basic-cmp.bin
sim65 float-basic-cmp.bin
run: runminimal runbasic runbasiccmp
sim65 float-minimal.bin
sim65 float-basic.bin
sim65 float-basic-cmp.bin
runwoz: float-minimal.woz.bin float-basic.woz.bin float-basic-cmp.woz.bin
sim65 float-minimal.woz.bin
sim65 float-basic.woz.bin
sim65 float-basic-cmp.woz.bin
###############################################################################
clean:
$(RM) ./minimal
$(RM) ./basic
$(RM) ./basiccmp
$(RM) ./floattest
$(RM) $(FILES)
$(RM) quick.c64.s
$(RM) float-minimal.s
$(RM) float-minimal.c64.s
$(RM) float-minimal.woz.s
$(RM) float-basic.s
$(RM) float-basic.c64.s
$(RM) float-basic.woz.s
$(RM) float-basic-cmp.s
$(RM) float-basic-cmp.c64.s
$(RM) float-basic-cmp.woz.s

View File

@ -0,0 +1,121 @@
#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 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);
float __fastcall__ _utof(unsigned char v);
float __fastcall__ _itof(int v);
float __fastcall__ _stof(unsigned short v);
int __fastcall__ _ftoi(float f);
/* compare two floats, returns 0 if f = a, 1 if f < a, 255 if f > a */
unsigned char __fastcall__ _fcmp(float f, float a);
/* 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 */
/* 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);
float __fastcall__ _fneg(float f); /* negate (flip sign) */
unsigned char __fastcall__ _ftestsgn(float f); /* FIXME */
float __fastcall__ _fsgn(float s);
float __fastcall__ _fint(float s);
#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

View File

@ -0,0 +1,388 @@
.import __ctof
.import __utof
.import __itof
.import __stof
; 8bit signed -> float
.export afloat
afloat:
jmp __ctof
; 8bit unsigned -> float
.export aufloat
aufloat:
jmp __utof
; 16bit signed -> float
.export axfloat
axfloat:
jmp __itof
; 16bit unsigned -> float
.export axufloat
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 eaxfloat
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 eaxufloat
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 feaxint
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 feaxlong
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 fbnegeax
.import bnegax
fbnegeax:
jsr __ftoi
jmp bnegax
;--------------------------------------------------------------
; math ops
.import __fadd
.import __fsub
.import __fdiv
.import __fmul
; Primary = TOS + Primary (like tosaddeax)
.export ftosaddeax
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 ftossubeax
ftossubeax:
jmp __fsub
.export ftosdiveax
ftosdiveax:
jmp __fdiv
.export ftosmuleax
ftosmuleax:
jmp __fmul
;--------------------------------------------------------------
.import __fcmp
; test for equal
.export ftoseqeax
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 ftosneeax
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 ftosgteax
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 ftoslteax
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 ftosgeeax
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 ftosleeax
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
.export _powf
_powf:
; arg0: a/x/sreg/sreg+1
; arg1: (sp),y (y=0..3)
jmp __fpow
.export _sinf
_sinf:
; arg0: a/x/sreg/sreg+1
jmp __fsin
.export _cosf
_cosf:
; arg0: a/x/sreg/sreg+1
jmp __fcos
.export _logf
_logf:
; arg0: a/x/sreg/sreg+1
jmp __flog
.export _expf
_expf:
; arg0: a/x/sreg/sreg+1
jmp __fexp
.export _sqrtf
_sqrtf:
; arg0: a/x/sreg/sreg+1
jmp __fsqr
.export _tanf
_tanf:
; arg0: a/x/sreg/sreg+1
jmp __ftan
.export _atanf
_atanf:
; arg0: a/x/sreg/sreg+1
jmp __fatn
.export _fabsf
_fabsf:
; arg0: a/x/sreg/sreg+1
jmp __fabs

View File

@ -0,0 +1,24 @@
#include <_float.h>
#include <math.h>
#include <cbmfp.h>
#define _fcmplt(_d, _s) (_fcmp((_d), (_s)) == 1)
#define _fcmpgt(_d, _s) (_fcmp((_d), (_s)) == 255)
#define _fcmpeq(_d, _s) (_fcmp((_d), (_s)) == 0)
/* FIXME: this is really too simple */
float ffloor(float x)
{
signed long n;
float d;
n = _ftoi(x); /* FIXME: long */
d = _itof(n); /* FIXME: long */
if (_fcmpeq(d, x) || _fcmplt(_itof(0), x)) {
return d;
}
return _fsub(d, 1);
}

View File

@ -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<x2)
BASIC_FAC_Poly2 = $e040 ; in: FAC x a/y ptr to poly (1byte grade,5bytes per coefficient)
BASIC_FAC_Poly1 = $e056 ; in: FAC x a/y ptr to poly (1byte grade,5bytes per coefficient)

View File

@ -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
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<x2)
BASIC_FAC_Poly2 = $e043 ; in: FAC x a/y ptr to poly (1byte grade,5bytes per coefficient)
BASIC_FAC_Poly1 = $e059 ; in: FAC x a/y ptr to poly (1byte grade,5bytes per coefficient)

View File

@ -0,0 +1,849 @@
BINARYFORMAT_CBM_UNPACKED = 0
BINARYFORMAT_CBM_PACKED = 1
BINARYFORMAT_IEEE754 = 2
; BEWARE: also change in float.h
;BINARYFORMAT = BINARYFORMAT_CBM_UNPACKED
;BINARYFORMAT = BINARYFORMAT_CBM_PACKED
BINARYFORMAT = BINARYFORMAT_IEEE754
.segment "LOWCODE"
;---------------------------------------------------------------------------------------------
.if .defined(__C64__)
__basicon:
sei
ldx #$37
stx $01
rts
__basicoff:
ldx #$36
stx $01
cli
rts
.endif
.macro __enable_basic_if_needed
.if .defined(__C64__)
jsr __basicon
.endif
.endmacro
.macro __disable_basic_if_needed
.if .defined(__C64__)
jsr __basicoff
.endif
.endmacro
.macro __return_with_cleanup
.if .defined(__C64__)
jmp __basicoff
.else
rts
.endif
.endmacro
;---------------------------------------------------------------------------------------------
; first come the actual stubs to floating point routines, these are ment to be
; used from further written ml-math routines aswell. (maybe also from the compiler?!)
;---------------------------------------------------------------------------------------------
.if .defined(__VIC20__)
.include "float-vic20.inc"
.else
.include "float.inc"
.endif
.importzp sreg, ptr1
;---------------------------------------------------------------------------------------------
; converter integer types to float
;---------------------------------------------------------------------------------------------
___float_s8_to_fac:
;a: low
__float_s8_to_fac:
__enable_basic_if_needed
jsr BASIC_s8_to_FAC
__return_with_cleanup
___float_u8_to_fac:
;a: low
tay
;y: low
__float_u8_to_fac:
__enable_basic_if_needed
jsr BASIC_u8_to_FAC
__return_with_cleanup
; get C-parameter (signed int), convert to FAC
___float_s16_to_fac:
;a: low x: high
tay
txa
;y: low a: high
; convert signed int (YA) to FAC
__float_s16_to_fac:
__enable_basic_if_needed ; enable BASIC (trashes X)
jsr BASIC_s16_to_FAC
__return_with_cleanup
; get C-parameter (unsigned short), convert to FAC
___float_u16_to_fac:
;a: low x: high
tay
txa
;y: low a: high
__float_u16_to_fac:
sta FAC_MANTISSA0
sty FAC_MANTISSA1
__enable_basic_if_needed
ldx #$90
sec
jsr BASIC_u16_to_FAC
__return_with_cleanup
; return to C, FAC as unsigned int
__float_fac_to_u16:
__enable_basic_if_needed
jsr BASIC_FAC_to_u16
__disable_basic_if_needed
ldx FAC_MANTISSA2
lda FAC_MANTISSA3
rts
;---------------------------------------------------------------------------------------------
; converter float to string and back
;---------------------------------------------------------------------------------------------
; this converts to exponential form, ie what %e in printf would give you
__float_fac_to_str:
__enable_basic_if_needed
jsr BASIC_FAC_to_string
__return_with_cleanup
___float_str_to_fac:
; jsr popax
__float_str_to_fac:
sta $22
stx $23
ldy #$00
@l: lda ($22),y
beq @s
iny
bne @l
@s: tya
__enable_basic_if_needed
jsr BASIC_string_to_FAC
__return_with_cleanup
;---------------------------------------------------------------------------------------------
; get C-parameter (float), convert to FAC
___float_float_to_fac:
.if BINARYFORMAT = BINARYFORMAT_CBM_UNPACKED
sta FAC_MANTISSA1 ; 3
stx FAC_MANTISSA0 ; 2
ldy sreg ; 1
sty FAC_EXPONENT
ldy sreg+1 ; 0
sty FAC_SIGN
ldx #$00
stx FAC_MANTISSA2
stx FAC_MANTISSA3
stx FAC_ROUNDING
.endif
.if BINARYFORMAT = BINARYFORMAT_CBM_PACKED
sta FAC_MANTISSA2 ; 3
stx FAC_MANTISSA1 ; 2
lda sreg ; 1
ora #$80
sta FAC_MANTISSA0
; bit7=0 sign=0
; bit7=1 sign=$ff
ldx #0
lda sreg
bpl @pos
dex
@pos:
stx FAC_SIGN
ldy sreg+1 ; 0
sty FAC_EXPONENT
ldx #$00
stx FAC_MANTISSA3
stx FAC_ROUNDING
.endif
.if BINARYFORMAT = BINARYFORMAT_IEEE754
; ieee float is in A/X/sreg/sreg+1
sta FAC_MANTISSA2
stx FAC_MANTISSA1
; shift msb from mantissa into exponent
asl sreg ; mantissa msb
rol sreg+1 ; exp
; sign is in carry
lda #$ff
bcs @l
lda #0
@l:
sta FAC_SIGN
lda sreg ; mantissa msb
lsr
ora #$80 ; msb of mantissa is always 1
sta FAC_MANTISSA0
lda sreg+1 ; exp
clc
adc #2
sta FAC_EXPONENT
ldx #$00
stx FAC_MANTISSA3
stx FAC_ROUNDING
.endif
rts
; load BASIC float into FAC
; in: pointer (a/x) to BASIC float (not packed)
__float_float_to_fac: ; only used in ATAN2?
sta ptr1
stx ptr1+1
ldy #$00
lda (ptr1),y
sta FAC_EXPONENT
iny
lda (ptr1),y
sta FAC_MANTISSA0
iny
lda (ptr1),y
sta FAC_MANTISSA1
iny
lda (ptr1),y
sta FAC_MANTISSA2
iny
lda (ptr1),y
sta FAC_MANTISSA3
iny
lda (ptr1),y
sta FAC_SIGN
ldx #$00
stx FAC_ROUNDING
; always load arg after fac so these can
; be removed in funcs that only take fac
eor ARG_SIGN
sta FAC_SIGN_COMPARE
rts
; get C-parameter (two floats), to FAC and ARG
___float_float_to_fac_arg:
jsr ___float_float_to_fac
___float_float_to_arg:
ldy #$03
jsr ldeaxysp
.if BINARYFORMAT = BINARYFORMAT_CBM_UNPACKED
sta ARG_MANTISSA1 ; 3
stx ARG_MANTISSA0 ; 2
ldy sreg ; 1
sty ARG_EXPONENT
ldx #$00
stx ARG_MANTISSA2
stx ARG_MANTISSA3
lda sreg+1 ; 0
sta ARG_SIGN
eor FAC_SIGN
sta FAC_SIGN_COMPARE ; sign compare
.endif
.if BINARYFORMAT = BINARYFORMAT_CBM_PACKED
sta ARG_MANTISSA2 ; 3
stx ARG_MANTISSA1 ; 2
lda sreg ; 1
ora #$80
sta ARG_MANTISSA0
; bit7=0 sign=0
; bit7=1 sign=$ff
ldx #0
lda sreg ; 1
bpl @pos
dex
@pos:
stx ARG_SIGN
ldy sreg+1 ; 0
sty ARG_EXPONENT
ldx #$00
stx ARG_MANTISSA3
lda ARG_SIGN
eor FAC_SIGN
sta FAC_SIGN_COMPARE ; sign compare
.endif
.if BINARYFORMAT = BINARYFORMAT_IEEE754
; ieee float in a/x/sreg/sreg+1
sta ARG_MANTISSA2
stx ARG_MANTISSA1
asl sreg ; mantissa msb
rol sreg+1 ; exp
; sign is in carry
lda #$ff
bcs @l
lda #0
@l:
sta ARG_SIGN
lda sreg ; mantissa msb
lsr
ora #$80 ; the first bit in the mantissa should always be 1
sta ARG_MANTISSA0
lda sreg+1 ; exp
clc
adc #2
sta ARG_EXPONENT
ldx #$00
stx ARG_MANTISSA3
lda ARG_SIGN
eor FAC_SIGN
sta FAC_SIGN_COMPARE ; sign compare
.endif
jmp incsp4
; load BASIC float into ARG
; in: pointer (a/x) to BASIC float (not packed)
__float_float_to_arg: ; only used in ATAN2?
sta ptr1
stx ptr1+1
ldy #$00
lda (ptr1),y
sta ARG_EXPONENT
iny
lda (ptr1),y
sta ARG_MANTISSA0
iny
lda (ptr1),y
sta ARG_MANTISSA1
iny
lda (ptr1),y
sta ARG_MANTISSA2
iny
lda (ptr1),y
sta ARG_MANTISSA3
iny
lda (ptr1),y
sta ARG_SIGN
; sign compare
eor FAC_SIGN
sta FAC_SIGN_COMPARE
rts
; return to C, float as unsigned long
___float_fac_to_float:
.if BINARYFORMAT = BINARYFORMAT_CBM_UNPACKED
lda FAC_SIGN
sta sreg+1 ; 0
lda FAC_EXPONENT
sta sreg ; 1
ldx FAC_MANTISSA0 ; 2
lda FAC_MANTISSA1 ; 3
.endif
.if BINARYFORMAT = BINARYFORMAT_CBM_PACKED
lda FAC_EXPONENT
sta sreg+1 ; 0
; use the MSB of the mantissa for the sign
lda FAC_SIGN ; either $ff or $00
ora #$7f ; -> $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
;---------------------------------------------------------------------------------------------
.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
@l:
lda $0100,y
sta (ptr1),y
beq @s
iny
bne @l
@s:
lda ptr1
ldx ptr1+1
rts
.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
__flog: __ffunc1 BASIC_FAC_Log
;__fpos: __ffunc1 BASIC_FAC_Pos
__frnd: __ffunc1 BASIC_FAC_Rnd
__fsgn: __ffunc1 BASIC_FAC_Sgn
__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
;---------------------------------------------------------------------------------------------
; 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
.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
__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
ldx #>tempfloat
jsr __float_arg_to_float_packed
lda #<tempfloat
ldy #>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
__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
__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

134
test/float/cbmkernal/ftoa.c Normal file
View File

@ -0,0 +1,134 @@
#include <_float.h>
#include <math.h>
#include <cbmfp.h>
// convert float into a string. this is surprisingly complex, so we just use
// the kernal function, and then fix up the result
char *ftoa(char *buf, float n)
{
char i, ii, epos = 0, ex;
char tempbuf[0x20];
_ftostr(tempbuf, n);
// find position of the 'e'
i=0;while(tempbuf[i]) {
if (tempbuf[i] == 69) { /* 'e' */
epos = i;
break;
}
i++;
}
if (epos == 0) {
i = ii = 0;
// no exponent, we can return the number as is
if (tempbuf[i] == '-') {
buf[ii] = tempbuf[i];
i++;ii++;
}
// else {
// buf[ii] = ' ';
// ii++;
// }
// skip space
if (tempbuf[i] == ' ') {
i++;
}
if (tempbuf[i] == '.') {
i++;
buf[ii] = '0'; ii++;
buf[ii] = '.'; ii++;
}
while (tempbuf[i]) {
buf[ii] = tempbuf[i];
i++;ii++;
}
buf[ii] = 0;
} else {
// we have an exponent, get rid of it
i = ii = 0;
if (tempbuf[i] == '-') {
buf[ii] = tempbuf[i];
i++;ii++;
}
// else {
// buf[ii] = ' ';
// ii++;
// }
// skip space
if (tempbuf[i] == ' ') {
i++;
}
ex = ((tempbuf[epos+2] - '0') * 10) + (tempbuf[epos+3] - '0');
if (tempbuf[epos+1] == '+') {
// positive exponent, move decimal point to right, add zeros to the right
// first copy until we see either the decimal point, or the 'e'
while (tempbuf[i] && tempbuf[i] != '.' && tempbuf[i] != 69) {
buf[ii] = tempbuf[i];
i++;ii++;
}
// 'e' found, add as many zeros as in the exponent
if (tempbuf[i] == 69) {
while(ex) {
buf[ii] = '0';
ii++;
ex--;
}
}
if (tempbuf[i] == '.') {
i++; // skip '.'
// copy digits until 'e'
while(ex && tempbuf[i] != 69) {
buf[ii] = tempbuf[i];
ii++;i++;
ex--;
}
// add zeros
while(ex) {
buf[ii] = '0';
ii++;
ex--;
}
}
} else {
// negative exponent, move decimal point to left, add zeros to left
buf[ii] = '0'; ii++;
buf[ii] = '.'; ii++;
ex--;
// add zeros
while(ex) {
buf[ii] = '0';
ii++;
ex--;
}
while (tempbuf[i] && tempbuf[i] != 69) {
if (tempbuf[i] == '.') {
i++;
}
buf[ii] = tempbuf[i];
i++;ii++;
}
}
buf[ii] = 0;
}
return buf;
}

View File

@ -0,0 +1,161 @@
// test comparison operations
// WIP WIP WIP
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <_float.h>
float fp1, fp2, fp3, fp4;
char buf[0x10];
char buf2[0x10];
char buf3[0x10];
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 main(void)
{
printf("float-basic-cmp\n");
//-------------------------------------------------------------------------
// float variable vs float constant
printf("var vs const\n");
//FIXME: compiles, but is wrong, the constant in the comparison becomes 0
fp1 = 1.5f;
printf("1.5f == 1.6f is ");
if (fp1 == 1.6f) {
printf("true\n");
} else {
printf("false\n");
}
fp1 = 1.5f;
printf("1.5f == 1.5f is ");
if (1.5f == fp1) {
printf("true\n");
} else {
printf("false\n");
}
//FIXME: compiles, but is wrong, the constant in the comparison becomes 0
fp1 = 1.5f;
printf("1.5f != 1.6f is ");
if (fp1 != 1.6f) {
printf("true\n");
} else {
printf("false\n");
}
fp1 = 1.5f;
printf("1.5f != 1.5f is ");
if (1.5f != fp1) {
printf("true\n");
} else {
printf("false\n");
}
//FIXME: compiles, but is wrong, the constant in the comparison becomes 0
fp1 = 1.5f;
printf("1.5f < 1.6f is ");
if (fp1 < 1.6f) {
printf("true\n");
} else {
printf("false\n");
}
fp1 = 1.7f;
printf("1.7f < 1.5f is ");
if (1.7f < fp1) {
printf("true\n");
} else {
printf("false\n");
}
//-------------------------------------------------------------------------
// float variable vs float variable
printf("var vs var\n");
fp1 = 1.5f;
fp2 = 1.6f;
printf("1.5f == 1.6f is ");
if (fp1 == fp2) {
printf("true\n");
} else {
printf("false\n");
}
printf("1.5f != 1.6f is ");
if (fp1 != fp2) {
printf("true\n");
} else {
printf("false\n");
}
printf("1.5f < 1.6f is ");
if (fp1 < fp2) {
printf("true\n");
} else {
printf("false\n");
}
printf("1.5f > 1.6f is ");
if (fp1 > fp2) {
printf("true\n");
} else {
printf("false\n");
}
printf("1.5f <= 1.6f is ");
if (fp1 <= fp2) {
printf("true\n");
} else {
printf("false\n");
}
printf("1.5f >= 1.6f is ");
if (fp1 >= fp2) {
printf("true\n");
} else {
printf("false\n");
}
fp1 = 1.6f;
printf("1.6f == 1.6f is ");
if (fp1 == fp2) {
printf("true\n");
} else {
printf("false\n");
}
printf("1.6f != 1.6f is ");
if (fp1 != fp2) {
printf("true\n");
} else {
printf("false\n");
}
printf("1.6f < 1.6f is ");
if (fp1 < fp2) {
printf("true\n");
} else {
printf("false\n");
}
printf("1.6f > 1.6f is ");
if (fp1 > fp2) {
printf("true\n");
} else {
printf("false\n");
}
printf("1.6f <= 1.6f is ");
if (fp1 <= fp2) {
printf("true\n");
} else {
printf("false\n");
}
printf("1.6f >= 1.6f is ");
if (fp1 >= fp2) {
printf("true\n");
} else {
printf("false\n");
}
return 0;
}

183
test/float/float-basic.c Normal file
View File

@ -0,0 +1,183 @@
// test basic arithmetic operations
// WIP WIP WIP
#ifdef CONIO
#include <conio.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <_float.h>
float fp1 = 12.34f;
float fp2; // non initialized
float fp3, fp4 = 55.55f;
char buf[0x10];
char buf2[0x10];
char buf3[0x10];
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 main(void)
{
float fp2 = 43.21f;
printf("float-basic\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));
/* addition, variable + variable */
printf("addition, variable + variable\n");
fp1 = 12.34f;
fp2 = 43.21f;
fp3 = fp1 + fp2;
printf("%s+%s=%s\n", _ftostr(buf, fp1), _ftostr(buf2, fp2), _ftostr(buf3, fp3));
printf("fp3:0x%08lx [0x425e3333] %s (55.549999)\n", *((uint32_t*)&fp3), _ftostr(buf, fp3));
/* addition, variable + constant */
printf("addition, variable + constant\n");
fp3 = 55.549999f;
fp1 = fp3 + 0.05f;
printf("%s+%s=%s\n", _ftostr(buf, fp3), _ftostr(buf3, 0.05f), _ftostr(buf2, fp1));
printf("fp3:0x%08lx [0x425e3333] %s\n", *((uint32_t*)&fp3), _ftostr(buf, fp3));
printf("fp1:0x%08lx [0x425e6666] %s\n", *((uint32_t*)&fp1), _ftostr(buf, fp1));
#if 1
/* addition, constant + variable */
printf("addition, constant + variable\n");
fp2 = 43.21f;
fp1 = 12.7f + fp2; // FIXME: wrong, the add is dropped?
printf("%s+%s=%s\n", _ftostr(buf3, 12.7f), _ftostr(buf, fp2), _ftostr(buf2, fp1));
printf("fp3:0x%08lx [0x425e3333] %s\n", *((uint32_t*)&fp2), _ftostr(buf, fp2));
printf("fp1:0x%08lx [0x425e6666] %s\n", *((uint32_t*)&fp1), _ftostr(buf, fp1));
#endif
/* addition, constant + constant (already tested by minimal) (omitted) */
#ifdef CONIO
cgetc();
#endif
#if 0
/* substraction, variable - constant */
printf("substraction, variable - constant\n");
fp1 = 12.34;
fp3 = fp1 - 11.5f; // FIXME: Invalid operands for binary operator '-'
printf("%s-%s=%s\n", _ftostr(buf, fp1), _ftostr(buf2, 0x11.5f), _ftostr(buf3, fp3));
printf("fp3:0x%08lx [] %s ()\n", *((uint32_t*)&fp3), _ftostr(buf, fp3));
#endif
#if 1
/* substraction, constant - variable */
printf("substraction, constant - variable\n");
fp2 = 12.34;
fp3 = 11.5f - fp2;
printf("%s-%s=%s\n", _ftostr(buf, 11.5f), _ftostr(buf2, fp2), _ftostr(buf3, fp3));
printf("fp3:0x%08lx [] %s ()\n", *((uint32_t*)&fp3), _ftostr(buf, fp3));
#endif
#if 1
/* substraction, variable - variable */
printf("substraction, variable - variable\n");
fp3 = fp1 - fp2;
printf("%s-%s=%s\n", _ftostr(buf, fp1), _ftostr(buf2, fp2), _ftostr(buf3, fp3));
printf("fp3:0x%08lx [0x41463d70] %s (12.389999)\n", *((uint32_t*)&fp3), _ftostr(buf, fp3));
#endif
#if 1
printf("conversions (integer variable to float)\n");
var_schar = -12;
fp1 = var_schar;
var_uchar = 199;
fp2 = var_uchar;
printf("fp1 0x%08lx [] %s (-12)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1));
printf("fp2 0x%08lx [] %s (199)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2));
var_sint = -4711;
fp1 = var_sint;
var_uint = 42000;
fp2 = var_uint;
printf("fp1 0x%08lx [] %s (-4711)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1));
printf("fp2 0x%08lx [] %s (42000)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2));
var_slong = -4711456;
fp1 = var_slong;
var_ulong = 42000456;
fp2 = var_ulong;
printf("fp1 0x%08lx [] %s (-4711456)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1));
printf("fp2 0x%08lx [] %s (42000456)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2));
#ifdef CONIO
cgetc();
#endif
#endif
printf("conversions (float variable to integer)\n");
fp1 = -12.3f;
var_schar = (signed char)fp1;
printf("fp1 0x%08lx %s (12.3) schar:%d (12)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1), (int)var_schar);
fp2 = 19.9f;
var_uchar = (unsigned char)fp2;
printf("fp2 0x%08lx %s (19.9) uchar:%u (19)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2), (int)var_uchar);
fp1 = 1234.5f;
var_sint = (signed short)fp1;
printf("fp1 0x%08lx %s (1234.5) sint:%d (1234)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1), var_sint);
fp2 = 1999.9f;
var_uint = (unsigned short)fp2;
printf("fp2 0x%08lx %s (1999.9) uint:%u (1999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2), var_uint);
fp1 = 123456.5f;
var_slong = (signed long)fp1;
printf("fp1 0x%08lx %s (1234.5) slong:%ld (1234)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1), var_slong);
fp2 = 199988.9f;
var_ulong = (unsigned long)fp2;
printf("fp2 0x%08lx %s (1999.9) ulong:%lu (1999)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2), var_ulong);
#if 1
printf("multiplication, variable * variable\n");
fp1 = 25.2f;
fp2 = 2.3f;
fp3 = fp1 * fp2;
printf("%s*%s=%s\n", _ftostr(buf, fp1), _ftostr(buf2, fp2), _ftostr(buf3, fp3));
#endif
#if 1
printf("division, variable / variable\n");
fp1 = 25.2f;
fp2 = 2.3f;
fp3 = fp1 / fp2;
printf("%s/%s=%s\n", _ftostr(buf, fp1), _ftostr(buf2, fp2), _ftostr(buf3, fp3));
#endif
// FIXME: does not compile
#if 0
fp1 = (fp2 == 2.5f) ? 1.5f : 0.5f;
#endif
// NOT
printf("binary negate (not)\n");
fp1 = 12.6f;
fp2 = !fp1;
var_sint = !fp1;
fp3 = !fp2;
printf("fp2 0x%08lx [] %s () %d\n", *((uint32_t*)&fp2), _ftostr(buf, fp2), var_sint);
printf("fp3 0x%08lx [] %s ()\n", *((uint32_t*)&fp3), _ftostr(buf, fp3));
fp1 = -12.6f;
fp1 = 0.0f - fp1;
fp2 = !fp1;
var_sint = !fp1;
fp3 = !fp2;
printf("fp2 0x%08lx [] %s () %d\n", *((uint32_t*)&fp2), _ftostr(buf, fp2), var_sint);
printf("fp2 0x%08lx [] %s ()\n", *((uint32_t*)&fp2), _ftostr(buf, fp2));
printf("fp3 0x%08lx [] %s ()\n", *((uint32_t*)&fp3), _ftostr(buf, fp3));
return 0;
}

138
test/float/float-cbm..c Normal file
View File

@ -0,0 +1,138 @@
#ifdef __CC65__
#include <conio.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <float.h>
#include <math.h>
#include <cbmfp.h>
char strbuf[0x20];
char strbuf2[0x20];
char strbuf3[0x20];
typedef union {
float f;
unsigned char b[sizeof (float)];
} U;
#ifdef __CC65__
uint32_t ftobin(float f)
#else
unsigned long ftobin(float f)
#endif
{
U u;
u.f = f;
#ifdef __CC65__
return ((uint32_t)u.b[0] << 0) | ((uint32_t)u.b[1] << 8) | ((uint32_t)u.b[2] << 16) | ((uint32_t)u.b[3] << 24);
#else
return ((uint32_t)u.b[3] << 0) | ((uint32_t)u.b[2] << 8) | ((uint32_t)u.b[1] << 16) | ((uint32_t)u.b[0] << 24);
#endif
}
float fd, fs;
float a, b, c1;
int c, i, t;
int n;
void testconversions(void)
{
printf("\ntestconversions:\n\n");
printf("ftobin(0x12345678):0x%08lx\n", ftobin((float)0x12345678));
/* 42 ieee754: 0x42280000 */
b=_ctof(42);
printf("b:0x%08lx ", ftobin(b));
n=(int)((float)0x42280000);
printf("n:%d\n", n);
b=_ctof(42);
printf("b:0x%08lx ", ftobin(b));
n=(int)(b);
printf("n:%d\n", n);
b=_utof(42);
printf("b:0x%08lx ", ftobin(b));
n=(int)(b);
printf("n:%d\n", n);
b=_stof(1234);
printf("b:0x%08lx ", ftobin(b));
n=(int)(b);
printf("n:%d\n", n);
b=(float)(1234);
printf("b:0x%08lx ", ftobin(b));
n=(int)(b);
printf("n:%d\n", n);
b=atof("1234");
printf("b:0x%08lx ", ftobin(b));
n=(int)(b);
printf("n:%d\n", n);
_ftoa(strbuf, b);
printf("s:%s\n", strbuf);
printf("a:%s\n", _ftostr(strbuf, (float)(1234)));
printf("a:%s b:%s c:%s\n",
_ftostr(strbuf, (float)(1234)),
_ftostr(strbuf2, (float)(5678)),
_ftostr(strbuf3, (float)(9012))
);
#ifdef __CC65__
cgetc();
#endif
}
void testlogical(void)
{
printf("\ntestlogical:\n\n");
a = (float)(0xffa5);
b = (float)(0x5aff);
printf("a:0x%08lx (0xffa5)\n", ftobin(a));
printf("b:0x%08lx (0x5aff)\n", ftobin(b));
c1 = _fand(a, b);
printf("c1:0x%08lx\n", ftobin(c1));
n=(int)(c1);
printf("c1:%04x\n", n);
#ifdef __CC65__
cgetc();
#endif
}
#define _fcmplt(_d, _s) (_fcmp((_d), (_s)) == 1)
#define _fcmpgt(_d, _s) (_fcmp((_d), (_s)) == 255)
#define _fcmpeq(_d, _s) (_fcmp((_d), (_s)) == 0)
void testcompare(void)
{
printf("\ntestcompare:\n\n");
a=(float)(2);
b=(float)(3);
printf("cmp 2,3: %3d %d %d %d\n", fcmp(a, b), fcmpgt(a, b), fcmpeq(a, b), fcmplt(a, b));
printf("cmp 3,2: %3d %d %d %d\n", fcmp(b, a), fcmpgt(b, a), fcmpeq(b, a), fcmplt(b, a));
printf("cmp 2,2: %3d %d %d %d\n", fcmp(a, a), fcmpgt(a, a), fcmpeq(a, a), fcmplt(a, a));
#ifdef __CC65__
cgetc();
#endif
}
int main(void)
{
printf("sizeof (float): %d\n", (int)sizeof(float));
testconversions();
testlogical();
testcompare();
return EXIT_SUCCESS;
}

160
test/float/float-minimal.c Normal file
View File

@ -0,0 +1,160 @@
// 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 <conio.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#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[0x10];
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 main(void)
{
float fp2 = 23.1234f;
printf("float-minimal\n");
printf("fp2:0x%08lx [0x41b8f5c3] %s (23.1234)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2));
printf("fp4:0x%08lx [0x41b8f5c3] %s (23.12)\n", *((uint32_t*)&fp4), _ftostr(buf, fp4));
#if 1
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 [0x42280a43] %s (42.01002)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1));
printf("fp2:0x%08lx [0x42280a43] %s (42.01002)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2));
#endif
#if 1
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 [] %s (23.1234)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2));
printf("fp3:0x%08lx [] %s (23.1234)\n", *((uint32_t*)&fp3), _ftostr(buf, fp3));
#endif
// addition
#if 1
printf("constant + constant\n");
fp1 = 0.1f;
fp2 = 0.2f;
printf(" 0x%08lx [] %s (0.1)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1));
printf(" 0x%08lx [] %s (0.2)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2));
fp3 = 0.1f + 0.2f;
printf("fp3:0x%08lx [] %s (0.3)\n", *((uint32_t*)&fp3), _ftostr(buf, fp3));
#endif
// substraction
#if 0
printf("constant - constant\n");
fp1 = 0.1f;
fp2 = 0.2f;
fp3 = 0.1f - 0.2f; //FIXME: Invalid operands for binary operator '-'
printf(" 0x%08lx [] %s (0.1)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1));
printf(" 0x%08lx [] %s (0.2)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2));
printf("fp3:0x%08lx [] %s (0.3)\n", *((uint32_t*)&fp3), _ftostr(buf, fp3));
#endif
// multiplication
#if 0
printf("constant * constant\n");
fp1 = 0.1f;
fp2 = 0.2f;
fp3 = 0.1f * 0.2f; // FIXME: Precondition violated: IsClassInt (T), file 'cc65/datatype.c', line 1008
printf(" 0x%08lx [] %s (0.1)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1));
printf(" 0x%08lx [] %s (0.2)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2));
printf("fp3:0x%08lx [] %s (0.3)\n", *((uint32_t*)&fp3), _ftostr(buf, fp3));
#endif
// division
#if 0
printf("constant / constant\n");
fp1 = 0.1f;
fp2 = 0.2f;
fp3 = 0.1f / 0.2f; // FIXME: Precondition violated: IsClassInt (T), file 'cc65/datatype.c', line 1008
printf(" 0x%08lx [] %s (0.1)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1));
printf(" 0x%08lx [] %s (0.2)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2));
printf("fp3:0x%08lx [] %s (0.3)\n", *((uint32_t*)&fp3), _ftostr(buf, fp3));
#endif
#ifdef CONIO
cgetc();
#endif
// comparisons
#if 1
/* FIXME: this does not work yet */
printf("0.1f == 0.1f is "); if (0.1f == 0.1f) { printf("true\n"); } else { printf("false\n"); }
printf("0.2f == 0.1f is "); if (0.2f == 0.1f) { printf("true\n"); } else { printf("false\n"); }
printf("0.1f != 0.1f is "); if (0.1f != 0.1f) { printf("true\n"); } else { printf("false\n"); }
printf("0.2f != 0.1f is "); if (0.2f != 0.1f) { printf("true\n"); } else { printf("false\n"); }
#endif
#ifdef CONIO
cgetc();
#endif
// conversions
#if 1
printf("conversions (integer constant to float)\n");
fp1 = -12;
fp2 = 199;
printf("fp1 0x%08lx [] %s (-12)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1));
printf("fp2 0x%08lx [] %s (199)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2));
fp1 = -4711;
fp2 = 42000;
printf("fp1 0x%08lx [] %s (-4711)\n", *((uint32_t*)&fp1), _ftostr(buf, fp1));
printf("fp2 0x%08lx [] %s (42000)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2));
#endif
#if 1
printf("conversions (float constant to integer)\n");
var_schar = (signed char)12.3f;
printf("%s (12.3) schar:%d (12)\n", _ftostr(buf, 12.3f), (int)var_schar);
var_uchar = (unsigned char)19.9f;
printf("%s (19.9) uchar:%u (19)\n", _ftostr(buf, 19.9f), (int)var_uchar);
var_sint = (signed short)1234.5f;
printf("%s (1234.5) sint:%d (1234)\n", _ftostr(buf, 1234.5f), var_sint);
var_uint = (unsigned short)1999.9f;
printf("%s (1999.9) uint:%u (1999)\n", _ftostr(buf, 1999.9f), var_uint);
var_slong = (signed long)123456.5f;
printf("%s (123456.5f) slong:%ld (123456)\n", _ftostr(buf, 123456.5f), var_slong);
var_ulong = (unsigned long)199988.9f;
printf("%s (199988.9) ulong:%lu (199988)\n", _ftostr(buf, 199988.9f), var_ulong);
#endif
return 0;
}

350
test/float/floattest.c Normal file
View File

@ -0,0 +1,350 @@
#ifdef __CC65__
#include <conio.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <_float.h>
#include <math.h>
char strbuf[0x20];
char strbuf2[0x20];
char strbuf3[0x20];
typedef union {
float f;
unsigned char b[sizeof (float)];
} U;
#ifdef __CC65__
uint32_t ftobin(float f)
#else
unsigned long ftobin(float f)
#endif
{
U u;
u.f = f;
#ifdef __CC65__
return ((uint32_t)u.b[0] << 0) | ((uint32_t)u.b[1] << 8) | ((uint32_t)u.b[2] << 16) | ((uint32_t)u.b[3] << 24);
#else
return ((uint32_t)u.b[3] << 0) | ((uint32_t)u.b[2] << 8) | ((uint32_t)u.b[1] << 16) | ((uint32_t)u.b[0] << 24);
#endif
}
float fd, fs;
float a, b, c1;
int c, i, t;
int n;
void csetpoint8(unsigned char x)
{
while(x--) {
printf(" ");
}
printf("*\n");
}
#define YNUM 32
#define YNUM2 16
#define XNUM 32
#define XNUM2 16
void calcsin(void)
{
printf("sinus:\n");
for(i = 0; i < YNUM; i++) {
csetpoint8(XNUM2+((int)(sinf(deg2rad((float)(i),(float)(YNUM))) * (float)(YNUM2))/(YNUM/XNUM)));
}
}
void calccos(void)
{
printf("cosinus:\n");
for(i = 0; i < YNUM; i++) {
fs=deg2rad((float)(i),(float)(YNUM));
fd=cosf(fs) * (float)(YNUM2);
csetpoint8(XNUM2+((int)(fd)/(YNUM/XNUM)));
}
}
#ifdef __CC65__
int fx, fy;
#define CYNUM 20
#define CYNUM2 10
#define CXNUM 20
#define CXNUM2 10
void cplot(unsigned char x, unsigned char y)
{
gotoxy(x,y);cputc('*');
}
void testatan2(void)
{
for(i = 0; i < YNUM; i++) {
fx = CXNUM2+((int)((sinf(deg2rad((float)(i),(float)(CYNUM)))*(float)(CYNUM2)))/(CYNUM/CXNUM));
fs = deg2rad((float)(i), (float)(CYNUM));
fd = cosf(fs) * (float)(CYNUM2);
fy = CXNUM2 + ((int)(fd) / (CYNUM/CXNUM));
cplot(fx, fy);
fd = fatan2((float)(fx-CXNUM2), (float)(fy-CYNUM2));
_ftostr(strbuf, fd);
cputs(strbuf);
}
}
#endif
#if 0
void calcpoly1(void){
p=malloc(sizeof(fpoly)+((1+3)*sizeof(float)));
p.exponent=3;
// _strtof(&(p->coffs[3]),"0.25");
// _strtof(&(p->coffs[2]),"1");
// _strtof(&(p->coffs[1]),"-0.5");
// _strtof(&(p->coffs[0]),"0.25");
// _ftostr(&strbuf,&(p->coffs[3])); printf("a0:%s\n",strbuf);
// _ftostr(&strbuf,&(p->coffs[2])); printf("a1:%s\n",strbuf);
// _ftostr(&strbuf,&(p->coffs[1])); printf("a2:%s\n",strbuf);
// _ftostr(&strbuf,&(p->coffs[0])); printf("a3:%s\n",strbuf);
// _fpoly1(&fd,&p,&_f_pi);
// _ftostr(&strbuf,&fd); printf("x:%s\n",strbuf);
for(i=0;i<256;i++){
fs=_(float)(i);
_ftostr(&strbuf,fs); printf("%s:",strbuf);
fd=_fpoly1(&p,&fs);
_ftostr(&strbuf,fd); printf("%s\n",strbuf);
// c=_(int)(&fd);
// csetpoint8(i/(256/35),12+(c/(256/23)));
}
free(p);
}
#endif
unsigned short var_bs;
unsigned short var_fs;
float var_i;
unsigned char var_w;
unsigned char var_j;
float var_k;
unsigned short var_co;
void f1(void)
{
printf("i:0x%08lx\n",ftobin(_ctof(0)));
#if 0
printf("exp mantissa sign\n");
printf("%02x ",*(unsigned char*)(1024+(40*2)+0));
printf("%02x ",*(unsigned char*)(1024+(40*2)+1));
printf("%02x ",*(unsigned char*)(1024+(40*2)+2));
printf("%02x ",*(unsigned char*)(1024+(40*2)+3));
printf("%02x ",*(unsigned char*)(1024+(40*2)+4));
printf("%02x ",*(unsigned char*)(1024+(40*2)+5));
#endif
var_bs=1024;
var_fs=55304;
// var_i=_(float)(var_bs);while(1)
var_i=(float)(2);while(1)
{
printf("i:%d\n",(int)(var_i));
var_bs++;if(var_bs==1030)break;
#if 0
if(FCMPGT(0x00028000,U16TOF(0)))
{
if (FCMPGTEQ(var_i,(U16TOF(var_bs+1000)))) break;
}
else if(FCMPLT(0x00028000,U16TOF(0)))
{
if (FCMPLTEQ(var_i,(U16TOF(var_bs+1000)))) break;
}
#endif
// var_i=var_i + 0x00028000;
var_i=var_i + 0x00818000; // FIXME: float value?
// var_i=var_i + _ctof(1);
};
#ifdef __CC65__
cgetc();
#endif
}
void testbinary(void)
{
printf("\ntestbinary:\n\n");
n= 5;b=(float)(n);printf("%d:0x%08lx\n", n, ftobin(b));
n=-5;b=(float)(n);printf("%d:0x%08lx\n", n, ftobin(b));
n= 2;b=(float)(n);printf("%d:0x%08lx\n", n, ftobin(b));
n= 3;b=(float)(n);printf("%d:0x%08lx\n", n, ftobin(b));
#ifdef __CC65__
cgetc();
#endif
}
void testbasicmath(void)
{
printf("\ntestbasicmath:\n\n");
t=123;
fd=(float)((int)t);
fs=_fneg(fd);
_ftostr(strbuf,fd);
printf("123:%s\n",strbuf);
_ftostr(strbuf,fs);
printf("-123:%s\n",strbuf);
a = (float)(4321);
b = (float)(1234);
printf("4321:0x%08lx\n", ftobin(a));
printf("1234:0x%08lx\n", ftobin(b));
c1 = a + b;
printf("4321+1234:0x%08lx\n", ftobin(c1));
_ftoa(strbuf, c1);
printf("4321+1234:%s\n", strbuf);
a = (float)(1111);
b = (float)(2222);
printf("1111:0x%08lx\n", ftobin(a));
printf("2222:0x%08lx\n", ftobin(b));
c1 = a - b;
printf("1111-2222:0x%08lx\n", ftobin(c1));
_ftoa(strbuf, c1);
printf("1111-2222:%s\n", strbuf);
fd=(float)((int)t);
fs=(float)((int)2);
fd=fd / fs;
_ftostr(strbuf,fd);
printf("t:%s\n",strbuf);
// 1234 / 60 = 20,5666...
t=1234;
fd=(float)((int)t);
fs=(float)((int)60);
fd=fd / fs;
_ftostr(strbuf,fd);
printf("t:%s\n",strbuf);
// 5678 / 60 = 94,6333...
t=5678;
fd=(float)((int)t);
fs=(float)((int)60);
fd=fd / fs;
_ftostr(strbuf,fd);
printf("t:%s\n",strbuf);
// ! operator DOES work on floats!
fd=(float)((int)4);
fd=!fd;
_ftostr(strbuf,!fd);
printf("!!4:%s\n",strbuf);
fd=(float)((int)0);
fd=!fd;
_ftostr(strbuf,!fd);
printf("!!0:%s\n",strbuf);
a = 10.0f;
b = powf(a,(float)(1)); printf("0x%08lx %s\n", ftobin(b), _ftoa(strbuf,b));
b = powf(a,(float)(2)); printf("0x%08lx %s\n", ftobin(b), _ftoa(strbuf,b));
b = powf(a,(float)(3)); printf("0x%08lx %s\n", ftobin(b), _ftoa(strbuf,b));
#ifdef __CC65__
cgetc();
#endif
}
#define fcmp(_d, _s) (((_d) < (_s)) ? 1 : (((_d) > (_s)) ? 255 : (0)))
#define fcmplt(_d, _s) ((_d) < (_s))
#define fcmpgt(_d, _s) ((_d) > (_s))
#define fcmpeq(_d, _s) ((_d) == (_s))
void testcompare(void)
{
printf("\ntestcompare:\n\n");
a=(float)(2);
b=(float)(3);
printf("cmp 2,3: %3d %d %d %d\n", fcmp(a, b), fcmpgt(a, b), fcmpeq(a, b), fcmplt(a, b));
printf("cmp 3,2: %3d %d %d %d\n", fcmp(b, a), fcmpgt(b, a), fcmpeq(b, a), fcmplt(b, a));
printf("cmp 2,2: %3d %d %d %d\n", fcmp(a, a), fcmpgt(a, a), fcmpeq(a, a), fcmplt(a, a));
#ifdef __CC65__
cgetc();
#endif
}
void testprinting(void)
{
printf("\ntestprinting:\n\n");
a = 1.0f;
b = (a / 10.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
b = (a / 100.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
b = (a / 1000.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
b = (a / 10000.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
// printf("\n");
a = 2.0f;
b = (a / 10.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
b = (a / 100.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
b = (a / 1000.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
b = (a / 10000.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
// printf("\n");
a = 400000000.0f;
b = (a * 10.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
b = (a * 100.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
b = (a * 1000.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
b = (a * 10000.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
// printf("\n");
a = -2.0f;
b = (a / 10.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
b = (a / 100.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
b = (a / 1000.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
b = (a / 10000.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
// printf("\n");
a = -400000000.0f;
b = (a * 10.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
b = (a * 100.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
b = (a * 1000.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
b = (a * 10000.0f); printf("0x%08lx %s %s\n", ftobin(b), _ftostr(strbuf, b), _ftoa(strbuf2, b));
#ifdef __CC65__
cgetc();
#endif
}
int main(void)
{
printf("sizeof (float): %d\n", (int)sizeof(float));
testbasicmath();
// testlogical();
testbinary();
testcompare();
testprinting();
#if 0
f1();
calcsin();
calccos();
testatan2(); // FIXME
#endif
#if 0
calcpoly1();
#endif
return EXIT_SUCCESS;
}

49
test/float/gccstubs.c Normal file
View File

@ -0,0 +1,49 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
float _fneg(float f)
{
return f * -1.0f;
}
float _fand(float f1, float f2)
{
return ((unsigned)f1) & ((unsigned)f2);
}
char buffer[32];
char *_ftostr(char *d, float s)
{
if (d == NULL) {
d = &buffer[0];
}
sprintf(d, "%f", (double)s);
return d;
}
char *_ftoa(char *d, float s)
{
if (d == NULL) {
d = &buffer[0];
}
sprintf(d, "%f", (double)s);
return d;
}
float _ctof(char c)
{
return (float)c;
}
float _utof(unsigned int c)
{
return (float)c;
}
float _stof(signed int c)
{
return (float)c;
}

View File

@ -0,0 +1,97 @@
#include <stdlib.h>
#include <stdio.h>
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;
}

View File

@ -0,0 +1,7 @@
.include "ieee754.inc"
.export afloat
afloat:
; FIXME
rts

View File

@ -0,0 +1,7 @@
.include "ieee754.inc"
.export aufloat
aufloat:
; FIXME
rts

View File

@ -0,0 +1,7 @@
.include "ieee754.inc"
.export axfloat
axfloat:
; FIXME
rts

View File

@ -0,0 +1,7 @@
.include "ieee754.inc"
.export axufloat
axufloat:
; FIXME
rts

View File

@ -0,0 +1,7 @@
.include "ieee754.inc"
.export eaxfloat
eaxfloat:
; FIXME
rts

View File

@ -0,0 +1,7 @@
.include "ieee754.inc"
.export eaxufloat
eaxufloat:
; FIXME
rts

View File

@ -0,0 +1,7 @@
.include "ieee754.inc"
.export fbnegeax
fbnegeax:
; FIXME
rts

View File

@ -0,0 +1,8 @@
.include "ieee754.inc"
; float -> 16bit int
.export feaxint
feaxint:
; FIXME
rts

View File

@ -0,0 +1,8 @@
.include "ieee754.inc"
; float -> 32bit long
.export feaxlong
feaxlong:
; FIXME
rts

View File

@ -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

View File

@ -0,0 +1,12 @@
.include "ieee754.inc"
.importzp sp, sreg, tmp1
.import addysp1
.import addysp
.import popax
.export ftosdiveax
ftosdiveax:
; FIXME
rts

View File

@ -0,0 +1,8 @@
.include "ieee754.inc"
.export ftoseqeax
ftoseqeax:
; FIXME
lda #0
tax
rts

View File

@ -0,0 +1,8 @@
.include "ieee754.inc"
.export ftosgeeax
ftosgeeax:
; FIXME
lda #0
tax
rts

View File

@ -0,0 +1,8 @@
.include "ieee754.inc"
.export ftosgteax
ftosgteax:
; FIXME
lda #0
tax
rts

View File

@ -0,0 +1,8 @@
.include "ieee754.inc"
.export ftosleeax
ftosleeax:
; FIXME
lda #0
tax
rts

View File

@ -0,0 +1,8 @@
.include "ieee754.inc"
.export ftoslteax
ftoslteax:
; FIXME
lda #0
tax
rts

View File

@ -0,0 +1,12 @@
.include "ieee754.inc"
.importzp sp, sreg, tmp1
.import addysp1
.import addysp
.import popax
.export ftosmuleax
ftosmuleax:
; FIXME
rts

View File

@ -0,0 +1,8 @@
.include "ieee754.inc"
.export ftosneeax
ftosneeax:
; FIXME
lda #0
tax
rts

View File

@ -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

View File

@ -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

View File

@ -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_ */

46
test/float/include/math.h Normal file
View File

@ -0,0 +1,46 @@
#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 */
/* beware, this is not standard */
#ifndef M_PI
#define M_PI 3.14159265358979323846f
#endif
/* FIXME */
float __fastcall__ _fatan2(float x, float y);
float ffloor(float x);
#endif /* _MATH_H_ */

25
test/float/quick.c Normal file
View File

@ -0,0 +1,25 @@
/*
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <_float.h>
#include <math.h>
unsigned char buf[32];*/
//unsigned char var_uchar;
// float fp2;
float fp1 = 42.0f;
float fp2 = 23;
float fp3 = 33.0;
int main(void)
{
// fp2 = (float)((unsigned char)19);
// var_uchar = (unsigned char)fp2;
// var_uchar = (unsigned char)192.3f;
// printf("fp2 0x%08lx %s (19.9) uchar:%u (19)\n", *((uint32_t*)&fp2), _ftostr(buf, fp2), (int)var_uchar);
}

196
test/float/readme.md Normal file
View File

@ -0,0 +1,196 @@
## cc65 floating point support
WARNING: the following is just a brain dump after a long weekend of hacking. it
sure needs cleanup etc :)
The current 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. Dont bother. This is for
people who want to help pushing the floating point support further.
- build the compiler/toolchain/libs from this fptest branch
- now you can build the programs in this directory
right now you'll have to use the cbm kernal wrapper library, as that is pretty
much the only one that somewhat works :)
feel free to work on "real" ieee754 functions (see below)
## The Compiler
- for the time being i will handle and test only expressions where left and
right side are both floats. that will enable me to fix and test a fair portion
of what has to be done, before i will have to dive into the ugly areas of type
conversion and casting.
NOT WORKING YET:
- float values as in "12.34f" work, but "12.34" does not - should it?
- compare, float const vs float const
- substraction, float variable - float constant (compile error)
- multiplication operator, float const * float const (compile error)
- division operator, float const / float const
- ternary operator (compile error)
- addition, float constant + float variable (compiles but does not work)
(and probably more :))
TODO (much later):
- add a cmdline option to the compiler to switch the float binary type (754, cbm,
woz, ...). -> remember the code in fp.c/h
### Files & Functions
#### codegen.c
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
#### datatype.c
ArithmeticConvert
#### expr.c
LimitExprValue
parseadd
parsesub
#### initdata.c
DefineData Output a data definition for the given expression
#### loadexpr.c
LoadExpr
#### locals.c
ParseAutoDecl
#### assignment.c
OpAssignArithmetic Parse an "=" (if 'Gen' is 0) or "op=" operation for arithmetic lhs
#### fp.c
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
--------------------------------------------------------------------------------
## The Library
cbmkernal:
this is a wrapper to the CBM kernal functions
- this one is fairly complete and should be OK to use when fixing/adding basic
things in the compiler
- the only missing functions are ftosrsubeax, fnegeax - which can be easily
added once testcode is found that actually triggers it :)
ieee754:
this should become a freestanding ieee754 library
- basically everything missing except addition/substraction
- compare functions are missing
- mul, div functions are missing
- type conversion functions are missing
woz:
historical float routines by woz :) unfortunately not ieee754
- (optionally) converting from/to ieee754 format is missing (compile time option)
- compare functions are missing
- type conversion functions are missing
--------------------------------------------------------------------------------
### runtime functions
these must be available in the runtime library
func description cbmfp wozfp 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
### extra functions
optional utility functions.
func description cbmfp wozfp 754
char *_ftostr(char *d, float s) * ? ? for printf family
float _strtof(char *d) * - - for scanf family
### math.h functions
these are optional, required for standard libm
func description cbmfp wozfp 754
/* C99 */
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); * - -
--------------------------------------------------------------------------------
https://www.geeksforgeeks.org/ieee-standard-754-floating-point-numbers/
https://www.h-schmidt.net/FloatConverter/IEEE754.html

97
test/float/woz/_ftostr.c Normal file
View File

@ -0,0 +1,97 @@
#include <stdlib.h>
#include <stdio.h>
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;
}

7
test/float/woz/afloat.s Normal file
View File

@ -0,0 +1,7 @@
.include "wozfp.inc"
.export afloat
afloat:
; FIXME
rts

7
test/float/woz/aufloat.s Normal file
View File

@ -0,0 +1,7 @@
.include "wozfp.inc"
.export aufloat
aufloat:
; FIXME
rts

7
test/float/woz/axfloat.s Normal file
View File

@ -0,0 +1,7 @@
.include "wozfp.inc"
.export axfloat
axfloat:
; FIXME
rts

View File

@ -0,0 +1,7 @@
.include "wozfp.inc"
.export axufloat
axufloat:
; FIXME
rts

View File

@ -0,0 +1,7 @@
.include "wozfp.inc"
.export eaxfloat
eaxfloat:
; FIXME
rts

View File

@ -0,0 +1,7 @@
.include "wozfp.inc"
.export eaxufloat
eaxufloat:
; FIXME
rts

View File

@ -0,0 +1,7 @@
.include "wozfp.inc"
.export fbnegeax
fbnegeax:
; FIXME
rts

8
test/float/woz/feaxint.s Normal file
View File

@ -0,0 +1,8 @@
.include "wozfp.inc"
; float -> 16bit int
.export feaxint
feaxint:
; FIXME
rts

View File

@ -0,0 +1,8 @@
.include "wozfp.inc"
; float -> 32bit long
.export feaxlong
feaxlong:
; FIXME
rts

View File

@ -0,0 +1,9 @@
.include "wozfp.inc"
.export ftosaddeax
ftosaddeax:
; FIXME
lda #0
tax
rts

View File

@ -0,0 +1,9 @@
.include "wozfp.inc"
.export ftosdiveax
ftosdiveax:
; FIXME
lda #0
tax
rts

View File

@ -0,0 +1,8 @@
.include "wozfp.inc"
.export ftoseqeax
ftoseqeax:
; FIXME
lda #0
tax
rts

View File

@ -0,0 +1,8 @@
.include "wozfp.inc"
.export ftosgeeax
ftosgeeax:
; FIXME
lda #0
tax
rts

View File

@ -0,0 +1,8 @@
.include "wozfp.inc"
.export ftosgteax
ftosgteax:
; FIXME
lda #0
tax
rts

View File

@ -0,0 +1,8 @@
.include "wozfp.inc"
.export ftosleeax
ftosleeax:
; FIXME
lda #0
tax
rts

View File

@ -0,0 +1,8 @@
.include "wozfp.inc"
.export ftoslteax
ftoslteax:
; FIXME
lda #0
tax
rts

View File

@ -0,0 +1,9 @@
.include "wozfp.inc"
.export ftosmuleax
ftosmuleax:
; FIXME
lda #0
tax
rts

View File

@ -0,0 +1,8 @@
.include "wozfp.inc"
.export ftosneeax
ftosneeax:
; FIXME
lda #0
tax
rts

View File

@ -0,0 +1,8 @@
.include "wozfp.inc"
.export ftossubeax
ftossubeax:
; FIXME
lda #0
tax
rts

16
test/float/woz/wozfp.inc Normal file
View File

@ -0,0 +1,16 @@
; .org $40 ; SET BASE PAGE ADRESSES
; SIGN = *
SIGN = $40
X2 = SIGN+1 ; EXPONENT 2
M2 = X2+1 ; MANTISSA 2
X1 = M2+3 ; EXPONENT 1
M1 = X1+1 ; MANTISSA 1
E = M1+3 ; SCRATCH
ZZ = E+4
T = ZZ+4
SEXP = T+4
INT = SEXP+4
;

456
test/float/woz/wozfp.s Normal file
View File

@ -0,0 +1,456 @@
; JULY 5, 1976
; BASIC FLOATING POINT ROUTINES
; FOR 6502 MICROPROCESSOR
; BY R. RANKIN AND S. WOZNIAK
;
; CONSISTING OF:
; NATURAL LOG
; COMMON LOG
; EXPONENTIAL (E**X)
; FLOAT FIX
; FADD FSUB
; FMUL FDIV
;
;
; FLOATING POINT REPRESENTATION (4-BYTES)
; EXPONENT BYTE 1
; MANTISSA BYTES 2-4
;
; MANTISSA: TWO'S COMPLEMENT REPRESENTATION WITH SIGN IN
; MSB OF HIGH-ORDER BYTE. MANTISSA IS NORMALIZED WITH AN
; ASSUMED DECIMAL POINT BETWEEN BITS 5 AND 6 OF THE HIGH-ORDER
; BYTE. THUS THE MANTISSA IS IN THE RANGE 1. TO 2. EXCEPT
; WHEN THE NUMBER IS LESS THAN 2**(-128).
;
; EXPONENT: THE EXPONENT REPRESENTS POWERS OF TWO. THE
; REPRESENTATION IS 2'S COMPLEMENT EXCEPT THAT THE SIGN
; BIT (BIT 7) IS COMPLEMENTED. THIS ALLOWS DIRECT COMPARISON
; OF EXPONENTS FOR SIZE SINCE THEY ARE STORED IN INCREASING
; NUMERICAL SEQUENCE RANGING FROM $00 (-128) TO $FF (+127)
; ($ MEANS NUMBER IS HEXADECIMAL).
;
; REPRESENTATION OF DECIMAL NUMBERS: THE PRESENT FLOATING
; POINT REPRESENTATION ALLOWS DECIMAL NUMBERS IN THE APPROXIMATE
; RANGE OF 10**(-38) THROUGH 10**(38) WITH 6 TO 7 SIGNIFICANT
; DIGITS.
;
;
.include "wozfp.inc"
; .org $1D00 ; STARTING LOCATION FOR LOG
; .export WOZFP
;WOZFP:
;
;
; NATURAL LOG OF MANT/EXP1 WITH RESULT IN MANT/EXP1
;
LOG: LDA M1
BEQ ERROR
BPL CONT ; IF ARG>0 OK
ERROR: BRK ; ERROR ARG<=0
;
CONT: JSR SWAP ; MOVE ARG TO EXP/MANT2
LDX #0 ; LOAD X FOR HIGH BYTE OF EXPONENT
LDA X2 ; HOLD EXPONENT
LDY #$80
STY X2 ; SET EXPONENT 2 TO 0 ($80)
EOR #$80 ; COMPLEMENT SIGN BIT OF ORIGINAL EXPONENT
STA M1+1 ; SET EXPONENT INTO MANTISSA 1 FOR FLOAT
BPL *+3 ; IS EXPONENT NEGATIVE
DEX ; YES, SET X TO $FF
STX M1 ; SET UPPER BYTE OF EXPONENT
JSR FLOAT ; CONVERT TO FLOATING POINT
LDX #3 ; 4 BYTE TRANSFERS
SEXP1: LDA X2,X
STA ZZ,X ; COPY MANTISSA TO Z
LDA X1,X
STA SEXP,X ; SAVE EXPONENT IN SEXP
LDA R22,X ; LOAD EXP/MANT1 WITH SQRT(2)
STA X1,X
DEX
BPL SEXP1
JSR FSUB ; Z-SQRT(2)
LDX #3 ; 4 BYTE TRANSFER
SAVET: LDA X1,X ; SAVE EXP/MANT1 AS T
STA T,X
LDA ZZ,X ; LOAD EXP/MANT1 WITH Z
STA X1,X
LDA R22,X ; LOAD EXP/MANT2 WITH SQRT(2)
STA X2,X
DEX
BPL SAVET
JSR FADD ; Z+SQRT(2)
LDX #3 ; 4 BYTE TRANSFER
TM2: LDA T,X
STA X2,X ; LOAD T INTO EXP/MANT2
DEX
BPL TM2
JSR FDIV ; T=(Z-SQRT(2))/(Z+SQRT(2))
LDX #3 ; 4 BYTE TRANSFER
MIT: LDA X1,X
STA T,X ; COPY EXP/MANT1 TO T AND
STA X2,X ; LOAD EXP/MANT2 WITH T
DEX
BPL MIT
JSR FMUL ; T*T
JSR SWAP ; MOVE T*T TO EXP/MANT2
LDX #3 ; 4 BYTE TRANSFER
MIC: LDA C,X
STA X1,X ; LOAD EXP/MANT1 WITH C
DEX
BPL MIC
JSR FSUB ; T*T-C
LDX #3 ; 4 BYTE TRANSFER
M2MB: LDA MB,X
STA X2,X ; LOAD EXP/MANT2 WITH MB
DEX
BPL M2MB
JSR FDIV ; MB/(T*T-C)
LDX #3
M2A1: LDA A1,X
STA X2,X ; LOAD EXP/MANT2 WITH A1
DEX
BPL M2A1
JSR FADD ; MB/(T*T-C)+A1
LDX #3 ; 4 BYTE TRANSFER
M2T: LDA T,X
STA X2,X ; LOAD EXP/MANT2 WITH T
DEX
BPL M2T
JSR FMUL ; (MB/(T*T-C)+A1)*T
LDX #3 ; 4 BYTE TRANSFER
M2MHL: LDA MHLF,X
STA X2,X ; LOAD EXP/MANT2 WITH MHLF (.5)
DEX
BPL M2MHL
JSR FADD ; +.5
LDX #3 ; 4 BYTE TRANSFER
LDEXP: LDA SEXP,X
STA X2,X ; LOAD EXP/MANT2 WITH ORIGINAL EXPONENT
DEX
BPL LDEXP
JSR FADD ; +EXPN
LDX #3 ; 4 BYTE TRANSFER
MLE2: LDA LE2,X
STA X2,X ; LOAD EXP/MANT2 WITH LN(2)
DEX
BPL MLE2
JSR FMUL ; *LN(2)
RTS ; RETURN RESULT IN MANT/EXP1
;
; COMMON LOG OF MANT/EXP1 RESULT IN MANT/EXP1
;
LOG10: JSR LOG ; COMPUTE NATURAL LOG
LDX #3
L10: LDA LN10,X
STA X2,X ; LOAD EXP/MANT2 WITH 1/LN(10)
DEX
BPL L10
JSR FMUL ; LOG10(X)=LN(X)/LN(10)
RTS
;
LN10: .byte $7E, $6F, $2D, $ED ; 0.4342945
R22: .byte $80, $5A, $82, $7A ; 1.4142136 SQRT(2)
LE2: .byte $7F, $58, $B9, $0C ; 0.69314718 LOG BASE E OF 2
A1: .byte $80, $52, $B0, 40 ; 1.2920074
MB: .byte $81, $AB, $86, $49 ; -2.6398577
C: .byte $80, $6A, $08, $66 ; 1.6567626
MHLF: .byte $7F, $40, $00, $00 ; 0.5
;
; .res $1e00-*
; .org $1E00 ; STARTING LOCATION FOR EXP
;
; EXP OF MANT/EXP1 RESULT IN MANT/EXP1
;
EXP: LDX #3 ; 4 BYTE TRANSFER
LDA L2E,X
STA X2,X ; LOAD EXP/MANT2 WITH LOG BASE 2 OF E
DEX
BPL EXP+2
JSR FMUL ; LOG2(3)*X
LDX #3 ; 4 BYTE TRANSFER
FSA: LDA X1,X
STA ZZ,X ; STORE EXP/MANT1 IN Z
DEX
BPL FSA ; SAVE Z=LN(2)*X
JSR FIX ; CONVERT CONTENTS OF EXP/MANT1 TO AN INTEGER
LDA M1+1
STA INT ; SAVE RESULT AS INT
SEC ; SET CARRY FOR SUBTRACTION
SBC #124 ; INT-124
LDA M1
SBC #0
BPL OVFLW ; OVERFLOW INT>=124
CLC ; CLEAR CARRY FOR ADD
LDA M1+1
ADC #120 ; ADD 120 TO INT
LDA M1
ADC #0
BPL CONTIN ; IF RESULT POSITIVE CONTINUE
LDA #0 ; INT<-120 SET RESULT TO ZERO AND RETURN
LDX #3 ; 4 BYTE MOVE
ZERO: STA X1,X ; SET EXP/MANT1 TO ZERO
DEX
BPL ZERO
RTS ; RETURN
;
OVFLW: BRK ; OVERFLOW
;
CONTIN: JSR FLOAT ; FLOAT INT
LDX #3
ENTD: LDA ZZ,X
STA X2,X ; LOAD EXP/MANT2 WITH Z
DEX
BPL ENTD
JSR FSUB ; Z*Z-FLOAT(INT)
LDX #3 ; 4 BYTE MOVE
ZSAV: LDA X1,X
STA ZZ,X ; SAVE EXP/MANT1 IN Z
STA X2,X ; COPY EXP/MANT1 TO EXP/MANT2
DEX
BPL ZSAV
JSR FMUL ; Z*Z
LDX #3 ; 4 BYTE MOVE
LA2: LDA A2,X
STA X2,X ; LOAD EXP/MANT2 WITH A2
LDA X1,X
STA SEXP,X ; SAVE EXP/MANT1 AS SEXP
DEX
BPL LA2
JSR FADD ; Z*Z+A2
LDX #3 ; 4 BYTE MOVE
LB2: LDA B2,X
STA X2,X ; LOAD EXP/MANT2 WITH B2
DEX
BPL LB2
JSR FDIV ; T=B/(Z*Z+A2)
LDX #3 ; 4 BYTE MOVE
DLOAD: LDA X1,X
STA T,X ; SAVE EXP/MANT1 AS T
LDA C2,X
STA X1,X ; LOAD EXP/MANT1 WITH C2
LDA SEXP,X
STA X2,X ; LOAD EXP/MANT2 WITH SEXP
DEX
BPL DLOAD
JSR FMUL ; Z*Z*C2
JSR SWAP ; MOVE EXP/MANT1 TO EXP/MANT2
LDX #3 ; 4 BYTE TRANSFER
LTMP: LDA T,X
STA X1,X ; LOAD EXP/MANT1 WITH T
DEX
BPL LTMP
JSR FSUB ; C2*Z*Z-B2/(Z*Z+A2)
LDX #3 ; 4 BYTE TRANSFER
LDD: LDA D,X
STA X2,X ; LOAD EXP/MANT2 WITH D
DEX
BPL LDD
JSR FADD ; D+C2*Z*Z-B2/(Z*Z+A2)
JSR SWAP ; MOVE EXP/MANT1 TO EXP/MANT2
LDX #3 ; 4 BYTE TRANSFER
LFA: LDA ZZ,X
STA X1,X ; LOAD EXP/MANT1 WITH Z
DEX
BPL LFA
JSR FSUB ; -Z+D+C2*Z*Z-B2/(Z*Z+A2)
LDX #3 ; 4 BYTE TRANSFER
LF3: LDA ZZ,X
STA X2,X ; LOAD EXP/MANT2 WITH Z
DEX
BPL LF3
JSR FDIV ; Z/(**** )
LDX #3 ; 4 BYTE TRANSFER
LD12: LDA MHLF,X
STA X2,X ; LOAD EXP/MANT2 WITH .5
DEX
BPL LD12
JSR FADD ; +Z/(***)+.5
SEC ; ADD INT TO EXPONENT WITH CARRY SET
LDA INT ; TO MULTIPLY BY
ADC X1 ; 2**(INT+1)
STA X1 ; RETURN RESULT TO EXPONENT
RTS ; RETURN ANS=(.5+Z/(-Z+D+C2*Z*Z-B2/(Z*Z+A2))*2**(INT+1)
L2E: .byte $80, $5C, $55, $1E ; 1.4426950409 LOG BASE 2 OF E
A2: .byte $86, $57, $6A, $E1 ; 87.417497202
B2: .byte $89, $4D, $3F, $1D ; 617.9722695
C2: .byte $7B, $46, $FA, $70 ; .03465735903
D: .byte $83, $4F, $A3, $03 ; 9.9545957821
;
;
; BASIC FLOATING POINT ROUTINES
;
; .res $1F00-*
; .org $1F00 ; START OF BASIC FLOATING POINT ROUTINES
ADD: CLC ; CLEAR CARRY
LDX #$02 ; INDEX FOR 3-BYTE ADD
ADD1: LDA M1,X
ADC M2,X ; ADD A BYTE OF MANT2 TO MANT1
STA M1,X
DEX ; ADVANCE INDEX TO NEXT MORE SIGNIF.BYTE
BPL ADD1 ; LOOP UNTIL DONE.
RTS ; RETURN
MD1: ASL SIGN ; CLEAR LSB OF SIGN
JSR ABSWAP ; ABS VAL OF MANT1, THEN SWAP MANT2
ABSWAP: BIT M1 ; MANT1 NEG?
BPL ABSWP1 ; NO,SWAP WITH MANT2 AND RETURN
JSR FCOMPL ; YES, COMPLEMENT IT.
INC SIGN ; INCR SIGN, COMPLEMENTING LSB
ABSWP1: SEC ; SET CARRY FOR RETURN TO MUL/DIV
;
; SWAP EXP/MANT1 WITH EXP/MANT2
;
SWAP: LDX #$04 ; INDEX FOR 4-BYTE SWAP.
SWAP1: STY E-1,X
LDA X1-1,X ; SWAP A BYTE OF EXP/MANT1 WITH
LDY X2-1,X ; EXP/MANT2 AND LEAVEA COPY OF
STY X1-1,X ; MANT1 IN E(3BYTES). E+3 USED.
STA X2-1,X
DEX ; ADVANCE INDEX TO NEXT BYTE
BNE SWAP1 ; LOOP UNTIL DONE.
RTS
;
;
;
; CONVERT 16 BIT INTEGER IN M1(HIGH) AND M1+1(LOW) TO F.P.
; RESULT IN EXP/MANT1. EXP/MANT2 UNEFFECTED
;
;
FLOAT: LDA #$8E
STA X1 ; SET EXPN TO 14 DEC
LDA #0 ; CLEAR LOW ORDER BYTE
STA M1+2
BEQ NORML ; NORMALIZE RESULT
NORM1: DEC X1 ; DECREMENT EXP1
ASL M1+2
ROL M1+1 ; SHIFT MANT1 (3 BYTES) LEFT
ROL M1
NORML: LDA M1 ; HIGH ORDER MANT1 BYTE
ASL ; UPPER TWO BITS UNEQUAL?
EOR M1
BMI RTS1 ; YES,RETURN WITH MANT1 NORMALIZED
LDA X1 ; EXP1 ZERO?
BNE NORM1 ; NO, CONTINUE NORMALIZING
RTS1: RTS ; RETURN
;
;
; EXP/MANT2-EXP/MANT1 RESULT IN EXP/MANT1
;
FSUB: JSR FCOMPL ; CMPL MANT1 CLEARS CARRY UNLESS ZERO
SWPALG: JSR ALGNSW ; RIGHT SHIFT MANT1 OR SWAP WITH MANT2 ON CARRY
;
; ADD EXP/MANT1 AND EXP/MANT2 RESULT IN EXP/MANT1
;
FADD: LDA X2
CMP X1 ; COMPARE EXP1 WITH EXP2
BNE SWPALG ; IF UNEQUAL, SWAP ADDENDS OR ALIGN MANTISSAS
JSR ADD ; ADD ALIGNED MANTISSAS
ADDEND: BVC NORML ; NO OVERFLOW, NORMALIZE RESULTS
BVS RTLOG ; OV: SHIFT MANT1 RIGHT. NOTE CARRY IS CORRECT SIGN
ALGNSW: BCC SWAP ; SWAP IF CARRY CLEAR, ELSE SHIFT RIGHT ARITH.
RTAR: LDA M1 ; SIGN OF MANT1 INTO CARRY FOR
ASL ; RIGHT ARITH SHIFT
RTLOG: INC X1 ; INCR EXP1 TO COMPENSATE FOR RT SHIFT
BEQ OVFL ; EXP1 OUT OF RANGE.
RTLOG1: LDX #$FA ; INDEX FOR 6 BYTE RIGHT SHIFT
ROR1: LDA #$80
BCS ROR2
ASL
ROR2: LSR E+3,X ; SIMULATE ROR E+3,X
ORA E+3,X
STA E+3,X
INX ; NEXT BYTE OF SHIFT
BNE ROR1 ; LOOP UNTIL DONE
RTS ; RETURN
;
;
; EXP/MANT1 X EXP/MANT2 RESULT IN EXP/MANT1
;
FMUL: JSR MD1 ; ABS. VAL OF MANT1, MANT2
ADC X1 ; ADD EXP1 TO EXP2 FOR PRODUCT EXPONENT
JSR MD2 ; CHECK PRODUCT EXP AND PREPARE FOR MUL
CLC ; CLEAR CARRY
MUL1: JSR RTLOG1 ; MANT1 AND E RIGHT.(PRODUCT AND MPLIER)
BCC MUL2 ; IF CARRY CLEAR, SKIP PARTIAL PRODUCT
JSR ADD ; ADD MULTIPLICAN TO PRODUCT
MUL2: DEY ; NEXT MUL ITERATION
BPL MUL1 ; LOOP UNTIL DONE
MDEND: LSR SIGN ; TEST SIGN (EVEN/ODD)
NORMX: BCC NORML ; IF EXEN, NORMALIZE PRODUCT, ELSE COMPLEMENT
FCOMPL: SEC ; SET CARRY FOR SUBTRACT
LDX #$03 ; INDEX FOR 3 BYTE SUBTRACTION
COMPL1: LDA #$00 ; CLEAR A
SBC X1,X ; SUBTRACT BYTE OF EXP1
STA X1,X ; RESTORE IT
DEX ; NEXT MORE SIGNIFICANT BYTE
BNE COMPL1 ; LOOP UNTIL DONE
BEQ ADDEND ; NORMALIZE (OR SHIFT RIGHT IF OVERFLOW)
;
;
; EXP/MANT2 / EXP/MANT1 RESULT IN EXP/MANT1
;
FDIV: JSR MD1 ; TAKE ABS VAL OF MANT1, MANT2
SBC X1 ; SUBTRACT EXP1 FROM EXP2
JSR MD2 ; SAVE AS QUOTIENT EXP
DIV1: SEC ; SET CARRY FOR SUBTRACT
LDX #$02 ; INDEX FOR 3-BYTE INSTRUCTION
DIV2: LDA M2,X
SBC E,X ; SUBTRACT A BYTE OF E FROM MANT2
PHA ; SAVE ON STACK
DEX ; NEXT MORE SIGNIF BYTE
BPL DIV2 ; LOOP UNTIL DONE
LDX #$FD ; INDEX FOR 3-BYTE CONDITIONAL MOVE
DIV3: PLA ; PULL A BYTE OF DIFFERENCE OFF STACK
BCC DIV4 ; IF MANT2<E THEN DONT RESTORE MANT2
STA M2+3,X
DIV4: INX ; NEXT LESS SIGNIF BYTE
BNE DIV3 ; LOOP UNTIL DONE
ROL M1+2
ROL M1+1 ; ROLL QUOTIENT LEFT, CARRY INTO LSB
ROL M1
ASL M2+2
ROL M2+1 ; SHIFT DIVIDEND LEFT
ROL M2
BCS OVFL ; OVERFLOW IS DUE TO UNNORMALIZED DIVISOR
DEY ; NEXT DIVIDE ITERATION
BNE DIV1 ; LOOP UNTIL DONE 23 ITERATIONS
BEQ MDEND ; NORMALIZE QUOTIENT AND CORRECT SIGN
MD2: STX M1+2
STX M1+1 ; CLR MANT1 (3 BYTES) FOR MUL/DIV
STX M1
BCS OVCHK ; IF EXP CALC SET CARRY, CHECK FOR OVFL
BMI MD3 ; IF NEG NO UNDERFLOW
PLA ; POP ONE
PLA ; RETURN LEVEL
BCC NORMX ; CLEAR X1 AND RETURN
MD3: EOR #$80 ; COMPLEMENT SIGN BIT OF EXP
STA X1 ; STORE IT
LDY #$17 ; COUNT FOR 24 MUL OR 23 DIV ITERATIONS
RTS ; RETURN
OVCHK: BPL MD3 ; IF POS EXP THEN NO OVERFLOW
OVFL: BRK
;
;
; CONVERT EXP/MANT1 TO INTEGER IN M1 (HIGH) AND M1+1(LOW)
; EXP/MANT2 UNEFFECTED
;
JSR RTAR ; SHIFT MANT1 RT AND INCREMENT EXPNT
FIX: LDA X1 ; CHECK EXPONENT
CMP #$8E ; IS EXPONENT 14?
BNE FIX-3 ; NO, SHIFT
RTRN: RTS ; RETURN
; .include "util.s"