view src/number.s @ 80:bb50ac9fdf37

Checkpoint with very basic integer and floating point arithmetic, untested This commit has implementations for floating point add, subtract, multiply, and divide, along with 32 bit signed integer equivalents. These can probably be optimized and they are untested.
author William Astle <lost@l-w.ca>
date Sat, 07 Oct 2023 02:56:59 -0600
parents df86e6d64ce2
children f959c92bc329
line wrap: on
line source

                *pragmapush list
                *pragma list
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Arithmetic package
;
; This section contains routines that handle floating point and integer arithmetic. It mostly delegates to int.s and
; fps.s.
;
; Most routines take a pointer to a value accumulator in X. Some take two pointers with the second in U.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Match operands for a numeric calculation. This works as follows:
;
; * If both operands are the same, ensure the type is numeric and return
; * If one operand is floating point, convert the other to floating point, as long as it is numeric
; * If one or both operands are not numeric, raise a type mismatch
; The operands are in (X) and (U)
val_matchtypes  ldb val.type,x                  ; get the type of first argument
                cmpb #valtype_int               ; is it integer?
                beq val_matchtypes0             ; brif so
                cmpb #valtype_float             ; is it floating point?
                beq val_matchtypes1             ; brif so
TMERROR         ldb #err_tm                     ; raise a type mismatch
                jmp ERROR
val_matchtypes0 ldb val.type,u                  ; get type of second operand
                cmpb #valtype_int               ; is it integer?
                bne val_matchtypes2             ; brif not
val_matchtypes3 rts                             ; both types int - we're good so return
val_matchtypes2 cmpb #valtype_float             ; is it floating point?
                bne TMERROR                     ; brif not - raise error
                pshs x                          ; save X which may be clobbered
                leay ,x                         ; point to input operand as destination for conversion
                jsr fps_fromint32               ; convert first argument to floating point
                puls x,pc                       ; restore second operand pointer and return
val_matchtypes1 ldb val.type,u                  ; get second argument type
                cmpb #valtype_float             ; is it floating point?
                beq val_matchtypes3             ; brif so - we're good
                cmpb #valtype_int               ; is it integer?
                bne TMERROR                     ; brif not - invalid type combination
                pshs x                          ; save X which mill be clobbered
                leax ,u                         ; convert (U) to floating point
                leay ,u
                jsr fps_fromint32
                puls x,pc                       ; restore argument pointer and return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Addition and subtraction of values; must enter with values of matching types and the result type already set
; to the correct type.
;
; Calculates (X) + (U) -> (Y) (addition)
; Calculates (X) - (U) -> (Y) (subtraction)
val_add         ldb val.type,x                  ; get type of left operand
                cmpb valtype_int                ; is it integer?
                lbeq int32_add                  ; brif so - do integer addition
                cmpb #valtype_float             ; floating point?
                lbeq fps_add                    ; brif so - do floating point addition
                jmp TMERROR                     ; we have a type we don't understand
val_sub         ldb val.type,x                  ; get type of left operand
                cmpb valtype_int                ; is it integer?
                lbeq int32_sub                  ; brif so - do integer addition
                cmpb #valtype_float             ; floating point?
                lbeq fps_sub                    ; brif so - do floating point addition
                jmp TMERROR                     ; we have a type we don't understand
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Multiplication
;
; Calculates (X) × (U) -> (Y)
;
; The result might overflow the integer type. In this case, an actual overflow error will occur.
val_mul         ldb val.type,x                  ; get type of left operand
                cmpb #valtype_int               ; integer?
                lbeq int32_mul                  ; brif so - do integer multiplication
                cmpb #valtype_float             ; is it float?
                lbeq fps_mul                    ; brif so - do floating point multiplication
                jmp TMERROR                     ; have an unhandled type - bail on it
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Division
;
; Calculates (X) ÷ (U) -> (Y)
;
; The integer operation simply truncates the result ("rounds toward zero")
val_div         ldb val.type,x                  ; get type of left operand
                cmpb #valtype_int               ; integer?
                lbeq int32_div                  ; brif so - do integerdivision
                cmpb #valtype_float             ; floating point?
                lbeq fps_div                    ; brif so - do floating point division
                jmp TMERROR                     ; unsupported type
                if 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Modulus - note that this is a division operator returning effectively the remainder, not an absolute value as is
; sometimes meant by "modulus".
;
; Calculates (X) <MOD> (U) -> (Y)
;
; Note: modulus will have the same sign as the quotient so that (U) * [(X) / (U)] + [(X) MOD (U)] gives (X) (integer)
; Note2: the modulus can be calculated on floating point values in which case it will represent the fraction part
;    of the quotient multiplied by the divisor, again with the same sign as the quotient
val_mod         ldb val.type,x                  ; get type of left operand
                cmpb #valtype_int               ; integer?
                lbeq int32_mod                  ; do integer modulus
                cmpb #valtype_float             ; floating point?
                lbeq fps_mod                    ; floating point modulus
                jmp TMERROR                     ; unsupported type
                endc
                *pragmapop list