Apple Assembly Line
Volume 4 -- Issue 1October 1983

In This Issue...

Index to Apple Assembly Line

Why haven't we ever published an index to AAL?, you ask. Now that there are three year's worth of back issues to dig through for that article you know you saw a while back, wouldn't a true index come in handy? Well here it is! The 12 center pages of this issue are a complete index to volumes 1 through 3 of Apple Assembly Line. That's October, 1980 through September, 1983, all at your fingertips. The index is placed in the center of this issue so that, if you wish, you can easily remove those pages and store them separately.

More Applesoft Variable Cross Reference

In this issue Louis Pitz presents us with still more tinkering with the old Applesoft Variable Cross Reference. Now that the program has been modified a couple of times, and since it appeared way back in the second issue of Apple Assembly Line, we'll include the complete source code, including all of Louis' enhancements, on the next Quarterly Disk. Remember that all of the back issues are still available, if you don't have Volume 1, Number 2.

New Basis Version 1.1 Available

If any of you are using the S-C Macro Assembler with a Basis 108 computer, Bob Matzinger has adapted version 1.1 for you. Call us for the upgrade price. (214) 324-2050.


A Compilation of Monitor ModificationsSteve Knouse

Over the years since I bought my Apple I have been collecting various handy modifications to the Apple Monitor. I wanted a convenient way to load up all my patches so that they would be there when I needed them.

Let me point out right now that the following set of patches will NOT work in an Apple //e. They are only for the Apple II Plus monitor. Anyway, several of my favorite patches are already implemented in the Apple //e; the others may fit, but I haven't tried them.

There are two basic ways to get a modified monitor into an Apple. The first requires burning an EPROM with the new version, modifying the motherboard to accept an EPROM in the F8 ROM socket, and plugging it in. (Rather than cutting and splicing the motherboard, a better way is to use a PROMETTE from Computer Micro Works.) The second way is to run out of a language card (16K RAM Card), with a modified monitor at F800 in the RAM card. Some RAM cards may not allow this, leaving the motherboard F8 ROM always switched on, but all the ones I have tried work. If you want to use Applesoft with the modified monitor, or patch Applesoft as well, you can copy it up into the language card too.

I combined my favorite patches with Bill Morgan's patch program (see "PATCHER: General Purpose Patch Installer", AAL, April, 1983) so that BRUNning the program copies the motherboard monitor into a RAM card and then installs all the patches.

The listing that follows uses the .PH and .EP directives found in Version 1.1 of the S-C Macro Assembler. .PH starts a phase, and .EP ends one. At the start of a phase the current assembler origin is saved and the address from the .PH is substituted. Code continues to be assembled into the target file or at the target address, and the saved origin is incremented along with the phase origin. At the end of the phase the saved origin is restored. This allows me to assemble a series of patches with the correct addresses all into one big target file.

Here is a list of my favorite patches:

