# Disk 4 : Basic Integer Math and Pseudorandom Numbers - [Part I: The Math Collection](#part-i-the-math-collection) - [Math Components](#math-components) - [Math Header File](#math-header-file) - [Math Macros and Subroutines](#math-macros-and-subroutines) - [Math By Constants: 8-bit Division](#math-by-constants-macros-8-bit-division) - [The D8BY2 Macro](#the-d8by2-macro) - [The D8BY3 Macro](#the-d8by3-macro) - [The D8BY4 Macro](#the-d8by4-macro) - [The D8BY5 Macro](#the-d8by5-macro) - [The D8BY6 Macro](#the-d8by6-macro) - [The D8BY7 Macro](#the-d8by7-macro) - [The D8BY8 Macro](#the-d8by8-macro) - [The D8BY9 Macro](#the-d8by9-macro) - [The D8BY10 Macro](#the-d8by10-macro) - [Math By Constants: 8-bit Multiplication](#math-by-constants-macros-8-bit-multiplication) - [The M8BY2 Macro](#the-m8by2-macro) - [The M8BY3 Macro](#the-m8by3-macro) - [The M8BY4 Macro](#the-m8by4-macro) - [The M8BY5 Macro](#the-m8by5-macro) - [The M8BY6 Macro](#the-m8by6-macro) - [The M8BY7 Macro](#the-m8by7-macro) - [The M8BY8 Macro](#the-m8by8-macro) - [The M8BY9 Macro](#the-m8by9-macro) - [The M8BY10 Macro](#the-m8by10-macro) - [Math By Constants: 16-bit Multiplication](#math-by-constants-macros-16-bit-multiplication) - [The M16BY2 Macro](#the-m16by2-macro) - [The M16BY3 Macro](#the-m16by3-macro) - [The M16BY4 Macro](#the-m16by4-macro) - [The M16BY5 Macro](#the-m16by5-macro) - [The M16BY6 Macro](#the-m16by6-macro) - [The M16BY7 Macro](#the-m16by7-macro) - [The M16BY8 Macro](#the-m16by8-macro) - [The M16BY9 Macro](#the-m16by9-macro) - [The M16BY10 Macro](#the-m16by10-macro) - [The M16BY1H Macro](#the-m16by1h-macro) - [General Purpose Math: 8-bit Macros and Subroutines](#general-purpose-math-8-bit-procedures) - [The ADD8 Macro](#the-add8-macro) - [The SUB8 Macro](#the-sub8-macro) - [The MUL8 Macro](#the-mul8-macro) - [The MULTU8 Subroutine](#the-multu8-subroutine) - [The DIV8 Macro](#the-div8-macro) - [The DIVDU8 Subroutine](#the-divdu8-subroutine) - [General Purpose Math: 16-bit Macros and Subroutines](#general-purpose-math-16-bit-procedures) - [The ADD16 Macro](#the-add16-macro) - [The ADDIT16 Subroutine](#the-addit16-subroutine) - [The SUB16 Macro](#the-sib16-macro) - [The SUBT16 Subroutine](#the-subt16-subroutine) - [The MUL16 Macro](#the-mul16-macro) - [The MULTU16 Subroutine](#the-multu16-subroutine) - [The DIV16 Macro](#the-div16-macro) - [The DIVDU16 Subroutine](#the-divdu16-subroutine) - [The CMP16 Macro](#the-cmp16-macro) - [The COMP16 Subroutine](#the-comp16-subroutine) - [Pseudorandom Number Generation Macros and Subroutines](#pseudorandom-number-generation-macros-and-subroutines) - [The RNDEOR Macro](#the-rndeor-macro) - [The RNDMZ Macro](#the-rndmz-macro) - [The RND8 Macro](#the-rnd8-macro) - [The RAND8 Subroutine](#the-rand8-subroutine) - [The RAND Macro](#the-rand-macro) - [The RANDB Subroutine](#the-randb-subroutine) - [The RND16 Macro](#the-rnd16-macro) - [The RAND16 Subroutine](#the-rand16-subroutine) - [Part II: Math Collection Demonstrations](@part-ii-math-collection-demonstrations) --- ## Part I: The Math Collection The fourth disk in the library is dedicated to Integer Math and Pseudorandom Number Generation. For the most part, this collection is limited to basic math routines only due to disk size constraints; the routines and macros for all of the current implementations already occupy most of the disk space available. This includes, somewhat meagerly, macros and subroutines for: - 8-bit Addition - 8-bit Subtraction - 8-bit Multiplication - 8-bit Division - 16-bit Addition - 16-bit Subtraction - 16-bit Multiplication - 16-bit Division - 8-bit Pseudorandom Number Generation - 16-bit Pseudorandom Number Generation - Ranged Pseudorandom Number Generation - Two Randomization Techniques Currently, all operations are for unsigned integers, though this will likely be the last addition to the collection in the next revision (accounting for negative numbers requires using wrappers that predetermine the sign value before multiplying or dividing, making the added number of bytes somewhat trivial). While a math routine and macro disk is planned for the Extended AppleIIAsm Library disks, including routines for finding percentages, floating point math, greatest common factors and least common multiples and more, the appearance of the Extended Library disks will not be any time soon. --- ## Math Components The Math Collection contains the following components: - A header file that contains the various hooks, vectors and memory space used by the entire Math Collection. - Macros and subroutines for basic integer math as well as pseudorandom numbers. The basic math macros and subroutines are further separated into "math-by" items that calculate by a given integer constant and general purpose items that calculate by arbitrary numbers. - Demonstrations of all macros and subroutines in the collection, ordered by type: "math-by", general purpose basic math, and pseudorandom numbers. --- ## Header File The mathematics header file includes a number of vectors and spans of address space for use by the rest of the collection. The header is especially important for pseudorandom number generation, as it holds the location for the seed (both low byte and high byte) as well as a table used to determine the value to `EOR` the seed by in the process of number generation. This table is 64 bytes long, and contains "magic numbers" that allow for the generation of a complete set of 65,536 different numbers before being repeated, guaranteeing that 1) with the same number and `EOR` value, the number generated can be reproduced, which allows for stepping back and forth between the generated numbers if needed, and 2) maximum variability is achieved, although this may come at the cost of statistical unlikeliness. The table is used by the `RNDMZ` macro for randomization of the generator, but the `EOR` value can also be directly altered by the `RNDEOR` macro when a specific `EOR` value is desired. | Condition | Value | | ------------- | ------------------------------------------------------------ | | Name | File: HEAD.MATH.ASM | | Type | Header File | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin 8 Pro | | OS | Apple DOS 3.3 | | Purpose | Provide appropriate hooks and routines for the Math collection | | Dependencies | none | | Bytes | 0 | | Notes | Repeatedly used subroutines by the library may be placed here in the future | | See Also | none | --- *DETAILS* `Listing 4.0` provides the complete source of the header file. `Listing 4.0: HEAD.MATH.ASM Source` ```assembly * *``````````````````````````````* * HEAD.MATH.ASM * * * * * * AUTHOR: NATHAN RIGGS * * CONTACT: NATHAN.RIGGS@ * * OUTLOOK.COM * * * * DATE: 22-MAR-2021 * * ASSEMBLER: MERLIN 8 PRO * * OS: DOS 3.3 * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * GETNUM EQU $FFA7 ; ASCII TO HEX IN 3E & 3F RNDL EQU $4E ; RANDOM NUMBER LOW RNDH EQU $4F ; RANDOM NUMBER HIGH * FAC EQU $9D ; FLOATING POINT ACCUM FSUB EQU $E7A7 ; FLOATING POINT SUBTRACT FADD EQU $E7BE FMULT EQU $E97F ; FP MULTIPLY FDIV EQU $EA66 ; FP DIVIDE FMULTT EQU $E982 FDIVT EQU $EA69 FADDT EQU $E7C1 FSUBT EQU $E7AA * MOVFM EQU $EAF9 ; MOVE FAC > MEM MOVMF EQU $EB2B ; MOVE MEM > FAC NORM EQU $E82E CONUPK EQU $E9E3 * FLOG EQU $E941 ; LOGARITHM FSQR EQU $EE8D ; SQUARE ROOT FCOS EQU $EFEA ; FP COSINE FSIN EQU $EFF1 ; SINE FTAN EQU $F03A ; TANGENT FATN EQU $F09E ; ATANGENT * ** THE FOLLOWING IS A SERIES OF "MAGIC NUMBERS" ** TO USE AS SEEDS FOR PSEUDO-RANDOM NUMBER GENERATION. ** THESE CAN BE FOUND ON CODEBASE64, BUT ARE KNOWN ** WELL ENOUGH TO BE CONSIDERED COMMON KNOWLEDGE. * JMP ]MATH_GO ]MAGEOR HEX 002D ]MAGNUM HEX 002D0039003F005300BD00D7012F013D HEX 014F015D019701A101AD01BF01C70215 HEX 02190225022F025D026D0285029102A1 HEX 02E5031D034B036903710387038D039F HEX 03A303DD03F904290457046704830489 HEX 049104BF04C1053305470569058705C3 HEX 05DD05EB0641064B0653068B06C3076B HEX 076D0779078307F1080D086108BF08D5 ]MATH_GO * ``` --- ## Macros and Subroutines The Basic Math Collection is divided into six different macro categories: 8-bit basic math, 16-bit basic math, 8-bit constant operations, 16-bit constant operations, and pseudorandom number generation. As always, 8-bit operations should be used whenever possible, as significantly fewer bytes and cycles are used in comparison to 16-bit operations. Additionally, math by constants should be used whenever one of the arguments is already known; that is, the programmer knows that something will be multiplied by three, or ten, or thirty. While macros do not exist for numbers above ten (except for 100), the answers can be easily derived from using two or more of the math-by macros. For instance, to get multiplication by thirty, first multiply by 10, then multiply that by three. Although this seems like extra work, the number of cycles saved here can be substantial, as compared to using the general purpose macros. If speed is a concern, then math-by-constants is the way to go. --- ### Math By Constants Macros: 8-bit Division These macros are dedicated to dividing a given 8-bit number by a known constant. Since the constant is known, we are able to precisely measure the number of cycles and bytes needed for the operation, and it takes significantly fewer of both to return a result than would using a general purpose division implementation. It should be noted that these macros do not take sign into consideration, and there are no plans to make wrappers for the math-by macros; only unsigned numbers are accepted. For signed operations, either use the general purpose division macros or create wrappers specific to each divide-by-constant macro. `LISTING 4.10: MAC.D8BY.ASM Header Source` ```assembly * *``````````````````````````````* * MAC.M8BY.ASM * * * * THESE MACROS CONSIST OF 8BIT * * DIVISION BY A CONSTANT * * ROUTINES. WHILE SOME OF * * THESE ARE TRIVIAL, MOST HAVE * * BEEN TAKEN FROM THE WORK OF * * OMEGAMATRIX AS SHARED ON * * THE NESDEV FORUMS. AS SUCH, * * LICENSING MAY VARY; HOWEVER, * * SINCE THEY WERE FREELY * * SHARED, IT SHOULD BE SAFELY * * ASSUMED THAT THEY ARE PUBLIC * * DOMAIN. * * * * NOTE: THESE ARE ^HIGHLY^ * * OPTIMIZED BY BRUTE FORCE ON * * A MODERN SYSTEM, AND SOME OF * * THESE MAY EXPLOIT QUIRKS OF * * THE 6502. TO SUM THAT UP: * * THESE ARE NOT ROUTINES THAT * * ARE EASILY CUT THROUGH BY A * * NOVICE, EVEN THOUGH THEY * * LOOK SIMPLE ENOUGH. * * * * AUTHOR: NATHAN RIGGS * * (COPIED FROM OMEGAMATRIX) * * * * CONTACT: NATHAN.RIGGS@ * * OUTLOOK.COM * * * * DATE: 29-MAR-2021 * * ASSEMBLER: MERLIN 8 PRO * * OS: DOS 3.3 * * * * LIST OF MACROS * * * * D8BY2 : DIVIDE BY TWO * * D8BY3 : DIVIDE BY THREE * * D8BY4 : DIVIDE BY FOUR * * D8BY5 : DIVIDE BY FIVE * * D8BY6 : DIVIDE BY SIX * * D8BY7 : DIVIDE BY SEVEN * * D8BY8 : DIVIDE BY EIGHT * * D8BY9 : DIVIDE BY NINE * * D8BY10 : DIVIDE BY TEN * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ``` --- ### THE D8BY2 MACRO _SUMMARY_ | Condition | Value | | --------------- | ---------------------------- | | Name | `D8BY2` | | Type | Macro | | File | `MAC.D8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Divide an 8-bit value by two | | Input | ]1 = Number to divide | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 6 | | Bytes | 4 | | Notes | None | | See Also | `M8BY2` `M16BY2` | --- *DETAILS* The `D8BY2` macro divides a given number by two using a left shift (`LSR`). The result is floored, and no remainder is provided; it is passed back via the **.A** register. `LISTING 4.11: The D8BY2 Macro Source` ```assembly * *``````````````````````````````* * D8BY2 (NATHAN RIGGS) * * * * DIVIDE 8-BIT NUMBER BY TWO * * * * PARAMETERS * * * * ]1 = NUMBER TO DIVIDE * * * * CYCLES: 6 * * SIZE: 4 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * D8BY2 MAC LDA ]1 ; {4C3B} LSR ; {2C1B} SHIFT BITS RIGHT IN .A ; TO DIVIDE BY TWO. ANSWER REMAINS ; IN .A REGISTER <<< ``` --- ### THE D8BY3 MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------ | | Name | `D8BY3` | | Type | Macro | | File | `MAC.D8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Divide an 8-bit value by three | | Input | ]1 = Number to divide | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 29 | | Bytes | 19 | | Notes | None | | See Also | `M8BY3` `M16BY3` | --- *DETAILS* The `DIV8BY3` macro divides a given 8-bit number by three. `LISTING 4.12: D8BY3 Macro Source` ```assembly * *``````````````````````````````* * D8BY3 (NATHAN RIGGS) * * * * DIVIDE 8-BIT NUMBER BY THREE * * * * PARAMETERS * * * * ]1 = NUMBER TO DIVIDE * * * * CYCLES: 29 * * SIZE: 19 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * D8BY3 MAC LDA ]1 ; {4C3B} CLC ; {2C2B} CLEAR THE CARRY STA BPAR1 ; {3C2B} STORE ORIG NUM IN Z PAGE LSR ; {2C1B} DIVIDE .A BY TWO ADC #21 ; {2C2B} ADD 21 AS A CORRECTION LSR ; {2C1B} DIVIDE .A BY TWO ADC BPAR1 ; {3C2B} ADD ORIGINAL VALUE TO NEW ROR ; {2C1B} ROTATE A TO NEXT BIT LSR ; {2C1B} SHIFT RIGHT TO DIVIDE BY 2 ADC BPAR1 ; {3C2B} ADD ORIGINAL VALUE ROR ; {2C1B} ROTATE .A TO NEXT BIT LSR ; {2C1B} DIVIDE BY 2 <<< * ``` --- ### THE D8BY4 MACRO _SUMMARY_ | Condition | Value | | --------------- | ----------------------------- | | Name | `D8BY4` | | Type | Macro | | File | `MAC.D8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Divide an 8-bit value by four | | Input | ]1 = Number to divide | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 8 | | Bytes | 5 | | Notes | None | | See Also | `M8BY4` `M16BY4` | --- *DETAILS* The `DIV8BY4` macro divides a given 8-bit number by four. `LISTING 4.13: D8BY4 Macro Source` ```assembly * *``````````````````````````````* * D8BY4 (NATHAN RIGGS) * * * * DIVIDE 8-BIT NUMBER BY FOUR * * * * PARAMETERS * * * * ]1 = NUMBER TO DIVIDE * * * * CYCLES: 8 * * SIZE: 5 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * D8BY4 MAC LDA ]1 ; {4C3B} LSR ; {2C1B} DIVIDE .A BY TWO LSR ; {2C1B} DIVIDE .A BY TWO <<< * ``` --- ### THE D8BY5 MACRO _SUMMARY_ | Condition | Value | | --------------- | ----------------------------- | | Name | `D8BY5` | | Type | Macro | | File | `MAC.D8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Divide an 8-bit value by five | | Input | ]1 = Number to divide | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 34 | | Bytes | 21 | | Notes | None | | See Also | `M8BY5` `M16BY5` | --- *DETAILS* The `DIV8BY4` macro divides a given 8-bit number by five. `LISTING 4.14: D8BY5 Macro Source` ```assembly * *``````````````````````````````* * D8BY5 (NATHAN RIGGS) * * * * DIVIDE 8-BIT NUMBER BY FIVE * * * * PARAMETERS * * * * ]1 = NUMBER TO DIVIDE * * * * CYCLES: 34 * * SIZE: 21 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * D8BY5 MAC LDA ]1 ; {4C3B} STA BPAR1 ; {3C2B} STORE ORIG ON ZERO PAGE LSR ; {2C1B} DIVIDE BY TWO ADC #13 ; {2C2B} ADD 13 AS A CORRECTIVE ADC BPAR1 ; {3C2B} ADD ORIGINAL ROR ; {2C1B} ROTATE BITS RIGHT LSR ; {2C1B} DIVIDE BY TWO LSR ; {2C1B} DIVIDE BY TWO ADC BPAR1 ; {3C2B} ADD ORIGINAL ROR ; {2C1B} ROTATE BITS RIGHT ADC BPAR1 ; {3C2B} ADD ORIGINAL VALUE ROR ; {2C1B} ROTATE BITS RIGHT LSR ; {2C1B} DIVIDE BY TWO LSR ; {2C1B} DIVIDE BY TWO <<< * ``` --- ### THE D8BY6 MACRO _SUMMARY_ | Condition | Value | | --------------- | ---------------------------- | | Name | `D8BY6` | | Type | Macro | | File | `MAC.D8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Divide an 8-bit value by six | | Input | ]1 = Number to divide | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 36 | | Bytes | 21 | | Notes | None | | See Also | `M8BY6` `M16BY6` | --- *DETAILS* The `DIV8BY6` macro divides a given 8-bit number by six. `LISTING 4.15: D8BY5 Macro Source` ```assembly * *``````````````````````````````* * D8BY6 (NATHAN RIGGS) * * * * DIVIDE 8-BIT NUMBER BY SIX * * * * PARAMETERS * * * * ]1 = NUMBER TO DIVIDE * * * * CYCLES: 36 * * SIZE: 21 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * D8BY6 MAC LDA ]1 ; {4C3B} CLC ; {2C1B} LSR ; {2C1B} DIVIDE .A BY TWO STA BPAR1 ; {3C2B} STORE IN ZERO PAGE LSR ; {2C1B} DIVIDE AGAIN LSR ; {2C1B} DIVIDE AGAIN ADC BPAR1 ; {3C2B} ADD VALUE/2 ROR ; {2C1B} ROTATE BITS RIGHT LSR ; {2C1B} DIVIDE BY TWO ADC BPAR1 ; {3C2B} ADD VALUE/2 ROR ; {2C1B} ROTATE RIGHT LSR ; {2C1B} DIVIDE BY TWO ADC BPAR1 ; {3C2B} ADD VALUE/2 ROR ; {2C1B} ROTATE BITS RIGHT LSR ; {2C1B} DIVIDE BY TWO <<< * ``` --- ### THE D8BY7 MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------ | | Name | `D8BY7` | | Type | Macro | | File | `MAC.D8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Divide an 8-bit value by seven | | Input | ]1 = Number to divide | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 33 | | Bytes | 19 | | Notes | None | | See Also | `M8BY7` `M16BY7` | --- *DETAILS* The `DIV8BY7` macro divides a given 8-bit number by seven. `LISTING 4.16: D8BY7 Macro Source` ```assembly * *``````````````````````````````* * D8BY7 (NATHAN RIGGS) * * * * DIVIDE 8-BIT NUMBER BY SEVEN * * * * PARAMETERS * * * * ]1 = NUMBER TO DIVIDE * * * * CYCLES: 33 * * SIZE: 19 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * D8BY7 MAC LDA ]1 ; {4C3B} CLC ; {2C1B} CLEAR CARRY STA BPAR1 ; {3C2B} STORE NUMBER IN ZERO PAGE LSR ; {2C1B} DIVIDE .A BY TWO LSR ; {2C1B} AGAIN LSR ; {2C1B} AGAIN ADC BPAR1 ; {3C2B} ADD ORIGINAL NUMBER ROR ; {2C1B} ROTATE BITS RIGHT LSR ; {2C1B} DIVIDE BY TWO LSR ; {2C1B} DIVIDE BY TWO ADC BPAR1 ; {3C2B} ADD ORIGINAL NUMBER ROR ; {2C1B} ROTATE BITS RIGHT LSR ; {2C1B} DIVIDE BY TWO LSR ; {2C1B} DIVIDE BY TWO <<< * ``` --- ### THE D8BY8 MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------ | | Name | `D8BY8` | | Type | Macro | | File | `MAC.D8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Divide an 8-bit value by eight | | Input | ]1 = Number to divide | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 10 | | Bytes | 6 | | Notes | None | | See Also | `M8BY8` `M16BY8` | --- *DETAILS* The `DIV8BY8` macro divides a given 8-bit number by eight. `LISTING 4.17: D8BY8 Macro Source` ```assembly * *``````````````````````````````* * D8BY8 (NATHAN RIGGS) * * * * DIVIDE 8-BIT NUMBER BY EIGHT * * * * PARAMETERS * * * * ]1 = NUMBER TO DIVIDE * * * * CYCLES: 10 * * SIZE: 6 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * D8BY8 MAC LDA ]1 ; {4C3B} LSR ; {2C1B} DIVIDE .A BY TWO (2) LSR ; {2C1B} DIVIDE BY TWO (4) LSR ; {2C1B} DIVIDE BY TWO (8) <<< * ``` --- ### THE D8BY9 MACRO _SUMMARY_ | Condition | Value | | --------------- | ----------------------------- | | Name | `D8BY9` | | Type | Macro | | File | `MAC.D8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Divide an 8-bit value by nine | | Input | ]1 = Number to divide | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 36 | | Bytes | 21 | | Notes | None | | See Also | `M8BY9` `M16BY9` | --- *DETAILS* The `DIV8BY9` macro divides a given 8-bit number by nine. `LISTING 4.18: D8BY9 Macro Source` ```assembly * *``````````````````````````````* * D8BY9 (NATHAN RIGGS) * * * * DIVIDE 8-BIT NUMBER BY NINE * * * * PARAMETERS * * * * ]1 = NUMBER TO DIVIDE * * * * CYCLES: 36 * * SIZE: 21 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * D8BY9 MAC LDA ]1 ; {4C3B} CLC ; {2C1B} CLEAR CARRY STA BPAR1 ; {3C2B} STORE .A IN ZERO PAGE LSR ; {2C1B} DIVIDE .A BY TWO LSR ; {2C1B} AGAIN LSR ; {2C1B} AGAIN ADC BPAR1 ; {3C2B} ADD ORIGINAL NUMBER ROR ; {2C1B} ROTATE BITS RIGHT ADC BPAR1 ; {3C2B} ADD ORIGINAL NUMBER ROR ; {2C1B} ROTATE BITS RIGHT ADC BPAR1 ; {3C2B} ADD ORIGINAL NUMBER ROR ; {2C1B} ROTATE BITS RIGHT LSR ; {2C1B} DIVIDE BY TWO LSR ; {2C1B} DIVIDE BY TWO LSR ; {2C1B} DIVIDE BY TWO <<< * ``` --- ### THE D8BY10 MACRO _SUMMARY_ | Condition | Value | | --------------- | ---------------------------- | | Name | `D8BY10` | | Type | Macro | | File | `MAC.D8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Divide an 8-bit value by ten | | Input | ]1 = Number to divide | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 36 | | Bytes | 21 | | Notes | None | | See Also | `M8BY10` `M16BY10` | --- *DETAILS* The `DIV8BY10` macro divides a given 8-bit number by ten. `LISTING 4.19: D8BY10 Macro Source` ```assembly * *``````````````````````````````* * D8BY10 (NATHAN RIGGS) * * * * DIVIDE 8-BIT NUMBER BY TEN * * * * PARAMETERS * * * * ]1 = NUMBER TO DIVIDE * * * * CYCLES: 36 * * SIZE: 21 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * D8BY10 MAC CLC ; {2C1B} CLEAR CARRY LDA ]1 ; {4C3B} LSR ; {2C1B} DIVIDE .A BY TWO STA BPAR1 ; {3C2B} STORE IN ZERO PAGE LSR ; {2C1B} DIVIDE .A BY TWO ADC BPAR1 ; {3C2B} ADD ORIGINAL/2 ROR ; {2C1B} ROTATE BITS RIGHT LSR ; {2C1B} DIVIDE BY TWO LSR ; {2C1B} DIVIDE BY TWO ADC BPAR1 ; {3C2B} ADD ORIGINAL/2 ROR ; {2C1B} ROTATE BITS RIGHT ADC BPAR1 ; {3C2B} ADD ORIGINAL/2 ROR ; {2C1B} ROTATE BITS RIGHT LSR ; {2C1B} DIVIDE BY TWO LSR ; {2C1B} DIVIDE BY TWO <<< ``` --- ### Math By Constants Macros: 8-bit Multiplication These macros are dedicated to multiplying a given 8-bit number by a known constant. Since the constant is known, we are able to precisely measure the number of cycles and bytes needed for the operation, and it takes significantly fewer of both to return a result than would using a general purpose multiplication implementation. It should be noted that these macros do not take sign into consideration, and there are no plans to make wrappers for the math-by macros; only unsigned numbers are accepted. For signed operations, either use the general purpose division macros or create wrappers specific to each divide-by-constant macro. In the comments of each macro, a formula is provided that shows, mathematically, how the algorithm works. In simple terms: since the 6502 runs on binary, it can divide and multiply only by two on its own. Thus, any division or multiplication ultimately has to reduce an equation to factors of two, plus or minus the original value passed at times. `LISTING 4.20: MAC.D8BY.ASM Header Source` ```assembly * *``````````````````````````````* * MAC.M8BY.ASM * * * * THESE MACROS ARE FOR QUICKLY * * CALCULATING A NUMBER BY A * * CONSTANT VALUE. THIS IS * * OFTEN FASTER THAN THE ALL- * * PURPOSE IMPLEMENTATIONS DUE * * TO KNOWING EXACTLY HOW MANY * * SHIFTS AND ROTATES ARE * * NEEDED, ADDITIONS, ETC. * * * * NOTE THAT THIS IS FOR 8-BIT * * VALUES ONLY, AND ALL ANSWERS * * ARE RETURNED IN THE .A * * REGISTER. .X IS SOMETIMES * * DESTROYED AS WELL. * * * * AUTHOR: NATHAN RIGGS * * CONTACT: NATHAN.RIGGS@ * * OUTLOOK.COM * * * * DATE: 29-MAR-2021 * * ASSEMBLER: MERLIN 8 PRO * * OS: DOS 3.3 * * * * LIST OF MACROS * * * * M8BY2 : MULTIPLY BY TWO * * M8BY3 : MULTIPLY BY THREE * * M8BY4 : MULTIPLY BY FOUR * * M8BY5 : MULTIPLY BY FIVE * * M8BY6 : MULTIPLY BY SIX * * M8BY7 : MULTIPLY BY SEVEN * * M8BY8 : MULTIPLY BY EIGHT * * M8BY9 : MULTIPLY BY NINE * * M8BY10 : MULTIPLY BY TEN * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ``` --- ### THE M8BY2 MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------ | | Name | `M8BY2` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply an 8-bit value by two | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 6 | | Bytes | 4 | | Notes | None | | See Also | `D8BY2` `M16BY2` | --- *DETAILS* The `MUL8BY2` macro multiplies a given 8-bit number by two. `LISTING 4.21: M8BY2 Macro Source` ```assembly * *``````````````````````````````* * M8BY2 (NATHAN RIGGS) * * * * MULTIPLY AN 8-BIT VALUE BY * * TWO. ONLY RETURNS 8-BIT * * PRODUCTS. * * * * PARAMETERS * * * * ]1 = NUMBER TO MULTIPLY * * * * CYCLES: 6 * * SIZE: 4 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * M8BY2 MAC LDA ]1 ; {4C3B} LOAD NUMBER ASL ; {2C1B} SHIFT LEFT TO MUL BY 2 ; ANSWER HELD IN .A REGISTER <<< * ``` --- ### THE M8BY3 MACRO _SUMMARY_ | Condition | Value | | --------------- | -------------------------------- | | Name | `M8BY3` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply an 8-bit value by three | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 6 | | Bytes | 4 | | Notes | None | | See Also | `D8BY3` `M16BY3` | --- *DETAILS* The `MUL8BY3` macro multiplies a given 8-bit number by three. `LISTING 4.22: M8BY3 Macro Source` ```assembly * *``````````````````````````````* * M8BY3 (NATHAN RIGGS) * * * * MULTIPLY AN 8-BIT VALUE BY * * THREE. ONLY RETURNS 8-BIT * * PRODUCTS. * * * * PARAMETERS * * * * ]1 = NUMBER TO MULTIPLY * * * * CYCLES: 13 * * SIZE: 9 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * M8BY3 MAC LDA ]1 ; {4C3B} LOAD NUMBER STA BPAR1 ; {3C2B} BACKUP IN BPAR1 ASL ; {2C1B} MUL 1ST ARGUMENT BY 2 CLC ; {2C1B} CLEAR CARRY ADC BPAR1 ; {2C2B} ADD ORIGINAL NUMBER ; ANSWER HELD IN .A REGISTER <<< * ``` --- ### THE M8BY4 MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------- | | Name | `M8BY4` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply an 8-bit value by four | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 8 | | Bytes | 5 | | Notes | None | | See Also | `D8BY4` `M16BY4` | --- *DETAILS* The `MUL8BY4` macro multiplies a given 8-bit number by four. `LISTING 4.23: M8BY4 Macro Source` ```assembly * *``````````````````````````````* * M8BY4 (NATHAN RIGGS) * * * * MULTIPLY AN 8-BIT VALUE BY * * FOUR. ONLY RETURNS 8-BIT * * PRODUCTS. * * * * PARAMETERS * * * * ]1 = NUMBER TO MULTIPLY * * * * CYCLES: 8 * * SIZE: 5 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * M8BY4 MAC LDA ]1 ; {4C3B} LOAD NUMBER INTO .A ASL ; {2C1B} MULTIPLY BY TWO ASL ; {2C1B} MUL AGAIN BY TWO (SO, FOUR) ; ANSWER HELD IN .A <<< * ``` --- ### THE M8BY5 MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------- | | Name | `M8BY5` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply an 8-bit value by five | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 15 | | Bytes | 10 | | Notes | None | | See Also | `D8BY5` `M16BY5` | --- *DETAILS* The `MUL8BY5` macro multiplies a given 8-bit number by five. `LISTING 4.25: M8BY5 Macro Source` ```assembly * *``````````````````````````````* * M8BY5 (NATHAN RIGGS) * * * * MULTIPLY AN 8-BIT VALUE BY * * FIVE. ONLY RETURNS 8-BIT * * PRODUCTS. * * * * PARAMETERS * * * * ]1 = NUMBER TO MULTIPLY * * * * CYCLES: 15 * * SIZE: 10 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * M8BY5 MAC LDA ]1 ; {4C3B} LOAD NUMBER INTO .A STA BPAR1 ; {3C2B} STORE ORIG VAL IN BPAR1 ASL ; {2C1B} MULTIPLY BY TWO ASL ; {2C1B} MUL BY TWO (SO, FOUR) CLC ; {2C1B} CLEAR CARRY ADC BPAR1 ; {2C2B} ADD ORIGINAL VALUE TO NEW ; ANSWER HELD IN .A <<< * ``` --- ### THE M8BY6 MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------ | | Name | `M8BY6` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply an 8-bit value by six | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 15 | | Bytes | 10 | | Notes | None | | See Also | `D8BY6` `M16BY6` | --- *DETAILS* The `MUL8BY6` macro multiplies a given 8-bit number by six. `LISTING 4.25: M8BY6 Macro Source` ```assembly * *``````````````````````````````* * M8BY6 (NATHAN RIGGS) * * * * MULTIPLY AN 8-BIT VALUE BY * * SIX. ONLY RETURNS 8-BIT * * PRODUCTS. * * * * PARAMETERS * * * * ]1 = NUMBER TO MULTIPLY * * * * CYCLES: 27 * * SIZE: 18 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * M8BY6 MAC LDA ]1 ; {4C3B} LOAD NUMBER INTO .A STA BPAR1 ; {3C2B} STORE ORIG IN BPAR1 ASL ; {2C1B} MULTIPLY .A BY TWO ASL ; {2C1B} DO AGAIN TO MUL BY FOUR TAX ; {2C1B} TRANSFER ANSWER INTO .X LDA BPAR1 ; {3C2B} RELOAD ORIGINAL IN .A ASL ; {2C1B} MULTIPLY BY TWO STA BPAR1 ; {3C2B} STORE BACK INTO BPAR1 TXA ; {2C1B} TRANSFER .X BACK TO .A CLC ; {2C1B} CLEAR THE CARRY ADC BPAR1 ; {2C3B} ADD SECOND ARGUMENT ANSWER <<< * ``` --- ### THE M8BY7 MACRO _SUMMARY_ | Condition | Value | | --------------- | -------------------------------- | | Name | `M8BY7` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply an 8-bit value by seven | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 133 | | Bytes | 20 | | Notes | None | | See Also | `D8BY7` `M16BY7` | --- *DETAILS* The `MUL8BY7` macro multiplies a given 8-bit number by seven. `LISTING 4.28: M8BY7 Macro Source` ```assembly * *``````````````````````````````* * M8BY7 (NATHAN RIGGS) * * * * MULTIPLY AN 8-BIT VALUE BY * * SEVEN. ONLY RETURNS 8-BIT * * PRODUCTS. * * * * PARAMETERS * * * * ]1 = NUMBER TO MULTIPLY * * * * CYCLES: 33 * * SIZE: 20 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * M8BY7 MAC LDA ]1 ; {4C3B} LOAD NUMBER INTO .A STA BPAR1 ; {3C2B} STORE IN ZERO PAGE ASL ; {2C1B} MULTIPLY NUM BY TWO ASL ; {2C1B} AND AGAIN, SO BY FOUR CLC ; {2C1B} CLEAR CARRY ADC BPAR1 ; {3C2B} ADD ORIGINAL NUMBER TO VALUE TAX ; {2C1B} TEMPORARY TRANSFER TO .X LDA BPAR1 ; {3C2B} LOAD ORIGINAL NUMBER IN .A ASL ; {2C1B} MULTIPLY BY TWO STA BPAR1 ; {3C2B} STORE IN ZERO PAGE TXA ; {2C1B} TRANSFER .X BACK INTO .A CLC ; {2C1B} CLEAR CARRY ADC BPAR1 ; {3C2B} ADD OTHER ARGUMENT SAVED IN MEM ; ANSWER IS HELD IN .A REGISTER <<< * ``` --- ### THE M8BY8 MACRO _SUMMARY_ | Condition | Value | | --------------- | -------------------------------- | | Name | `M8BY8` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply an 8-bit value by eight | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 10 | | Bytes | 6 | | Notes | None | | See Also | `D8BY8` `M16BY8` | --- *DETAILS* The `MUL8BY8` macro multiplies a given 8-bit number by eight. `LISTING 4.29: M8BY8 Macro Source` ```assembly * *``````````````````````````````* * M8BY8 (NATHAN RIGGS) * * * * MULTIPLY AN 8-BIT VALUE BY * * EIGHT. ONLY RETURNS 8-BIT * * PRODUCTS. * * * * PARAMETERS * * * * ]1 = NUMBER TO MULTIPLY * * * * CYCLES: 10 * * SIZE: 6 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * M8BY8 MAC LDA ]1 ; {4C3B} LOAD NUMBER INTO .A ASL ; {2C1B} MULTIPLY BY TWO ASL ; {2C1B} MULTIPLY BY 2 (SO FOUR) ASL ; {2C1B} MULTIPLY BY 2 (SO EIGHT) ; ANSWER IS HELD IN THE .A REGISTER <<< * ``` --- ### THE M8BY9 MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------- | | Name | `M8BY9` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply an 8-bit value by nine | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 18 | | Bytes | 11 | | Notes | None | | See Also | `D8BY9` `M16BY9` | --- *DETAILS* The `MUL8BY9` macro multiplies a given 8-bit number by nine. `LISTING 4.30: M8BY9 Macro Source` ```assembly * *``````````````````````````````* * M8BY9 (NATHAN RIGGS) * * * * MULTIPLY AN 8-BIT VALUE BY * * NINE. ONLY RETURNS 8-BIT * * PRODUCTS. * * * * PARAMETERS * * * * ]1 = NUMBER TO MULTIPLY * * * * CYCLES: 18 * * SIZE: 11 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * M8BY9 MAC LDA ]1 ; {4C3B} LOAD NUMBER INTO .A STA BPAR1 ; {3C2B} TEMPORARY HOLD IN ZERO PAGE ASL ; {2C1B} MULTIPLY BY 2 (2) ASL ; {2C1B} MULTIPLY BY 2 (4) ASL ; {2C1B} MULTIPLY BY 2 (8) CLC ; {2C1B} CLEAR CARRY ADC BPAR1 ; {3C2B} ADD ORIGINAL VALUE ; ANSWER IS HELD IN .A REGISTER <<< * ``` --- ### THE M8BY10 MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------ | | Name | `M8BY10` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply an 8-bit value by ten | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 18 | | Bytes | 11 | | Notes | None | | See Also | `D8BY10` `M16BY10` | --- *DETAILS* The `MUL8BY10` macro multiplies a given 8-bit number by ten. `LISTING 4.30: M8BY10 Macro Source` ```assembly * *``````````````````````````````* * M8BY10 (NATHAN RIGGS) * * * * MULTIPLY AN 8-BIT VALUE BY * * TEN. ONLY RETURNS 8-BIT * * PRODUCTS. * * * * PARAMETERS * * * * ]1 = NUMBER TO MULTIPLY * * * * CYCLES: 18 * * SIZE: 11 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * M8BY10 MAC LDA ]1 ; {4C3B} LOAD NUMBER INTO .A STA BPAR1 ; {3C2B} STORE IT IN ZERO PAGE ASL ; {2C1B} MULTIPLY BY TWO (2) ASL ; {2C1B} MULTIPLY BY TWO (4) CLC ; {2C1B} CLEAR CARRY ADC BPAR1 ; {3C2B} ADD ORIGINAL NUMBER TO VALUE ASL ; {2C1B} AND MULTIPLY TOTAL BY TWO ; ANSWER IS HELD IN .A REGISTER <<< * ``` --- ### Math By Constants Macros: 16-bit Multiplication These macros are dedicated to multiplying a given 16-bit number by a known constant. Since the constant is known, we are able to precisely measure the number of cycles and bytes needed for the operation, and it takes significantly fewer of both to return a result than would using a general purpose multiplication implementation. It should be noted that these macros do not take sign into consideration, and there are no plans to make wrappers for the math-by macros; only unsigned numbers are accepted. For signed operations, either use the general purpose division macros or create wrappers specific to each divide-by-constant macro. In the comments of each macro, a formula is provided that shows, mathematically, how the algorithm works. In simple terms: since the 6502 runs on binary, it can divide and multiply only by two on its own. Thus, any division or multiplication ultimately has to reduce an equation to factors of two, plus or minus the original value passed at times. `LISTING 4.40: MAC.D8BY.ASM Header Source` ```assembly * *``````````````````````````````* * MAC.M16BY.ASM * * * * THESE MACROS ARE FOR FASTER * * MULTIPLICATION THROUGH USE * * OF KNOWN CONSTANTS. THIS WAY * * IS FASTER THAN USUAL ALL- * * PURPOSE IMPLEMENTATIONS DUE * * TO CYCLES SAVED FROM NO * * LOOPS, TRACKING, ETC., AND * * ARE MEANT AS A POSSIBLE * * ALTERNATIVE TO THE REGULAR * * MULTIPLICATION ROUTINE IF * * NECESSARY. * * * * NOTE THAT THIS IS FOR 16-BIT * * NUMBERS. ADDITIONALLY, THE * * FINAL ANSWER IS PLACED IN * * THE .X REGISTER (HIGH BYTE) * * AND .Y REGISTER (LOW BYTE). * * * * AUTHOR: NATHAN RIGGS * * CONTACT: NATHAN.RIGGS@ * * OUTLOOK.COM * * * * DATE: 25-MAR-2021 * * ASSEMBLER: MERLIN 8 PRO * * OS: DOS 3.3 * * * * LIST OF MACROS * * * * MBY2 : MULTIPLY BY TWO * * MBY3 : MULTIPLY BY THREE * * MBY4 : MULTIPLY BY FOUR * * MBY5 : MULTIPLY BY FIVE * * MBY6 : MULTIPLY BY SIX * * MBY7 : MULTIPLY BY SEVEN * * MBY8 : MULTIPLY BY EIGHT * * MBY9 : MULTIPLY BY NINE * * MBY10 : MULTIPLY BY TEN * * MBY1H : MULTIPLY BY 100 * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ``` --- ### THE M16BY2 MACRO _SUMMARY_ | Condition | Value | | --------------- | ---------------------------- | | Name | `M16BY2` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply a 16-bit value by 2 | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 20 | | Bytes | 13 | | Notes | None | | See Also | `D8BY2` `M8BY2` | --- *DETAILS* The `MUL16BY2` macro multiplies a given 16-bit number by two. `LISTING 4.41: M16BY2 Macro Source` ```assembly * *``````````````````````````````* * MBY2 (NATHAN RIGGS) * * * * MULTIPLY A 16-BIT NUMBER BY * * TWO. * * * * PARAMETERS * * * * ]1 = NUMBER ADDRESS * * * * CYCLES: 20 * * SIZE: 13 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * MBY2 MAC LDA ]1 ; {4C3B} LOAD LOW BYTE IN .A ASL ; {2C1B} MULTIPLY IT BY TWO STA WPAR1 ; {3C2B} STORE ON ZERO PAGE LDA ]1+1 ; {4C3B} LOAD NUMBER HIGH BYTE ROL ; {2C1B} ADJUST FOR CARRY AND MULTIPLY TAX ; {2C1B} TRANSFER HIGH BYTE TO .X REGISTER LDA WPAR1 ; {3C2B} HOLD LOW BYTE IN .A <<< * ``` --- ### THE M16BY3 MACRO _SUMMARY_ | Condition | Value | | --------------- | ---------------------------- | | Name | `M16BY3` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply a 16-bit value by 3 | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 47 | | Bytes | 32 | | Notes | None | | See Also | `D8BY3` `M8BY3` | --- *DETAILS* The `MUL16BY2` macro multiplies a given 16-bit number by three. `LISTING 4.42: M16BY3 Macro Source` ```assembly * *``````````````````````````````* * MBY3 (NATHAN RIGGS) * * * * MULTIPLY A 16-BIT NUMBER BY * * THREE. * * * * FORMULA: 3X = 2X +X * * * * PARAMETERS * * * * ]1 = NUMBER ADDRESS * * * * CYCLES: 47 * * SIZE: 32 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * MBY3 MAC LDA ]1 ; {4C3B} LOAD NUMBER LOW BYTE STA WPAR1 ; {3C2B} STORE IT ON ZERO PAGE ASL ; {2C1B} NOW MULTIPLY BY TWO STA WPAR2 ; {3C2B} STORE IN 2ND ZERO PAGE LOC LDA ]1+1 ; {4C3B} GET NUMBER HIGH BYTE STA WPAR1+1 ; {3C2B} STORE HIGH BYTE ON ZERO PAGE ROL ; {2C1B} ADJUST FOR CARRY AND MULTIPLY STA WPAR2+1 ; {3C2B} STORE HIGH BYTE IN 2ND LOCATION LDA WPAR1 ; {4C3B} LOAD ORIGINAL NUMBER IN .A CLC ; {2C2B} CLEAR CARRY ADC WPAR2 ; {3C2B} ADD SECOND NUMBER TO ORIGINAL STA WPAR1 ; {3C2B} STORE LOW BYTE IN ZERO PAGE LDA WPAR1+1 ; {3C2B} LOAD NUMBER HIGH BYTE IN .A ADC WPAR2+1 ; {3C2B} ADD 2ND VALUE HIGH BYTE TO IT TAX ; {2C1B} TRANSFER NEW HIGH BYTE TO .X LDA WPAR1 ; {3C2B} RELOAD LOW BYTE IN .A <<< * ``` --- ### THE M16BY4 MACRO _SUMMARY_ | Condition | Value | | --------------- | ---------------------------- | | Name | `M16BY4` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply a 16-bit value by 4 | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 37 | | Bytes | 24 | | Notes | None | | See Also | `D8BY4` `M8BY4` | --- *DETAILS* The `MUL16BY4` macro multiplies a given 16-bit number by four. `LISTING 4.43: M16BY4 Macro Source` ```assembly * *``````````````````````````````* * MBY4 (NATHAN RIGGS) * * * * MULTIPLY A 16-BIT NUMBER BY * * FOUR. * * * * PARAMETERS * * * * ]1 = NUMBER ADDRESS * * * * CYCLES: 37 * * SIZE: 24 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * MBY4 MAC LDA ]1 ; {4C3B} LOAD NUMBER LOW BYTE TO .A ASL ; {2C1B} MULTIPLY BY TWO STA BPAR1 ; {3C2B} STORE LOW BYTE TO ZERO PAGE LDA ]1+1 ; {4C3B} LOAD NUMBER HIGH BYTE ROL ; {2C1B} ADJUST FOR CARRY AND MUL TAX ; {2C1B} TRANSFER HIGH BYTE TO .X LDA BPAR1 ; {4C3B} RELOAD LOW BYTE ASL ; {2C1B} MULTIPLY AGAIN STA BPAR1 ; {4C3B} STORE BACK ON ZERO PAGE TXA ; {2C1B} TRANSFER HIGH BYTE BACK TO .A ROL ; {2C1B} ADJUST FOR CARRY AND MULTIPLY TAX ; {2C1B} TRANSFER HIGH BYTE BACK TO .X LDA BPAR1 ; {4C3B} RELOAD LOW BYTE IN .A <<< * ``` --- ### THE M16BY5 MACRO _SUMMARY_ | Condition | Value | | --------------- | ---------------------------- | | Name | `M16BY5` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply a 16-bit value by 5 | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 46 | | Bytes | 30 | | Notes | None | | See Also | `D8BY5` `M8BY5` | --- *DETAILS* The `MUL16BY5` macro multiplies a given 16-bit number by five. `LISTING 4.44: M16BY5 Macro Source` ```assembly * *``````````````````````````````* * MBY5 (NATHAN RIGGS) * * * * MULTIPLY A 16-BIT NUMBER BY * * FIVE. * * * * FORMULA: 5X = 4X + X * * * * PARAMETERS * * * * ]1 = NUMBER ADDRESS * * * * CYCLES: 46 * * SIZE: 30 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * MBY5 MAC LDA ]1 ; {4C3B} LOAD NUMBER LOW BYTE ASL ; {2C1B} MULTIPLY BY TWO STA WPAR1 ; {3C2B} STORE ON ZERO PAGE LDA ]1+1 ; {4C3B} LOAD NUMBER HIGH BYTE ROL ; {2C1B} APPLY CARRY AND MULTIPLY STA WPAR1+1 ; {3C2B} STORE ON ZERO PAGE ASL WPAR1 ; {2C1B} MULTIPLY LOW BYTE BY TWO AGAIN ROL WPAR1+1 ; {2C1B} AND HIGH BYTE AGAIN LDA WPAR1 ; {4C3B} LOAD LOW BYTE INTO .A CLC ; {2C1B} CLEAR THE CARRY ADC ]1 ; {3C2B} ADD ORIGINAL VALUE STA WPAR1 ; {3C2B} STORE ON ZERO PAGE LDA WPAR1+1 ; {3C2B} LOAD HIGH BYTE IN .A ADC ]1+1 ; {4C3B} ADD ORIGINAL HIGH BYTE TAX ; {2C1B} TRANSFER HIGH BYTE TO .X LDA WPAR1 ; {3C2B} LOAD LOW BYTE BACK IN .A <<< * ``` --- ### THE M16BY6 MACRO _SUMMARY_ | Condition | Value | | --------------- | ---------------------------- | | Name | `M16BY6` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply a 16-bit value by 6 | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 58 | | Bytes | 38 | | Notes | None | | See Also | `D8BY6` `M8BY6` | --- *DETAILS* The `MUL16BY6` macro multiplies a given 16-bit number by six. `LISTING 4.45: M16BY6 Macro Source` ```assembly * *``````````````````````````````* * MBY6 (NATHAN RIGGS) * * * * MULTIPLY A 16-BIT NUMBER BY * * SIX. * * * * FORMULA: 6X = 2(2X + X) * * * * PARAMETERS * * * * ]1 = NUMBER ADDRESS * * * * CYCLES: 58 * * SIZE: 38 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * MBY6 MAC LDA ]1 ; {4C3B} LOAD NUMBER LOW BYTE ASL ; {2C1B} MULTIPLY BY TWO STA WPAR1 ; {3C2B} STORE ON ZERO PAGE LDA ]1+1 ; {4C3B} LOAD HIGH BYTE ROL ; {2C1B} ADJUST CARRY AND MULTIPLY STA WPAR1+1 ; {3C2B} STORE ON ZERO PAGE LDA WPAR1 ; {3C2B} RELOAD LOW BYTE IN .A CLC ; {2C1B} CLEAR THE CARRY ADC ]1 ; {4C3B} ADD ORIGINAL LOW BYTE STA WPAR1 ; {3C2B} STORE BACK ON ZERO PAGE LDA WPAR1+1 ; {3C2B} LOAD HIGH BYTE AGAIN ADC ]1+1 ; {4C3B} ADD ORIGINAL HIGH BYTE STA WPAR1+1 ; {3C2B} STORE ON ZERO PAGE LDA WPAR1 ; {3C2B} LOAD LOW BYTE AGAIN ASL ; {2C1B} MULTIPLY BY TWO STA WPAR1 ; {3C2B} STORE ON ZERO PAGE LDA WPAR1+1 ; {3C2B} LOAD HIGH BYTE ROL ; {2C1B} APPLY CARRY AND MULTIPLY TAX ; {2C1B} HOLD HIGH BYTE IN .X LDA WPAR1 ; {3C2B} RELOAD LOW BYTE IN .A <<< * ``` --- ### THE M16BY7 MACRO _SUMMARY_ | Condition | Value | | --------------- | ---------------------------- | | Name | `M16BY7` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply a 16-bit value by 7 | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 72 | | Bytes | 47 | | Notes | None | | See Also | `D8BY7` `M8BY7` | --- *DETAILS* The `MUL16BY7` macro multiplies a given 16-bit number by seven. `LISTING 4.46: M16BY7 Macro Source` ```assembly * *``````````````````````````````* * MBY7 (NATHAN RIGGS) * * * * MULTIPLY A 16-BIT NUMBER BY * * SEVEN. * * * * FORMULA: 7X = 4X + 2X + X * * * * PARAMETERS * * * * ]1 = NUMBER ADDRESS * * * * CYCLES: 72 * * SIZE: 47 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * MBY7 MAC LDA ]1 ; {4C3B} LOAD NUMBER LOW BYTE IN .A ASL ; {2C1B} MULTIPLY BY TWO STA WPAR1 ; {3C2B} STORE IN ZERO PAGE STA WPAR2 ; {3C2B} STORE IN 2ND ZP LOCATION LDA ]1+1 ; {4C3B} LOAD NUMBER HIGH BYTE ROL ; {2C1B} APPLY CARRY AND MULTIPLY STA WPAR1+1 ; {3C2B} STORE IN 1ST ZP HIGH BYTE LOC STA WPAR2+1 ; {3C2B} STORE IN 2ND ZP HIGH BYTE LOC ASL WPAR1 ; {2C1B} MULTIPLY 1ST LOC BY TWO ROL WPAR1+1 ; {2C1B} ALSO HIGH BYTE LDA ]1 ; {4C3B} LOAD ORIGINAL NUMBER CLC ; {2C1B} CLEAR CARRY ADC WPAR1 ; {3C2B} ADD FIRST LOC TO NUMBER LOW BYTE STA WPAR1 ; {3C2B} STORE IN 1ST LOC LDA ]1+1 ; {4C3B} LOAD NUMBER HIGH BYTE ADC WPAR1+1 ; {3C2B} ADD 1ST LOC HIGH BYTE STA WPAR1+1 ; {3C2B} AND STORE IN 1ST LOC LDA WPAR1 ; {3C2B} RELOAD NEW LOW BYTE CLC ; {2C1B} CLEAR CARRY ADC WPAR2 ; {3C2B} ADD SECOND LOC LOW BYTE STA WPAR1 ; {3C2B} STORE IN 1ST LOC LOW BYTE LDA WPAR1+1 ; {3C2B} LOAD 1ST LOC HIGH BYTE ADC WPAR2+1 ; {3C2B} ADD 2ND LOC HIGH BYTE TAX ; {2C1B} HOLD FINAL HIGH BYTE IN .X LDA WPAR1 ; {3C2B} HOLD FINAL LOW BYTE IN .A <<< * ``` --- ### THE M16BY8 MACRO _SUMMARY_ | Condition | Value | | --------------- | ---------------------------- | | Name | `M16BY8` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply a 16-bit value by 8 | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 34 | | Bytes | 21 | | Notes | None | | See Also | `D8BY8` `M8BY8` | --- *DETAILS* The `MUL16BY8` macro multiplies a given 16-bit number by eight. `LISTING 4.47: M16BY8 Macro Source` ```assembly * *``````````````````````````````* * MBY8 (NATHAN RIGGS) * * * * MULTIPLY A 16-BIT NUMBER BY * * EIGHT. * * * * PARAMETERS * * * * ]1 = NUMBER ADDRESS * * * * CYCLES: 34 * * SIZE: 21 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * MBY8 MAC LDA ]1 ; {4C3B} LOAD NUMBER LOW BYTE ASL ; {2C1B} MULTIPLY BY TWO STA WPAR1 ; {3C2B} STORE IN ZP LOC LDA ]1+1 ; {4C3B} LOAD NUMBER HIGH BYTE ROL ; {2C1B} APPLY CARRY AND MUL BY 2 STA WPAR1+1 ; {3C2B} STORE IN ZP LOC ASL WPAR1 ; {2C1B} MULTIPLY LOW BYTE BY 2 ROL WPAR1+1 ; {2C1B} APPLY CARRY, MUL HIGH BY 2 ASL WPAR1 ; {2C1B} MUL LOW BYTE BY 2 LDA WPAR1+1 ; {3C2B} LOAD HIGH BYTE IN .A ROL ; {2C1B} APPLY CARRY AND MUL BY 2 TAX ; {2C1B} HOLD HIGH BYTE IN .X LDA WPAR1 ; {3C2B} HOLD LOW BYTE IN .A <<< * ``` --- ### THE M16BY9 MACRO _SUMMARY_ | Condition | Value | | --------------- | ---------------------------- | | Name | `M16BY9` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply a 16-bit value by 9 | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 62 | | Bytes | 36 | | Notes | None | | See Also | `D8BY9` `M8BY9` | --- *DETAILS* The `MUL16BY9` macro multiplies a given 16-bit number by nine. `LISTING 4.48: M16BY9 Macro Source` ```assembly * *``````````````````````````````* * MBY9 (NATHAN RIGGS) * * * * MULTIPLY A 16-BIT NUMBER BY * * NINE. * * * * FORMULA: 9X = 8X + X * * * * PARAMETERS * * * * ]1 = NUMBER ADDRESS * * * * CYCLES: 62 * * SIZE: 36 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * MBY9 MAC LDA ]1 ; {4C3B} LOAD NUMBER LOW BYTE ASL ; {2C1B} MULTIPLY BY TWO STA WPAR1 ; {3C2B} STORE ON ZERO PAGE LDA ]1+1 ; {4C3B} LOAD NUMBER HIGH BYTE ROL ; {2C1B} APPLY CARRY AND MUL BY 2 STA WPAR1+1 ; {3C2B} STORE ON ZP ASL WPAR1 ; {5C2B} MUL LOW BYTE BY 2 ROL WPAR1+1 ; {5C2B} CARRY AND MUL HIGH BY 2 ASL WPAR1 ; {5C2B} MUL LOW BY 2 ROL WPAR1+1 ; {5C2B} CARRY AND MUL HIGH BY 2 LDA WPAR1 ; {3C2B} LOAD LOW BYTE CLC ; {2C1B} CLEAR CARRY ADC ]1 ; {4C3B} ADD ORIGINAL VALUE STA WPAR1 ; {3C2B} STORE ON ZP LDA WPAR1+1 ; {3C2B} LOAD HIGH BYTE ADC ]1+1 ; {4C3B} ADD ORIGINAL HIGH BYTE TAX ; {2C1B} HOLD FINAL HIGH BYTE IN .X LDA WPAR1 ; {3C2B} HOLD FINAL LOW BYTE IN .A <<< * ``` --- ### THE M16BY10 MACRO _SUMMARY_ | Condition | Value | | --------------- | ----------------------------- | | Name | `M16BY10` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply a 16-bit value by 10 | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 66 | | Bytes | 39 | | Notes | None | | See Also | `D8BY10` `M8BY10` | --- *DETAILS* The `MUL16BY10` macro multiplies a given 16-bit number by ten. `LISTING 4.49: M16BY10 Macro Source` ```assembly * *``````````````````````````````* * MBY10 (NATHAN RIGGS) * * * * MULTIPLY A 16-BIT NUMBER BY * * TEN. * * * * FORMULA: 10X = 2(4X + X) * * * * PARAMETERS * * * * ]1 = NUMBER ADDRESS * * * * CYCLES: 65 * * SIZE: 39 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * MBY10 MAC LDA ]1 ; {4C3B} LOAD NUMBER LOW BYTE ASL ; {2C1B} MUL LOW BYTE BY 2 STA WPAR1 ; {3C2B} STORE ON ZERO PAGE LDA ]1+1 ; {4C3B} LOAD NUMBER HIGH BYTE ROL ; {2C1B} APPLY CARRY AND MUL BY 2 STA WPAR1+1 ; {3C2B} STORE ON ZERO PAGE ASL WPAR1 ; {5C2B} MUL LOW BY 2 ROL WPAR1+1 ; {5C2B} CARRY AND MUL HIGH BY 2 LDA ]1 ; {4C3B} LOAD ORIGINAL LOW BYTE CLC ; {2C1B} CLEAR CARRY ADC WPAR1 ; {3C2B} ADD ZP LOW BYTE STA WPAR1 ; {3C2B} STORE BACK ON ZP LDA ]1+1 ; {4C3B} LOAD ORIGINAL HIGH BYTE ADC WPAR1+1 ; {3C2B} ADD ZP HIGH BYTE STA WPAR1+1 ; {3C2B} STORE BACK ON ZP ASL WPAR1 ; {5C2B} MULTIPLY NEW VAL LOW BY 2 LDA WPAR1+1 ; {3C2B} LOAD HIGH BYTE IN .A ROL ; {2C1B} CARRY AND MUL HIGH BY 2 TAX ; {2C1B} HOLD FINAL HIGH BYTE IN .X LDA WPAR1 ; {3C2B} HOLD FINAL LOW BYTE IN .A <<< * ``` --- ### THE M16BY1H MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------ | | Name | `M16BY100` | | Type | Macro | | File | `MAC.M8BY.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply a 16-bit value by 100 | | Input | ]1 = Number to multiply | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 124 | | Bytes | 70 | | Notes | None | | See Also | none | --- *DETAILS* The `MUL16BY1H` macro multiplies a given 16-bit number by one hundred. `LISTING 4.50: M16BY1H Macro Source` ```assembly * *``````````````````````````````* * MBY1H (NATHAN RIGGS) * * * * MULTIPLY A 16-BIT NUMBER BY * * ONE HUNDRED. * * * * FORMULA: 100X = 4(16X+8X+X) * * * * PARAMETERS * * * * ]1 = NUMBER ADDRESS * * * * CYCLES: 124 * * SIZE: 70 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * MBY1H MAC LDA ]1 ; {4C3B} LOAD NUMBER INTO .A ASL ; {2C1B} MUL LOW BYTE BY 2 STA WPAR2 ; {3C2B} STORE IN ZP LOC 1 LDA ]1+1 ; {4C3B} LOAD NUMBER HIGH BYTE ROL ; {2C1B} CARRY AND MUL BY 2 STA WPAR2+1 ; {3C2B} STORE IN ZP LOC 1 ASL WPAR2 ; {5C2B} MUL ZP LOW BYTE BY 2 ROL WPAR2+1 ; {5C2B} CARRY AND MUL ZP HIGH BY 2 ASL WPAR2 ; {5C2B} MUL LOW BY 2 ROL WPAR2+1 ; {5C2B} MUL HIGH BY 2 LDA WPAR2 ; {3C2B} LOAD LOW BYTE IN .A ASL ; {2C1B} MULTIPLY BY TWO STA WPAR1 ; {3C2B} STORE IN 2ND ZP LOC LDA WPAR2+1 ; {3C2B} LOAD HIGH BYTE IN .A ROL ; {2C1B} CARRY AND MUL BY 2 STA WPAR1+1 ; {3C2B} STORE IN 2ND ZP LOC LDA ]1 ; {4C3B} LOAD ORIGINAL VALUE CLC ; {2C1B} CLEAR CARRY ADC WPAR1 ; {3C2B} ADD LOW BYTE ZP LOC 1 STA WPAR1 ; {3C2B} STORE AT ZP LOC 1 LDA ]1+1 ; {4C3B} LOAD ORIGINAL HIGH BYTE ADC WPAR1+1 ; {3C2B} ADD ZP LOC HIGH STA WPAR1+1 ; {3C2B} STORE BACK AT ZP LOC 1 HIGH LDA WPAR1 ; {3C2B} LOAD LOC 1 LOW BYTE IN .A CLC ; {2C1B} CLEAR CARRY ADC WPAR2 ; {3C2B} ADD 2ND ZP LOC LOW BYTE STA WPAR1 ; {3C2B} STORE IN LOC 1 LOW LDA WPAR1+1 ; {3C2B} LOAD ZP LOC 1 HIGH BYTE ADC WPAR2+1 ; {3C2B} ADD 2ND LOC HIGH BYTE STA WPAR1+1 ; {3C2B} STORE BACK IN ZP LOC 1 HIGH ASL WPAR1 ; {5C2B} MULTIPLY THAT VALUE LOW BY 2 ROL WPAR1+1 ; {5C2B} CARRY AND MUL HIGH BY 2 LDA WPAR1 ; {3C2B} LOAD LOW BYTE IN .A ASL ; {2C1B} MULTIPLY AGAIN BY TWO STA WPAR1 ; {3C2B} STORE IN ZP LOC 1 LOW LDA WPAR1+1 ; {3C2B} LOAD HIGH BYTE IN .A ROL ; {2C1B} CARRY AND MUL HIGH BY 2 TAX ; {2C1B} HOLD FINAL HIGH BYTE IN .X LDA WPAR1 ; {3C2B} HOLD FINAL LOW BYTE IN .A <<< * ``` --- ### General Purpose Math: 8-bit Procedures These macros are dedicated to adding, subtracting, multiplying or dividing a given 8-bit number by another arbitrary 8-bit number. All values are **unsigned**; wrappers for signed numbers will be provided in a future revision, along with a modulus macro that wraps around `DIV8`. `LISTING 4.60: MAC.MATHBAS.ASM Header Source` ```assembly * *``````````````````````````````* * MAC.MATH8.ASM * * * * AUTHOR: NATHAN RIGGS * * CONTACT: NATHAN.RIGGS@ * * OUTLOOK.COM * * * * DATE: 01-APR-2021 * * ASSEMBLER: MERLIN 8 PRO * * OS: DOS 3.3 * * * * SUBROUTINE FILES USED * * * * SUB.DIVDU8 * * SUB.MULTU8 * * * * LIST OF MACROS * * * * ADD8 : ADD 8BIT NUMBERS * * SUB8 : SUBTRACT 8BIT NUMS * * MUL8 : MULTIPLY 8BIT NUMS * * DIV8 : DIVIDE 8BIT NUMS * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ``` --- ### THE ADD8 MACRO _SUMMARY_ | Condition | Value | | --------------- | -------------------------------------------------------- | | Name | `ADD8` | | Type | Macro | | File | `MAC.MATH8.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Add one 8-bit number to another | | Input | ]1 = first number to add
]2 = second number to add | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 21 | | Bytes | 15 | | Notes | None | | See Also | `SUB8` `ADD16` | --- *DETAILS* The `ADD8` macro adds two arbitrary 8-bit numbers and passes back the sum in the **.A** register and in `RETURN`. Note that this macro, along with `SUB8`, is included as a courtesy to beginners, and they should not be relied on for fast and compact code (bytes and cycles are wasted to keep within the standards of the library). `LISTING 4.61: ADD8 Macro Source` ```assembly * *``````````````````````````````* * ADD8 (NATHAN RIGGS) * * * * DIRTY MACRO TO ADD TWO BYTES * * * * PARAMETERS * * * * ]1 = ADDEND 1 * * ]2 = ADDEND 2 * * * * CYCLES: 21 * * SIZE: 15 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ADD8 MAC LDA #1 ; {3C2B} STA RETLEN ; {4C3B} LDA ]1 ; {4C3B} CLC ; {2C1B} ADC ]2 ; {4C3B} STA RETURN ; {4C3B} <<< * ``` --- ### THE SUB8 MACRO _SUMMARY_ | Condition | Value | | --------------- | ---------------------------------- | | Name | `SUB8` | | Type | Macro | | File | `MAC.MATH8.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Add one 8-bit number to another | | Input | ]1 = Minuend
]2 = Subtrahend | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 21 | | Bytes | 15 | | Notes | None | | See Also | `ADD8` `SUB16` | --- *DETAILS* The `SUB8` macro subtracts one arbitrary 8-bit number from another and passes back the sum in the **.A** register and in `RETURN`. Note that this macro, like with `ADD8`, is included as a courtesy to beginners, and should not be relied on for fast and compact code (bytes and cycles are wasted to keep within the standards of the library). `LISTING 4.62: SUB8 Macro Source` ```assembly * *``````````````````````````````* * SUB8 (NATHAN RIGGS) * * * * MACRO TO SUBTRACT TWO BYTES * * * * PARAMETERS * * * * ]1 = MINUEND * * ]2 = SUBTRAHEND * * * * CYCLES: 21 * * SIZE: 15 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * SUB8 MAC LDA #1 ; {3C2B} STA RETLEN ; {4C3B} LDA ]1 ; {4C3B} SEC ; {2C1B} SBC ]2 ; {4C3B} STA RETURN ; {4C3B} <<< * ``` --- ### THE MUL8 MACRO _SUMMARY_ | Condition | Value | | --------------- | -------------------------------------- | | Name | `MUL8` | | Type | Macro | | File | `MAC.MATH8.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply one 8-bit number by another | | Input | ]1 = Multiplicand
]2 = Multiplier | | Output | none | | Dependencies | `SUB.MULTU8` | | Flags Destroyed | NZCV | | Cycles | 97+ | | Bytes | 56 | | Notes | None | | See Also | `DIV8` `MUL16` | --- *DETAILS* The `MUL8` macro multiplies one 8-bit number by another, passing back the 16-bit product in `RETURN` and in the .A (low byte) and .X (high byte) registers. `LISTING 4.63: MUL8 Macro Source` ```assembly * *``````````````````````````````* * MUL8 (NATHAN RIGGS) * * * * MULTIPLIES TWO 8BIT VALUES * * AND RETURNS A 16BIT RESULT * * IN .A,.X (LOW, HIGH). * * * * PARAMETERS * * * * ]1 = MULTIPLICAND * * ]2 = MULTIPLIER * * * * CYCLES: 97+ * * BYTES: 56 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * MUL8 MAC LDA ]1 ; {4C3B} LDX ]2 ; {4C3B} JSR MULTU8 ; {89C50B} <<< * ``` --- ### THE MULTU8 SUBROUTINE _SUMMARY_ | Condition | Value | | --------------- | -------------------------------------------- | | Name | `MULTU8` | | Type | Subroutine | | File | `SUB.MULTU8.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply one 8-bit number by another | | Input | WPAR1 = Multiplicand
WPAR2 = Multiplier | | Output | none | | Dependencies | `SUB.MULTU8` | | Flags Destroyed | NZCV | | Cycles | 83+ | | Bytes | 47 | | Notes | None | | See Also | `MUL16` | --- *DETAILS* The `MUL8` macro multiplies one 8-bit number by another, passing back the 16-bit product in `RETURN` and in the **.A** (low byte) and **.X** (high byte) registers (`RETLEN` holds 2, the length in bytes of the return value). `LISTING 4.63: MULTU8 Subroutine Source` ```assembly * *``````````````````````````````* * MULTU8 (NATHAN RIGGS) * * * * MULTIPLY TWO 8-BIT NUMBERS. * * * * INPUT: * * * * WPAR1 = MULTIPLIER * * WPAR2 = MULTIPLICAND * * * * DESTROY: NZCIDV * * ^^^ ^ * * * * CYCLES: 83+ * * SIZE: 47 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ]MUL1 EQU WPAR1 ; MULTIPLIER ]MUL2 EQU WPAR2 ; MULTIPLICAND * MULTU8 STA ]MUL1 ; {3C2B} STX ]MUL2 ; {3C2B} LDA #0 ; {3C2B} CLEAR REGISTERS TAY ; {2C1B} TAX ; {2C1B} STA ]MUL1+1 ; {3C2B} CLEAR HIBYTE BEQ :GOLOOP ; {3C2B} :DOADD CLC ; {2C1B} CLEAR CARRY ADC ]MUL1 ; {3C2B} ADD MULTIPLIER TAX ; {2C1B} HOLD IN .Y TYA ; {2C1B} XFER .X TO .A ADC ]MUL1+1 ; {3C2B} ADD MULTIPLIER HIBYTE TAY ; {2C1B} HOLD BACK IN .X TXA ; {2C1B} MOVE LOBYTE INTO .A :LP ASL ]MUL1 ; {5C2B} SHIFT LEFT ROL ]MUL1+1 ; {5C2B} ROLL HIBYTE :GOLOOP LSR ]MUL2 ; {5C2B} SHIFT MULTIPLIER BCS :DOADD ; {3C2B} IF SHIFTED IN CARRY ADD AGAIN BNE :LP ; {3C2B} OTHERWISE, LOOP LDA #2 ; {3C2B} 16-BIT LENGTH, 2 BYTES STA RETLEN ; {4C3B} FOR RETURN LENGTH STX RETURN ; {4C3B} STORE LOBYTE STY RETURN+1 ; {4C3B} STORE HIBYTE TXA ; {2C1B} LOBYTE TO .A LDX RETURN+1 ; {4C3B} HIBYTE TO .X RTS ; {6C1B} ``` --- ### THE DIV8 MACRO _SUMMARY_ | Condition | Value | | --------------- | ---------------------------------- | | Name | `DIV8` | | Type | Macro | | File | `MAC.MATH8.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Divide one 8-bit number by another | | Input | ]1 = Dividend
]2 = Divisor | | Output | none | | Dependencies | `SUB.DIVDU8` | | Flags Destroyed | NZCV | | Cycles | 75+ | | Bytes | 43 | | Notes | None | | See Also | `DIV8` `DIVDU8` | --- *DETAILS* The `DIV8` macro divides one 8-bit number by another, passing back the 8-bit result in `RETURN` and in the .A register. `LISTING 4.65: DIV8 Macro Source` ```assembly * *``````````````````````````````* * DIV8 (NATHAN RIGGS) * * * * DIVIDES ONE 8BIT NUMBER BY * * ANOTHER AND STORES THE * * QUOTIENT IN .A WITH THE * * REMAINDER IN .X. * * * * PARAMETERS * * * * ]1 = DIVIDEND * * ]2 = DIVISOR * * * * CYCLES: 75+ * * SIZE: 43 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * DIV8 MAC LDA ]1 ; {4C3B} LDX ]2 ; {4C3B} JSR DIVDU8 ; {67C37B} <<< * ``` --- ### THE DIVDU8 SUBROUTINE _SUMMARY_ | Condition | Value | | --------------- | ------------------------------------- | | Name | `DIVDU8` | | Type | Subroutine | | File | `SUB.DIVDU8.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Divide one 8-bit number by another | | Input | WPAR1 = Dividend
WPAR2 = Divisor | | Output | none | | Dependencies | `SUB.DIVDU8` | | Flags Destroyed | NZCV | | Cycles | 61+ | | Bytes | 34 | | Notes | None | | See Also | `DIV16` | --- *DETAILS* The `DIVDU8` subroutine divides an 8-bit dividend by an 8-bit divisor, passing back an 8-bit result in the .A register and `RETURN`. Additionally, any remainder is returned in the **.X** register. `LISTING 4.63: SUB8 Macro Source` ```assembly * *``````````````````````````````* * DIVDU8 (NATHAN RIGGS) * * * * DIVIDE WITH TWO 8-BIT VALUES * * * * INPUT: * * * * WPAR1 = DIVIDEND * * WPAR2 = DIVISOR * * * * DESTROY: NZCIDV * * ^^^ ^ * * * * CYCLES: 61+ * * SIZE: 34 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ]DVEND EQU WPAR1 ; DIVIDEND ]DVSOR EQU WPAR2 ; DIVISOR * DIVDU8 STX ]DVEND ; {3C2B} .X HOLDS DIVIDEND STA ]DVSOR ; {3C2B} .A HOLDS DIVISOR LDA #$00 ; {3C2B} CLEAR ACCUMULATOR LDX #8 ; {3C2B} COUNTER ASL ]DVSOR ; {5C2B} SHIFT LEFT DIVISOR :L1 ROL ; {2C1B} ROTATE LEFT .A CMP ]DVEND ; {3C2B} COMPARE TO DIVIDEND BCC :L2 ; {3C2B} IF NEXT BIT = 0, BRANCH :L2 SBC ]DVEND ; {3C2B} OTHERWISE, SUBTRACT DIVIDEND :L2 ROL ]DVSOR ; {5C2B} LEFT DIVISOR DEX ; {2C1B} DECREMENT COUNTER BNE :L1 ; {3C2B} IF > 0, LOOP TAX ; {2C1B} REMAINDER IN .X LDA #1 ; {3C2B} STA RETLEN ; {4C3B} LDA ]DVSOR ; {3C2B} RESULT IN .A STA RETURN ; {4C3B} RTS ; {6C1B} ``` --- ### General Purpose Math: 16-bit Procedures These macros are dedicated to adding, subtracting, multiplying or dividing with two 8-bit or 16-bit numbers, as well as a macro for 16-bit comparisons. All values are **unsigned**; wrappers for signed numbers will be provided in a future revision, along with a modulus macro that wraps around `DIV16`. While these macros and subroutines are adequate for most general purposes, if speed or size is a major concern then it is advised that at least addition and subtraction be done manually, as some bytes and cycles are "wasted" keeping the library's operating principles intact. `LISTING 4.70: MAC.MATHBAS.ASM Header Source` ```assembly * *``````````````````````````````* * MAC.MATH16.ASM * * * * AUTHOR: NATHAN RIGGS * * CONTACT: NATHAN.RIGGS@ * * OUTLOOK.COM * * * * DATE: 01-APR-2021 * * ASSEMBLER: MERLIN 8 PRO * * OS: DOS 3.3 * * * * SUBROUTINE FILES USED * * * * SUB.ADDIT16 * * SUB.COMP16 * * SUB.DIVDU16 * * SUB.MULTU16 * * SUB.SUBT16 * * * * LIST OF MACROS * * * * ADD16 : ADD 16BIT NUMBERS * * SUB16 : SUBTRACT 16BIT NUMS * * MUL16 : MULTIPLY 16BIT NUMS * * DIV16 : DIVIDE 16BIT NUMS * * CMP16 : COMPARE 16BIT NUMS * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ``` --- ### THE ADD16 MACRO _SUMMARY_ | Condition | Value | | --------------- | ----------------------------------------- | | Name | `ADD16` | | Type | Macro | | File | `MAC.MATH16.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Add two 16-bit numbers | | Input | ]1 = First Addend
]2 = Second Addend | | Output | none | | Dependencies | `SUB.ADDIT16` | | Flags Destroyed | NZCV | | Cycles | 78+ | | Bytes | 51 | | Notes | None | | See Also | `ADD8` `ADDIT16` | --- *DETAILS* The `ADD16` macro adds two 16-bit numbers, passing back the 16-bit result in `RETURN` and in the **.A** (low byte) and **.X** (high byte) registers. `LISTING 4.71: ADD16 Macro Source` ```assembly * *``````````````````````````````* * ADD16 (NATHAN RIGGS) * * * * ADD TWO 16BIT VALUES, STORE * * RESULT IN .A, .X (LOW, HIGH) * * * * PARAMETERS * * * * ]1 = ADDEND 1 * * ]2 = ADDEND 2 * * * * CYCLES: 78+ * * SIZE: 51 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ADD16 MAC _MLIT ]1;WPAR1 ; {16C12B} _MLIT ]2;WPAR2 ; {16C12B} JSR ADDIT16 ; {46C27B} <<< * ``` --- ### THE ADDIT16 SUBROUTINE _SUMMARY_ | Condition | Value | | --------------- | ---------------------------------- | | Name | `ADDIT16` | | Type | Subroutine | | File | `SUB.ADDIT16.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Add two 16-bit numbers | | Input | WPAR1 = Augend
WPAR2 = Addend | | Output | none | | Dependencies | `SUB.ADDIT16` | | Flags Destroyed | NZCV | | Cycles | 40+ | | Bytes | 24 | | Notes | None | | See Also | `ADD16` | --- *DETAILS* The `ADDIT16` subroutine adds two 16-bit numbers and passes back a 16-bit sum via `RETURN` and the .A (low byte) and .X (high byte) registers. `RETLEN` holds #2, the byte-length of the return value. `LISTING 4.72: ADDIT16 Macro Source` ```assembly * *``````````````````````````````* * ADDIT16 (NATHAN RIGGS) * * * * ADD TWO 16-BIT VALUES. * * * * INPUT: * * * * WPAR1 = AUGEND * * WPAR2 = ADDEND * * * * * * DESTROY: NZCIDV * * ^^^ ^ * * * * CYCLES: 40 * * SIZE: 24 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ]ADD1 EQU WPAR1 ; FIRST ARGUMENT ]ADD2 EQU WPAR2 ; SECOND ARGUMENT * ADDIT16 LDA #2 ; {2C2B} PUT SUMMAND LENGTH STA RETLEN ; {4C3B} IN RETLEN LDA ]ADD1 ; {3C2B} ADD LOBYTES CLC ; {2C1B} CLEAR CARRY ADC ]ADD2 ; {3C2B} TAY ; {2C1B} TEMPORARY STORE IN .Y LDA ]ADD1+1 ; {3C2B} ADD HIBYTES ADC ]ADD2+1 ; {3C2B} TAX ; {2C1B} STORE IN .X TYA ; {2C1B} XFER LOBYTE TO .A STA RETURN ; {4C3B} ALSO PASS BACK IN RETURN STX RETURN+1 ; {4C3B} TO KEEP CONSISTENT RTS ; {6C1B} ``` --- ### THE SUB16 MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------------- | | Name | `SUB16` | | Type | Macro | | File | `MAC.MATH16.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Subtract a 16-bit number from another | | Input | ]1 = Minuend
]2 = Subtrahend | | Output | none | | Dependencies | `SUB.SUBT16` | | Flags Destroyed | NZCV | | Cycles | 79+ | | Bytes | 51 | | Notes | None | | See Also | `SUB8` `SUBT16` | --- *DETAILS* The `SUB16` macro subtracts one 16-bit number from another, storing the difference in `RETURN` an in the **.A** (low byte) and **.X** (high byte) registers. The byte length of the difference, two, is stored in `RETLEN`. `LISTING 4.73: SUB16 Macro Source` ```assembly * *``````````````````````````````* * SUB16 (NATHAN RIGGS) * * * * SUBTRACTS ONE 16BIT INTEGER * * FROM ANOTHER, STORING THE * * RESULT IN .A, .X (LOW, HIGH) * * * * PARAMETERS * * * * ]1 = MINUEND * * ]2 = SUBTRAHEND * * * * CYCLES: 79+ * * SIZE: 51 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * SUB16 MAC _MLIT ]1;WPAR1 ; {16C12B} _MLIT ]2;WPAR2 ; {16C12B} JSR SUBT16 ; {47C27B} <<< * ``` --- ### THE SUBT16 SUBROUTINE _SUMMARY_ | Condition | Value | | --------------- | --------------------------------------- | | Name | `SUBT16` | | Type | Subroutine | | File | `SUB.SUBT16.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | subtract one 16-bit number from another | | Input | WPAR1 = Minuend
WPAR2 = Subtrahend | | Output | none | | Dependencies | `SUB.SUBT16` | | Flags Destroyed | NZCV | | Cycles | 41+ | | Bytes | 24 | | Notes | None | | See Also | `SUB16` | --- *DETAILS* The `SUBT16` subroutine subtracts one 16-bit number from another, storing the difference in `RETURN` as well as in the .A (low byte) and .X registers (high byte). The byte-length of the return value, two, is held in `RETLEN`. `LISTING 4.74: ADDIT16 Macro Source` ```assembly * *``````````````````````````````* * SUBT16 (NATHAN RIGGS) * * * * SUBTRACT A 16-BIT SUBTRAHEND * * FROM A MINUEND. * * * * INPUT * * * * WPAR1 = MINUEND * * WPAR2 = SUBTRAHEND * * * * DESTROY: NZCIDV * * ^^^ ^ * * * * CYCLES: 41+ * * SIZE: 24 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ]MINU EQU WPAR1 ; MINUEND ]SUBT EQU WPAR2 ; SUBTRAHEND * SUBT16 LDA #2 ; {3C2B} STA RETLEN ; {4C3B} LDA ]MINU ; {3C2B} SUBTRACT SUBTRAHEND SEC ; {2C1B} LOBYTE FROM MINUEND SBC ]SUBT ; {3C2B} LOBYTE TAY ; {2C1B} HOLD LOBYTE IN .Y LDA ]MINU+1 ; {3C2B} SUBTRACT SUBTRAHEND SBC ]SUBT+1 ; {3C2B} HIBYTE FROM MINUEND TAX ; {2C1B} HIGH BYTE, PASS IN .X TYA ; {2C1B} LOBYTE BACK IN .A STA RETURN ; {4C3B} STX RETURN+1 ; {4C3B} RTS ; {6C1B} ``` --- ### THE MUL16 MACRO _SUMMARY_ | Condition | Value | | --------------- | -------------------------------------- | | Name | `SUB16` | | Type | Macro | | File | `MAC.MATH16.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply two 16-bit numbers | | Input | ]1 = Multiplier
]2 = Multiplicand | | Output | none | | Dependencies | `SUB.MULTU16` | | Flags Destroyed | NZCV | | Cycles | 144+ | | Bytes | 91 | | Notes | None | | See Also | `MUL8` `MULT16` | --- *DETAILS* The `MUL16` macro multiplies two 16-bit values, holding the product in `RETURN` with a total byte-length of 4 in `RETLEN` (32-bit product). If the full 32 bits is not needed, the lower 16-bits of the product are held in the **.A** register (low byte) and the **.X** register (high byte). `LISTING 4.75: MUL16 Macro Source` ```assembly * *``````````````````````````````* * MUL16 (NATHAN RIGGS) * * * * MULTIPLIES TWO 16BIT NUMBERS * * AND RETURNS THE PRODUCT IN * *.A, .X (LOW, HIGH). * * * * PARAMETERS * * * * ]1 = MULTIPLICAND * * ]2 = MULTIPLIER * * * * CYCLES: 144+ * * SIZE: 91 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * MUL16 MAC _MLIT ]1;WPAR1 ; {16C12B} _MLIT ]2;WPAR2 ; {16C12B} JSR MULTU16 ; {112C67B} <<< * ``` --- ### THE MULTU16 SUBROUTINE _SUMMARY_ | Condition | Value | | --------------- | -------------------------------------------- | | Name | `MULTU16` | | Type | Subroutine | | File | `SUB.MULTU16.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Multiply two 16-bit numbers | | Input | WPAR1 = Multiplier
WPAR2 = Multiplicand | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 106+ | | Bytes | 64 | | Notes | None | | See Also | `MUL16` | --- *DETAILS* The `MULTu16` subroutine accepts two 16-bit values and multiplies them, passing back the 32-bit product via `RETURN`, with `RETLEN` holding its byte-length, four. Additionally, the bottom two bytes of the product are held in the **.A** (low byte) and **.X** (high byte) registers for faster retrieval if the number is known to be 16 bits. `LISTING 4.76: MULTU16 Subroutine Source` ```assembly * *``````````````````````````````* * MULT16 (NATHAN RIGGS) * * * * MULTIPLY TWO 16-BIT VALUES. * * NOTE THAT THIS ONLY WORKS * * CORRECTLY WITH UNSIGNED * * VALUES. SIGNS MUST BE * * DETERMINED BEFOREHAND. * * * * INPUT: * * * * WPAR1 = MULTIPLICAND * * WPAR2 = MULTIPLIER * * * * DESTROY: NZCIDV * * ^^^ ^ * * * * CYCLES: 106+ * * SIZE: 64 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ]MCAND EQU WPAR1 ; MULTIPLICAND ]MLIER EQU WPAR2 ; MULTIPLIER ]HPROD EQU WPAR3 ; HIGH BYTES OF PRODUCT * MULTU16 LDA #0 ; {3C2B} ZERO OUT TOP TWO STA ]HPROD ; {4C3B} HIGH BYTES OF 32-BIT STA ]HPROD+1 ; {4C3B} RESULT LDX #17 ; {4C3B} # OF BITS IN MLIER PLUS 1 ; FOR LAST CARRY INTO PRODUCT CLC ; {2C1B} CLEAR CARRY FOR 1ST TIME ; THROUGH LOOP. :MLP * ** IF NEXT BIT = 1, HPROD += 1 * ROR ]HPROD+1 ; {5C2B} SHIFT HIGHEST BYTE ROR ]HPROD ; {5C2B} SHIFT 2ND-HIGHEST ROR ]MLIER+1 ; {5C2B} SHIFT 3RD-HIGHEST ROR ]MLIER ; {5C2B} SHIFT LOW BYTE BCC :DX ; {3C2B} BRANCH IF NEXT BIT = 0 CLC ; {2C1B} OTHERWISE NEXT BIT =1, LDA ]MCAND ; {3C2B} SO ADD MCAND TO PRODUCT ADC ]HPROD ; {3C2B} STA ]HPROD ; {3C2B} STORE NEW LOBYTE LDA ]MCAND+1 ; {3C2B} ADC ]HPROD+1 ; {3C2B} STA ]HPROD+1 ; {3C2B} STORE NEW HIBYTE :DX DEX ; {2C1B} DECREASE COUNTER BNE :MLP ; {3C2B} DO MUL LOOP UNTIL .X = 0 * ** NOW STORE IN RETURN, WITH LOWEST TWO ** BYTES ALSO LEFT IN .A (LO) AND .X (HI) * LDA #4 ; {3C2B} LENGTH OF PRODUCT STA RETLEN ; {4C3B} STORED IN RETLEN LDA ]HPROD+1 ; {3C2B} STA RETURN+3 ; {4C3B} LDA ]HPROD ; {3C2B} STA RETURN+2 ; {4C3B} LDX ]MLIER+1 ; {3C2B} STX RETURN+1 ; {4C3B} LDA ]MLIER ; {3C2B} STA RETURN ; {4C3B} RTS ; {6C1B} ``` --- ### THE DIV16 MACRO _SUMMARY_ | Condition | Value | | --------------- | ----------------------------------- | | Name | `DIV16` | | Type | Macro | | File | `MAC.MATH16.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Divide one 16-bit number by another | | Input | ]1 = Dividend
]2 = Divisor | | Output | none | | Dependencies | `SUB.DIVDU16` | | Flags Destroyed | NZCV | | Cycles | 133+ | | Bytes | 81 | | Notes | None | | See Also | `DIV8` `DIVDU16` | --- *DETAILS* The `DIV16` macro divides one 16-bit number by another, storing the 16-bit result in both `RETURN` and in the **.A** (low byte) and **.X** (high) registers. Additionally, any possible remainder is passed back via the **.Y** register. `RETLEN` holds the value 2, which represents the byte-length of the result. Note that no considerations are given for signed numbers in this subroutine. If necessary, a macro wrapper for signed values will be provided in future updates. `LISTING 4.77: DIV16 Macro Source` ```assembly * *``````````````````````````````* * DIV16 (NATHAN RIGGS) * * * * DIVIDES ONE 16BIT NUMBER BY * * ANOTHER AND RETURNS THE * * RESULT IN .A, .X (LOW,HIGH). * * * * PARAMETERS * * * * ]1 = DIVIDEND * * ]2 = DIVISOR * * * * CYCLES: 133+ * * SIZE: 81 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * DIV16 MAC _MLIT ]1;WPAR1 ; {16C12B} _MLIT ]2;WPAR2 ; {16C12B} JSR DIVDU16 ; {101C57B} UNSIGNED FIN <<< * ``` --- ### THE DIVDU16 SUBROUTINE _SUMMARY_ | Condition | Value | | --------------- | ------------------------------------- | | Name | `DIVDU16` | | Type | Subroutine | | File | `SUB.DIVDU16.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Divide one 16-bit number by another | | Input | WPAR1 = Dividend
WPAR2 = Divisor | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 95+ | | Bytes | 54 | | Notes | None | | See Also | `DIV16` | --- *DETAILS* The `MULTu16` subroutine accepts two 16-bit values and multiplies them, passing back the 32-bit product via `RETURN`, with `RETLEN` holding its byte-length, four. Additionally, the bottom two bytes of the product are held in the **.A** (low byte) and **.X** (high byte) registers for faster retrieval if the number is known to be 16 bits. `LISTING 4.78: DIVDU16 Subroutine Source` ```assembly * *``````````````````````````````* * DIVDU16 (NATHAN RIGGS) * * * * DIVIDE WITH 16-BIT VALUES. * * * * ADAPTED FROM LISTINGS IN THE * * C=64 MAGAZINES. * * * * INPUT: * * * * WPAR1 = DIVIDEND * * WPAR2 = DIVISOR * * * * DESTROY: NZCIDV * * ^^^ ^ * * * * CYCLES: 95+ * * SIZE: 54 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ]DVEND EQU WPAR1 ; DIVIDEND ]DVSOR EQU WPAR2 ; DIVISOR ]REM EQU WPAR3 ; REMAINDER ]RESULT EQU WPAR1 ; DIVISION RESULT * DIVDU16 LDA #0 ; {4C3B} RESET REMAINDER STA ]REM ; {3C2B} STA ]REM+1 ; {3C2B} LDX #16 ; {3C2B} NUMBER OF BITS :DVLP ASL ]DVEND ; {5C2B} LOBYTE * 2 ROL ]DVEND+1 ; {5C2B} HIBYTE * 2 ROL ]REM ; {5C2B} LOBYTE * 2 ROL ]REM+1 ; {5C2B} HIBYTE * 2 LDA ]REM ; {3C2B} SEC ; {2C1B} SET CARRY SBC ]DVSOR ; {3C2B} SUBTRACT DIVISOR TAY ; {2C1B} TO SEE IF IT FITS IN DVEND, LDA ]REM+1 ; {3C2B} HOLD LOBYTE IN .Y SBC ]DVSOR+1 ; {3C2B} AND DO SAME WITH HIBYTES BCC :SKIP ; {3C2B} IF C=0, DVSOR DOESN'T FIT * STA ]REM+1 ; {3C2B} ELSE SAVE RESULT AS REM STY ]REM ; {3C2B} INC ]RESULT ; {5C2B} AND INC RES :SKIP DEX ; {2C1B} DECREASE BIT COUNTER BNE :DVLP ; {3C2B} RELOOP IF > 0 LDA #2 ; {3C2B} LENGTH OF RESULT IN BYTES STA RETLEN ; {4C3B} STORED IN RETLEN LDA ]RESULT ; {3C2B} STORE RESULT LOBYTE STA RETURN ; {4C3B} IN .A AND RETURN LDX ]RESULT+1 ; {3C2B} STORE HIBYTE IN .X STX RETURN+1 ; {4C3B} AND IN RETURN+1 RTS ; {6C1B} ``` --- ### THE CMP16 MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------------------------------------ | | Name | `CMP16` | | Type | Macro | | File | `MAC.MATH16.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Compare two 16-bit numbers | | Input | ]1 = First comparison argument
]2 = Second comparison argument | | Output | none | | Dependencies | `SUB.COMP16` | | Flags Destroyed | NZCV | | Cycles | 100+ | | Bytes | 53 | | Notes | None | | See Also | `COMP16` | --- *DETAILS* The `CMP16` macro mimics the `CMP` instruction, except that it compares 16-bit values instead of the regular 8-bit values. The macro accepts two parameters, then sets the status flags based on the results of a comparison between the values. The status flags are set as such: - If the values are equal, then the Zero flag is set to 1 - If the first value is greater than the second, then the Carry flag is set to zero - If the first value is less than or equal to the second, then the Carry flag is set to 1 - If a signed first value is greater than a signed second value, then the Negative flag is set to 0 - If a signed first value is less than or equal to the second, the the Negative flag is set to 1 `LISTING 4.79: CMP16 Macro Source` ```assembly * *``````````````````````````````* * CMP16 (NATHAN RIGGS) * * * * COMPARES TWO 16BIT VALUES * * AND ALTERS THE P-REGISTER * * ACCORDINGLY (FLAGS). * * * * PARAMETERS * * * * ]1 = WORD 1 TO COMPARE * * ]2 = WORD 2 TO COMPARE * * * * CYCLES: 100+ * * SIZE: 53 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * CMP16 MAC _MLIT ]1;WPAR1 ; {16C12B} _MLIT ]2;WPAR2 ; {16C12B} JSR COMP16 ; {59C29B} <<< ``` --- ### THE COMP16 SUBROUTINE _SUMMARY_ | Condition | Value | | --------------- | ------------------------------------------------------------ | | Name | `COMP16` | | Type | Subroutine | | File | `SUB.COMP16.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Compare one 16-bit value to another | | Input | WPAR1 = First comparison argument
WPAR2 = Second comparison argument | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 53+ | | Bytes | 26 | | Notes | None | | See Also | `CMP16` | --- *DETAILS* The `COMP16` subroutine compares one 16-bit value to another, much like the `CMP` instruction for 8-bit values. The flags are set given the following conditions: - If the values are equal, then the Zero flag is set to 1 - If the first value is greater than the second, then the Carry flag is set to zero - If the first value is less than or equal to the second, then the Carry flag is set to 1 - If a signed first value is greater than a signed second value, then the Negative flag is set to 0 - If a signed first value is less than or equal to the second, the the Negative flag is set to 1 `LISTING 4.80: COMP16 Subroutine Source` ```assembly * *``````````````````````````````* * COMP16 (NATHAN RIGGS) * * * * 16-BIT COMPARISON DIRECTIVE * * * * BASED ON LEVENTHAL AND * * SAVILLE'S /6502 ASSEMBLY * * LANGUAGE ROUTINES/ LISTING * * * * Z FLAG = 1 IF VALUES EQUAL * * C FLAG = 0 IF CMP1 > CMP2, * * 1 IF CMP1 <= CMP2 * * N FLAG = 1 IF SIGNED CMP1 > * * SIGNED CMP2, 0 IF * * SIGNED CMP1 <= * * SIGNED CMP2 * * * * INPUT: * * * * ]WPAR1 = 16-BIT CMP VALUE * * ]WPAR2 = 16-BIT CMP VALUE * * * * DESTROY: NZCIDV * * ^^^ ^ * * * * CYCLES: 53+ * * SIZE: 26 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ]CMP1 EQU WPAR1 ; COMPARISON VAR 1 ]CMP2 EQU WPAR2 ; COMPARISON VAR 2 * COMP16 LDA ]CMP1 ; {3C2B} FIRST, COMPARE LOW BYTES CMP ]CMP2 ; {3C2B} BEQ :EQUAL ; {3C2B} BRANCH IF EQUAL LDA ]CMP1+1 ; {3C2B} COMPARE HIGH BYTES SBC ]CMP2+1 ; {3C2B} SET ZERO FLAG TO 0, ORA #1 ; {2C1B} SINCE LOW BYTES NOT EQUAL BVS :OVFLOW ; {3C2B} HANDLE V FLAG FOR SIGNED RTS ; {6C1B} :EQUAL LDA ]CMP1+1 ; {3C2B} COMPARE HIGH BYTES SBC ]CMP2+1 ; {3C2B} BVS :OVFLOW ; {3C2B} HANDLE OVERFLOW FOR SIGNED RTS ; {6C1B} :OVFLOW EOR #$80 ; {3C2B} COMPLEMENT NEGATIVE FLAG ORA #1 ; {3C2B} IF OVERFLOW, Z = 0 RTS ; {6C1B} ``` --- ### Pseudorandom Number Generation Macros and Subroutines The final group of macros and subroutines in the math collection is dedicated to generating and managing pseudorandom numbers. The value of the number generated depends on an initial **seed** and a "magic number" that the seed is `EOR`'d by, and these are usually set before any pseudorandom number is generated. Additionally, these numbers are highly variable, but ultimately predictable if you know the seed, the `EOR` value, and the number of times a number is generated. This is useful for instances when a programmer wants definite and discrete results that are reproducible and seem planned but are simply based on the generation algorithm. The Atari game *Pitfall*, for instance, uses this exact method to determine the makeup of each screen of the game, saving valuable memory space while remaining regular enough to seem intentionally designed. `LISTING 4.90: MAC.MATHRND.ASM Header Source` ```assembly * *``````````````````````````````* * MAC.MATHEXT.ASM * * * * AUTHOR: NATHAN RIGGS * * CONTACT: NATHAN.RIGGS@ * * OUTLOOK.COM * * * * DATE: 03-APR-2021 * * ASSEMBLER: MERLIN 8 PRO * * OS: DOS 3.3 * * * * SUBROUTINE FILES USED * * * * SUB.RAND16.ASM * * SUB.RAND8.ASM * * SUB.RANDB.ASM * * SUB.PERCT16.ASM * * SUB.GCFCT16.ASM * * SUB.LCMUL16.ASM * * * * LIST OF MACROS * * * * RAND : GET RANDOM BETWEEN * * RND16 : RANDOM WORD * * RND8 : RANDOM BYTE * * RNDMZ : RANDOMIZE * * RNDEOR: SET PRNG SEED + EOR * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ``` --- ### THE RNDEOR MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------------------------------ | | Name | `RNDEOR16` | | Type | Macro | | File | `MAC.MATHRND.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Set the seed and magic number for pseudorandom numbers | | Input | ]1 = Seed
]2 = EOR value | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 30+ | | Bytes | 22 | | Notes | None | | See Also | `RNDMZ` | --- *DETAILS* The `RNDEOR` macro allows you to directly set both the seed and the magic number used by `EOR` in pseudorandom number generation. This is different from the `RNDMZ` in that the number you assign to the magic number becomes its actual value, rather than be used as an index in a lookup table. `LISTING 4.91: RNDEOR Macro Source` ```assembly * *``````````````````````````````* * RNDEOR (NATHAN RIGGS) * * * * DIRECTLY DETERMINE THE PRNG * * SEED AND EOR VALUES. * * * * PARAMETERS * * * * ]1 = SEED VALUE * * ]2 = EOR MAGIC NUMBER VALUE * * * * CYCLES: 30+ * * SIZE: 22 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * RNDEOR MAC LDA ]1 ; {4C3B} STA RNDL ; {3C2B} LDA ]1+1 ; {4C3B} STA RNDH ; {3C2B} LDA ]2 ; {4C3B} STA ]MAGEOR ; {4C3B} LDA ]2+1 ; {4C3B} STA ]MAGEOR+1 ; {4C3B} <<< * ``` --- ### THE RNDMZ MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------------------------------ | | Name | `RNDMZ` | | Type | Macro | | File | `MAC.MATHRND.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Set the seed and magic number for pseudorandom numbers | | Input | ]1 = Seed
]2 = EOR value | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 56+ | | Bytes | 35 | | Notes | None | | See Also | `RNDEOR` | --- *DETAILS* The `RNDMZ` macro first lets you set the seed value that initializes the pseudorandom number generator. Then, in the separate parameter, a byte value is passed that acts as the index for a table of 64 predetermined "magic numbers" (2 bytes long each) that are used for maximum variability in the generation of each number outputted. The second parameter is divided by four to ensure that it is a value between zero and 63, and then the magic number is picked from the following table of values (found in the math collection header file): `LISTING 3.91: Magic Number Table` ``` 002D0039003F005300BD00D7012F013D 014F015D019701A101AD01BF01C70215 02190225022F025D026D0285029102A1 02E5031D034B036903710387038D039F 03A303DD03F904290457046704830489 049104BF04C1053305470569058705C3 05DD05EB0641064B0653068B06C3076B 076D0779078307F1080D086108BF08D5 ``` `LISTING 4.92: RNDEOR Macro Source` ```assembly * *``````````````````````````````* * RNDMZ (NATHAN RIGGS) * * * * ASSIGN A SEED VALUE FOR THE * * PSEUDORANDOM NUMBER * * GENERATOR AS WELL AS AN EOR * * "MAGIC NUMBER." NO MATTER * * THE EOR VALUE PROVIDED, A * * VALUE WILL BE TAKEN FROM A * * TABLE THAT ALLOWS FOR A FULL * * 65536 NON-REPEATED NUMBERS. * * * * PARAMETERS * * * * ]1 = SEED VALUE * * ]2 = EOR NUMBER REFERENCE * * * * CYCLES: 56+ * * SIZE: 35 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * RNDMZ MAC LDA ]1 ; {4C3B} STA RNDL ; {3C2B} LDA ]1+1 ; {4C3B} STA RNDH ; {3C2B} * LDA ]2 ; {4C3B} LSR ; {2C1B} LSR ; {2C1B} TAY ; {2C1B} LDA #]MAGNUM ; {3C2B} STA ADDR1 ; {3C2B} LDA #]MAGNUM/$100 ; {3C2B} STA ADDR1+1 ; {3C2B} LDA (ADDR1),Y ; {5C2B} STA ]MAGEOR ; {4C3B} INY ; {2C1B} LDA (ADDR1),Y ; {5C2B} STA ]MAGEOR+1 ; {4C3B} <<< * ``` --- ### THE RND8 MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------------- | | Name | `RND8` | | Type | Macro | | File | `MAC.MATHRND.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Generate an 8-bit pseudorandom number | | Input | none | | Output | none | | Dependencies | `RAND8` | | Flags Destroyed | NZCV | | Cycles | 51+ | | Bytes | 30 | | Notes | None | | See Also | `RAND8` `RND16` | --- *DETAILS* The `RND8` macro generates a pseudorandom number between 0 and 255. The number is passed back via the .A register as well as in `RETURN`. `LISTING 4.93: RND8 Macro Source` ``` * *``````````````````````````````* * RND8 (NATHAN RIGGS) * * * * RETURN AN 8-BIT PSEUDORANDOM * * NUMBER. * * * * PARAMETERS * * * * NONE * * * * CYCLES: 51+ * * SIZE: 30 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * RND8 MAC JSR RAND8 ; {51C30B} <<< * ``` --- ### THE RAND8 SUBROUTINE _SUMMARY_ | Condition | Value | | --------------- | ------------------------------------- | | Name | `RAND8` | | Type | Subroutine | | File | `SUB.RAND8.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Generate an 8-bit pseudorandom number | | Input | none | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 45+ | | Bytes | 27 | | Notes | None | | See Also | `RND8` `RAND16` | --- *DETAILS* The `RAND8` subroutine generates a pseudorandom number between 0 and 255. `LISTING 4.94: RND8 Subroutine Source` ```assembly * *``````````````````````````````* * RAND8 (NATHAN RIGGS) * * * * GENERATE PSEUDO-RANDOM BYTE * * * * INPUT: * * * * NONE * * * * DESTROY: NZCIDV * * ^^^ ^ * * * * CYCLES: 45+ * * SIZE: 27 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * RAND8 LDX #8 ; {3C2B} NUMBER OF BITS LDA RNDL+0 ; {3C2B} GET SEED :A ASL ; {2C1B} SHIFT THE REG ROL RNDL+1 ; {5C2B} ROTATE HIGH BYTE BCC :B ; {3C2B} IF 1 BIT SHIFTED OUT, EOR ]MAGEOR ; {2C2B} APPLY XOR FEEDBACK :B DEX ; {2C1B} DECREASE BIT COUNTER BNE :A ; {3C2B} IF NOT ZERO, RELOOP STA RNDL+0 ; {3C2B} STORE NEW SEED STA RETURN ; {4C3B} STORE IN RETURN LDY #1 ; {3C2B} RETURN BYTE LENGTH STY RETLEN ; {4C3B} IN RETLEN CMP #0 ; {2C2B} RELOAD FLAGS RTS ; {6C1B} * ``` --- ### THE RAND MACRO _SUMMARY_ | Condition | Value | | --------------- | ------------------------------------------------------------ | | Name | `RAND` | | Type | Macro | | File | `MAC.MATHRND.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Generate an 8-bit pseudorandom number
between a given low and high value | | Input | ]1 = lower boundary
]2 = higher boundary | | Output | none | | Dependencies | `RANDB` | | Flags Destroyed | NZCV | | Cycles | 263+ | | Bytes | 171 | | Notes | None | | See Also | `RND8` `RND16` `RANDB` | --- *DETAILS* The `RAND` macro takes a lower boundary and a higher boundary, both between 0 and 255, and generates a pseudo-random number between them. When possible, `RND8` should be used due to the much higher number of cycles and bytes used in calculating the number between new boundaries. `LISTING 4.95: RAND Macro Source` ```assembly * *``````````````````````````````* * RAND (NATHAN RIGGS) * * * * RETURNS A RANDOM NUMBER IN * * REGISTER .A THAT IS BETWEEN * * THE LOW AND HIGH BOUNDARIES * * PASSED IN THE PARAMETERS. * * * * NOTE THAT THIS RETURNS A * * BYTE, AND THUS ONLY DEALS * * WITH VALUES BETWEEN 0..255. * * * * PARAMETERS * * * * ]1 = LOW BOUNDARY * * ]2 = HIGH BOUNDARY * * * * CYCLES: 263+ * * SIZE: 171 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * RAND MAC LDA ]1 ; {4C3B} LOW LDX ]2 ; {4C3B} HIGH JSR RANDB ; {255C165B} <<< * ``` --- ### THE RANDB SUBROUTINE _SUMMARY_ | Condition | Value | | --------------- | ------------------------------------------------------- | | Name | `RANDB` | | Type | Subroutine | | File | `SUB.RANDB.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Generate a pseudorandom number between a low and a high | | Input | BPAR1 = Lower boundary
BPAR2 = Upper boundary | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 249+ | | Bytes | 162 | | Notes | None | | See Also | `RAND` `RND8` | --- *DETAILS* The `RANDB` subroutine generates a pseudorandom number between a given lower boundary and a high boundary. The number generated is stored in the **.A** register as well as in `RETURN`. `LISTING 4.96: RANDB Subroutine Source` ```assembly * *``````````````````````````````* * RANDB (NATHAN RIGGS) * * * * GET A RANDOM VALUE BETWEEN * * A MIN AND MAX 8-BIT BOUNDARY * * * * INPUT: * * * * BPAR1 = MINIMUM VALUE * * BPAR2 = MAXIMUM VALUE * * * * DESTROY: NZCIDV * * ^^^ ^ * * * * CYCLES: 249+ * * SIZE: 162 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ]NEWMIN EQU BPAR1 ; MINIMUM PARAMETER ]NEWMAX EQU BPAR2 ; MAXIMUM PARAMETER ]OLDMIN EQU WPAR1 ; OLD MINIMUM (1) ]OLDMAX EQU WPAR1+1 ; OLD MAXIMUM (255) ]OLDRNG EQU VARTAB ; OLD RANGE ]NEWRNG EQU VARTAB+2 ; NEW RANGE ]MULRNG EQU VARTAB+4 ; MULTIPLIED RANGE ]DIVRNG EQU VARTAB+6 ; DIVIDED RANGE ]VALRNG EQU VARTAB+8 ; VALUE RANGE ]OLDVAL EQU VARTAB+10 ; OLD VALUE ]NEWVAL EQU VARTAB+12 ; NEW VALUE ]NUM1HI EQU VARTAB+14 ; MULTIPLICATION HI BYTE ]REMAIN EQU VARTAB+16 ; REMAINDER * RANDB STX ]NEWMAX ; {4C3B} NEW HIGH VALUE STA ]NEWMIN ; {4C3B} NEW LOW VALUE OF RANGE * ** GET OLDMIN,OLDMAX,OLDVAL * LDA #1 ; {3C2B} OLD LOW IS ALWAYS 1 STA ]OLDMIN ; {3C2B} LDA #255 ; {3C2B} OLD HIGH IS ALWAYS 255 STA ]OLDMAX ; {3C2B} LDX #8 ; {3C2B} NUMBER OF BITS IN # LDA RNDL+0 ; {3C2B} LOAD SEED VALUE :AA ASL ; {2C1B} SHIFT ACCUMULATOR ROL RNDL+1 ; {5C2B} BCC :BB ; {3C2B} IF NEXT BIT IS 0, BRANCH EOR ]MAGEOR ; {2C2B} ELSE, APPLY XOR FEEDBACK :BB DEX ; {2C1B} DECREASE .X COUNTER BNE :AA ; {3C2B} IF > 0, KEEP LOOPING STA RNDL+0 ; {3C2B} OVERWRITE SEED VALUE CMP #0 ; {2C2B} RESET FLAGS STA ]OLDVAL ; {4C3B} STORE RANDOM NUMBER * ** NEWVALUE = (((OLDVAL-NEWMIN) * (NEWMAX-NEWMIN) / ** (OLDMAX-OLDMIN)) + NEWMIN * ** OLDRANGE = (OLDMAX-OLDMIN) ** NEWRANGE = (NEWMAX - NEWMIN) ** NEWVAL = (((OLDVAL-OLDMIN) * NEWRANGE) / OLDRANGE) + NEWMIN * LDA ]OLDMAX ; {3C2B} SUBTRACT OLDMIN SEC ; {2C1B} FROM OLDMAX, STORE SBC ]OLDMIN ; {3C2B} IN OLDRANGE STA ]OLDRNG ; {4C3B} LDA ]NEWMAX ; {4C3B} SUBTRACT NEWMIN SEC ; {2C1B} FROM NEWMAX, THEN SBC ]NEWMIN ; {4C3B} STORE IN NEWRANGE STA ]NEWRNG ; {4C3B} LDA ]OLDVAL ; {4C3B} SUBTRACT OLDMIN SEC ; {2C1B} FROM OLDVAL AND SBC ]OLDMIN ; {3C2B} STORE IN VALRANGE STA ]VALRNG ; {4C3B} * ** GET MULRANGE: VALRANGE * NEWRANGE * LDA #00 ; {3C2B} CLEAR ACCUMULATOR, TAY ; {2C1B} .Y AND THE HIGH BYTE STY ]NUM1HI ; {4C3B} BEQ :ENTLP ; {3C2B} IF ZERO, BRANCH :DOADD CLC ; {2C1B} CLEAR CARRY ADC ]VALRNG ; {4C3B} ADD VALUE RANGE TO .A TAX ; {2C1B} HOLD IN .X TYA ; {2C1B} .Y BACK TO .A ADC ]NUM1HI ; {4C3B} ADD HIBYTE TAY ; {2C1B} MOVE BACK TO .Y TXA ; {2C1B} .X BACK TO .A :MLP ASL ]VALRNG ; {5C2B} SHIFT VALUE RANGE ROL ]NUM1HI ; {5C2B} ADJUST HIGH BYTE :ENTLP LSR ]NEWRNG ; {5C2B} SHIFT NEW RANGE BCS :DOADD ; {3C2B} IF LAST BIT WAS 1, LOOP ADD BNE :MLP ; {3C2B} IF ZERO FLAG CLEAR, LOOP SHIFT STA ]MULRNG ; {4C3B} STORE RESULT LOW BYTE STY ]MULRNG+1 ; {4C3B} STORE HIGH BYTE * ** NOW GET DIVRANGE: MULRANGE / OLDRANGE * :DIVIDE LDA #0 ; {3C2B} CLEAR ACCUMULATOR STA ]REMAIN ; {4C3B} AND THE REMAINDER LOBYTE STA ]REMAIN+1 ; {4C3B} AND REMAINDER HIBYTE LDX #16 ; {3C2B} NUMBER OF BYTES :DIVLP ASL ]MULRNG ; {5C2B} LOW BYTE * 2 ROL ]MULRNG+1 ; {5C2B} HIGH BYTE * 2 ROL ]REMAIN ; {5C2B} REMAINDER LOW BYTE * 2 ROL ]REMAIN+1 ; {5C2B} HIGH BYTE * 2 LDA ]REMAIN ; {4C3B} SUBTRACT OLDRANGE SEC ; {2C1B} FROM REMAINDER SBC ]OLDRNG ; {4C3B} TAY ; {2C1B} HOLD IN .Y LDA ]REMAIN+1 ; {4C3B} SUBTRACT HIGH BYTES SBC ]OLDRNG+1 ; {4C3B} BCC :SKIP ; {3C2B} IF NO CARRY, THEN NOT DONE STA ]REMAIN+1 ; {4C3B} SAVE SBC AS NEW REMAINDER STY ]REMAIN ; {4C3B} INC ]DIVRNG ; {6C3B} INCREMENT THE RESULT :SKIP DEX ; {2C1B} DECREMENT COUNTER BNE :DIVLP ; {3C2B} IF ZERNO, RELOOP * ** NOW ADD NEWMIN TO DIVRANGE * LDA ]DIVRNG ; {4C3B} USE LOW BYTE ONLY CLC ; {2C1B} AND ADD TO ]NEWMIN ADC ]NEWMIN ; {4C3B} TO GET THE NEW VALUE STA ]NEWVAL ; {4C3B} STA RETURN ; {4C3B} COPY TO RETURN LDX #1 ; {3C2B} RETURN LENGTH STX RETLEN ; {4C3B} RTS ; {6C1B} ``` --- ### THE RND16 MACRO _SUMMARY_ | Condition | Value | | --------------- | -------------------------------------- | | Name | `RND16` | | Type | Macro | | File | `MAC.MATHRND.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Generate an 16-bit pseudorandom number | | Input | none | | Output | none | | Dependencies | `RND16` | | Flags Destroyed | NZCV | | Cycles | 101+ | | Bytes | 63 | | Notes | None | | See Also | `RND8` `RAND16` | --- *DETAILS* The `RND16` macro generates a 16-bit pseudorandom number. After being called, the value is stored in `RETURN` as well as in the .A (low byte) and .X (high byte) registers. `RETLEN` holds #2, the byte-length of the number. `LISTING 4.97: RND16 Macro Source` ```assembly * *``````````````````````````````* * RND16 (NATHAN RIGGS) * * * * RETURN A 16-BIT PSEUDORANDOM * * NUMBER. * * * * PARAMETERS * * * * NONE * * * * CYCLES: 101+ * * SIZE: 63 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * RND16 MAC JSR RAND16 ; {101C63B} <<< * ``` --- ### THE RAND16 SUBROUTINE _SUMMARY_ | Condition | Value | | --------------- | ------------------------------------- | | Name | `RAND16` | | Type | Subroutine | | File | `SUB.RAND16.ASM` | | Author | Nathan Riggs | | Last Revision | 02-APR-2021 | | Assembler | Merlin Pro 8 | | OS | Apple DOS 3.3 | | Purpose | Generate a 16-bit pseudorandom number | | Input | none | | Output | none | | Dependencies | none | | Flags Destroyed | NZCV | | Cycles | 95+ | | Bytes | 60 | | Notes | None | | See Also | `RND16` | --- *DETAILS* The `RAND16` subroutine generates a pseudorandom number between 0 and 65,535 (16-bits). This value is stored in `RETURN` with its byte-length, two, in `RETLEN`. Additionally, the value is returned in the **.A** (low byte) and **.X** (high byte) registers. `LISTING 4.98: RANDB Subroutine Source` ```assembly *``````````````````````````````* * RAND16 : 16BIT RANDOM NUMBER * * * * GENERATE A 16BIT PSEUDO- * * RANDOM NUMBER AND RETURN IT * * IN A,X (LOW, HIGH). * * * *------------------------------* * ORIGINAL AUTHOR IS WHITE * * FLAME, AS SHARED ON * * CODEBASE64. * *------------------------------* * * * INPUT: * * * * NONE * * * * DESTROY: NZCIDV * * ^^^ ^ * * * * CYCLES: 95+ * * SIZE: 60 BYTES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ]SEED EQU WPAR1 ; SEED FOR PRNG * RAND16 LDA RNDL ; {3C2B} GET SEED LOBYTE STA ]SEED ; {3C2B} LDA RNDH ; {3C2B} GET SEED HIBYTE STA ]SEED+1 ; {3C2B} * LDA ]SEED ; {3C2B} CHECK IF $0 OR $8000 BEQ :LOW0 ; {3C2B} * ** DO A NORMAL SHIFT * ASL ]SEED ; {5C2B} MUTATE LDA ]SEED+1 ; {3C2B} ROL ; {2C1B} BCC :NOEOR ; {3C2B} IF CARRY CLEAR, EXIT :DOEOR ; HIGH BYTE IN A EOR ]MAGEOR+1 ; {3C2B} EOR WITH MAGIC NUMBER STA ]SEED+1 ; {3C2B} STORE BACK INTO HIBYTE LDA ]SEED ; {3C2B} EOR ]MAGEOR ; {3C2B} DO SAME WITH LOW BYTE STA ]SEED ; {3C2B} JMP :EXIT ; {3C3B} :LOW0 LDA ]SEED+1 ; {3C2B} BEQ :DOEOR ; {3C2B} IF HI ALSO 0, APPLY EOR ASL ; {2C1B} BEQ :NOEOR ; {3C2B} IF 00, THEN IT WAS $80 BCS :DOEOR ; {3C2B} ELSE DO EOR :NOEOR STA ]SEED+1 ; {3C2B} :EXIT LDX ]SEED+1 ; {3C2B} VAL HIBYTE IN .X LDY ]SEED ; {3C2B} LOBYTE TEMP IN .Y STX RNDH STY RNDL STY RETURN ; {4C3B} TRANSFER TO RETURN AREA STX RETURN+1 ; {4C3B} LDA #2 ; {3C2B} LENGTH OF RETURN IN BYTES STA RETLEN ; {4C3B} TYA ; {2C1B} TRANSFER LOBYTE TO .A RTS ; {6C1B} ``` --- # PART II: MATH COLLECTION DEMONSTRATIONS The following demo programs illustrate how to use the macros in the math collection that deal with dividing by constants, general-purpose integer math routines for 8-bit and 16-bit addition, subtraction, multiplication and division, and macros dedicated to generating and manipulating pseudorandom numbers. These span three different demo programs, grouped together as presented here. Note that these are not extensive tests, and should not be mistaken as such; they merely show the basic usage of the macros and one instance of each macro working correctly. The purpose of the demo files is to provide assistance to beginners rather than to do a thorough test of every subroutine. `LISTING 4.9A: The DEMO.MATHBY.ASM File Source` ```assembly * *``````````````````````````````* * DEMO.MATH * * * * A DEMO OF THE INTEGER MATH * * MACROS INCLUDED AS PART OF * * THE APPLEIIASM LIBRARY. * * * * AUTHOR: NATHAN RIGGS * * CONTACT: NATHAN.RIGGS@ * * OUTLOOK.COM * * * * DATE: 16-JUL-2019 * * ASSEMBLER: MERLIN 8 PRO * * OS: DOS 3.3 * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** ASSEMBLER DIRECTIVES * CYC AVE EXP OFF TR ON DSK DEMO.MATHBY OBJ $BFE0 ORG $6000 * *``````````````````````````````* * TOP INCLUDES (HOOKS,MACROS) * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * PUT MIN.HEAD.REQUIRED.ASM USE MIN.MAC.REQUIRED.ASM PUT MIN.HEAD.MATH.ASM USE MIN.MAC.M8BY.ASM USE MIN.MAC.M16BY.ASM USE MIN.MAC.D8BY.ASM ]HOME2 EQU $FC58 * *``````````````````````````````* * PROGRAM MAIN BODY * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * JSR ]HOME2 * ** THIS DEMO SHOWS HOW TO USE THE QUICK ** MATH MACROS AVAILABLE FOR USE AS ALTERNATIVES ** TO THE NORMAL MATH ROUTINES. THESE MACROS ** DO NOT CALL ANY ROUTINES, AND ALL PASSING ** OF VARIABLES IS DONE VIA THE REGISTERS. THESE ** TEND TO BE QUICKER BECAUSE WE ARE MULTIPLYING ** AND DIVIDING BY CONSTANTS, THUS NOT REQUIRING ** THE USE OF LOOPING, CHECKING VALUES, ETC. ** EVERYTHING IS STRAIGHTFORWARDLY DEDICATED TO ** ONLY A SINGLE FUNCTION. * ** WE SHALL START WITH 8-BIT MULTIPLICATION MACROS, ** FOLLOWED BY 16-BIT MULTIPLICATION, THEN 8-BIT ** DIVISION. CURRENTLY, NO 16-BIT DIVISION QUICK ** MATH ROUTINES EXIST, BECAUSE THE CYCLES SAVED IN ** COMPARISON TO THE BYTES USED WOULD PROBABLY BE ** MINIMAL. * *``````````````````````````````* * 8-BIT QUICK MULTIPLICATION * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** STARTING WITH THE LOWEST NUMBER TO MULTIPLY BY, ** THE NUMBER TWO. * JSR ]HOME2 _PRN "8-BIT CONSTANT MATH MACROS",8D _PRN "==========================",8D8D _PRN "#5 * 2 = ",8D8D M8BY2 BIT8 STA RETURN DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * M8BY3 BIT8 STA RETURN _PRN "#5 * #3 = ",8D8D DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * M8BY4 BIT8 STA RETURN _PRN "#5 * #4 = ",8D8D DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * M8BY5 BIT8 STA RETURN _PRN "#5 * #5 = ",8D8D DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * M8BY6 BIT8 STA RETURN _PRN "#5 * #6 = ",8D8D DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * M8BY7 BIT8 STA RETURN _PRN "#5 * #7 = ",8D8D DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * M8BY8 BIT8 STA RETURN _PRN "#5 * #8 = ",8D8D DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * M8BY9 BIT8 STA RETURN _PRN "#5 * #9 = ",8D8D DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * M8BY10 BIT8 STA RETURN _PRN "#5 * #10 = ",8D8D DUMP #RETURN;#1 _WAIT * *``````````````````````````````* * 16-BIT CONST MULTIPLICATION * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** NOW WE WILL TEST THE 16-BIT MULTIPLY-BY- ** A-CONSTANT MACROS. * JSR ]HOME2 _PRN "16-BIT CONSTANT MULTIPLICATION",8D _PRN "==============================",8D8D * _PRN "#500 * #2 = ",8D8D MBY2 BIT16 STA RETURN STX RETURN+1 DUMP #RETURN;#2 _WAIT * _PRN " ",8D8D MBY3 BIT16 STA RETURN STX RETURN+1 _PRN "#500 * #3 = ",8D8D DUMP #RETURN;#2 _WAIT _PRN " ",8D8D * _PRN " ",8D8D MBY4 BIT16 STA RETURN STX RETURN+1 _PRN "#500 * #4 = ",8D8D DUMP #RETURN;#2 _WAIT _PRN " ",8D8D * _PRN " ",8D8D MBY5 BIT16 STA RETURN STX RETURN+1 _PRN "#500 * #5 = ",8D8D DUMP #RETURN;#2 _WAIT _PRN " ",8D8D * _PRN " ",8D8D MBY6 BIT16 STA RETURN STX RETURN+1 _PRN "#500 * #6 = ",8D8D DUMP #RETURN;#2 _WAIT _PRN " ",8D8D * _PRN " ",8D8D MBY7 BIT16 STA RETURN STX RETURN+1 _PRN "#500 * #7 = ",8D8D DUMP #RETURN;#2 _WAIT _PRN " ",8D8D * _PRN " ",8D8D MBY8 BIT16 STA RETURN STX RETURN+1 _PRN "#500 * #8 = ",8D8D DUMP #RETURN;#2 _WAIT _PRN " ",8D8D * _PRN " ",8D8D MBY9 BIT16 STA RETURN STX RETURN+1 _PRN "#500 * #9 = ",8D8D DUMP #RETURN;#2 _WAIT _PRN " ",8D8D * _PRN " ",8D8D MBY10 BIT16 STA RETURN STX RETURN+1 _PRN "#500 * #10 = ",8D8D DUMP #RETURN;#2 _WAIT _PRN " ",8D8D * _PRN " ",8D8D MBY1H BIT16 STA RETURN STX RETURN+1 _PRN "#500 * #100 = ",8D8D DUMP #RETURN;#2 _WAIT _PRN " ",8D8D * *``````````````````````````````* * 8BIT DIVISION BY CONSTANTS * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * JSR ]HOME2 _PRN "8-BIT DIVISION BY CONSTANTS",8D _PRN "===========================",8D8D * _PRN "#100 / 2 = ",8D8D D8BY2 BIT82 STA RETURN DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * _PRN "#100 / 3 = ",8D8D D8BY3 BIT82 STA RETURN DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * _PRN "#100 / 4 = ",8D8D D8BY4 BIT82 STA RETURN DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * _PRN "#100 / 5 = ",8D8D D8BY5 BIT82 STA RETURN DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * _PRN "#100 / 6 = ",8D8D D8BY6 BIT82 STA RETURN DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * _PRN "#100 / 7 = ",8D8D D8BY7 BIT82 STA RETURN DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * _PRN "#100 / 8 = ",8D8D D8BY8 BIT82 STA RETURN DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * _PRN "#100 / 9 = ",8D8D D8BY9 BIT82 STA RETURN DUMP #RETURN;#1 _PRN " ",8D8D _WAIT * * _PRN "#100 / 10 = ",8D8D D8BY10 BIT82 STA RETURN DUMP #RETURN;#1 _PRN " ",8D8D _WAIT JMP REENTRY * *``````````````````````````````* * BOTTOM INCLUDES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** BOTTOM INCLUDES * PUT MIN.LIB.REQUIRED.ASM * BIT8 HEX 05 ; #5 BIT82 HEX 64 BIT16 HEX F401 ; #500 ``` `LISTING 4.9B: The DEMO.MATHBAS.ASM File Source` ```assembly * *``````````````````````````````* * DEMO.MATHBAS.ASM * * * * A DEMO OF THE 8-BIT AND THE * * 16-BIT MACROS FOR ADDING, * * SUBTRACTING, MULTIPLYING AND * * DIVIDING. A 16-BIT COMPARE * * MACRO IS ALSO INCLUDED AS * * PART OF THE COLLECTION. * * * * AUTHOR: NATHAN RIGGS * * CONTACT: NATHAN.RIGGS@ * * OUTLOOK.COM * * * * DATE: 02-APR-2021 * * ASSEMBLER: MERLIN 8 PRO * * OS: DOS 3.3 * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** ASSEMBLER DIRECTIVES * CYC AVE EXP OFF TR ON DSK DEMO.MATHBAS OBJ $BFE0 ORG $6000 * *``````````````````````````````* * TOP INCLUDES (HOOKS,MACROS) * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * PUT MIN.HEAD.REQUIRED.ASM USE MIN.MAC.REQUIRED.ASM PUT MIN.HEAD.MATH.ASM USE MIN.MAC.MATH8.ASM USE MIN.MAC.MATH16.ASM ]HOME2 EQU $FC58 * *``````````````````````````````* * PROGRAM MAIN BODY * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * JSR ]HOME2 * *``````````````````````````````* * 8-BIT BASIC MATH MACROS * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** THIS COLLECTION CONTAINS MACROS FOR 8-BIT ** BASIC MATH, INCLUDING ADDITION, SUBTRACTION, ** MULTIPLICATION AND DIVISION. CURRENTLY, ONLY ** UNSIGNED NUMBERS ARE SUPPORTED, THOUGH THIS ** WILL LIKELY CHANGE IN A NEAR-FUTURE REVISION. * *``````````````````````````````* * 8-BIT ADDITION * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** 8-BIT ADDITION IS RATHER TRIVIAL, BUT IS ** INCLUDED HERE FOR BEGINNERS' REFERENCE. IF ** YOU ARE CAPABLE OF WRITING THESE ROUTINES ** YOURSELF, YOU ARE LIKELY TO SAVE AT LEAST ** 8 CYCLES, AS THE MACRO USES THE RETURN ** ADDRESS FOR PASSING BACK THE SUM. THIS SUM ** IS ALSO PASSED BACK VIA THE .A REGISTER, ** BUT THERE ARE STILL WASTED CYCLES. * ** ADDITION IS PARTICULARLY SIMPLE: PASS THE ** TWO BYTE VALUES TO BE ADDED, THEN EXPECT ** THE SUM IN .A AS WELL AS IN RETURN. * ** NOTE THAT CURRENTLY, THE 8-BIT ADDITION ** AND SUBTRACTION ROUTINES ONLY ACCEPT A ** DIRECT ADDRESS, AND THUS DOES NOT ALLOW ** FOR THE INDIRECT ADDRESSING WORKAROUND THAT ** MOST OF THE REST OF THE LIBRARY USES. THIS ** IS FOR THE SAKE OF PRESERVING CYCLES AND ** DISCARDING BYTES. * JSR ]HOME2 _PRN "8-BIT ADDITION",8D _PRN "==============",8D8D _PRN "10 + 20 =",8D ADD8 NUM81;NUM82 DUMP #RETURN;RETLEN _WAIT * *``````````````````````````````* * 8-BIT SUBTRACTION * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** 8-BIT SUBTRACTION WORKS THE SAME WAY AS ** ADDITION (EXCEPT, OBVIOUSLY, IN THE FACT ** THAT THEY ARE OPPOSITE OPERATIONS), AND ** ALSO HAS THE SAME LIMITATION: NO ADDRESSING ** MODES OTHER THAN THE STANDARD PASSING OF ** ADDRESSES WHERE THE ARGUMENT VALUES ARE ** LOCATED. * JSR ]HOME2 _PRN "8-BIT SUBTRACTION",8D _PRN "=================",8D8D _PRN "20 - 10 =",8D SUB8 NUM82;NUM81 DUMP #RETURN;#1 _WAIT * *``````````````````````````````* * 8-BIT MULTIPLICATION * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** 8-BIT MULTIPLICATION IS A BIT MORE COMPLICATED ** THAN ADDITION AND SUBTRACTION UNDER THE HOOD, ** BUT CALLING IT REMAINS THE SAME. LIKE WITH ** THE OTHER 8-BIT BASIC MATH MACROS, ONLY LITERALS ** AND DIRECT ADDRESSES ARE ACCEPTED AS PARAMETERS, ** UNLIKE THE REST OF THE LIBRARY, TO SAVE RESOURCES ** IN SUBROUTINES THAT ARE LIKELY TO BE CALLED MUCH ** MORE THAN OTHERS AS PART OF A PROGRAM (AND OFTEN ** IN LOOPS). * JSR ]HOME2 _PRN "8-BIT MULTIPLICATION",8D _PRN "====================",8D8D _PRN "10 * 20 = ",8D MUL8 NUM81;NUM82 DUMP #RETURN;RETLEN _WAIT * *``````````````````````````````* * 8-BIT DIVISION * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** THIS MACRO IS USED LIKE ALL OTHER 8-BIT ** MACROS, BUT THE ORDER IS IMPORTANT HERE: ** THE FIRST VALUE PASSED IS THE DIVIDEND ** WHILE THE SECOND VALUE US THE DIVISOR. IT ** MAY HELP TO THINK OF THE SEMI-COLON HERE ** AS STANDING FOR "BY" SO THAT THE STATEMENT ** CAN BE READ AS "DIVIDE DIVIDEND BY DIVISOR." * ** 8-BIT DIVISION IS LIMITED TO ARGUMENTS THAT ** ARE EITHER A DIRECT ADDRESS OR A LITERAL VALUE, ** LIKE OTHER 8-BIT MATH ROUTINES. * JSR ]HOME2 _PRN "8-BIT DIVISION",8D _PRN "==============",8D8D _PRN "20 / 10 = ",8D DIV8 NUM82;NUM81 DUMP #RETURN;RETLEN _WAIT * *``````````````````````````````* * 16-BIT BASIC MATH MACROS * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** BOTH ADDITION AND SUBTRACTION OF 16-BIT ** NUMBERS IS ALSO RATHER TRIVIAL, BUT CAN ** BE CONFUSING TO SOMEONE NEW TO 6502 ** ASSEMBLY (ESPECIALLY WITHOUT A FULL ** UNDERSTANDING OF HOW ADC WORKS). EVEN STILL, ** IT CAN BECOME A BIT TEDIOUS TO CONSTANTLY ** WRITE OUT THE ROUTINES MANUALLY, AS THEY DO ** CONSTITUTE A SMALL NUMBER OF BYTES THAT CAN ** GET TIRESOME ON REPEAT. * *``````````````````````````````* * 16-BIT ADDITION * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** USING THE 16-BIT ADDITION MACRO IS SIMILAR TO ITS ** 8-BIT COUSIN: TWO ADDRESSES ARE PROVIDED THAT HOLD ** THE VALUES TO BE ADDED. THE TWO-BYTE SUM IS THEN ** PASSED BACK VIA RETURN (WITH RETLEN HOLDING ITS ** LENGTH, 2) AS WELL AS IN .A (LOW BYTE) AND .X (HIGH). * ** LIKE 8-BIT ADDITION, 16-BIT ADDITION ALSO HAS EXTRA ** BYTES AND CYCLES THAT CAN BE EASILY DISCARDED EITHER ** BY ALTERING THE MACRO AND RELATED SUBROUTINE ITSELF OR ** BY SIMPLY DOING THE ADDITION MANUALLY. * JSR ]HOME2 _PRN "16-BIT ADDITION",8D _PRN "===============",8D8D ADD16 NUM161;NUM162 _PRN "300 + 400 =",8D DUMP #RETURN;RETLEN _WAIT * *``````````````````````````````* * 16-BIT SUBTRACTION * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** 16-BIT SUBTRACTION FOLLOWS THE SAME SETUP ** AND RULES AS 16-BIT ADDITION: * JSR ]HOME2 _PRN "16-BIT SUBTRACTION",8D _PRN "==================",8D8D _PRN "400 - 300 = ",8D SUB16 NUM162;NUM161 DUMP #RETURN;RETLEN _WAIT * *``````````````````````````````* * 16-BIT MULTIPLICATION * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** BY NOW, THE METHOD SHOULD BE OBVIOUS: MUL16 ** TAKES TWO ARGUMENTS WHICH ARE ADDRESSES THAT ** HOLD THE TWO VALUES TO BE MULTIPLIED. * JSR ]HOME2 _PRN "16-BIT MULTIPLICATION",8D _PRN "=====================",8D8D _PRN "300 * 400 = ",8D MUL16 NUM161;NUM162 DUMP #RETURN;RETLEN _WAIT * *``````````````````````````````* * 16-BIT DIVISION * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** 16-BIT DIVISION WORKS LIKE 8-BIT DIVISION, ** WITH THE RESULT STORED IN RETURN (2 BYTES) ** AS WELL AS IN .A (LOW BYTE) AND .X (HIGH). ** ADDITIONALLY, THE REMAINDER IS HELD IN THE ** .Y REGISTER--A MODULUS FUNCTION CAN SIMPLY ** CALL THIS DIVISION MACRO AND THEN READ THE ** VALUE OF .Y FOR THE ANSWER. * JSR ]HOME2 _PRN "16-BIT DIVISION",8D _PRN "===============",8D8D _PRN "400 / 300 = ",8D DIV16 NUM162;NUM161 DUMP #RETURN;RETLEN _WAIT * *``````````````````````````````* * 16-BIT COMPARISON * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** LASTLY, A 16-BIT COMPARISON MACRO IS PROVIDED ** THAT MIMICS THE FUNCTIONALITY OF THE CMP INSTRUCTION, ** BUT OF COURSE FOR 16-BIT VALUES. THE ADDRESSES ** OF TWO SEPARATE VALUES ARE PROVIDED, AND THEN THE ** COMPARISON IS MADE WITH THE FOLLOWING RESULTS: * ** Z FLAG = 1 IF BOTH VALUES ARE EQUAL ** C FLAG = 0 IF FIRST IS GREATER THAN SECOND ** C FLAG = 1 IF FIRST IS LESS THAN OR EQUAL TO SECOND ** N FLAG = 1 IF A SIGNED FIRST IS GREATER THAN A SIGNED SECOND ** N FLAG = 0 IF SIGNED FIRST IS LESS THAN OR EQUAL TO ** THE SIGNED SECOND PARAMETER * JSR ]HOME2 _PRN "16-BIT COMPARISON",8D _PRN "=================",8D8D _PRN "CMP16 #300;#400",8D8D CMP16 NUM161;NUM162 BEQ :GREATER BNE :LESSOREQ :GREATER _PRN "FIRST IS GREATER THAN SECOND.",8D8D JMP :EXIT :LESSOREQ _PRN "FIRST IS <= THE SECOND PARAMETER.",8D8D :EXIT _WAIT * JSR ]HOME2 _PRN "DONE.",8D8D8D * JMP REENTRY * *``````````````````````````````* * BOTTOM INCLUDES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** BOTTOM INCLUDES * PUT MIN.LIB.REQUIRED.ASM * ** INDIVIDUAL SUBROUTINE INCLUDES * ** 8-BIT MATH SUBROUTINES * PUT MIN.SUB.MULTU8.ASM PUT MIN.SUB.DIVDU8.ASM * ** 16-BIT MATH SUBROUTINES * PUT MIN.SUB.ADDIT16.ASM PUT MIN.SUB.SUBT16.ASM PUT MIN.SUB.COMP16.ASM PUT MIN.SUB.MULTU16.ASM PUT MIN.SUB.DIVDU16.ASM * NUM81 DB 10 NUM82 DB 20 NUM161 DW 300 NUM162 DW 400 ``` `LISTING 3.9C: The DEMO.MATHRND.ASM File Source` ```assembly * *``````````````````````````````* * DEMO.MATH * * * * A DEMO OF THE INTEGER MATH * * MACROS INCLUDED AS PART OF * * THE APPLEIIASM LIBRARY. * * * * AUTHOR: NATHAN RIGGS * * CONTACT: NATHAN.RIGGS@ * * OUTLOOK.COM * * * * DATE: 02-APR-2021 * * ASSEMBLER: MERLIN 8 PRO * * OS: DOS 3.3 * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** ASSEMBLER DIRECTIVES * CYC AVE EXP OFF TR ON DSK DEMO.MATHRND OBJ $BFE0 ORG $6000 * *``````````````````````````````* * TOP INCLUDES (HOOKS,MACROS) * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * PUT MIN.HEAD.REQUIRED.ASM USE MIN.MAC.REQUIRED.ASM PUT MIN.HEAD.MATH.ASM USE MIN.MAC.MATHRND.ASM ]HOME2 EQU $FC58 * *``````````````````````````````* * PROGRAM MAIN BODY * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * *``````````````````````````````* * PSEUDORANDOM NUMBER MACROS * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** THERE ARE FIVE MACROS DEDICATED TO USING AND ** GENERATING PSEUDORANDOM NUMBERS. THE RND8 ** MACRO AND THE RND16 MACRO GENERATE EITHER 8-BIT ** OR 16-BIT RANDOM NUMBERS, RESPECTIVELY, WHILE ** THE RAND MACRO GENERATES AN 8-BIT NUMBER BETWEEN ** A LOW AND A HIGH. * ** IN ADDITION TO THESE ARE TWO OTHER IMPORTANT MACROS: ** THE RNDMZ MACRO AND THE RNDEOR MACRO. THESE ARE BOTH ** DEDICATED TO ALTERING THE SEED AND THE EOR VALUE ** FOR GENERATING PSEUDORANDOM NUMBERS, BUT THE RNDEOR ** ALLOWS YOU TO DIRECTLY SPECIFY THE SEED AND THE EOR ** VALUE WHEREAS THE RNDMZ MACRO ALLOWS YOU TO SET THE ** SEED DIRECTLY BUT NOT THE EOR VALUE. INSTEAD, THE ** VALUE PASSED FOR THE EOR ARGUMENT IS DIVIDED BY FOUR ** TO SET IT TO A NUMBER BETWEEN 0 AND 63, AND A FINAL ** EOR VALUE IS CHOSEN FROM A TABLE OF CONSTANTS THAT ** ENSURES MAXIMUM VARIABILITY (TO THE POINT OF BEING ** "UNNATURAL" RANDOMNESS). * ** EITHER RNDMZ OR RNDEOR SHOULD BE EXECUTED BEFORE ** RND8, RND16, OR RAND ARE USED. OTHERWISE, THE SEED ** AND EOR VALUE WILL REVERT TO DEFAULT VALUES, ** POSSIBLY BECOMING HIGHLY PREDICTABLE BY SOMEONE ** LOOKING TO EXPLOIT SUCH SYSTEMS. * *``````````````````````````````* * THE RNDEOR MACRO * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** AS NOTED ABOVE, THE RNDEOR MACRO ALLOWS YOU TO SET ** THE SEED AND EOR VALUE FOR THE PSEUDORANDOM NUMBER ** GENERATOR. THE SEED IS PROVIDED FIRST, FOLLOWED BY ** THE EOR "MAGIC NUMBER." * JSR ]HOME2 _PRN "THE RNDEOR MACRO",8D _PRN "================",8D8D RNDEOR SEED1;NUM1 _PRN "SEED LOW AND HIGH NOW:",8D DUMP #RNDL;#2 _PRN " ",8D8D _PRN "AND THE MAGIC NUMBER IS:",8D DUMP #]MAGEOR;#2 _WAIT * *``````````````````````````````* * THE RNDMZ MACRO * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** AS DESCRIBED ABOVE, THE RNDMZ (RANDOMIZE) MACRO ** SETS THE SEED OF THE PRNG TO A GIVEN VALUE, AND ** PULLS FROM A TABLE OF PRESET VALUES THE "MAGIC ** NUMBER" THAT IS USED TO EOR THE SEED. THE NUMBER ** PROVIDED AS ARGUMENT TWO SERVES AS AN INDEX. * JSR ]HOME2 _PRN "THE RNDMZ MACRO",8D _PRN "===============",8D8D RNDMZ SEED2;NUM2 _PRN "THE NEW SEED IS: ",8D DUMP #RNDL;#2 _PRN " ",8D8D _PRN "AND THE NEW MAGIC NUMBER IS:",8D DUMP #]MAGEOR;#2 _WAIT * *``````````````````````````````* * THE RND8 MACRO * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** THE RND8 MACRO RETURNS A PSEUDORANDOM NUMBER ** BETWEEN 0 AND 255 (THUS THE 8, FOR 8-BIT). ** THIS IS PASSED BACK VIA RETURN AND .A. * JSR ]HOME2 _PRN "THE RND8 MACRO",8D _PRN "==============",8D8D _PRN "SOME RANDOM NUMBERS:",8D8D RND8 DUMP #RETURN;#1 _PRN " " RND8 DUMP #RETURN;#1 _PRN " " RND8 DUMP #RETURN;#1 _WAIT * *``````````````````````````````* * THE RAND MACRO * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** THE RAND MACRO TAKES A LOW VALUE AND A ** HIGH VALUE AND PASSES BACK A RANDOM NUMBER ** BETWEEN THE TWO IN RETURN AND .A. * JSR ]HOME2 _PRN "THE RAND MACRO",8D _PRN "==============",8D8D _PRN "SOME RANDOM NUMBERS:",8D8D RAND #1;#30 DUMP #RETURN;#1 _PRN " " RAND #1;#30 DUMP #RETURN;#1 _PRN " " RAND #1;#30 DUMP #RETURN;#1 _WAIT * *``````````````````````````````* * THE RND16 MACRO * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** THE RND16 MACRO WORKS THE SAME WAY AS ** THE RND8 MACRO, EXCEPT THAT IT PASSES BACK ** A 16-BIT RANDOM VALUE VIA RETURN AS WELL AS ** IN .A (LOW BYTE) AND .X (HIGH). * JSR ]HOME2 _PRN "THE RND16 MACRO",8D _PRN "==============",8D8D _PRN "SOME RANDOM NUMBERS:",8D8D RND16 DUMP #RETURN;#2 _PRN " " RND16 DUMP #RETURN;#2 _PRN " " RND16 DUMP #RETURN;#2 _WAIT * JSR ]HOME2 _PRN "FIN!",8D8D8D * JMP REENTRY * *``````````````````````````````* * BOTTOM INCLUDES * *,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* * ** BOTTOM INCLUDES * PUT MIN.LIB.REQUIRE * ** INDIVIDUAL SUBROUTINE INCLUDES * PUT MIN.SUB.RAND8.ASM PUT MIN.SUB.RANDB.ASM PUT MIN.SUB.RAND16.ASM * SEED1 DW 1000 NUM1 DW 666 SEED2 DW 2000 NUM2 DB 200 ```