# HG changeset patch # User William Astle # Date 1688340071 21600 # Node ID f492fa6f6dc8f0f123e478e67c82236463261b72 # Parent f4b2406d7352e297cd3ae8f7990d337b205bf462 First pass implementation of addition and subtraction diff -r f4b2406d7352 -r f492fa6f6dc8 src/lwbasic.s --- a/src/lwbasic.s Sun Jul 02 02:33:53 2023 -0600 +++ b/src/lwbasic.s Sun Jul 02 17:21:11 2023 -0600 @@ -1707,6 +1707,7 @@ puls b,pc ; return current value to complete previous operation eval_expr3 jsr nextchar ; eat the operator token ldx 1,x ; get handler address of this operator + leas -val.size,s ; make room for the result accumulator pshs x ; save handler address for later lda val0+val.type ; get current value type ldx val0 ; get value accumlator contents (6 bytes) @@ -1719,7 +1720,15 @@ sty val1+2 stu val1+4 sta val1+val.type ; save previous value type + ldx #val1 ; point to left operand + ldu #val0 ; point to right operand + leay 2,s ; point to return value location jsr [,s++] ; go handle the operator + puls a,x,y,u ; get return value + sta val0 + stx val0+1 + sty val0+3 + stu val0+5 puls b ; get back the previous operator precedence bra eval_expr0 ; go process another operator or end of expression eval_term jsr curchar ; get current input character @@ -1814,9 +1823,9 @@ ; Each entry starts with the precedence value followed by the handler routine. Each handler will receive its left ; operand in val1 and its right operand in val0 and should return its result in val0. oper_tab fcb 0x79 ; addition - fdb SNERROR + fdb oper_plus fcb 0x79 ; subtraction - fdb SNERROR + fdb oper_minus fcb 0x7b ; multiplication fdb SNERROR fcb 0x7b ; division @@ -1859,6 +1868,20 @@ suba #-'0 setcifdigit0 rts ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Operator handling routines +; +; binary plus: addition and concatenation +oper_plus ldb val.type,x ; get type of the left operand + cmpb valtype_string ; is it string? + bne oper_plus0 ; brif not + cmpb val.type,u ; is right operand also string? + lbeq SNERROR ; brif so - do string concatenation +oper_plus0 bsr val_matchtypes ; go match data types + jmp val_add ; go add the values +; binary minus: subtraction +oper_minus bsr val_matchtypes ; go match data types + jmp val_sub ; do subtraction +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Arithmetic package ; ; This section contains routines that handle floating point and integer arithmetic. @@ -1993,6 +2016,121 @@ clr val.fpsign,x puls b,pc ; clean up stack and return ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Addition and subtraction of values; must enter with values of matching types +; +; Calculates (X) + (U) -> (Y) (addition) +; Calculates (X) - (U) -> (Y) (subtraction) +val_add ldb val.type,x ; get type of left operand + stb val.type,y ; set result type + cmpb #valtype_float ; is it float? + beq fp_add ; brif so + ldd val.int+2,x ; do the addition + addd val.int+2,u + std val.int+2,y + ldd val.int,x + adcb val.int+1,u + adca val.int,u + std val.int,y + lbvs OVERROR ; brif calculation overflowed + rts +val_sub ldb val.type,x ; get type of left operand + stb val.type,y ; set result type + cmpb #valtype_float ; floating point? + beq fp_sub ; brif so + ldd val.int+2,x ; do the subtraction + subd val.int+2,u + std val.int+2,y + ldd val.int,x + sbcb val.int+1,u + sbca val.int,u + std val.int,y + lbvs OVERROR ; brif overflow + rts +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; FP subtraction: just invert the sign of the second operand and add; operands must be writable and they should be +; considered to be clobbered +fp_sub com val.fpsign,u ; negate right operand + ; fall through to addition +; FP addition: this requires that *both operands* are writable and they may be clobbered +fp_add ldb val.fpexp,u ; is the second operand zero? + beq fp_add0 ; brif so - it's a no-op - copy the left operand to the output + lda val.fpexp,x ; is left operand zero? + bne fp_add1 ; brif not - we have to do the add + leau ,x ; copy the right operand to the output +fp_add0 ldd ,u ; copy the value across + std ,y + ldd 2,u + std 2,y + ldd 4,u + std 4,y + rts +fp_add1 subb val.fpexp,x ; get difference in exponents + beq fp_add6 ; brif they're the same - no denormalizing is needed + bhi fp_add2 ; brif second one is bigger, need to right-shift the mantissa of first + exg x,u ; swap the operands (we can do that for addition)l second is now biggest + negb ; invert the shift count +fp_add2 cmpb #32 ; are we shifting more than 32 bits? + blo fp_add0 ; brif so - we're effectively adding zero so bail out +fp_add3 cmpb #8 ; have 8 bits to move? + bhs fp_add5 ; brif not + lda val.fpmant+2,x ; shift 8 bits right + sta val.fpmant+3,x + lda val.fpmant+1,x + sta val.fpmant+2,x + lda val.fpmant,x + sta val.fpmant+1,x + clr val.fpmant,x + subb #8 ; account for 8 shifts + bra fp_add3 ; see if we have a whole byte to shift +fp_add4 lsr val.fpmant,x ; shift right one bit + ror val.fpmant+1,x + ror val.fpmant+2,x + ror val.fpmant+3,x +fp_add5 decb ; done all shifts? + bmi fp_add4 ; brif not - do a shift +fp_add6 ldb val.fpexp,u ; set exponent of result + stb val.fpexp,y + ldb val.fpsign,u ; fetch sign of larger value + stb val.fpsign,y ; set result sign + cmpb val.fpsign,x + bne fp_add8 ; brif not - need to subtract the operands + ldd val.fpmant+2,u ; add the mantissas + addd val.fpmant+2,x + std val.fpmant+2,y + ldd val.fpmant,u + adcb val.fpmant+1,x + adca val.fpmant,x + std val.fpmant,y + clrb ; clear extra precision bits + bcc fp_add7 ; brif no carry + ror val.fpmant,y ; shift carry into mantissa + ror val.fpmant+1,y + ror val.fpmant+2,y + ror val.fpmant+3,y + rorb ; keep bits for founding + inc val.fpexp,y ; bump exponent to account for shift + lbeq OVERROR ; brif it overflowed +fp_add7 leax ,y ; point to result + jmp fp_normalize ; go normalize the result +fp_add8 ldd val.fpmant+2,u ; subtract operands + subd val.fpmant+2,x + std val.fpmant+2,y + ldd val.fpmant,u + sbcb val.fpmant+1,x + sbca val.fpmant,x + std val.fpmant,y + bcc fp_add7 ; brif we didn't carry - no need to fix up + ldd zero ; negate the mantissa bits since we use sign+magnitude + subd val.fpmant+2,y + std val.fpmant+2,y + ldd zero + sbcb val.fpmant+1,y + sbca val.fpmant,y + std val.fpmant,y + neg val.fpsign,y ; invert sign of result since we went past zero + clrb ; clear extra precision bits + bra fp_add7 ; go normalize the result and return +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Pack a floating point value at (X) fp_packval ldb val.fpsign,x ; get sign bmi fp_packval ; brif negative - the default 1 bit will do