I included several conditional assembly options, using the .DO, .ELSE, and .FIN directives. These let you select or reject the non-flashing cursor patch and the lowercase display patch. The third option allows you to copy Applesoft from the motherboard along with the monitor, or just the monitor by itself.

  1000 *SAVE S.KNOUSE'S MONITOR PATCHES
  1010 *--------------------------------
  1020 *
  1030 *  A COMPILATION OF MONITOR MODIFICATIONS
  1040 *--------------------------------
  1050 YES        .EQ 1
  1060 NO         .EQ 0
  1070 *
  1080 *  OPTIONS
  1090 *
  1100 NFC        .EQ YES  SET TO YES IF YOU WANT
  1110 *                   A NON-FLASHING CURSOR
  1120 LOWERCASE  .EQ YES  SET TO YES IF YOU CAN
  1130 *                   DISPLAY LOWER CASE
  1140 W.APPLESOFT .EQ YES SET TO YES IF YOU WANT
  1150 *                   TO MOVE APPLESOFT WITH
  1160 *                   THE MONITOR, ELSE SET
  1170 *                   TO NO IF YOU ONLY WANT
  1180 *                   TO MOVE AND MODIFY THE
  1190 *                   MONITOR
  1200 *--------------------------------
  1210 PNTR   .EQ $00,01
  1220 PATCH  .EQ $02,03
  1230 A1L    .EQ $3C
  1240 A1H    .EQ A1L+1
  1250 A2L    .EQ $3E
  1260 A2H    .EQ A2L+1
  1270 A4L    .EQ $42
  1280 A4H    .EQ A4L+1
  1290 BASL   .EQ $28
  1300 CH     .EQ $24
  1310 KSWL   .EQ $38  
  1320 *--------------------------------
  1330 COUT       .EQ $FDED      
  1340 CRMON      .EQ $FEF6
  1350 CROUT      .EQ $FD8E
  1360 MON.HEADR  .EQ $FCC9
  1370 MON.MOVE   .EQ $FE2C
  1380 NXTA1      .EQ $FCBA
  1390 PRA1       .EQ $FD92
  1400 PRBYTE     .EQ $FDDA
  1410 PRERR      .EQ $FF2D
  1420 RDKEY      .EQ $FD0C
  1430 MON.READ   .EQ $FEFD
  1440 MON.WRITE  .EQ $FECD
  1450 *--------------------------------
  1460 ROMR.RAMW  .EQ $C081
  1470 RAMRW      .EQ $C083
  1480 *--------------------------------
  1490 *
  1500 *  GENERAL PURPOSE PATCHER
  1510 *
  1520 *--------------------------------
  1530        .OR $2D0
  1540        .DO W.APPLESOFT
  1550            .TF PATCH MONITOR & APPLESOFT
  1560 MON.START  .EQ $D000
  1570        .ELSE
  1580            .TF PATCH MONITOR ONLY
  1590 MON.START  .EQ $F800
  1600        .FIN
  1610 MON.END    .EQ $FFFF
  1620 *--------------------------------
  1630 PATCH.MONITOR
  1640        LDA #MON.START    COPY MONITOR TO RAM CARD
  1650        STA A4L
  1660        STA A1L
  1670        LDA /MON.START    
  1680        STA A4H
  1690        STA A1H
  1700        LDA #MON.END
  1710        STA A2L
  1720        LDA /MON.END
  1730        STA A2H
  1740        LDA ROMR.RAMW     WRITE ENABLE RAM CARD
  1750        LDA ROMR.RAMW     BY 2 OF THESE
  1760        LDY #0            SET UP MON.MOVE
  1770        JSR MON.MOVE      COPY FROM MOTHERBOARD TO RAMCARD
  1780 *
  1790        LDA #PATCHES-1
  1800        STA PNTR
  1810        LDA /PATCHES-1
  1820        STA PNTR+1
  1830        LDY #0
  1840 *
  1850 .1     JSR GET.BYTE LENGTH OF NEXT PATCH
  1860        BEQ .4
  1870        TAX          SAVE LENGTH IN X
  1880        JSR GET.BYTE GET ADDR OF PATCH
  1890        STA PATCH
  1900        JSR GET.BYTE
  1910        STA PATCH+1
  1920 *
  1930 .2     JSR GET.BYTE    GET A BYTE
  1940        STA (PATCH),Y   STORE AT DESTINATION
  1950        INC PATCH       BUMP SOURCE ADDRESS
  1960        BNE .3
  1970        INC PATCH+1
  1980 .3     DEX             DECREMENT NUMBER OF BYTES
  1990        BNE .2          LOOP FOR MORE
  2000        BEQ .1      ... ALWAYS
  2010 *
  2020        .DO W.APPLESOFT
  2030 .4     LDA RAMRW 
  2040        RTS
  2050        .ELSE
  2060 .4     RTS
  2070        .FIN
  2080 *--------------------------------
  2090 GET.BYTE
  2100        INC PNTR
  2110        BNE .1
  2120        INC PNTR+1
  2130 .1     LDA (PNTR),Y
  2140        RTS
  2150 *--------------------------------
  2160        .MA PATCH
  2170 ]1.ORG .EQ ]2
  2180        .DA #]1.LENGTH
  2190        .DA ]1.ORG
  2200        .PH ]1.ORG
  2210 ]1
  2220        .EM
  2230 *
  2240        .MA ENDP
  2250 ]1.END .EQ *-1
  2260 ]1.LENGTH  .EQ *-]1
  2270        .EP
  2280        .EM
  2290 *--------------------------------
  2300 PATCHES    .EQ *    
  2310 *--------------------------------
  2320 *  MONITOR LOWERCASE INPUT ROUTINE
  2330 *--------------------------------
  2340 *
  2350 *---DON'T STOMP ON LOWERCASE-----
  2360     >PATCH NOP.CONVERT,$FD82
  2370        AND #$FF     DO NOTHING
  2380     >ENDP  NOP.CONVERT
  2390 *
  2400 *---MAKE SENSIBLE CURSOR---------
  2410     >PATCH HANDLE.CURSOR,$FBB3
  2420        CMP #$E0     IS IT LOWER CASE?
  2430        BCS .1
  2440        AND #$3F     NO - MAKE CHAR INVERSE
  2450        .DO NFC
  2460        ORA #$00
  2470        .ELSE
  2480        ORA #$40     THEN FLASHING
  2490        .FIN
  2500        RTS
  2510 .1     AND #$1F     CONVERT TO UC INVERSE
  2520        RTS
  2530     >ENDP  HANDLE.CURSOR
  2540 *
  2550 *---CALL NEW CURSOR ROUTINE------
  2560     >PATCH VEC.HANDLE.CURSOR,$FD11
  2570        JSR HANDLE.CURSOR  GO TO PATCH
  2580        NOP          FILL BYTE
  2590     >ENDP  VEC.HANDLE.CURSOR
  2600 *--------------------------------
  2610 *  ASCII DUMP
  2620 *--------------------------------
  2630 *
  2640 *---MODIFIED DUMPER--------------
  2650     >PATCH ASC.DUMP,MON.HEADR 
  2660        PHA          SAVE CHAR
  2670        LDA A1L      GET LO ADDR BYTE
  2680        AND #$07     MOD 8
  2690        CLC          ADD DISPLACEMENT
  2700        ADC #30        OF 30 CHAR
  2710        TAY
  2720        PLA          RECOVER CHARACTER
  2730        PHA          SAVE IT AGAIN
  2740        ORA #$80     FORCE NORMAL VIDEO
  2750        CMP #$A0     MAKE CONTROL CHAR INVERSE
  2760        BCS .1       ...NOT CONTROL
  2770        .DO LOWERCASE
  2780        AND #$7F     ...CONTROL
  2790 .1     STA (BASL),Y PUT ON SCREEN
  2800        NOP          TO STAY ALIGNED W/
  2810        NOP          NON-LOWERCASE CODE
  2820        NOP
  2830        NOP
  2840        NOP
  2850        NOP
  2860        .ELSE
  2870        LDA #$DF     MAKE CTRL-CHARS INVERSE
  2880 .1     CMP #$E0     IN LOWER CASE RANGE?
  2890        BCC .2       ..NO, DISPLAY NORMAL VIDEO
  2900        AND #$1F     ..YES, FORCE INVERSE VIDEO
  2910 .2     STA (BASL),Y STORE IT ON SCREEN
  2920        .FIN
  2930        LDY #0       RESTORE Y REG
  2940        PLA          RECOVER BYTE AGAIN
  2950        JMP PRBYTE
  2960     >ENDP  ASC.DUMP
  2970 *
  2980 *---CALL ASCII DUMP--------------
  2990     >PATCH VEC.ASC.DUMP,$FDBD
  3000        JSR ASC.DUMP
  3010     >ENDP  VEC.ASC.DUMP
  3020 *--------------------------------
  3030 *   + CURSOR IN ESCAPE MODE
  3040 *--------------------------------
  3050 *
  3060 *---SAVE SCREEN, SPOT + ---------
  3070     >PATCH RDKEY2,ASC.DUMP.END+1
  3080        LDY CH       SAVE CHARACTER
  3090        LDA (BASL),Y
  3100        PHA
  3110        LDA #'+      PUT AN INVERSE + ON SCREEN
  3120        STA (BASL),Y
  3130        PLA          GET THE CHARACTER BACK
  3140        JMP (KSWL)
  3150        .BS RDKEY-*  FILL W/ 0'S TO RDKEY
  3160     >ENDP  RDKEY2
  3170 *
  3180 *---CALL + CURSOR----------------
  3190     >PATCH VEC.RDKEY2.1,$FBA2
  3200        JSR RDKEY2
  3210     >ENDP  VEC.RDKEY2.1
  3220 *
  3230 *---CALL + CURSOR----------------
  3240     >PATCH VEC.RDKEY2.2,$FD2F
  3250        JSR RDKEY2
  3260     >ENDP  VEC.RDKEY2.2
  3270 *--------------------------------
  3280 *   MASK BIT CONTROL OVER MEMORY RANGE
  3290 *   XXYY<ADR1.ADR2W   FORMS M=(M.AND.XX).OR.YY
  3300 *--------------------------------
  3310 *
  3320     >PATCH WRITE,MON.WRITE
  3330        LDA (A1L),Y  GET A BYTE
  3340        AND A4H      AND IT WITH XX
  3350        ORA A4L      OR  IT WITH YY
  3360        STA (A1L),Y  PUT IT BACK
  3370        JSR NXTA1    INCR ADDRESS
  3380        BCC WRITE    LOOP FOR MORE
  3390        RTS
  3400        .BS CRMON-*  FILL W/ 0'S TO CRMON
  3410     >ENDP  WRITE
  3420 *--------------------------------
  3430 *   SEARCH
  3440 *   XXYY<ADR1.ADR2S 
  3450 *--------------------------------
  3460 *
  3470 *---SEARCH PROCESSOR-------------
  3480     >PATCH SEARCH,MON.READ 
  3490        LDA A4H      IS THIS A 1 OR 2 BYTE COMPARE
  3500        BEQ .2       ..ONE BYTE
  3510        LDA A2L      ..TWO BYTE
  3520        BNE .1       DECREMENT ENDING ADDR
  3530        DEC A2H
  3540 .1     DEC A2L
  3550 *
  3560 .2     LDA A4H      GET FIRST BYTE TO COMPARE
  3570        BEQ .3       IF ZERO DO A ONE BYTE SEARCH
  3580        CMP (A1L),Y  COMPARE WITH MEMORY
  3590        BNE .4       NOT EQUAL - GO TO NEXT BYTE
  3600        INY          GET NEXT BYTE
  3610 .3     LDA (A1L),Y  
  3620        LDY #0       RESTORE Y REG
  3630        CMP A4L      COMPARE
  3640        BNE .4       NOT EQUAL - DRIVE ON
  3650        JSR PRA1
  3660 .4     JSR NXTA1    GET NEXT BYTE
  3670        BCC .2       LOOP FOR MORE
  3680        RTS
  3690        .BS PRERR-*  FILL W/ 0'S TO PRERR
  3700     >ENDP  SEARCH
  3710 *
  3720 *---PATCH COMMAND TABLE----------
  3730     >PATCH VEC.SEARCH,$FFDE
  3740        .DA #$EC     'S' EOR $B0 + $89
  3750     >ENDP  VEC.SEARCH
  3760 *--------------------------------
  3770        .DA #0       END OF PATCHES   
  3780 *--------------------------------
  3790 END    .EQ *-1
  3800 LENGTH .EQ END-PATCH.MONITOR+1
  3810        .LIST OFF

