Add overflow and underflow checking for floats
This commit is contained in:
parent
84648fbd88
commit
93174c8e68
|
@ -38,8 +38,7 @@ There are still several open areas, but most targets have been reached. The cur
|
|||
|
||||
### Runtime
|
||||
|
||||
* No INF and NaN support for floats
|
||||
* Underflow in float multiply and divide not checked
|
||||
* No NaN support for floats
|
||||
* Basic zero page variables not restored on stop/restore
|
||||
|
||||
### Optimizing
|
||||
|
|
107
include/crt.c
107
include/crt.c
|
@ -2474,6 +2474,22 @@ W1:
|
|||
|
||||
__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
|
||||
lda tmp + 4
|
||||
sbc tmp + 5
|
||||
|
@ -2542,6 +2558,8 @@ fas_aligned:
|
|||
inc tmp + 4
|
||||
fas_done:
|
||||
lda tmp + 4
|
||||
cmp #$ff
|
||||
beq INF
|
||||
lsr
|
||||
ora accu + 3
|
||||
sta accu + 3
|
||||
|
@ -2677,6 +2695,17 @@ W1:
|
|||
sta accu + 3
|
||||
rts
|
||||
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
|
||||
sta tmp + 6
|
||||
sta tmp + 7
|
||||
|
@ -2707,16 +2736,28 @@ W5:
|
|||
W3: and #$7f
|
||||
sta tmp + 8
|
||||
|
||||
lda accu + 3
|
||||
eor tmp + 3
|
||||
and #$80
|
||||
sta accu + 3
|
||||
|
||||
lda tmp + 4
|
||||
sbc #$7e
|
||||
|
||||
clc
|
||||
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
|
||||
ora accu + 3
|
||||
sta accu + 3
|
||||
|
@ -2729,6 +2770,13 @@ W3: and #$7f
|
|||
lda tmp + 6
|
||||
sta accu
|
||||
rts
|
||||
ZERO:
|
||||
lda #0
|
||||
sta accu
|
||||
sta accu + 1
|
||||
sta accu + 2
|
||||
sta accu + 3
|
||||
rts
|
||||
}
|
||||
|
||||
__asm inp_binop_mul_f32
|
||||
|
@ -2754,6 +2802,12 @@ W1:
|
|||
and #$80
|
||||
sta accu + 3
|
||||
|
||||
lda tmp + 5
|
||||
beq INF
|
||||
lda tmp + 4
|
||||
cmp #$ff
|
||||
beq INF
|
||||
|
||||
lda #0
|
||||
sta tmp + 6
|
||||
sta tmp + 7
|
||||
|
@ -2804,12 +2858,29 @@ W4:
|
|||
and #$7f
|
||||
sta tmp + 8
|
||||
|
||||
lda tmp + 5
|
||||
eor #$7f
|
||||
adc tmp + 4
|
||||
sec
|
||||
sbc #1
|
||||
lda tmp + 4
|
||||
sbc tmp + 5
|
||||
bcc W5
|
||||
|
||||
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
|
||||
ora accu + 3
|
||||
sta accu + 3
|
||||
|
@ -2822,6 +2893,16 @@ W4:
|
|||
lda tmp + 6
|
||||
sta accu
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@ float log10(float f);
|
|||
float pow(float p, float q);
|
||||
float sqrt(float f);
|
||||
|
||||
bool isinf(float f);
|
||||
bool isfinite(float f);
|
||||
|
||||
#pragma intrinsic(fabs)
|
||||
#pragma intrinsic(floor)
|
||||
#pragma intrinsic(ceil)
|
||||
|
|
183
include/stdio.c
183
include/stdio.c
|
@ -259,105 +259,114 @@ int nformf(const sinfo * si, char * str, float f, char type)
|
|||
else if (si->sign)
|
||||
sp[d++] = '+';
|
||||
|
||||
int exp = 0;
|
||||
|
||||
char fdigits = si->precision != 255 ? si->precision : 6;
|
||||
|
||||
if (f != 0.0)
|
||||
if (isinf(f))
|
||||
{
|
||||
while (f >= 1000.0)
|
||||
{
|
||||
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';
|
||||
|
||||
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--;
|
||||
}
|
||||
sp[d++] = 'I';
|
||||
sp[d++] = 'N';
|
||||
sp[d++] = 'F';
|
||||
}
|
||||
else
|
||||
{
|
||||
float r = 0.5;
|
||||
for(char i=0; i<fdigits; i++)
|
||||
r /= 10.0;
|
||||
f += r;
|
||||
if (f >= 10.0)
|
||||
int exp = 0;
|
||||
|
||||
char fdigits = si->precision != 255 ? si->precision : 6;
|
||||
|
||||
if (f != 0.0)
|
||||
{
|
||||
f /= 10.0;
|
||||
exp ++;
|
||||
while (f >= 1000.0)
|
||||
{
|
||||
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 (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)
|
||||
if (type == 'g')
|
||||
{
|
||||
sp[d++] = '-';
|
||||
exp = -exp;
|
||||
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
|
||||
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)
|
||||
|
|
|
@ -707,6 +707,59 @@ Expression* Parser::ParseInitExpression(Declaration* dtype)
|
|||
nexp->mDecValue = ndec;
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue