AppleIIAsm-Collection/documentation/AppleIIAsm Library Collection Technical Manual/0.6.1/33.0 Detailed_Reference_D4_MATH.md

5474 lines
174 KiB
Markdown
Raw Normal View History

# 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 <br />]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 <br />]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<br />]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<br />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<br />]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<br />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<br />]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<br />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<br />]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<br />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<br />]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<br />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<br />]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<br />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<br />]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<br />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<br />]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<br />]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 <br />between a given low and high value |
| Input | ]1 = lower boundary <br />]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 <br />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
```