Volume 4 -- Issue 1 | October 1983

In This Issue...

- Compilation of Monitor Modifications
- Still More Tinkering with VCR
- Corrections to the Generic Screen Dump
- Price Changes
- Duplicated Ideas and Red Faces
- Faster Booting for ScreenWriter II
- Large Assembly Listing into Text File
- Avoiding EXTRA DEFINITION ERROR
- Lower Case Titles in Version 1.1
- Suppressing Unwanted Object Bytes
- Where To?
- Macro-Calculated Spiral Screen Clear
- Counting Lines
- If You Like Shapes, Try Shapemaker
- Index to Volumes 1-3

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 Modifications | Steve 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:

- Allow lowercase input -- nullify conversion of lowercase to uppercase, make cursor over lowercase character to uppercase inverse (since Apple doesn't have inverse or flashing lowercase). (From Videx Keyboard Enhancer II Manual, page 4.)
- Non-flashing cursor -- Make cursor inverse instead of flashing. (From Videx Keyboard Enhancer II Manual, page 4.)
- Inverse + cursor when in escape mode -- to indicate IJKM is active. (By Donald W. Miller, Jr., Call-APPLE Mar 83 pp 51-52.)
- ASCII dump -- display both hex and ASCII values. (By Peter Bartlett, AAL Dec 81 pp 18-20, and Bruce Field, AAL Jul 83 page 20.)
- Mask -- XXYY<ADR1.ADR2W masks bytes in memory range, ANDing with XX and ORing with YY. (By Bob Sander-Cederlof, AAL Dec 82 pp 10-11.)
- Search -- XXYY<ADR1.ADR2S searches memory range for XXYY, printing addresses of matches. If XXYY is in the range $00-$FF, only one byte will be compared; otherwise both bytes will be compared during the search. (By Steve Knouse)

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 VCR | Louis 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 Dump | Bob 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 Changes | Bob 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 Faces | Bob 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 II | Bob 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 File | Robert 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 ERROR | Bill 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.1 | Bob 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.)

TITLE | Bob 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 Clear | Bruce 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 Lines | Bill 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 Shapemaker | Bob 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:

- Shape Editor
- Shape Table Editor
- Nine &-routines, including
  - Clear any window in the hi-res page
  - Display string of shapes
  - Input anything
- 44-page manual
- Source Code of &-routines in S-C format
- Unprotected, copyable, modifiable

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