Still More Tinkering with VCRLouis Pitz
De Witt, Iowa

I finally figured out how to modify the Applesoft Variable Cross Reference (from the November, 1980 AAL) to distinguish between defined functions and array variables. As Bob mentioned at that time, VCR tags an occurence of FN AB(whatever) as an appearance of the array variable AB().

It turns out that the changes needed aren't many, and are compatible with my tinkering in the August '83 AAL, which added 80-column output to a printer.

As VCR is scanning for variables, in the GET.NEXT.VARIABLE section, add the check for the FN token in lines 2132-2134. If found, go to lines 2222-2228 to set a flag and go back to get the NEXT.CHAR.NOT.QUOTE. Unless the Applesoft program is in error, a variable name immediately follows the FN token.

In PACK.VARIABLE.NAME, the program distinguishes variables by VARNAM+2 having a space, $, or %. Array variables have the high bit set. In lines 2791-2796 I set apart FN variables by placing a dash (-) with the high bit set in VARNAM+2. This will make FN types come after the others alphabetically.

Now we come to the printing stage, in PRINT.LETTER.CHAIN. There the variable name (and dash, in case of FN types) is printed. If the high bit of VARNAM+2 is set, lines 4292-4294 check for the dash value. If so, skip to lines 4511-4515 and print out "FN" also.

This way, FN AB will come out as "AB-FN", which is a bit of a cop-out on my part. But I opted for making minimal changes to VCR to keep things simple.

If you play with long programs also having defined functions, as I have, these additions to VCR should help.

