;************************************************************************** ;* Although considerable effort has been expended to make this software * ;* correct and reliable, no warranty is implied; the author disclaims any * ;* obligation or liability for damages, including but not limited to * ;* special, indirect, or consequential damages arising out of or in * ;* connection with the use or performance of this software. * ;************************************************************************** .title arithmetic .ident /01/ ; ; This module contains extended precision arithmetic. ; ; Routine 'XN_Div_D_T' multiplies X by a numerator value N, ; then divides by the denominator D, truncating the result. ; ; The calling sequence is: ; ; Quotient = XN_Div_D_T (X, N, D) ; ; X, N, and D are passed by value. ; .psect $code pic,shr,exe,rd,nowrt X = 4 N = 8 D = 12 .entry XN_Div_D_T,^m MovL X(ap), r4 ; Move into register BEql 10$ ; If eql, zero - skip MovL N(ap), r5 ; Move into register BEql 10$ ; If eql, zero EMul r4, r5, #0, r2 ; Perform extended multiplication EDiv D(ap), r2, r0, r1 ; Divide by D Ret ; Return to caller 10$: ClrL r0 ; Set result to zero Ret ; Return to caller ; ; Routine 'XN_Div_D_R' is similar to the above, except that ; the result is rounded to the next higher integer. ; ; The calling sequence is: ; ; Quotient = XN_Div_D_R (X, N, D) ; ; X, N and D are passed by value. ; X = 4 N = 8 D = 12 .entry XN_Div_D_R,^m MovL X(ap), r4 ; Move into register BEql 40$ ; If eql, zero - skip MovL N(ap), r5 ; Move into register BEql 40$ ; If eql, zero MovL D(ap), r0 ; Get divisor BGtr 10$ ; If gtr, continue MNegL r0, r0 ; Negate the denominator MNegL r5, r5 ; Negate the numerator 10$: AshL #-1, r0, r1 ; Divide denominator by two EMul r4, r5, #0, r2 ; Perform extended multiplication BGeq 20$ ; If Geq, branch SubL2 r1, r2 ; Subtract out half of divisor SbWC #0, r3 ; Brb 30$ ; Branch to common code 20$: AddL2 r1, r2 ; Add in half of divisor AdWC #0, r3 ; 30$: EDiv r0, r2, r0, r1 ; Divide by divisor Ret ; Return to caller 40$: ClrL r0 ; Set result to zero Ret ; Return to caller ; ; Routine 'Multiply_Long' multiplies two longwords to form a ; single 64-bit output value. ; ; The calling sequence is: ; ; Multiply_Long (Multiplicand, Multiplier, Product) ; ; The longword Multiplicand and Multiplier are passed by value. ; The Product argument is the address of a quadword value. ; Multiplicand = 4 Multiplier = 8 Product = 12 .entry Multiply_Long,^m<> MovL Multiplicand(ap), r0 ; Get multiplicand MovL Multiplier(ap), r1 ; Get multiplier EMul r0, r1, #0, @Product(ap); Perform extended multiplication Ret ; Return to caller ; ; Routine 'Subtract_Quad' subtracts one quadword value from ; another, replacing the minuend with the difference. ; ; The calling sequence is: ; ; Subtract_Quad (Subtrahend, Minuend) ; ; Both arguments are the address of a quadword value. ; Subtrahend = 4 Minuend = 8 .entry Subtract_Quad,^m<> MovAQ @Subtrahend(ap), r0 ; Get subtrahend quadword address MovAQ @Minuend(ap), r1 ; Get minuend quadword address SubL2 (r0), (r1) ; Subtract low order longword SbWC 4(r0), 4(r1) ; Subtract high order longword Ret ; Return to caller ; ; Routine 'Add_Quad' adds one quadword value to another, ; replacing the second argument with the sum. ; ; The calling sequence is: ; ; Subtract_Quad (Addend, Sum) ; ; Both arguments are the address of a quadword value. ; Addend = 4 Sum = 8 .entry Add_Quad,^m<> MovAQ @Addend(ap), r0 ; Get addend quadword address MovAQ @Sum(ap), r1 ; Get sum quadword address AddL2 (r0), (r1) ; Add low order longword AdWC 4(r0), 4(r1) ; Add high order longword Ret ; Return to caller ; ; Routine 'Compare_Quad' compares two signed quadword values, ; returning -1 if the first is less than the second, 0 if they are ; equal, or +1 if the first is greater than the second. ; ; The calling sequence is: ; ; = Compare_Quad (First, Second) ; ; Both arguments are the address of a quadword value. ; First = 4 Second = 8 .entry Compare_Quad,^m<> MovAQ @First(ap), r0 ; Get first quadword address MovAQ @Second(ap), r1 ; Get second quadword address CmpL 4(r0), 4(r1) ; Compare high order 32 bits BNeq 10$ ; If not equal, do further tests CmpL (r0), (r1) ; Compare low order 32 bits 10$: BLss 20$ ; Branch if less than BGtr 30$ ; Else branch if greater than ClrL r0 ; Set result to "equal" Ret ; Return to caller 20$: MNegL #1, r0 ; Set result to "less than" Ret ; Return to caller 30$: MovL #1, r0 ; Set result to "greater than" Ret ; Return to caller .end