Add overflow and underflow checking for floats

This commit is contained in:
drmortalwombat 2021-11-24 20:01:08 +01:00
parent 84648fbd88
commit 93174c8e68
6 changed files with 283 additions and 104 deletions

View File

@ -38,8 +38,7 @@ There are still several open areas, but most targets have been reached. The cur
### Runtime ### Runtime
* No INF and NaN support for floats * No NaN support for floats
* Underflow in float multiply and divide not checked
* Basic zero page variables not restored on stop/restore * Basic zero page variables not restored on stop/restore
### Optimizing ### Optimizing

View File

@ -2474,6 +2474,22 @@ W1:
__asm faddsub __asm faddsub
{ {
lda #$ff
cmp tmp + 4
beq INF
cmp tmp + 5
bne nINF
INF:
lda accu + 3
ora #$7f
sta accu + 3
lda #$80
sta accu + 2
lda #$00
sta accu + 0
sta accu + 1
rts
nINF:
sec sec
lda tmp + 4 lda tmp + 4
sbc tmp + 5 sbc tmp + 5
@ -2542,6 +2558,8 @@ fas_aligned:
inc tmp + 4 inc tmp + 4
fas_done: fas_done:
lda tmp + 4 lda tmp + 4
cmp #$ff
beq INF
lsr lsr
ora accu + 3 ora accu + 3
sta accu + 3 sta accu + 3
@ -2677,6 +2695,17 @@ W1:
sta accu + 3 sta accu + 3
rts rts
W2: W2:
lda accu + 3
eor tmp + 3
and #$80
sta accu + 3
lda #$ff
cmp tmp + 4
beq INF
cmp tmp + 5
beq INF
lda #0 lda #0
sta tmp + 6 sta tmp + 6
sta tmp + 7 sta tmp + 7
@ -2707,16 +2736,28 @@ W5:
W3: and #$7f W3: and #$7f
sta tmp + 8 sta tmp + 8
lda accu + 3
eor tmp + 3
and #$80
sta accu + 3
lda tmp + 4 lda tmp + 4
sbc #$7e
clc
adc tmp + 5 adc tmp + 5
bcc W7
sbc #$7f
bcs INF
cmp #$ff
bne W8
INF:
lda accu + 3
ora #$7f
sta accu + 3
lda #$80
sta accu + 2
lda #$00
sta accu + 0
sta accu + 1
rts
W7:
sbc #$7e
bcc ZERO
W8:
lsr lsr
ora accu + 3 ora accu + 3
sta accu + 3 sta accu + 3
@ -2729,6 +2770,13 @@ W3: and #$7f
lda tmp + 6 lda tmp + 6
sta accu sta accu
rts rts
ZERO:
lda #0
sta accu
sta accu + 1
sta accu + 2
sta accu + 3
rts
} }
__asm inp_binop_mul_f32 __asm inp_binop_mul_f32
@ -2754,6 +2802,12 @@ W1:
and #$80 and #$80
sta accu + 3 sta accu + 3
lda tmp + 5
beq INF
lda tmp + 4
cmp #$ff
beq INF
lda #0 lda #0
sta tmp + 6 sta tmp + 6
sta tmp + 7 sta tmp + 7
@ -2804,12 +2858,29 @@ W4:
and #$7f and #$7f
sta tmp + 8 sta tmp + 8
lda tmp + 5 lda tmp + 4
eor #$7f sbc tmp + 5
adc tmp + 4 bcc W5
sec
sbc #1
clc
adc #$7f
bcs INF
cmp #$ff
bne W6
INF:
lda accu + 3
ora #$7f
sta accu + 3
lda #$80
sta accu + 2
lda #$00
sta accu + 1
sta accu + 0
rts
W5:
adc #$7f
bcc ZERO
W6:
lsr lsr
ora accu + 3 ora accu + 3
sta accu + 3 sta accu + 3
@ -2822,6 +2893,16 @@ W4:
lda tmp + 6 lda tmp + 6
sta accu sta accu
rts rts
ZERO:
lda #$00
sta accu + 3
sta accu + 2
sta accu + 1
sta accu + 0
rts
} }
#pragma bytecode(BC_BINOP_MUL_F32, inp_binop_mul_f32) #pragma bytecode(BC_BINOP_MUL_F32, inp_binop_mul_f32)

View File

@ -199,3 +199,37 @@ float sqrt(float f)
} }
bool isinf(float f)
{
__asm
{
lda #$00
sta accu + 1
asl f + 2
lda f + 3
rol
eor #$ff
beq W1
lda #$01
W1:
eor #$01
sta accu
}
}
bool isfinite(float f)
{
__asm
{
lda #$00
sta accu + 1
asl f + 2
lda f + 3
rol
eor #$ff
beq W1
lda #$01
W1:
sta accu
}
}

View File

@ -23,6 +23,9 @@ float log10(float f);
float pow(float p, float q); float pow(float p, float q);
float sqrt(float f); float sqrt(float f);
bool isinf(float f);
bool isfinite(float f);
#pragma intrinsic(fabs) #pragma intrinsic(fabs)
#pragma intrinsic(floor) #pragma intrinsic(floor)
#pragma intrinsic(ceil) #pragma intrinsic(ceil)

View File

