From 93174c8e68a0d51fb4bc550917e8e82282e04630 Mon Sep 17 00:00:00 2001 From: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com> Date: Wed, 24 Nov 2021 20:01:08 +0100 Subject: [PATCH] Add overflow and underflow checking for floats --- README.md | 3 +- include/crt.c | 109 ++++++++++++++++++++++---- include/math.c | 34 +++++++++ include/math.h | 3 + include/stdio.c | 185 ++++++++++++++++++++++++--------------------- oscar64/Parser.cpp | 53 +++++++++++++ 6 files changed, 283 insertions(+), 104 deletions(-) diff --git a/README.md b/README.md index 9724c41..b7718ca 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/include/crt.c b/include/crt.c index 6129056..3e4a9f2 100644 --- a/include/crt.c +++ b/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 @@ -2706,17 +2735,29 @@ W5: clc W3: and #$7f sta tmp + 8 - - lda accu + 3 - eor tmp + 3 - and #$80 - sta accu + 3 lda tmp + 4 + 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 - - clc - adc tmp + 5 + 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) diff --git a/include/math.c b/include/math.c index 64aa9ca..ab004f4 100644 --- a/include/math.c +++ b/include/math.c @@ -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 + } +} diff --git a/include/math.h b/include/math.h index 6d86800..842d32d 100644 --- a/include/math.h +++ b/include/math.h @@ -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) diff --git a/include/stdio.c b/include/stdio.c index 15ddffc..8ffc596 100644 --- a/include/stdio.c +++ b/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= 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= 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 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= 10.0) + { + f /= 10.0; + fdigits--; + } } else - sp[d++] = '+'; + { + float r = 0.5; + for(char i=0; i= 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; iwidth) diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index 5a953bc..b650226 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -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;