mirror of
https://github.com/nathanriggs/AppleIIAsm-Collection.git
synced 2024-06-09 23:29:29 +00:00
c28c9d87da
Cleaned up disk one documentation, both inline and in the manual
5107 lines
197 KiB
Markdown
5107 lines
197 KiB
Markdown
# Disk 2 : STDIO Library and Aliases
|
|
|
|
- [Part I: The STDIO Library](#part-i-stdio-macros-and-subroutine-library)
|
|
- [STDIO Components](#stdio-components)
|
|
- [STDIO Header File](#stdio-header-file)
|
|
- [Next Up: STDIO Macros](#macros-and-subroutines)
|
|
- [COUT Text Output](#cout-macros-and-subroutines)
|
|
- [The `CURB` Macro](#the-curb-macro)
|
|
- [The `CURD` Macro](#the-curd-macro)
|
|
- [The `CURF` Macro](#the-curf-macro)
|
|
- [The `CURU` Macro](#the-curu-macro)
|
|
- [The `PRN` Macro](#the-prn-macro)
|
|
- [The `DPRINT` Subroutine](#the-dprint-subroutine)
|
|
- [The `XPRINT` Subroutine](#the-xprint-subroutine)
|
|
- [The `SCPOS` Macro](#the-scpos-macro)
|
|
- [The `SETCX` Macro](#the-setcx-macro)
|
|
- [The `SETCY` Macro](#the-setcy-macro)
|
|
- [The `SPRN` Macro](#the-sprn-macro)
|
|
- [The `PRNSTR` Subroutine](#the-prnstr-subroutine)
|
|
- [The `TMORE` Macro](#the-tmore-macro)
|
|
- [The `TXTMORE` Subroutine](#the-txtmore-subroutine)
|
|
- [Direct Memory Text Input / Output](#screen-memory-macros-and-subroutines)
|
|
- [The `CPUT` Macro](#the-cput-macro)
|
|
- [The `TXTPUT` Subroutine](#the-txtput-subroutine)
|
|
- [The `RCPOS` Macro](#the-rcpos-macro)
|
|
- [The `SPUT` Macro](#the-sput-macro)
|
|
- [The `STRPUT` Subroutine](#the-strput-subroutine)
|
|
- [The `TCIRC` Macro](#the-tcirc-macro)
|
|
- [The `TCIRCLE` Subroutine](#the-tcircle-subroutine)
|
|
- [The `TCLR` Macro](#the-tclr-macro)
|
|
- [The `TXTCLR` Subroutine](#the-txtclr-subroutine)
|
|
- [The `THLIN` Macro](#the-thlin-macro)
|
|
- [The `THLINE` Subroutine](#the-thline-subroutine)
|
|
- [The `TREC` Macro](#the-trec-macro)
|
|
- [The `TRECT` Subroutine](#the-trect-subroutine)
|
|
- [The `TRECF` Macro](#the-trecf-macro)
|
|
- [The `TRECTF` Subroutine](#the-trectf-subroutine)
|
|
- [The `TLINE` Macro](#the-tline-macro)
|
|
- [The `TBLINE` Subroutine](#the-tbline-subroutine)
|
|
- [The `TVLIN` Macro](#the-tvlin-macro)
|
|
- [The `TVLINE` Subroutine](#the-tvline-subroutine)
|
|
- [Standard Input](#)
|
|
- [The `GKEY` Macro](#)
|
|
- [The `INP` Macro](#)
|
|
- [The `SINPUT` Subroutine](#)
|
|
- [The `PBX` Macro](#)
|
|
- [The `PDL` Macro](#)
|
|
- [The `WAIT` Macro](#)
|
|
- [Misc](#miscellaneous-macros-and-subroutines)
|
|
- [The `COL40` Macro](#the-col40-macro)
|
|
- [The `COL80` Macro](#the-col80-macro)
|
|
- [The `DIE80` Macro](#the-die80-macro)
|
|
- [The `TCTR` Macro](#the-tctr-macro)
|
|
- [The `TXTCENT` Subroutine](#the-txtcent-macro)
|
|
- [PART II: STDIO Collection Demo File](#part-ii-stdio-collection-demo-file)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## PART I: STDIO Macros and Subroutine Library
|
|
|
|
The second disk in the AppleIIAsm Library includes all of the macros, subroutines, vectors and reserved memory locations for standard input and output on the Apple II. Note that by "Standard Output," we are primarily referring to the text screen only, and 40-column mode at that. A separate disk, as part of the "inessential" collection, will deal with 80-column mode as well as devices like printers. As for "Standard Input," here we refer to the keyboard and game paddle, though there are plans to also include optional mouse macros and subroutines (in some cases, the mouse is dealt with in the same fashion as the game paddle). Note that as with all libraries, the **STDIO** collection will not function properly without the **REQUIRED** collection.
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## STDIO Components
|
|
|
|
The STDIO collection contains the following components:
|
|
|
|
- A header file with various hooks, vectors and definitions for the rest of the library as well as use by the end programmer.
|
|
- Macros and subroutines dedicated to standard input and output, which includes keyboard and paddle input routines, 40-column text printing routines, basic text-mode drawing routines, and various macros and subroutines that support other functions provided by the Apple II that don't fit into the previous categories so well.
|
|
- COUT versus non-COUT components. Note that some routines use COUT, while others use direct screen memory manipulation (which is why some macros, especially those for drawing, will not translate to 80-column mode). Whether a macro or subroutine uses COUT is listed under the appropriate section. In general, the macros and subroutines are already listed categorically as such.
|
|
|
|
Macros are largely grouped here by function rather than by a more arbitrary alphabetical scheme, as used in the **REQUIRED** collection documentation. First, macros and subroutines that do not fit in with any of the other categories will be covered. This seems counterintuitive at first, but hopefully the reasoning for it will reveal itself as the documentation is read (long story short: these miscellaneous subroutines can have drastic effects on the rest of the subroutines). Next, COUT cursor macros and subroutines are detailed, followed by standard input routines and screen output routines that rely on COUT for functionality.
|
|
|
|
Lastly, macros and subroutines that directly access screen memory to output characters are covered. Usually, these subroutines and macros are dedicated to creating shapes, lines, and ASCII art in general. Note that while this can be used in tandem with the macros and subroutines that use COUT, the standard COUT routine will not recognize that these characters have been plotted, and the cursor position will remain the same as before.
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## STDIO Header File
|
|
|
|
_Summary_
|
|
|
|
The STDIO header file is required for all macros and subroutines to work correctly, although there may be a select few that can get away without its inclusion. Primarily, this header file contains vectors and hooks that point to routines found in the Monitor.
|
|
|
|
| Condition | Value |
|
|
| --- | --- |
|
|
| Name | File: HEAD.STDIO.ASM |
|
|
| Type | Header File |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 19-JAN-2020 |
|
|
| Assembler | Merlin 8 Pro |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Provide appropriate hooks for standard input and output |
|
|
| Dependencies | none |
|
|
| Bytes | 0 |
|
|
| Notes | Repeatedly used subroutines by the library may be placed here in the future |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
As with all files in the collection, this header file includes a short heading that provides contact information, date last changed, number of bytes, a short description, etc.
|
|
|
|
`LISTING 2.0: HEAD.STDIO File Heading`
|
|
|
|
```asm
|
|
*
|
|
*``````````````````````````````*
|
|
* HEAD.REQUIRED *
|
|
* *
|
|
* THESE ARE HOOKS THAT ARE *
|
|
* USED BY THE STDIO LIBRARY. *
|
|
* *
|
|
* AUTHOR: NATHAN RIGGS *
|
|
* CONTACT: NATHAN.RIGGS@ *
|
|
* OUTLOOK.COM *
|
|
* *
|
|
* DATE: 19-JAN-2020 *
|
|
* ASSEMBLER: Merlin Pro 8 *
|
|
* OS: DOS 3.3 *
|
|
* *
|
|
* BYTES: 0 *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
```
|
|
|
|
Most of the pointers in the STDIO header are rather self-explanatory, and therefore will not be covered here. When used, some of these may be explained more in the macro or subroutine documentation.
|
|
|
|
`LISTING 2.10: HEAD.STDIO Source`
|
|
|
|
```asm
|
|
*
|
|
*``````````````````````````````*
|
|
* HEAD.STDIO.ASM *
|
|
* *
|
|
* THESE ARE HOOKS, VECTORS AND *
|
|
* POINTERS THAT ARE USED BY *
|
|
* THE STDIO LIBRARY. *
|
|
* *
|
|
* AUTHOR: NATHAN RIGGS *
|
|
* CONTACT: NATHAN.RIGGS@ *
|
|
* OUTLOOK.COM *
|
|
* *
|
|
* DATE: 19-JAN-2020 *
|
|
* ASSEMBLER: MERLIN 8 PRO *
|
|
* OS: DOS 3.3 *
|
|
* *
|
|
* BYTES: 0 *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
* OUTPUT
|
|
*
|
|
COUT1 EQU $FDF0 ; FASTER SCREEN OUTPUT
|
|
COUT EQU $FDED ; MONITOR STD OUTPUT
|
|
HOME EQU $FC58 ; CLEAR SCREEN, HOME CURSOR
|
|
VTAB EQU $FC22 ; MONITOR CURSOR POS ROUTINE
|
|
CURSH EQU $24 ; HPOS OF COUT CURSOR
|
|
CURSV EQU $25 ; VPOS OF COUT CURSOR
|
|
KEYBUFF EQU $0200 ; KEYBUFFER START
|
|
GSTROBE EQU $C040 ; GAME CONNECTOR STROBE
|
|
GBCALC EQU $F847 ; SCREEN CALCULATION
|
|
GBPSH EQU $26 ; VALUE RETURNED BY GBCALC
|
|
*
|
|
* INPUT
|
|
*
|
|
KYBD EQU $C000 ; LDA SINGLE KEYPRESS
|
|
STROBE EQU $C010 ; CLEAR KYBD BUFFER
|
|
GETLN EQU $FD6F ; MONITOR GET LINE OF KB INPUT
|
|
GETKEY EQU $FD0C ; MONITOR GET SINGLE KEY INPUT
|
|
*
|
|
* PADDLE ADDRESS LABELS
|
|
*
|
|
PREAD EQU $FB1E ; READ STATE OF PADDLE
|
|
PB0 EQU $C061 ; PADDLE BUTTON 0
|
|
PB1 EQU $C062 ; PADDLE BUTTON 1
|
|
PB2 EQU $C063 ; PADDLE BUTTON 2
|
|
PB3 EQU $C060 ; PADDLE BUTTON 3
|
|
*
|
|
** UNUSED BY LIBRARY
|
|
*
|
|
WNDLEFT EQU $20 ; SCROLL WINDOW LEFT
|
|
WNDWIDTH EQU $21 ; SCROLL WINDOW WIDTH
|
|
WNDTOP EQU $22 ; SCROLL WINDOW TOP
|
|
WNDBOT EQU $23 ; SCROLL WINDOW BOTTOM
|
|
TEXTP1 EQU $0400 ; START OF TEXT PAGE 1
|
|
TEXTP2 EQU $0800 ; START OF TEXT PAGE 2
|
|
PAGE1 EQU $C054 ; SOFT SWITCH USE PAGE 1
|
|
PAGE2 EQU $C055 ; SOFT SWITCH USE PAGE 2
|
|
S80COL EQU $C01F ; READ ONLY; CHECK IF 80C
|
|
TXTSET EQU $C051 ; TEXT ON SOFT SWITCH
|
|
SETWND EQU $FB4B ; SET NORMAL WINDOW MODE
|
|
CURADV EQU $FBF4 ; ADVANCE CURSOR RIGHT
|
|
CURBS EQU $FC10 ; CURSOR LEFT
|
|
CURUP EQU $FC1A ; CURSOR UP
|
|
CR EQU $FC62 ; CARRIAGE RETURN TO SCREEN
|
|
LF EQU $FC66 ; LINE FEED ONLY TO SCREEN
|
|
CLEOL EQU $FC9C ; CLEAR TEXT TO END OF LINE
|
|
OPAPP EQU $C061 ; OPEN-APPLE KEY
|
|
CLAPP EQU $C062 ; CLOSED-APPLE KEY
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## Macros and Subroutines
|
|
|
|
The **STDIO** collection is separated into three distinct groups of macros and subroutines, with the corresponding macros placed in a file that represents each group: COUT-based components, Direct Screen Memory components, and Miscellaneous components. This is primarily for convenience: very often, you'll only want to use the COUT components without the bells and whistles of the Direct Memory accessing components, or vice versa. However, this also serves a more practical purpose: if all of the macros were held in a single file, memory usage by the assembler could become an issue. Because of this ever-present threat, it is always good practice to copy the macros and subroutines that you need, then delete any unused macros, in the final product.
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## COUT Macros and Subroutines
|
|
|
|
All macros that use COUT functionality for output are held in the `MAC.COUT.STDOUT.ASM` file. These macros and subroutines play nicely with the standard COUT features of the Apple II, which should be familiar terrain to even Applesoft programmers. Unless plotting text to the screen display quickly is a high concern, the macros and subroutines in this group and file should serve most mundane purposes.
|
|
|
|
|
|
|
|
`LISTING 2.20: MAC.COUT.STDOUT.ASM Heading`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* MAC.COUT.STDOUT.ASM *
|
|
* *
|
|
* THIS IS A MACRO LIBRARY FOR *
|
|
* STANDARD INPUT AND OUTPUT. *
|
|
* *
|
|
* AUTHOR: NATHAN RIGGS *
|
|
* CONTACT: NATHAN.RIGGS@ *
|
|
* OUTLOOK.COM *
|
|
* *
|
|
* DATE: 11-MAR-2021 *
|
|
* ASSEMBLER: MERLIN 8 PRO *
|
|
* OS: DOS 3.3 *
|
|
* *
|
|
* SUBROUTINES FILES USED: *
|
|
* *
|
|
* SUB.XPRINT *
|
|
* SUB.DPRINT *
|
|
* SUB.PRNSTR *
|
|
* SUB.TXTMORE *
|
|
* SUB.TXTCENT *
|
|
* *
|
|
* LIST OF MACROS *
|
|
* *
|
|
* PRN : FLEXIBLE PRINT *
|
|
* SPRN : PRINT STRING *
|
|
* SCPOS : SET CURS POS AT X,Y *
|
|
* SETCX : SET CURSOR X *
|
|
* SETCY : SET CURSOR Y *
|
|
* CURF : CURSOR FORWARD *
|
|
* CURB : CURSOR BACKWARD *
|
|
* CURU : CURSOR UP *
|
|
* CURD : CURSOR DOWN *
|
|
* TMORE : TEXT MORE WRAPPER *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE PRN MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --- | --- |
|
|
| Name | `PRN` |
|
|
| Type | Macro |
|
|
| File | `MAC.COUT.STDOUT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Print a literal string or a null-terminated string at a given address |
|
|
| Input | ]1 = memory address or literal string |
|
|
| Output | Text displayed at current cursor position |
|
|
| Dependencies | `SUB.DPRINT.ASM` `SUB.XPRINT.ASM` |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 159+ |
|
|
| Bytes | 34+ |
|
|
| Notes | Note that as with all macros that may take an address as its parameter, a literal address (#$0000) indicates that the address is where the string resides, whereas a regular address reference indicates that the address holds a pointer to the correct address of the string. |
|
|
| See Also | `XPRINT` `DPRINT` `SPRN` `PRNSTR` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `PRN` macro does what you would expect it to do: it prints characters to the screen via COUT. This is slower than directly altering screen memory, but in many cases is preferable because it allows for the many affordances provided by COUT. `Listing 2.21` provides the source code for the `PRN` macro, which utilizes the `DPRINT` or `XPRINT` subroutines, depending on the parameter passed to the macro.
|
|
|
|
|
|
|
|
`LISTING 2.21: The PRN Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* PRN *
|
|
* *
|
|
* PRINT A LITERAL STRING OR *
|
|
* A NULL-TERMINATED STRING AT *
|
|
* A GIVEN ADDRESS. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = STRING OR ADDRESS *
|
|
* *
|
|
* CYCLES: 159+ OR 127+ *
|
|
* BYTES: 34+ OR 24+ *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
PRN MAC
|
|
IF ",]1 ; {0C0B} IF PARAM IS A STRING
|
|
JSR XPRINT ; (159C31B} GOSUB TO STACK PRINT ROUTINE
|
|
ASC ]1 ; {0C1B} PUT STRING HERE FOR STACK
|
|
HEX 00 ; {0C1B} PRINT TO ACCESS; TERMINATE STRING
|
|
ELSE ; {0C0B} OTHERWISE, PARAM IS AN ADDRESS
|
|
_MLIT ]1;WPAR1 ; {16C12B} SO PARSE ADDRESS FOR DIRECT OR
|
|
JSR DPRINT ; {111C12B} INDIRECT PASSING, THEN GOSUB
|
|
FIN ; REGULAR PRINT ROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
If a literal string is passed as a parameter, the `PRN` macro allocates the required number of bytes for its storage in memory and calls the `XPRINT` subroutine to display the characters on the screen. While this is extremely useful, care should be taken not to use this feature too much: the number of bytes allocated by the macro add up quickly, and the memory used is not regained; the bytes are allocated permanently. When possible, a null-terminated string address should be used instead, as the user can then allocate space in any way necessary. For instance, a block of memory could be used and reused to read in string data from a file, significantly cutting down the total memory used by a program.
|
|
|
|
If an address is passed, as suggested, then the macro treats the address like any other macro treats a potential address: a literal address, preceded by a **#** sign, indicates that the string is located at the address (direct), whereas an address reference without the pound sign indicates that the address located at the reference points to where the string is located (indirect). This is parsed via the `_MLIT` macro and passed to the `DPRINT` subroutine, which is dedicated to printing null-terminated strings (for regular strings that have a preceding length-byte, see the `SPRN` macro).
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE DPRINT SUBROUTINE
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------- |
|
|
| Name | `DPRINT` |
|
|
| Type | Subroutine |
|
|
| File | `SUB.DPRINT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Print a null-terminated string passed via address |
|
|
| Input | ]1 = memory address |
|
|
| Output | *variable* |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 111+ |
|
|
| Bytes | 12+ |
|
|
| Notes | Required by the PRN Macro |
|
|
| See Also | `XPRINT` `SPRN` `PRNSTR` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
As `Listing 2.22` shows, the `DPRINT` subroutine accepts a single parameter that is passed via the zero page, which points to the address of the null-terminated string to be printed. The subroutine uses a simple loop to send each character of the string to COUT one at a time until a null value ($00) is found or 255 bytes have been read, at which point the loop is exited and the subroutine returns control to the calling routine.
|
|
|
|
|
|
|
|
`LISTING 2.22: DPRINT Subroutine Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* DPRINT (NATHAN RIGGS) *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* WPAR1 = STRING ADDRESS (2B) *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* PRINT A ZERO-TERMINATED *
|
|
* STRING AT A GIVEN ADDRESS. *
|
|
* *
|
|
* DESTROYS: NZCIDV *
|
|
* ^^^ ^ *
|
|
* *
|
|
* CYCLES: 111+ *
|
|
* SIZE: 12 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
]ADDR1 EQU WPAR1 ; INDIRECT ADDRESS IS PASSED HERE
|
|
*
|
|
DPRINT
|
|
*
|
|
LDY #$00 ; {2C2B} RESET COUNTER {NZ}
|
|
:LOOP
|
|
LDA (]ADDR1),Y ; {6C2B} GET NEXT CHARACTER IN STRING {NZ}
|
|
BEQ :EXIT ; {3C2B} IF CHAR = $00 THEN EXIT
|
|
JSR COUT1 ; {89C2B} OTHERWISE, PRINT CHAR {NZCV}
|
|
INY ; {2C1B} INCREAS COUNTER {NZ}
|
|
BNE :LOOP ; {3C2B} IF COUNTER < 256, LOOP
|
|
:EXIT
|
|
RTS ; {6C1B} RETURN TO CALLING ROUTINE
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE XPRINT SUBROUTINE
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `XPRINT` |
|
|
| Type | Subroutine |
|
|
| File | `SUB.XPRINT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Print a null-terminated string that follows the call to the procedure |
|
|
| Input | none (string put after call to routine) |
|
|
| Output | *variable* |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 111+ |
|
|
| Bytes | 12+ |
|
|
| Notes | Required by the PRN Macro |
|
|
| See Also | `DPRINT` `SPRN` `PRNSTR` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `XPRINT` subroutine sends to COUT the null-terminated string that directly follows the calling of the subroutine, which can be helpful when passing literal strings to the `PRN` macro. This is accomplished with a little bit of program stack trickery: the current address of execution is stored until the printing is finished, at which point the execution address is recalculated (by adding the number of bytes in the string and its null terminator) and fed into the `RTS` command.
|
|
|
|
While the `DPRINT` subroutine could be used in a functionally equivalent manner, `XPRINT` is used to exclusively indicate that a string is being stored and accessed during runtime. This also presents an easy way for beginners to print text to the screen that somewhat resembles BASIC syntax.
|
|
|
|
|
|
|
|
`LISTING 2.23: XPRINT Subroutine Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* XPRINT (NATHAN RIGGS) *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* BYTES IMMEDIATELY AFTER THE *
|
|
* CALL TO THE SUBROUTINE ARE *
|
|
* PRINTED TO THE SCREEN UNTIL *
|
|
* A #00 IS ENCOUNTERED OR *
|
|
* 256 CHARS HAVE BEEN REACHED *
|
|
* *
|
|
* OUTPUT *
|
|
* *
|
|
* STRING TO SCREEN *
|
|
* *
|
|
* DESTROY: NZCDIV *
|
|
* ^^^ ^ *
|
|
* *
|
|
* CYCLES: 159+ *
|
|
* SIZE: 31 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
XPRINT
|
|
PLA ; {4C1B} GET CURRENT EXEC ADDRESS {NZ}
|
|
STA ADDR1 ; {3C2B} AND STORE IN ZERO PAGE
|
|
PLA ; {4C1B} GET HIGH BYTE {NZ}
|
|
STA ADDR1+1 ; {3C2B} AND ALSO STORE AT ZP+1
|
|
LDY #$01 ; {2C2B} LOAD .Y WITH #1 TO POINT {NZ}
|
|
; TO INSTRUCTION AFTER ADDRESS
|
|
:LOOP
|
|
LDA (ADDR1),Y ; {6C2B} GET CHARACTER FROM NEXT BYTE {NZ}
|
|
BEQ :EXIT ; {3C2B} IF CHAR = $00 THEN EXIT LOOP
|
|
JSR COUT1 ; {89C2B} OTHERWISE, PRINT CHAR {NZCV}
|
|
INY ; {2C1B} INCREASE THE BYTE INDEX {NZ}
|
|
BNE :LOOP ; {3C2B} IF INDEX < 255, LOOP
|
|
:EXIT
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
TYA ; {2C1B} MOVE .Y INDEX TO .A FOR ADDITION {NZ}
|
|
ADC ADDR1 ; {3C2B} ADD EXECUTION ADDRESS LOW BYTE {NZCV}
|
|
STA ADDR1 ; {3C2B} SAVE AGAIN ON ZERO PAGE
|
|
LDA ADDR1+1 ; {3C2B} GET EXECUTION ADDRESS HIGH BYTE {NZ}
|
|
ADC #$00 ; {2C2B} ADD CARRY (ADD 1 TO HI IF C=1) {NZCV}
|
|
PHA ; {3C1B} PUSH TNEW HIGH BYTE TO STACK
|
|
LDA ADDR1 ; {3C2B} LOAD THE LOW BYTE {NZ}
|
|
PHA ; {3C1B} PUSH NEW LOW BYTE TO STACK
|
|
RTS ; {6C1B} RETURN TO NEW EXECUTION ADDRESS
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE SPRN MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | -------------------------------------------- |
|
|
| Name | `SPRN` |
|
|
| Type | Macro |
|
|
| File | `MAC.COUT.STDOUT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Displays string with a preceding length byte |
|
|
| Input | ]1 = memory address or literal string |
|
|
| Output | *variable* |
|
|
| Dependencies | `SUB.PRNSTR.ASM` |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 147+ |
|
|
| Bytes | 35 |
|
|
| Notes | none |
|
|
| See Also | `XPRINT` `DPRINT` `PRNSTR` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
Strings come in two distinct forms: either they are null-terminated, meaning that a string continues until a value of $00 is found, or they have a preceding length byte that determines the length of the string (note: special cases, like long strings, may have a preceding two-byte word to indicate the string length). The `PRN` macro already handles the former case while the `SPRN` macro addresses the latter case: printing a string to the screen, via COUT, with an established length byte.
|
|
|
|
Generally, this kind of string should be used over that of null-terminated strings (although there are special exceptions). Using a preceding length byte makes strings easier to manage, but it does require a separate printing mechanism. The `SPRN` macro, along with its embedded `PRNSTR` subroutine, serve this end. Note that this macro and its subroutine assumes an 8-bit string with no more than 255 characters, thus allowing for a single preceding byte to convey the string's length.
|
|
|
|
The `SPRN` macro is about as simple as a macro gets: the parameters are packed into the registers for passing to the `PRNSTR` subroutine, then the subroutine is called.
|
|
|
|
|
|
|
|
`LISTING 2.24: SPRN Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* SPRN *
|
|
* *
|
|
* PRINTS THE STRING LOCATED AT *
|
|
* THE SPECIFIED ADDRESS, WHICH *
|
|
* HAS A PRECEDING LENGTH BYTE. *
|
|
* *
|
|
* PARAMETERS: *
|
|
* *
|
|
* ]1 = STRING ADDRESS *
|
|
* *
|
|
* CYCLES: 147+ *
|
|
* SIZE: 35 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
SPRN MAC
|
|
_AXLIT ]1 ; {8C6B} PARSE INTO REGISTERS
|
|
JSR PRNSTR ; {139C29B} EXECUTE PRNSTR ROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE PRNSTR SUBROUTINE
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ----------------------------------------------------- |
|
|
| Name | `PRNSTR` |
|
|
| Type | Subroutine |
|
|
| File | `SUB.PRNSTR.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Prints a string with a preceding length byte via COUT |
|
|
| Input | ]1 = memory address or literal string |
|
|
| Output | *variable* |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 133+ |
|
|
| Bytes | 26+ |
|
|
| Notes | none |
|
|
| See Also | `XPRINT` `DPRINT` `SPRN` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `PRNSTR` subroutine accepts an address that points to a normal string in the .A and .X registers (low byte and high byte, respectively). This address is first stored in the zero page to allow for indirect referencing, and the first byte, which contains the length of the string, is stored in temporary variable space for later access. After this brief setup is accomplished, the string is then displayed via a simple loop: each character is sent to COUT, one after the other, until the length of the string is reached. Control is then returned to the calling routine.
|
|
|
|
|
|
|
|
`LISTING 2.25: PRNSTR Subroutine Source`
|
|
|
|
```assembly
|
|
*``````````````````````````````*
|
|
* PRNSTR (NATHAN RIGGS) *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* .A = ADDRESS LOBYTE *
|
|
* .X = ADDRESS HIBYTE *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* PRINTS STRING TO SCREEN. *
|
|
* *
|
|
* DESTROY: NZCIDV *
|
|
* ^^^ ^ *
|
|
* *
|
|
* CYCLES: 133+ *
|
|
* SIZE: 26 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
]STRLEN EQU VARTAB ; STRING LENGTH
|
|
*
|
|
PRNSTR
|
|
*
|
|
STA ADDR1 ; {3C2B} STORE ADDRESS IN ZERO PAGE
|
|
STX ADDR1+1 ; {3C2B} STORE ADDRESS IN ZERO PAGE
|
|
LDY #0 ; {2C2B} RESET INDEX {NZ}
|
|
LDA (ADDR1),Y ; {6C2B} GET STRING LENGTH {NZ}
|
|
STA ]STRLEN ; {4C3B} AND STORE IT IN MEM
|
|
:LP
|
|
INY ; {3C1B} INCREASE INDEX {NZ}
|
|
LDA (ADDR1),Y ; {6C2B} GET CHARACTER {NZ}
|
|
JSR COUT1 ; {89C3B} PRINT CHARACTER TO SCREEN {NZCV}
|
|
CPY ]STRLEN ; {4C3B} IF Y < LENGTH {NZ}
|
|
BNE :LP ; {3C2B} THEN LOOP; ELSE
|
|
LDA ]STRLEN ; {4C3B} LOAD STRING LENGTH {NZ}
|
|
RTS ; {6C1B} RETURN TO CALLING ROUTINE
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE SCPOS MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ---------------------------------------- |
|
|
| Name | `SCPOS` |
|
|
| Type | Macro |
|
|
| File | `MAC.COUT.STDOUT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Set COUT cursor to given coordinates |
|
|
| Input | ]1 = X-coordinate<br />]2 = Y-coordinate |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 10+ |
|
|
| Bytes | 8 |
|
|
| Notes | none |
|
|
| See Also | `SETCX` `SETCY` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `SCPOS` macro sets the coordinates of the COUT cursor in a single sweep by calling the `VTAB` monitor routine, which should exist in every Apple II (and related emulators). The X position (or number of columns) is passed first and stored in `CURSH` on the zero page for `VTAB` to access, and the Y position (or row number) is passed second and stored in `CURSV` on the zero page. `VTAB` is then executed before returning control to the parent program.
|
|
|
|
Note that the cursor position is permanently changed, and cannot be undone without storing the current coordinates (found in `CURSH` and `CURSV`) before calling the macro.
|
|
|
|
|
|
|
|
`LISTING 2.26: SCPOS Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* SCPOS *
|
|
* *
|
|
* SETS THE CURSOR POSITION. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = X POSITION *
|
|
* ]2 = Y POSITION *
|
|
* *
|
|
* CYCLES: 10+ *
|
|
* SIZE: 8 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
SCPOS MAC
|
|
LDX ]1 ; {2C2B} HORIZONTAL POSITION
|
|
STX CURSH ; {3C2B}
|
|
LDX ]2 ; {2C2B} VERTICAL POSITION
|
|
STX CURSV ; {3C2B}
|
|
JSR VTAB ; {????} EXECUTE VTAB ROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE SETCX MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ---------------------------------------------- |
|
|
| Name | `SETCX` |
|
|
| Type | Macro |
|
|
| File | `MAC.COUT.STDOUT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Set COUT cursor to given X-coordinate (column) |
|
|
| Input | ]1 = X-coordinate |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 10+ |
|
|
| Bytes | 8 |
|
|
| Notes | none |
|
|
| See Also | `SCPOS` `SETCY` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `SETCX` macro simply sets the X-coordinate of the COUT cursor, independent of the Y-coordinate. While the `SCPOS` macro can be used to replace `SETCX` and `SETCY` (next) alike, there are cases in which a user may only wish to change one or the other, saving a couple spare cycles in the process.
|
|
|
|
|
|
|
|
`LISTING 2.27: The SETCX Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* SETCX *
|
|
* *
|
|
* SETS THE CURSOR X POSITION. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = X POSITION *
|
|
* *
|
|
* CYCLES: 4+ *
|
|
* SIZE: 5 *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
SETCX MAC
|
|
LDX ]1 ; {2C2B} GET HORIZONTAL POS
|
|
STX CURSH ; {2C3B} AND STORE IN CURSH
|
|
JSR VTAB ; {????} CALL VTAB ROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE SETCY MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ---------------------------------------------- |
|
|
| Name | `SETCXY` |
|
|
| Type | Macro |
|
|
| File | `MAC.COUT.STDOUT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Set COUT cursor to given Y-coordinate (column) |
|
|
| Input | ]1 = X-coordinate |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 4+ |
|
|
| Bytes | 5 |
|
|
| Notes | none |
|
|
| See Also | `SCPOS` `SETCX` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `SETCY` macro sets the Y-coordinate of the COUT cursor, independent of the X-coordinate. Again, the `SCPOS` can be used to this effect, but there are cases in which a user wants to set the Y-coordinate alone.
|
|
|
|
|
|
|
|
`LISTING 2.28: The SETCY Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* SETCY *
|
|
* *
|
|
* SET THE CURSOR Y POSITION. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = Y POSITION *
|
|
* *
|
|
* CYCLES: 4+ *
|
|
* SIZE: 5+ *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
SETCY MAC
|
|
LDY ]1 ; {2C2B} VERTICAL POSITION
|
|
STY CURSV ; {2C3B} INTO CURSV LOCATION
|
|
JSR VTAB ; {????} CALL VTAB ROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE CURF MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ---------------------------------------------- |
|
|
| Name | `CURF` |
|
|
| Type | Macro |
|
|
| File | `MAC.COUT.STDOUT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Move COUT cursor forward by a number of spaces |
|
|
| Input | ]1 = number of spaces to move |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 10+ |
|
|
| Bytes | 7 |
|
|
| Notes | none |
|
|
| See Also | `CURB` `CURD` `CURU` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `CURF` macro increases the current X-position of the COUT cursor by a given number of spaces.
|
|
|
|
|
|
|
|
`LISTING 2.29: The CURF Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* CURF *
|
|
* *
|
|
* MOVE CURSOR FORWARD A NUMBER *
|
|
* OF SPACES. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = # OF SPACES TO MOVE *
|
|
* *
|
|
* CYCLES: 10+ *
|
|
* SIZE: 7+ BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
CURF MAC
|
|
LDA ]1 ; {2C2B} SPACES TO ADD TO
|
|
CLC ; {2C1B} CURRENT POSITION
|
|
ADC CURSH ; {3C2B} ADD CURRENT POSITION
|
|
STA CURSH ; {3C2B} STORE NEW IN CURSH
|
|
JSR VTAB ; {????} CALL VTAB ROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE CURB MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ----------------------------------------------- |
|
|
| Name | `CURB` |
|
|
| Type | Macro |
|
|
| File | `MAC.COUT.STDOUT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Move COUT cursor backward by a number of spaces |
|
|
| Input | ]1 = number of spaces to move |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 10+ |
|
|
| Bytes | 7 |
|
|
| Notes | none |
|
|
| See Also | `CURD` `CURF` `CURU` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `CURB` macro decreases the current X-position of the COUT cursor by a given number of spaces.
|
|
|
|
|
|
|
|
`LISTING 2.30: The CURB Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* CURB *
|
|
* *
|
|
* MOVE THE CURSOR BACKWARD BY *
|
|
* A NUMBER OF SPACES. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = # OF SPACES TO MOVE *
|
|
* *
|
|
* CYCLES: 10+ *
|
|
* SIZE: 7 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
CURB MAC
|
|
LDA CURSH ; {2C2B} GET CURRENT CURSOR XPOS
|
|
SEC ; {2C1B} SET CARRY
|
|
SBC ]1 ; {3C2B} SUBTRACT # OF SPACES PASSED
|
|
STA CURSH ; {3C2B} AND STORE BACK IN CURSH
|
|
JSR VTAB ; {????} EXEC VTAB SUBROUTINE
|
|
<<<
|
|
*
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE CURU MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | --------------------------------------------- |
|
|
| Name | `CURU` |
|
|
| Type | Macro |
|
|
| File | `MAC.COUT.STDOUT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Move COUT cursor upward by a number of spaces |
|
|
| Input | ]1 = number of spaces to move |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 10+ |
|
|
| Bytes | 7 |
|
|
| Notes | none |
|
|
| See Also | `CURB` `CURD` `CURF` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `CURU` macro decreases the current Y-position of the COUT cursor by a given number of spaces.
|
|
|
|
|
|
|
|
`LISTING 2.31: The CURU Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* CURU *
|
|
* *
|
|
* MOVE CURSOR UP BY A NUMBER *
|
|
* OF SPACES. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = # OF SPACES TO GO UP *
|
|
* *
|
|
* CYCLES: 10+ *
|
|
* SIZE: 7 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
CURU MAC
|
|
LDA CURSV ; {2C2B} GET CURRENT YPOS
|
|
SEC ; {2C1B} SET CARRY
|
|
SBC ]1 ; {3C2B} SUBTRACT GIVEN PARAM
|
|
STA CURSV ; {3C2B} AND STORE BACK IN CURSV
|
|
JSR VTAB ; {????} VTAB MONITOR ROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE CURD MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ----------------------------------------------- |
|
|
| Name | `CURD` |
|
|
| Type | Macro |
|
|
| File | `MAC.COUT.STDOUT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Move COUT cursor downward by a number of spaces |
|
|
| Input | ]1 = number of spaces to move |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 10+ |
|
|
| Bytes | 7 |
|
|
| Notes | none |
|
|
| See Also | `CURB` `CURF` `CURU` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `CURD` macro increases the current Y-position of the COUT cursor by a given number of spaces.
|
|
|
|
|
|
|
|
`LISTING 2.32: The CURD Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* CURD *
|
|
* *
|
|
* MOVE THE CURSOR DOWN BY A *
|
|
* NUMBER OF SPACES. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = # OF SPACES TO MOVE *
|
|
* *
|
|
* CYCLES: 9+ *
|
|
* SIZE: 8 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
CURD MAC
|
|
LDA CURSV ; {2C2B} GET CURRENT YPOS
|
|
CLC ; {2C1B} CLEAR CARRY
|
|
ADC ]1 ; {3C2B} ADD GIVEN PARAMETER
|
|
STA CURSV ; {2C3B} STORE BACK IN CURSV
|
|
JSR VTAB ; {????} EXEC VTAB SUBROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TMORE MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `TMORE` |
|
|
| Type | Macro |
|
|
| File | `MAC.COUT.STDOUT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | word-wrap a null-terminated string <br />across the screen and pause listing at given intervals |
|
|
| Input | ]1 = String Address<br />]2 = Line Length <br />]3 = Pausing Interval |
|
|
| Output | Zero-terminated string scrolling to the screen |
|
|
| Dependencies | `SUB.TXTMORE.ASM` |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 482+ |
|
|
| Bytes | 472 |
|
|
| Notes | none |
|
|
| See Also | `TXTMORE` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `TMORE` macro prints a null-terminated string to the screen, word-wrapping it as the lines are printed. Additionally, the macro can be set to pause at a specific interval of lines or, by passing zero in the third parameter, pausing the scroll of the string every time a line feed is encountered. The macro passes these parameters via the zero page to the `TXTMORE` subroutine, which is considerably more complicated than most subroutines in the STDIO collection. See the `TXTMORE`entry for a description of how the word-wrapping implementation works.
|
|
|
|
|
|
|
|
`LISTING 2.33: The TMORE Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TMORE *
|
|
* *
|
|
* SCROLL THROUGH A ZERO- *
|
|
* TERMINATED STRING ON THE *
|
|
* SCREEN, PAUSING EVERY GIVEN *
|
|
* INTERVAL _OR_ PAUSING EVERY *
|
|
* TIME A NEWLINE CHARACTER IS *
|
|
* ENCOUNTERED. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = STRING ADDRESS *
|
|
* ]2 = LINE MAXIMUM LENGTH *
|
|
* ]3 = LINE PAUSE INTERVAL, *
|
|
* EVERY NEWLINE IF = 0 *
|
|
* *
|
|
* CYCLES: 482+ *
|
|
* SIZE: 472 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
TMORE MAC
|
|
_MLIT ]1;WPAR1 ; {16C12B} PARSE ADDR TO ZERO PAGE
|
|
LDA ]2 ; {2C2B} LOAD MAX LENGTH
|
|
STA WPAR2 ; {3C2B} STORE IN ZERO PAGE
|
|
LDA ]3 ; {2C2B} LOAD LINE INTERVAL
|
|
STA BPAR1 ; {3C2B} STORE IN ZERO PAGE
|
|
JSR TXTMORE ; {????} CALL TXTMORE SUBROUTINE
|
|
<<<
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TXTMORE SUBROUTINE
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `TXTMORE` |
|
|
| Type | Subroutine |
|
|
| File | `MAC.COUT.STDOUT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 18-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | word-wrap a null-terminated string <br />across the screen and pause listing at given intervals |
|
|
| Input | ]1 = String Address<br />]2 = Line Length <br />]3 = Pausing Interval |
|
|
| Output | Zero-terminated string scrolling to the screen |
|
|
| Dependencies | `SUB.TXTMORE.ASM` |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 482+ |
|
|
| Bytes | 472 |
|
|
| Notes | none |
|
|
| See Also | `TMORE` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `TXTMORE` subroutine takes a null-terminated string and prints it to the screen, word-wrapping it and pausing for a keypress at a given interval. Alternatively, a zero interval can be passed to the subroutine that signals that a pause for a keypress should happen every time a newline character is read (#$8D).
|
|
|
|
`TXTMORE` looks considerably more complicated than most other subroutines in the STDIO collection, and thus deserves some explanation; it is not, however, as complicated as it might seem. First, a substring between the start of the string and the string start plus the maximum line length is checked for a null character. If one is found, then it means the end of the string is found in the substring, and control is passed to a final routine that prints what is left over of the string. If not found, then the subroutine prepares for the next steps for the substring.
|
|
|
|
Next, `TXTMORE` needs to find the last space found in the given substring. The index of this space is stored in temporary memory (if it is not found, then the index is the maximum line length). This means that we are ready to print the substring: each character is read and sent to COUT. If the character is a linefeed (#$8D) then the tracking of the number of printed lines is increased, and if the maximum number of lines is zero (as passed during the call to the subroutine) then the scrolling is paused until a user initiates a keypress.
|
|
|
|
Afterwards, we now have a line printed at the desired length; if the line count is equal to the given interval, execution is paused for a keypress. Now a new substring is created started where the last substring ended, and the new substring's end address is calculated by adding the maximum line length. These are placed in the beginning and ending address variables, and the whole process loops back to checking for a null character. Once the null character is found in a substring, that substring is printed, and control is returned back to the calling program.
|
|
|
|
|
|
|
|
`LISTING 2.34: TXTMORE Subroutine Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TXTMORE (NATHAN RIGGS) *
|
|
* THIS SUBROUTINE PRINTS A *
|
|
* NULL-TERMINATED STRING TO *
|
|
* THE SCREEN, WRAPPING THE *
|
|
* TEXT FOR A GIVEN LENGTH OF *
|
|
* EACH LINE. AFTER A GIVEN *
|
|
* NUMBER OF LINES ARE *
|
|
* PRINTED, SCROLLING PAUSES *
|
|
* WHILE THE READER CATCHES *
|
|
* UP. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* WPAR1 = STRING ADDRESS (2B) *
|
|
* WPAR2 = LINE LENGTH *
|
|
* BPAR1 = VERTICAL SCROLL *
|
|
* LENGTH TO PAUSE *
|
|
* *
|
|
* DESTROYS: NZCIDV *
|
|
* ^^^ ^ *
|
|
* *
|
|
* CYCLES: 466+ *
|
|
* SIZE: 452 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
]ADDR EQU WPAR1 ; STRING ADDRESS
|
|
]LEN EQU WPAR2 ; MAXIMUM LENGTH OF STRING
|
|
]SCROLL EQU BPAR1 ; MAXIMUM LINES BEFORE PAUSING
|
|
*
|
|
]START EQU VARTAB ; STARTING POINT OF CURRENT LINE
|
|
]END EQU VARTAB+2 ; ENDING OF CURRENT LINE
|
|
]PTR EQU WPAR3 ; POINTER BETWEEN START AND END
|
|
]LAST EQU VARTAB+4 ; LOCATION OF NULL TERMINATION
|
|
]LINES EQU VARTAB+6 ; LINE COUNTER
|
|
]LSPACE EQU VARTAB+8 ; LAST SPACE FOUND
|
|
*
|
|
TXTMORE
|
|
*
|
|
** INIT
|
|
*
|
|
LDA ]ADDR ; {2C2B} GET STRING ADDRESS LOW BYTE
|
|
STA ]START ; {3C2B} STORE AS START ADDRESS LOW BYTE
|
|
LDA ]ADDR+1 ; {2C2B} GET STRING ADDRESS HIGH BYTE
|
|
STA ]START+1 ; {3C2B} STORE AS START ADDRESS HIGH BYTE
|
|
*
|
|
LDA ]ADDR ; {2C2B} LOAD STRING ADDRESS LOW BYTE
|
|
CLC ; {2C1B} CLEAR CARRY
|
|
ADC ]LEN ; {2C2B} ADD LINE LENGTH
|
|
STA ]END ; {3C2B} STORE AS LINE END ADDR LOW BYTE
|
|
LDA ]ADDR+1 ; {2C2B} LOAD ADDRESS HIGH BYTE
|
|
ADC #0 ; {2C2B} ADD ZERO FOR CARRY
|
|
STA ]END+1 ; {2C3B} STORE AS LINE END ADDR HIGH BYTE
|
|
*
|
|
LDA #0 ; {2C2B} CLEAR REGISTERS
|
|
TAY ; {2C1B}
|
|
TAX ; {2C1B}
|
|
*
|
|
** FIRST, CHECK LINE FOR NULL TERMINATION
|
|
*
|
|
:ENTER
|
|
LDA ]START ; {2C2B} FIRST, COPY START INTO
|
|
STA ]PTR ; {3C32} OUR POINTER ADDRESS
|
|
LDA ]START+1 ; {2C2B} BOTH LOW BYTE AND HIGH BYTE
|
|
STA ]PTR+1 ; {3C2B}
|
|
*
|
|
** CHECK FOR NULL VALUE IN STRING
|
|
**
|
|
** LOOP WILL EXIT ONLY IF #$00 IS FOUND AT POINTER
|
|
** POSITION OR THE POINTER ADDRESS EQUALS THE ENDING ADDRESS
|
|
*
|
|
:NULCHK
|
|
LDY #0 ; {2C2B}
|
|
LDA (]PTR),Y ; {6C2B} LOAD CHAR AT CURRENT POINTER
|
|
CMP #0 ; {2C2B} COMPARE TO NULL
|
|
BEQ :FNDNULL ; {3C2B} IF NULL THEN GOTO :FNDNULL
|
|
LDA ]PTR+1 ; {2C2B} CHECK IF HIGH BYTE OF POINTER IS
|
|
CMP ]END+1 ; {2C2B} EQUAL TO HIGH BYTE OF ENDING
|
|
BNE :CNTLP1 ; {3C2B} IF NOT, CONTINUE LOOP
|
|
LDA ]PTR ; {2C2B} IF SO, CHECK LOW BYTE OF POINTER
|
|
CMP ]END ; {2C2B} TO SEE IF IT MATCHES END LOW BYTE
|
|
BEQ :NULCHKX ; {3C2B} IF IT DOES, THEN EXIT NULL FINDER
|
|
:CNTLP1
|
|
LDA ]PTR ; {2C2B} NULL NOT FOUND AND LOOP NOT DONE
|
|
CLC ; {2C1B} SO ADD ONE TO THE POINTER
|
|
ADC #1 ; {2C2B} LOW BYTE
|
|
STA ]PTR ; {3C2B}
|
|
LDA ]PTR+1 ; {2C2B} AND ADD CARRY TO THE HIGH BYTE
|
|
ADC #0 ; {2C2B} IF NEEDED
|
|
STA ]PTR+1 ; {3C2B}
|
|
JMP :NULCHK ; {3C3B} AND CONTINUE LOOP
|
|
*
|
|
** NULL VALUE HAS BEEN FOUND, SO STORE POINTER AND
|
|
** GO TO PRINTING LAST LINE OF THE STRING
|
|
*
|
|
:FNDNULL
|
|
LDA ]PTR ; {2C2B} COPY POINTER ADDRESS LOW BYTE
|
|
STA ]LAST ; {3C2B} TO THE ]LAST VAR FOR FINAL PRINT
|
|
LDA ]PTR+1 ; {2C2B} DO THE SAME WITH THE HIGH BYTE
|
|
STA ]LAST+1 ; {3C2B}
|
|
JMP :PRNLAST ; {3C3B} JUMP TO FINAL PRINTING
|
|
*
|
|
** END OF CHECKING FOR NULL. NO NULL WAS FOUND
|
|
*
|
|
:NULCHKX
|
|
*
|
|
** NOW FIND THE LAST SPACE BETWEEN ]START POSITION
|
|
** AND THE ]END POSITION BY COUNTING BACKWARDS UNTIL
|
|
** A SPACE IS FOUND
|
|
*
|
|
LDA ]END ; {2C2B} LOAD LAST ADDRESS LOW BYTE
|
|
STA ]PTR ; {3C2B} STORE IN POINTER
|
|
LDA ]END+1 ; {2C2B} LOAD THE HIGH BYTE AND
|
|
STA ]PTR+1 ; {3C2B} STORE POINTER HIGH BYTE
|
|
*
|
|
:SPCLOOP
|
|
LDY #0 ; {2C2B} CLEAR .Y INDEX
|
|
LDA (]PTR),Y ; {6C2B} LOAD CHAR AT CURRENT POINTER
|
|
CMP #" " ; {2C2B} COMPARE CHAR TO SPACE
|
|
BEQ :FNDSPC ; {3C2B} IF EQUAL, THEN GOTO :FNDSPC
|
|
LDA ]PTR ; {2C2B} OTHERWISE LOAD POINTER LOW BYTE
|
|
SEC ; {2C1B} SET CARRY
|
|
SBC #1 ; {2C2B} SUBTRACT 1 FROM ADDRESS
|
|
STA ]PTR ; {3C2B} STORE BACK IN LOW BYTE
|
|
LDA ]PTR+1 ; {2C2B} LOAD POINTER HIGH BYTE
|
|
SBC #0 ; {2C2B} SUBTRACT CARRY, IF NEEDED
|
|
STA ]PTR+1 ; {3C2B} STORE BACK IN HIGH BYTE
|
|
JMP :SPCLOOP ; {3C3B} LOOP UNTIL A SPACE IS FOUND
|
|
*
|
|
** THE LAST SPACE BETWEEN ]START AND ]END HAS BEEN FOUND!
|
|
*
|
|
:FNDSPC
|
|
LDA ]PTR ; {2C2B} LOAD LOW BYTE OF CURRENT PTR
|
|
STA ]LSPACE ; {3C2B} AND STORE INTO LAST SPACE VAR
|
|
STA ]END ; {3C2B}
|
|
LDA ]PTR+1 ; {2C2B} AND THEN DO THE SAME FOR THE
|
|
STA ]LSPACE+1 ; {3C2B} HIGH BYTE
|
|
STA ]END+1 ; {3C2B}
|
|
*
|
|
** RESET POINTER AGAIN
|
|
*
|
|
LDA ]START ; {2C2B} LOAD STARTING POINT
|
|
STA ]PTR ; {3C2B} PACK INTO POINTER ADDRESS
|
|
LDA ]START+1 ; {2C2B} BOTH LOW BYTE AND
|
|
STA ]PTR+1 ; {3C2B} HIGH BYTE
|
|
*
|
|
** NOW PRINT THE LINE
|
|
*
|
|
:PRNLP ; PRINTING LOOP
|
|
LDA ]PTR+1 ; {2C2B} LOAD HIGH BYTE OF POINTER
|
|
CMP ]LSPACE+1 ; {2C2B} COMPARE TO HIGH BYTE OF LAST SPACE
|
|
BNE :PRNLP0 ; {3C2B} IF !=, THEN SKIP TO INNER LOOP
|
|
LDA ]PTR ; {2C2B} IF =, THEN COMPARE LOW BYTES
|
|
CMP ]LSPACE ; {2C2B}
|
|
BNE :PRNLP0 ; {3C2B} IF !=, GOTO INNER LOOP
|
|
LDA ]LINES ; {2C2B} OTHERWISE, LOAD CURRENT # OF LINES
|
|
CLC ; {2C1B} CLEAR CARRY
|
|
ADC #1 ; {3C2B} ADD A LINE
|
|
STA ]LINES ; {3C2B} STORE BACK INTO LINES
|
|
LDA ]LINES+1 ; {2C2B} LOAD HIGH BYTE OF LINES
|
|
ADC #0 ; {3C2B} ADD CARRY
|
|
STA ]LINES+1 ; {3C2B} STORE BACK INTO HIGH BYTE
|
|
LDA #$8D ; {2C2B} LOAD A LINE FEED CHARACTER
|
|
JSR COUT ; {6+C3B} SEND TO COUT (PRESS RETURN)
|
|
JMP :XXX ; {3C3B} SKIP REPRINTING SPACE
|
|
:PRNLP0 ; INNER PRINT LOOP
|
|
LDY #0 ; {2C2B} RESET .Y (JUST IN CASE?)
|
|
LDA (]PTR),Y ; {6C2B} LOAD CHARACTER AT POINTER
|
|
JSR COUT ; {6+C2B} PRINT CHARACTER
|
|
LDA (]PTR),Y ; {2C2B} LOAD AGAIN, JUST IN CASE
|
|
CMP #$8D ; {2C2B} IF CHAR != LINE FEED
|
|
BNE :XXX ; {3C2B} SKIP LINE ADDING
|
|
LDA ]LINES ; {2C2B} ELSE LOAD LINES COUNTER
|
|
CLC ; {2C1B} CLEAR CARRY
|
|
ADC #1 ; {3C2B} ADD A LINE
|
|
STA ]LINES ; {3C2B} STORE BACK INTO LOW BYTE
|
|
LDA ]LINES+1 ; {2C2B} LOAD HIGH BYTE OF LINES
|
|
ADC #0 ; {3C2B} ADD CARRY
|
|
STA ]LINES+1 ; {3C2B} STORE BACK INTO HIGH BYTE
|
|
LDA ]SCROLL ; {2C2B} LOAD MAX NUMBER OF LINES
|
|
CMP #0 ; {2C2B} COMPARE TO 0
|
|
BNE :XXX ; {3C2B} IF MAX != 0, SKIP PAUSING
|
|
:WLP LDA ]KYBD ; {2C2B} CHECK FOR KEYSTROKE
|
|
BPL :WLP ; {3C2B} IF .A HAS CLEAR HIGH BYTE
|
|
AND #$7F ; {2C2B} THEN NOT PRESSED; LOOP UNTIL
|
|
STA ]STROBE ; {3C2B} CLEAR THE KEYBOARD STROBE
|
|
LDA #0 ; {2C2B} CLEAR .A
|
|
STA ]LINES ; {3C2B} RESET LINE COUNTER
|
|
STA ]LINES+1 ; {3C2B} RESET LINE COUNTER HIGH BYTE
|
|
*
|
|
:XXX
|
|
LDA ]PTR+1 ; {2C2B} LOAD POINTER HIGH BYTE
|
|
CMP ]END+1 ; {2C2B} COMPARE TO ENDING HIGH BYTE
|
|
BNE :CNTPRN ; {3C2B} IF !=, CONTINUE PRINTING
|
|
LDA ]PTR ; {2C2B} ELSE LOAD POINTER LOW BYTE
|
|
CMP ]END ; {2C2B} COMPARE TO ENDING LOW BYTE
|
|
BEQ :PRNLPX ; {3C2B} IF EQUAL, EXIT PRINTING
|
|
:CNTPRN
|
|
LDA ]PTR ; {2C2B} LOAD POINTER LOW BYTE
|
|
CLC ; {2C1B} CLEAR CARRY
|
|
ADC #1 ; {3C2B} INCREASE ADDRESS BY ONE
|
|
STA ]PTR ; {3C2B} STORE BACK INTO LOW BYTE
|
|
LDA ]PTR+1 ; {2C2B} LOAD POINTER HIGH BYTE
|
|
ADC #0 ; {3C2B} ADD THE CARRY
|
|
STA ]PTR+1 ; {3C2B} STORE BACK INTO HIGH BYTE
|
|
JMP :PRNLP ; {3C3B} RESTART THE PRINTING LOOP
|
|
*
|
|
** FINISHED PRINTING LINE, SO NOW SWAP POINTER VARIABLES
|
|
** TO MOVE ON TO THE NEXT SECTION
|
|
*
|
|
:PRNLPX ; END PRINTING
|
|
LDA ]SCROLL ; {2C2B} LOAD MAX LINES
|
|
CMP ]LINES ; {2C2B} COMPARE TO CURRENT LINES
|
|
BNE :SWAPPP ; {3C2B} IF !=, SKIP WAIT
|
|
:WLP3 LDA ]KYBD ; {2C2B} WAIT FOR A KEYPRESS
|
|
BPL :WLP3 ; {3C2B}
|
|
AND #$7F ; {2C2B}
|
|
STA ]STROBE ; {3C2B} RESET KEYBOARD STROBE
|
|
LDA #0 ; {2C2B} RESET .A
|
|
STA ]LINES ; {3C2B} RESET LINE COUNTER LOW BYTE
|
|
STA ]LINES+1 ; {3C2B} RESET LINE COUNTER HIGH BYTE
|
|
:SWAPPP
|
|
LDA ]END ; {2C2B} LOAD ENDING ADDRESS LOW BYTE
|
|
CLC ; {2C1B} CLEAR CARRY
|
|
ADC #1 ; {3C2B} INCREASE ADDRESS BY ONE
|
|
STA ]END ; {3C2B} STORE BACK INTO LOW BYTE
|
|
LDA ]END+1 ; {2C2B} LOAD ENDING HIGH BYTE
|
|
ADC #0 ; {3C2B} ADD THE CARRY
|
|
STA ]END+1 ; {3C2B} STORE BACK INTO HIGH BYTE
|
|
*
|
|
LDA ]END ; {2C2B} RELOAD ENDING LOW BYTE
|
|
STA ]START ; {3C2B} STORE IN STARTING LOW BYTE
|
|
LDA ]END+1 ; {2C2B} RELOAD ENDING HIGH BYTE
|
|
STA ]START+1 ; {3C2B} STORE IN STARTING HIGH BYTE
|
|
LDA ]END ; {2C2B} RELOAD ENDING LOW BYTE
|
|
CLC ; {2C1B} CLEAR CARRY
|
|
ADC ]LEN ; {3C2B} ADD MAX LENGTH TO ENDING
|
|
STA ]END ; {3C2B} STORE BACK INTO LOW BYTE
|
|
LDA ]END+1 ; {2C2B} LOAD ENDING HIGH BYTE
|
|
ADC #0 ; {3C2B} ADD THE CARRY
|
|
STA ]END+1 ; {3C2B} STORE BACK INTO HIGH BYTE
|
|
JMP :ENTER ; {3C3B} BACK TO BEGINNING OF SUBROUTINE!
|
|
:PRNLAST
|
|
LDA ]START ; {2C2B} LOAD STARTING ADDRESS
|
|
STA ]PTR ; {3C2B} STORE LOW BYTE INTO POINTER LOW
|
|
LDA ]START+1 ; {2C2B} LOAD STARTING HIGH BYTE
|
|
STA ]PTR+1 ; {3C2B} STORE IN POINTER HIGH BYTE
|
|
:LASTLP
|
|
LDY #0 ; {2C2B} CLEAR .Y JUST IN CASE
|
|
LDA (]PTR),Y ; {6C2B} LOAD CHARACTER
|
|
JSR COUT ; {6+C3B} SEND CHARACTER TO COUT
|
|
LDA ]PTR+1 ; {2C2B} LOAD POINTER HIGH BYTE
|
|
CMP ]LAST+1 ; {2C2B} COMPARE IT TO NULL POINTER POS
|
|
BNE :LASTCNT ; {3C2B} IF !=, THEN LOOP
|
|
LDA ]PTR ; {2C2B} LOAD POINTER LOW BYTE AGAIN
|
|
CMP ]LAST ; {2C2B} COMPARE IT TO NULL POSITION LOW
|
|
BEQ :EXIT ; {3C2B} IF EQUAL, THEN EXIT
|
|
:LASTCNT
|
|
LDA ]PTR ; {2C2B} OTHERWISE, LOAD POINTER LOW BYTE
|
|
CLC ; {2C1B} CLEAR CARRY
|
|
ADC #1 ; {3C2B} ADD ONE TO ADDRESS
|
|
STA ]PTR ; {3C2B} STORE LOW BYTE AGAIN
|
|
LDA ]PTR+1 ; {2C2B} LOAD POINTER HIGH BYTE
|
|
ADC #0 ; {3C2B} ADD THE CARRY
|
|
STA ]PTR+1 ; {3C2B} STORE BACK IN POINTER HIGH BYTE
|
|
JMP :LASTLP ; {3C3B} LOOP AGAIN UNTIL LAST IS REACHED
|
|
:EXIT
|
|
LDA ]SCROLL ; {2C2B} LOAD MAX LINES
|
|
CMP #0 ; {2C2B} IF = 0, THEN JUST EXIT
|
|
BEQ :EXIT2 ; {3C2B}
|
|
:WLPZ LDA ]KYBD ; {2C2B} OTHERWISE, PAUSE FOR KEYPRESS
|
|
BPL :WLPZ ; {3C2B} BEFORE LEAVING SUBROUTINE
|
|
AND #$7F ; {2C1B}
|
|
STA ]STROBE ; {3C2B} CLEAR KEYBOARD STROBE
|
|
:EXIT2
|
|
RTS ; {6C1B}
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## Screen Memory Macros and Subroutines
|
|
|
|
There are many instances when avoiding COUT for screen output is either necessary or desirable, whether it be due to needing much greater speed or wanting to write a custom input/output system that might compete with COUT. In such cases, the macros and subroutines listed as part of this collection help plot text characters to the screen memory directly.
|
|
|
|
The `CPUT` and `SPUT` macros are especially pertinent to such uses; however, there are many other optional macros and their respective subroutines that plot to screen memory in order to create rudimentary shapes for creating interfaces, ASCII art, or text animations. This includes macros to create 1) vertical lines and horizontal lines as well as diagonals, 2) open and closed rectangles, 3) circles and 4) screen fills. In addition, this library carries the `RCPOS` macro, which reveals a character in screen memory when given an X, Y coordinate.
|
|
|
|
All of these macros are held in the `MAC.SCRMEM.STDIO.ASM` file. The heading of the file is listed below.
|
|
|
|
|
|
|
|
`LISTING 2.40: Screen Memory Macro File Heading`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* MAC.SCRMEM.STDIO.ASM *
|
|
* *
|
|
* THIS IS A MACRO LIBRARY FOR *
|
|
* STANDARD INPUT AND OUTPUT. *
|
|
* *
|
|
* AUTHOR: NATHAN RIGGS *
|
|
* CONTACT: NATHAN.RIGGS@ *
|
|
* OUTLOOK.COM *
|
|
* *
|
|
* DATE: 11-MAR-2021 *
|
|
* ASSEMBLER: MERLIN 8 PRO *
|
|
* OS: DOS 3.3 *
|
|
* *
|
|
* SUBROUTINES FILES USED: *
|
|
* *
|
|
* SUB.TVLINE *
|
|
* SUB.THLINE *
|
|
* SUB.TRECTF *
|
|
* SUB.TBLINE *
|
|
* SUB.TCIRCLE *
|
|
* SUB.TXTPUT *
|
|
* SUB.TXTCLR *
|
|
* SUB.STRPUT *
|
|
* SUB.TRECT *
|
|
* *
|
|
* LIST OF MACROS *
|
|
* *
|
|
* RCPOS : READ CURSOR POSITION *
|
|
* TLINE : DIAGONAL TEXT LINE *
|
|
* TCIRC : TEXT CIRCLE *
|
|
* TVLIN : TEXT VERTICAL LINE *
|
|
* THLIN : TEXT HORIZ LINE *
|
|
* TRECF : TEXT FILL RECTANGLE *
|
|
* CPUT : TEXT CHAR PLOT AT XY *
|
|
* TCLR : FILL SCREEN W/ CHAR *
|
|
* TREC : CREATE UNFILLED RECT *
|
|
* SPUT : STRING PUT *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE RCPOS MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ---------------------------------------------------------- |
|
|
| Name | `RCPOS` |
|
|
| Type | Macro |
|
|
| File | `MAC.SCRMEM.STDIO.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Return the character value at the given screen coordinates |
|
|
| Input | ]1 = X-position<br />]2 = Y-position |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 10+ |
|
|
| Bytes | 6 |
|
|
| Notes | none |
|
|
| See Also | `SCPOS` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `RCPOS` macro retrieves the character on screen at the given X and Y coordinates, returning the character via the **.A** register. Technically, this works regardless of whether COUT is being used, but it is included in the Screen Memory Access group because it simply reads the data at an encoded address in screen memory. Neither Applesoft nor Integer BASIC has an equivalent routine for text, although this works much like the SCRN() statement for Lo-Res graphics in Applesoft.
|
|
|
|
|
|
|
|
|
|
|
|
`LISTING 2.41: The RCPOS Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* RCPOS *
|
|
* *
|
|
* READ THE CHARACTER AT POS *
|
|
* X,Y AND LOADS INTO ACCUM *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = X POSITION *
|
|
* ]2 = Y POSITION *
|
|
* *
|
|
* CYCLES: 10+ *
|
|
* SIZE: 6 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
RCPOS MAC
|
|
LDY ]1 ; {2C2B} PUT ROW INTO .Y
|
|
LDA ]2 ; {2C2B} PUT COLUMN IN .A
|
|
JSR GBCALC ; {????} GET MEM ADDRESS FOR COORDS
|
|
LDA (GBPSH),Y ; {6C2B} GET CHARACTER FROM MEMORY
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TVLIN MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `TVLIN` |
|
|
| Type | Macro |
|
|
| File | `MAC.SCRMEM.STDIO.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Draw a vertical line to screen memory |
|
|
| Input | ]1 = Y-position Origin<br />]2 = Y-position Destination<br />]3 = X-position<br />]4 = Fill Character |
|
|
| Output | A vertical line made up of a given character <br />directly plotted to screen memory |
|
|
| Dependencies | `SUB.TVLINE.ASM` |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 104+ |
|
|
| Bytes | 45 |
|
|
| Notes | none |
|
|
| See Also | `TVLINE` `THLIN` `THLINE` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `TVLIN` macro draws a vertical line to screen memory made up of a given fill character at the passed X, Y coordinate. Since the output is plotted directly to screen memory, this does not "play nicely" with COUT.
|
|
|
|
It may seem trivial to have this macro and dedicated subroutine for creating vertical lines, since the `TBLINE` subroutine can create any line: vertical, horizontal, or diagonal. However, `TBLINE` and its associated macro (`TLINE`) uses many more cycles to accomplish the same functionality here; therefore, when speed is a concern, `TVLIN` should be used to create lines that are already known to be perfectly vertical lines unless the size of the program is of utmost concern.
|
|
|
|
|
|
|
|
`LISTING 2.42: TVLIN Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TVLIN *
|
|
* *
|
|
* CREATE A VERTICAL LINE WITH *
|
|
* A GIVEN TEXT FILL CHARACTER *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = START OF VERT LINE *
|
|
* ]2 = END OF VERT LINE *
|
|
* ]3 = X POSITION OF LINE *
|
|
* ]4 = FILL CHARACTER *
|
|
* *
|
|
* CYCLES: 104+ *
|
|
* SIZE: 45 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
TVLIN MAC
|
|
LDA ]1 ; {2C2B} Y-COORDINATE ORIGIN
|
|
STA WPAR2 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]2 ; {2C2B} Y-COORDINATE DESTINATION
|
|
STA WPAR2+1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]3 ; {2C2B} X-COORDINATE OF LINE
|
|
STA WPAR1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]4 ; {3C2B} CHARACTER TO PLOT
|
|
STA BPAR1 ; {3C2B} PASS VIA ZERO PAGE
|
|
JSR TVLINE ; {83C29B} CALL TVLINE SUBROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TVLINE Subroutine
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `TVLINE` |
|
|
| Type | Subroutine |
|
|
| File | `SUB.TVLINE.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Draw a vertical line to screen memory |
|
|
| Input | WPAR1 = X-position<br />WPAR2 = Y-position Origin<br />WPAR2+1 = Y-position Destination<br />BPAR1 = Fill Character |
|
|
| Output | A vertical line made up of a given character <br />directly plotted to screen memory |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 77+ |
|
|
| Bytes | 26 |
|
|
| Notes | none |
|
|
| See Also | `TVLIN` `THLIN` `THLINE` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `TVLINE` subroutine takes an X-coordinate, a Y-origin and a Y-destination as well as a fill character as parameters (sent via the zero page), then "paints" a vertical line to screen memory with the passed fill character. Although the `TBLINE` subroutine can create vertical lines as well, this subroutine takes substantially fewer cycles and therefore should be used in its stead when possible.
|
|
|
|
The subroutine first loads the Y-origin into the **.A** register and the X-position in the **.Y** register in preparation for calling **GBCALC**, which returns the address in screen memory of a given coordinate (this address is returned in the zero page at the **GBPSH** location). The fill character is then plotted at the resulting address, and a loop is begun that increments the Y-origin every iteration, plotting each character in the line until the Y-origin equals the Y-destination. Once finished, control is returned back to the calling program or routine.
|
|
|
|
|
|
|
|
`FIGURE 2.43: TVLINE Subroutine Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TVLINE (NATHAN RIGGS) *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* ]X1 STORED AT WPAR1 *
|
|
* ]Y1 STORED AT WPAR2 *
|
|
* ]Y2 STORED AT WPAR2+1 *
|
|
* ]F STORED AT BPAR1 *
|
|
* *
|
|
* OUTPUT: VERT LINE TO SCREEN *
|
|
* *
|
|
* DESTROY: NZCIDV *
|
|
* ^^^ ^ *
|
|
* *
|
|
* CYCLES: 77+ *
|
|
* SIZE: 26 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
]X1 EQU WPAR1 ; X COLUMN OF LINE
|
|
]Y1 EQU WPAR2 ; Y POSITION ORIGIN
|
|
]Y2 EQU WPAR2+1 ; Y POSITION DESTINATION
|
|
]F EQU BPAR1 ; LINE FILL CHARACTER
|
|
*
|
|
TVLINE
|
|
*
|
|
LDA ]Y1 ; {4C3B} LOAD Y ORIGIN {NZ}
|
|
LDY ]X1 ; {4C3B} LOAD X POSITION {NZ}
|
|
:LOOP
|
|
JSR GBCALC ; {43C3B} GET POS SCREEN ADDRESS {NZCV}
|
|
LDA ]F ; {4C3B} LOAD FILL CHARACTER {NZ}
|
|
STA (GBPSH),Y ; {6C2B} PLOT TO SCREEN MEMORY
|
|
INC ]Y1 ; {6C3B} INCREASE Y POSITION {NZ}
|
|
LDA ]Y1 ; {4C3B} RELOAD Y POSITION {NZ}
|
|
CMP ]Y2 ; {4C3B} IF Y1 < Y2 {NZC}
|
|
BNE :LOOP ; {3C2B} LOOP; ELSE, CONTINUE
|
|
:EXIT
|
|
RTS ; {6C1B}
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE THLIN MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `THLIN` |
|
|
| Type | Macro |
|
|
| File | `MAC.SCRMEM.STDIO.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Draw a horizontal line to screen memory |
|
|
| Input | ]1 = X-position Origin<br />]2 = X-position Destination<br />]3 = Y-position<br />]4 = Fill Character |
|
|
| Output | A horizontal line made up of a given character <br />directly plotted to screen memory |
|
|
| Dependencies | `SUB.THLINE.ASM` |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 107+ |
|
|
| Bytes | 38 |
|
|
| Notes | none |
|
|
| See Also | `TVLIN` `TVLINE` `THLINE` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `THLIN` macro plots a horizontal line made up of a given fill character directly to screen memory. Like the `TVLIN` macro, `THLIN` can be replaced by the `TLINE` macro, but only if program size is of utmost concern; the subroutine called, `THLINE`, uses substantially fewer cycles than the `TLINE` macro due to the fact that its flat, horizontal nature is already known.
|
|
|
|
|
|
|
|
`FIGURE 2.44: THLIN Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* THLIN *
|
|
* *
|
|
* CREATE A HORIZONTAL LINE *
|
|
* FROM A FILL CHARACTER. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = START OF HORIZ LINE *
|
|
* ]2 = END OF HORIZ LINE *
|
|
* ]3 = Y POSITION OF LINE *
|
|
* ]4 = FILL CHARACTER *
|
|
* *
|
|
* CYCLES: 107+ *
|
|
* SIZE: 38 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
THLIN MAC
|
|
LDA ]1 ; {2C2B} X-COORDINATE ORIGIN
|
|
STA WPAR1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]2 ; {2C2B} X-COORDINATE DESTINATION
|
|
STA WPAR1+1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]3 ; {2C2B} Y-COORDINATE OF LINE
|
|
STA BPAR1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]4 ; {2C2B} CHARACTER TO FILL
|
|
STA BPAR2 ; {3C2B} PASS VIA ZERO PAGE
|
|
JSR THLINE ; {87C22B} CALL THLINE SUBROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE THLINE Subroutine
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `THLINE` |
|
|
| Type | Subroutine |
|
|
| File | `SUB.THLINE.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Draw a horizontal line to screen memory |
|
|
| Input | WPAR1 = X-position Origin<br />WPAR1+1 = X-position Destination<br />BPAR1 = Y-position<br />BPAR2 = Fill Character |
|
|
| Output | A horizontal line made up of a given character <br />directly plotted to screen memory |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 77+ |
|
|
| Bytes | 26 |
|
|
| Notes | none |
|
|
| See Also | `TVLIN` `TVLINE` `THLIN` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `THLINE` subroutine accepts parameters from the zero page that include an X-position origin, X-position destination, Y-position, and a fill character to draw a horizontal line made of the given text character directly to screen memory. For the most part this is complementary to the `TVLINE` subroutine, and like `TVLINE` this subroutine could be replaced by the `TBLINE` subroutine on its own. However, like with `TVLINE`, this subroutine uses substantially fewer cycles than `TBLINE`, and should be used when it is known that the line will be a straight, horizontal line.
|
|
|
|
`THLINE` works much the same as `TVLINE`, but differs in the fact that it creates a horizontal line rather than a vertical one. First the Y-position is loaded into **.A** with the X-position origin loaded in **.Y** in order to retrieve the starting address via the GBCALC routine (often known as GBASCALC in other implementations; the name is abbreviated here for convenience). Afterwards, the X-position origin is increased with the passing of a loop and a new character is plotted. This is repeated until the X-position origin equals the X-position destination, at which point control is then returned back to the calling routine.
|
|
|
|
|
|
|
|
`FIGURE 2.45: The THLINE Subroutine Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* THLINE (NATHAN RIGGS) *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* WPAR1 = X ORIGIN *
|
|
* WPAR1+1 = X DESTINATION *
|
|
* BPAR1 = Y POSITION *
|
|
* BPAR2 = FILL CHARACTER *
|
|
* *
|
|
* OUTPUT: HORIZONTAL LINE TO *
|
|
* SCREEN *
|
|
* *
|
|
* DESTROY: NZCIDV *
|
|
* ^^^ ^ *
|
|
* *
|
|
* CYCLES: 81+ *
|
|
* SIZE: 19 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
]X1 EQU WPAR1 ; X POS ORIGIN
|
|
]X2 EQU WPAR1+1 ; X POS DESTINATION
|
|
]Y1 EQU BPAR1 ; Y POSITION
|
|
]F EQU BPAR2 ; FILL CHAR
|
|
*
|
|
THLINE
|
|
LDA ]Y1 ; {3C2B} LOAD ROW {NZ}
|
|
LDY ]X1 ; {3C2B} LOAD X START POS {NZ}
|
|
:LOOP
|
|
JSR GBCALC ; {49C3B} GOSUB GBASCALC ROUTINE, {NZCV}
|
|
; WHICH FINDS MEMLOC FOR
|
|
; POSITION ON SCREEN
|
|
LDA ]F ; {3C2B} LOAD FILL CHAR {NZ}
|
|
STA (GBPSH),Y ; {6C2B} PUSH ]F TO SCREEN MEM
|
|
LDA ]Y1 ; {3C2B} LOAD Y POSITION {NZ}
|
|
INY ; {2C1B} INCREASE X POS {NZ}
|
|
CPY ]X2 ; {3C2B} IF < X DEST THEN END {NZC}
|
|
BNE :LOOP ; {3C2B} REPEAT UNTIL DONE
|
|
:EXIT
|
|
RTS ; {6C1B}
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TRECF MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `TRECF` |
|
|
| Type | Macro |
|
|
| File | `MAC.SCRMEM.STDIO.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Draw a filled rectangle to screen memory |
|
|
| Input | ]1 = X-position Origin<br />]2 = Y-position Origin<br />]3 = X-position Destination<br />]4 = Y-position Destination<br />]5 = Fill Character |
|
|
| Output | A filled rectangle made up of a given character <br />directly plotted to screen memory |
|
|
| Dependencies | `SUB.TRECTF.ASM` |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 157+ |
|
|
| Bytes | 77 |
|
|
| Notes | none |
|
|
| See Also | `TRECTF` `TREC` `TRECF` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `TRECF` macro uses the `TRECTF` subroutine to draw a rectangle to screen memory that is filled with the character passed in the parameters (5th parameter). These parameters are passed to the subroutine via the zero page.
|
|
|
|
|
|
|
|
`FIGURE 2.46: TRECF Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TRECF *
|
|
* *
|
|
* CREATE A RECTANGLE FILLED *
|
|
* WITH A GIVEN TEXT CHARACTER *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = HORIZ START POSITION *
|
|
* ]2 = VERT START POSITION *
|
|
* ]3 = HORIZ END POSITION *
|
|
* ]4 = VERT END POSITION *
|
|
* ]5 = FILL CHARACTER *
|
|
* *
|
|
* CYCLES: 157+ *
|
|
* SIZE: 77 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
TRECF MAC
|
|
LDA ]1 ; {2C2B} X-COORDINATE ORIGIN
|
|
STA WPAR1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]2 ; {2C2B} Y-COORDINATE ORIGIN
|
|
STA WPAR2 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]3 ; {2C2B} X-COORDINATE DESTINATION
|
|
STA WPAR1+1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]4 ; {2C2B} Y-COORDINATE DESTINATION
|
|
STA WPAR2+1 ; {2C2B} PASS VIA ZERO PAGE
|
|
LDA ]5 ; {2C2B} CHARACTER TO PLOT
|
|
STA BPAR1 ; {3C2B} PASS VIA ZERO PAGE
|
|
JSR TRECTF ; {133C57B} CALL TRECTF SUBROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TRECTF Subroutine
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `TRECTF` |
|
|
| Type | Subroutine |
|
|
| File | `SUB.TRECTF.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Draw a filled rectangle line to screen memory |
|
|
| Input | WPAR1 = X-position Origin<br />WPAR1+1 = X-position Destination<br />WPAR2 = Y-position Origin<br />WPAR2+1 = Y-position Destination<br />BPAR1 = Fill Character |
|
|
| Output | A filled rectangle made up of a given character <br />directly plotted to screen memory |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 127+ |
|
|
| Bytes | 54 |
|
|
| Notes | none |
|
|
| See Also | `TRECF` `TREC` `TRECF` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `TRECTF` subroutine reads parameters from the zero page that include an X, Y origin, and X, Y destination, and a fill character to create a filled rectangle on the text screen. This is plotted via direct access to screen memory, and thus does not interfere with--or play nice with--COUT routines.
|
|
|
|
This subroutine creates a successive series of horizontal lines in screen memory that constitute a rectangle of the given dimensions together. First, the X and Y origins are stored in temporary variable storage as the change in X and the change in Y, then the lookup and plotting loop is started. The Change in X and change in Y are loaded into **.A** and **.Y** respectively in order to find the screen memory address of the coordinates using **GBCALC**. This is then plotted to the screen after retrieving the address from the zero page (**GBPSH**). Each X position in the line is plotted as the **.Y** index counter is increased to form a horizontal line until the line is a proper length (the length of the desired rectangle), at which point the Y position is increased, the X position is reset, and the loop continues plotting the next line until the Y destination is reached. Afterward, control is returned to the calling program or routine.
|
|
|
|
`FIGURE 2.47: The TRECTF Subroutine Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TRECTF (NATHAN RIGGS) *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* WPAR1 = X ORIGIN *
|
|
* WPAR1+1 = X DESTINATION *
|
|
* WPAR2 = Y ORIGIN *
|
|
* WPAR2+1 = Y DESTINATION *
|
|
* BPAR1 = FILL CHARACTER *
|
|
* *
|
|
* OUTPUT *
|
|
* *
|
|
* FILLED RECTANGLE TO SCREEN *
|
|
* *
|
|
* DESTROY: NZCIDV *
|
|
* ^^^ ^ *
|
|
* *
|
|
* CYCLES: 127+ *
|
|
* SIZE: 54 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
]X1 EQU WPAR1 ; TOP LEFT OF RECTANGLE
|
|
]X2 EQU WPAR1+1 ; BOTTOM RIGHT OF RECTANGLE
|
|
]Y1 EQU WPAR2 ; TOP Y POSITION OF RECTANGLE
|
|
]Y2 EQU WPAR2+1 ; BOTTOM POSITION OF RECTANGLE
|
|
]F EQU BPAR1 ; FILL CHARACTER
|
|
*
|
|
]XC EQU VARTAB ; CHANGE IN X
|
|
]YC EQU VARTAB+1 ; CHANGE IN Y
|
|
*
|
|
TRECTF
|
|
LDA ]X1 ; {4C3B} LOAD TOP LEFT X ORIGIN {NZ}
|
|
STA ]XC ; {4C3B} STORE AS INITIAL INDEX
|
|
LDA ]Y1 ; {3C2B} LOAD TOP LEFT Y ORIGIN {NZ}
|
|
STA ]YC ; {4C3B} STORE AS INITIAL INDEX
|
|
:LP1 ; PRINT HORIZONTAL LINE
|
|
LDA ]YC ; {4C3B} LOAD FIRST Y INDEX {NZ}
|
|
LDY ]XC ; {4C3B} LOAD FIRST X INDEX IN Y {NZ}
|
|
JSR GBCALC ; {43C3B} GET SCREEN MEMORY ADDR {NZCV}
|
|
LDA ]F ; {3C2B} LOAD FILL CHARACTER {NZ}
|
|
STA (GBPSH),Y ; {6C2B} PUT CHAR IN SCREEN MEMORY {NZ}
|
|
LDA ]YC ; {4C3B} LOAD Y INDEX {NZ}
|
|
INY ; {2C1B} INCREASE XPOS INDEX {NZ}
|
|
STY ]XC ; {4C3B} STORE NEW X INDEX
|
|
CPY ]X2 ; {4C3B} IF XPOS < XMAX, {NZC}
|
|
BNE :LP1 ; {3C2B} KEEP PRINTING LINE
|
|
*
|
|
LDA ]X1 ; {4C3B} OTHERWISE, RESET XPOS {NZ}
|
|
STA ]XC ; {4C3B} AND STORE IN INDEX
|
|
INC ]YC ; {6C3B} AND INCREASE YPOS {NZ}
|
|
LDA ]YC ; {4C3B} RELOAD Y INDEX {NZ}
|
|
CMP ]Y2 ; {4C3B} IF YPOS < YMAX {NZC}
|
|
BNE :LP1 ; {3C2B} PRINT HORIZONTAL LINE
|
|
:EXIT
|
|
RTS ; {6C1B}
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE CPUT MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `CPUT` |
|
|
| Type | Macro |
|
|
| File | `MAC.SCRMEM.STDIO.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Plot a single character to screen memory |
|
|
| Input | ]1 = X-position<br />]2 = Y-position <br />]3 = Fill Character |
|
|
| Output | A single character is plotted to screen memory<br /> at the desired X, Y coordinate. |
|
|
| Dependencies | `SUB.TXTPUT.ASM` |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 91+ |
|
|
| Bytes | 31 |
|
|
| Notes | none |
|
|
| See Also | `TXTPUT` `SPUT` `STRPUT` `PRN` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `CPUT` macro uses the `TXTPUT` subroutine to plot a character directly to screen memory, bypassing COUT. While this is functionally similar to the COUT routine, it is much faster due to the fact that it does not consider the extra functionality that COUT provides, and only plots a character on the screen.
|
|
|
|
`CPUT` does no more than loads parameters into the registers for passing to the `TXTPUT` subroutine, which handles the actual implementation. The X-position is loaded into **.X**, the Y-position in **.Y**, and the fill character in **.A**.
|
|
|
|
|
|
|
|
`FIGURE 2.48: CPUT Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* CPUT *
|
|
* *
|
|
* PLOT A SINGLE TEXT CHARACTER *
|
|
* DIRECTLY TO SCREEN MEMORY AT *
|
|
* A GIVEN X,Y POSITION. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = X POSITION *
|
|
* ]2 = Y POSITION *
|
|
* ]3 = CHARACTER TO PLOT *
|
|
* *
|
|
* CYCLES: 91+ *
|
|
* SIZE: 31 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
CPUT MAC
|
|
LDX ]1 ; {2C2B} CARRY X-COORD IN .X
|
|
LDY ]2 ; {2C2B} CARRY Y-COORD IN .Y
|
|
LDA ]3 ; {2C2B} CARRY FILL CHAR IN .A
|
|
JSR TXTPUT ; {85C25B} CALL TXTPUT SUBROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TXTPUT Subroutine
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `TXTPUT` |
|
|
| Type | Subroutine |
|
|
| File | `SUB.TXTPUT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Plot a single character to screen memory |
|
|
| Input | .A = Fill Character<br />.X = X-position<br />.Y = Y-position |
|
|
| Output | A single character is placed in screen memory,<br />thus displaying on the screen. |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 79+ |
|
|
| Bytes | 22 |
|
|
| Notes | none |
|
|
| See Also | `CPUT` `SPUT` `STRPUT` `PRN` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `TXTPUT` subroutine retrieves a fill character and X, Y coordinates from the registers and plots the character directly to screen memory at the desired location. This is done via using **GBCALC** (also known as GBASCALC) to determine the memory address of the given coordinates.
|
|
|
|
Technically, this subroutine could use some optimization, especially since its purpose is so fundamental to possible extensions of its use. Changes to the subroutine and its calling macro, `CPUT`, can prevent the extra cycles and bytes used in storing the coordinates and fill character in temporary variable space, and if this is a concern then a user should make the appropriate changes.
|
|
|
|
However, `TXTPUT` is implemented, like all of the library's routines, so that a beginner can easily understand how it works. Most of the library holds variables either in the zero page or in temporary storage, and the less-than-optimal implementation of `TXTPUT`reflects this strategy. This may be changed in future revision, if the need seems to outweigh the benefits of beginner-level understanding.
|
|
|
|
|
|
|
|
`FIGURE 2.49: TXTPUT Subroutine Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TXTPUT (NATHAN RIGGS) *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* .A = FILL CHAR *
|
|
* .X = X POSITION *
|
|
* .Y = Y POSITION *
|
|
* *
|
|
* OUTPUT *
|
|
* *
|
|
* CHAR TO SCREEN AT X,Y *
|
|
* *
|
|
* DESTROY: NZCIDV *
|
|
* ^^^ ^ *
|
|
* *
|
|
* CYCLES: 79+ *
|
|
* SIZE: 22 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
]Y1 EQU VARTAB ; Y COORDINATE (1 BYTE)
|
|
]X1 EQU VARTAB+1 ; X COORDINATE (1 BYTE)
|
|
]F EQU VARTAB+3 ; CHARACTER TO PLOT (1 BYTE)
|
|
*
|
|
TXTPUT
|
|
*
|
|
* WITH SOME REARRANGEMENT, STORING VARS FOR LATER
|
|
* CAN BE ERASED TO SAVE CYCLES AND BYTES, BUT THIS WOULD
|
|
* BE AT THE EXPENSE OF INTERNAL LIBRARY CONSISTENCY
|
|
*
|
|
STA ]F ; {4C3B} STORE CHARACTER TO PLOT
|
|
STY ]Y1 ; {4C3B} STORE Y POSITION
|
|
STX ]X1 ; {4C3B} STORE X POSITION
|
|
LDA ]Y1 ; {4C3B} LOAD Y POS INTO .A AND {NZ}
|
|
LDY ]X1 ; {4C3B} X POS IN .Y TO CALL GBCALC {NZ}
|
|
JSR GBCALC ; {43C24B} GET SCREEN ADDRESS TO PLOT {NZCV}
|
|
LDA ]F ; {4C3B} LOAD .A WITH CHARACTER TO PLOT {NZ}
|
|
STA (GBPSH),Y ; {6C3B} PUSH CHARACTER TO SCREEN ADDR
|
|
:EXIT ; THAT WAS RETURNED BY GBCALC
|
|
RTS ; {6C1B}
|
|
*
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TLINE MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `TLINE` |
|
|
| Type | Macro |
|
|
| File | `MAC.SCRMEM.STDIO.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Plot any line to the text display using a fill character |
|
|
| Input | ]1 = X-position Origin<br />]2 = Y-position Origin<br />]3 = X-position destination<br />]4 = Y-position destination<br />5 = Fill Character |
|
|
| Output | A line-shape displayed on the screen, <br />made up of the given fill character. |
|
|
| Dependencies | `SUB.TBLINE.ASM` |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 305+ |
|
|
| Bytes | 198 |
|
|
| Notes | Please see the `TVLIN` and `THLIN` macros for <br />vertical and horizontal text line plotting that is <br />more efficient in both cycles and size. |
|
|
| See Also | `TBLINE` |
|
|
|
|
*DETAILS*
|
|
|
|
The `TLINE` macro uses Bresenham's line algorithm to draw a line of text characters directly to screen memory. Parameters are passed to the `TBLINE` subroutine via the zero page, including an X-position origin, Y-position origin, X-position destination, Y-position destination, and a designated fill character. For an explanation of Bresenham's line algorithm at work, please see the listing for the `TBLINE` subroutine.
|
|
|
|
|
|
|
|
`FIGURE 2.50: TLINE Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TLINE *
|
|
* *
|
|
* USE THE BRESSENHAM LINE *
|
|
* ALGORITHM TO DRAW A LINE *
|
|
* WITH A FILL CHARACTER. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = X-ORIGIN *
|
|
* ]2 = Y-ORIGIN *
|
|
* ]3 = X-DESTINATION *
|
|
* ]4 = Y-DESTINATION *
|
|
* ]5 = FILL CHARACTER *
|
|
* *
|
|
* CYCLES: 411+ *
|
|
* SIZE: 187 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
TLINE MAC
|
|
LDA ]1 ; {2C2B} LOAD X-ORIGIN
|
|
STA WPAR1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]2 ; {2C2B} LOAD Y-ORIGIN
|
|
STA WPAR1+1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]3 ; {2C2B} LOAD X-DESTINATION
|
|
STA WPAR2 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]4 ; {2C2B} LOAD Y-DESTINATION
|
|
STA WPAR2+1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]5 ; {2C2B} LOAD FILL CHARACTER
|
|
STA BPAR1 ; {3C2B} PASS VIA ZERO PAGE
|
|
JSR TBLINE ; {286C167B} CALL TBLINE SUBROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TBLINE Subroutine
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `TBLINE` |
|
|
| Type | Subroutine |
|
|
| File | `SUB.TBLINE.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Plot a line of text at any slop to screen memory |
|
|
| Input | WPAR1 = X-position Origin<br />WPAR1+1 = Y-position Origin<br />WPAR2 = X-position Destination<br />WPAR2+1 = Y-position Destination<br />BPAR1 = Fill Character |
|
|
| Output | A line composed of the fill character is placed<br />in screen memory, thus displaying on the screen. |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 280+ |
|
|
| Bytes | 178 |
|
|
| Notes | See the `TCIRCLE` subroutine for an implementation<br /> of Bresenham's Circle algorithm. |
|
|
| See Also | `TLINE` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `TBLINE` subroutine creates a line drawn by a specified fill character from an X,Y origin to an X,Y destination on the text screen using Bresenham's line algorithm, plotting directly to screen memory. Of all the STDIO subroutines, `TBLINE` is one of the more complicated algorithms (with `TCIRCLE` coming in at a close second), and therefore demands more explanation than other STDIO subroutines. By having an overall understanding of how `TBLINE` works, a user will be more than prepared to understand how later graphics routines are implemented.
|
|
|
|
Parameters for `TBLINE` are passed via the zero page; this includes the origin and destination coordinates as well as the fill character, totaling five bytes in total. Before any other calculations can be made, it first needs to be determined whether the slope of the line is positive or negative. This is done by subtracting the Y-position destination from the Y-position origin. If the result is positive, then the Y-value of the slope is negative; otherwise, both the X and Y values of the slope are positive. Either way, the change in Y is stored in temporary variable storage as ]DY, and the positive or negative step of the slope is stored in ]SY. The step in the X-position is equally tested and stored in ]DX, with the step of 1 or -1 stored in ]SX.
|
|
|
|
After the slope has been established, the next step is to determine the error variable, ]ERR, which is used to calculate whether the path of the line to be plotted should be increased or decreased by a pixel (this error represents the difference between Euclidian space and the raster-based plotting of most computers). This is the key to the drawing of the line, and it replaces what would normally be a cycle-hungry process of division to determine the current slope on the line segment. The current point is drawn to the screen memory using GBCALC, and the slope is then recalculated for every point (or character) on the line, altering the change in Y and change in X as needed. The process then loops, continuing until the segment being worked on has all of its points plotted.
|
|
|
|
Put together, the series of points created constitutes the shape of a line in discrete space. In this implementation, those discrete points are character spaces representing large pixels, but the same principle applies to any raster system: the algorithm is the same for a line in the Low Resolution subroutines and the high resolution subroutines alike.
|
|
|
|
|
|
|
|
`FIGURE 2.51: TBLINE Subroutine Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TBLINE (NATHAN RIGGS) *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* ]X0 = X ORIGIN *
|
|
* ]X1 = X DESTINATION *
|
|
* ]Y0 = Y ORIGIN *
|
|
* ]Y1 = Y DESTINATION *
|
|
* ]F = LINE FILL CHARACTER *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* OUTPUTS A LINE FROM COORDS *
|
|
* X0,Y0 TO X1,Y1 USING THE *
|
|
* BRESSENHAM LINE ALOGORITHM *
|
|
* *
|
|
* DESTROY: NZCIDV *
|
|
* ^^^ ^ *
|
|
* *
|
|
* CYCLES: 280+ *
|
|
* SIZE: 178 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
]X0 EQU WPAR1 ; XPOS ORIGIN PASSED VIA ZP
|
|
]X1 EQU WPAR2 ; XPOS DEST PASSED VIA ZP
|
|
]Y0 EQU WPAR1+1 ; YPOS ORIGIN PASSED VIA ZP
|
|
]Y1 EQU WPAR2+1 ; YPOS DEST PASSED VIA ZP
|
|
]F EQU BPAR1 ; FILL VALUE
|
|
*
|
|
]DX EQU ADDR1 ; CHANGE IN X
|
|
]DY EQU ADDR1+1 ; CHANGE IN Y
|
|
]SX EQU ADDR2 ; X POSITION STEP
|
|
]SY EQU ADDR2+1 ; Y POSITION STEP
|
|
]ERR EQU ADDR3 ; SLOPE ERROR
|
|
]ERRX2 EQU ADDR3+1 ; COMPARISON COPY OF ]ERR
|
|
*
|
|
TBLINE
|
|
LDA ]X1 ; {3C2B} SUBTRACT X0 FROM X1
|
|
SEC ; {2C1B}
|
|
SBC ]X0 ; {3C2B}
|
|
BPL :ABSF1 ; {3C2B} IF POS, SKIP ABSOLUTE VALUE
|
|
SEC ; {2C1B} SUBTRACT 1 AND EOR #$FF
|
|
SBC #1 ; {3C2B} TO GET THE ABSOLUTE VALUE
|
|
EOR #$FF ; {2C2B}
|
|
:ABSF1
|
|
STA ]DX ; {3C2B} STORE VALUE AS CHANGE IN X
|
|
*
|
|
LDA ]Y1 ; {3C2B} SUBTRACT Y0 FROM Y1
|
|
SEC ; {2C1B}
|
|
SBC ]Y0 ; {3C2B}
|
|
BPL :ABSF2 ; {3C2B} IF POSITIVE, SKIP ABS VALUE
|
|
SEC ; {2C1B} SUBTRACT 1 AND EOR #$FF
|
|
SBC #1 ; {3C2B} TO GET THE ABSOLUTE VALUE
|
|
EOR #$FF ; {2C2B}
|
|
:ABSF2
|
|
STA ]DY ; {3C2B} STORE VALUE AS CHANGE IN Y
|
|
*
|
|
LDA ]DX ; {3C2B} ]ERR = DX - DY
|
|
SEC ; {2C1B}
|
|
SBC ]DY ; {3C2B}
|
|
STA ]ERR ; {3C2B}
|
|
*
|
|
LDX #$FF ; {3C2B} .X = -1
|
|
LDA ]X0 ; {3C2B} IF X0 >= X1
|
|
CMP ]X1 ; {3C2B}
|
|
BCS :NONEG ; {3C2B} THEN SKIP CHANGE IN .X
|
|
LDX #$01 ; {3C2B} ELSE, CHANGE .X TO +1
|
|
:NONEG STX ]SX ; {3C2B} STORE EITHER -1 OR +1 IN SX
|
|
*
|
|
LDX #$FF ; {3C2B} .X = -1
|
|
LDA ]Y0 ; {3C2B} IF Y0 >= Y1
|
|
CMP ]Y1 ; {3C2B}
|
|
BCS :NONEG2 ; {3C2B} THEN SKIP CHANGE IN .X
|
|
LDX #$01 ; {3C2B} ELSE CHANGE .X TO +1
|
|
:NONEG2 STX ]SY ; {3C2B} STORE EITHER -1 OR +1 IN SY
|
|
*
|
|
** MAIN LOOP
|
|
*
|
|
:LOOP
|
|
LDA ]Y0 ; {3C2B} .A = Y POSITION {NZ}
|
|
LDY ]X0 ; {3C2B} .Y = X POSITION {NZ}
|
|
JSR GBCALC ; {43C24B} FIND SCREEN MEM LOCATION {NZCV}
|
|
LDA ]F ; {3C2B} LOAD FILL INTO .A {NZ}
|
|
STA (GBPSH),Y ; {6C2B} PUSH TO SCREEN MEMORY
|
|
*
|
|
LDA ]X0 ; {3C2B} IF X0 != X1, KEEP LOOPING
|
|
CMP ]X1 ; {3C2B}
|
|
BNE :CONT ; {3C2B}
|
|
LDA ]Y0 ; {3C2B} IF Y0 != Y1, KEEP LOOPING
|
|
CMP ]Y1 ; {3C2B}
|
|
BNE :CONT ; {3C2B}
|
|
JMP TBLEXIT ; {3C3B} ELSE, EXIT LOOP
|
|
:CONT
|
|
*
|
|
LDA ]ERR ; {3C2B} ]ERR = ]ERR * 2
|
|
ASL ; {2C1B}
|
|
STA ]ERRX2 ; {3C2B}
|
|
*
|
|
LDA ]DY ; {3C2B} NEGATE ]DY
|
|
EOR #$FF ; {3C2B}
|
|
CLC ; {2C1B}
|
|
ADC #1 ; {3C2B}
|
|
SEC ; {2C1B} USE SBC FOR SIGNED COMPARE
|
|
SBC ]ERRX2 ; {3C2B}
|
|
BMI :NFSETX ; {3C2B} IF N FLAG SET, GO CHECK V FLAG
|
|
BVC :GEX ; {3C2B} IF V = 0 & N = 0, VAL >= .A REG
|
|
:LTX ; N = 0 AND V = 1, SO LESS THAN
|
|
LDA ]ERR ; {3C2B} ]ERR = ]ERR - ]DY
|
|
SEC ; {2C1B}
|
|
SBC ]DY ; {3C2B}
|
|
STA ]ERR ; {3C2B}
|
|
LDA ]X0 ; {3C2B} X0 = X0 + SX
|
|
CLC ; {2C1B}
|
|
ADC ]SX ; {3C2B}
|
|
STA ]X0 ; {3C2B}
|
|
JMP :GEX ; {3C3B}
|
|
:NFSETX BVC :LTX ; {3C2B} IF N = 1 & V = 0, VAL < .A REG
|
|
:GEX ; N = 1 & V = 1, SO VAL >= .A REG
|
|
*
|
|
LDA ]ERRX2 ; {3C2B} IF ER * 2 < DX, GOTO :LTY
|
|
SEC ; {2C1B}
|
|
SBC ]DX ; {3C2B}
|
|
BMI :SKIPY ; {3C2B} IF N FLAG = 1, GO CHECK V FLAG
|
|
BVC :GEY ; {3C2B} N = 0 & V = 0, SO VAL >= .A REG
|
|
:LTY LDA ]ERR ; {3C2B} N = 0 AND V = 1, SO LESS THAN
|
|
CLC ; {2C1B}
|
|
ADC ]DX ; {3C2B} ]ERR = ]ERR + ]DX
|
|
STA ]ERR ; {3C2B}
|
|
LDA ]Y0 ; {3C2B} ]Y0 = ]Y0 + ]SY
|
|
CLC ; {2C1B}
|
|
ADC ]SY ; {3C2B}
|
|
STA ]Y0 ; {3C2B}
|
|
JMP :GEY ; {3C3B}
|
|
:SKIPY BVC :LTY ; {3C2B} IF N = 1 & V = 0, VAL < .A REG
|
|
:GEY ; {3C2B} N = 1 & V = 1, SO VAL >= .A REG
|
|
*
|
|
JMP :LOOP ; {3C3B}
|
|
TBLEXIT
|
|
RTS ; {6C1B}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TCIRC MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `TCIRC` |
|
|
| Type | Macro |
|
|
| File | `MAC.SCRMEM.STDIO.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Plot a circle to the text screen |
|
|
| Input | ]1 = Center X-position<br />]2 = Center Y-position <br />]3 = Radius<br />]4 = Fill Character |
|
|
| Output | A circle is plotted directly to screen memory<br />composed of the fill character specified. |
|
|
| Dependencies | `SUB.TCIRCLE.ASM` |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 627+ |
|
|
| Bytes | 290 |
|
|
| Notes | none |
|
|
| See Also | `TCIRCLE` |
|
|
|
|
*DETAILS*
|
|
|
|
The `TCIRC` macro draws a circle of text on the screen with the given center X, Y coordinates and a given radius. This is directly plotted to screen memory, bypassing the slower execution of COUT. These parameters are passed to the `TCIRCLE` subroutine via the zero page. It should be noted that this implementation uses Bresenham's Circle Algorithm, which is something of an extension of Bresenham's Line Algorithm, which can be found in the `TBLINE` subroutine. To gain a broad understanding of how the algorithm works, it is suggested that the reader consult the `TCIRCLE` subroutine entry.
|
|
|
|
|
|
|
|
`FIGURE 2.52: TCIRC Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TCIRC *
|
|
* *
|
|
* USE THE BRESSENHAM CIRCLE *
|
|
* ALGORITHM TO DRAW A CIRCLE *
|
|
* WITH A FILL CHARACTER. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = CENTER X-LOCATION *
|
|
* ]2 = CENTER Y-LOCATION *
|
|
* ]3 = RADIUS *
|
|
* ]4 = FILL CHARACTER *
|
|
* *
|
|
* CYCLES: 627+ *
|
|
* SIZE: 290 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
TCIRC MAC
|
|
LDA ]1 ; {2C2B} LOAD CENTER X-COORD
|
|
STA WPAR1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]2 ; {2C2B} LOAD CENTER Y-COORD
|
|
STA WPAR2 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]3 ; {2C2B} LOAD RADIUS
|
|
STA BPAR1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]4 ; {2C2B} LOAD FILL CHARACTER
|
|
STA BPAR2 ; {3C2B} PASS VIA ZERO PAGE
|
|
JSR TCIRCLE ; {607C374B} CALL TCIRCLE SUBROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TCIRCLE Subroutine
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `TCIRCLE` |
|
|
| Type | Subroutine |
|
|
| File | `SUB.TCIRCLE.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Plot a circle of text at any slop to screen memory |
|
|
| Input | WPAR1 = Center X-position <br />WPAR2 = Center Y-position<br />BPAR1 = Radius<br />BPAR2 = Fill Character |
|
|
| Output | A circle composed of the fill character is placed<br />in screen memory, thus displaying on the screen. |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 601+ |
|
|
| Bytes | 371 |
|
|
| Notes | See the `TBLINE` subroutine for an implementation<br /> of Bresenham's Line algorithm. |
|
|
| See Also | `TCIRC` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `TCIRCLE` subroutine uses Bresenham's Circle Algorithm to draw a circle made up of a given text character directly to screen memory. This algorithm is akin to an extension of Bresenham's line algorithm; the difference is that the slope of an arc is being calculated, and only a single octant is actually calculated: thanks to the uniform nature of a circle, a single octant can be created and then transformed and translated to make the whole circle, saving a number of cycles in the process. See the `TBLINE` subroutine for a more comprehensive overview of how the algorithm works.
|
|
|
|
Note that because Bresenham's circle algorithm is inexact (thus the use of an error value), not all spaces will be filled if one were to superimpose circles of different radii. It is impractical, as such, to use the algorithm for a filled circle shape.
|
|
|
|
|
|
|
|
`FIGURE 2.53: TCIRCLE Subroutine Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TCIRCLE (NATHAN RIGGS) *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* WPAR1 = X CENTER POS *
|
|
* WPAR2 = Y CENTER POS *
|
|
* BPAR1 = RADIUS *
|
|
* BPAR2 = FILL CHARACTER *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* USES BRESENHAM'S CIRCLE *
|
|
* ALGORITHM TO DRAW A CIRCLE *
|
|
* TO THE 40-COLUMN TEXTMODE *
|
|
* SCREEN. *
|
|
* *
|
|
* DESTROY: NZCIDV *
|
|
* *
|
|
* *
|
|
* CYCLES: 601+ *
|
|
* SIZE: 371 BYTES *
|
|
* *
|
|
* SUBSTANTIAL DEBT IS OWED TO *
|
|
* MARC GOLOMBECK AND HIS GREAT *
|
|
* IMPLEMENTATION OF THE *
|
|
* BRESENHAM CIRCLE ALGORITHM *
|
|
* IN 6502 AND APPLESOFT, WHICH *
|
|
* IS BASED ON THE GERMAN LANG *
|
|
* VERSION OF WIKIPEDIA'S ENTRY *
|
|
* ON THE ALGORITHM THAT HAS A *
|
|
* BASIC PSEUDOCODE EXAMPLE. *
|
|
* THAT EXAMPLE, WITH CHANGED *
|
|
* VARIABLE NAMES, IS INCLUDED *
|
|
* BELOW. *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
]XC EQU WPAR1 ; X CENTER POSITION
|
|
]YC EQU WPAR2 ; Y CENTER POSITION
|
|
]R EQU BPAR1 ; RADIUS
|
|
]F EQU BPAR2 ; FILL CHAR
|
|
*
|
|
]Y EQU VARTAB ; CENTER YPOS
|
|
]X EQU VARTAB+1 ; CENTER XPOS
|
|
]DY EQU VARTAB+2 ; CHANGE IN Y
|
|
]DX EQU VARTAB+4 ; CHANGE IN X
|
|
]ERR EQU VARTAB+6 ; ERROR VALUE
|
|
]DIAM EQU VARTAB+8 ; DIAMETER
|
|
]XT EQU VARTAB+10 ; INVERTED X VALUE
|
|
]YT EQU VARTAB+12 ; INVERTED Y VALUE
|
|
*
|
|
********************************
|
|
* *
|
|
* BASIC PSEUDOCODE *
|
|
* *
|
|
********************************
|
|
*
|
|
* X = R
|
|
* Y = 0
|
|
* ERROR = R
|
|
* SETPIXEL XC + X, YC + Y
|
|
* WHILE Y < X
|
|
* DY = Y * 2 + 1
|
|
* Y = Y + 1
|
|
* ERROR = ERROR - DY
|
|
* IF ERROR < 0 THEN
|
|
* DX = 1 - X * 2
|
|
* X = X - 1
|
|
* ERROR = ERROR - DX
|
|
* END IF
|
|
* SETPIXEL XC + X, YC + Y
|
|
* SETPIXEL XC - X, YC + Y
|
|
* SETPIXEL XC - X, YC - Y
|
|
* SETPIXEL XC + X, YC - Y
|
|
* SETPIXEL XC + Y, YC + X
|
|
* SETPIXEL XC - Y, YC + X
|
|
* SETPIXEL XC - Y, YC - X
|
|
* SETPIXEL XC + Y, YC - X
|
|
* WEND
|
|
*
|
|
********************************
|
|
*
|
|
TCIRCLE
|
|
*
|
|
** FIRST, INITIALIZE VARIABLES
|
|
*
|
|
LDA #0 ; {2C2B} CLEAR YPOS {NZ}
|
|
STA ]Y ; {4C3B}
|
|
LDA ]R ; {4C3B} LOAD RADIUS {NZ}
|
|
STA ]X ; {4C3B} X = RADIUS
|
|
STA ]ERR ; {4C3B} ERROR = RADIUS
|
|
ASL ; {2C1B} R * 2 {NZC}
|
|
STA ]DIAM ; {4C3B} STORE DIAMETER
|
|
*
|
|
** NOW DRAW FIRST PART OF CIRCLE
|
|
*
|
|
** CALCULATE -X AND -Y
|
|
*
|
|
LDA ]X ; {4C3B} GET XPOS {NZ}
|
|
NEGA ; {6C5B} {NZCV}
|
|
STA ]XT ; {4C3B} STORE NEGATED IN XT
|
|
LDA ]Y ; {4C3B} GET YPOS {NZ}
|
|
NEGA ; {6C5B} {NZCV}
|
|
STA ]YT ; {4C3B} STORE NEGATED IN YT
|
|
*
|
|
** PLOT XC+X,YC
|
|
*
|
|
LDA ]XC ; {4C3B} LOAD CIRCLE CENTER XPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]X ; {4C3B} ADD CURRENT XPOS {NZCV}
|
|
TAY ; {2C1B} TRANSER TO .Y {NZ}
|
|
TAX ; {2C1B} AND .X {NZ}
|
|
LDA ]YC ; {4C3B} LOAD CIRCLE CENTER YPOS {NZ}
|
|
JSR GBCALC ; {43C3B} GET X,Y SCREEN MEMORY POS
|
|
LDA ]F ; {4C3B} LOAD FILL CHAR {NZ}
|
|
STA (GBPSH),Y ; {5C3B} STORE IN SCREEN MEMORY
|
|
*
|
|
** PLOT XC-X,YC
|
|
*
|
|
LDA ]XC ; {4C3B} LOAD CIRCLE CENTER XPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]XT ; {4C3B} ADD NEGATED CURRENT XPOS {NZCV}
|
|
TAX ; {2C1B} TRANSFER TO .X {NZ}
|
|
TAY ; {2C1B} AND .Y {NZ}
|
|
LDA ]YC ; {4C3B} LOAD CIRCLE CENTER YPOS {NZ}
|
|
JSR GBCALC ; {43C3B} GET X,Y SCREEN MEMORY POS
|
|
LDA ]F ; {4C3B} LOAD FILL CHAR {NZ}
|
|
STA (GBPSH),Y ; {5C3B} STORE IN SCREEN MEMORY
|
|
*
|
|
** PLOT XC,YC+X
|
|
*
|
|
LDA ]XC ; {4C3B} LOAD CIRCLE CENTER XPOS {NZ}
|
|
TAY ; {2C1B} TRANSFER TO .Y {NZ}
|
|
TAX ; {2C1B} AND .X {NZ}
|
|
LDA ]YC ; {4C3B} LOAD CIRCLE CENTER YPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]X ; {4C3B} ADD CURRENT XPOS {NZCV}
|
|
JSR GBCALC ; {43C3B} GET X,Y SCREEN MEMORY POS
|
|
LDA ]F ; {4C3B} LOAD FILL CHAR {NZ}
|
|
STA (GBPSH),Y ; {5C3B} STORE IN SCREEN MEMORY
|
|
*
|
|
** PLOT XC,YC-X
|
|
*
|
|
LDA ]XC ; {4C3B} LOAD CIRCLE CENTER XPOS {NZ}
|
|
TAY ; {2C1B} TRANSFER TO .Y {NZ}
|
|
TAX ; {2C1B} AND .X {NZ}
|
|
LDA ]YC ; {4C3B} LOAD CIRCLE CENTER YPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]XT ; {4C3B} ADD NEGATED CURRENT XPOS {NZCV}
|
|
JSR GBCALC ; {43C3B} GET X,Y SCREEN MEMORY POS
|
|
LDA ]F ; {4C3B} LOAD FILL CHAR {NZ}
|
|
STA (GBPSH),Y ; {5C3B} STORE IN SCREEN MEMORY
|
|
*
|
|
** NOW LOOP UNTIL CIRCLE IS FINISHED
|
|
*
|
|
:LOOP
|
|
*
|
|
** CHECK IF CIRCLE FINISHED
|
|
*
|
|
LDA ]Y ; {4C3B} IF Y > X {NZ}
|
|
CMP ]X ; {4C3B} {NZC}
|
|
BCC :LPCONT ; {3C2B} CONTINUE LOOPING
|
|
JMP :EXIT ; {3C3B} OTHERWISE, CIRCLE DONE
|
|
:LPCONT
|
|
:STEPY ; STEP THE Y POSITION
|
|
LDA ]Y ; {4C3B} LOAD YPOS {NZ}
|
|
ASL ; {2C1B} MULTIPLY BY 2 {NZC}
|
|
*CLC
|
|
ADC #1 ; {3C2B} ADD +1 {NZCV}
|
|
STA ]DY ; {4C3B} STORE CHANGE OF Y
|
|
INC ]Y ; {6C3B} INCREASE YPOS {NZ}
|
|
LDA ]DY ; {3C2B} NEGATE {NZ}
|
|
NEGA ; {6C5B} {NZCV}
|
|
ADC ]ERR ; {4C3B} ADD ERR {NZCV}
|
|
STA ]ERR ; {4C3B} ERR = ERR - DY
|
|
BPL :PLOT ; {3C2B} IF ERR IS +, SKIP TO PLOT
|
|
:STEPX
|
|
LDA ]X ; {3C2B} LOAD XPOS {NZ}
|
|
ASL ; {2C1B} MULTIPLY BY 2 {NZC}
|
|
NEGA ; {6C5B} NEGATE {NZCV}
|
|
ADC #1 ; {3C2B} (X*2) + 1 {NZCV}
|
|
STA ]DX ; {4C3B} STORE CHANGE OF X
|
|
DEC ]X ; {6C3B} DECREASE YPOS {NZ}
|
|
LDA ]DX ; {3C2B} NEGATE {NZ}
|
|
NEGA ; {6C5B} {NZCV}
|
|
ADC ]ERR ; {4C3B} ADD ERR {NZCV}
|
|
STA ]ERR ; {4C3B} ERR = ERR - DX
|
|
*
|
|
:PLOT
|
|
*
|
|
** NOW CALCULATE -X AND -Y
|
|
*
|
|
LDA ]X ; {3C2B} {NZ}
|
|
NEGA ; {6C5B} NEGATE {NZCV}
|
|
STA ]XT ; {4C3B}
|
|
LDA ]Y ; {3C2B} {NZ}
|
|
NEGA ; {6C5B} NEGATE {NZCV}
|
|
STA ]YT ; {4C3B}
|
|
*
|
|
** NOW PLOT CIRCLE OCTANTS
|
|
*
|
|
** PLOT XC+X,YC+Y
|
|
*
|
|
LDA ]XC ; {3C2B} LOAD CIRCLE CENTER XPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]X ; {4C3B} ADD CURRENT XPOS {NZCV}
|
|
TAY ; {2C1B} TRANSFER TO .Y {NZ}
|
|
TAX ; {2C1B} AND .X {NZ}
|
|
LDA ]YC ; {3C2B} LOAD CIRCLE CENTER YPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]Y ; {4C3B} ADD CURRENT YPOS {NZCV}
|
|
JSR GBCALC ; {43C3B} GET X,Y SCREEN ADDRESS {NZCV}
|
|
LDA ]F ; {3C2B} LOAD FILL CHAR {NZ}
|
|
STA (GBPSH),Y ; {6C2B} STORE AT SCREEN ADDRESS
|
|
*
|
|
** PLOT XC-X,YC+Y
|
|
*
|
|
LDA ]XC ; {3C2B} LOAD CIRCLE CENTER XPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]XT ; {4C3B} ADD NEGATED CURRENT XPOS {NZCV}
|
|
TAY ; {2C1B} TRANSFER TO .Y {NZ}
|
|
TAX ; {2C1B} AND TO .X {NZ}
|
|
LDA ]YC ; {3C2B} LOAD CIRCLE CENTER YPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]Y ; {4C3B} ADD CURRENT YPOS {NZCV}
|
|
JSR GBCALC ; {43C3B} GET X,Y SCREEN ADDRESS {NZCV}
|
|
LDA ]F ; {3C2B} LOAD FILL CHAR {NZ}
|
|
STA (GBPSH),Y ; {6C2B} STORE AT SCREEN ADDRESS
|
|
*
|
|
** PLOT XC-X,YC-Y
|
|
*
|
|
LDA ]XC ; {3C2B} LOAD CIRCLE CENTER XPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]XT ; {4C3B} ADD NEGATED CURRENT XPOS {NZCV}
|
|
TAY ; {2C1B} TRANSFER TO .Y {NZ}
|
|
TAX ; {2C1B} AND .X {NZ}
|
|
LDA ]YC ; {3C2B} LOAD CIRCLE CENTER YPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]YT ; {4C3B} ADD NEGATED CURRENT YPOS {NZCV}
|
|
JSR GBCALC ; {43C3B} GET X,Y SCREEN ADDRESS {NZCV}
|
|
LDA ]F ; {3C2B} LOAD FILL CHARACTER {NZ}
|
|
STA (GBPSH),Y ; {6C2B} STORE AT SCREEN ADDRESS
|
|
*
|
|
** PLOT XC+X,YC-Y
|
|
*
|
|
LDA ]XC ; {3C2B} LOAD CIRCLE CENTER XPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]X ; {4C3B} ADD CURRENT XPOS {NZCV}
|
|
TAY ; {2C1B} TRANSFER TO .Y {NZ}
|
|
TAX ; {2C1B} AND .X {NZ}
|
|
LDA ]YC ; {3C2B} LOAD CIRCLE CENTER YPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]YT ; {4C3B} ADD NEGATE CURRENT YPOS {NZCV}
|
|
JSR GBCALC ; {43C3B} GET X,Y SCREEN ADDRESS {NZCV}
|
|
LDA ]F ; {3C2B} LOAD FILL CHAR {NZ}
|
|
STA (GBPSH),Y ; {6C2B} STORE AT SCREEN ADDRESS
|
|
*
|
|
** PLOT XC+Y,YC+X
|
|
*
|
|
LDA ]XC ; {3C2B} LOAD CIRCLE CENTER XPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]Y ; {4C3B} ADD CURRENT YPOS {NZCV}
|
|
TAX ; {2C1B} TRANSFER TO .X {NZ}
|
|
TAY ; {2C1B} AND .Y {NZ}
|
|
LDA ]YC ; {3C2B} LOAD CIRCLE CENTER YPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]X ; {4C3B} ADD CURRENT XPOS {NZCV}
|
|
JSR GBCALC ; {43C3B} GET X,Y SCREEN ADDRESS {NZCV}
|
|
LDA ]F ; {3C2B} LOAD FILL CHAR {NZ}
|
|
STA (GBPSH),Y ; {6C2B} STORE AT SCREEN ADDRESS
|
|
*
|
|
** PLOT XC-Y,YC+X
|
|
*
|
|
LDA ]XC ; {3C2B} LOAD CIRCLE CENTER XPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]YT ; {4C3B} ADD NEGATED CURRENT YPOS {NZCV}
|
|
TAX ; {2C1B} TRANSFER TO .X {NZ}
|
|
TAY ; {2C1B} AND .Y {NZ}
|
|
LDA ]YC ; {3C2B} LOAD CIRCLE CENTER YPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]X ; {4C3B} ADD CURRENT XPOS {NZCV}
|
|
JSR GBCALC ; {43C3B} GET X,Y SCREEN ADDRESS {NZCV}
|
|
LDA ]F ; {3C2B} LOAD FILL CHAR {NZ}
|
|
STA (GBPSH),Y ; {6C2B} STORE AT SCREEN ADDRESS
|
|
*
|
|
** PLOT XC-Y,YC-X
|
|
*
|
|
LDA ]XC ; {3C2B} LOAD CIRCLE CENTER XPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]YT ; {4C3B} ADD NEGATED CURRENT YPOS {NZCV}
|
|
TAX ; {2C1B} TRANSFER TO .X {NZ}
|
|
TAY ; {2C1B} AND .Y {NZ}
|
|
LDA ]YC ; {3C2B} LOAD CIRCLE CENTER YPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]XT ; {4C3B} ADD NEGATED CURRENT XPOS {NZCV}
|
|
JSR GBCALC ; {43C3B} GET X,Y SCREEN ADDRESS {NZCV}
|
|
LDA ]F ; {3C2B} LOAD FILL CHAR {NZ}
|
|
STA (GBPSH),Y ; {6C2B} STORE AT SCREEN ADDRESS
|
|
*
|
|
** PLOT XC+Y,YC-X
|
|
*
|
|
LDA ]XC ; {3C2B} LOAD CIRCLE CENTER XPOS {NZ}
|
|
CLC ; {2C1B} CLEAR CARRY {C=0}
|
|
ADC ]Y ; {4C3B} ADD CURRENT YPOS {NZCV}
|
|
TAY ; {2C1B} TRANSFER TO .Y {NZ}
|
|
TAX ; {2C1B} AND .X {NZ}
|
|
LDA ]YC ; {3C2B} LOAD CIRCLE CENTER YPOS {NZ}
|
|
CLC ; {2C1B} {C=0}
|
|
ADC ]XT ; {4C3B} ADD NEGATED CURRENT XPOS {NZCV}
|
|
JSR GBCALC ; {43C3B} GET X,Y SCREEN ADDRESS {NZCV}
|
|
LDA ]F ; {3C2B} LOAD FILL CHAR {NZ}
|
|
STA (GBPSH),Y ; {6C2B} STORE AT SCREEN ADDRESS
|
|
JMP :LOOP ; {3C3B} LOOP UNTIL FINISHED
|
|
:EXIT
|
|
RTS ; {6C1B}
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TREC MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `TREC` |
|
|
| Type | Macro |
|
|
| File | `MAC.SCRMEM.STDIO.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Plot an unfilled rectangle to the text screen |
|
|
| Input | ]1 = X Origin<br />]2 = Y Origin <br />]3 = X Destination<br />]4 = Y Destination<br />]5 = Fill Value |
|
|
| Output | An unfilled rectangle made of the specified <br />character is placed in screen memory. |
|
|
| Dependencies | `SUB.TRECT.ASM` |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 362+ |
|
|
| Bytes | 115 |
|
|
| Notes | none |
|
|
| See Also | `TRECT` `TRECTF` `TRECF` |
|
|
|
|
*DETAILS*
|
|
|
|
The `TREC` macro plots an unfilled rectangle directly to screen memory at the given coordinates, composed of the passed fill character. The macro itself is fairly standard, and only functions to pass parameters to the `TRECT` subroutine via the proper addresses on the zero page.
|
|
|
|
|
|
|
|
`FIGURE 2.54: TREC Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TREC *
|
|
* *
|
|
* CREATE A RECTANGULAR BORDER *
|
|
* ON THE SCREEN. NOTE THAT THE *
|
|
* INSIDE IS NOT FILLED WITH *
|
|
* ANY CHARACTER, INCLUDING *
|
|
* BLANK SPACES. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = X ORIGIN *
|
|
* ]2 = Y ORIGIN *
|
|
* ]3 = X DESTINATION *
|
|
* ]4 = Y DESTINATION *
|
|
* ]5 = BORDER CHARACTER *
|
|
* *
|
|
* CYCLES: 362+ *
|
|
* SIZE: 115 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
TREC MAC
|
|
LDA ]1 ; {2C2B} LOAD X-ORIGIN
|
|
STA WPAR1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]2 ; {2C2B} LOAD Y-ORIGIN
|
|
STA WPAR1+1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]3 ; {2C2B} LOAD X-DESTINATION
|
|
STA WPAR2 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]4 ; {2C2B} LOAD Y-DESTINATION
|
|
STA WPAR2+1 ; {2C2B} PASS VIA ZERO PAGE
|
|
LDA ]5 ; {2C2B} LOAD FILL CHARACTER
|
|
STA BPAR1 ; {3C2B} PASS VIA ZERO PAGE
|
|
JSR TRECT ; {338C95B} CALL TRECT SUBROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TRECT Subroutine
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `TRECT` |
|
|
| Type | Subroutine |
|
|
| File | `SUB.TRECT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Plot an open rectangle to screen memory |
|
|
| Input | WPAR1 = X-position Origin <br />WPAR1+1 = X-position Destination<br />WPAR2 = Y-position Origin<br />WPAR2+1 = Y-position Destination<br />BPAR1 = Fill Character |
|
|
| Output | An unfilled rectangle is painted to screen memory |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 332+ |
|
|
| Bytes | 92 |
|
|
| Notes | none |
|
|
| See Also | `TREC` `TRECTF` `TRECF` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `TRECT` subroutine draws an unfilled rectangle on the screen (via direct memory access) made up of a given text character. It accepts an X,Y origin and an X,Y destination along with the fill character as parameters passed via the zero page.
|
|
|
|
For the most part, `TRECT` combines the algorithms found in `TVLINE` and `THLINE` to create the horizontal and vertical sides of the rectangle. The memory address for each given point is determined by GBCALC (GBASCALC), and thus does not use or interfere with any COUT activities or machine states.
|
|
|
|
|
|
|
|
`FIGURE 2.55: TRECT Subroutine Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TRECT (NATHAN RIGGS) *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* WPAR1 = X ORIGIN *
|
|
* WPAR1+1 = X DESTINATION *
|
|
* WPAR2 = Y ORIGIN *
|
|
* WPAR2+1 = Y DESTINATION *
|
|
* BPAR1 = FILL CHARACTER *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* UNFILLED BOX BORDER TO THE *
|
|
* SCREEN MEMORY. *
|
|
* *
|
|
* DESTROYS: NZCIDV *
|
|
* ^^^ ^ *
|
|
* *
|
|
* CYCLES: 332+ *
|
|
* SIZE: 92 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
]X1 EQU WPAR1 ; XPOS ORIGIN
|
|
]X2 EQU WPAR2 ; XPOS DESTINATION
|
|
]Y1 EQU WPAR1+1 ; YPOS ORIGIN
|
|
]Y2 EQU WPAR2+1 ; YPOS DESTINATION
|
|
]F EQU BPAR1 ; FILL CHARACTER (BORDER)
|
|
*
|
|
]YB1 EQU VARTAB
|
|
*
|
|
TRECT
|
|
*
|
|
LDA ]Y1 ; {3C2B} LOAD 1ST ROW {NZ}
|
|
LDY ]X1 ; {3C2B} LOAD XPOS START {NZ}
|
|
:LP1
|
|
JSR GBCALC ; {49C3B} GOSUB GBASCALC {NZCV}
|
|
LDA ]F ; {3C2B} LOAD FILL CHAR {NZ}
|
|
STA (GBPSH),Y ; {6C2B} PUSH ]F TO SCREEN MEM
|
|
LDA ]Y1 ; {3C2B} LOAD YPOS {NZ}
|
|
INY ; {2C1B} INCREASE XPOS {NZ}
|
|
CPY ]X2 ; {3C2B} IF < X DEST THEN END {NZC}
|
|
BNE :LP1 ; {3C2B} REPEAT UNTIL DONE
|
|
*
|
|
** NEXT HORIZONTAL LINE ROUTINE
|
|
*
|
|
LDA ]Y2 ; {3C2B} LOAD 2ND ROW {NZ}
|
|
LDY ]X1 ; {3C2B} LOAD XPOS START {NZ}
|
|
:LP2
|
|
JSR GBCALC ; {49C3B} GOSUB GBASCALC {NZCV}
|
|
LDA ]F ; {2C2B} LOAD FILL CHAR {NZ}
|
|
STA (GBPSH),Y ; {6C2B} PUSH ]F TO SCREEN MEM
|
|
LDA ]Y2 ; {3C2B} LOAD YPOS
|
|
INY ; {2C1B} INCREASE XPOS {NZ}
|
|
CPY ]X2 ; {3C2B} IF < X DEST THEN END {NZC}
|
|
BNE :LP2 ; {3C2B} REPEAT UNTIL DONE
|
|
*
|
|
** VERTICAL LINES ROUNTINE
|
|
*
|
|
LDA ]Y1 ; {4C3B} LOAD Y ORIGIN
|
|
STA ]YB1 ; {3C2B} COPY OF Y ORIGIN
|
|
LDY ]X1 ; {4C3B} LOAD X POSITION {NZ}
|
|
:LP3
|
|
JSR GBCALC ; {49C3B} GET POS SCREEN ADDR {NZCV}
|
|
LDA ]F ; {4C3B} LOAD FILL CHAR
|
|
STA (GBPSH),Y ; {6C2B} PUSH ]F TO SCREEN MEM
|
|
INC ]YB1 ; {6C3B} INCREASE Y POSITION {NZ}
|
|
LDA ]YB1 ; {4C3B} RELOAD Y POSITION {NZ}
|
|
CMP ]Y2 ; {4C3B} IF Y1 < Y2 {NZC}
|
|
BNE :LP3 ; {3C2B} THEN LOOP; ELSE END
|
|
*
|
|
INC ]Y2 ; {6C3B} ADD 1 TO Y2 FOR RECT {NZ}
|
|
LDA ]Y1 ; {4C3B} LOAD Y ORIGIN
|
|
LDY ]X2 ; {4C3B} LOAD X POSITION {NZ}
|
|
:LP4
|
|
JSR GBCALC ; {49C3B} GET SCREEN ADDRESS {NZCV}
|
|
LDA ]F ; {4C3B} LOAD FILL CHAR
|
|
STA (GBPSH),Y ; {6C2B} PUSH ]F TO SCREEN MEM
|
|
INC ]Y1 ; {6C3B} INCREASE Y POSITION {NZ}
|
|
LDA ]Y1 ; {4C3B} RELOAD Y POSITION {NZ}
|
|
CMP ]Y2 ; {4C3B} IF Y1 < Y2 {NZC}
|
|
BNE :LP4 ; {3C2B} THEN LOOP; ELSE EXIT LOOP
|
|
RTS ; {6C1B}
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE SPUT MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `SPUT` |
|
|
| Type | Macro |
|
|
| File | `MAC.SCRMEM.STDIO.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Plot a string to the text screen |
|
|
| Input | ]1 = X Coordinate<br />]2 = Y Coordinate <br />]3 = String Address |
|
|
| Output | A string of characters at the give X,Y<br />position. |
|
|
| Dependencies | `SUB.STRPUT.ASM` |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 124+ |
|
|
| Bytes | 50 |
|
|
| Notes | none |
|
|
| See Also | `STRPUT` `CPUT` `TXTPUT` `SPRN` |
|
|
|
|
*DETAILS*
|
|
|
|
The `SPUT` macro plots a regular string of characters to screen memory, passing the necessary parameters via the zero page. Like other macros in this file, `SPUT` leaves COUT untouched; a string can be plotted at any place on the screen without, for instance, changing the COUT cursor values. Additionally, emphasis should be put on the fact that this subroutine works with **regular** strings, not null-terminated strings. A regular string has a preceding byte that holds the length of the string.
|
|
|
|
As with any time a memory address is passed to a subroutine, the parameter is parsed based on whether a literal value is given or a memory address alone. If the value is literal (begins with a # sign), then the address is to be read as pointing directly to the string to be printed; if the value points to a specific address, on the other hand, then the value passed is considered an indirect memory address: the address given holds another address at which the string resides.
|
|
|
|
|
|
|
|
`FIGURE 2.56: SPUT Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* SPUT *
|
|
* *
|
|
* THIS MACRO PLOTS A CHARACTER *
|
|
* TO THE SCREEN VIA DIRECT *
|
|
* ACCESS TO SCREEN MEMORY. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = X COORDINATE *
|
|
* ]2 = Y COORDINATE *
|
|
* ]3 = ADDRESS OF STRING *
|
|
* TO PRINT ON SCREEN *
|
|
* *
|
|
* CYCLES: 124+ *
|
|
* SIZE: 50 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
SPUT MAC
|
|
LDA ]1 ; {2C2B} GET X COORDINATE
|
|
STA WPAR1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]2 ; {2C2B} GET Y COORDINATE
|
|
STA WPAR1+1 ; {3C2B} PASS VIA ZERO PAGE
|
|
_MLIT ]3;WPAR2 ; {16C12B} PARSE STRING ADDRESS
|
|
JSR STRPUT ; {98C30B} CALL STRPUT SUBROUTINE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE STRPUT Subroutine
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `STRPUT` |
|
|
| Type | Subroutine |
|
|
| File | `SUB.STRPUT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Print a regular string to screen memory |
|
|
| Input | WPAR1 = X Coordinate <br />WPAR1+1 =Y Coordinate<br />WPAR2 = String Address |
|
|
| Output | A given string is printed at the given coordinates |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 98+ |
|
|
| Bytes | 30 |
|
|
| Notes | none |
|
|
| See Also | `SPUT` `CPUT` `TXTPUT` `SPRN` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `STRPUT` subroutine plots a string directly to screen memory at a given starting coordinate, bypassing COUT in the process. This works much like the `CPUT` routine, except that each character in the string is cycled through and plotted instead of storing a single character value. Like most other subroutines on the STDIO disk, the appropriate address is determined using the GBCALC (GBASCALC) subroutine that is already provided by the Monitor.
|
|
|
|
|
|
|
|
`FIGURE 2.57: STRPUT Subroutine Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* STRPUT (NATHAN RIGGS) *
|
|
* *
|
|
* THIS SUBROUTINE PLOTS A *
|
|
* STRING OF CHARACTERS *
|
|
* DIRECTLY TO SCREEN MEMORY, *
|
|
* AVOIDING THE SLOW-DOWN OF *
|
|
* USING COUT ROUTINES. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* WPAR1 = X COORDINATE *
|
|
* WPAR1+1 = Y COORDINATE *
|
|
* WPAR2 = STRING ADDRESS *
|
|
* *
|
|
* DESTROYS: NZCIDV *
|
|
* ^^^ ^ *
|
|
* *
|
|
* CYCLES: 98+ *
|
|
* SIZE: 30 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
]X1 EQU WPAR1 ; X-COORDINATE TO PLOT
|
|
]Y1 EQU WPAR1+1 ; Y-COORDINATE TO PLOT
|
|
]ADDR EQU WPAR2 ; ADDRESS OF STRING TO PRINT
|
|
*
|
|
]LEN EQU VARTAB ; LENGTH OF STRING
|
|
]CNT EQU VARTAB+2 ; INDEX COUNTER
|
|
]CHAR EQU VARTAB+4 ; CHARACTER TO PRINT
|
|
*
|
|
STRPUT
|
|
*
|
|
LDY #0 ; {2C2B} CLEAR .Y COUNTER
|
|
STY ]CNT ; {3C2B} CLEAR ]CNT VARIABLE
|
|
LDA (]ADDR),Y ; {6C2B} GET STRING LENGTH
|
|
STA ]LEN ; {3C2B} STORE LENGTH IN ]LEN
|
|
:LP
|
|
INC ]CNT ; {6C3B} INCREMENT ]CNT BY 1
|
|
INC ]X1 ; {6C3B} INCREMENT X-COORD BY 1
|
|
LDY ]CNT ; {2C2B} PASS ]CNT TO .Y
|
|
LDA (]ADDR),Y ; {6C2B} LOAD CHARACTER FROM STRING
|
|
STA ]CHAR ; {3C2B} WITH Y OFFSET; HOLD IN ]CHAR
|
|
LDA ]Y1 ; {2C2B} LOAD Y COORDINATE
|
|
LDY ]X1 ; {2C2B} RELOAD X COORDINATE
|
|
JSR GBCALC ; {43C3B} CALCULATE SCREEN MEMORY ADDRESS
|
|
LDA ]CHAR ; {2C2B} LOAD FILL CHARACTER INTO .A
|
|
STA (GBPSH),Y ; {6C2B} STORE CHARACTER IN SCREEN MEMORY
|
|
LDY ]CNT ; {2C2B} RELOAD COUNTER
|
|
CPY ]LEN ; {2C2B} IF COUNTER != STRING LENGTH
|
|
BNE :LP ; {2C2B} THEN KEEP LOOPING
|
|
RTS ; {6C1B} OTHERWISE, RETURN FROM CALL
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TCLR MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ----------------------------------------------------- |
|
|
| Name | `TCLR` |
|
|
| Type | Macro |
|
|
| File | `MAC.SCRMEM.STDIO.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | fill text screen with a given character |
|
|
| Input | ]1 = Fill Character |
|
|
| Output | The entire screen fills with the given fill character |
|
|
| Dependencies | `SUB.TXTCLR.ASM` |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 50+ |
|
|
| Bytes | 42 |
|
|
| Notes | none |
|
|
| See Also | `TXTCLR` |
|
|
|
|
*DETAILS*
|
|
|
|
The `TCLR` macro simply fills the entirety of screen memory with the same value, providing a whole-screen clearing function that does not interact with COUT and additionally has the ability to paint the whole screen with more than blank spaces. The fill character is passed to the `TXTCLR` subroutine via the **.A** register.
|
|
|
|
|
|
|
|
`FIGURE 2.58: TCLR Macro`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TCLR *
|
|
* *
|
|
* THE TCLR MACRO FILLS (OR *
|
|
* CLEARS) THE ENTIRE SCREEN *
|
|
* WITH A GIVEN CHARACTER. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = FILL CHARACTER *
|
|
* *
|
|
* CYCLES: 50+ *
|
|
* SIZE: 42 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
TCLR MAC
|
|
LDA ]1 ; {2C2B} LOAD FILL CHARACTER
|
|
JSR TXTCLR ; {48C40B} CALL TXTCLR SUBROUTINE
|
|
<<<
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TXTCLR Subroutine
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ----------------------------------------- |
|
|
| Name | `TXTCLR` |
|
|
| Type | Subroutine |
|
|
| File | `SUB.TXTCLR.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Fill screen memory with a given character |
|
|
| Input | .A = Fill Character |
|
|
| Output | Full-screen fill with a single character |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 42+ |
|
|
| Bytes | 37 |
|
|
| Notes | none |
|
|
| See Also | `TCLR` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `TXTCLR` subroutine fills page 1 of the screen memory with a given value, filling the display with the associated character. Note that this fill is done in sections as they are naturally interweaved by the Apple II; this allows for a quicker fill while also avoiding a write overtop the fabled "screen hole" memory locations used by various devices.
|
|
|
|
|
|
|
|
`FIGURE 2.59: TXTCLR Subroutine Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TXTCLR (NATHAN RIGGS) *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* .A = FILL CHARACTER *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* FILLS THE SCREEN WITH THE *
|
|
* GIVEN CHARACTER. FILLS BY *
|
|
* SECTION TO AVOID CHANGING *
|
|
* SCREENHOLE VALUES. *
|
|
* *
|
|
* DESTROYS: NZCIDV *
|
|
* ^^ *
|
|
* *
|
|
* CYCLES: 42+ *
|
|
* SIZE: 37 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
]F EQU VARTAB ; FILL CHARACTER
|
|
*
|
|
TXTCLR
|
|
*
|
|
STA ]F ; {4C3B} STORE FILL CHAR IN MEM
|
|
LDY #$78 ; {2C2B} LENGTH OF EACH SCREEN SECTION {NZ}
|
|
:LP1
|
|
STA $400,Y ; {5C3B} 1ST SECTION
|
|
STA $480,Y ; {5C3B} 2ND SECTION
|
|
STA $500,Y ; {5C3B} 3RD SECTION
|
|
STA $580,Y ; {5C3B} 4TH SECTION
|
|
CPY #120 ; {2C2B} {NZC} -- #80
|
|
BPL :NDB ; {3C2B}
|
|
STA $600,Y ; {5C3B} 5TH SECTION
|
|
STA $680,Y ; {5C3B} 6TH SECTION
|
|
STA $700,Y ; {5C3B} 7TH SECTION
|
|
STA $780,Y ; {5C3B} 8TH SECTION
|
|
:NDB
|
|
DEY ; {2C1B} DECREASE BYTE COUNTER {NZ}
|
|
BPL :LP1 ; {3C2B} IF POSITIVE, KEEP LOOPING
|
|
RTS ; {6C1B} RETURN TO CALLING ROUTINE
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## Standard Input Macros and Subroutines
|
|
|
|
While the STDIO collection of macros and subroutines primarily focuses on screen output, methods of retrieving input from the keyboard or the paddles are essential for almost any program, and thus are provided here. Most of the macros and subroutines here use pre-existing routines provided by the Monitor and are thus integrated with COUT; when this is not the case, the reasoning behind the macro or subroutine will be explained in detail.
|
|
|
|
|
|
|
|
`FIGURE 2.60: MAC.STDIN.ASM Header Listing`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* MAC.STDIN.ASM *
|
|
* *
|
|
* THIS IS A MACRO LIBRARY FOR *
|
|
* STANDARD INPUT AND OUTPUT. *
|
|
* *
|
|
* AUTHOR: NATHAN RIGGS *
|
|
* CONTACT: NATHAN.RIGGS@ *
|
|
* OUTLOOK.COM *
|
|
* *
|
|
* DATE: 11-MAR-2021 *
|
|
* ASSEMBLER: MERLIN 8 PRO *
|
|
* OS: DOS 3.3 *
|
|
* *
|
|
* SUBROUTINES FILES USED: *
|
|
* *
|
|
* SUB.SINPUT *
|
|
* *
|
|
* LIST OF MACROS *
|
|
* *
|
|
* INP : STRING INPUT *
|
|
* GKEY : GET SINGLE KEY *
|
|
* PDL : READ PADDLE STATE *
|
|
* PBX : READ PDL BTN X *
|
|
* WAIT : WAIT FOR KEYPRESS *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE INP MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `INP` |
|
|
| Type | Macro |
|
|
| File | `MAC.STDIN.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | input a string from the keyboard |
|
|
| Input | none |
|
|
| Output | keystrokes are printed to the screen<br />as they are entered |
|
|
| Dependencies | `SUB.SINPUT.ASM` |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 64+ |
|
|
| Bytes | 41 |
|
|
| Notes | none |
|
|
| See Also | `SINPUT` |
|
|
|
|
*DETAILS*
|
|
|
|
The `INP` macro is as simple as a macro can get: it simply calls the `SINPUT` subroutine, which works much like the `INPUT` command in Applesoft BASIC. Please see the `SINPUT` entry for details about how the subroutine works.
|
|
|
|
|
|
|
|
`FIGURE 2.61: INP Macro Source`
|
|
|
|
```asm
|
|
*
|
|
*``````````````````````````````*
|
|
* INP *
|
|
* *
|
|
* INPUTS A STRING FROM KEYBRD *
|
|
* AND STORES IT IN [RETURN] *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* NONE *
|
|
* *
|
|
* CYCLES: 64+ *
|
|
* SIZE: 41 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
INP MAC
|
|
JSR SINPUT
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE SINPUT SUBROUTINE
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `SINPUT` |
|
|
| Type | Subroutine |
|
|
| File | `SUB.SINPUT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | input a string from the keyboard |
|
|
| Input | none |
|
|
| Output | keystrokes are printed to the screen<br />as they are entered |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 58+ |
|
|
| Bytes | 38 |
|
|
| Notes | none |
|
|
| See Also | `INP` |
|
|
|
|
*DETAILS*
|
|
|
|
The `SINPUT` subroutine waits for a line of input to be entered by the user via the keyboard, terminated by a press of the **RETURN** key. The subroutine can be thought of as a wrapper around the `GETLN` routine already provided on the Apple II: `GETLN` is first called, which handles all of the necessary details of inputting from the keyboard. After the user hits **RETURN**, the `SINPUT` subroutine then copies the string from its usual location to the library's **RETURN** address, with its length in bytes stored at **RETLEN**, which resides at the byte just prior to **RETURN** (making it accessible as a normal string).
|
|
|
|
Of course, `SINPUT` can be abandoned in favor of `GETLN`, as `SINPUT` does nothing but integrate `GETLN` into the logic of the AppleIIASM library. This would save a number of cycles, but the savings would be rather pointless: it does not matter how many cycles an input routine will take. For the sake of consistency, it is advised that `SINPUT` be used in place of `GETLN` alone so that the programmer need not remember the extra data location used by `GETLN`.
|
|
|
|
|
|
|
|
`FIGURE 2.62: SINPUT Subroutine Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* SINPUT (NATHAN RIGGS) *
|
|
* *
|
|
* INPUT *
|
|
* *
|
|
* USER TYPES UP TO 255 CHARS *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* .X = LENGTH OF STRING *
|
|
* RETURN = STRING TYPED *
|
|
* RETLEN = LENGTH OF STRING *
|
|
* *
|
|
* DESTROY: NZCIDV *
|
|
* ^^^ *
|
|
* *
|
|
* CYCLES: 58+ *
|
|
* SIZE: 38 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
]STRLEN EQU VARTAB ; STRING LENGTH (1 BYTE)
|
|
*
|
|
SINPUT
|
|
LDX #$00 ; {2C2B} RESET LENGTH {NZ}
|
|
JSR GETLN ; {6C3B} GOSUB GETLN ROUTINE. AS JOHN ROMERO
|
|
; HILARIOUSLY POINTED OUT ON FACEBOOK,
|
|
; COMING OUT OF NOWHERE,
|
|
; WHICH I AM BOTH ASHAMED AND PROUD OF,
|
|
; IT'S PRETTY POINTLESS TO CYCLE-COUNT
|
|
; AN INPUT FUNCTION, SO I WON'T BE DOING
|
|
; SO HERE, THOUGH I STARTED TO TRY
|
|
*
|
|
STX ]STRLEN ; {4C3B} STRING LENGTH RETURNED IN .X; STORE
|
|
CPX #0 ; {2C2B} IF LENGTH = 0, EXIT {NZC}
|
|
BNE :INP_CLR ; {3C2B} OTHER, COPY STRING
|
|
STX RETLEN ; {4C3B} OTHERWISE, STORE IN RETURN LENGTH
|
|
JMP :EXIT ; {6C5B} JUMP TO EXIT
|
|
:INP_CLR
|
|
STX RETLEN ; {4C3B} STORE STRING LENGTH
|
|
LDY #255 ; {2C2B} RESET COUNTER TO -1 {NZ}
|
|
:LOOP
|
|
INY ; {2C1B} INCREASE COUNTER BY 1 {NZ}
|
|
LDA KEYBUFF,Y ; {5C3B} CHAR FROM KEYBOARD BUFFER {NZ}
|
|
STA RETURN,Y ; {5C3B} STORE IN RETURN AT INDEX
|
|
CPY ]STRLEN ; {4C3B} IF COUNTER < STRING LENGTH {NZC}
|
|
BNE :LOOP ; {3C2B} LOOP; ELSE, EXIT
|
|
:EXIT
|
|
RTS ; {6C1B} RETURN TO CALLING ROUTINE
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE GKEY MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ----------------------------------- |
|
|
| Name | `GKEY` |
|
|
| Type | Macro |
|
|
| File | `MAC.STDIN.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | input a character from the keyboard |
|
|
| Input | none |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 11+ |
|
|
| Bytes | 7 |
|
|
| Notes | none |
|
|
| See Also | `WAIT` |
|
|
|
|
*DETAILS*
|
|
|
|
The `GKEY` macro simply serves as a shortcut for the `GETKEY` routine provided by the Monitor. This routine pauses execution until a key is pressed, and then stores the value of the key pressed in the **.A** register. Afterward, the keyboard strobe is reset, which is required for any other future `GETKEY` uses to work correctly.
|
|
|
|
|
|
|
|
`Figure 2.63: GKEY Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* GKEY *
|
|
* *
|
|
* WAITS FOR USER TO PRESS A *
|
|
* KEY, THEN STORES THAT IN .A *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* NONE *
|
|
* *
|
|
* CYCLES: 11+ *
|
|
* SIZE: 7 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
GKEY MAC
|
|
JSR GETKEY ; {6+C3B} MONITOR GET SUBROUTINE
|
|
LDY #0 ; {2C2B}
|
|
STY STROBE ; {3C2B} RESET KBD STROBE
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE PDL MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------- |
|
|
| Name | `PDL` |
|
|
| Type | Macro |
|
|
| File | `MAC.STDIN.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Reads state of the given paddle wheel |
|
|
| Input | ]1 = Paddle Address |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 8+ |
|
|
| Bytes | 5 |
|
|
| Notes | none |
|
|
| See Also | `PBX` |
|
|
|
|
*DETAILS*
|
|
|
|
The `PDL` macro returns the state value of a specified paddle wheel (#0 or #1, passed via **.X**), ranging from 0 to 255, and returns it in the **.Y** register. For the most part this is another wrapper macro, and adds very little in the way of extra functionality.
|
|
|
|
|
|
|
|
`FIGURE 2.64: PDL Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* PDL *
|
|
* *
|
|
* SIMPLY READS STATE OF PADDLE *
|
|
* NUMBER [NUM] AND STORES IT *
|
|
* IN THE Y REGISTER. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = PADDLE # TO READ *
|
|
* *
|
|
* CYCLES: 8+ *
|
|
* SIZE: 5 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
PDL MAC ; GET PADDLE VALUE
|
|
LDX ]1 ; {2C2B} READ PADDLE # ]1 (USUALLY 0)
|
|
JSR PREAD ; {6+C3B} PADDLE READING STORED IN Y
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE PBX MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | -------------------------------------- |
|
|
| Name | `PBX` |
|
|
| Type | Macro |
|
|
| File | `MAC.STDIN.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Reads state of the given paddle button |
|
|
| Input | ]1 = Paddle button address |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 8+ |
|
|
| Bytes | 8 |
|
|
| Notes | none |
|
|
| See Also | `PDL` |
|
|
|
|
*DETAILS*
|
|
|
|
The `PBX` macro returns the state of a specified paddle button. A button can either be pressed (or on, value #1) or unpressed (off, #0). The state of the button is returned via the **.X** register: 0 for for unpressed, 1 for pressed.
|
|
|
|
This library also provides convenient labels for the paddle button addresses to be passed as parameters and read. There are four possible buttons that can be read, each with their own memory address byte. These can be accessed via the labels PB0, PB1, PB2 and PB3. These correlate, in order, to the addresses $C061, $C062, $C063, and $C060.
|
|
|
|
|
|
|
|
`FIGURE 2.65: PBX Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* PBX *
|
|
* *
|
|
* READ THE SPECIFIED PADDLE *
|
|
* BUTTON. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = PADDLE BUTTON TO READ *
|
|
* *
|
|
* PB0: $C061 PB1: $C062 *
|
|
* PB2: $C063 PB4: $C060 *
|
|
* *
|
|
* CYCLES: 8+ *
|
|
* SIZE: 8 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
PBX MAC
|
|
LDX #1 ; {2C2B}
|
|
LDA ]1 ; {2C2B} IF BTN = PUSHED
|
|
BMI EXIT ; {2C2B} IF HIBYTE SET, BUTTON PUSHED
|
|
LDX #0 ; {2C2B} OTHERWISE, BUTTON NOT PUSHED
|
|
EXIT
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE WAIT MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------- |
|
|
| Name | `WAIT` |
|
|
| Type | Macro |
|
|
| File | `MAC.STDIN.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Pauses execution until key is pressed |
|
|
| Input | none |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 9+ |
|
|
| Bytes | 8 |
|
|
| Notes | none |
|
|
| See Also | `GKEY` |
|
|
|
|
*DETAILS*
|
|
|
|
The `WAIT` macro is rather self-explanatory: program execution is paused until a key is pressed. While this is similar to the `GKEY` macro, `WAIT` does not use COUT; instead, the loop is handled by the macro itself. Once a button is pressed, its ASCII value can be found in the **.A** register.
|
|
|
|
|
|
|
|
`FIGURE 2.66: WAIT Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* WAIT *
|
|
* *
|
|
* WAIT FOR A KEYPRESS WITHOUT *
|
|
* INTERFERING WITH COUT. KEY *
|
|
* CODE IS STORED IN .A. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* NONE *
|
|
* *
|
|
* CYCLES: 9 *
|
|
* SIZE: 8 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
WAIT MAC
|
|
]WTLP LDA KYBD ; {2C2B} READ KEYBOARD BUFFER
|
|
BPL ]WTLP ; {2C2B} IF 0, KEEP LOOPING
|
|
AND #$7F ; {2C2B} OTHERWISE, SET HI BIT
|
|
STA STROBE ; {3C2B} CLEAR STROBE
|
|
<<<
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## Miscellaneous STDIO Macros and Subroutines
|
|
|
|
The final collection of macros on the STDIO disk contains miscellaneous items that do not necessarily fit neatly into the COUT or direct screen memory collections. Some of these macros may work only in systems with a Language card for 80-column mode, or versions of the Apple II that can use Mousetext characters. For the most part, these macros are less complicated or less useful than other STDIO macros, and may be added to your own work easier on a one-by-one basis.
|
|
|
|
`FIGURE 2.67: MAC.MSC.STDIO.ASM Header`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* MAC.MISC.STDIO.ASM *
|
|
* *
|
|
* THIS IS A MACRO LIBRARY FOR *
|
|
* STANDARD INPUT AND OUTPUT. *
|
|
* *
|
|
* AUTHOR: NATHAN RIGGS *
|
|
* CONTACT: NATHAN.RIGGS@ *
|
|
* OUTLOOK.COM *
|
|
* *
|
|
* DATE: 11-MAR-2021 *
|
|
* ASSEMBLER: MERLIN 8 PRO *
|
|
* OS: DOS 3.3 *
|
|
* *
|
|
* REQUIRED SUBROUTINES *
|
|
* *
|
|
* SUB.TXTCENT.ASM *
|
|
* *
|
|
* LIST OF MACROS *
|
|
* *
|
|
* COL40 : FORCE 40COL MODE *
|
|
* COL80 : FORCE 80COL MODE *
|
|
* DIE80 : KILL 80COL FIRMWARE *
|
|
* TCTR : CALCULATE TEXT CENTER *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE DIE80 MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ----------------------------------------- |
|
|
| Name | `DIE80` |
|
|
| Type | Macro |
|
|
| File | `MAC.MISC.STDIO.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | kill 80-column mode, restoring 40 columns |
|
|
| Input | none |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 8+ |
|
|
| Bytes | 5 |
|
|
| Notes | none |
|
|
| See Also | `COL80` `COL40` |
|
|
|
|
*DETAILS*
|
|
|
|
The `DIE80` macro sends a CTRL-U command to COUT, which tells COUT to force an exit from 80-column mode.
|
|
|
|
|
|
|
|
`FIGURE 2.68: DIE80 Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* DIE80 *
|
|
* *
|
|
* SEND CTRL-U TO COUT, FORCING *
|
|
* 40 COLUMN MODE. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* NONE *
|
|
* *
|
|
* CYCLES: 8+ *
|
|
* SIZE: 5 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
DIE80 MAC
|
|
LDA #21 ; {2C2B} CTRL-U CHARACTER
|
|
JSR COUT ; {6+C3B} SEND TO SCREEN
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE COL80 MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ---------------------- |
|
|
| Name | `COL80` |
|
|
| Type | Macro |
|
|
| File | `MAC.MISC.STDIO.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | turn on 80-column mode |
|
|
| Input | none |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 8+ |
|
|
| Bytes | 5 |
|
|
| Notes | none |
|
|
| See Also | `DIE80` `COL40` |
|
|
|
|
*DETAILS*
|
|
|
|
The `COL80` Macro turns on 80-column mode, if it is available, by sending a CTRL-R signal to COUT.
|
|
|
|
|
|
|
|
`FIGURE 2.69: COL80 Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* COL80 *
|
|
* *
|
|
* FORCE 80-COLUMN MODE. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* NONE *
|
|
* *
|
|
* CYCLES: 8+ *
|
|
* SIZE: 5 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
COL80 MAC
|
|
LDA #18 ; {2C2B} CTRL-R CHARACTER
|
|
JSR COUT ; {6+C3B} SEND TO SCREEN
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE COL40 MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ---------------------- |
|
|
| Name | `COL40` |
|
|
| Type | Macro |
|
|
| File | `MAC.MISC.STDIO.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | turn on 40-column mode |
|
|
| Input | none |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 8+ |
|
|
| Bytes | 5 |
|
|
| Notes | none |
|
|
| See Also | `DIE80` `COL80` |
|
|
|
|
*DETAILS*
|
|
|
|
The `COL40` Macro turns on 40-column mode by sending a CTRL-Q character to COUT.
|
|
|
|
|
|
|
|
`FIGURE 2.70: COL40 Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* COL40 *
|
|
* *
|
|
* FORCE 40-COLUMN MODE *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* NONE *
|
|
* *
|
|
* CYCLES: 8+ *
|
|
* SIZE: 5 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
COL40 MAC
|
|
LDA #17 ; {2C2B} CTRL-Q CHARACTER
|
|
JSR COUT ; {6+C3B} SEND TO SCREEN
|
|
<<<
|
|
*
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TCTR MACRO
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `TCTR` |
|
|
| Type | Macro |
|
|
| File | `MAC.MISC.STDIO.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Calculate the point a string fits inside<br /> of another in order to center it |
|
|
| Input | ]1 = short string length<br />]2 = long string length |
|
|
| Output | none |
|
|
| Dependencies | `SUB.TXTCENT.ASM` |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 47+ |
|
|
| Bytes | 27 |
|
|
| Notes | none |
|
|
| See Also | `TXTCENT` |
|
|
|
|
*DETAILS*
|
|
|
|
The `TCTR` macro accepts two string lengths, the first smaller than the second, and then calculates the position the first string needs to be placed within the second string (or line) in order to center it. The numeric result is stored in the RETURN address. This is primarily helpful for centering strings of text on the screen.
|
|
|
|
|
|
|
|
`FIGURE 2.71: TCTR Macro Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TCTR *
|
|
* *
|
|
* THE TCTR MACRO TAKES A LINE *
|
|
* LENGTH AND A SMALLER STRING *
|
|
* LENGTH, THEN CALCULATES THE *
|
|
* STARTING POSITION OF THE *
|
|
* STRING IN THE LINE SO THAT *
|
|
* IT CAN BE CENTERED. *
|
|
* *
|
|
* PARAMETERS *
|
|
* *
|
|
* ]1 = STRING LENGTH *
|
|
* ]2 = LINE LENGTH *
|
|
* *
|
|
* CYCLES: 47+ *
|
|
* SIZE: 27 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
TCTR MAC
|
|
LDA ]1 ; {2C2B} LOAD STRING LENGTH
|
|
STA WPAR1 ; {3C2B} PASS VIA ZERO PAGE
|
|
LDA ]2 ; {2C2B} LOAD LINE LENGTH
|
|
STA WPAR1+1 ; {3C2B} PASS VIA ZERO PAGE
|
|
JSR TXTCENT ; {37C19B} CALL TXTCENT SUBROUTINE
|
|
<<<
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
### THE TXTCENT Subroutine
|
|
|
|
_SUMMARY_
|
|
|
|
| Condition | Value |
|
|
| --------------- | ------------------------------------------------------------ |
|
|
| Name | `TXTCENT` |
|
|
| Type | Subroutine |
|
|
| File | `SUB.TXTCENT.ASM` |
|
|
| Author | Nathan Riggs |
|
|
| Last Revision | 14-MAR-2021 |
|
|
| Assembler | Merlin Pro 8 |
|
|
| OS | Apple DOS 3.3 |
|
|
| Purpose | Calculate a position in a line for a <br />string to be centered |
|
|
| Input | WPAR1 = Short String Length<br />WPAR1+1 = Longer String Length |
|
|
| Output | none |
|
|
| Dependencies | none |
|
|
| Flags Destroyed | NZCV |
|
|
| Cycles | 31+ |
|
|
| Bytes | 16 |
|
|
| Notes | none |
|
|
| See Also | `TCTR` |
|
|
|
|
---
|
|
|
|
*DETAILS*
|
|
|
|
The `TXTCENT` subroutine calculates the center position of a string within a larger string or possible characters. The formula for this is fairly simple, and is easy to implement: (LONG / 2) - (SHORT / 2). The reason a subroutine exists for this is that when such a subroutine is needed--usually to center text on the screen--it will be used repeatedly, meriting a separate subroutine. If a situation arises where centering text needs to be done once alone in a program, then the subroutine should simply be copied in-line to the program rather than have it be called.
|
|
|
|
|
|
|
|
`FIGURE 2.72: TXTCENT Subroutine Source`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* TXTCENT (NATHAN RIGGS) *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* WPAR1 = STRING LENGTH *
|
|
* WPAR1+1 = LINE LENGTH *
|
|
* *
|
|
* DESTROYS: NZCIDV *
|
|
* ^^^ ^ *
|
|
* *
|
|
* CYCLES: 31+ *
|
|
* SIZE: 16 BYTES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
]SLEN EQU WPAR1 ; STRING LENGTH
|
|
]LNLEN EQU WPAR1+1 ; LINE LENGTH
|
|
*
|
|
TXTCENT
|
|
*
|
|
LSR ]SLEN ; {5C2B} DIVIDE STRING LENGTH IN HALF
|
|
LSR ]LNLEN ; {5C2B} DIVIDE LINE LENGTH IN HALF
|
|
LDA ]LNLEN ; {2C2B} GET LINE LENGTH
|
|
SEC ; {2C1B} SET CARRY
|
|
SBC ]SLEN ; {3C2B} SUBTRACT STRING LENGTH/2
|
|
STA RETURN ; {3C2B}
|
|
LDX #1 ; {2C2B} SET RETURN LENGTH BYTE
|
|
STX RETLEN ; {3C2B}
|
|
RTS ; {6C1B}
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
# PART II: STDIO Collection Demo File
|
|
|
|
The following listing shows the usage of each macro in the STDIO Collection, with extensive commentary about how to use the macro. This covers all of the macros in the `MAC.COUT.STDOUT.ASM` file, `MAC.SCRMEM.STDIO.ASM` file, and the `MAC.MISC.STDIO.ASM` file.
|
|
|
|
|
|
|
|
`FIGURE 2.73: DEMO.STDIO.ASM Source Listing`
|
|
|
|
```assembly
|
|
*
|
|
*``````````````````````````````*
|
|
* DEMO.STDIO *
|
|
* *
|
|
* A DEMO OF THE MACROS AND *
|
|
* SUBROUTINES IN THE STDIO *
|
|
* APPLEIIASM LIBRARY. *
|
|
* *
|
|
* AUTHOR: NATHAN RIGGS *
|
|
* CONTACT: NATHAN.RIGGS@ *
|
|
* OUTLOOK.COM *
|
|
* *
|
|
* DATE: 11-MAR-2021 *
|
|
* ASSEMBLER: MERLIN 8 PRO *
|
|
* OS: DOS 3.3 *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** ASSEMBLER DIRECTIVES
|
|
*
|
|
CYC AVE
|
|
EXP OFF
|
|
TR ON
|
|
DSK DEMO.STDIO
|
|
OBJ $BFE0
|
|
ORG $6000
|
|
*
|
|
*``````````````````````````````*
|
|
* TOP INCLUDES (HOOKS,MACROS) *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
PUT MIN.HEAD.REQUIRED.ASM
|
|
USE MIN.MAC.REQUIRED.ASM
|
|
*
|
|
PUT MIN.HEAD.STDIO.ASM
|
|
*
|
|
USE MIN.MAC.COUT.STDOUT.ASM
|
|
USE MIN.MAC.STDIN.ASM
|
|
USE MIN.MAC.SCRMEM.STDIO.ASM
|
|
USE MIN.MAC.MISC.STDIO.ASM
|
|
*
|
|
]HOME2 EQU $FC58
|
|
*
|
|
*``````````````````````````````*
|
|
* PROGRAM MAIN BODY *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
JSR ]HOME2 ; CLEAR SCREEN
|
|
*
|
|
*``````````````````````````````*
|
|
* OUTPUT MACRO EXAMPLES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE STDIO LIBRARY CONTAINS A NUMBER OF
|
|
** MACROS AND SUBROUTINES FOR OUTPUTTING
|
|
** CHARACTERS TO THE 40 COLUMN SCREEN.
|
|
** THESE ARE:
|
|
*
|
|
** - CPUT : PUT CHARACTER INTO SCREEN MEMORY
|
|
** - CURB : MOVE COUT CURSOR BACKWARDS
|
|
** - CURD : MOVE COUT CURSOR DOWN
|
|
** - CURF : MOVE COUT CURSOR FORWARDS
|
|
** - CURU : MOVE COUT CURSOR UP
|
|
** - PRN : PRINT A STRING OR TEXT LITERAL
|
|
** - SCPOS : SET CURSOR POSITION
|
|
** - SETCX : SET CURSOR X POSITION
|
|
** - SETCY : SET CURSOR Y POSITION
|
|
** - SPRN : PRINT A PRECEDING LENGTH BYTE STRING
|
|
** - SPUT : PUT STRING INTO SCREEN MEMORY
|
|
** - TCIRC : PUT TEXT CIRCLE INTO SCREEN MEMORY
|
|
** - TCLR : FILL THE SCREEN MEMORY
|
|
** - TCTR : CALCULATE CENTER POSITION
|
|
** - THLIN : PUT HORIZONTAL TEXT LINE TO SCREEN MEMORY
|
|
** - TMORE : WORD-WRAP AND PAUSE SCROLLING OF NULL-TERM STRING
|
|
** - TREC : PUT UNFILLED RECTANGLE INTO SCREEN MEMORY
|
|
** - TRECF : PUT FILLED RECTANGLE INTO SCREEN MEMORY
|
|
** - TLINE : PLOT DIAGONAL LINE TO SCREEN MEMORY
|
|
** - TVLIN : PLOT VERTICAL LINE TO SCREEN MEMORY
|
|
*
|
|
*``````````````````````````````*
|
|
* CPUT MACRO *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE CPUT MACRO PLACES A CHARACTER PROVIDED
|
|
** IN THE PARAMETERS INTO SCREEN MEMORY,
|
|
** CALCULATING THE MEMORY ADDRESS IN REAL-TIME.
|
|
** THIS IS SIGNIFICANTLY FASTER THAN USING COUT
|
|
** SUBROUTINES, BUT THE OBVIOUS DOWNSIDE IS
|
|
** THAT COUT SUBROUTINES WILL NOT PLAY NICE
|
|
** WITH CPUT.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2 ; FILL SCREEN NOT COVERED YET
|
|
_PRN "CPUT MACRO",8D
|
|
_PRN "==========",8D8D
|
|
CPUT #10;#10;#"C"
|
|
CPUT #11;#11;#"P"
|
|
CPUT #12;#12;#"U"
|
|
CPUT #13;#11;#"T"
|
|
CPUT #16;#10;#"W"
|
|
CPUT #17;#11;#"O"
|
|
CPUT #18;#12;#"O"
|
|
CPUT #19;#11;#"T"
|
|
CPUT #20;#10;#"!"
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* CURB MACRO *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE CURB MACRO MOVES THE COUT CURSOR
|
|
** BACKWARDS BY THE GIVEN NUMBER OF SPACES.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
_PRN "CURB MACRO",8D
|
|
_PRN "==========",8D8D
|
|
_PRN "0123456789"
|
|
_WAIT
|
|
CURB #3
|
|
_PRN "--",8D
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* CURD MACRO *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE CURD MACRO MOVES THE COUT CURSOR
|
|
** DOWNWARDS BY THE GIVEN NUMBER OF SPACES.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
_PRN "CURD MACRO",8D
|
|
_PRN "==========",8D8D
|
|
_PRN "HA"
|
|
CURD #2
|
|
_PRN "HAA"
|
|
CURD #3
|
|
_PRN "HAAAA"
|
|
CURD #4
|
|
_PRN "HAAAAAAAA!"
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* CURF *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE CURF MACRO MOVES THE COUT CURSOR
|
|
** FORWARD BY THE NUMBER OF GIVEN SPACES.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
_PRN "CURF MACRO",8D
|
|
_PRN "==========",8D8D
|
|
_PRN " ",8D8D8D
|
|
_PRN "HEEEEEE"
|
|
CURF #3
|
|
_PRN "HEEEE"
|
|
CURF #2
|
|
_PRN "HEE"
|
|
CURF #1
|
|
_PRN "HE!",8D8D
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* CURU *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE CURU MACRO MOVES THE COUT CURSOR
|
|
** UP THE NUMBER OF GIVEN SPACES.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
_PRN "CURU MACRO",8D
|
|
_PRN "==========",8D8D8D8D8D8D8D8D8D8D8D8D8D8D
|
|
_PRN "HO"
|
|
CURU #2
|
|
_PRN "HO HO"
|
|
CURU #3
|
|
_PRN "HOOO HO HO"
|
|
CURU #4
|
|
_PRN "HOOOOO!"
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* PRN *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE PRN MACRO PRINTS A LITERAL STRING
|
|
** TO THE CURSOR POSITION, OR PRINTS A
|
|
** NULL-TERMINATED STRING AT A GIVEN ADDRESS.
|
|
** NOTE THAT A SEPARATE MACRO, SPRN, IS USED
|
|
** FOR PRINTING PRECEDING LENGTH-BYTE STRINGS.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "PRN MACRO",8D
|
|
PRN #ESGN
|
|
PRN " ",8D8D8D8D8D8D
|
|
PRN #MSG1
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* SCPOS *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE SCPOS MACRO POSITIONS THE COUT CURSOR
|
|
** AT THE GIVEN X,Y COORDINATES.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "SCPOS MACRO",8D
|
|
PRN "==========="
|
|
SCPOS #15;#8
|
|
PRN "NEW CURSOR POSITION"
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* SETCX *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE SETCX MACRO SETS THE X POSITION
|
|
** OF THE CURSOR TO A GIVEN VALUE.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "SETCX MACRO",8D
|
|
PRN "==========="
|
|
PRN " ",8D8D8D8D
|
|
SETCX #10
|
|
PRN "X POSITION HERE!"
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* SETCY *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE SETCY MACRO SETS THE Y-POSITION
|
|
** OF THE CURSOR TO A GIVEN VALUE.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "SETCY MACRO",8D
|
|
PRN "==========="
|
|
SETCY #10
|
|
PRN "10 LINE DOWN FROM TOP!"
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* SPRN *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE SPRN MACRO PRINTS A REGULAR STRING
|
|
** THAT HAS A PRECEDING LENGTH-BYTE TO
|
|
** COUT. NOTE THAT THIS ONLY COVERS STRINGS
|
|
** LESS THAN 256 BYTES LONG.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "SPRN MACRO",8D
|
|
PRN "==========",8D8D8D
|
|
SPRN #STR1
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* SPUT *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE SPUT MACRO DIRECTLY PLOTS A STRING OF
|
|
** CHARACTERS TO THE SCREEN MEMORY. NOTE THAT
|
|
** THERE IS NO ERROR HANDLING, SO CARE MUST BE
|
|
** TAKEN TO NOT EXCEED THE SCREEN BOUNDARIES.
|
|
** THIS DOES NOT INTERACT WITH COUT.
|
|
*
|
|
** USAGE:
|
|
*
|
|
*
|
|
JSR ]HOME2
|
|
PRN "SPUT MACRO",8D
|
|
PRN "==========",8D8D
|
|
SPUT #10;#10;#STR1
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* TCIRC *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE TCIRC MACRO DRAWS A CIRCLE WITH
|
|
** THE FILL CHARACTER SPECIFIED ONTO THE
|
|
** SCREEN MEMORY. THIS MACRO PLOTS DIRECTLY
|
|
** TO MEMORY, AND THEREFORE IS NOT SUBJECT TO
|
|
** THE WHIMS OF COUT.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "TCIRC MACRO",8D
|
|
PRN "===========",8D8D
|
|
TCIRC #19;#10;#9;#"X"
|
|
TCIRC #19;#10;#7;#"+"
|
|
TCIRC #19;#10;#4;#"-"
|
|
TCIRC #19;#10;#2;#"^"
|
|
TCIRC #19;#10;#1;#"."
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* TCLR *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE TCLR MACRO FILLS THE SCREEN MEMORY
|
|
** WITH A GIVEN CHARACTER VALUE. THE DATA
|
|
** STORED IN THE "SCREEN HOLES" IS KEPT
|
|
** INTACT.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "TCLR MACRO",8D
|
|
PRN "==========",8D
|
|
_WAIT
|
|
TCLR #"@"
|
|
_WAIT
|
|
TCLR #"%"
|
|
_WAIT
|
|
TCLR #"$"
|
|
_WAIT
|
|
TCLR #"&"
|
|
_WAIT
|
|
TCLR #"!"
|
|
_WAIT
|
|
TCLR #":"
|
|
_WAIT
|
|
TCLR #"'"
|
|
_WAIT
|
|
TCLR #"`"
|
|
_WAIT
|
|
TCLR #","
|
|
_WAIT
|
|
TCLR #"."
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* TCTR *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE TCTR MACRO CALCULATES THE X POSITION
|
|
** OF A STRING IN RELATION TO THE AVAILABLE
|
|
** LINE LENGTH TO CENTER THE STRING ON THE
|
|
** LINE. THE X POSITION IS PASSED BACK VIA
|
|
** THE [RETURN] LOCATION.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "TCTR MACRO",8D
|
|
PRN "==========",8D8D
|
|
SETCY #12
|
|
TCTR CTRSTR;#40
|
|
SETCX RETURN
|
|
SPRN #CTRSTR
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* THLIN *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE THLIN MACRO DRAWS A HORIZONTAL LINE
|
|
** ON TO SCREEN MEMORY WITH THE GIVEN
|
|
** CHARACTER. THIS DOES NOT INTERACT WITH
|
|
** COUT.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "THLIN MACRO",8D
|
|
PRN "===========",8D8D
|
|
THLIN #5;#35;#6;#"@"
|
|
THLIN #5;#35;#8;#"#"
|
|
THLIN #5;#35;#10;#"$"
|
|
THLIN #5;#35;#12;#"%"
|
|
THLIN #5;#35;#14;#":"
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* TMORE *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE TMORE MACRO SCROLLS A ZERO-TERMINATING STRING
|
|
** ON THE SCREEN, WORD-WRAPPING EACH LINE AS IT GOES.
|
|
** THE FIRST PARAMETER IS THE STRING ADDRESS, OR AN
|
|
** INDIRECT ADDRESS. THE SECOND PARAMETER IS THE
|
|
** DESIRED MAXIMUM LINE LENGTH, AND THE THIRD PARAMETER
|
|
** IS THE NUMBER OF LINES TO PRINT BEFORE PAUSING
|
|
** THE SCROLL UNTIL A KEY IS PRESSED.
|
|
*
|
|
** IF THE THIRD PARAMETER (SCROLL) IS #0, THEN SCROLLING
|
|
** IS PAUSED ANY TIME A RETURN CHARACTER IS FOUND (8D).
|
|
** YOU CAN THEN HAVE IT SCROLL A PARAGRAPH AT A TIME BY
|
|
** HAVING A LINE WITH A SPACE FOLLOWED BY #$8D.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
TMORE #LONGSTR;#39;#15
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* TREC *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE TREC MACRO CREATES A RECTANGULAR
|
|
** BORDER IN SCREEN MEMORY, INDEPENDENT OF
|
|
** THE STATE OF COUT. NOTE THAT THIS DOES
|
|
** NOT FILL IN THE EMPTY SPACE INSIDE OF THE
|
|
** RECTANGULAR BORDER.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "TREC MACRO",8D
|
|
PRN "==========",8D8D
|
|
TREC #5;#6;#35;#17;#"@"
|
|
TREC #7;#8;#33;#15;#"#"
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* TRECF *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE TRECF MACRO WRITES A FILLED
|
|
** RECTANGLE TO THE SCREEN MEMORY SPACE.
|
|
** THIS DOES NOT INTERACT WITH COUT.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "TRECF MACRO",8D
|
|
PRN "===========",8D8D
|
|
TRECF #5;#5;#14;#14;#"+"
|
|
TRECF #16;#5;#25;#14;#":"
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* TLINE *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE TLINE MACRO CREATES A DIAGONAL
|
|
** LINE STARTING AT AN ORIGIN X,Y
|
|
** POSITION TO A DESTINATION X,Y COORDINATE.
|
|
** THIS PRINTS DIRECTLY TO SCREEN MEMORY,
|
|
** AND DOES NOT INTERACT WITH COUT.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "TLINE MACRO",8D
|
|
PRN "===========",8D8D
|
|
TLINE #5;#5;#15;#10;#"@"
|
|
TLINE #5;#10;#15;#5;#"#"
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* TVLIN *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE TVLIN MACRO CREATES A VERTICAL LINE
|
|
** IN SCREEN MEMORY WITH THE GIVEN CHARACTER.
|
|
** THIS DOES NOT INTERACT WITH COUT.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "TVLIN MACRO",8D
|
|
PRN "===========",8D8D
|
|
TVLIN #5;#15;#19;#"#"
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* INPUT MACRO EXAMPLES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE STDIO LIBRARY INCLUDES MACROS
|
|
** AND SUBROUTINES DEDICATED TO RETRIEVING
|
|
** INPUT DATA FROM THE KEYBOARD, FROM
|
|
** THE SCREEN MEMORY, AND FROM THE
|
|
** PADDLE.
|
|
*
|
|
** - GKEY : GET KEY FROM KEYBOARD INPUT
|
|
** - INP : INPUT A STRING FROM KEYBOARD
|
|
** - PBX : INPUT FROM PADDLE BUTTONS
|
|
** - PDL : INPUT FROM PADDLE WHEELS
|
|
** - RCPOS : GET VALUE FROM SCREEN POSITION
|
|
** - WAIT : WAIT FOR A KEYBOARD KEY PRESS
|
|
*
|
|
*``````````````````````````````*
|
|
* GKEY *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE GKEY MACRO WAITS FOR THE USER
|
|
** TO PRESS A KEY ON THE KEYBOARD, THEN
|
|
** RETURNS THE VALUE RECEIVED IN .A.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "GKEY MACRO",8D
|
|
PRN "==========",8D8D
|
|
GKEY
|
|
JSR COUT
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* INP *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE INP MACRO INPUTS A STRING OF
|
|
** TEXT FROM THE USER VIA THE KEYBOARD,
|
|
** ENDING WHEN THE RETURN KEY IS PRESSED. THE
|
|
** STRING IS THEN STORED IN [RETURN], WITH
|
|
** ITS LENGTH IN THE PRECEDING BYTE KNOWN
|
|
** AS [RETLEN].
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "INP MACRO",8D
|
|
PRN "=========",8D8D8D
|
|
INP
|
|
PRN " ",8D8D8D
|
|
SPRN #RETLEN
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* PBX *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE PBX MACRO READS THE STATE OF
|
|
** THE SPECIFIED PADDLE BUTTON. FOR THE
|
|
** SAKE OF EASE, THE BUTTONS HAVE BEEN
|
|
** GIVEN ALIASES OF PB0 - PB1, WITH THE
|
|
** CORRESPONDING VALUES:
|
|
*
|
|
** - PB0 = $C061
|
|
** - PB1 = $CO62
|
|
** - PB2 = $CO63
|
|
** - PB3 = $CO60
|
|
*
|
|
** NOTE THAT THE OPEN AND CLOSED APPLE KEYS
|
|
** CAN BE READ AS PADDLE BUTTONS, SO A PADDLE
|
|
** IS NOT NECESSARY FOR THE FOLLOWING EXAMPLE.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "PBX MACRO",8D
|
|
PRN "=========",8D8D
|
|
LDX #1
|
|
:MLP1
|
|
PBX PB0
|
|
CPX #1
|
|
BNE :MLP1
|
|
PRN "PB0 PRESSED!",8D8D
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* PDL *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE PDL MACRO READS THE PADDLE WHEEL
|
|
** AND RETURNS THE VALUE READ FROM IT
|
|
** IN .Y. SINCE WE WON'T ASSUME THE USER
|
|
** HAS A PADDLE HERE, A WORKING EXAMPLE
|
|
** WILL NOT BE GIVEN. HOWEVER, THE MACRO
|
|
** ACCEPTS A SINGLE PARAMETER THAT DENOTES
|
|
** THE PADDLE NUMBER TO READ, AS SUCH:
|
|
*
|
|
** PDL #0
|
|
*
|
|
*``````````````````````````````*
|
|
* RCPOS *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE RCPOS MACRO READS A GIVEN ROW
|
|
** AND COLUMN OF THE SCREEN AND RETURNS
|
|
** THE CHARACTER VALUE IN .A.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "RCPOS MACRO",8D
|
|
PRN "===========",8D8D
|
|
RCPOS #0;#0
|
|
JSR COUT
|
|
_WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* WAIT *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE WAIT MACRO IS FUNCTIONALLY
|
|
** EQUIVALENT TO THE GKEY MACRO, BUT
|
|
** DOES NOT RELY ON THE GETKEY SUBROUTINE.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
PRN "WAIT MACRO",8D
|
|
PRN "==========",8D8D
|
|
WAIT
|
|
JSR COUT
|
|
WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* OTHER STDIO MACROS *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE STDIO LIBRARY CONTAINS A FEW
|
|
** MACROS THAT CANNOT BE EASILY CATEGORIZED
|
|
** TOGETHER, AND THUS ARE THROWN INTO A
|
|
** MISCELLANEOUS SECTION HERE. THE MACROS
|
|
** ARE:
|
|
*
|
|
** - COL40 : SET SCREEN TO 40-COLUMN MODE
|
|
** - COL80 : SET SCREEN TO 80-COLUMN MODE
|
|
** - DIE80 : KILL 80-COLUMN MODE, FORCING 40
|
|
*
|
|
*``````````````````````````````*
|
|
* COL40 *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE COL40 MACRO TURNS ON 40-COLUMN
|
|
** MODE. OBVIOUSLY, THIS ONLY HAS A
|
|
** NOTICEABLE EFFECT IF THE USER IS
|
|
** ALREADY IN 80-COLUMN MODE.
|
|
*
|
|
** USAGE:
|
|
*
|
|
COL40
|
|
*
|
|
*``````````````````````````````*
|
|
* COL80 *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE COL80 MACRO TURNS ON 80-COLUMN
|
|
** MODE.
|
|
*
|
|
JSR ]HOME2
|
|
COL80
|
|
PRN "80 COLUMNS!"
|
|
WAIT
|
|
*
|
|
*``````````````````````````````*
|
|
* DIE80 *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
** THE DIE80 MACRO KILLS 80-COLUMN
|
|
** MODE, RETURNING TO 40-COLUMN MODE
|
|
** BY DEFAULT.
|
|
*
|
|
** USAGE:
|
|
*
|
|
JSR ]HOME2
|
|
DIE80
|
|
PRN "BACK TO 40 COLUMNS!"
|
|
*
|
|
JMP REENTRY
|
|
*
|
|
*``````````````````````````````*
|
|
* BOTTOM INCLUDES *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
PUT MIN.LIB.REQUIRED.ASM
|
|
*
|
|
** INDIVIDUAL SUBROUTINE INCLUDES
|
|
*
|
|
* STDIO SUBROUTINES
|
|
*
|
|
PUT MIN.SUB.XPRINT.ASM
|
|
PUT MIN.SUB.DPRINT.ASM
|
|
PUT MIN.SUB.THLINE.ASM
|
|
PUT MIN.SUB.TVLINE.ASM
|
|
PUT MIN.SUB.TRECTF.ASM
|
|
PUT MIN.SUB.TXTPUT.ASM
|
|
PUT MIN.SUB.TBLINE.ASM
|
|
PUT MIN.SUB.TCIRCLE.ASM
|
|
PUT MIN.SUB.PRNSTR.ASM
|
|
PUT MIN.SUB.TXTMORE.ASM
|
|
PUT MIN.SUB.TXTCENT.ASM
|
|
PUT MIN.SUB.STRPUT.ASM
|
|
PUT MIN.SUB.TRECT.ASM
|
|
PUT MIN.SUB.TXTCLR.ASM
|
|
PUT MIN.SUB.SINPUT.ASM
|
|
*
|
|
ESGN ASC "========="
|
|
HEX 00
|
|
MSG1 ASC "THIS IS A MESSAGE."
|
|
HEX 00
|
|
STR1 STR "THIS IS A STRING."
|
|
CTRSTR STR "CENTERED STRING."
|
|
LONGSTR ASC "ONE TWO THREE FOUR FIVE SIX SEVEN "
|
|
ASC "EIGHT NINE TEN ELEVEN TWELVE THIRTEEN "
|
|
ASC "FOURTEEN FIFTEEN SIXTEEN SEVENTEEN "
|
|
HEX 8D
|
|
ASC "EIGHTEEN NINETEEN TWENTY TWENTY-ONE "
|
|
ASC "TWENTY-TWO TWENTY-THREE TWENTY-FOUR "
|
|
ASC "25 26 27 28 29 30 31 32 33 34 35 36 37 "
|
|
ASC "38 39 40"
|
|
HEX 00
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
[Return to Table of Contents](./0.0%20Title_to_TOC)
|
|
[Next -- Disk 3: Array Macros and Subroutines](32.0%20Detailed_Reference_D3_Arrays.md)
|
|
|
|
|
|
|