Apple Assembly Line
Volume 8 -- Issue 1 October 1987

In This Issue...

Thanksgiving

I know the date above says October, but it is now the day before Thanksgiving on my calendar. Since Bill Morgan moved to a new job in Austin, Texas, it has been quite a challenge to put the newsletter together! I am thankful that you are patient, and that God is faithful. And He reigns. Even in this day of wild stock markets, economic uncertainty, natural disasters, and wars we can see that He is, and that "He has made the earth by his power, He has established the world by His wisdom, and has stretched out the heaven by His understanding."

Using Laumer Research Full Screen Editor on IIgs

The ProDOS version of the Full Screen Editor is compatible with the IIgs and with Version 2.0 of the S-C Macro Assembler. The DOS version, on the other hand, requires a different setup file. This is now provided as the file "ED IIGS 2.0", a text file which you EXEC to load and install the FSE. Since there are a lot of you who may need this file so I will describe its contents here:

     MNTR
     BLOAD EDITOR,A$5000
     BLOAD B.DRIVER.AP2E,A$5DB5
     0=L
     0/D000<0/5000.5FFFM
     1=L
     0/D074:4C FA F7
     0/F7F4:AD 80 C0 4C 03 D0 AD 88 C0 4C 00 D0
     Q

You can create this file by typing the above lines with line numbers in the S-C Macro Assembler, and then save them on a text file using the command "TEXT ED IIGS 2.0" You may of course move the files ED IIGS 2.0, EDITOR, and B.DRIVER.AP2E to your assembler disks, and create a composite load file so that the FSE installation is automatic.


Key-Edit Utility Program for the IIgs Bob Boughner

Key-Edit is a IIgs utility program that permits the rapid recall and easy editing of previously entered commands or program source lines. Key-Edit works in either 40- or 80-column mode, and will work inside a window smaller than the full screen if you set the proper values in the monitor window definition bytes. The program is patterned after a similar program I use at work on an IBM AT, which explains some of the rather strange keyboard choices.

The current version, shown here, of Key-Edit works only under DOS. I hope to modify it for at least ProDOS-8 in the near future. Because of the keyboard choices I made, it is currently tied to the IIgs. Toward the end of this article I will describe the changes needed to make it work in a //e or //c.

Key-Edit requires four pages (1024 bytes) for itself and the buffer of previously-typed commands. I obtained these four pages by moving the DOS buffers down (an old trick). When you BRUN KEY.EDIT it loads at $5000; the code at $5000 then moves the buffers down four pages, copies Key-Edit into the hole starting at $9900, and clears a command buffer at $9C00-$9CFF. I also patch in a RESET routine so that RESET will re-install Key-Edit. The vector which was at $3F2,3F3 is copied into my patch, so that RESET will still function normally. Of course if you later patch a new RESET vector, my patch will be left out in the cold.

Key-Edit works by intercepting the normal keyboard input stream. A table (lines 2660-2870) defines fifteen special combinations of normal keys with the Open-Apple, Option (Solid-Apple), Control, and Shift keys. If any of these special keystrokes is detected, Key-Edit performs an editing operation on the input buffer and the screen. Other keystrokes are passed to the program which asked for input. Key-Edit is compatible with the S-C Macro Assembler and Applesoft, and may work with other DOS-based applications.

When you finally type a RETURN, the current line is copied into my one-page buffer. A pointer keeps track of the end of the last line copied in my buffer, so the each command is copied onto the end of the previous command. I separate the commands in my buffer with $00 bytes rather than RETURN ($8D) codes, because it is easier to test for them in the various loops. When you type the "up arrow" key, the most recently entered command line is retrieved, placed into the buffer at $200, and displayed on the screen. Another "up arrow" will move back in time to the command line before that one, and so on. Since the buffer is only 256 bytes long, there is a limit to how many commands are remembered. The buffer is circular, so after you have looked at the oldest one another "up arrow" will show you the newest one. The "down arrow" key moves you around the buffer in the opposite direction. When you find the command you want, simply hit RETURN to execute it. Or, if it is only approximately what you want, edit it and then hit RETURN.

When you start up Key-Edit, the command buffer is cleared. Each time you enter a new command, it is copied on the end of the previous command. Once the end of the buffer is reached, the buffer wraps around to the beginning, and the command there is over-written. The over-written command is obviously the oldest command in the buffer. Then enough $00 bytes are stored to clear out any partial command line. This allows the up- and down-arrows to scan smoothly forward or backward around the buffer.

The editing commands in Key-Edit allow you to scan back and forth along the input line, delete characters, insert characters, and submit the line without needing to scan to the end-of-line first. Regardless of where the cursor is on the line, you can type the RETURN key and the whole line will be submitted. Scanning back and forth is done with either the TAB key or the left and right arrow keys, with or without the open-apple key:

       left arrow      move back one character
       right arrow     move ahead one character
       OA-left         move to beginning of line
       OA-right        move to end of line
       TAB             move ahead to next "tab" stop
       OA-TAB          move back to next "tab" stop

These keys will not move backward beyond the beginning of the line, nor forward past the end of the line. A "tab" stop is defined as the next occurrence of any of five characters: space, comma, period, semi-colon, or colon. The cursor will move until it encounters one of those five characters or the end or beginning of the line. The five "tab" characters are contained in a table at line 5710, so you modify the list as you wish.

There are six different commands available to delete characters from the current line. The simplest is simply the DELETE key, which deletes the key to the left of the cursor. If the cursor is at the beginning of the line, the first character is deleted. Pressing the Open Apple with the DELETE key deletes the entire line. Pressing the Control-key with DELETE deletes from the cursor to the end of line. Control-Shift-DELETE scrubs everything from the left of the cursor to the beginning of the line. Option (or Solid-Apple) with DELETE causes my internal command buffer to be cleared. Finally, hitting the decimal point key on the numeric key pad with the Open-Apple key deletes the key under the cursor. Here they are in tabular format:

       DELETE       Delete char before cursor
       OA-DEL       Delete entire line
       C-DEL        Delete to end of line
       CS-DEL       Delete to beginning
       OP-DEL       Clear command buffer
       OA-PAD-"."   Delete char under cursor

That last one is there because of the program I use at work on my IBM AT. It has a DELETE CHAR key on the key pad decimal point, and INSERT TOGGLE key on the key pad "0" key. If you do not have a numeric key pad, change the equate line 1010 to "HAVE.PAD .EQ 0"; then it will assemble Open-Apple Period for the DELETE CHAR function, and Open-Apple Comma for the INSERT TOGGLE function.

Speaking of INSERT.... If you hold down the Open-Apple and type the "0" on the numeric key pad (or comma on the regular keyboard if you select the "HAVE.PAD .EQ 0" option), the cursor will be changed to a flashing "^". Then any normal characters you type will be inserted before the cursor. Typing the OA-PAD-0 again will toggle insert mode back off, and you will be back in the "replace" mode.

Key-Edit does not interfere with the other editing commands which are available in Applesoft and the S-C Macro Assembler, it supplements them. However, the ESCAPE key functions may work a little differently than you expect. I was not able to get them to work exactly as they should. Maybe you can do it.

Since Key-Edit uses the input hook, it can be disconnected by typing PR#3 (which engages both input and output hooks and turns on 40-columns), or any IN# command. Hitting RESET will reconnect it. Remember that the DOS buffers have been moved down to make space for Key-Edit. If you move them back up, be sure you also unhook the input vector change the RESET vector to no longer point into Key-Edit, as it will be G-O-N-E.