[ Now that the Variable Cross Reference program has been modified a couple of times, and since it appeared way back in the second issue of Apple Assembly Line, we'll include the complete source code, including all of Louis' enhancements, on the next Quarterly Disk. Remember that all of the back issues are still available, if you don't have Volume 1, Number 2. ...Bill ]

     2132        CMP $#C2
     2134        BEQ .4

     2222 .4     STA $7       set FLAG2
     2224        BEQ .1       ...always
     2226 *  unless syntax error, NEXT.CHAR.NOT.QUOTE
     2228 *  will be letter, hence variable!

     2791        LDA $7       recall FLAG2
     2792        CMP #$C2     FN token?
     2793        BNE .5       (to RTS)
     2794        LDA #'-+80   "-"
     2795        STA VARNAM+2 to indicate FN
     2796        STA $7       and reset FLAG2

     4292        CMP #$AD     not array, but FN?
     4294        BEQ .6

     4511 .6     LDA #'F      add 'FN' after
     4512        JSR PRINT.CHAR
     4513        LDA #'N      variable name
     4514        JSR PRINT.CHAR
     4515        BNE .4       ...always

Here is the complete program with the revisions in line:

  1000 *---------------------------------
  1010 *      VARIABLE CROSS REFERENCE
  1020 *       FOR APPLESOFT PROGRAMS
  1030 *---------------------------------
  1040 ZZ.BEG .EQ $8800
  1050        .OR ZZ.BEG
  1060        .TF B.VCRP
  1070 *---------------------------------
  1080        LDA #$4C     AMPERSAND VECTOR
  1090        STA $3F5
  1100        LDA #VCR
  1110        STA $3F6
  1120        LDA /VCR
  1130        STA $3F7
  1140        RTS
  1150 *---------------------------------
  1160 PNTR   .EQ $18,19   POINTER INTO PROGRAM
  1170 DATA   .EQ $1A THRU $1D
  1180 LZFLAG .EQ $1A      LEADING ZERO FLAG
  1190 NEXTLN .EQ $1A,1B   ADDRESS OF NEXT LINE
  1200 LINNUM .EQ $1C,1D   CURRENT LINE NUMBER
  1210 STPNTR .EQ $1E,1F   POINTER INTO VARIABLE TABLE
  1220 TPTR   .EQ $9B,9C   TEMP POINTER
  1230 SYMBOL .EQ $9D THRU $A4  8 BYTES
  1240 VARNAM .EQ SYMBOL+1
  1250 HSHTBL .EQ $280
  1260 ENTRY.SIZE .EQ $A5,A6
  1270 *---------------------------------
  1280 PRGBOT .EQ $67,68   BEGINNING OF PROGRAM
  1290 LOMEM  .EQ $69,6A   BEGINNING OF VARIABLE SPACE
  1300 EOT    .EQ $6B,6C   END OF VARIABLE TABLE
  1310 *---------------------------------
  1320 TKN.REM    .EQ 178
  1330 TKN.DATA   .EQ 131
  1340 *---------------------------------
  1350 MON.CH     .EQ $24
  1360 MON.PRBL2  .EQ $F94A
  1370 MON.COUT   .EQ $FDED
  1380 MON.CROUT  .EQ $FD8E
  1390 *---------------------------------
  1400 VCR
  1410        JSR INITIALIZATION
  1420 .1     JSR PROCESS.LINE
  1430        BNE .1       UNTIL END OF PROGRAM
  1440        JSR PRINT.REPORT
  1450        JSR INITIALIZATION  ERASE VARIABLE TABLE
  1452        LDA #0       CLEAR $A4 SO APPLESOFT WILL
  1454        STA $A4      WORK CORRECTLY
  1460        RTS
  1470 *---------------------------------
  1480 INITIALIZATION
  1490        LDA LOMEM
  1500        STA EOT
  1510        LDA LOMEM+1
  1520        STA EOT+1
  1530        LDX #52      # OF BYTES FOR HASH POINTERS
  1540        LDA #0
  1550 .1     STA HSHTBL-1,X
  1560        DEX
  1570        BNE .1
  1580        LDA PRGBOT
  1590        STA PNTR
  1600        LDA PRGBOT+1
  1610        STA PNTR+1
  1620        RTS
  1630 *---------------------------------
  1640 PROCESS.LINE
  1650        LDY #3       CAPTURE POINTER AND LINE #
  1660 .1     LDA (PNTR),Y
  1670        STA DATA,Y
  1680        DEY
  1690        BPL .1
  1692        LDA DATA+1   CHECK IF END
  1694        BEQ .3       YES
  1700        CLC          SKIP OVER DATA
  1710        LDA PNTR
  1720        ADC #4
  1730        STA PNTR
  1740        BCC .2
  1750        INC PNTR+1
  1760 .2     JSR SCAN.FOR.VARIABLES
  1770        LDA DATA
  1780        STA PNTR
  1790        LDA DATA+1
  1800        STA PNTR+1
  1810 *      BNE .3
  1820 .3     RTS
  1830 *---------------------------------
  1840 SCAN.FOR.VARIABLES
  1850 .1     JSR GET.NEXT.VARIABLE
  1860        BEQ .3       END OF LINE
  1870        JSR PACK.VARIABLE.NAME
  1880        JSR SEARCH.VARIABLE.TABLE
  1890        BCC .2       FOUND SAME VARIABLE
  1900        LDA #0
  1910        STA SYMBOL+4 START OF LINE NUMBER CHAIN
  1920        STA SYMBOL+5
  1930        LDA LINNUM+1 MSB FIRST
  1940        STA SYMBOL+6
  1950        LDA LINNUM
  1960        STA SYMBOL+7
  1970        LDA #8       ADD 8 BYTE ENTRY
  1980        JSR ADD.NEW.ENTRY
  1990        JMP .1
  2000 .2     JSR SEARCH.LINE.CHAIN
  2010        BCC .1       FOUND SAME LINE NUMBER
  2020        LDA #4       ADD 4 BYTE ENTRY
  2030        JSR ADD.NEW.ENTRY
  2040        JMP .1
  2050 .3     RTS
  2060 *---------------------------------
  2070 GET.NEXT.VARIABLE
  2080 .1     JSR NEXT.CHAR.NOT.QUOTE
  2090        BEQ .2       END OF LINE
  2100        CMP #TKN.DATA
  2110        BEQ .3
  2120        CMP #TKN.REM
  2130        BEQ .2       SKIP TO NEXT LINE
  2132        CMP #$C2     FN token?
  2134        BEQ .4
  2140        JSR LETTER   LETTER?
  2150        BCC .1       NO, KEEP LOOKING
  2160 .2     RTS
  2170 *   DATA, SO SKIP TO NEXT STATEMENT
  2180 .3     JSR NEXT.CHAR.NOT.QUOTE
  2190        BEQ .2       EOL, RETURN
  2200        CMP #':      COLON?
  2210        BNE .3       NOT END YET
  2220        BEQ .1       ...ALWAYS
  2222 .4     STA $7       set FLAG2
  2224        BEQ .1       ...always
  2226 *  unless syntax error, NEXT.CHAR.NOT.QUOTE
  2228 *  will be letter, hence variable!
  2230 *---------------------------------
  2240 NEXT.CHAR.NOT.QUOTE
  2250 .1     JSR NEXT.CHAR
  2260        BEQ .2       EOL, RETURN
  2270        CMP #'"      QUOTE?
  2280        BEQ .3       YES, SCAN OVER QUOTATION
  2290 .2     RTS          RETURN
  2300 .3     JSR NEXT.CHAR
  2310        BEQ .2       EOL, RETURN
  2320        CMP #'"      TERMINAL QUOTE?
  2330        BNE .3       NOT YET
  2340        BEQ .1       ...ALWAYS
  2350 *---------------------------------
  2360 *      NEXT CHARACTER FROM LINE
  2370 *        CALL:  JSR NEXT.CHAR
  2380 *      RETURN:  (A)=CHAR FROM LINE
  2390 *               IF CHAR .NE. EOL,
  2400 *                   INCREMENT PNTR AND
  2410 *                   STATUS Z=0
  2420 *               IF CHAR .EQ. EOL,
  2430 *                   STATUS Z=1
  2440 *---------------------------------
  2450 NEXT.CHAR
  2460        LDY #0
  2470        LDA (PNTR),Y
  2480        BEQ .1       EOL
  2490        INC PNTR     BUMP POINTER
  2500        BNE .1
  2510        INC PNTR+1
  2520 .1     RTS
  2530 *---------------------------------
  2540 PACK.VARIABLE.NAME
  2550        STA VARNAM   FIRST CHAR OF NAME
  2560        LDA #'       BLANKS FOR OTHER TWO CHARS
  2570        STA VARNAM+1
  2580        STA VARNAM+2
  2590        JSR NEXT.CHAR
  2600        BEQ .5       END OF LINE
  2610        JSR LTRDIG
  2620        BCC .2       NOT LETTER OR DIGIT
  2630        STA VARNAM+1
  2640 .1     JSR NEXT.CHAR IGNORE EXCESS NAME
  2650        BEQ .5       END OF LINE
  2660        JSR LTRDIG
  2670        BCS .1       LETTER OR DIGIT
  2680 .2     CMP #'$      DOLLAR SIGN?
  2690        BEQ .3       YES
  2700        CMP #'%      PER CENT?
  2710        BNE .4       NO
  2720 .3     STA VARNAM+2
  2730        JSR NEXT.CHAR
  2740        BEQ .5       END OF LINE
  2750 .4     CMP #'(      LEFT PAREN?
  2752        BEQ .6       YES
  2754        CMP #'"      QUOTE?
  2760        BNE .5       NO
  2762        LDA PNTR     YES, BACK UP POINTER
  2763        BNE .7
  2764        DEC PNTR+1
  2765 .7     DEC PNTR
  2766        RTS
  2770 .6     LDA VARNAM+2 SET HIGH BIT
  2780        ORA #$80     TO FLAG ARRAY
  2790        STA VARNAM+2 REFERENCE
  2791        LDA $7       recall FLAG2
  2792        CMP #$C2     FN token?
  2793        BNE .5       (to RTS)
  2794        LDA #'-+$80  "-"
  2795        STA VARNAM+2 to indicate FN
  2796        STA $7       and reset FLAG2
  2800 .5     RTS
  2810 *---------------------------------
  2820 SEARCH.VARIABLE.TABLE
  2830        SEC          CONVERT 1ST CHAR TO
  2840        LDA VARNAM   HASH TABLE INDEX
  2850        SBC #'A
  2860        ASL
  2870        ADC #HSHTBL
  2880        STA STPNTR
  2890        LDA /HSHTBL
  2900        ADC #0
  2910        STA STPNTR+1
  2920 *---   FALL INTO CHAIN SEARCH ROUTINE
  2930 *---------------------------------
  2940 CHAIN.SEARCH
  2950 .1     LDY #0       POINT AT POINTER IN ENTRY
  2960        LDA (STPNTR),Y
  2970        STA TPTR
  2980        INY
  2990        LDA (STPNTR),Y
  3000        BEQ .4       END OF CHAIN, NOT IN TABLE
  3010        STA TPTR+1
  3020        LDX #2       2 MORE CHARS IN SYMBOL
  3030        LDY #2       POINT AT NAME IN ENTRY
  3040 .2     LDA (TPTR),Y COMPARE NAMES
  3050        CMP SYMBOL,Y
  3060        BCC .3       NOT THIS ONE, BUT KEEP LOOKING
  3070        BNE .4       NOT IN THIS CHAIN
  3080        DEX
  3090        BEQ .5       NAME IS THE SAME
  3100        INY          NEXT BYTE PAIR
  3110        BNE .2       ...ALWAYS
  3120 *---------------------------------
  3130 .3     JSR .5       UPDATE POINTER, CLEAR CARRY
  3140        BCC .1       ...ALWAYS
  3150 *---------------------------------
  3160 .4     SEC          DID NOT FIND
  3170        RTS
  3180 *---------------------------------
  3190 .5     LDA TPTR
  3200        STA STPNTR
  3210        LDA TPTR+1
  3220        STA STPNTR+1
  3230        CLC
  3240        RTS
  3250 *---------------------------------
  3260 ADD.NEW.ENTRY
  3270        STA ENTRY.SIZE
  3280        CLC          SEE IF ROOM
  3290        LDX #1
  3300        LDY #0
  3310        STY ENTRY.SIZE+1
  3320 .1     LDA (STPNTR),Y  GET CURRENT POINTER
  3330        STA SYMBOL,Y
  3340        LDA EOT,Y
  3350        STA (STPNTR),Y
  3360        STA TPTR,Y
  3370        ADC ENTRY.SIZE,Y
  3380        STA EOT,Y
  3390        INY
  3400        DEX
  3410        BPL .1
  3420 *---   SEE IF GOING TO BE ENOUGH ROOM
  3430        LDA EOT
  3440        CMP #ZZ.BEG
  3450        LDA EOT+1
  3460        SBC /ZZ.BEG
  3470        BCS .3       MEM FULL ERR
  3480 *---   MOVE ENTRY INTO VARIABLE TABLE
  3490        LDY ENTRY.SIZE
  3500        DEY
  3510 .2     LDA SYMBOL,Y
  3520        STA (TPTR),Y
  3530        DEY
  3540        BPL .2
  3550        LDA TPTR
  3560        STA STPNTR
  3570        LDA TPTR+1
  3580        STA STPNTR+1
  3590        RTS
  3600 .3     JMP MEM.FULL.ERR
  3610 MEM.FULL.ERR
  3620        BRK
  3630 *---------------------------------
  3640 SEARCH.LINE.CHAIN
  3650        CLC          ADJUST POINTER TO START
  3660        LDA STPNTR   OF LINE # CHAIN
  3670        ADC #4
  3680        STA SYMBOL
  3690        LDA STPNTR+1
  3700        ADC #0
  3710        STA SYMBOL+1
  3720        LDA #SYMBOL
  3730        STA STPNTR
  3740        LDA /SYMBOL
  3750        STA STPNTR+1
  3760        LDA LINNUM   PUT LINE NUMBER INTO SYMBOL
  3770        STA SYMBOL+3
  3780        LDA LINNUM+1
  3790        STA SYMBOL+2
  3800        JMP CHAIN.SEARCH
  3810 *---------------------------------
  3820 PRINT.REPORT
  3830        LDA #'A      START WITH A'S
  3840 .1     STA VARNAM
  3850        SEC
  3860        SBC #'A      CONVERT TO HSHTBL INDEX
  3870        ASL
  3880        TAY
  3890        LDA HSHTBL+1,Y
  3900        BEQ .2       NO ENTRY FOR THIS LETTER
  3910        STA PNTR+1
  3920        LDA HSHTBL,Y
  3930        STA PNTR
  3940        JSR PRINT.LETTER.CHAIN
  3950 .2     INC VARNAM   NEXT LETTER
  3960        LDA VARNAM
  3970        CMP #'Z+1
  3980        BCC .1       STILL MORE LETTERS
  3990        RTS          FINISHED
  4000 *---------------------------------
  4010 LTRDIG
  4020        CMP #'0      DIGIT?
  4030        BCC LD1      NO
  4040        CMP #'9+1
  4050        BCC LD2      YES
  4060 LETTER
  4070        CMP #'A      LETTER?
  4080        BCC LD1      NO
  4090        CMP #'Z+1
  4100        BCC LD2      YES
  4110        CLC          NO
  4120 LD1    RTS
  4130 LD2    SEC
  4140        RTS
  4150 *---------------------------------
  4160 PRINT.LETTER.CHAIN
  4170 .1     LDA VARNAM   FIRST LETTER
  4180        JSR PRINT.CHAR
  4190        LDY #1
  4200 .2     INY
  4210        LDA (PNTR),Y REST OF NAME
  4220        AND #$7F
  4230        CMP #'       BLANK?
  4240        BEQ .3
  4250        JSR PRINT.CHAR
  4260 .3     CPY #3
  4270        BCC .2
  4280        LDA (PNTR),Y CHECK IF ARRAY
  4290        BPL .4
  4292        CMP #$AD     not array, but FN?
  4294        BEQ .6
  4300        LDA #'(
  4310        JSR PRINT.CHAR
  4320 .4     CLC          POINT AT LINE # CHAIN
  4330        LDA PNTR
  4340        ADC #4
  4350        STA TPTR
  4360        LDA PNTR+1
  4370        ADC #0
  4380        STA TPTR+1
  4390        JSR PRINT.LINNUM.CHAIN
  4400        JSR MON.CROUT
  4410        LDY #1
  4420        LDA (PNTR),Y POINTER TO NEXT VARIABLE
  4430        BEQ .5       NO MORE
  4440        PHA
  4450        DEY
  4460        LDA (PNTR),Y
  4470        STA PNTR
  4480        PLA
  4490        STA PNTR+1
  4500        BNE .1       ...ALWAYS
  4510 .5     RTS
  4511 .6     LDA #'F      add 'FN' after
  4512        JSR PRINT.CHAR
  4513        LDA #'N      variable name
  4514        JSR PRINT.CHAR
  4515        BNE .4       ...always
  4520 *---------------------------------
  4530 PRINT.LINNUM.CHAIN
  4534        LDA #0       reset counter to 0
  4538        STA $6       for each variable
  4540 .1     JSR TAB.NEXT.COLUMN
  4550        LDY #2       POINT AT LINE #
  4560        LDA (TPTR),Y
  4570        STA LINNUM+1
  4580        INY
  4590        LDA (TPTR),Y
  4600        STA LINNUM
  4610        JSR PRINT.LINE.NUMBER
  4620        LDY #1       SET UP NEXT POINTER
  4630        LDA (TPTR),Y
  4640        BEQ .2
  4650        PHA
  4660        DEY
  4670        LDA (TPTR),Y
  4680        STA TPTR
  4690        PLA
  4700        STA TPTR+1
  4710        BNE .1       ...ALWAYS
  4720 .2     RTS
  4730 *---------------------------------
  4740 TAB.NEW.LINE
  4750        JSR MON.CROUT
  4760 TAB.NEXT.COLUMN
  4770 .1     LDA #7       FIRST TAB STOP
  4780 .2     CMP MON.CH   CURSOR POSITION
  4790        BCS .3       PERFORM TAB
  4800        ADC #6       NEXT TAB STOP
  4810        CMP #33      END OF LINE?
  4820        BCC .2
  4821        INC $6       count the screen line
  4822        LDA $6
  4823        AND #1       look at odd-even bit
  4824        BEQ TAB.NEW.LINE  both scrn and printer
  4834        LDA #$8D
  4835        JSR $FDF0    <CR> to screen only
  4836        JMP .1       ...always
  4840 .3     BEQ .4       ALREADY THERE
  4850        SBC MON.CH   CALCULATE # OF BLANKS
  4860        TAX
  4870        JSR MON.PRBL2
  4880 .4     RTS
  4890 *---------------------------------
  4900 PRINT.LINE.NUMBER
  4910        LDX #4       PRINT 5 DIGITS
  4920        STX LZFLAG   TURN ON LEADING ZERO FLAG
  4930 .1     LDA #'0      DIGIT=0
  4940 .2     PHA
  4950        SEC
  4960        LDA LINNUM
  4970        SBC PLNTBL,X
  4980        PHA
  4990        LDA LINNUM+1
  5000        SBC PLNTBH,X
  5010        BCC .3       LESS THAN DIVISOR
  5020        STA LINNUM+1
  5030        PLA
  5040        STA LINNUM
  5050        PLA
  5060        ADC #0       INCREMENT DIGIT
  5070        BNE .2       ...ALWAYS
  5080 .3     PLA
  5090        PLA
  5100        CMP #'0
  5110        BEQ .5       ZERO, MIGHT BE LEADING
  5120        SEC          TURN OFF LZFLAG
  5130        ROR LZFLAG
  5140 .4     JSR PRINT.CHAR
  5150        DEX
  5160        BPL .1
  5170        RTS
  5180 .5     BIT LZFLAG   LEADING ZERO FLAG
  5190        BMI .4       NO
  5200        LDA #'       BLANK
  5210        BNE .4       ...ALWAYS
  5220 PLNTBL .DA #1
  5230        .DA #10
  5240        .DA #100
  5250        .DA #1000
  5260        .DA #10000
  5270 PLNTBH .DA /1
  5280        .DA /10
  5290        .DA /100
  5300        .DA /1000
  5310        .DA /10000
  5320 *---------------------------------
  5330 PRINT.CHAR
  5340        ORA #$80
  5350        JSR MON.COUT
  5360        RTS
  5370 *---------------------------------
  5380 ZZ.END .EQ *
  5390 ZZ.SIZ .EQ ZZ.END-ZZ.BEG

Corrections to the Generic Screen DumpBob Sander-Cederlof

Steve Knouse called to thank us for printing his Generic Screen Dump program last month, and to chew us out for garbling it.

It seems that we edited and renumbered the code, but didn't update the line number references in the text.

Here's a table to translate what the article says into what it means:

     Says      Means

     1610      1100

     2030      1460

     2190      1620
     2250      1680
     2260      1690
     2270      1700
     2280      1710
     2290      1720
     2300      1730
     2310      1740

Sorry about that, readers. Sorry about that, Steve.

[ And another last-minute correction -- the TAY instruction in line 1510 should be a TYA. ]


Price ChangesBob Sander-Cederlof

It has been nearly two years since we raised the price of a subscription from $12 to $15 per year, and now we are forced to another increase. Effective January 1, 1984, a year's subscription by bulk mail in the USA will be $18. For First Class Mail in the USA, Canada, and Mexico, add $3. Subscriptions to other countries, including postage, will be $30 per year.

You can beat the price by renewing early. All renewals received before January 1st will be at the old rates.

Now for some good news! We want to reduce our inventory of back issues, so we are offering some special prices. We normally sell them for $1.50 each; between now and January 1st you can buy them for only $1 each!

We want to encourage more of you to save your time and energy by getting the Quarterly Disks, with all the source code from three issues already correctly entered. Each Quarterly Disk costs only $15. To save even more trouble, and some $$$, you can subscribe to the Quarterly Disks. Effectively immediately, prepaid subscriptions for four Quarterly Disks will be only $45. You save 25%!

Continuing in the Christmas spirit, here are some more specials good through the end of this year, only for subscribers to Apple Assembly Line:

                                     Regular  Special
       FLASH! Integer BASIC Compiler   $79      $50
       The Visible Computer: 6502      $50      $40
       ES-CAPE                         $60      $40
       S-C Math Disk & Game Disk Set   $35      $20
       Laumer's Full Screen Editor     $49      $40

Duplicated Ideas and Red FacesBob Sander-Cederlof

I suppose it had to happen at least once in three years, but it still came as a shock.

Last June I wrote and published a program and article called Amper-Monitor, and then I did it all over again for the September issue. The programs are slightly different, both in design and implementation, but they still do the same thing.

Maybe now that we have a complete index to the first three volumes I won't make this mistake again.


Faster Booting for ScreenWriter IIBob Leedom
Glenwood, Maryland

I have found a solution to ScreenWriter II's long boot-up time (which is one of my few complaints with the product). Would you believe a reduction from 46 seconds to just under 14 seconds?

The solution was given in a patch to DOS 3.3 given by Paul Schlyter and Bob Sander-Cederlof in the April 1983 issue of AAL. Since ScreenWriter's DOS is nearly identical to 3.3, I was inspired to try the patch (on ONE of my two copy-protected original disks) -- and it worked!

I installed the patch between lines 50 and 60 of APP2 (ScreenWriter's customizeable startup program). The POKEs will only be performed at startup -- if you look closely at APP2, you'll see that the POKEing lines will be skipped when the program is used to switch between Editor and Runoff in the non-RAMcard version.

To install the patch, do the following: 1. From BASIC, LOAD APP2 2. Type in Lines 51 - 59, carefully! 3. SAVE APP2 4. RUN CUSTOMIZEA

That's it! You will now have a fast-booting ScreenWriter. You may also want to do this to some of your normal DOS 3.3 disks -- the patch is in an unused area of DOS, and seems to coexist happily with everything else I tried (like PLE and GPLE for instance). Exception: in the //e version of DOS 3.3, the patch screws up the infamous APPEND command -- no great loss, in my opinion.

51 READ N: IF N=0 THEN 59:REM Make this "THEN 60" (60 is the next ScreenWriter II line) when line 59 is DELETEd
52 READ A: SUM = SUM + A + N
53 FOR I = 1 TO N: READ P: POKE A,P: A=A+1: SUM=SUM+P: NEXT
54 GOTO 51
55 DATA 44, 47721, 173, 230, 181, 208, 36, 173, 194, 181, 240, 31, 173, 203, 181, 72, 173, 204, 181, 72, 173, 195, 181, 141, 203, 181, 173, 196, 181, 141, 204, 181, 32, 182, 176, 176, 3, 76, 223, 188, 76, 111, 179, 76, 150, 172
56 DATA 33, 48351, 238, 228, 181, 208, 3, 238, 229, 181, 238, 196, 181, 238, 204, 181, 206, 194, 181, 208, 11, 104, 141, 204, 181, 104, 141, 203, 181, 76, 150, 172, 76, 135, 186
57 DATA 2, 44198, 105, 186
58 DATA 0
59 IF SUM <> 153114 THEN PRINT "OOPS! DATA IS OFF BY "153114-SUM: STOP: REM (Delete this line when you are SURE it works!)

Large Assembly Listing into Text FileRobert F. O'Brien
Dublin, Ireland

I liked the procedure for getting listings into a text file during assembly (AAL July '83). However, it won't work if the file is too large and requires .IN directives. I recently did a large assembly using the following source code:

     0      .DU
     1      .TF LISTING
     2      .IN PART1
     3      .IN PART2
     4      .ED

What I expected to get was a 356-sector text file on disk, but all I got was a 2-sector file -- the code for PART1 and PART2 was not sent to the disk (they did list to the screen!)

I first tried to solve my particular problem by making more RAM available for the assembly by moving the Symbol Table base down to $400. I thought that should work, since I use an 80-column card and not the Apple's text screen. However, the assembler and the system monitor had other ideas, and promptly destroyed the symbol table by scrolling the screen memory.

However, I did manage to get my large assembly listing to go to disk as a text file -- by doing it in two parts. I used a utility program from the assembler disk to give each part the missing label definitions from the other part.

The steps are as follows:

1) Assemble the code normally with .IN directives.

     0001       .IN PART1
     0002       .IN PART2

2) BRUN B.MAKE EQUATE FILE (from the S-C Macro Version 1.1 Disk.) That creates a file of .EQ statements called SYMBOLS which contains all the normal labels and values from the Symbol Table in memory.

3) Merge SYMBOLS with PART1 and delete all duplicate labels from the SYMBOLS section.

