*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=* * * * MATH.LIB * * * * AUTHOR: NATHAN RIGGS * * CONTACT: NATHAN.RIGGS@ * * OUTLOOK.COM * * * * VERSION: 0.2.0 * * DATE: 12-DEC-2018 * * ASSEMBLER: MERLIN 8 PRO * * OS: DOS 3.3 * * LICENSE: APACHE 2.0 * * * * STANDARD INTEGER MATH * * LIBRARY FOR 16-BIT VALUES, * * SIGNED OR UNSIGNED, AS WELL * * AS 16-BIT PRNG ROUTINES. * * * *------------------------------* * * * LIST OF ROUTINES * * * * ADDIT16: 16-BIT ADD * * SUBT16: 16BIT SUBTRACT * * MULT16 : 16BIT MULTIPLY * * SDIVD16: 16BIT DIVIDE (SIGN) * * UDIVD16: 16BIT DIVIDE (UNSN) * * SREMD16: 16BIT REMNDR (SIGN) * * UREMD16: 16BIT REMNDR (UNSN) * * COMP16 : 16BIT COMPARE * * RAND16 : RANDOM # 0..65535 * * * *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=* * *``````````````````````````````* * ADDIT16 :: ADD 16-BIT VALUES * *- -* * ADDS TWO SIXTEEN BIT VALUES * * AND RETURNS A 16 BIT VALUE * * IN .Y (LOW) AND .X (HIGH). * * CAN BE SIGNED OR UNSIGNED. * *- -* * CLOBBERS: * * * * FLAGS: ????---- REG: AXYM * *- -* * CYCLES: ??? * * SIZE: * *- -* * USAGE: * * * * LDA #>1000 * * PHA * * LDA #<1000 * * PHA * * LDA #>1200 ; ADD2 * * PHA * * LDA #<1200 * * PHA * * JSR ADDIT16 * *- -* * ENTRY * * * * TOP OF STACK * * * * LOW BYTE OF RETURN ADDRESS * * HI BYTE OF RETURN ADDRESS * * ADDEND 2 LOW BYTE * * ADDEND 2 HIGH BYTE * * ADDEND 1 LOW BYTE * * ADDEND 1 HIGH BYTE * *- -* * EXIT * * * * TOP OF STACK * * * * LOW BYTE OF RETURN ADDRESS * * HI BYTE OF RETURN ADDRESS * * * * .Y = LOW BYTE OF RESULT * * .X = HIGH BYTE OF RESULT * * .A = LOW BYTE OF RET ADDR * * * * [RETURN] = RESULT (2 BYTES) * * [RETLEN] = 2 (RESULT LENGTH) * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ADDIT16 * ** GET RETURN ADDR * PLA STA RETADR PLA STA RETADR+1 * ** GET PARAMETERS * PLA STA :ADD2 PLA STA :ADD2+1 PLA STA :ADD1 PLA STA :ADD1+1 * LDA :ADD1 CLC ADC :ADD2 TAY ; LOW BYTE STY RETURN LDA :ADD1+1 ADC :ADD2+1 TAX ; HIGH BYTE STX RETURN+1 LDA #2 STA RETLEN * ** RESTORE RETURN ADDRESS * LDA RETADR+1 PHA LDA RETADR PHA * RTS * ** DATA * :ADD1 DS 2 :ADD2 DS 2 * *``````````````````````````````* * SUBT16 :: SUBTRACT WORDS * *- -* * SUBTRACT ONE 16BIT NUMBER * * FROM ANOTHER, RETURNING THE * * RESULT IN .Y (LOW), .X (HI). * * SIGNED OR UNSIGNED. * *- -* * CLOBBERS: * * * * FLAGS: ????---- REG: AXYM * *- -* * CYCLES: ??? * * SIZE: * *- -* * USAGE: * * * * LDA #>1000 ; MINUEND * * PHA * * LDA #<1000 * * PHA * * LDA #>500 ; SUBTRAHEND * * PHA * * LDA #<500 * * PHA * * JSR SUBT16 * *- -* * ENTRY * * * * TOP OF STACK * * * * LOW BYTE OF RETURN ADDRESS * * HI BYTE OF RETURN ADDRESS * * LOW BYTE OF SUBTRAHEND * * HIGH BYTE OF SUBTRAHEND * * LOW BYTE OF MINUEND * * HIGH BYTE OF MINUEND * *- -* * EXIT * * * * TOP OF STACK * * * * LOW BYTE OF RETURN ADDRESS * * HI BYTE OF RETURN ADDRESS * * * * .Y = RESULT LOW BYTE * * .X = RESULT HIGH BYTE * * .A = LOW BYTE OF RET ADDR * * * * [RETURN] = RESULT (2 BYTES) * * [RETLEN] = 2 (RESULT LENGTH) * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * SUBT16 * ** GET RETURN ADDRESS * PLA STA RETADR PLA STA RETADR+1 * ** GET PARAMETERS * PLA STA :SUBT PLA STA :SUBT+1 ; SUBTRAHEND PLA STA :MINU PLA STA :MINU+1 ; MINUEND * ** MINUEND - SUBTRAHEND * LDA :MINU SEC SBC :SUBT TAY ; LOW BYTE STY RETURN LDA :MINU+1 SBC :SUBT+1 TAX ; HIGH BYTE STX RETURN+1 LDA #2 STA RETLEN * ** RESTORE RETURN ADDRESS * LDA RETADR+1 PHA LDA RETADR PHA * RTS * ** DATA * :MINU DS 2 :SUBT DS 2 * *``````````````````````````````* * MULT16 :: MULTIPLY WORDS * *- -* * PERFORM MULTIPLICATION USING * * THE SHIFT AND ADD ALGORITHM * * * * NOTE: WHILE THIS DOES PASS * * THE FULL 32BIT PRODUCT BACK * * VIA X AND Y, THIS WOULD * * RETURN FALSE RESULTS IF ONE * * OF THE PARAMETERS HAD BEEN * * SIGNED. THUS, USUALLY ONLY * * THE LOW WORD IS USED. * *- -* * CLOBBERS: * * * * FLAGS: ????---- REG: AXYM * *- -* * CYCLES: ??? * * SIZE: * *- -* * USAGE: * * * * LDA #>1000 * * PHA * * LDA #<1000 ; MCAND * * PHA * * LDA #>3 * * PHA * * LDA #<3 ; MLIER * * PHA * * JSR MUL16 ; = 3000 * *- -* * ENTRY * * * * TOP OF STACK * * * * LOW BYTE OF RETURN ADDRESS * * HI BYTE OF RETURN ADDRESS * * LOW BYTE OF MULTIPLIER * * HIGH BYTE OF MULTIPLIER * * LOW BYTE OF MULTIPLICAND * * HIGH BYTE OF MULTIPLICAND * *- -* * EXIT * * * * TOP OF STACK * * * * LOW BYTE OF RETURN ADDRESS * * HI BYTE OF RETURN ADDRESS * * LOW BYTE OF PRODUCT * * HIGH BYTE OF PRODUCT (16BIT) * * * * .Y = LOW BYTE OF HIGH WORD * * .X = HIGH BYTE OF HIGH WORD * * .A = LOW BYTE OF RET ADDR * * * * [RETURN] = RESULT (2 BYTES) * * [RETLEN] = 2 (RESULT LENGTH) * *- -* * ADAPTED FROM LEVANTHAL AND * * WINTHROP'S /6502 ASSEMBLY * * LANGUAGE ROUTINES/. * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * MULT16 * ** GET RETURN ADDRESS * PLA STA RETADR PLA STA RETADR+1 * ** GET PARAMETERS * PLA STA :MLIER PLA STA :MLIER+1 PLA STA :MCAND PLA STA :MCAND+1 * ** PERFORM MULTIPLICATION USING THE SHIFT ** AND ADD ALGORITHM, WHICH PRODUCES AN ** UNSIGNED 32-BIT PRODUCT IN :HIPROD AND ** :MLIER WITH :HIPROD BEING THE HIGH WORD. * LDA #0 STA :HPROD ; ZERO HIGH WORD STA :HPROD+1 LDX #17 ; # OF BITS IN MPLIER ; PLUS 1. EXTRA LOOP IS ; TO MOVE LAST CARRY INTO ; THE PRODUCT. CLC ; CLEAR CARRY FOR 1ST TIME ; THROUGH LOOP. :MULLP * ** IF NEXT BIT = 1 THEN ** HIPROD = HIPROD+MCAND * ROR :HPROD+1 ROR :HPROD ROR :MLIER+1 ROR :MLIER BCC :DECCNT ; BR IF NEXT BIT OF ; MULTIPLIER IS 0 CLC ; NEXT BIT=1 SO ADD MCAND ; TO PRODUCT LDA :MCAND ADC :HPROD STA :HPROD LDA :MCAND+1 ADC :HPROD+1 STA :HPROD+1 ; CARRY = OVERFLOW ; FROM ADD :DECCNT DEX BNE :MULLP ; CONTINUE UNTIL DONE LDY :HPROD ; LOW BYTE OF HIGH WORD LDX :HPROD+1 ; HIGH BYTE OF HIGH WORD * ** PUSH LOW WORD OF PRODUCT ONTO THE STACK * LDA :MLIER+1 TAX STX RETURN+1 LDA :MLIER TAY STY RETURN LDA :HPROD STA RETURN+2 LDA #2 STA RETLEN * ** RESTORE RETURN ADDRESS * LDA RETADR+1 PHA LDA RETADR PHA * LDA :HPROD ;24BIT RTS * ** DATA * :MCAND DS 3 :MLIER DS 3 :HPROD DS 2 * *``````````````````````````````* * 16-BIT DIVISION: * * * * SDIV16, UDIV16, SREM16, AND * * UREM16. * *- -* * SDIV16: DIVIDED 2 SIGNED BIT * * WORDS AND RETURN A 16-BIT * * SIGNED QUOTIENT. * * * * UDIV16: DIVIDE 2 UNSIGNED * * 16BIT WORDS AND RETURN A * * 16BIT UNSIGNED QUOTIENT. * * * * SREM16: DIVIDE 2 SIGNED * * 16BIT WORDS AND RETURN A * * 16BIT SIGNED REMAINDER. * * * * UREM16: DIVIDE 2 UNSIGNED * * 16BIT WORKDS AND RETURN A * * 16BIT UNSIGNED REMAINDER. * *- -* * CLOBBERS: * * * * FLAGS: ????---- REG: AXYM * *- -* * CYCLES: ??? * * SIZE: * *- -* * USAGE: * * * ** ALL ROUTINES USE THE SAME * ** FORMAT. * * * * LDA #>10000 * * PHA * * LDA #<10000 ; DIVIDEND * * PHA * * LDA #>1000 ; DIVISOR * * PHA * * LDA #<1000 * * PHA * * JSR UDIV16 * *- -* * ENTRY * * * * TOP OF STACK * * * * LOW BYTE OF RETURN ADDRESS * * HI BYTE OF RETURN ADDRESS * * LOW BYTE OF DIVISOR * * HIGH BYTE OF DIVISOR * * LOW BYTE OF DIVIDEND * * HIGH BYTE OF DIVIDEND * *- -* * EXIT * * * * TOP OF STACK * * * * LOW BYTE OF RETURN ADDRESS * * HI BYTE OF RETURN ADDRESS * * * * IF NO ERRORS, CARRY = 0, * * ELSE CARRY=1, QUOTIENT=0, * * AND REMAINDER=0 * * * * .Y = COUNTER; TRASH * * .X = COUNTER; TRASH * * .A = LOW BYTE OF RET ADDR * * * * [RETURN] = RESULT (2 BYTES) * * [RETLEN] = 2 (RESULT LENGTH) * *- -* * ADAPTED FROM LEVANTHAL AND * * WINTHROP'S /6502 ASSEMBLY * * LANGUAGE ROUTINES/. * * AS SUCH, IT MAY FALL UNDER A * * DIFFERENT LICENSE UNTIL IT * * IS RADICALLY REWORKED. * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * UDIVD16 LDA #0 BEQ UDIVMD UREMD16 LDA #2 UDIVMD STA _RSLTI * ** GET RETURN ADDRESS * PLA STA RETADR PLA STA RETADR+1 * ** GET PARAMETERS * PLA STA _DVSOR PLA STA _DVSOR+1 PLA STA _DVEND PLA STA _DVEND+1 * JSR UDIV BCC DIVOK ; BR IF NO ERR DIVERR JMP EREXIT DIVOK JMP OKEXIT * ** SIGNED DIVISION * SDIVD16 LDA #0 ; RESULT IS QUOTIENT BEQ SDIVMD ; (INDEX=0) * ** SIGNED REMAINDER * SREMD16 LDA #2 ; RES = REMAINDER (I=2) BNE SDIVMD * SDIVMD STA _RSLTI ;RESULT INDEX;0=Q,2=R * ** GET RETURN ADDRESS * PLA STA RETADR PLA STA RETADR+1 * ** GET PARAMETERS * PLA STA _DVSOR PLA STA _DVSOR+1 PLA STA _DVEND PLA STA _DVEND+1 * * ** DETERMINE SIGN OF QUOTIENT BY ** PERFORMING AN EXCLUSIVE OR OF ** THE HIGH BYTES. IF THE SIGNS ** ARE THE SAME THEN BIT 7 WILL ** BE 0 AND THE QUOTIENT IS ** POSITIVE. IF THE SIGNS ARE ** DIFFERENT THEN THE QUOTIENT ** IS NEGATIVE. * LDA _DVEND+1 EOR _DVSOR+1 STA _SQUOT * ** SIGN OF REMAINDER IS THE SIGN ** OF THE DIVIDEND * LDA _DVEND+1 STA _SREMD * ** TAKE THE ABSOLUTE VALUE OF ** THE DIVISOR * LDA _DVSOR+1 BPL CHKDE ; BR IF ALREADY POS LDA #0 ; SUB DVSOR FROM ZERO SEC SBC _DVSOR STA _DVSOR LDA #0 SBC _DVSOR+1 STA _DVSOR+1 * ** TAKE ABS VALUE OF THE DIVIDEND * CHKDE LDA _DVEND+1 BPL DODIV ; BR IF DVEND IS POS LDA #0 ; SUB DVEND FROM ZERO SEC SBC _DVEND STA _DVEND LDA #0 SBC _DVEND+1 STA _DVEND+1 * ** DIVIDE ABS VALUES * DODIV JSR UDIV BCS EREXIT ; EXIT IF DIV BY 0 * ** NEGATE QUOTIENT IF IT IS NEGATIVE * LDA _SQUOT BPL DOREM ; BR IF Q IS POS LDA #0 SEC SBC _DVEND STA _DVEND LDA #0 SBC _DVEND+1 STA _DVEND+1 * DOREM * ** NEGATE REMAINDER IF IT IS NEG * LDA _SREMD BPL OKEXIT ; BR IF REM IS POS LDA #0 SEC SBC _DVEND+2 STA _DVEND+2 LDA #0 SBC _DVEND+3 STA _DVEND+3 JMP OKEXIT * ** ERROR EXIT (CARRY=1, RSLTS ARE 0) * EREXIT LDA #0 STA _DVEND STA _DVEND+1 ;QUOTIENT = 0 STA _DVEND+2 STA _DVEND+3 ; REMAINDER=0 STA RETURN STA RETURN+1 LDA #2 STA RETLEN SEC ; CARRY=1 IF ERROR BCS DVEXIT * ** GOOD EXIT (CARRY = 0) * OKEXIT CLC ; CARRY = 0, NO ERRORS * DVEXIT * ** STORE RESULT * LDX _RSLTI ;GET INDEX TO RESULT ; 0=QUOTIENT, 2=REMAINDER * ** STORE RESULT * LDA _DVEND,X TAY LDA _DVEND+1,X TAX STY RETURN STX RETURN+1 LDA #2 STA RETLEN * ** RESTORE RETURN ADDRESS * LDA RETADR+1 PHA LDA RETADR PHA * RTS * ******************************** * UDIV ROUTINE ******************************** UDIV * ** ZERO UPPER WORD DIVIDEND ** THIS WILL BE CALLED ** DIVIDEND(1) BELOW * LDA #0 STA _DVEND+2 STA _DVEND+3 * ** FIRST CHECK FOR DIV BY 0 * LDA _DVSOR ORA _DVSOR+1 BNE OKUDIV ; BR IF DVSOR NOT 0 SEC RTS * ** PERFORM THE DIVISION BY ** TRIAL SUBTRACTIONS * OKUDIV LDX #16 ; LOOP THROUGH 16 BITS DIVLP ROL _DVEND ;SHFT CARRY INTO BIT 0 OF DVEND ROL _DVEND+1 ;WHICH WILL BE THE QUOTIENT AND ROL _DVEND+2 ;SHFT DVEND AT THE SAME TIME ROL _DVEND+3 CHKLT SEC LDA _DVEND+2 SBC _DVSOR TAY ; SAVE LOW BYTE IN Y LDA _DVEND+3 SBC _DVSOR+1 ;SUB HIGHBYTES W RES IN A BCC DECCNT ; BR IF DVEND < DVSOR AND CARRY STY _DVEND+2 ; ELSE STA _DVEND+3 ;VEN(1)=DVEND(1)-DVSOR * DECCNT DEX BNE DIVLP * ROL _DVEND ;SHFT IN LAST CAR FOR QUOT ROL _DVEND+1 CLC ; NO ERRORS, CLEAR CARRY RTS * ** DATA * _DVSOR DS 2 ; DIVISOR _DVEND DS 4 ; DIVIDEND[0] AND QUOTIENT ; DIVIDEND[1] AND REMAINDER _SQUOT DS 1 ; SIGN OF QUOTIENT _SREMD DS 1 ; SIGN OF REMAINDER _RSLTI DS 1 ; RESULT INDEX * *``````````````````````````````* * COMP16 :: 16-BIT COMPARE * *- -* * COMPARE TWO 16BIT SIGNED OR * * UNSIGNED WORDS AND RETURN * * THE C,Z,N FLAGS AS SET OR * * CLEARED. * *- -* * CLOBBERS: * * * * FLAGS: CZN----- REG: AXYM * *- -* * CYCLES: ??? * * SIZE: * *- -* * USAGE: * * * * LDA #>123 * * PHA * * LDA #<123 * * PHA ; WORD 1 * * LDA #>1023 * * PHA * * LDA #<1023 * * PHA ; WORD 2 * * JSR CMP16 * *- -* * ENTRY * * * * TOP OF STACK * * * * LOW BYTE OF RETURN ADDRESS * * HI BYTE OF RETURN ADDRESS * * LOW BYTE OF WORD 2 (SUBTRA) * * HIGH BYTE OF WORD 2 * * LOW BYTE OF WORD 1 (MINU) * * HIGH BYTE OF WORD 1 * *- -* * EXIT * * * * TOP OF STACK * * * * FLAGS RETURNED BASED ON WORD * * 1 - WORD 2. * * * * IF W1 & W2 ARE 2S COMPLEMENT * * IF W1 = W2 Z=1,N=0 * * IF W1 > W2 Z=0,N=0 * * IF W1 < W2 Z=0,N=1 * * ELSE * * IF W1 = W2 Z=1,C=1 * * IF W1 > W2 Z=0,C=1 * * IF W1 < W2 Z=0,C=0 * * * *- -* * ADAPTED FROM LEVANTHAL AND * * WINTHROP'S /6502 ASSEMBLY * * LANGUAGE ROUTINES/. * * AS SUCH, THE SAME LICENSE * * MAY NOT APPLY UNTIL RADICAL * * ALTERATION. * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * COMP16 * ** GET RETURN ADDRESS * PLA STA RETADR PLA STA RETADR+1 * ** GET PARAMETERS * PLA STA :SUBT ; SUBTRAHEND PLA STA :SUBT+1 PLA STA :MINU ; MINUEND PLA STA :MINU+1 * ** RESTORE RETURN ADDRESS * LDA RETADR+1 PHA LDA RETADR PHA * LDA :MINU CMP :SUBT ; COMPARE LOW BYTES BEQ :EQUAL * ** LOW BYTES ARE NOTE EQUAL ** COMPARE HIGH BYTES * LDA :MINU+1 SBC :SUBT+1 ; COMPARE HIGH BYTES ORA #1 ; MAKE Z=0, SINCE LOW ; BYTES ARE NOT EQUAL BVS :OVFLOW ; MUST HANDLE OVERFLOW ; FOR SIGNED MATH RTS ; EXIT * ** LOW BYTES ARE UQAL -- COMPARE HIGH * :EQUAL LDA :MINU+1 SBC :SUBT+1 ; UPPER BYTES BVS :OVFLOW RTS ; RETURN W FLAGS SET * ** ** OVERFLOW WITH SIGNED ARITHMETIC SO ** COMPLEMENT THE NEGATIVE FLAG. ** DO NO CHANGE THE CARRY FLAG AND ** MAKE THE ZERO FLAG EQUAL TO 0. ** COMPLEMENT NEG FLAG BY EORING ** #$80 AND ACCUMULATOR. ** * :OVFLOW EOR #$80 ; COMPLEMENT N FLAG ORA #1 ; IF OVERFLOW THEN THE ; WORDS ARE !=. Z= 0 ; CARRY UNCHANGED RTS * ** DATA * :MINU DS 2 :SUBT DS 2 * *``````````````````````````````* * RAND16 : 16BIT RANDOM NUMBER * *- -* * GENERATE A 16BIT PSEUDO- * * RANDOM NUMBER AND RETURN IT * * IN Y,X (LOW, HIGH). * * * * ORIGINAL AUTHOR IS WHITE * * FLAME, AS SHARED ON * * CODEBASE64. * *- -* * CLOBBERS: * * * * FLAGS: ????---- REG: AXYM * *- -* * CYCLES: ??? * * SIZE: * *- -* * USAGE: * * * *- -* * ENTRY * * * * LOW BYTE OF RETURN ADDRESS * * HIGH BYTE OF RETURN ADDRESS * *- -* * EXIT * * * * .Y = HIGH BYTE OF PRODUCT * * .X = LOW BYTE OF PRODUCT * * .A = LOW BYTE OF PRODUCT * * * * [RETURN] = RESULT (2 BYTES) * * [RETLEN] = 2 (RESULT LENGTH) * *- -* * NOTE: THERE ARE 2048 MAGIC * * NUMBERS THAT COULD BE EOR'D * * TO GENERATE A PSEUDO-RANDOM * * PATTERN THAT DOESN'T REPEAT * * UNTIL 65535 ITERATIONS. TOO * * MANY TO LIST HERE, BUT SOME * * ARE: $002D, $1979, $1B47, * * $41BB, $3D91, $B5E9, $FFEB * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * RAND16 * LDA RNDL STA :SEED LDA RNDH STA :SEED+1 * LDA :SEED BEQ :LOW0 * ** DO A NORMAL SHIFT * ASL :SEED LDA :SEED+1 ROL BCC :NOEOR :DOEOR ; HIGH BYTE IN A EOR #>$0369 STA :SEED+1 LDA :SEED EOR #<$0369 STA :SEED JMP :EXIT :LOW0 LDA :SEED+1 BEQ :DOEOR ASL BEQ :NOEOR BCS :DOEOR :NOEOR STA :SEED+1 :EXIT LDX :SEED+1 LDY :SEED STY RETURN STX RETURN+1 LDA #2 STA RETLEN RTS * ** DATA * :SEED DS 2 * *``````````````````````````````* * RANDW :: RANDOM WORD * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * * ** THIS WILL BE INCLUDED IN FUTURE UPDATES * *