Lines 1210-1580 are the code which install Key-Edit. Lines 1210-1230 check to see if it is already installed, and if so just return without doing anything. Lines 1600-1870 are an alternate installation routine which I used during development. I deleted the .TF at line 1070, so that assembly was into RAM at $5000. Then the first time I tested Key-Edit I typed $5000G to install it. After subsequent patches and re-assembly, I typed MGOT to copy the new code into place. If you start making changes, you can use the same technique. In fact, you might want to change the "BEQ .6" at line 1230 to "BEQ T", to make it semi-automatic.

The command table (lines 2660-2870) uses a macro to simplify typing it in. The listing shows the macro expansion, so you can type them directly if you wish. The first byte of each four-byte entry is the ASCII value of the character. The second byte is the contents of the keyboard modfifier register, which is $C025 in the Apple IIgs. The eight bits of this byte tell you which modifier keys were pressed when the key was typed:

       bit 7:  Open-Apple
       bit 6:  Option (Solid Apple)
       bit 5:  (data updated without keypress)
       bit 4:  numeric key pad
       bit 3:  repeat active
       bit 2:  caps lock down
       bit 1:  control key down
       bit 0:  shift key down

I only look at bits 7, 6, 4, 1, and 0. If you modify this program for a //e or //c, you will have to change all code which accesses $C025 (called KEY.STATE in the program), because it doesn't exist in these older machines.

By modifying the keyboard command table and the insert-mode cursor, you could use Key-Edit on a //e or //c equipped with a 65802 processor. A little more work would eliminate the 65802-specific opcodes and let it run in a normal //c or enhanced //e with a 65C02 processor. In fact, I only used one opcode which is in the 65802 or 65816 and not in the 65C02, and I only used it one time: the TYX at line 5460. You could replace it with two lines: TYA and TAX. The insert-mode cursor would give a little more trouble, but you could just delete that code and leave the cursor alone. You have to modify the keyboard command table to use key combinations that are available and testable on the //e and //c. Then the PROCESS.CHAR subroutine would have to access the Open- and Solid-Apple information in a different way.

When I sent this program to AAL, it was nearly a full 3 pages plus the buffer and some patches inside DOS over the top of the INIT code. A few days later I thought of some changes and sent them on to AAL which shortened the code enough to eliminate the need for the patches inside DOS. However, the program as you see it here has been significantly revised by Bob Sander-Cederlof.