@ -259,105 +259,114 @@ int nformf(const sinfo * si, char * str, float f, char type)
else if (si->sign) else if (si->sign)
sp[d++] = '+'; sp[d++] = '+';
int exp = 0; if (isinf(f))
char fdigits = si->precision != 255 ? si->precision : 6;
if (f != 0.0)
{ {
while (f >= 1000.0) sp[d++] = 'I';
{ sp[d++] = 'N';
f /= 1000; sp[d++] = 'F';
exp += 3;
}
while (f < 1.0)
{
f *= 1000;
exp -= 3;
}
while (f >= 10.0)
{
f /= 10;
exp ++;
}
}
char digits = fdigits + 1;
bool fexp = type == 'e';
if (type == 'g')
{
if (exp > 3 || exp < 0)
fexp = true;
}
if (!fexp)
{
while (exp < 0)
{
f /= 10.0;
exp++;
}
digits = fdigits + exp + 1;
float r = 0.5;
for(char i=1; i<digits; i++)
r /= 10.0;
f += r;
if (f >= 10.0)
{
f /= 10.0;
fdigits--;
}
} }
else else
{ {
float r = 0.5; int exp = 0;
for(char i=0; i<fdigits; i++)
r /= 10.0; char fdigits = si->precision != 255 ? si->precision : 6;
f += r;
if (f >= 10.0) if (f != 0.0)
{ {
f /= 10.0; while (f >= 1000.0)
exp ++; {
f /= 1000;
exp += 3;
}
while (f < 1.0)
{
f *= 1000;
exp -= 3;
}
while (f >= 10.0)
{
f /= 10;
exp ++;
}
} }
}
char digits = fdigits + 1;
bool fexp = type == 'e';
char pdigits = digits - fdigits; if (type == 'g')
if (digits > 20)
digits = 20;
if (pdigits == 0)
sp[d++] = '0';
for(char i=0; i<digits; i++)
{
if (i == pdigits)
sp[d++] = '.';
int c = (int)f;
f -= (float)c;
f *= 10.0;
sp[d++] = c + '0';
}
if (fexp)
{
sp[d++] = 'E';
if (exp < 0)
{ {
sp[d++] = '-'; if (exp > 3 || exp < 0)
exp = -exp; fexp = true;
}
if (!fexp)
{
while (exp < 0)
{
f /= 10.0;
exp++;
}
digits = fdigits + exp + 1;
float r = 0.5;
for(char i=1; i<digits; i++)
r /= 10.0;
f += r;
if (f >= 10.0)
{
f /= 10.0;
fdigits--;
}
} }
else else
sp[d++] = '+'; {
float r = 0.5;
for(char i=0; i<fdigits; i++)
r /= 10.0;
f += r;
if (f >= 10.0)
{
f /= 10.0;
exp ++;
}
}
sp[d++] = exp / 10 + '0';
sp[d++] = exp % 10 + '0'; char pdigits = digits - fdigits;
if (digits > 20)
digits = 20;
if (pdigits == 0)
sp[d++] = '0';
for(char i=0; i<digits; i++)
{
if (i == pdigits)
sp[d++] = '.';
int c = (int)f;
f -= (float)c;
f *= 10.0;
sp[d++] = c + '0';
}
if (fexp)
{
sp[d++] = 'E';
if (exp < 0)
{
sp[d++] = '-';
exp = -exp;
}
else
sp[d++] = '+';
sp[d++] = exp / 10 + '0';
sp[d++] = exp % 10 + '0';
}
} }
if (d < si->width) if (d < si->width)

View File

@ -707,6 +707,59 @@ Expression* Parser::ParseInitExpression(Declaration* dtype)
nexp->mDecValue = ndec; nexp->mDecValue = ndec;
exp = nexp; exp = nexp;
} }
else if (exp->mType == EX_CONSTANT && exp->mDecType != dtype)
{
Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTANT);
nexp->mDecType = dtype;
if (dtype->mType == DT_TYPE_INTEGER || dtype->mType == DT_TYPE_ENUM || dtype->mType == DT_TYPE_BOOL)
{
Declaration* ndec = new Declaration(exp->mDecValue->mLocation, DT_CONST_INTEGER);
ndec->mBase = dtype;
ndec->mSize = dtype->mSize;
if (exp->mDecValue->mType == DT_CONST_INTEGER)
ndec->mInteger = exp->mDecValue->mInteger;
else if (exp->mDecValue->mType == DT_CONST_FLOAT)
ndec->mInteger = int64(exp->mDecValue->mNumber);
else
mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Illegal integer constant initializer");
nexp->mDecValue = ndec;
}
else if (dtype->mType == DT_TYPE_FLOAT)
{
Declaration* ndec = new Declaration(exp->mDecValue->mLocation, DT_CONST_FLOAT);
ndec->mBase = dtype;
ndec->mSize = dtype->mSize;
if (exp->mDecValue->mType == DT_CONST_INTEGER)
ndec->mNumber = double(exp->mDecValue->mInteger);
else if (exp->mDecValue->mType == DT_CONST_FLOAT)
ndec->mNumber = exp->mDecValue->mNumber;
else
mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Illegal float constant initializer");
nexp->mDecValue = ndec;
}
else if (dtype->mType == DT_TYPE_POINTER)
{
if (exp->mDecValue->mType == DT_CONST_ADDRESS)
;
else
mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Illegal pointer constant initializer");
nexp = exp;
}
else
{
mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Illegal constant initializer");
nexp = exp;
}
exp = nexp;
}
} }
return exp; return exp;