Volume 2 -- Issue 7 | April 1982

In This Issue...

- Adding Auto-SAVE to S-C Macro Assembler
- Review of AED ][ (A new Applesoft Editor)
- Ashby's Easy Shift-Key Modifier
- Potential Trouble in TYMAC
- Using Macros and Nested Macros
- Recursive Macros
- Controlling Software Configuration
- Funny Noise

Another New Book: Bag of Tricks

The authors of Beneath Apple DOS (Don Worth and Pieter Lechner) have done it again! This time you get a diskette with four powerful disk utilities on it, and a book expaining their use. The retail price is $39.95, but I will have them for only $36.

The utilities are TRAX, INIT, ZAP, and FIXCAT. TRAX examines any track on a disk, reading it in as pure nibbles and displaying in a partially analyzed form. INIT reformats any track or tracks, optionally retaining existing data in whatever readable sectors are in the track. You can reorder the sectors, change the volume number, and more. ZAP is a general purpose disk utility: sectors may be read, written, displayed, modified with a powerful assortment of over 50 commands. It works with 13- and 16-sector DOS, as well as Pascal and CP/M diskettes. You can even "program" in ZAP, with labels, loops, and macro-commands. FIXCAT can automatically repair or reconstruct a catalog track by analyzing the rest of the disk.

Beyond the utilities themselves, there is about 40 pages of advanced tutorial material which starts where "Beneath Apple DOS" ends.

Unless you are fully satisfied with your present collection of disk utilities, you ought to get this set.

Adding Auto-SAVE to S-C Macro Assembler | Greg H. Anders

[ Greg is a subscriber from Albuquerque, New Mexico. ]

One of the nice features of the new S-C Macro Assembler is the title directive (.TI). This directive causes a title and page number to be printed at the top of each page of an assembly listing. The title directive gave me the idea for the Automatic Save command program which follows.

I felt the need for an Auto Save command because of my own carelessness. After extensive editing of a rather lengthy program, I decided it was a good time to save the program before I proceeded. The file names I use are usually descriptive and forgettable, so to save a file, I list the Catalog, then use the cursor controls to copy the file name. After the file name appeared on the screen, I zipped the cursor next to the name I wanted to save the file under and, succumbing to temporary insanity, typed an "L". The word "LOAD" flashed on the screen and my mouth dropped open in disbelief. The only sounds that could be heard were the whirr of the disk drive and the screams of my new code byting the dust cover!

I decided to try to simplify the task of saving a program, giving myself less chance of making an error. From this came the Auto Save command. With this command, typing SAVE does not save your program on cassette. Instead, the SAVE command searches your source program for a title. If a title is found and it is a valid DOS name, the source program is automatically saved, using the title as the file name. In addition, if you end your title with a version number in the form N.N, Auto Save automatically increments the version number in the source program and saves the program using the new version number. The version number option does not erase your old file, which means your old file is a back-up. Be careful, though. A few saves and your disk is full of back-up files. You'll need to go back and delete a file or two every once in a while.

The version number goes up to a maximum of 9.9, after which it starts back at 0.0. If the version number option is not desired, don't put a number in the form N.N at the end of your title.

Leading and trailing blanks are ignored by Auto Save. If there is more than one consecutive blank in a title, the blanks are compressed to one. Thus, the title ".TI 56,TI TLE" generates a SAVE to the file named "TI TLE". Also, any commas in your title are changed to dashes so as not to confuse DOS.

To use the Auto Save command, the vector address of the SAVE command must be changed. The address must be one less than the actual start of the Auto Save command. For example, if Auto Save is assembled at $800, the address would be changed in the table inside the S-C Macro Assembler to $07FF.

For the version of the S-C Macro Assembler which loads at $1000, change the contents of address $1679 to $07 and $1678 to $FF. Shown as a monitor command, this would be:

         :$1678:FF 07

For the Language Card version of the S-C Macro Assembler, change the content of address $D679 to $07 and $D678 to $FF. You have to write-enable the card first:

         :$C083 C083 D678:FF 07

I like to keep Auto Save behind the Language Card version of the Macro Assembler. I put the program at $F320 and the changes are:

         :$C083 C083 D678:1F F3

One thing you'll have to look out for. If you type an illegal DOS SAVE command such as "SAVE 1 4 THE ROAD", DOS ignores this command and the Auto Save goes into effect; the "1 4 THE ROAD" is ignored. Also note that the save is performed on the drive that is active. Since commas are changed to dashes, there is currently no way to specify which drive you want the save to be performed on. Perhaps you would like to try to implement this enhancement yourself.

After you've installed the Auto Save program, type in this program:

         1000 *    A TEST OF AUTO SAVE
         1010      .TI 54, TITLE TEST VER. 0.9

Then type SAVE, and CATALOG. See how the file was saved? List the file and notice the change in line 1010. Voila!

For those of you who haven't updated to the Macro Assembler yet, Auto Save can be implemented with S-C Version 4.0 by using the .US command for the title. The changes which are necessary are outlined below.

         1.  The following lines must be deleted: 1490-1540,
             2090-2150, 2460-2470, 2560-2930.

         2.  The following lines must be added:

         1210        .US S-C VER. 4.0 AUTO SAVE 1.0
         1600        BNE .2       ...ALWAYS
         1920 *   CHECK THE OP CODE FOR .US
         2170        BCS TITLE
         2480 .1     CMP #$80
         3480 OPS    .AS /.US/
         3510 NO.TTL .AS /*** NO TITLE ERRO/
         3515        .AS  -/R/
         3520        .AS /*** ILLEGAL TITLE FIRST CHARACTE/
         3525        .AS  -/R/

         3.  Change the SAVE vector address.  For an origin of $800,
             that would be

              :$1271:FF 07

         4.  To use the command, put the title you want to use for
             the file name like so:

              .US MY TITLE VER. 1.0

     1000  *--------------------------------
     1010  *      AUTOMATIC SAVE PROGRAM
     1020  *      THIS PROGRAM CHECK'S FOR A TITLE
     1030  *      AND IF ONE IS FOUND, THE CURRENT PROGRAM
     1040  *      IS SAVED UNDER THE TITLE
     1050  *      ALSO, IF THE VERSION NUMBER IS APPENDED
     1060  *      IT IS UPDATED BEFORE EACH SAVE
     1070  *--------------------------------
     1080  *      SYSTEM EQUATES
     1090  *--------------------------------
     1100  MON.COUT   .EQ $FDED
     1110  MON.CROUT  .EQ $FD8E
     1120  MON.BELL1  .EQ $FBDD
     1130  IN.BUF     .EQ $200
     1140  SRC.END    .EQ $4C,4D
     1150  SRC.START  .EQ $CA,CB
     1160  NEXT       .EQ $1D
     1170  SEARCH     .EQ $1E,1F
     1180  *--------------------------------
     1190         .OR $800
     1200         .TF AUTO.SAVE.OBJECT A$800
     1210  *--------------------------------
     1220  *      INITIALIZE SEARCH REGISTERS AND
     1230  *      DETERMINE IF AT END OF SOURCE PROGRAM
     1240  *--------------------------------
     1250  AUTO.SAVE
     1260         LDA SRC.START     GET START OF SOURCE PROGRAM ADDRESS
     1270         STA SEARCH        AND MOVE TO THE SEARCH ADDRESS REGISTER
     1280         LDA SRC.START+1
     1290         STA SEARCH+1
     1300         CLD
     1310  ADDRESS.END.CMP
     1320         LDA SEARCH
     1330         CMP SRC.END       SEE IF AT END OF SOURCE PROGRAM
     1340         BNE .1
     1350         LDA SEARCH+1
     1360         CMP SRC.END+1
     1370         BEQ ERROR1        DIDN'T FIND TITLE
     1380  *--------------------------------
     1390  *      SEARCH LINE FOR OP CODE
     1400  *--------------------------------
     1410  .1     LDY #0       Y OFFSET FOR LINE EXAMINATION
     1420         LDA (SEARCH),Y    NEXT LINE OFFSET
     1430         STA NEXT
     1440         LDY #3       POINT TO CHARACTER AFTER LINE NUMBER
     1450         LDA (SEARCH),Y
     1460         CMP #'*      COMMENT LINE?
     1470         BEQ NEW.LINE      YEP
     1480  .5     CMP #$C0     COMPRESSED CODE?
     1490         BNE .2       NOPE
     1500  .4     INY          MOVE OFFSET PAST COMPRESSED INFO
     1510         INY
     1520         CLV
     1530         BVC .3       ...ALWAYS
     1540  .2     CMP #$80     SPACE(S)?
     1550         BCS OPCHK    YES, CHECK THE OP-CODE
     1560  .3     INY
     1570         LDA (SEARCH),Y
     1580         BEQ NEW.LINE      END OF LINE (EOL) IS 0
     1590         BNE .5       ...ALWAYS
     1600  *--------------------------------
     1610  *      CALCULATE ADDRESS OF NEXT LINE
     1620  *--------------------------------
     1630  NEW.LINE
     1640         CLC
     1650         LDA SEARCH   MOVE SEARCH ADDRESS TO NEXT LINE
     1660         ADC NEXT
     1670         STA SEARCH
     1680         BCC ADDRESS.END.CMP
     1690         INC SEARCH+1
     1700         BNE ADDRESS.END.CMP   ...ALWAYS
     1710  *--------------------------------
     1720  *      ERROR ROUTINES
     1730  *--------------------------------
     1740  ERROR1
     1750         LDY #0       POINT TO NO TITLE ERROR
     1760  PRTERR LDA NO.TTL,Y
     1770         BMI ERREND
     1780         ORA #$80
     1790         JSR MON.COUT
     1800         INY
     1810         BNE PRTERR
     1820  ERREND JSR MON.COUT
     1830         JSR MON.BELL1
     1840         JSR MON.BELL1
     1850         JSR MON.CROUT
     1860         RTS
     1870  ERROR2
     1880         LDY #18      POINT TO ILLEGAL CHAR. ERROR
     1890         BNE PRTERR   ...ALWAYS
     1900  *--------------------------------
     1910  *      CHECK THE OP CODE FOR .TI
     1920  *--------------------------------
     1930  OPCHK  LDX #0
     1940  .1     INY
     1950         LDA (SEARCH),Y
     1960         BEQ NEW.LINE      EOL
     1970         CMP OPS,X    COMPARE OP CODE
     1980         BNE NEW.LINE THAT'S NOT IT
     1990         INX
     2000         CPX #3       IF ALL 3 COMPARE, FOUND OP CODE
     2010         BNE .1
     2020  *--------------------------------
     2030  *      NOW LOOK FOR TITLE
     2040  *--------------------------------
     2050  TITLE  INY
     2060         LDA (SEARCH),Y
     2070         BEQ ERROR1   NO TITLE?
     2080         CMP #',      LOOKING FOR COMMA (TITLE FOLLOWS)
     2090         BNE TITLE
     2100  .1     INY
     2110         LDA (SEARCH),Y
     2120         BEQ ERROR1   NO TITLE?
     2130         CMP #$C0     COMPRESSED?
     2140         BEQ COMP.CODE1
     2150         CMP #$80     SPACE?
     2160         BCS .1       YEP--SKIP
     2170         CMP #'A      MAKE SURE 1ST CHAR. IS LETTER
     2180         BCC ERROR2   NOT LETTER
     2190         CMP #$5B     1 MORE THAN "Z"
     2200         BCS ERROR2
     2210  *--------------------------------
     2220  *      TITLE FOUND
     2230  *      OUTPUT CTRL-D, "SAVE" AND TITLE
     2240  *--------------------------------
     2250         PHA
     2260         LDX #0
     2270  .2     LDA SAVE,X
     2280         JSR MON.COUT
     2290         INX
     2300         CPX #5
     2310         BNE .2
     2320         PLA
     2330  NEXT.CHAR1
     2340         ORA #$80
     2350         JSR MON.COUT
     2360         INX          X KEEPS TRACK OF INPUT BUFFER OFFSET
     2370  NEXT.CHAR2
     2380         INY
     2390         LDA (SEARCH),Y
     2400         BEQ GOT.TTL2 EOL--GOT THE TITLE
     2410         CMP #',      NO COMMAS ALLOWED
     2420         BNE .1
     2430         LDA #'-      REPLACE COMMA WITH DASH
     2440         BNE NEXT.CHAR1    ...ALWAYS
     2450  .1     CMP #$C0
     2460         BEQ COMP.CODE2
     2470         CMP #$80
     2480         BCC NEXT.CHAR1
     2490         INY          CHECK FOR CHARACTER AFTER SPACE
     2500         LDA (SEARCH),Y
     2510         BEQ GOT.TTL1 DROP TRAILING SPACES
     2520         DEY          MOVE POINTER BACK TO CORRECT POSITION
     2530         LDA #$20     SPACE--SPACES IN TITLE COMPRESSED TO 1
     2540         BNE NEXT.CHAR1    ...ALWAYS
     2550  *--------------------------------
     2560  *      COMPRESSED CHARACTER ROUTINES
     2570  *--------------------------------
     2580  COMP.CODE1
     2590         INY
     2600         LDA (SEARCH),Y    THIS IS NUMBER OF CHARACTERS COMPRESSED
     2610         STA NEXT
     2620         INY
     2630         LDA (SEARCH),Y    ACTUAL CHARACTER
     2640         CMP #'A      MAKE SURE IT'S A LETTER
     2650         BCC ERROR2
     2660         CMP #$5B
     2670         BCS ERROR2
     2680         PHA
     2690         LDX #0
     2700  .1     LDA SAVE,X
     2710         JSR MON.COUT
     2720         INX
     2730         CPX #5
     2740         BNE .1
     2750         PLA
     2760         BNE STORE    ...ALWAYS
     2770  COMP.CODE2
     2780         INY
     2790         LDA (SEARCH),Y
     2800         STA NEXT
     2810         INY
     2820         LDA (SEARCH),Y
     2830         CMP #',
     2840         BNE STORE
     2850         LDA #'-
     2860  STORE
     2870         ORA #$80
     2880         JSR MON.COUT
     2890         INX
     2900         DEC NEXT
     2910         BNE STORE
     2920         BEQ NEXT.CHAR2
     2930  *--------------------------------
     2940  *      SEARCH FOR VERSION NUMBER AND CHANGE IF FOUND
     2950  *--------------------------------
     2960  GOT.TTL1
     2970         DEY
     2980  GOT.TTL2
     2990         DEY          MOVE Y POINTER TO THIRD NON-BLANK
     3000         DEY          CHARACTER FROM THE END OF LINE
     3010         DEY
     3020         DEX
     3030         LDA (SEARCH),Y    THIRD CHAR. FROM END
     3040         CMP #'0
     3050         BCC DOS.OP
     3060         CMP #':      ASCII ":" IS 1 MORE THAN ASCII 9
     3070         BCS DOS.OP
     3080         INY
     3090         LDA (SEARCH),Y    2ND CHAR. FROM END
     3100         CMP #'.      SHOULD BE PERIOD
     3110         BNE DOS.OP
     3120         INY
     3130         LDA (SEARCH),Y    LAST CHARACTER
     3140         CMP #'0
     3150         BCC DOS.OP
     3160         CMP #':
     3170         BCS DOS.OP
     3180         ADC #1
     3190         CMP #':
     3200         BNE STORIT
     3210         LDA #'0
     3220         STA (SEARCH),Y    CHANGE DIGIT IN SOURCE CODE
     3230         ORA #$80
     3240         STA IN.BUF,X      CHANGE DIGIT IN DOS COMMAND
     3250         DEX
     3260         DEX
     3270         DEY
     3280         DEY
     3290         LDA (SEARCH),Y
     3300         CLC
     3310         ADC #1
     3320         CMP #':
     3330         BNE STORIT
     3340         LDA #'0
     3350  STORIT STA (SEARCH),Y
     3360         ORA #$80
     3370         STA IN.BUF,X
     3380  *--------------------------------
     3390  *      CR OUTPUT CAUSES DOS TO PERFORM SAVE
     3400  *      AFTERWARDS, RETURN TO ASSEMBLER
     3410  *--------------------------------
     3420  DOS.OP JSR MON.CROUT
     3430  END    RTS
     3440  *--------------------------------
     3450  *      MESSAGES
     3460  *--------------------------------
     3470  OPS    .AS /.TI/
     3480  SAVE   .HS 84       CTRL-D
     3490         .AS -/SAVE/
     3500  NO.TTL .AT /*** NO TITLE ERROR/
     3510         .AT /*** ILLEGAL TITLE FIRST CHARACTER/
     3520  ZZZEND .EQ *
     3530  ZZZLEN .EQ ZZZEND-AUTO.SAVE

AED -- A New Applesoft Program Editor | Reviewed by Bob Sander-Cederlof

One of the joys of putting the Apple Assembly Line out each month has been the knowledge that a lot of readers are putting making good use out of what I print. A case in point: William Linn, of Lithonia, Georgia, was inspired by a combination of several articles to produce a new software product we all can use!

He calls it AED, which stands for Applesoft EDitor. AED combines in one easy-to-use package:

Line Editing as in PLE and the S-C Macro Assembler Automatic Line Numbering Global Search and Replace (with wildcard matching) Controlled LISTing (Page- or Line-at-a-time, and Slow Scroll) Display of Variables after execution Quick entry of DOS commands from a mini-menu And a lot more.

I said it is easy to use. Why? Here are a few reasons:

The screen is split, with the line being entered at the bottom 6 lines and two possiblities for the top 18 lines. The top 18 lines are used for listing or for display of the most frequently used commands and edit controls.

The commands and edit controls are single letters or control-letters, with mnemonic value.

An inverse letter appears before the prompt character indicating which of six special modes you are in, so you don't get lost.

Clicks and tones provide pleasant feedback at appropriate times.

One very unusual feature, which I have grown to love in a very short time, is a new kind of cursor. Rather than the flashing cursor of the standard Apple input routines, AED alternates the underline character with the character already on the screen. This alternation is done at the same rate as the Apple's flashing mode, but doesn't tire the eyes.

AED loads into memory from $8500 through $95FF, and uses a 256-byte buffer from $8400 to $84FF. HIMEM is set to $83FF.

AED is normally in charge of all input, until the Control-Q command (QUIT) is typed. If you type a letter A, C, E, F, L, M, R, S, or V the rest of the AED command starting with that letter will be displayed. If the command requires no additional information, it is immediately executed. Otherwise, it waits for you to finish the command and type a carriage return. The period is also a command: call it "dot", and think of "DOS", because its purpose is to call up the DOS Command Mini-Menu. If you type a line beginning with a non-command character, it is passed on to Applesoft. Thus you can enter numbered lines, or type immediate mode commands such as NEW or PRINT X(3) or PR#1.If you do leave AED control, typing "&" will enter AED again. If you have the Autostart Monitor, hitting RESET will re-enter AED.

It is important to realize that you are always in an editing mode. Even commands can be edited using the edit control keys.

Here is a list of the commands:

Letter Commands

         A AUTO line #,increment
         C CHANGE /string1/string2/A
         E EDIT line #
         F FILE = filename to use in DOS commands
         L LIST [ line #,line # ]
         M MANUAL line numbering
         R Repeat last LIST command
         S SEARCH /string/
         V Variable display
         . DOS Mini-Menu

Control Commands

         ^A  Assistance
         ^C  Clear Scroll Area
         ^Q  Quit
         ^X  Clear Edit Area
         ESC Edit Next Line

Editing Commands

         ^B   Cursor to beginning
         ^D   Delete a character
         ^E   Cursor to end of line
         ^Fx  Cursor to next "x"
         ^I   Begin Insert mode
         ^M   (RETURN) Submit line
         ^N   Cursor to end of line
         ^R   Recall last line edited
         ^Tx  Delete through next "x"
         ^T^T Delete to end of line
         ^V   Next character verbatim
         ^W   Enter word cursor mode

AED does not have user-defined keyboard macros. The keyboard macros in PLE are a big selling point; however, the ones you actually end up using in PLE are built-in to AED as actual commands or as part of the DOS Mini-Menu. Of course, PLE words with both Integer BASIC and Applesoft; AED is only for Applesoft.

If you use Applesoft, are not already firmly addicted to PLE, and if you do not use Integer BASIC, then you should consider picking up a copy of AED. It is only $40 (same price as PLE), and packs a lot of usefulness for the dollars.

Ashby's Easy Shift-Key Modifier | Bob Sander-Cederlof

How many times have you read or heard about a way to modify your Apple so that the shift-key would function like a normal typewriter? It is a relatively safe and easy thing to do, but the directions can really be frightening.

Words like "solder", "wire", "take the bottom off your Apple", and so on.

If you have an Apple with the piggy-back board hanging down under your keyboard (Revision 7 or newer), take heart! There is a little device you can pick up for only $15 postpaid, called Ashby's Shift-Key Modifier, which hooks up the modification without any tools or trouble. And it only takes a minute or so! (In fact, only a few seconds if you have done it a few times like I have.)

The Modifier consists of a piece of wire fitted with a plug for the game connector on one end, and with a clip on the other end. The plug is devised so that you still have an empty game socket on top, for attaching paddles or whatever.

To install the Modifier, all you have to do is insert the plug into the game socket, and clip the other end onto the connector from the keyboard to the piggy-back board at the second wire from the right (the RESET key side).

I have installed them on all my Apples, except for my oldest one. (That one is serial #219, bought in August of 1977, and is so old it doesn't even have ventilation slots on the case! Yes, I installed the open-case-and-solder-a-wire modification in the old one.)

Now I can use the shift-key the way I was taught in typing class when I am using Data Capture 4.0, SuperText II, Apple Pie 2.0, the S-C Macro Assembler, or the Word Handler. And more and more programs are being created to take advantage of a REAL shift key on an Apple.

The normal retail price of the Ashby Shift-Key Modifier is $18. I have bought a bunch of them, and you can have them for only $15 each. They come complete with directions for installation.

Potential Trouble in TYMAC | Robert H. Bernard

[ Bob is a subscriber in Westport, Connecticut. ]

The article by Peter Bartlett on improving the Epson Controller Card (which appeared in the February 1982 issue of AAL) has prompted me to write to bring to the attention of fellow AAL readers that the TYMAC controller card, which is a lower-cost alternative to the official Epson card, has a potentially serious problem.

To achieve slot independence, controller card ROM programs JSR to an RTS instruction in the Monitor. Then they extract the slot from the return address the JSR put on the stack. The Apple II Reference Manual details the process on page 81-82.

Most controller cards use the Apple technique verbatim, JSR'ing to $FF58, which is an RTS instruction in the Monitor ROM. However, the TYMAC card JSR's to $FDFF. That location also contains an RTS, so there is no problem using the TYMAC card as long as the Monitor ROM is enabled.

The problem occurs when the TYMAC card is used with Pascal. While Apple Computer has specifically guaranteed an RTS instruction at $FF58 in the Pascal Basic Input/Output System (BIOS), no RTS exists at $FDFF. Therefore TYMAC loses control and causes a Pascal crash as soon as it is called.

If any of you have TYMAC cards, and plan to make the Peter Bartlett modification (or perhaps even if you don't plan to), you should also change the JSR instruction at $0A relative to the beginning of the ROM from 20FFFD to 2058FF.

Using Macros and Nested Macros | Art Schumer

[ Art is a subscriber in Manvel, North Dakota; he is the programming side of S&H Software. Art wrote the Universal Boot Initializer, The DOS Enhancer, and the AmperCat Utility. ]

The new S-C Macro Assembler is truly the best assembler around. With the addition of Macros, easier programming is limited only by your imagination. All you have to do is dream up some uses for Macros. Are Macros and Nested Macros really worth using? You bet! One of my source files was 104 sectors long, but after going back through it and implementing macros, the file shortened to only 96 sectors; it was also easier to read.

As Bob pointed out in the manual, nested macros are allowed in this new version, but he frowned on their use. I beg to differ with him, as I believe that nested macros can make your source files easier to read, as well as easier to write. They may seem complex at first, but after setting them up they become very easy to use.

In my example program, I've defined a macro called GOTO.XY that will take two variables and use them to position the cursor. Another defined macro called CLEAR.XY is a singly nested macro that uses GOTO.XY to position the cursor, and then clears from there to the end of screen. CLEAR.PRINT.XY positions the cursor (using GOTO.XY inside CLEAR.PRINT.XY), clears the rest of the screen, and prints a message. It may sound confusing, but after examining the source listing and th macro definitions, it should be easy to understand how this all works.

In all the macros, the first variable is the horizontal cursor position and the second variable is the vertical cursor position. CLEAR.PRINT.XY calls on a subroutine (JSR PRNT), which expects the message to follow the JSR instruction. The message is terminated by a 00 byte, and execution proceeds at the instruction which follows the message in memory.

The PRNT subroutine came from a Call A.P.P.L.E. article by Andy Hertzfeld.

Have fun with your new S-C Macro Assembler!

     1000  *--------------------------------
     1010  * USE OF MACROS & NESTED MACROS
     1020  * BY ART SCHUMER - 3/25/82
     1030  *--------------------------------
     1040  VTAB   .EQ $FB5B
     1050  CLREOP .EQ $FC42
     1060  HOME   .EQ $FC58
     1070  RDKEY  .EQ $FD0C
     1080  COUT   .EQ $FDED
     1090  *--------------------------------
     1100  PTR    .EQ $6
     1110  CH     .EQ $24
     1120  CV     .EQ $25
     1130  *--------------------------------
     1140  *      MACRO DEFINITIONS
     1150  *
     1160  * CLR.PRNT.XY AND GOTO.PRNT.XY
     1170  * ARE EXAMPLES OF NESTED MACROS
     1180  *--------------------------------
     1190         .MA GOTO.XY
     1200         LDA #]1
     1210         STA CH
     1220         LDA #]2
     1230         JSR VTAB
     1240         .EM
     1250  *--------------------------------
     1260         .MA CLEAR.XY
     1270         >GOTO.XY ]1,]2
     1280         JSR CLREOP
     1290         .EM
     1300  *--------------------------------
     1310         .MA CLEAR.PRNT.XY
     1320         >CLEAR.XY ]1,]2
     1330         JSR PRNT
     1340         .EM
     1350  *--------------------------------
     1360         .MA GOTO.PRNT.XY
     1370         >GOTO.XY ]1,]2
     1380         JSR PRNT
     1390         .EM
     1400  *--------------------------------
     1410         .MA READ.XY
     1420         >GOTO.XY ]1,]2
     1430         JSR RDKEY
     1440         .EM
     1450  *--------------------------------
     1460  *      THE PROGRAM . . . .
     1470  *--------------------------------
     1480  START  JSR HOME
     1490         >GOTO.PRNT.XY 4,12
     1500         .AS -/THIS EXAMPLE USES NESTED MACROS/
     1510         .HS 00
     1520         >READ.XY 36,12
     1530         >CLEAR.PRNT.XY 4,12
     1540         .AS -/AND THIS ONE ALSO!/
     1550         .HS 00
     1560         >READ.XY 22,12
     1570         RTS
     1580  *--------------------------------
     1590  * ANDY HERTZFELD'S PRINT ROUTINE
     1600  *--------------------------------
     1610  PRNT   PLA
     1620         STA PTR
     1630         PLA
     1640         STA PTR+1
     1650         LDY #0
     1660  .1     INC PTR
     1670         BNE .2
     1680         INC PTR+1
     1690  .2     LDA (PTR),Y
     1700         BEQ .3
     1710         JSR COUT
     1720         JMP .1
     1730  .3     LDA PTR+1
     1740         PHA
     1750         LDA PTR
     1760         PHA
     1770         RTS
     1780  *--------------------------------

Recursive Macro Example | Lee Meador

[ Lee is a subscriber from Arlington, Texas. He wrote the original code for the .TF directive and REPLACE command in the S-C Assemblers. ]

Here is short example of a useful macro that uses a recursive definition. By recursive I mean that the definition calls itself.

Most large computers have a shift instruction which can shift any number of bits; the 6502 shifts only shift one bit at a time. The LSR macro shown here accepts a shift count as the first parameter, and generates one LSR opcode for each bit shift you want.

The second parameter is optional. If there is no second parameter, the A-register will be shifted. If you specify a variable for the second parameter, that memory location will be shifted. Both cases are shown in the example below.

How does it work? The definiton says to test the first parameter; if it is greater than zero, generate the LSR with the optional second parameter as the address field, and call on the LSR macro with the first parameter decremented by one. If the first parameter is zero (and it eventually will be), no code is generated. Read the listing carefully, noting the indentation, and you should be able to follow it.

                      1000         .MA LSR			Define LSR macro
                      1010         .DO ]1>0
                      1020         LSR ]2
                      1030         >LSR ]1-1,]2
                      1040         .FIN
                      1050         .EM
                      1060  *--------------------------------
        0800-         1070         >LSR 3,$12    Shift $12 left 3 times
                      0000>        .DO 3>0
        0800- 46 12   0000>        LSR $12
        0802-         0000>        >LSR 3-1,$12
                      0000>>        .DO 3-1>0
        0802- 46 12   0000>>        LSR $12
        0804-         0000>>        >LSR 3-1-1,$12
                      0000>>>        .DO 3-1-1>0
        0804- 46 12   0000>>>        LSR $12
        0806-         0000>>>        >LSR 3-1-1-1,$12
                      0000>>>>        .DO 3-1-1-1>0
                      0000>>>>        .FIN
                      0000>>>        .FIN
                      0000>>        .FIN
                      0000>        .FIN
        0806-         1100         >LSR 2        Shift A-register left 2 times
                      0000>        .DO 2>0
        0806- 4A      0000>        LSR
        0807-         0000>        >LSR 2-1,$12
                      0000>>        .DO 2-1>0
        0807- 4A      0000>>        LSR
        0808-         0000>>        >LSR 2-1-1,$12
                      0000>>>        .DO 2-1-1>0
                      0000>>>        .FIN
                      0000>>        .FIN
                      0000>        .FIN

Controlling Software Configuration | Don Taylor

Paul Schlyter's article on moving the S-C Assembler into the language card (AAL January 1982) couldn't have come at a better time for me. I was working on a project that had just outgrown the available memory space, and LANGASM came to the rescue. Long live LANGASM!

LANGASM and the extensions to the S-C Assembler that have appeared in the AAL bring to the fore an important subject: controlling the configuration of your copy of someone else's software.

How do I know that a particular "patched" copy I have of the assembler is compatible with another extension that will appear in next month's AAL? What kind of documentation must I keep somewhere to keep track of patched object code for which I have no source code? And how many different patched source code versions (to which I have given different names) of the S-C Assembler am I willing to keep track of?

For my use, I've chosen to keep track of only two modified copies of the assembler; I call them ASM II.1 and LANGASM.1. These two versions are simply the "standard issue" S-C Assembler Version 4.0 and LANGASM, each augmented with the listed .DA directive patch described by Bob in the December, 1980 issue of AAL. (I chose this configuration because the extension was written by Bob himself, and because other AAL articles have used the listed .DA directive. The feature is upward compatible, and listed .DAs presented to unmodified copies of the assembler will cause invisible errors by seemingly accepting those directives, while generating no code for items beyond the comma.)

To add the extensions I want, I first load in ASM II.1 or LANGASM.1, and then modify the copy in memory with a configuration file before using it.

The source listing of LANGASM.1 EXT.SRC shows the method I use to add HOME, COPY and EDIT commands to my copy of LANGASM.1. This particular routine is .OR'd at the beginning of one of the 4K language card memory blocks located at $D000, which permits several extensions to be loaded in one contiguous area of memory, while leaving the main memory area free for the source file and symbol table.

Lines 1160-1570 install the patches in the memory-resident copy of LANGASM.1 and then return to a calling routine. Lines 1320-1400 patch the FAST command (disabled by the LANGASM patches) to render it a HOME command that works like Applesoft's does.

Lines 1260-1430 make similar modifications to LANGASM's command table entries, replacing LOAD with COPY and SAVE with EDIT, along with their assembled addresses (less one).

Lines 1440-1520 are the patches that were contained in Mike Laumer's source code for the EDIT command, found in the January, 1981 issue of AAL.

The source files for EDIT and COPY used within LANGASM.1 EXT.SRC in lines 1590 to the end of the file are identical to those written by Mike Laumer and Bob Sander-Cederlof, with a couple of exceptions. As stated above, the patch code for NML was moved to the modification area in lines 1440-1520. Second, all .OR and .TF directives were removed from both files. Third, a few redundant .EQ directives (internal assembler reference addresses) had to be removed to avoid any EXTRA DEFINITION errors. Finally, $D000 was added to all internal assembler references to make them compatible with LANGASM's $E000 origin.

To install these patches to LANGASM.1, I EXEC the following text file, which I call LANGASM:

CALL -151 (get into the monitor) C0C1 (turn off any firmware card) C081 C081 (write enable the language card) BLOAD LANGASM.1 (load LANGASM into the language card) BLOAD MONITOR EXTENSIONS (load in page 3 extensions from 10/81 issue of AAL) BLOAD LANGASM.1 EXTENSIONS (load in the mods) A5B8:80 (patch DOS to use the language card) A5C0:81 300G (install monitor extensions) C083 (switch in Bank 2) D000G (install LANGASM mods) 3D3G (return to DOS and Applesoft) INT (enter the assembler)

To use this method of in-memory configuration with ASM II.1 (where patches can't always be added in contiguous memory), I use a separate file for each command patch, each .OR'd at the proper address, and then install all patch routines within a single text file that is EXEC'd. Since I'm not dealing with the language card, and each of the commands added above are indepedent of one another, I can skip the EXEC and just BLOAD and install each command (or group of commands) I want to add with the monitor. The result is an easy configuration of the assembler, done at run time.

The use of configuration files to modify the assembler takes a few extra seconds (and a couple of extra files on my utility disk), but it is no more work thanks to the EXEC file. It permits me to keep only a single copy of the assembler (in a known configuration), while enabling me to fully document any modifications I make to the assembler with configuration files for which I have the source code. By creating different EXEC files, I can quickly and easily intermix configuration files to create (and document!) any version of the assembler I wish.

Even though I suppressed the listing of the EDIT and COPY commands to save newsletter space, the source code is on the Quarterly Disk (#7) which will include this program.

     1000  *---------------------------------
     1010  *      INSTALL EXTENSIONS TO LANGASM
     1020  *
     1030  *      AUTHOR:  DON TAYLOR
     1040  *        DATE:  2/6/82, 4:00 PM
     1050  *
     1060  *---------------------------------
     1070         .OR $D000
     1080         .TF LANGASM.1 EXTENSIONS
     1090  *---------------------------------
     1100  DOS.REENTRY             .EQ $03D0
     1110  MON.HOME                .EQ $FC58
     1120  SCA.LOAD.CMD            .EQ $E246
     1130  SCA.SAVE.CMD            .EQ $E26E
     1140  SCA.SLOW.CMD            .EQ $E273
     1150  *---------------------------------
     1160  INSTALL.MODIFICATIONS
     1170         LDY #2            MODIFY ASSEMBLER
     1180  .1     LDA HOME.TABLE,Y  COMMAND JUMP
     1190         STA SCA.SLOW.CMD,Y
     1200         DEY
     1210         BPL .1
     1220         LDA #MON.HOME-1
     1230         STA SCA.SLOW.CMD+3
     1240         LDA /MON.HOME-1
     1250         STA SCA.SLOW.CMD+4
     1260         LDY #2
     1270  .2     LDA COPY.TABLE,Y
     1280         STA SCA.LOAD.CMD,Y
     1290         DEY
     1300         BPL .2
     1310         LDA #COPY-1
     1320         STA SCA.LOAD.CMD+3
     1330         LDA /COPY-1
     1340         STA SCA.LOAD.CMD+4
     1350         LDY #2
     1360  .3     LDA EDIT.TABLE,Y
     1370         STA SCA.SAVE.CMD,Y
     1380         DEY
     1390         BPL .3
     1400         LDA #EDIT-1
     1410         STA SCA.SAVE.CMD+3
     1420         LDA /EDIT-1
     1430         STA SCA.SAVE.CMD+4
     1440         LDA #$60       PATCH NML TO
     1450         STA $E125      MAKE IT A
     1460         LDA #$4C       SUBROUTINE
     1470         STA NML
     1480         STA $E078
     1490         LDA #NEW.NML
     1500         STA NML+1
     1510         LDA /NEW.NML
     1520         STA NML+2
     1530         RTS
     1540  *---------------------------------
     1550  HOME.TABLE .AS ^HOM^
     1560  COPY.TABLE .AS ^COP^
     1570  EDIT.TABLE .AS ^EDI^
     1580  *---------------------------------
     1590  * COPY COMMAND FOR S-C ASSEMBLER
     1600  * VERSION 4.0
     1610  *
     1620  * SOURCE: BOB SANDER-CEDERLOF 12/80
     1630  *
     1640  *---------------------------------
     1650  *
     1660  *
     1670  * NOTE: COPY FUNCTION SOURCE IS
     1680  *       ASSEMBLED HERE...
     1690         .LIST OFF
     1700  *
     1710  *      COPY FUNCTION <COPY L1,L2,L3>
     1720  *      L1= FIRST LINE OF RANGE TO COPY
     1730  *      L2= LAST LINE OF RANGE TO COPY
     1740  *      L3= LINE BEFORE WHICH TO INSERT COPY
     1750  *
     1760  *      ROUTINE BY BOB SANDER-CEDERLOF
     1770  *      APPLE ASSEMBLY LINE 12/80
     1780  *
     1790  *---------------------------------
     1800  SS     .EQ $00,01     START OF SOURCE BLOCK
     1810  SE     .EQ $02,03     END OF SOURCE BLOCK
     1820  SL     .EQ $04,05     LENGTH OF SOURCE BLOCK
     1830  NEWPP  .EQ $06,07     NEW PROGRAM POINTER
     1840  A0L    .EQ $3A,3B
     1850  A0H    .EQ $3B
     1860  A1L    .EQ $3C,3D
     1870  A1H    .EQ $3D
     1880  A2L    .EQ $3E
     1890  A2H    .EQ $3F
     1900  A4L    .EQ $42
     1910  A4H    .EQ $43
     1920  LOMEM  .EQ $4A,4B
     1930  PP     .EQ $CA,CB
     1940  *---------------------------------
     1950  SYNX   .EQ $E05E
     1960  MFER   .EQ $E128
     1970  SCND   .EQ $E12D
     1980  SERTXT .EQ $E4F6
     1990  MON.MOVE .EQ $FE2C
     2000  *---------------------------------
     2010  ERR1   JMP SYNX
     2020  ERR2   .EQ ERR1
     2030  ERR3   JMP MFER
     2040  ERR4   .EQ ERR1
     2050  *---------------------------------
     2060  COPY
     2070         JSR SCND       GET THIRD PARAMETER
     2080         CPX #6         BE SURE WE GOT THREE
     2090         BCC ERR1       NOT ENOUGH PARAMS
     2100         LDX #A0L       FIND BEGINNING OF SOURCE
     2110         JSR SERTXT
     2120         LDA $E4        SAVE POINTER
     2130         STA SS
     2140         LDA $E5
     2150         STA SS+1
     2160         LDX #A1L       FIND END OF SOURCE BLOCK
     2170         JSR SERTXT
     2180         SEC            SAVE POINTER AND COMPUTE
     2190         LDA $E6        LENGTH
     2200         STA SE
     2210         SBC SS
     2220         STA SL         SOURCE LENGTH
     2230         LDA $E7
     2240         STA SE+1
     2250         SBC SS+1
     2260         STA SL+1
     2270         BCC ERR2       RANGE BACKWARD
     2280         BNE .4
     2290         LDA SL
     2300         BEQ ERR2       NOTHING TO MOVE
     2310  *---------------------------------
     2320  .4     LDA PP         COMPUTE NEW PP POINTER
     2330         SBC SL
     2340         STA NEWPP
     2350         LDA PP+1
     2360         SBC SL+1
     2370         STA NEWPP+1
     2380  *---------------------------------
     2390         LDA NEWPP      SEE IF ROOM FOR THIS
     2400         CMP LOMEM
     2410         LDA NEWPP+1
     2420         SBC LOMEM+1
     2430         BCC ERR3       MEM FULL ERROR
     2440  *---------------------------------
     2450         LDX #A2L       FIND TARGET LOCATION
     2460         JSR SERTXT
     2470         LDA SS         BE SURE NOT INSIDE SOURCE
     2480         CMP $E4
     2490         LDA SS+1
     2500         SBC $E5
     2510         BCS .1         BELOW SOURCE BLOCK
     2520         LDA $E4
     2530         CMP SE
     2540         LDA $E5
     2550         SBC SE+1
     2560         BCC ERR4       INSIDE SOURCE BLOCK
     2570  *  TARGET IS ABOVE SOURCE BLOCK, SO WE HAVE TO
     2580  *  ADJUST SOURCE BLOCK POINTERS.
     2590         SEC
     2600         LDA SS
     2610         SBC SL         SS=SS-SL
     2620         STA SS
     2630         LDA SS+1
     2640         SBC SL+1
     2650         STA SS+1
     2660         SEC
     2670         LDA SE
     2680         SBC SL         SE=SE-SL
     2690         STA SE
     2700         LDA SE+1
     2710         SBC SL+1
     2720         STA SE+1
     2730  *---------------------------------
     2740  .1     LDA PP         SET UP MOVE TO MAKE HOLE
     2750         STA A1L
     2760         LDA PP+1
     2770         STA A1H
     2780         LDA NEWPP
     2790         STA PP
     2800         STA A4L
     2810         LDA NEWPP+1
     2820         STA PP+1
     2830         STA A4H
     2840         LDA $E5
     2850         STA A2H
     2860         LDA $E4
     2870         STA A2L
     2880         BNE .2
     2890         DEC A2H
     2900  .2     DEC A2L        A2=A2-1
     2910         LDY #0
     2920         LDA A2L
     2930         CMP A1L
     2940         LDA A2H
     2950         SBC A1H
     2960         BCC .5
     2970         JSR MON.MOVE   A4<A1.A2M
     2980  *---------------------------------
     2990  .5     LDA SS         MOVE IN SOURCE BLOCK
     3000         STA A1L        (MON.MOVE LEFT
     3010         LDA SS+1       A4 POINTING AT FIRST
     3020         STA A1H        BYTE OF THE HOLE)
     3030         LDA SE+1
     3040         STA A2H
     3050         LDA SE
     3060         STA A2L
     3070         BNE .3
     3080         DEC A2H        A2=A2-1
     3090  .3     DEC A2L
     3100         JSR MON.MOVE   A4<A1.A2
     3110         RTS
     3120         .LIST ON
     3130  *
     3140  *
     3150  * NOTE: EDIT FUNCTION SOURCE IS
     3160  *       ASSEMBLED HERE...
     3170         .LIST OFF
     3180  *
     3190  *
     3200  *---------------------------------
     3210  * EDIT COMMAND FOR S-C ASSEMBLER
     3220  * VERSION 4.0
     3230  *
     3240  * SOURCE: MIKE LAUMER 12/6/80
     3250  *
     3260  *---------------------------------
     3270  *
     3280  *  SYSTEM EQUATES
     3290  *---------------------------------
     3300  MON.COUT     .EQ $FDED
     3310  MON.BELL     .EQ $FF3A
     3320  MON.RDKEY    .EQ $FD0C
     3330  MON.CLREOP   .EQ $FC42
     3340  MON.VTAB     .EQ $FC22
     3350  CH           .EQ $0024
     3360  CV           .EQ $0025
     3370  *---------------------------------
     3380  *  ASSEMBLER EQUATES
     3390  *---------------------------------
     3400  GNL    .EQ $E026
     3410  NML    .EQ $E063
     3420  PLNO   .EQ $E779
     3430  GNB    .EQ $E2C5
     3440  DOIT   .EQ $E874
     3450  SEARCH .EQ $E64B
     3460  SERNXT .EQ $E4FE
     3470  NTKN   .EQ $E2AF
     3480  SRCP   .EQ $DD,DE
     3490  WBUF   .EQ $0200
     3500  CURRENT.LINE.NUMBER .EQ $D3,D4
     3510  *---------------------------------
     3520  * PATCH ROUTINES FOR ASSEMBLER
     3530  *---------------------------------
     3540  NEW.NML JSR MY.NML
     3550         JMP GNL
     3560  MY.NML LDY #0
     3570         JSR $E28D
     3580         JSR $E14A
     3590         JMP $E066
     3600  *---------------------------------
     3610  * LOCAL VARIABLES FOR EDIT COMMAND
     3620  *---------------------------------
     3630  NEXT   .DA 0
     3640  END    .DA 0
     3650  CHAR   .DA #0
     3660  EDPTR  .DA #0
     3670  FKEY   .DA #0
     3680  *---------------------------------
     3690  EDIT   DEX
     3700         DEX
     3710         BMI .2         NO ARGUMENTS
     3720         BEQ .4         1 ARGUMENT
     3730         JSR .3         2 ARGUMENTS
     3740         LDX #A1L       FIND END PTR
     3750         JSR SERNXT
     3760         LDA $E6
     3770         STA END
     3780         LDA $E7
     3790         STA END+1
     3800  .1     LDA NEXT+1
     3810         STA SRCP+1
     3820         PHA
     3830         LDA NEXT
     3840         STA SRCP
     3850         CMP END
     3860         PLA
     3870         SBC END+1      PAST END LINE?
     3880         BCS .2         YES, EXIT
     3890         JSR E.LIST     NO, LIST AND EDIT
     3900         JMP .1         TRY FOR NEXT LINE
     3910  .3     LDX #A0L       FIND START PTR
     3920         JSR SERTXT
     3930         LDA $E4
     3940         STA SRCP
     3950         STA NEXT       SAVE NEXT LINE ADRS
     3960         LDA $E5
     3970         STA SRCP+1
     3980         STA NEXT+1
     3990  .2     RTS
     4000  .4     JSR .3         SEARCH FOR LINE
     4010         BCC .2         NOT FOUND EXIT
     4020  E.LIST JSR E.POSN     POSITION FOR EDIT
     4030         JSR MON.CLREOP  PREPARE DISPLAY
     4040         JSR GNB        GET LINE SIZE
     4050         CLC
     4060         ADC NEXT       COMPUTE NEXT LINE ADRS
     4070         STA NEXT
     4080         TYA
     4090         ADC NEXT+1
     4100         STA NEXT+1
     4110         JSR GNB        GET LINE # FOR DISPLAY
     4120         STA CURRENT.LINE.NUMBER
     4130         JSR GNB
     4140         STA CURRENT.LINE.NUMBER+1
     4150         SEC
     4160         ROR $F8        STUFF WBUF FLAG
     4170         JSR PLNO
     4180         LSR $F8        TURN OFF FLAG
     4190         LDA #$20       SPACE AFTER LINE #
     4200         LDX #0
     4210  .1     STX EDPTR
     4220         ORA #$80       FORCE VIDEO BIT
     4230         STA WBUF+4,X   STORE INTO INPUT BUFFER
     4240         CMP #$A0       TEST FOR CONTROL CHAR
     4250         BCS .2         OK, IF NOT
     4260         AND #$7F       OUTPUT INVERSE ALPHA
     4270  .2     JSR MON.COUT   PRINT CHAR
     4280         JSR NTKN       GET NEXT TOKEN
     4290         LDX EDPTR
     4300         INX
     4310         CMP #0         END TOKEN?
     4320         BNE .1         NO,PRINT IT
     4330         STA WBUF+4,X   YES,PUT IT IN TOO
     4340  E.LINE LDX #0
     4350  E.0    STX EDPTR
     4360  E.1    JSR E.INPUT    GET INPUT CHAR
     4370  E.2    LDA #EDTB
     4380         STA $2
     4390         LDA /EDTB
     4400         STA $3
     4410         LDA #CHAR
     4420         STA $12
     4430         LDA /CHAR
     4440         STA $13
     4450         JSR SEARCH     SEARCH EDIT COMMAND TABLE
     4460         BNE .2         NOT IN TABLE
     4470         LDX EDPTR
     4480         JSR DOIT       EXECUTE COMMAND ROUTINE
     4490         BCC E.0        NO DISPLAY ON RETURN
     4500         BCS .5         DISPLAY ON RETURN
     4510  .2     LDX EDPTR      MUST BE TYPE OVER
     4520         LDA CHAR
     4530         CMP #$A0
     4540         BCS .4
     4550  .3     JSR MON.BELL   ERR IF CONTROL KEY
     4560         JMP E.1
     4570  .4     LDA WBUF+5,X   SEE IT END OF LINE
     4580         BNE .6         TYPE OVER IF NOT
     4590         STA WBUF+6,X   SHIFT OVER END OF LINE
     4600  .6     LDA CHAR       STUFF CHAR INTO BUFFER
     4610         STA WBUF+5,X
     4620         CPX #256-5-2   TEST BUFFER SIZE
     4630         BEQ .5         TYPE OVER LAST CHAR IN BUFFER
     4640         INX            INSTEAD OF BUFFER END
     4650  .5     JSR E.DISP     DISPLAY LINE
     4660         JMP E.0        GET NEXT EDIT COMMAND
     4670  *---------------------------------
     4680  E.POSN LDA #19        POSITION TO LINE 19,
     4690         STA CV
     4700         LDA #0         COLUMN 0
     4710         STA CH
     4720         JMP MON.VTAB
     4730  *---------------------------------
     4740  E.DISP STX EDPTR
     4750         JSR E.POSN     POSITION DISPLAY
     4760         LDX #$FF
     4770  .1     INX
     4780         LDA WBUF,X     GET BUFFER CHAR
     4790         BEQ .3         END OF BUFFER
     4800         CMP #$A0       CONTROL CHAR?
     4810         BCS .2         NO
     4820         AND #$7F       PRINT INVERSE ALPHA
     4830  .2     JSR MON.COUT   PRINT CHAR
     4840         JMP .1         NEXT CHAR
     4850  .3     JSR MON.CLREOP CLEAN ANY REMAINING SCREEN
     4860         LDX EDPTR
     4870         RTS
     4880  *---------------------------------
     4890  E.BEG  LDX #0         SET CURSOR TO BEGINNING OF LINE
     4900         CLC
     4910         RTS
     4920  *---------------------------------
     4930  E.DEL  LDA WBUF+5,X   IS THIS END
     4940         BEQ .2
     4950  .1     INX
     4960         LDA WBUF+5,X   SHIFT TO LOWER MEMORY
     4970         STA WBUF+4,X   TO DELETE CHAR
     4980         BNE .1
     4990         LDX EDPTR
     5000  .2     SEC            RETURN WITH DISPLAY
     5010         RTS
     5020  *---------------------------------
     5030  E.END  LDA WBUF+5,X   END OF BUFFER?
     5040         BEQ .1         YES
     5050         INX            NO
     5060         BNE E.END      TRY END AGAIN
     5070  .1     CLC            RETURN NO DISPLAY
     5080         RTS
     5090  *---------------------------------
     5100  E.FIND LDA WBUF+5,X   END OF BUFFER?
     5110         BNE .2         NO
     5120  .1     STA FKEY       YES SO ERR
     5130         JSR MON.BELL   RING BELL
     5140         CLC            RETURN NO DISPLAY
     5150         RTS
     5160  .2     JSR E.INPUT    GET 1 CHAR
     5170         STA FKEY       SAVE KEY TO LOCATE
     5180  .3     INX
     5190         LDA WBUF+5,X   TEST BUFFER
     5200         BEQ .1         END OF BUFFER
     5210         CMP FKEY       NO, SEE IF KEY
     5220         BNE .3         NO, GO FORWARD
     5230         JSR E.INPUT    TRY ANOTHER KEY
     5240         CMP FKEY       SAME CHAR?
     5250         BEQ .3         YES, SEARCH AGAIN
     5260         PLA
     5270         PLA
     5280         STX EDPTR      NO, EXIT POINTING HERE
     5290         JMP E.2
     5300  *---------------------------------
     5310  E.BKSP TXA            AT BEGINNING?
     5320         BEQ .1         YES, STAY THERE
     5330         DEX            BACKUP
     5340  .1     CLC            RETURN NO DISPLAY
     5350         RTS
     5360  *---------------------------------
     5370  E.OVR  JSR E.INPUT    READ CHAR
     5380         JMP E.INS1     SKIP CONTROL CHECK
     5390  *---------------------------------
     5400  E.INS  JSR E.INPUT    READ CHAR
     5410         CMP #$A0       CONTROL CHAR POPS USER OUT
     5420         BCC E.INS2     OF INSERT
     5430  E.INS1 CPX #256-5-2   END OF BLOCK
     5440         BEQ .1         YES STAY THERE
     5450         INX
     5460  .1     STX EDPTR
     5470  .2     PHA            CHAR TO INSERT
     5480         LDA WBUF+4,X   SAVE CHAR TO MOVE
     5490         TAY
     5500         PLA            GET CHAR TO INSERT
     5510         STA WBUF+4,X   PUT OVER SAVED CHAR
     5520         INX
     5530         TYA            INSERT SAVED CHAR
     5540         BNE .2         IF NOT BUFFER END
     5550         STA WBUF+4,X   STUFF END CODE
     5560         STA WBUF+256-5-1 INSURE AN END CODE
     5570         LDX EDPTR
     5580         JSR E.DISP     DISPLAY LINE
     5590         JMP E.INS      GET NEXT INSERT CHAR
     5600  E.INS2 PLA            SEND CHAR TO
     5610         PLA            COMMAND SEARCH
     5620         LDX EDPTR
     5630  *---------------------------------
     5640         JMP E.2
     5650  E.RETQ LDA #0         CLEAR REST OF LINE
     5660         STA WBUF+5,X
     5670         JSR E.DISP     DISPLAY LINE
     5680  E.RET  LDX #$FF       SUBMIT LINE TO ASSEMBLER
     5690  .1     INX            COMPUTE LINE SIZE
     5700         LDA WBUF,X
     5710         BNE .1
     5720         DEX
     5730  .2     STX $E1        SAVE SIZE
     5740         PLA
     5750         PLA
     5760         JMP MY.NML     SUBMIT THE LINE
     5770  *---------------------------------
     5780  E.TAB  CPX #20        <COL 20?
     5790         BCS .1         NO
     5800         LDA WBUF+5,X   END OF BUFFER?
     5810         BEQ .1         YES
     5820         INX            MOVE FORWARD
     5830         CPX #7         TAB MATCH?
     5840         BEQ .1
     5850         CPX #11        TAB MATCH?
     5860         BNE E.TAB
     5870  .1     CLC            RETURN WITHOUT DISPLAY
     5880         RTS
     5890  *---------------------------------
     5900  E.RIT  LDA WBUF+5,X   END OF BUFFER?
     5910         BNE .1         NO
     5920         STA WBUF+6,X
     5930         LDA #$A0       PUT A BLANK
     5940         STA WBUF+5,X   TO EXTEND LINE
     5950         CPX #256-5-2
     5960         BEQ .2
     5970  .1     INX            MOVE AHEAD
     5980  .2     CLC            RETURN NO DISPLAY
     5990         RTS
     6000  *---------------------------------
     6010  E.ABORT LDA #$DC      OUTPUT BACKSLASH
     6020         STA WBUF+5
     6030         LDA #0
     6040         STA WBUF+6
     6050         JSR E.DISP     SHOW CANCEL
     6060         JMP GNL        GET NEXT COMMAND
     6070  *---------------------------------
     6080  E.INPUT LDA #19
     6090         STA CV
     6100         TXA            POSITION TO CURSOR
     6110         CLC
     6120         ADC #5
     6130  .1     CMP #40        THIS LINE?
     6140         BCC .2         YES
     6150         SEC
     6160         SBC #40
     6170         INC CV         ON NEXT LINE
     6180         BNE .1
     6190  .2     STA CH
     6200         JSR MON.VTAB   SET BASL
     6210         JSR MON.RDKEY  INPUT A CHAR
     6220         STA CHAR
     6230         RTS
     6240  *---------------------------------
     6250  *  COMMAND TABLE
     6260  *---------------------------------
     6270  EDTB   .DA #3,#1      ITEM SIZE, KEY SIZE
     6280         .DA #$82,E.BEG-1   ^B
     6290         .DA #$84,E.DEL-1   ^D
     6300         .DA #$8E,E.END-1   ^N
     6310         .DA #$86,E.FIND-1  ^F
     6320         .DA #$88,E.BKSP-1  ^H
     6330         .DA #$89,E.INS-1   ^I
     6340         .DA #$8D,E.RET-1   ^M
     6350         .DA #$8F,E.OVR-1   ^O
     6360         .DA #$91,E.RETQ-1  ^Q
     6370         .DA #$94,E.TAB-1   ^T
     6380         .DA #$95,E.RIT-1   ^U
     6390         .DA #$98,E.ABORT-1 ^X
     6400         .DA #0
     6410         .EN

Funny Noise | Bob Sander-Cederlof

This funny program uses the contents of RAM and ROM from $0000 to $BFFF and from $D000 to $FFFF as timers to control a speaker-toggle loop. How it sounds depends on what you have in memory!

     1000  *--------------------------------
     1010  *      FUNNY NOISE
     1020  *--------------------------------
     1030  SPKR   .EQ $C030    SPEAKER TOGGLE ADDRESS
     1040  KYBD   .EQ $C000    KEYBOARD INPUT
     1050  STROBE .EQ $C010    KEYBOARD STROBE
     1060  *--------------------------------
     1070  PNTR   .EQ 0        ADDRESS OF CURRENT RANDOM VALUE
     1080  *--------------------------------
     1090  NOISE  JSR $FC58    CLEAR SCREEN, HOME CURSOR
     1100  N0     LDY #0       POINT TO FIRST BYTE IN PAGE
     1110         LDA #$D000   START AT $D000
     1120         STA PNTR
     1130         LDA /$D000
     1140         STA PNTR+1
     1150         JSR $FDDA    PRINT PAGE NUMBER
     1160  N1     LDA SPKR     TOGGLE SPEAKER
     1170         LDA (PNTR),Y GET HALF-CYCLE TIMER
     1180         TAX
     1190  N2     DEX          DELAY LOOP FOR HALF-CYCLE
     1200         BNE N2
     1210         INY          NEXT BYTE IN PAGE
     1220         BNE N1
     1230         INC PNTR+1   NEXT PAGE
     1240         LDA PNTR+1   BYPASS I/O AREA
     1250         CMP /$C000
     1260         BEQ N0
     1270         JSR $FDDA    PRINT PAGE NUMBER
     1280         LDA KYBD     SEE IF ANY KEY PRESSED
     1290         BPL N1       NO, KEEP MAKING NOISE
     1300         STA STROBE   YES, CLEAR STROBE
     1310         RTS          THAT'S ALL, FOLKS!

Apple Assembly Line is published monthly by S-C SOFTWARE, P. O. Box 280300, Dallas, TX 75228. Phone (214) 324-2050 Subscription rate is $15 per year, in the USA, sent Second Class Mail; $18 per year sent First Class Mail in USA, Canada, and Mexico; $28 per year sent Air Mail to other countries. Back issues are available for $1.50 each (other countries add $1 per back issue for postage). All material herein is copyrighted by S-C SOFTWARE, all rights reserved. Unless otherwise indicated, all material herein is authored by Bob Sander-Cederlof. (Apple is a registered trademark of Apple Computer, Inc.)