[Editor's note: Bob Boughner's code was good, but I just couldn't leave it alone. Blame any bugs you find on me! Hopefully you will be afflicted with the same impulse, and start modifying to your own taste.]

There is now room to add new features without expanding to more than a total of four pages. The end of code is currently at $9BA7, and you can go on up to $9BFF, so you have $58 (88 decimal) bytes left to play in. If you go too far, lines 5980-6000 will catch you and signal the fact when you try to assemble.

  900        .TI 76,Key Edit Program by Bob Boughner & Bob S-C......11-19-87.......
  1000        .LIST CON
  1010 HAVE.PAD   .EQ 0    =0 IF NO PAD, =1 IF PAD PRESENT
  1020        .OP 65816
  1030 *--------------------------------
  1040 * SAVE S.KEY.EDIT
  1050 *--------------------------------
  1060        .OR $5000
  1070        .TF KEY.EDIT
  1080 *--------------------------------
  1090 * VARIABLES NEEDED FOR LOADING
  1100 * KEY.EDIT
  1110 *--------------------------------
  1120 DOS.IO.HOOK         .EQ $3EA
  1130 BLD.DOS.BUFRS       .EQ $A7D4
  1140 DOS.BUFR.LOC        .EQ $9D00
  1150 KSWL                .EQ $38
  1160 KSWH                .EQ $39
  1170 COL80               .EQ $C300
  1180 MON.RESET           .EQ $3F2
  1190 PWRUP               .EQ $3F4
  1200 *--------------------------------
  1210 BGN    LDA /RESET.PTCH
  1220        CMP MON.RESET+1
  1230        BEQ .6       ALREADY SETUP
  1240 *---Copy BODY to $9900-9BFF------
  1250        LDY #0
  1260 .1     LDA IMAGE,Y
  1270        STA $9900,Y
  1280        LDA IMAGE+256,Y
  1290        STA $9A00,Y
  1300        LDA IMAGE+512,Y
  1310        STA $9B00,Y
  1320        INY
  1330        BNE .1
  1340 *---Clear command buffer---------
  1350        JSR CLEAR.BUFFER
  1360 *---Set up RESET vector----------
  1370        LDY #1
  1380 .5     LDA MON.RESET,Y   POINT MY RESET AT CURRENT
  1390        STA NORM.RESET,Y
  1400        LDA MY.RESET,Y    POINT RESET AT MY PATCH
  1410        STA MON.RESET,Y
  1420        DEY
  1430        BPL .5
  1440        LDA /RESET.PTCH^$A500   VALIDATE THE VECTOR
  1450        STA PWRUP
  1460 *---Drop DOS buffers 4 pages-----
  1470        SEC
  1480        LDA DOS.BUFR.LOC+1
  1490        SBC #4
  1500        STA DOS.BUFR.LOC+1
  1510        JSR BLD.DOS.BUFRS
  1520 *---Install my input hook--------
  1530        LDA #HOOK
  1540        LDY /HOOK
  1550        STA KSWL
  1560        STY KSWH
  1570        JSR DOS.IO.HOOK
  1580 .6     RTS
  1590 *--------------------------------
  1600 T
  1610 *---Copy BODY to $9900-9BFF------
  1620        LDY #0
  1630 .1     LDA IMAGE,Y
  1640        STA $9900,Y
  1650        LDA IMAGE+256,Y
  1660        STA $9A00,Y
  1670        LDA IMAGE+512,Y
  1680        STA $9B00,Y
  1690        INY
  1700        BNE .1
  1710 *---Clear command buffer---------
  1720        JSR CLEAR.BUFFER
  1730 *---Setup RESET Vector-----------
  1740        LDY #1
  1750 .5     LDA MY.RESET,Y    POINT RESET AT MY PATCH
  1760        STA MON.RESET,Y
  1770        DEY
  1780        BPL .5
  1790        LDA /RESET.PTCH^$A500   VALIDATE THE VECTOR
  1800        STA PWRUP
  1810 *---Install my input hook--------
  1820        LDA #HOOK
  1830        LDY /HOOK
  1840        STA KSWL
  1850        STY KSWH
  1860        JSR DOS.IO.HOOK
  1870 .6     RTS
  1880 *--------------------------------
  1890 MY.RESET .DA RESET.PTCH
  1900 *--------------------------------
  1910 *  VARIABLES AND CONSTANTS
  1920 *--------------------------------
  1930 MON.ADVANCE         .EQ $FBF4
  1940 MON.VTAB            .EQ $FC22
  1950 MON.RDKEY           .EQ $FD0C
  1960 MON.CLREOP          .EQ $FC42
  1970 MON.ESC             .EQ $FD2F
  1980 MON.COUT            .EQ $FDED
  1990 *--------------------------------
  2000 KEYIN.40            .EQ $FD1B
  2010 KEYIN.80            .EQ $C305
  2020 *--------------------------------
  2030 INBUF               .EQ $200
  2040 COL.STATE           .EQ $C01F
  2050 KEY.STATE           .EQ $C025 
  2060 CV                  .EQ $25
  2070 CH40                .EQ $24
  2080 CH80                .EQ $57B
  2090 WNDWDTH             .EQ $21
  2100 WNDBTM              .EQ $23
  2110 *--------------------------------
  2120 IMAGE  .PH $9900
  2130 *--------------------------------
  2140 *   The input hook at KSWL,H branches here whenever
  2150 *      RDKEY is called.
  2160 *--------------------------------
  2170 HOOK   BRA .2            <<<MODIFIED TO SKIP OR NOT SKIP
  2180 .1     JMP TRUE.KEYIN             THIS JMP>>>
  2190 .2     CPX LNGTH         IS X POSITION GREATER THAN MY SAVED LENGTH?
  2200        BCC .3            NO. MUST BELONG TO ME
  2210        BNE .1            IF NOT EQUAL, THEN IT IS NOT MINE
  2220 *--------------------------------
  2230 .3     PHA               SAVE THE CURRENT SCRN CHAR
  2240        TXA               AT BEGINNING OF LINE?
  2250        BNE .5            NO.
  2260 *---Save line start position-----
  2270        LDA CV            GET POSITION OF LINE START AND SAVE
  2280        STA BOL 
  2290        LDA CH40          ASSUME 40 COLUMNS
  2300        BIT COL.STATE     IS IT 40 OR 80 COLS?
  2310        BPL .4            ...40 COLUMNS
  2320        LDA CH80          ...80 COLUMMS
  2330 .4     STA BOC
  2340 .5     PLA               RETRIEVE SAVED SCREEN CHARACTER
  2350        JSR TRUE.KEYIN    GET A CHR FROM THE NORMAL INPUT ROUTINE
  2360        STZ HOOK+1        SWITCH TO LET MON.RDKEY FUNCTION
  2370 .6     JSR PROCESS.CHAR
  2380        JSR MON.RDKEY
  2390        BRA .6            NORMAL CHARS BUST THE LOOP
  2400 *--------------------------------
  2410 PROCESS.CHAR
  2420        STA CURRCHAR
  2430        LDY #-4
  2440 .1     INY
  2450        INY
  2460        INY
  2470        INY
  2480        LDA CMDTBL,Y
  2490        BEQ .2       ...END OF CMDTBL
  2500        CMP CURRCHAR
  2510        BNE .1       ...TRY NEXT ENTRY
  2520        LDA KEY.STATE
  2530        AND #%11010011    ONLY OA,SA,PAD,CTRL,SHIFT
  2540        CMP CMDTBL+1,Y
  2550        BNE .1       ...TRY NEXT ENTRY
  2560 .2     LDA CMDTBL+3,Y
  2570        PHA
  2580        LDA CMDTBL+2,Y
  2590        PHA
  2600        RTS
  2610 *--------------------------------
  2620        .MA CMD
  2630        .DA #$]1,#$]2,]3-1
  2640        .EM
  2650 *--------------------------------
  2660 CMDTBL
  2670   >CMD 88,00,BAKSPC      LEFT ARROW
  2680   >CMD 88,80,LINE.START  OA-LEFT ARROW
  2690   >CMD 95,00,FORWD       RIGHT ARROW
  2700   >CMD 95,80,END.OF.LINE OA-RIGHT ARROW
  2710   >CMD FF,00,DELCHR      DELETE
  2720   >CMD FF,80,DELALL      OA-DELETE
  2730   >CMD FF,02,DELEOL      CTRL-DELETE
  2740   >CMD FF,03,DELBOL      CTRL-SHIFT-DELETE
  2750   >CMD FF,40,CLEAR.BUFFER  SA-DELETE
  2760   .DO HAVE.PAD
  2770   >CMD AE,90,DELCUR      OA-PAD-"."
  2780   >CMD B0,90,INS.TOG     OA-PAD-"0"
  2790   .ELSE
  2800   >CMD AE,80,DELCUR      OA-"."
  2810   >CMD AC,80,INS.TOG     OA-","
  2820   .FIN
  2830   >CMD 8B,00,UP          UP ARROW
  2840   >CMD 8A,00,DOWN        DOWN ARROW
  2850   >CMD 89,00,TAB.FWD     TAB
  2860   >CMD 89,80,TAB.BAK     OA-TAB
  2870   >CMD 00,00,NORM.CHR   any other
  2880 *--------------------------------
  2890 BAKSPC TXA               AT LINE START?
  2900        BEQ RTS.1         YES, GET THE NEXT CHR
  2910        DEX               NO, BACKUP ONE SPACE
  2920        LDA #$88     PRINT A BACKSPACE
  2930 COUT.1 JMP MON.COUT
  2940 RTS.1  RTS
  2950 *--------------------------------
  2960 FORWD  CPX LNGTH         ALREADY AT END OF LINE?
  2970        BCS RTS.1         ...YES
  2980        INX               ...NO, ADVANCE
  2990        LDA #$9C          PRINT $9C TO SPACE FORWARD
  3000        BIT COL.STATE     80- OR 40-COLUMNS?
  3010        BMI COUT.1        ...80-COLUMNS
  3020        JMP MON.ADVANCE   ...40-COLUMNS
  3030 *--------------------------------
  3040 DELCHR JSR BAKSPC       Delete char to left of cursor
  3050 DELCUR JSR MON.CLREOP    Delete char under cursor
  3060        LDA LNGTH
  3070        BEQ .2
  3080        PHX
  3090 .1     INX
  3100        CPX LNGTH
  3110        BCS .3
  3120        LDA INBUF,X       MOVE INBUF DOWN BY ONE
  3130        STA INBUF-1,X
  3140        JSR MON.COUT
  3150        BRA .1
  3160 .3     PLX               RESTORE CURSOR POSITION ON SCREEN
  3170        JSR CURSOR.POSN
  3180        DEC LNGTH
  3190 .2     RTS         
  3200 *--------------------------------
  3210 DELBOL CPX LNGTH    If at eol, delete entire line
  3220        BCS DELALL
  3230        PHX               SAVE LOCAL POSITION WITHIN INBUF
  3240        JSR LINE.START    GO TO BEGINNING OF LINE
  3250        PLY               (Y) points at remaining chars
  3260 .1     LDA INBUF,Y       MOVE INBUF DOWN TO BEGINNING OF BUFFER
  3270        STA INBUF,X
  3280        JSR MON.COUT      AND WRITE TO SCREEN
  3290        INY
  3300        INX
  3310        CPY LNGTH
  3320        BCC .1
  3330        JSR DELEOL        LOP OFF THE REST
  3340 LINE.START
  3350        LDX #0             INDICATE BEGINNING OF INBUF
  3360        JMP CURSOR.POSN
  3370 *--------------------------------
  3380 DELALL JSR LINE.START    Delete entire line
  3390 DELEOL STX LNGTH         Delete from cursor to eol
  3400        JMP MON.CLREOP    CLEAR TO END OF WINDOW
  3410 *--------------------------------
  3420 INS.TOG
  3430        LDY CURSOR   SWAP THE CURSORS
  3440        LDA $E10134       CURRENT ACTIVE CURSOR
  3450        STA CURSOR        SAVE IT
  3460        TYA               PREVIOUS CURSOR
  3470        STA $E10134       START USING IT AGAIN
  3480        LDA INS.FLAG      TOGGLE THE FLAG
  3490        EOR #$80
  3500        STA INS.FLAG
  3510        RTS
  3520 *--------------------------------
  3530 *   Select stored input line from buffer
  3540 *      by scanning forward in time
  3550 *--------------------------------
  3560 DOWN   JSR PREPARE.BUFFER.SEARCH
  3570        BPL RTS.2    Buffer is empty
  3580        DEY
  3590 .1     INY          SEARCH FOR "00"
  3600        LDA BUFFER,Y
  3610        BNE .1
  3620 .2     INY          SEARCH FOR NON-ZERO
  3630        LDA BUFFER,Y
  3640        BEQ .2
  3650        JSR CBTB.1   STORE CHAR AND COPY REST OF CMND
  3660        STY WHERE
  3670        JMP CURSOR.POSN    RTN WITH CURSOR AT LINE END, CHK ADJUSTMENT
  3680 *--------------------------------
  3690 *   Select stored input line from buffer
  3700 *      by scanning backward in time.
  3710 *--------------------------------
  3720 UP     JSR PREPARE.BUFFER.SEARCH
  3730        BPL RTS.2    Buffer is empty
  3740        INY
  3750 .1     DEY          BACKUP TO NON-ZERO
  3760        LDA BUFFER,Y
  3770        BEQ .1
  3780 .2     DEY          BACKUP TO "00"
  3790        LDA BUFFER,Y
  3800        BNE .2
  3810        STY WHERE
  3820        JSR CBTB.2   COPY COMMAND TO INBUF
  3830        JMP CURSOR.POSN    RTN WITH CURSOR AT LINE END, CHK ADJUSTMENT
  3840 *--------------------------------
  3850 PREPARE.BUFFER.SEARCH
  3860        JSR LINE.START    GO TO BEGINNING OF LINE
  3870        JSR MON.CLREOP    CLEAR THE LINE
  3880        LDY WHERE         GET LAST POSITION IN BUFFER
  3890        BIT BUF.FLAG      ANYTHING IN BUFFER?
  3900 RTS.2  RTS
  3910 *--------------------------------
  3920 CBTB.1 STA INBUF,X
  3930        JSR MON.COUT
  3940        INX
  3950 CBTB.2 INY                COPY BUFFER TO INPUT BUFFER AND
  3960        LDA BUFFER,Y       DISPLAY ON SCREEN
  3970        BNE CBTB.1
  3980        STX LNGTH          SAVE TOTAL LINE LENGTH
  3990        RTS
  4000 *--------------------------------
  4010 TAB.FWD
  4020 .1     CPX LNGTH          ELSE, MOVE FORWARD IF NOT AT LINE END
  4030        BCS NEWPOS
  4040        INX
  4050        JSR COMPARE.TAB.CHARS
  4060        BCC .1             NO. GET THE NEXT INBUF CHAR
  4070 NEWPOS JMP CURSOR.POSN    YES. CALC NEW POSITION OF CURSOR
  4080 *--------------------------------
  4090 TAB.BAK
  4100 .1     TXA                TAB BACKWARD IF NOT AT LINE BEGINNING
  4110        BEQ NEWPOS
  4120        DEX
  4130        JSR COMPARE.TAB.CHARS
  4140        BCC .1
  4150        BCS NEWPOS
  4160 *--------------------------------
  4170 NORM.CHR
  4180        PLA          POP A RETURN ADDRESS
  4190        PLA
  4200        JSR DRCT.OFF
  4210        LDA CURRCHAR      GET INPUT CHAR
  4220        PHA                SAVE CHR FOR LATER CODE
  4230        CMP #$A0     IS IT A CONTROL CHAR?
  4240        BCS .2       ...NO
  4250        CMP #$8D     CARRIAGE RETURN?
  4260        BNE .0
  4270        JSR MOVE.TO.BUFFER
  4280        JSR END.OF.LINE
  4290 .0     BIT INS.FLAG       INSERTION MODE ON?
  4300        BPL .1             NO.
  4310        JSR INS.TOG        YES, TOGGLE INSERT MODE OFF
  4320 .1     STZ LNGTH          CLEAR TOTAL LINE LENGTH
  4330        PLA
  4340        CMP #$9B           ESC CHARACTER?
  4350        BNE .5
  4360 *---Handle ESC-------------------
  4370         STZ HOOK+1        SET CODE FOR PASS THRU WHILE IN 'ESC' MODE
  4380         JSR MON.ESC       LET MONITOR HANDLE ESCAPE MOVES
  4390         PHA               SAVE CHR ON THE STACK
  4400         JSR DRCT.OFF      RESET SET CODE TO CHK EACH CHR
  4410         ASL KEY.STATE     MOVE OPEN APPLE STATUS TO CARRY
  4420         BCS .4      AND RTN IF SET
  4430         LDA #" "          ELSE, INSERT A SPACE INTO INBUF
  4440         STA INBUF,X
  4450         INX               AND INCREMENT POSITION SO THAT NEXT TIME THRU
  4460 *                         KEY.EDIT WILL IGNORE THE LINE
  4470         BRA .4
  4480 .2     ASL KEY.STATE      MOVE STATUS OF OPEN APPLE KEY TO CARRY
  4490        BCS .4       IF SET, THEN RTN NOW
  4500        BIT INS.FLAG       INSERTION MODE ON?
  4510        BMI INS.CHR        YES. GO HANDLE IT
  4520        CPX LNGTH          NO. INC LENGTH IF AT END.
  4530        BCC .4
  4540        JSR CURSOR.POSN    POSITION CURSOR AT LINE END AND CHK
  4550 *                         ADJUSTMENT FOR BTM OF WINDOW
  4560        INC LNGTH
  4570 .4     PLA                GET CHAR FROM STACK AND RTN
  4580 .5     RTS
  4590 *--------------------------------
  4600 * This portion handles character insertions
  4610 * while the insert flag is on.
  4620 *--------------------------------
  4630 INS.CHR
  4640        PLY               GET CHR FROM STACK INTO Y-REG
  4650        PHY               LEAVE ON STACK TOO
  4660        PHX               SAVE LOCAL POSITION WITHIN INBUF
  4670        INC LNGTH         INCREASE LINE LENGTH BY ONE
  4680 .1     TYA               INSERT CHAR IN INBUF
  4690        LDY INBUF,X       GET CURRENT CHAR
  4700        STA INBUF,X       PUT NEW CHAR
  4710        JSR MON.COUT      AND DISPLAY ON SCREEN
  4720        INX               MOVE ON DOWN THE LINE
  4730        CPX LNGTH
  4740        BCC .1            MORE TO GO...
  4750        JSR CURSOR.POSN   ADJUSTMENT NEEDED FOR BEING NEAR WINDOW BTM?
  4760        PLX               RESET POSITION IN INBUF
  4770        JSR CURSOR.POSN   RESET CURSOR TO ITS ORIGINAL POSITION
  4780        PLA               INSERTED CHARACTER
  4790        RTS
  4800 *--------------------------------
  4810 END.OF.LINE
  4820        LDX LNGTH          CALCULATE OFFSET FROM LINE START
  4830 *--------------------------------
  4840 *   (X)=position in INBUF
  4850 *   Compute screen line and column for current position
  4860 *      and position cursor there.
  4870 *   If that is below window, adjust BOL accordingly and
  4880 *      position to bottom line.
  4890 *--------------------------------
  4900 CURSOR.POSN
  4910        LDY BOL      GET ROW OF LINE START
  4920        CLC          virtual screen position = BOC+X
  4930        TXA
  4940        ADC BOC
  4950 *---Adjust for window width------
  4960 .1     CMP WNDWDTH
  4970        BCC .2       THIS IS THE LINE
  4980        SBC WNDWDTH
  4990        INY          MOVE DOWN ONE LINE
  5000        BRA .1
  5010 *---HTAB to position-------------
  5020 .2     STA CH80
  5030        BIT COL.STATE     In 80-column mode?
  5040        BMI .3            ...yes
  5050        STA CH40          ...no, store in 40-col CH
  5060 *---Adjust if below window-------
  5070 .3     CPY WNDBTM
  5080        BCC .4       ON THE SCREEN NOW
  5090        DEC BOL      ADJUST BEGINNING OF LINE ROW NUMBER
  5100        DEY
  5110        BNE .3
  5120 *---VTAB to line-----------------
  5130 .4     STY CV
  5140        JMP MON.VTAB       SET NEW LINE ROW VALUE
  5150 *--------------------------------
  5160 DRCT.OFF
  5170        LDA #3
  5180        STA HOOK+1
  5190        RTS
  5200 *--------------------------------
  5210 CLEAR.BUFFER
  5220        LDY #0             ZERO CONTENTS OF STORAGE BUFFER
  5230        TYA
  5240 .1     STA BUFFER,Y
  5250        INY
  5260        BNE .1
  5270        STA BUF.FLAG       INDICATE NO BUFFER CONTENTS
  5280        RTS
  5290 *--------------------------------
  5300 MOVE.TO.BUFFER
  5310        LDA LNGTH         ANY CHARACTERS IN INBUF?
  5320        BEQ .3            ...NO, RETURN NOW
  5330        PHX                YES. SAVE POSITION WITHIN INBUF
  5340        LDY TOP            MOVE INBUF TO STORAGE BUFFER
  5350        LDX #0
  5360 .1     INY                POINT TO NEXT LOCATION IN BUFFER
  5370        LDA INBUF,X        MOVE INBUF AND PLACE ON TOP
  5380        STA BUFFER,Y
  5390        INX
  5400        CPX LNGTH
  5410        BCC .1
  5420        STA BUF.FLAG       TURN BUFFER FLAG ON
  5430        INY
  5440        STY TOP            MARK NEW POSITION OF TOP
  5450        STY WHERE          AND WHERE WE START AGAIN
  5460        TYX
  5470 .2     STZ BUFFER,X       ZERO OUT ANY RESIDUAL CMNDS
  5480        INX
  5490        LDA BUFFER,X
  5500        BNE .2
  5510        PLX
  5520 .3     RTS
  5530 *--------------------------------
  5540 TRUE.KEYIN
  5550        ASL COL.STATE     40- OR 80-COLUMNS?
  5560        ROR KYBRD         SAVE ANSWER IN KEYBOARD STORAGE BYTE
  5570        BMI .1       ...80
  5580        JMP KEYIN.40
  5590 .1     JMP KEYIN.80
  5600 *--------------------------------
  5610 COMPARE.TAB.CHARS    
  5620        LDA INBUF,X       GET CURRENT CHAR FROM LINE
  5630        LDY #TAB.SZ-1     NUMBER OF TAB CHARACTERS
  5640 .1     CMP TAB.CHARS,Y
  5650        BEQ .2            IF THEY ARE THE SAME, RTN WITH CARRY SET
  5660        DEY               ELSE GO CHK THE NEXT CHAR
  5670        BPL .1            ...MORE IN LIST
  5680        CLC               NO TAB CHARACTERS MATCH SO CLEAR CARRY AND
  5690 .2     RTS                RETURN TO CALLER
  5700 *--------------------------------
  5710 TAB.CHARS    .AS -" ,.;:"
  5720 TAB.SZ .EQ *-TAB.CHARS
  5730 *--------------------------------
  5740 *   COMES HERE DURING PROCESSING OF "RESET"
  5750 *--------------------------------
  5760 RESET.PTCH
  5770        JSR DRCT.OFF
  5780        BIT KYBRD    WAS I IN 80-COLUMN?
  5790        BPL .1       ...NO
  5800        JSR COL80    ...YES
  5810 .1     STZ KSWL     HOOK MYSELF IN
  5820        LDA /HOOK
  5830        STA KSWH
  5840        JMP $3D0     FILLED IN BY INIT CODE
  5850 NORM.RESET .EQ *-2
  5860 *--------------------------------
  5870 KYBRD      .DA #0
  5880 BOC        .BS 1
  5890 BOL        .BS 1
  5900 LNGTH      .DA #0
  5910 INS.FLAG   .DA #0
  5920 BUF.FLAG   .DA #0
  5930 TOP        .DA #0
  5940 WHERE      .DA #0
  5950 CURSOR     .AS -/^/
  5960 CURRCHAR   .BS 1
  5970 *--------------------------------
  5980        .DO *>$9BFF
  5990 ...ERROR:  KEY.EDIT IS LONGER THAN 3 PAGES...
  6000        .ELSE
  6010 BUFFER     .EQ $9C00
  6020        .FIN
  6030 *--------------------------------
  6040        .EP

How to Clear the Back-Up Bit Bob Sander-Cederlof

I received a letter from Paul R. Santa-Maria today, with a very good question: "How is the backup bit in the file access byte cleared in ProDOS 8?" Paul is writing a program that can use the backup bit, but he needs to be able to clear it.

The information about this bit in the various reference manuals is contradictory and incomplete. Apple's ProDOS Technical Reference Manual (even the new ProDOS-8 edition) says:

ProDOS sets bit 5, the backup bit, of the access field to 1 whenever the file is changed (that is, after a CREATE, RENAME, CLOSE after WRITE, or SET_FILE_INFO operation). This bit should be reset to 0 whenever the file is duplicated by a backup program.

Note: ONly ProDOS may change bits 2-4; only backup programs should clear bit 5, using SET_FILE_INFO.

As Paul pointed out in his letter, these two paragraphs contradict each other. Other references to "backup bit" listed in the index did not clear up the difficulty.

Paul noticed that one of the bytes in the System Global Page is called BUBIT (at $BF95). The only explanation of this bit is that it can be changed before MLI calls, and a comment "BACKUP BIT DISABLE, SETFILEINFO ONLY".

Neither of us could find any further information in Apple's manuals, or even in the various third-party books.

I did get some help from the supplement to "Beneath Apple ProDOS", and also from my Apple itself. First I did a search of the ProDOS code while it was in RAM and found two references to $BF95, at $DE7A and at $F7EF. (These are the addresses in Version 1.1.1, and are slightly different from the addresses in Version 1.2, 1.3, and 1.4.) The first reference is at the general exit from all MLI calls, and it stores a zero at $BF95 (BUBIT). The second is inside the SET FILE INFO processor. Here is a piece of the code:

   F7EF-  LDA BUBIT
          EOR #$20
          AND $FE7D       CURRENT ACCESS BITS
          AND #$20        ISOLATE BACKUP BIT
          STA $FEB4

According to the BAP Supplement, $FEB4 is later ORed into the Access Bits, immediately before the update is complete.

Apparently the steps necessary to clear the backup bit are:

  1. read the current file information using GET FILE INFO;
  2. clear the backup bit in the access byte and set at least bit 5 of $BF95 to 1;
  3. and use SET FILE INFO to install the change.

I wrote a test program to perform those steps, and it worked!

My program displays some information, so that I can see what it has done. Line 1170 reads the current file info and displays it in hex. The first byte displayed is the byte with the access bits. Lines 1180-1200 clear bit 5, the backup bit, in the access byte. Line 1210 changes BUBIT ($BF95) from $00 to $FF, so that SET FILE INFO will not set the backup bit. Lines 1220-1240 call MLI to SET FILE INFO. Finally, lines 1260-1380 read the file info and display it again, to see if it worked.

To make my test program simple, I assembled the pathname of a file I knew was on the mounted volume. The pathname is in line 1480. You should substitute here the name of the file you really want to play with.

By the way, there is another way to clear the backup bit. You can read and write directory sectors directly, using the READ_BLOCK and WRITE_BLOCK calls. If you are writing a super snazzy backup program, you may want to do it this way. It can be easier to follow the directory tree using such direct access.

  1000 *SAVE CLEAR.BUBIT
  1010 *--------------------------------
  1020 MLI    .EQ $BF00
  1030 BUBIT  .EQ $BF95
  1040 *--------------------------------
  1050 BELL   .EQ $FBDD
  1060 CROUT  .EQ $FD8E
  1070 PRBYTE .EQ $FDDA
  1080 COUT   .EQ $FDED
  1090 *--------------------------------
  1100        .MA MLI
  1110        JSR MLI
  1120        .DA #]1,]2
  1130        BCS ERROR
  1140        .EM
  1150 *--------------------------------
  1160 CLEAR.BUBIT
  1170        JSR GET.FILE.INFO.AND.DISPLAY.IT
  1180        LDA INFO+3
  1190        AND #$DF          CLEAR BACKUP BIT
  1200        STA INFO+3
  1210        DEC BUBIT         BUBIT = $FF
  1220        LDA #$07
  1230        STA INFO
  1240        >MLI $C3,INFO     SET INFO, CLEARING BUBIT
  1250 *--------------------------------
  1260 GET.FILE.INFO.AND.DISPLAY.IT
  1270        LDA #$0A
  1280        STA INFO
  1290        >MLI $C4,INFO     READ AND DISPLAY NEW INFO
  1300        LDY #3
  1310 .1     LDA INFO,Y
  1320        JSR PRBYTE
  1330        LDA #"."
  1340        JSR COUT
  1350        INY
  1360        CPY #18
  1370        BCC .1
  1380        JMP CROUT
  1390 *--------------------------------
  1400 ERROR  JSR PRBYTE
  1410        JMP BELL
  1420 *--------------------------------
  1430 INFO   .HS 0A
  1440        .DA PATH
  1450        .BS 15
  1460 *--------------------------------
  1470 PATH   .DA #LEN
  1480        .AS /PRODOS/
  1490 LEN    .EQ *-PATH-1
  1500 *--------------------------------

Sean Nolan's Proposed Setup File Standard Bob Sander-Cederlof

Sean Nolan has written a very significant program, and released it to the public domain in the November 1987 issue of Call APPLE. SETUP.SYSTEM is a ProDOS-8 program to give startup features similar to those available in ProDOS-16.

The normal ProDOS-8 boot sequence simply installs the ProDOS image and then loads and runs the first type SYS file found in the main directory whose name ends with ".SYSTEM". Apple puts BASIC.SYSTEM (Applesoft) there, and I put the S-C Macro Assembler (SCASM.SYSTEM) there.

If you install SETUP.SYSTEM as the first SYStem file, it will gain control right after ProDOS is loaded. SETUP.SYSTEM scans the directory for a subdirectory named SETUPS. If one is found, all of the type SYS and type BIN files in that subdirectory will be executed, in the order found in the subdirectory. After all of those files have been executed, SETUP.SYSTEM will go back to the main directory and start up the first SYStem file which follows SETUP.SYSTEM.

I got kind of excited about this program, and took several hours to type it in. I installed it in my RamFactor card, and put PRODRIVE in the SETUPS directory. I have a non-standard clock-calendar card, so I also put a program called FIX.CLOCK in SETUPS which patches ProDOS so it can deal with my clock. You could put all kinds of neat things in there. Sean suggests Bill Basham's Diversi-Cache and Diversi-Hack. The requirements are few:

  1. Programs must not touch RAM between $BD00 and BEFF.
  2. BIN programs must end with an RTS.
  3. SYS programs must end with a QUIT call.
  4. Programs must not go past $B8FF during loading.

I think you will find Sean's program very useful. He suggests developers start using it, without modification so as to maintain compatibliity. Since he put it in the public domain, he has made it fairly easy. I can't list the program here, because it has already been published in Call APPLE. However, I did include the source code on the AAL Monthly Disk for October. I will also list the 512 bytes in hexadecimal here, so you can punch it in the hard way if you want to.

I have printed a checksum for every row of 16 bytes. Of course you don't type in the checksum. Instead, run the program below after typing in all of the bytes. If any of the row checksums is wrong, you know you made a mistake in that row. Sean set his version up with a checksum balancer at the end for the rest of the 512 bytes, so you can check for errors by using the second checksumming program below too. It should give a result of "00" if all the bytes are correct.

Since writing this article, I have discovered that ProDOS-8 (versions 1.3 and later) has a new "secret" feature: before loading and executing the first type "SYS" file named "anything.SYSTEM" it searches the main directory for a type $E2 file named "ATINIT". If ATINIT is there it is loaded at $2000 and called with a JSR. You could BSAVE Sean's program as a type $E2 file named "ATINIT" and save the trouble of making it first in the directory. I haven't tried it, but I think that would work without making any changes to his program at all.

[ For this electronic edition, I have included Sean's program after all.]

  1000  .LIF
  1010 *SAVE S.SETUP.SYSTEM
  1020 *--------------------------------
  1030 *      SETUP.SYSTEM by Sean Nolan
  1040 *   --------------------------------
  1050 *   A Proposed Startup File Standard
  1060 *
  1070 *   Published in Call APPLE, November, 1987
  1080 *   This program is in the public domain.
  1090 *
  1100 *   Converted to S-C Macro Assembler Format
  1110 *   by Bob Sander-Cederlof
  1120 *
  1130 *--------------------------------
  1140        .OR $BD00
  1150        .TA $2000
  1160 *--------------------------------
  1170        .MA MLI
  1180        JSR PRODOS
  1190        .DA #]1,]2
  1200        .EM
  1210 *--------------------------------
  1220 CH         .EQ $24
  1230 *--------------------------------
  1240 IN2        .EQ $280
  1250 FILETYPE   .EQ IN2+16
  1260 AUXCODE    .EQ IN2+31
  1270 *--------------------------------
  1280 RESET      .EQ $3F2
  1290 *--------------------------------
  1300 IOBUFFER   .EQ $B900
  1310 *---System Global Page-----------
  1320 PRODOS     .EQ $BF00
  1330 QUITVECT   .EQ $BF03
  1340 DEVNUM     .EQ $BF30
  1350 BITMAP     .EQ $BF58
  1360 *---Monitor Subroutines----------
  1370 INIT       .EQ $FB2F
  1380 VTABZ      .EQ $FC24
  1390 HOME       .EQ $FC58
  1400 RDKEY      .EQ $FD0C
  1410 SETVID     .EQ $FE93
  1420 SETKBD     .EQ $FE89
  1430 SETNORM    .EQ $FE84
  1440 *--------------------------------
  1450 VOLNAME
  1460        LDX #1
  1470        STX BITMAP+23
  1480        DEX
  1490 .1     LDA $2000,X
  1500        STA $BD00,X
  1510        LDA $2100,X
  1520        STA $BE00,X
  1530        INX
  1540        BNE .1
  1550        DEX
  1560        TXS
  1570        JMP ENTER
  1580 *--------------------------------
  1590 DIRNAME
  1600        .DA #6
  1610        .AS -/SETUPS/
  1620 *--------------------------------
  1630 ENTER
  1640        LDA DEVNUM
  1650        STA ONLINEN
  1660        >MLI $C5,ONLINEP
  1670        LDA VOLNAME+1
  1680        AND #$0F
  1690        TAX
  1700        INX
  1710        STX VOLNAME
  1720        LDA #'/'
  1730        STA VOLNAME+1
  1740        LDA QUITVECT+1
  1750        STA QUITMOD1+1
  1760        LDA QUITVECT+2
  1770        STA QUITMOD2+1
  1780 *--------------------------------
  1790 MAINLOOP
  1800        LDX #2
  1810 .1     LDA JUMP+1,X
  1820        STA RESET,X
  1830        LDA JUMP,X
  1840        STA QUITVECT,X
  1850        DEX
  1860        BPL .1
  1870        TXS
  1880        JSR CLOSE
  1890 *--------------------------------
  1900        LDX #23
  1910        LDA #0
  1920 .2     STA BITMAP,X
  1930        DEX
  1940        BPL .2
  1950        LDA #$CF
  1960        STA BITMAP
  1970        LDA #$07
  1980        STA BITMAP+23
  1990 *--------------------------------
  2000        LDA $C082    LANGUAGE CARD OFF
  2010        STA $C00C    40-COL
  2020        STA $C00E    NORM CHAR SET
  2030        STA $C000    80STORE OFF
  2040        JSR SETNORM
  2050        JSR INIT
  2060        JSR SETVID
  2070        JSR SETKBD
  2080 *--------------------------------
  2090 .3     JSR HOME
  2100        >MLI $C6,PFX2P
  2110        BCC .6       ...VOLUME IS HERE
  2120        LDX #13
  2130 .4     LDA VOLTEXT-1,X
  2140        STA $5A8+4,X
  2150        DEX
  2160        BNE .4
  2170 .5     LDA VOLNAME+1,X
  2180        ORA #$80
  2190        STA $5A8+19,X
  2200        INX
  2210        CPX VOLNAME
  2220        BCC .5
  2230        LDA #35
  2240        STA CH
  2250        LDA #11
  2260        JSR VTABZ
  2270        JSR RDKEY
  2280        JMP .3
  2290 *--------------------------------
  2300 .6     JSR NEXTFILE
  2310        BCS EXITLOOP
  2320 *--------------------------------
  2330        >MLI $C6,PFX1P
  2340        JSR READFILE
  2350 JUMP   JMP MAINLOOP
  2360        .DA /JUMP^$A500
  2370 *--------------------------------
  2380 EXITLOOP
  2390        INC RESET+2
  2400 QUITMOD1   LDA #0
  2410        STA QUITVECT+1
  2420 QUITMOD2   LDA #0
  2430        STA QUITVECT+2
  2440 *--------------------------------
  2450        LDA #0
  2460        STA NUMBER+1
  2470        STA CHEKTYPE+1
  2480        LDA #VOLNAME
  2490        STA NAMEPTR
  2500 .1     JSR NEXTFILE
  2510        BCS .4       ...QUIT
  2520        LDX IN2
  2530        LDY #6
  2540 .2     LDA IN2,X
  2550        CMP SYSTEXT,Y
  2560        BNE .1
  2570        DEX
  2580        DEY
  2590        BPL .2
  2600        INC .3+1
  2610 .3     LDA #$FF
  2620        BEQ .1
  2630        JSR READFILE
  2640 .4     >MLI $65,QUITP
  2650 SYSTEXT    .AS /.SYSTEM/
  2660 *--------------------------------
  2670 NEXTFILE
  2680        >MLI $C8,OPENP
  2690        BCS CLOSE
  2700        LDA OPENN
  2710        STA MARKN
  2720        STA READN
  2730        >MLI $CA,READP
  2740        BCS CLOSE
  2750        LDA IN2+35
  2760        STA ENTSIZE+1
  2770        LDA IN2+36
  2780        STA ENTRIES+1
  2790 NEXTENT
  2800        INC NUMBER+1
  2810 NUMBER LDA #0
  2820        LDX #$FE
  2830 LOOP5  INX
  2840        INX
  2850 ENTRIES    CMP #13
  2860        BCC .1
  2870        SBC ENTRIES+1
  2880        BCS LOOP5
  2890 .1     TAY
  2900        LDA #4
  2910 LOOP10 DEY
  2920        BMI OK2
  2930        CLC
  2940 ENTSIZE ADC #39
  2950        BCC LOOP10
  2960        INX
  2970        BNE LOOP10
  2980 OK2    STA MARK
  2990        STX MARK+1
  3000        >MLI $CE,MARKP
  3010        BCS CLOSE
  3020        >MLI $CA,READP
  3030        BCS CLOSE
  3040        LDA IN2
  3050        BEQ NEXTENT
  3060        AND #$0F
  3070        STA IN2
  3080        LDA FILETYPE
  3090        EOR #$FF
  3100        BEQ CLOSE
  3110 CHEKTYPE
  3120        EOR #$06^$FF
  3130        BNE NEXTENT
  3140 CLOSE  PHP
  3150        >MLI $CC,CLOSEP
  3160        PLP
  3170 ANRTS  RTS
  3180 *--------------------------------
  3190 READFILE
  3200        LDX FILETYPE
  3210        LDA #$20
  3220        INX
  3230        BEQ SETDEST
  3240        LDX AUXCODE
  3250        LDA AUXCODE+1
  3260 SETDEST
  3270        STX READ2D
  3280        STA READ2D+1
  3290        >MLI $C8,OPEN2P
  3300        BCS CLOSE
  3310        LDA OPEN2N
  3320        STA READ2N
  3330        >MLI $CA,READ2P
  3340        JSR CLOSE
  3350        BCS ANRTS
  3360        JMP (READ2D)
  3370 *--------------------------------
  3380 ONLINEP .HS 02
  3390 ONLINEN .BS 1
  3400        .DA VOLNAME+1
  3410 *--------------------------------
  3420 PFX1P  .DA #1,DIRNAME
  3430 PFX2P  .DA #1,VOLNAME
  3440 QUITP  .DA #4,0,0,0
  3450 CLOSEP .DA #1,#0
  3460 *--------------------------------
  3470 OPENP  .DA #3
  3480 NAMEPTR .DA DIRNAME
  3490        .DA IOBUFFER
  3500 OPENN  .BS 1
  3510 *--------------------------------
  3520 MARKP  .DA #2
  3530 MARKN  .BS 1
  3540 MARK   .BS 3
  3550 *--------------------------------
  3560 READP  .DA #4
  3570 READN  .BS 1
  3580        .DA IN2,39,0
  3590 *--------------------------------
  3600 OPEN2P .DA #3,IN2,IOBUFFER
  3610 OPEN2N .BS 1
  3620 *--------------------------------
  3630 READ2P .DA #4
  3640 READ2N .BS 1
  3650 READ2D .DA 0,$B900-$800,0
  3660 *--------------------------------
  3670 VOLTEXT .AS -/INSERT VOLUME/
  3680 *--------------------------------
  3690        .HS E8
  3700 END
  3710 *--------------------------------
  3720        .OR $800
  3730 CS     LDX #0
  3740        TXA
  3750 .1     EOR $2000,X
  3760        INX
  3770        BNE .1
  3780 .2     EOR $2100,X
  3790        INX
  3800        BNE .2
  3810        JSR $FDDA
  3820        RTS

Here is the checksummer program.

  1000 *SAVE S.CHECKSUMMER
  1010 *--------------------------------
  1020 *   Two CHECKSUM programs for testing your
  1030 *   entry of the SETUP.SYSTEM file.  First
  1040 *   BLOAD SETUP.SYSTEM,TSYS,A$2000, and then
  1050 *   execute either CHECKSUM program below.
  1060 *   If you use CS1, compare your results to
  1070 *   those printed in the newsletter.  If you
  1080 *   use CS2, the single result should be 00.
  1090 *--------------------------------
  1100 PNTR   .EQ $00,01
  1110 *--------------------------------
  1120 CROUT  .EQ $FD8E
  1130 PRBYTE .EQ $FDDA
  1140 COUT   .EQ $FDED
  1150 *--------------------------------
  1160 *   CHECKSUM 16 BYTES AT A TIME
  1170 *--------------------------------
  1180 CS1
  1190        LDA #$2000   POINT TO FIRST PAGE TO BE SUMMED
  1200        STA PNTR
  1210        LDA /$2000
  1220        STA PNTR+1
  1230 *--------------------------------
  1240 .1     JSR CROUT    START A NEW LINE
  1250        LDA PNTR+1   PRINT ADDRESS "XXXX-"
  1260        JSR PRBYTE
  1270        LDA PNTR
  1280        JSR PRBYTE
  1290        LDA #"-"
  1300        JSR COUT
  1310        LDY #0       FOR Y = 0 TO 15
  1320 .2     LDA (PNTR),Y      PRINT BYTE AS "XX "
  1330        JSR PRBYTE
  1340        LDA #" "
  1350        JSR COUT
  1360        INY          NEXT Y
  1370        CPY #16
  1380        BCC .2
  1390 *--------------------------------
  1400        JSR COUT     PRINT " ("
  1410        LDA #"("
  1420        JSR COUT
  1430        DEY          Y=15
  1440        LDA #0       FOR Y = 15 TO 0
  1450 .3     EOR (PNTR),Y      SUM = SUM.EOR.BYTE(Y)
  1460        DEY          NEXT Y
  1470        BPL .3
  1480        JSR PRBYTE   PRINT "XX)"
  1490        LDA #")"
  1500        JSR COUT
  1510 *--------------------------------
  1520        CLC          BUMP POINTER TO NEXT GROUP
  1530        LDA PNTR          OF 16 BYTES
  1540        ADC #16
  1550        STA PNTR
  1560        LDA PNTR+1
  1570        ADC #0
  1580        STA PNTR+1
  1590        CMP /$2200   AT END YET?
  1600        BCC .1       ...NO
  1610        RTS          ...YES, FINISHED
  1620 *--------------------------------
  1630 *   CHECKSUM ENTIRE 512 BYTES
  1640 *--------------------------------
  1650 CS2
  1660        LDX #0
  1670        TXA
  1680 .1     EOR $2000,X
  1690        INX
  1700        BNE .1
  1710 .2     EOR $2100,X
  1720        INX
  1730        BNE .2
  1740        JSR PRBYTE
  1750        RTS
  1760 *--------------------------------
2000- A2 01 8E 6F  BF CA BD 00  20 9D 00 BD  BD 00 21 9D  (8B)
2010- 00 BE E8 D0  F1 CA 9A 4C  21 BD 06 D3  C5 D4 D5 D0  (36)
2020- D3 AD 30 BF  BD BF BE 20  00 BF C5 BE  BE AD 01 BD  (36)
2030- 29 0F AA E8  8E 00 BD A9  2F 8D 01 BD  AD 04 BF 8D  (7B)
2040- D2 BD AD 05  BF 8D D7 BD  A2 02 BD CB  BD 9D F2 03  (98)
2050- BD CA BD 9D  03 BF CA 10  F1 9A 20 85  BE A2 17 A9  (5D)
2060- 00 9D 58 BF  CA 10 FA A9  CF 8D 58 BF  A9 07 8D 6F  (1A)
2070- BF AD 82 C0  8D 0C C0 8D  0E C0 9D 00  C0 20 84 FE  (45)

2080- 20 2F FB 20  93 FE 20 90  FE 20 58 FC  20 00 BF C6  (33)
2090- C5 BE 90 28  A2 0D BD F1  BE 9D AC 05  CA D0 F7 BD  (FA)
20A0- 01 BD 09 80  9D BB 05 E8  EC 00 BD 90  F2 A9 23 85  (C2)
20B0- 24 A9 0B 20  24 FC 20 0C  FD 4C 90 BD  20 15 BE BO  (EC)
20C0- 0D 20 00 BF  C6 C2 BE 20  9E BE 4C 48  BD 18 EE F4  (83)
20D0- 03 A9 00 8D  04 BF A9 00  8D 05 BF A9  00 8D 3E BE  (A6)
20E0- 8D 82 BE A9  00 8D D2 BE  20 15 BE B0  1B AE 80 02  (F5)
20F0- A0 06 BD 80  02 D9 0E BE  D0 EE CA 88  10 F4 EE 02  (84)

2100- BE A9 FF F0  E3 20 8E BE  20 00 BF 65  C8 BE 2E 53  (1A)
2110- 59 53 54 45  4D 20 00 BF  C8 Dl BE B0  68 AD D6 BE  (73)
2120- 8D D8 BE 8D  DD BE 20 00  BF CA DC BE  B0 57 AD A3  (DB)
2130- 02 8D 54 BE  AD A4 02 8D  44 BE EE 3E  BE A9 00 A2  (7C)
2140- FE E8 E8 C9  0D 90 05 ED  44 BE B0 F5  A8 A9 04 88  (70)
2150- 30 08 18 69  27 90 F8 E8  D0 F5 8D D9  BE 8E DA BE  (DB)
2160- 20 00 BF CE  D7 BE B0 1D  20 00 BF CA  DC BE B0 15  (07)
2170- AD 80 02 F0  C5 29 0F 8D  80 02 AD 90  02 49 FF F0  (4A)

2180- 04 49 F9 D0  B5 08 20 00  BF CC CF BE  28 60 AE 90  (8D)
2l90- 02 A9 20 E8  F0 06 AE 9F  02 AD A0 02  8E EC BE 8D  (F8)
21A0- ED BE 20 00  BF C8 E4 BE  B0 DB AD E9  BE 8D EB BE  (17)
2lB0- 20 00 BF CA  EA BE 20 85  BE B0 D2 6C  EC BE 02 00  (44)
21C0- 01 BD 01 1A  3D 01 00 BD  04 00 00 00  00 00 00 01  (A3)
21D0- 00 03 1A BD  00 B9 00 02  00 00 00 00  04 00 80 02  (99)
21E0- 27 00 00 00  03 80 02 00  B9 00 04 00  00 00 00 B1  (AA)
2lF0- 00 00 C9 CE  D3 C5 D2 D4  A0 D6 CF CC  D5 CD C5 E8  (57)

Apple Assembly Line (ISSN 0889-4302) is published monthly by S-C SOFTWARE CORPORATION, P. O. Box 280300, Dallas, TX 75228 Phone (214) 324-2050. Subscription rate is $18 per year in the USA, sent Bulk Mail; add $3 for First Class postage in USA, Canada, and Mexico; add $14 postage for other countries. Back issues are $1.80 each for Volumes 1-7 (other countries inquire for postage). A subscription to the newsletter and the Monthly Disk containing all source code is $64 per year in the USA, Canada and Mexico, and $87 to other countries.

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.)