4) Assemble PART1 using the .DU-.TF-.ED trick, and using .LIST OFF/ON so that the SYMBOLS section does not write to the text file.

5) Repeat steps 3 and 4 on PART2.

It is a bit laborious deleting all the duplicate labels in the two assemblies. I hope someone can suggest a patch to the assembler to prevent it from reporting "EXTRA DEFINITION ERROR". That certainly would make this listing process easier.


Avoiding EXTRA DEFINITION ERRORBill Morgan
Dublin, Ireland

No sooner said...

OK, here are some patches to defeat the check for double definitions in the S-C Macro Assemblers. Just put an RTS ($60) at the appropriate location:

Version 1.0 -- Motherboard: $221D Language Card: $E369

Version 1.1 -- Motherboard: $210E Language Card: $E228

Be very certain that any double definitions are intentional and identical. If you use the same label with two different values (unless it's defined with .SE) the assembler cannot produce correct code.


Lower Case Titles in Version 1.1Bob Matzinger

A simple one-byte patch will enable you to use lower-case letters inside .TI titles. There are eight versions of the assembler on the Version 1.1 release disk, and the byte to be changed is in a different place for each version.

The code for the .TI directive looks the same wherever it is located. Here is a hex dump of the code, with a square around the byte to be changed:

       A2 00     LDX #0
       20 3E x2  JSR $123E or $D23E
       C9 2C     CMP #$2C
       D0 0D     BNE ...

       20 3E x2  JSR $123E or $D23E

       B0 08     BCS ...
       9D 70 01  STA $170,X       

The following table shows the address of the byte to be changed:

   File Name             x = 1000     x = D000
                         --------     --------
S-C.ASM.MACRO.x            $2CE6        $EE00
S-C.ASM.MACRO.x.E          $2CC2        $EDDC
S-C.ASM.MACRO.x.STB80      $2DDA        $EEFD
S-C.ASM.MACRO.x.VIDEX      $2DB1        $EED4

Once you find the right byte, which contains $3E, change it to $4E. (Remember to change a byte in the RAM card you need to write-enable it first.)


TITLEBob Sander-Cederlof
Suppressing Unwanted Object Bytes

Sometimes we want to get an assembly listing that doesn't use up half a page of paper for each .AS or .HS line, listing three object bytes on each line. A number of you have asked for a patch to show the source line without listing each and every one of those hex bytes.

Well, David Roberts, a subscriber in Australia, has come up with a simple way to do just that. He uses macros! David suggests these definitions:

       .MA AS
       .AS -"]1"
       .EM

       .MA AT
       .AT "]1"
       .EM

       .MA HS
       .HS "]1"
       .EM

Now you can code text with >AS "THIS IS MY STRING", and use the .LIST MOFF option to suppress the hex listing. That's really a "why didn't I think of that?" Thanks, David.


Where To?Bill Morgan

The word is that the new Macintosh machine from Apple is going to be 68000-based and affordable. I know that I am going to want one, and I would like to get a leg up on learning the machine, so I'm starting to study 68000. It looks like a lot of fun. With seventeen registers addressing 16 megabytes at 12 megaHertz or thereabouts, we should be able to do just about anything we want. I'll have a review next month of a new 68000 trainer board for your Apple, at about half the price of the existing 68000 boards.

To get to the point, how many of you good folks out there are interested in 68000? How many of you already know a little or a lot about it? Should we start a new newsletter about Macintosh? Should we devote a few pages of this one to it? Let us hear from you.

And another thing, how about C language? Several of you have mentioned that great August issue of Byte and expressed an interest in learning more about C. I know that I'm going to study up on it. There is a good C compiler available for the Apple, the Aztec C Compiler System from Manx Software. I'll have a review of it in the next month or two, and we may start carrying it for sale. Let me know if you're interested.


Macro-Calculated Spiral Screen ClearBruce V. Love
Hamilton, New Zealand

Here is what I think is a beautiful example of using nested recursive macros with the new .SE directive to calculate the addresses for a Spiral Screen Clear.

The macro SPIRAL calls, in order, LEFT, BOTTOM, RIGHT, and TOP to produce the code to handle each side of the screen. Each of those macros adjusts the appropriate X or Y coordinate and then calls GETADR to calculate the addresses and actually assemble the next instruction pair.

This program won't win any prizes for fast assembly: I timed it at almost 4 minutes. You could speed up the process by rewriting the BOTTOM and TOP macros. They really don't have to call GETADR for all the calculation, they only need to increment or decrement the addresses, but that destroys the symmetry of the original.

  1000        .TF CLEAR
  1010        .LIST OFF
  1020 *--------------------------------
  1030        .MA SPIRAL
  1040        >LEFT             move left side up
  1050 BOTLFT .SE BOTLFT-1        and move corner up
  1060        >BOTTOM           move bottom left
  1070 BOTRGT .SE BOTRGT-1        and move corner left
  1080        >RIGHT            move right side down
  1090 TOPRGT .SE TOPRGT+1        and move corner down
  1100        >TOP              move top right
  1110 TOPLFT .SE TOPLFT+1        and move corner right
  1120        .DO TOPLFT<13     done?
  1130        >SPIRAL           no, do it again
  1140        .FIN
  1150        .EM
  1160 *--------------------------------
  1170        .MA GETADR
  1180 ADRTO  .SE ADRFRM
  1190 BLOCK  .SE Y.CORD/8      hi, mid, or low, 0-2
  1200 BLK.AD .SE BLOCK*$28     block offset
  1210 TEMP   .SE BLOCK*8
  1220 LINE   .SE Y.CORD-TEMP   line within block, 0-7
  1230 LIN.AD .SE LINE*$80      line offset
  1240 ADRFRM .SE $400+BLK.AD+LIN.AD+X.CORD
  1250        LDA ADRFRM
  1260        STA ADRTO
  1270        .EM
  1280 *--------------------------------
  1290        .MA LEFT
  1300 Y.CORD .SE Y.CORD+1      down one step
  1310        >GETADR
  1320        .DO Y.CORD<BOTLFT done?
  1330        >LEFT             no, again
  1340        .FIN
  1350        .EM
  1360 *--------------------------------
  1370        .MA BOTTOM
  1380 X.CORD .SE X.CORD+1      right one step
  1390        >GETADR
  1400        .DO X.CORD<BOTRGT done?
  1410        >BOTTOM           no, again
  1420        .FIN
  1430        .EM
  1440 *--------------------------------
  1450        .MA RIGHT
  1460 Y.CORD .SE Y.CORD-1      up one step
  1470        >GETADR
  1480        .DO Y.CORD>TOPRGT done?
  1490        >RIGHT            no, again
  1500        .FIN
  1510        .EM
  1520 *--------------------------------
  1530        .MA TOP
  1540 X.CORD .SE X.CORD-1      left one step
  1550        >GETADR
  1560        .DO X.CORD>TOPLFT done?
  1570        >TOP              no, again
  1580        .FIN
  1590        .EM
  1600 *--------------------------------
  1610 BOTLFT .SE 23       bottom left Y coord
  1620 BOTRGT .SE 39       bottom right X coord
  1630 TOPRGT .SE 0        top right Y coord
  1640 TOPLFT .SE 1        top left X coord
  1650 X.CORD .SE 0        start with upper
  1660 Y.CORD .SE 0          left corner
  1670 ADRFRM .SE $400
  1680 *--------------------------------
  1690        LDX #960     do the loop 960 times
  1700        LDY /960
  1710        LDA #$A0     put space in center
  1720        STA $5B4
  1730 LOOP   >SPIRAL      do one spiral
  1740 END    DEX
  1750        BNE .1       branch if not done
  1760        DEY
  1770        BPL .1
  1780        JMP $3D0     exit to DOS
  1790 .1     JMP LOOP     go spiral again

I have also produced a faster version of the program. This one uses self-modifying code to avoid shifting the already-cleared bytes on the screen. It's interesting to watch the self-modifying version accelerate as it moves fewer bytes each time through the loop. To produce the faster version, just replace the code from line 1680 on with this new code:

  1680 POINTER .EQ 0
  1690 *--------------------------------
  1700        LDY #0       no indexing
  1710        LDA #END     start pointer at end of code
  1720        STA POINTER
  1730        LDA /END
  1740        STA POINTER+1
  1750 .2     JSR LOOP     do one step
  1760        LDA #$AD     restore LDA code
  1770        STA (POINTER),Y
  1780 *--------------------------------
  1790        LDA POINTER  decrement pointer
  1800        SEC          by 6
  1810        SBC #6
  1820        STA POINTER
  1830        BCS .1
  1840        DEC POINTER+1
  1850 .1     LDA #$60     insert RTS code
  1860        STA (POINTER),Y
  1870 *--------------------------------
  1880        LDA POINTER  compare pointer
  1890        CMP #LOOP    to beginning of code
  1900        BNE .2
  1910        LDA POINTER+1
  1920        SBC /LOOP
  1930        BNE .2       branch if not yet done
  1940 *--------------------------------
  1950 FIXUP  LDA #$AD     restore LDA
  1960        STA LOOP      at beginning
  1970        LDA #$60     and RTS
  1980        STA END       at end
  1990        JMP $3D0     and reenter DOS
  2000 *--------------------------------
  2010 SAVE   .DA #$A0     <space> to fill screen
  2020 *--------------------------------
  2030 LOOP   >SPIRAL
  2040        LDA SAVE
  2050        STA $5B4
  2060 END    RTS

Counting LinesBill Morgan

When Bob and I were first looking at Bruce Love's version of the Spiral Screen Clear, we got to wondering just how many lines actually were being processed by the assembler. With all those nested recursive macros, the total was bound to be in the thousands. Here's a little filter program I threw together to do a count:

     0000-          1000 COUNT.LO .EQ 0
     0001-          1010 COUNT.HI .EQ 1
     0036-          1020 OUTHOOK  .EQ $36
     03EA-          1030 DOSHOOK  .EQ $3EA
                    1040 *--------------------------------
                    1050        .OR $300
                    1060  
     0300- A9 00    1070        LDA #0
     0302- 85 00    1080        STA COUNT.LO      zero the counters
     0304- 85 01    1090        STA COUNT.HI
     0306- A9 11    1100        LDA #LINE.COUNTER
     0308- 85 36    1110        STA OUTHOOK       direct output
     030A- A9 03    1120        LDA /LINE.COUNTER to my routine
     030C- 85 37    1130        STA OUTHOOK+1
     030E- 4C EA 03 1140        JMP DOSHOOK
                    1150 *--------------------------------
                    1160 LINE.COUNTER
     0311- C9 8D    1170        CMP #$8D          carriage return?
     0313- D0 06    1180        BNE .1            no, exit
     0315- E6 00    1190        INC COUNT.LO      yes, count it
     0317- D0 02    1200        BNE .1
     0319- E6 01    1210        INC COUNT.HI
     031B- 60       1220 .1     RTS

I assembled that code at $300, and then used these commands to set the PRT vector:

     :$C083 C083 D009:4C 0 3 N C080

(For the motherboard versions of the S-C Assemblers, you only need to type :$1009:4C 0 3)

With that in place just load a source file, set .LIST ON, type PRT, and then type ASM. When the assembly is finished, type PR#0 to get the output back to the screen. Now you can type :$0.1 to look at the counters. You might also want to put a .LIST OFF line at the end of your program, so the count won't include the Symbol Table.

By the way, when the macros are expanded those 80 lines of Bruce's program produce 13,593 lines of code, or enough to fill over 200 pages of printout.


If You Like Shapes, Try ShapemakerBob Sander-Cederlof

Frank Belanger sent me a copy of his new Hi-Res utility program, called SHAPEMAKER. I know, there are a lot of these on the market, such as Accu-Shapes and Apple Mechanic. Frank's is priced between those two, at $35, and look at all you get:

If these features interest you, write Frank at 4200 Avenue B, Austin, TX 78751. Or call (512) 451-6868.


Apple Assembly Line is published monthly by S-C SOFTWARE CORPORATION, P.O. Box 280300, Dallas, Texas 75228. Phone (214) 324-2050. Subscription rate is $15 per year in the USA, sent Bulk Mail; add $3 for First Class postage in USA, Canada, and Mexico; add $13 postage for 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.)