Volume 3 -- Issue 11 | August 1983

In This Issue...

- Using Auxiliary Memory in the //e
- 65C02
- Speeding Up Spirals
- Tinkering With Variable Cross Reference
- Reversing, Getting, and Putting Nybbles
- Odds and Ends
- Some Small Patches
- More 68000 Boards
- Bringing Some Patches Together
- "One more beep and you're out!"

Mailing AAL

Let's review how AAL is mailed, when you should expect to receive it, and what to do about it when you don't. Most of you get your newletter by Bulk Mail, which is a little erratic. You should receive your issue around the third week of each month, but don't start worrying until the end of the month. If you haven't received an issue by the end of the month, call or write and we'll send a replacement. The Post Office does not forward Bulk Mail, so make certain to tell us if you move. Those of you who have First Class Mail subscriptions should receive your issue around the tenth of the month, and certainly before the twentieth.

The number in the upper right corner of your mailing label is the expiration date of your subscription. If that number is 8308, you're holding your last issue and better renew now. We send out postcards when your subscription is about to expire, and when it has expired. All you have to do is send us a check, or phone with a charge card number, and we'll keep your AAL coming.

Using Auxiliary Memory in the //e | David C. Johnson Ridgefield, CT

When I bought my Apple //e (3 days after they became available!), I also got the Extended 80-Column Text Card. I wanted it both to have 80 column text capability and a full complement of Apple Computer Inc. supported memory. However, Apple only supplied two small subroutines in ROM and incomplete (but otherwise excellent) documentation in their manuals, in "support" of the auxiliary memory.

I say "incomplete" because two I/O locations that I used in my program are not mentioned (in English anyway) anywhere in the manuals except in the listings of the 80-column firmware. The two I/O locations are $C011 & $C012 which I call READ.BSR.BANK & READ.BSR.RAM.READ. Apple evidently intends to let software developers determine how the auxiliary memory is to be used.

Well here goes: my program is called "USE.AUXMEM". This program allows you to access the "other" 64K in a manner most Apple users should already be familiar with: monitor commands.

The simplest way to see what I mean is to type in & assemble the program (not so simple), type :"MGO G", :"PR#3" and then :"$^Y" (that is control-Y). You will get a bell and the monitor's prompt. Any monitor commands you type now will "use" the auxiliary memory. Try these now:

           *3D0:55
           *3D0     (double nickels, right?)
           *^Y      (back to SCASM!)
           :$3D0    (a $4C!)

You should note that control-Y while using the auxiliary memory returns to main memory with everything as it was. Now try these:

           :$^Y 3D0
           *3D0 ^Y

After the second control-Y returned to main memory, SCASM finished the first command line!

The reason I had you type :"PR#3" before is quite simple: things don't all work right without the 80 column firmware active; specifically, right-arrow & escape functions. You can also type "escape 4" if you don't want 80 columns.

But wait a minute, if you read the 80-column firmware listing (carefully), you know that it does NOT work with the auxiliary memory enabled (as doesn't the regular 40-column firmware), so how is this all working? Well, the I/O hooks in the auxiliary memory zero page point to routines in USE.AUXMEM which switch to main memory, perform the I/O, switch back to auxiliary memory, and return to the monitor. The monitor executes its commands between I/O calls while auxiliary memory is enabled. These switchings also change the bank switched memory state.

The USE.AUXMEM program has two other control-Y commands. They implement the crossbank subroutines AUXMOVE & XFER (supplied in ROM) as monitor commands. See the comments at the top of the source listing for their syntax.

About Some //e Monitor Bugs...

One routine, USE.AUXMEM.CONTROL.Y.HANDLER, deserves a special note. It compensates for a bug in the Apple //e version of the monitor: when parsing a control-Y command the ASCII string "Bryan" at $FEC5 is executed as instructions prior to JMPing to USRADR ($03F8). This bug has a long history.

In the original Apple monitor the CHRSRCH loop ($FF78 - $FF81) scans the CHRTBL ($FFCC - $FFE2) from end to beginning, which matches the $B2 at $FFCD causing TOSUB ($FFBE - $FFCB) to load the $C9 at $FFE4 and RTS to USR ($FECA) which is a JMP USRADR ($03F8).

Things started to go astray when the autostart ROM was created, and the Apple II Plus. To make room for new features, (like printing "APPLE ][" at the top of the screen on power up, and like the escape-IJKM cursor motion), the TRACE and STEP commands were removed. To disable the entries for Trace and Step in CHRTBL, the bytes for "T" and "S" were changed: ($FFCF:B2 & $FFD2:B2, also $FFE9:C4). Locations $FEC5 - $FEC9, immediately prior to USR, were changed to NOPs.

Unfortunately, someone forgot that CHRTBL is searched from end to beginning, causing a control-Y command to be matched with the $B2 at $FFD2, corresponding to the branch address in SUBTBL at $FFE9. So when you type a control-Y command the monitor branches to $FFC5 and executes the 5 NOPs. If $FFE9 had been changed to $C9 instead of $C4, everything would have still been fine.

Executing 5 NOPs is not a bad bug. But when the Apple //e monitor was created those 5 NOPs were replaced by the string "Bryan". In hex it is C2 F2 F9 E1 EE. The 6502 instruction set does not include a definition for $C2, but after a little investigation, or after reading Bob Sander-Cederlof's article in AAL March 1981, you find out that $C2 acts like a two-byte NOP. The "r" is skipped over. The "yan", however, is a SBC $EEE1,Y instruction.

The USE.AUXMEM.CONTROL.Y.HANDLER uses the passed contents of the A & X registers to decide which of the three control-Y commands you've typed. The SBC $EEE1,Y changes the A register so its contents must be reconstructed. The reconstruction is further complicated by the fact that the monitor leaves the carry flag set when it RTS's to $FEC5, while the S-C Assembler and Mini-Assembler leave the carry flag clear.

To restore the A register to its proper value you must set the carry to the complement of the value that it was set to prior to the SBC $EEE1,Y then execute ADC $EEE1,Y.

The Apple //e 80 column firmware also contains a bug. Because of the $11 at $C92A, the key sequence "ESCape ^L" causes a RTS to $4CCE. Location $C92A should contain a $10. This bug can be used to advantage if you feel like adding a secret command to your own software. Just be certain you have the code for your command starting at $4CCE, and that you are running in 80-column mode. Then whenever you type control-L in the escape mode (cursor is an inverse plus) your code will be executed.

I hope all of you enjoy using your auxiliary memory as much as I do.

Last Minute Note: David just called to report yet another oddity in the //e ROMs. In 40-column ESCape mode the (, 5, *, and + keys duplicate the arrow keys. That is, "ESC 5" moves the cursor right one space, just like ESC right arrow. This is a little bit weird, but it doesn't seem to hurt anything. The effect is caused by an unnecessary AND #$DF instruction at $C26E.

      1000 *SAVE JOHNSON'S USE AUXMEM
      1010 *--------------------------------
      1020 * SWITCH.MIND Command:  ^Y
      1030 *
      1040 *   When in main bank, enters monitor in
      1050 *   auxmem BSR (hooks I/O through main
      1060 *   and brings USE.AUXMEM to auxmem too)
      1070 *   When in aux bank, returns to main bank
      1080 *   Best used w/80 column firmware active
      1090 *--------------------------------
      1100 * USE.AUXMOVE Command:  DEST<SOURCE.END^Y{CARRY}
      1110 *
      1120 *   DEST      = Destination in one bank
      1130 *   SOURCE    = Start in other bank
      1140 *   END       = End in other bank
      1150 *   CARRY     = Direction of move
      1160 *               (1 = Main Ram-->Card Ram)
      1170 *               (0 = Card Ram-->Main Ram)
      1180 *   DEST, SOURCE, & END must be: >=$0200 & <=$BFFF
      1190 *--------------------------------
      1200 * USE.XFER Command:  ADDRESS^Y{CARRY}{OVERFLOW}
      1210 *
      1220 *   ADDRESS   = Transfer address
      1230 *   CARRY     = Desired 48K Bank ($0200 - $BFFF)
      1240 *               (1 = Use 48K in Card Ram)
      1250 *               (0 = Use 48K in Main Ram)
      1260 *   OVERFLOW  = Desired ZP/STK/BSR
      1270 *               (1 = Use ZP/STK/BSR in Card Ram)
      1280 *               (0 = Use ZP/STK/BSR in Main Ram)
      1290 *   If using USE.XFER from auxmem, routine in main mem
      1300 *   MUST LDX BANK.SP.SAVE, TXS if it uses the stack at all
      1310 *--------------------------------
      1320 MON.BASL         .EQ $28,$29
      1330 MON.YSAV         .EQ $34
      1340 MON.CSWL         .EQ $36,$37
      1350 MON.KSWL         .EQ $38,$39
      1360 MON.A1           .EQ $3C,$3D   Source,Address
      1370 MON.A2           .EQ $3E,$3F   End
      1380 MON.A4           .EQ $42,$43   Dest
      1390 MON.STATUS       .EQ $48
      1400 *--------------------------------
      1410 IN                       .EQ $0200 - $02FF
      1420 BANK.X.SAVE              .EQ $03CC
      1430 BANK.BSR.BANK.SAVE       .EQ $03CD
      1440 BANK.BSR.RAM.READ.SAVE   .EQ $03CE
      1450 BANK.SP.SAVE             .EQ $03CF
      1460 TRANSFER                 .EQ $03ED,$03EE
      1470 MON.BRKV                 .EQ $03F0,$03F1
      1480 USRADR                   .EQ $03F8 - $03FA
      1490 NMI                      .EQ $03FB - $03FD
      1500 MON.IRQLOC               .EQ $03FE,$03FF
      1510 *--------------------------------
      1520 READ.MAIN.RAM            .EQ $C002
      1530 READ.AUX.RAM             .EQ $C003
      1540 WRITE.MAIN.RAM           .EQ $C004
      1550 WRITE.AUX.RAM            .EQ $C005
      1560 USE.MAIN.ZP.STK.BSR      .EQ $C008
      1570 USE.AUX.ZP.STK.BSR       .EQ $C009
      1580 READ.BSR.BANK            .EQ $C011
      1590 READ.BSR.RAM.READ        .EQ $C012
      1600 READ.RAM.READ.STATUS     .EQ $C013
      1610 READ.RAM.WRITE.STATUS    .EQ $C014
      1620 READ.ZP.STK.BSR.STATUS   .EQ $C016
      1630 BSR.2.RAM.READ.ONLY      .EQ $C080
      1640 BSR.2.ROM.READ.RAM.WRITE .EQ $C081
      1650 BSR.2.ROM.READ.ONLY      .EQ $C082
      1660 BSR.2.RAM.READ.RAM.WRITE .EQ $C083
      1670 BSR.1.RAM.READ.ONLY      .EQ $C088
      1680 BSR.1.ROM.READ.RAM.WRITE .EQ $C089
      1690 BSR.1.ROM.READ.ONLY      .EQ $C08A
      1700 BSR.1.RAM.READ.RAM.WRITE .EQ $C08B
      1710 *--------------------------------
      1720 AUXMOVE                  .EQ $C311
      1730 XFER                     .EQ $C314
      1740 MONITOR                  .EQ $F800 - $FFFF
      1750 MON.OLDBRK               .EQ $FA59
      1760 BEEP                     .EQ $FBDD
      1770 MON.RDKEY                .EQ $FD0C
      1780 MON.JSR.CLREOL           .EQ $FD8B - $FD8D
      1790 MON.COUT                 .EQ $FDED
      1800 MON                      .EQ $FF65
      1810 *--------------------------------
      1820            .OR $0803
      1830 USE.AUXMEM
      1840 G
      1850            JMP CONNECT.CONTROL.Y
      1860 JMP.TO.RETURN.TO.MAIN
      1870            JMP RETURN.TO.MAIN
      1880 JMP.TO.RETURN.TO.AUX
      1890            JMP RETURN.TO.AUX
      1900 JMP.TO.SAVE.BSR.STATE
      1910            JMP SAVE.BSR.STATE
      1920 JMP.TO.RESTORE.BSR.STATE
      1930            JMP RESTORE.BSR.STATE
      1940 *--------------------------------
      1950 CONNECT.CONTROL.Y
      1960            LDA /USE.AUXMEM.CONTROL.Y.HANDLER
      1970            STA USRADR+2
      1980            LDA #USE.AUXMEM.CONTROL.Y.HANDLER
      1990            STA USRADR+1
      2000            LDA #$4C      JMP
      2010            STA USRADR
      2020            RTS
      2030 *--------------------------------
      2040 USE.AUXMEM.CONTROL.Y.HANDLER
      2050 * Reconstruct monitor mode byte
      2060 * after "Bryan" messed with it
      2070 * ("Br" is NOPish)
      2080            PHA
      2090            LDA IN
      2100            CMP #"$"
      2110 * Branch w/Carry set causa S-C or Mini-Asm
      2120            BEQ .1
      2130            CLC
      2140 .1         PLA
      2150 * These lines are for you Bryan
      2160            .DA #'y'
      2170            .AS -'an'     Builds SBC $EEE1,Y
      2180 * Check for user specified address
      2190            CPX #$01
      2200            BNE SWITCH.MIND
      2210            TAY
      2220 * Lesser complex is USE.XFER
      2230            BEQ USE.XFER
      2240 * Most complex is USE.AUXMOVE
      2250 *--------------------------------
      2260 USE.AUXMOVE
      2270 * Fetch what should be a "0"
      2280 * or "1" to be AUXMOVE's carry
      2290            LDY MON.YSAV
      2300            LDA IN,Y
      2310 * Shift what we fetched to carry
      2320            LSR
      2330 * Save carry while comparing
      2340            PHP
      2350 * This is a "0" or "1" after a LSR
      2360            CMP #"0"/2
      2370            BNE INVALID.CARRY
      2380            INC MON.YSAV
      2390 * Recover Carry
      2400            PLP
      2410 CALL.AUXMOVE.WITH.CARRY
      2420            JSR AUXMOVE
      2430            RTS
      2440 *--------------------------------
      2450 USE.XFER
      2460 * Set XFER Transfer address
      2470 * from monitor parameter
      2480            LDA MON.A1,X
      2490            STA TRANSFER,X
      2500            DEX
      2510            BPL USE.XFER
      2520 * Fetch what should be a "0"
      2530 * or "1" to be XFER's carry
      2540            LDY MON.YSAV
      2550            LDA IN,Y
      2560 * Shift what we fetched to carry
      2570            LSR
      2580 * Save carry for a while
      2590            PHP
      2600 * This is a "0" or "1" after a LSR
      2610            CMP #"0"/2
      2620            BNE INVALID.CARRY
      2630            INC MON.YSAV
      2640 * Fetch what should be a "0"
      2650 * or a "1" to be XFER's overflow
      2660            INY
      2670            LDA IN,Y
      2680 * Shift what we fetched to carry
      2690            LSR
      2700 * Save this carry too, while we compare
      2710            PHP
      2720 * This is a "0" or "1" after a LSR
      2730            CMP #"0"/2
      2740            BNE INVALID.OVERFLOW
      2750            INC MON.YSAV
      2760 * Recovered carry is valid overflow
      2770            PLP
      2780 * Move it back to bit 0
      2790            ROL
      2800 * Recover carry
      2810            PLP
      2820 * Construct overflow
      2830            CLV
      2840            AND #%0000.0001
      2850            BEQ .1
      2860            BIT SEV
      2870 * Save BSR bank, BSR ram read, and SP
      2880 * for any calls or returns to main/auxmem
      2890 .1         JSR SAVE.BSR.STATE
      2900            TSX
      2910            STX BANK.SP.SAVE
      2920 JMP.XFER.WITH.CARRY.AND.OVERFLOW
      2930 * Routines in aux/main bank may jmp
      2940 * to RETURN.TO.MAIN/AUX when done
      2950 SEV        JMP XFER
      2960 *--------------------------------
      2970 INVALID.OVERFLOW
      2980            PLP
      2990 INVALID.CARRY
      3000            PLP
      3010 * Let's not process rest of line
      3020            LDY MON.YSAV
      3030            LDA #$8D
      3040            STA IN,Y
      3050            JMP BEEP
      3060 *--------------------------------
      3070 SWITCH.MIND
      3080 * Check in main or aux now
      3090            LDA READ.RAM.READ.STATUS
      3100            BPL ENTER.AUX.MON
      3110            JMP RETURN.TO.MAIN
      3120 ENTER.AUX.MON
      3130 * Move USE.AUXMEM to auxmem too
      3140            LDA #USE.AUXMEM
      3150            STA MON.A1
      3160            STA MON.A4
      3170            LDA /USE.AUXMEM
      3180            STA MON.A1+1
      3190            STA MON.A4+1
      3200            LDA #USE.AUXMEM.END
      3210            STA MON.A2
      3220            LDA /USE.AUXMEM.END
      3230            STA MON.A2+1
      3240            SEC
      3250            JSR AUXMOVE
      3260 * Save BSR bank, BSR ram read, and SP
      3270 * for calls and return to main mem
      3280            JSR SAVE.BSR.STATE
      3290            TSX
      3300            STX BANK.SP.SAVE
      3310 * Continue in auxmem w/rom
      3320            STA READ.AUX.RAM
      3330            STA WRITE.AUX.RAM
      3340            STA USE.AUX.ZP.STK.BSR
      3350            LDA BSR.2.ROM.READ.RAM.WRITE
      3360            LDA BSR.2.ROM.READ.RAM.WRITE
      3370 * What else but this too
      3380            LDX #$FF
      3390            TXS
      3400 * Copy rom monitor to auxmem BSR
      3410            LDY #MONITOR
      3420            STY MON.A1
      3430            STY MON.STATUS
      3440            LDA /MONITOR
      3450            STA MON.A1+1
      3460 .1         LDA (MON.A1),Y
      3470            STA (MON.A1),Y
      3480            INY
      3490            BNE .1
      3500            INC MON.A1+1
      3510            BNE .1
      3520 * Now use auxmem BSR
      3530            LDA BSR.2.RAM.READ.RAM.WRITE
      3540            LDA BSR.2.RAM.READ.RAM.WRITE
      3550 * Fix monitor in BSR
      3560            LDA /DO.CLREOL
      3570            STA MON.JSR.CLREOL+2
      3580            LDA #DO.CLREOL
      3590            STA MON.JSR.CLREOL+1
      3600 * Hook I/O through main
      3610            LDA #COUT.TO.MAIN
      3620            STA MON.CSWL
      3630            LDA #RDKEY.FROM.MAIN
      3640            STA MON.KSWL
      3650            LDA /COUT.TO.MAIN
      3660            STA MON.CSWL+1
      3670 *          LDA /RDKEY.FROM.MAIN
      3680            STA MON.KSWL+1
      3690 * USE.AUXMEM in auxmem too
      3700            JSR CONNECT.CONTROL.Y
      3710 * Do page 3 locs
      3720            STA NMI
      3730            LDA #MON
      3740            STA NMI+1
      3750            STA MON.IRQLOC
      3760            LDA /MON
      3770            STA NMI+2
      3780            STA MON.IRQLOC+1
      3790            LDA #MON.OLDBRK
      3800            STA MON.BRKV
      3810            LDA /MON.OLDBRK
      3820            STA MON.BRKV+1
      3830 * Enter monitor in auxmem BSR
      3840            JMP MON
      3850 *--------------------------------
      3860 RETURN.TO.AUX
      3870 * Continue in aux ram
      3880            STA READ.AUX.RAM
      3890            STA WRITE.AUX.RAM
      3900            STA USE.AUX.ZP.STK.BSR
      3910            JMP RETURN.COMMON
      3920 RETURN.TO.MAIN
      3930 * Continue in main ram
      3940            STA READ.MAIN.RAM
      3950            STA WRITE.MAIN.RAM
      3960            STA USE.MAIN.ZP.STK.BSR
      3970 RETURN.COMMON
      3980 * Recover SP
      3990            LDX BANK.SP.SAVE
      4000            TXS
      4010 RESTORE.BSR.STATE
      4020            CLV
      4030            LDX BANK.BSR.BANK.SAVE
      4040            BPL .2
      4050            LDX BANK.BSR.RAM.READ.SAVE
      4060            BPL .1
      4070            LDX BSR.2.RAM.READ.RAM.WRITE
      4080            LDX BSR.2.RAM.READ.RAM.WRITE
      4090            BVC .4
      4100 .1         LDX BSR.2.ROM.READ.RAM.WRITE
      4110            LDX BSR.2.ROM.READ.RAM.WRITE
      4120            BVC .4
      4130 .2         LDX BANK.BSR.RAM.READ.SAVE
      4140            BPL .3
      4150            LDX BSR.1.RAM.READ.RAM.WRITE
      4160            LDX BSR.1.RAM.READ.RAM.WRITE
      4170            BVC .4
      4180 .3         LDX BSR.1.ROM.READ.RAM.WRITE
      4190            LDX BSR.1.ROM.READ.RAM.WRITE
      4200 .4         RTS
      4210 *--------------------------------
      4220 SAVE.BSR.STATE
      4230            LDX READ.BSR.BANK
      4240            STX BANK.BSR.BANK.SAVE
      4250            LDX READ.BSR.RAM.READ
      4260            STX BANK.BSR.RAM.READ.SAVE
      4270            RTS
      4280 *--------------------------------
      4290 DO.CLREOL
      4300            LDA #"]"-'@'
      4310 COUT.TO.MAIN
      4320 * Save auxmem's X
      4330            STX BANK.X.SAVE
      4340 * Save BSR bank, BSR ram read, and SP
      4350 * over call to main ram
      4360            JSR SAVE.BSR.STATE
      4370            TSX
      4380            STX BANK.SP.SAVE
      4390 * Continue in main ram
      4400            STA READ.MAIN.RAM
      4410            STA WRITE.MAIN.RAM
      4420            STA USE.MAIN.ZP.STK.BSR
      4430 * Recover SP
      4440            LDX BANK.SP.SAVE
      4450            TXS
      4460            JSR RESTORE.BSR.STATE
      4470            JSR MON.COUT
      4480            JMP IO.COMMON
      4490 *--------------------------------
      4500 RDKEY.FROM.MAIN
      4510 * Repair monitor's sillier attempt
      4520            STA (MON.BASL),Y
      4530 * Save auxmem's X
      4540            STX BANK.X.SAVE
      4550 * Save BSR bank, BSR ram read, and SP
      4560 * over call to main ram
      4570            JSR SAVE.BSR.STATE
      4580            TSX
      4590            STX BANK.SP.SAVE
      4600 * Continue in main ram
      4610            STA READ.MAIN.RAM
      4620            STA WRITE.MAIN.RAM
      4630            STA USE.MAIN.ZP.STK.BSR
      4640            LDX BANK.SP.SAVE       Recover SP
      4650            TXS
      4660            JSR RESTORE.BSR.STATE
      4670            JSR MON.RDKEY
      4680 *--------------------------------
      4690 IO.COMMON
      4700            STA READ.AUX.RAM       Continue in Aux RAM
      4710            STA WRITE.AUX.RAM
      4720            STA USE.AUX.ZP.STK.BSR
      4730            LDX BANK.SP.SAVE       Recover SP
      4740            TXS
      4750            JSR RESTORE.BSR.STATE
      4760            LDX BANK.X.SAVE        Recover X
      4770            RTS
      4780 *--------------------------------
      4790 USE.AUXMEM.END           .EQ *-1

65C02 | Bob Sander-Cederlof

People who have started reading AAL since last December have asked what is all this 65C02 business, anyway? Well the 65C02 is a new CMOS version of the 6502 microprocessor. (CMOS stands for Complementary Metal Oxide Semiconductor. That's a different way of making chips. CMOS circuits are noted for extremely low power consumption and extremely high sensitivity to static electricity.) To us Apple owners, the important thing is that the designers of the new chip corrected the bugs in the 6502 and added several new instructions and addressing modes.

The new instructions include PHX, PLX, PHY, and PLY (push and pull the X and Y registers from the stack), BRA (branch always), STZ (store zero), TSB and TRB (test and set or reset bits), and SMB, RMB, BBR and BBS (set, reset and branch on single bits). The main new addressing mode is true indirect without indexing, LDA ($12). This mode is now available for ORA, AND, EOR, ADC, STA, LDA, CMP, and SBC. There are also new modes for the BIT and JMP instructions. INC and DEC can now work on the A register.

There are some problems, though. Rockwell, GTE, NCR, and Synertek (maybe) are manufacturing 65C02 processors, but they are not all the same. The SMB, RMB, BBS, and BBR instructions are only available in the Rockwell chip. The NCR chip works in the Apple //e, but not in older Apples. The GTE processor does work in all Apples (this is being written on an Apple ][+ with a GTE 65C02). I haven't yet received a sample of the Rockwell processor, so I don't personally know if it works in older Apples. Some people say yes, others no.

That's a summary of what we know so far. The confusion is beginning to clear up, but there are still questions about what will or won't work in which Apples, and why. Stay tuned...

Speeding Up Spirals | Bob Sander-Cederlof

Several have written to us about Roger Keating's Spiral Screen Clear (AAL June 1983). Charles Putney, who you may remember as the first one to double the speed of the prime number program in AAL several years ago, has now applied his talent to unwinding the screen.

Roger's program ran in 55 seconds, my table-lookup for BASCALC shortened it to 40 seconds. Charlie wrote the whole thing out as one long string of LDA-STA pairs, and trimmed the time to only 7 seconds!

Let's see...there are 960 characters on the screen. If I write a LDA-STA pair to move each byte ahead one position along the spiral path, I will have 959 such pairs. Each LDA and each STA will take 3 bytes, so the program to shift the whole screen one step around the spiral path will take 2x3x959 = 5754 bytes. Add another 5 bytes to LDA #$A0 and store it in the center of the screen before the first rotation. Then add some code to re- run the 959 steps 959 more times, so that the whole screen clears, and you get Charlie's program, 5777 bytes.

Now try to type it all in! Don't worry, we aren't even going to list it here. It will be on the next Quarterly disk, though.

Charlie decided to use five macros, to decrease the amount of manual labor involved. He defined a macro named MOVE which builds the LDA-STA pair for a pair of arguments:

           .MA MOVE
           LDA ]1
           STA ]2
           .EM

Then he defined one macro for each leg of the spiral: MOVED, MOVEL, MOVEU, and MOVER for down, left, up, and right respec- tively. With a few comment lines, the macro definitions take a mere 488 lines! The macros are each called with three parameters:

           >MOVED col,low.row,high.row
           >MOVEL row,low.col,high.col
           >MOVEU col,low.row,high.row
           >MOVER row,low.col,high.col

The definitions out of the way, it only remains to write 12 sets of 4 macro calls, or 48 lines, and a driving loop to do it all 960 times. Here is a condensed listing of the actual code part of Charlie's program:

      1000 *SAVE S.PUTNEY'S SPIRAL
      1010 *
      1020 *
      1030 *      FAST SPIRAL SCREEN CLEAR
      1040 *
      1050 *      CHARLES H. PUTNEY
      1060 *      18 QUINNS ROAD
      1070 *      SHANKILL
      1080 *      CO. DUBLIN
      1090 *      IRELAND
      1100 *
      1110 *
      1120 *
      1130 *
      1140 *--------------------------------
      1150 *
      1160 *      TEXT PAGE BASE ADDRESSES
      1170 *
      1180 *
      1190 R0     .EQ $400
      1200 R1     .EQ $480
      1210 R2     .EQ $500
      1220 R3     .EQ $580
      1230 R4     .EQ $600
      1240 R5     .EQ $680
      1250 R6     .EQ $700
      1260 R7     .EQ $780
      1270 R8     .EQ $428
      1280 R9     .EQ $4A8
      1290 R10    .EQ $528
      1300 R11    .EQ $5A8
      1310 R12    .EQ $628
      1320 R13    .EQ $6A8
      1330 R14    .EQ $728
      1340 R15    .EQ $7A8
      1350 R16    .EQ $450
      1360 R17    .EQ $4D0
      1370 R18    .EQ $550
      1380 R19    .EQ $5D0
      1390 R20    .EQ $650
      1400 R21    .EQ $6D0
      1410 R22    .EQ $750
      1420 R23    .EQ $7D0
      1430 *
      1440 *
      1450 *--------------------------------
      1460 *
      1470 *      MACRO DEFINITIONS
      1480 *
      1490 *
      1500        .MA MOVE
      1510        LDA ]1
      1520        STA ]2
      1530        .EM
      1540 *
      1550 *
      1560 *
      1570        .MA MOVER    MOVE RIGHT ROW,COLLOW,COLHIGH FROM 0-39
      1580        .DO ]3>]2
      1590        >MOVE ]1+]3-1,]1+]3
      1600        .FIN
      1610        .DO ]3-1>]2
      1620        >MOVE ]1+]3-2,]1+]3-1
      1630        .FIN
      1640        .DO ]3-2>]2
      1650        >MOVE ]1+]3-3,]1+]3-2
      1660        .FIN
      1670        .DO ]3-3>]2
      1680        >MOVE ]1+]3-4,]1+]3-3
      1690        .FIN
      1700        .DO ]3-4>]2
      1710        >MOVE ]1+]3-5,]1+]3-4
      1720        .FIN
      1730        .DO ]3-5>]2
      1740        >MOVE ]1+]3-6,]1+]3-5
      1750        .FIN
      1760        .DO ]3-6>]2
      1770        >MOVE ]1+]3-7,]1+]3-6
      1780        .FIN
      1790        .DO ]3-7>]2
      1800        >MOVE ]1+]3-8,]1+]3-7
      1810        .FIN
      1820        .DO ]3-8>]2
      1830        >MOVE ]1+]3-9,]1+]3-8
      1840        .FIN
      1850        .DO ]3-9>]2
      1860        >MOVE ]1+]3-10,]1+]3-9
      1870        .FIN
      1880        .DO ]3-10>]2
      1890        >MOVE ]1+]3-11,]1+]3-10
      1900        .FIN
      1910        .DO ]3-11>]2
      1920        >MOVE ]1+]3-12,]1+]3-11
      1930        .FIN
      1940        .DO ]3-12>]2
      1950        >MOVE ]1+]3-13,]1+]3-12
      1960        .FIN
      1970        .DO ]3-13>]2
      1980        >MOVE ]1+]3-14,]1+]3-13
      1990        .FIN
      2000        .DO ]3-14>]2
      2010        >MOVE ]1+]3-15,]1+]3-14
      2020        .FIN
      2030        .DO ]3-15>]2
      2040        >MOVE ]1+]3-16,]1+]3-15
      2050        .FIN
      2060        .DO ]3-16>]2
      2070        >MOVE ]1+]3-17,]1+]3-16
      2080        .FIN
      2090        .DO ]3-17>]2
      2100        >MOVE ]1+]3-18,]1+]3-17
      2110        .FIN
      2120        .DO ]3-18>]2
      2130        >MOVE ]1+]3-19,]1+]3-18
      2140        .FIN
      2150        .DO ]3-19>]2
      2160        >MOVE ]1+]3-20,]1+]3-19
      2170        .FIN
      2180        .DO ]3-20>]2
      2190        >MOVE ]1+]3-21,]1+]3-20
      2200        .FIN
      2210        .DO ]3-21>]2
      2220        >MOVE ]1+]3-22,]1+]3-21
      2230        .FIN
      2240        .DO ]3-22>]2
      2250        >MOVE ]1+]3-23,]1+]3-22
      2260        .FIN
      2270        .DO ]3-23>]2
      2280        >MOVE ]1+]3-24,]1+]3-23
      2290        .FIN
      2300        .DO ]3-24>]2
      2310        >MOVE ]1+]3-25,]1+]3-24
      2320        .FIN
      2330        .DO ]3-25>]2
      2340        >MOVE ]1+]3-26,]1+]3-25
      2350        .FIN
      2360        .DO ]3-26>]2
      2370        >MOVE ]1+]3-27,]1+]3-26
      2380        .FIN
      2390        .DO ]3-27>]2
      2400        >MOVE ]1+]3-28,]1+]3-27
      2410        .FIN
      2420        .DO ]3-28>]2
      2430        >MOVE ]1+]3-29,]1+]3-28
      2440        .FIN
      2450        .DO ]3-29>]2
      2460        >MOVE ]1+]3-30,]1+]3-29
      2470        .FIN
      2480        .DO ]3-30>]2
      2490        >MOVE ]1+]3-31,]1+]3-30
      2500        .FIN
      2510        .DO ]3-31>]2
      2520        >MOVE ]1+]3-32,]1+]3-31
      2530        .FIN
      2540        .DO ]3-32>]2
      2550        >MOVE ]1+]3-33,]1+]3-32
      2560        .FIN
      2570        .DO ]3-33>]2
      2580        >MOVE ]1+]3-34,]1+]3-33
      2590        .FIN
      2600        .DO ]3-34>]2
      2610        >MOVE ]1+]3-35,]1+]3-34
      2620        .FIN
      2630        .DO ]3-35>]2
      2640        >MOVE ]1+]3-36,]1+]3-35
      2650        .FIN
      2660        .DO ]3-36>]2
      2670        >MOVE ]1+]3-37,]1+]3-36
      2680        .FIN
      2690        .DO ]3-37>]2
      2700        >MOVE ]1+]3-38,]1+]3-37
      2710        .FIN
      2720        .DO ]3-38>]2
      2730        >MOVE ]1+]3-39,]1+]3-38
      2740        .FIN
      2750        .EM
      2760 *
      2770 *
      2780 *
      2790        .MA MOVEL    MOVE LEFT ROW,COLLOW,COLHIGH FROM 0-39
      2800        .DO ]3>]2
      2810        >MOVE ]1+]2+1,]1+]2
      2820        .FIN
      2830        .DO ]3-1>]2
      2840        >MOVE ]1+]2+2,]1+]2+1
      2850        .FIN
      2860        .DO ]3-2>]2
      2870        >MOVE ]1+]2+3,]1+]2+2
      2880        .FIN
      2890        .DO ]3-3>]2
      2900        >MOVE ]1+]2+4,]1+]2+3
      2910        .FIN
      2920        .DO ]3-4>]2
      2930        >MOVE ]1+]2+5,]1+]2+4
      2940        .FIN
      2950        .DO ]3-5>]2
      2960        >MOVE ]1+]2+6,]1+]2+5
      2970        .FIN
      2980        .DO ]3-6>]2
      2990        >MOVE ]1+]2+7,]1+]2+6
      3000        .FIN
      3010        .DO ]3-7>]2
      3020        >MOVE ]1+]2+8,]1+]2+7
      3030        .FIN
      3040        .DO ]3-8>]2
      3050        >MOVE ]1+]2+9,]1+]2+8
      3060        .FIN
      3070        .DO ]3-9>]2
      3080        >MOVE ]1+]2+10,]1+]2+9
      3090        .FIN
      3100        .DO ]3-10>]2
      3110        >MOVE ]1+]2+11,]1+]2+10
      3120        .FIN
      3130        .DO ]3-11>]2
      3140        >MOVE ]1+]2+12,]1+]2+11
      3150        .FIN
      3160        .DO ]3-12>]2
      3170        >MOVE ]1+]2+13,]1+]2+12
      3180        .FIN
      3190        .DO ]3-13>]2
      3200        >MOVE ]1+]2+14,]1+]2+13
      3210        .FIN
      3220        .DO ]3-14>]2
      3230        >MOVE ]1+]2+15,]1+]2+14
      3240        .FIN
      3250        .DO ]3-15>]2
      3260        >MOVE ]1+]2+16,]1+]2+15
      3270        .FIN
      3280        .DO ]3-16>]2
      3290        >MOVE ]1+]2+17,]1+]2+16
      3300        .FIN
      3310        .DO ]3-17>]2
      3320        >MOVE ]1+]2+18,]1+]2+17
      3330        .FIN
      3340        .DO ]3-18>]2
      3350        >MOVE ]1+]2+19,]1+]2+18
      3360        .FIN
      3370        .DO ]3-19>]2
      3380        >MOVE ]1+]2+20,]1+]2+19
      3390        .FIN
      3400        .DO ]3-20>]2
      3410        >MOVE ]1+]2+21,]1+]2+20
      3420        .FIN
      3430        .DO ]3-21>]2
      3440        >MOVE ]1+]2+22,]1+]2+21
      3450        .FIN
      3460        .DO ]3-22>]2
      3470        >MOVE ]1+]2+23,]1+]2+22
      3480        .FIN
      3490        .DO ]3-23>]2
      3500        >MOVE ]1+]2+24,]1+]2+23
      3510        .FIN
      3520        .DO ]3-24>]2
      3530        >MOVE ]1+]2+25,]1+]2+24
      3540        .FIN
      3550        .DO ]3-25>]2
      3560        >MOVE ]1+]2+26,]1+]2+25
      3570        .FIN
      3580        .DO ]3-26>]2
      3590        >MOVE ]1+]2+27,]1+]2+26
      3600        .FIN
      3610        .DO ]3-27>]2
      3620        >MOVE ]1+]2+28,]1+]2+27
      3630        .FIN
      3640        .DO ]3-28>]2
      3650        >MOVE ]1+]2+29,]1+]2+28
      3660        .FIN
      3670        .DO ]3-29>]2
      3680        >MOVE ]1+]2+30,]1+]2+29
      3690        .FIN
      3700        .DO ]3-30>]2
      3710        >MOVE ]1+]2+31,]1+]2+30
      3720        .FIN
      3730        .DO ]3-31>]2
      3740        >MOVE ]1+]2+32,]1+]2+31
      3750        .FIN
      3760        .DO ]3-32>]2
      3770        >MOVE ]1+]2+33,]1+]2+32
      3780        .FIN
      3790        .DO ]3-33>]2
      3800        >MOVE ]1+]2+34,]1+]2+33
      3810        .FIN
      3820        .DO ]3-34>]2
      3830        >MOVE ]1+]2+35,]1+]2+34
      3840        .FIN
      3850        .DO ]3-35>]2
      3860        >MOVE ]1+]2+36,]1+]2+35
      3870        .FIN
      3880        .DO ]3-36>]2
      3890        >MOVE ]1+]2+37,]1+]2+36
      3900        .FIN
      3910        .DO ]3-37>]2
      3920        >MOVE ]1+]2+38,]1+]2+37
      3930        .FIN
      3940        .DO ]3-38>]2
      3950        >MOVE ]1+]2+39,]1+]2+38
      3960        .FIN
      3970        .EM
      3980 *
      3990 *
      4000 *
      4010        .MA MOVEU    MOVE UP COL,ROWLOW,ROWHIGH FROM 0-23
      4020        .DO ]2<1
      4030        .DO ]3+1>1
      4040        >MOVE ]1+R1,]1+R0
      4050        .FIN
      4060        .FIN
      4070        .DO ]2<2
      4080        .DO ]3+1>2
      4090        >MOVE ]1+R2,]1+R1
      4100        .FIN
      4110        .FIN
      4120        .DO ]2<3
      4130        .DO ]3+1>3
      4140        >MOVE ]1+R3,]1+R2
      4150        .FIN
      4160        .FIN
      4170        .DO ]2<4
      4180        .DO ]3+1>4
      4190        >MOVE ]1+R4,]1+R3
      4200        .FIN
      4210        .FIN
      4220        .DO ]2<5
      4230        .DO ]3+1>5
      4240        >MOVE ]1+R5,]1+R4
      4250        .FIN
      4260        .FIN
      4270        .DO ]2<6
      4280        .DO ]3+1>6
      4290        >MOVE ]1+R6,]1+R5
      4300        .FIN
      4310        .FIN
      4320        .DO ]2<7
      4330        .DO ]3+1>7
      4340        >MOVE ]1+R7,]1+R6
      4350        .FIN
      4360        .FIN
      4370        .DO ]2<8
      4380        .DO ]3+1>8
      4390        >MOVE ]1+R8,]1+R7
      4400        .FIN
      4410        .FIN
      4420        .DO ]2<9
      4430        .DO ]3+1>9
      4440        >MOVE ]1+R9,]1+R8
      4450        .FIN
      4460        .FIN
      4470        .DO ]2<10
      4480        .DO ]3+1>10
      4490        >MOVE ]1+R10,]1+R9
      4500        .FIN
      4510        .FIN
      4520        .DO ]2<11
      4530        .DO ]3+1>11
      4540        >MOVE ]1+R11,]1+R10
      4550        .FIN
      4560        .FIN
      4570        .DO ]2<12
      4580        .DO ]3+1>12
      4590        >MOVE ]1+R12,]1+R11
      4600        .FIN
      4610        .FIN
      4620        .DO ]2<13
      4630        .DO ]3+1>13
      4640        >MOVE ]1+R13,]1+R12
      4650        .FIN
      4660        .FIN
      4670        .DO ]2<14
      4680        .DO ]3+1>14
      4690        >MOVE ]1+R14,]1+R13
      4700        .FIN
      4710        .FIN
      4720        .DO ]2<15
      4730        .DO ]3+1>15
      4740        >MOVE ]1+R15,]1+R14
      4750        .FIN
      4760        .FIN
      4770        .DO ]2<16
      4780        .DO ]3+1>16
      4790        >MOVE ]1+R16,]1+R15
      4800        .FIN
      4810        .FIN
      4820        .DO ]2<17
      4830        .DO ]3+1>17
      4840        >MOVE ]1+R17,]1+R16
      4850        .FIN
      4860        .FIN
      4870        .DO ]2<18
      4880        .DO ]3+1>18
      4890        >MOVE ]1+R18,]1+R17
      4900        .FIN
      4910        .FIN
      4920        .DO ]2<19
      4930        .DO ]3+1>19
      4940        >MOVE ]1+R19,]1+R18
      4950        .FIN
      4960        .FIN
      4970        .DO ]2<20
      4980        .DO ]3+1>20
      4990        >MOVE ]1+R20,]1+R19
      5000        .FIN
      5010        .FIN
      5020        .DO ]2<21
      5030        .DO ]3+1>21
      5040        >MOVE ]1+R21,]1+R20
      5050        .FIN
      5060        .FIN
      5070        .DO ]2<22
      5080        .DO ]3+1>22
      5090        >MOVE ]1+R22,]1+R21
      5100        .FIN
      5110        .FIN
      5120        .DO ]2<23
      5130        .DO ]3+1>23
      5140        >MOVE ]1+R23,]1+R22
      5150        .FIN
      5160        .FIN
      5170        .EM
      5180 *
      5190 *
      5200 *
      5210        .MA MOVED    MOVE DOWN COL,ROWLOW,ROWHIGH FROM 0-23
      5220        .DO ]2<23
      5230        .DO ]3+1>23
      5240        >MOVE ]1+R22,]1+R23
      5250        .FIN
      5260        .FIN
      5270        .DO ]2<22
      5280        .DO ]3+1>22
      5290        >MOVE ]1+R21,]1+R22
      5300        .FIN
      5310        .FIN
      5320        .DO ]2<21
      5330        .DO ]3+1>21
      5340        >MOVE ]1+R20,]1+R21
      5350        .FIN
      5360        .FIN
      5370        .DO ]2<20
      5380        .DO ]3+1>20
      5390        >MOVE ]1+R19,]1+R20
      5400        .FIN
      5410        .FIN
      5420        .DO ]2<19
      5430        .DO ]3+1>19
      5440        >MOVE ]1+R18,]1+R19
      5450        .FIN
      5460        .FIN
      5470        .DO ]2<18
      5480        .DO ]3+1>18
      5490        >MOVE ]1+R17,]1+R18
      5500        .FIN
      5510        .FIN
      5520        .DO ]2<17
      5530        .DO ]3+1>17
      5540        >MOVE ]1+R16,]1+R17
      5550        .FIN
      5560        .FIN
      5570        .DO ]2<16
      5580        .DO ]3+1>16
      5590        >MOVE ]1+R15,]1+R16
      5600        .FIN
      5610        .FIN
      5620        .DO ]2<15
      5630        .DO ]3+1>15
      5640        >MOVE ]1+R14,]1+R15
      5650        .FIN
      5660        .FIN
      5670        .DO ]2<14
      5680        .DO ]3+1>14
      5690        >MOVE ]1+R13,]1+R14
      5700        .FIN
      5710        .FIN
      5720        .DO ]2<13
      5730        .DO ]3+1>13
      5740        >MOVE ]1+R12,]1+R13
      5750        .FIN
      5760        .FIN
      5770        .DO ]2<12
      5780        .DO ]3+1>12
      5790        >MOVE ]1+R11,]1+R12
      5800        .FIN
      5810        .FIN
      5820        .DO ]2<11
      5830        .DO ]3+1>11
      5840        >MOVE ]1+R10,]1+R11
      5850        .FIN
      5860        .FIN
      5870        .DO ]2<10
      5880        .DO ]3+1>10
      5890        >MOVE ]1+R9,]1+R10
      5900        .FIN
      5910        .FIN
      5920        .DO ]2<9
      5930        .DO ]3+1>9
      5940        >MOVE ]1+R8,]1+R9
      5950        .FIN
      5960        .FIN
      5970        .DO ]2<8
      5980        .DO ]3+1>8
      5990        >MOVE ]1+R7,]1+R8
      6000        .FIN
      6010        .FIN
      6020        .DO ]2<7
      6030        .DO ]3+1>7
      6040        >MOVE ]1+R6,]1+R7
      6050        .FIN
      6060        .FIN
      6070        .DO ]2<6
      6080        .DO ]3+1>6
      6090        >MOVE ]1+R5,]1+R6
      6100        .FIN
      6110        .FIN
      6120        .DO ]2<5
      6130        .DO ]3+1>5
      6140        >MOVE ]1+R4,]1+R5
      6150        .FIN
      6160        .FIN
      6170        .DO ]2<4
      6180        .DO ]3+1>4
      6190        >MOVE ]1+R3,]1+R4
      6200        .FIN
      6210        .FIN
      6220        .DO ]2<3
      6230        .DO ]3+1>3
      6240        >MOVE ]1+R2,]1+R3
      6250        .FIN
      6260        .FIN
      6270        .DO ]2<2
      6280        .DO ]3+1>2
      6290        >MOVE ]1+R1,]1+R2
      6300        .FIN
      6310        .FIN
      6320        .DO ]2<1
      6330        .DO ]3+1>1
      6340        >MOVE ]1+R0,]1+R1
      6350        .FIN
      6360        .FIN
      6370        .EM
      6380 *
      6390 *
      6400 *--------------------------------
      6410 *
      6420 *      SPIRAL PROGRAM
      6430        .OR $6000    OUT OF THE WAY
      6440        .TF SPIRAL.OBJ
      6450 *
      6460 *
      6470 SPIRAL LDA #' '+$80 GET A SPACE
      6480        STA R12+12   PUT IT IN CENTER
      6490        LDX #960     HOW MANY TIMES ?
      6500        LDY /960     HIGH ORDER
      6510 *
      6520 SPI1   >MOVED 0,0,23
      6530        >MOVEL R0,0,39
      6540        >MOVEU 39,0,23
      6550        >MOVER R23,1,39
      6560 *
      6570        >MOVED 1,1,23
      6580        >MOVEL R1,1,38
      6590        >MOVEU 38,1,22
      6600        >MOVER R22,2,38
      6610 *
      6620        >MOVED 2,2,22
      6630        >MOVEL R2,2,37
      6640        >MOVEU 37,2,21
      6650        >MOVER R21,3,37
      6660 *
      6670        >MOVED 3,3,21
      6680        >MOVEL R3,3,36
      6690        >MOVEU 36,3,20
      6700        >MOVER R20,4,36
      6710 *
      6720        >MOVED 4,4,20
      6730        >MOVEL R4,4,35
      6740        >MOVEU 35,4,19
      6750        >MOVER R19,5,35
      6760 *
      6770        >MOVED 5,5,19
      6780        >MOVEL R5,5,34
      6790        >MOVEU 34,5,18
      6800        >MOVER R18,6,34
      6810 *
      6820        >MOVED 6,6,18
      6830        >MOVEL R6,6,33
      6840        >MOVEU 33,6,17
      6850        >MOVER R17,7,33
      6860 *
      6870        >MOVED 7,7,17
      6880        >MOVEL R7,7,32
      6890        >MOVEU 32,7,16
      6900        >MOVER R16,8,32
      6910 *
      6920        >MOVED 8,8,16
      6930        >MOVEL R8,8,31
      6940        >MOVEU 31,8,15
      6950        >MOVER R15,9,31
      6960 *
      6970        >MOVED 9,9,15
      6980        >MOVEL R9,9,30
      6990        >MOVEU 30,9,14
      7000        >MOVER R14,10,30
      7010 *
      7020        >MOVED 10,10,14
      7030        >MOVEL R10,10,29
      7040        >MOVEU 29,10,13
      7050        >MOVER R13,11,29
      7060 *
      7070        >MOVED 11,11,13
      7080        >MOVEL R11,11,28
      7090        >MOVEU 28,11,12
      7100        >MOVER R12,12,28
      7110 *
      7120        DEX
      7130        CPX #$FF
      7140        BNE SPI2
      7150        DEY
      7160        CPY #$FF
      7170        BNE SPI2
      7180        RTS
      7190 SPI2   JMP SPI1
      7200 *
      7210 ZZSIZE .EQ *-SPIRAL

Remember, the whole source with the full macro definitions will be on the next quarterly disk ($15, for all source code in issues July-August-September 1983).

Because Charlie's program makes such heavy use of macros, it takes considerable time to assemble. He timed it at nearly two minutes. If the program were written out the long way, without macros, it would take only about 20 seconds to assemble.

Charlie pointed out that we are needlessly moving the center of the spiral, which is already blank. As the blanked portion grows, this becomes very significant. In fact, by eliminating moving the cleared portion, the time could be further reduced to only 3 1/2 seconds. Each LDA-STA takes 8 cycles. The long way takes 959*960 pairs, plus some overhead. Ignoring the overhead, we get 7365120 cycles, or about 7.2 seconds. Forgetting the blanked stuff makes it 3.6 seconds. Any takers?

And I was just wondering...how about an Applesoft program which writes the 959 LDA-STA pairs as assembly language source on a text file? Or POKEs the actual object code, by computing the addresses necessary, into a binary buffer area. Again, any takers?

Tinkering with Variable Cross Reference | Louis Pitz De Witt, Iowa

I am a tinkerer! Yes I love to take programs and add features to improve them. Sometimes the "improved" version even works! Usually I learn a lot about humility, and occasionally a bit about programming.

A case in point is the program for doing an Applesoft Variable Cross Reference (from the November 1980 issue of Apple Assembly Line). I just recently got Quarterly Disk #1 with its source code, and so it became "tinker-time".

VCR works just fine, and is fast! But it only produces 40- column output, and I wanted both 40-column screen and 80-column printer hardcopy. Here are some patches which will do the job. It makes a good short example of changing output hooks in the middle of a program without goofing up DOS.

         1060       .TF B.VCRP  "P" FOR PRINTER VERSION

         4534        LDA #0     RESET COUNTER TO 0
         4538        STA $6     FOR EACH VARIABLE

         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
         4825        LDA #$FDF0         ONLY SCRN GETS NEW LINE
         4826        STA $36    SO DISCONNECT PRINTER
         4827        LDA /$FDF0
         4828        STA $37
         4829        JSR $3EA           PASS TO DOS
         4830        JSR MON.CROUT      SCREEN ONLY
         4831        LDA #$C100         REHOOK PRINTER
         4832        STA $36
         4833        LDA /$C100
         4834        STA $37
         4835        JSR $3EA           PASS TO DOS
         4836        BNE .1             ...ALWAYS

To use the printer version of VCR, BRUN B.VCRP. This sets up the ampersand vector. Then LOAD your Applesoft program. Use PR#1 to turn on your printer. Then type "&" and RETURN, and watch the cross reference.

If your printer is in some slot other than 1, change lines 4831 and 4833 to the correct value ($Cs00, where s=slot#).

Reversing, Getting, and Putting Nybbles | Bob Sander-Cederlof

In the process of de-crypting a large data base, I needed to reverse the nybbles in each of roughly 32000 bytes. There are probably a lot of ways to do this, but I found one which takes only 12 bytes to reverse the nybbles in the A-register.

Just to be sure we agree on what I am talking about, here is a little diagram:

           a b c d   e f g h

           e f g h   a b c d

One way, sort of brute force, involves breaking the nybbles out and remerging them:

           LDA (PNTR),Y
           ASL             SHIFT EFGH LEFT
           ASL
           ASL
           ASL
           STA TEMP
           LDA (PNTR),Y
           LSR             SHIFT ABCD RIGHT
           LSR
           LSR
           LSR
           ORA TEMP        RE-MERGE NYBBLES
           STA (PNTR),Y

From another perspective, I am trying to rotate the data byte half-way around. But if I try to do it with ROL or ROR instructions, one bit gets left in CARRY, and an extra bit gets inserted in the middle. Here is how I finally did it:

           LDA (PNTR),Y    abcd efgh
           ASL             bcde fgh0
           ADC #0          bcde fgha
           ASL             cdef gha0
           ADC #0          cdef ghab
           ASL             defg hab0
           ADC #0          defg habc
           ASL             efgh abc0
           ADC #0          efgh abcd
           STA (PNTR),Y

Each ASL-ADC pair shifts the byte around one bit. The ASL shifts the leftmost bit into the CARRY bit, and a zero into the right end. The ADC #0 adds CARRY into the rightmost bit.

Naturally, curiosity forces me to look at the possibility of shifting right one bit also. We have LSR and ROR, of course, but both of these leave the shifted out bit in CARRY. I want that bit back in the sign position, like this:

           ABCDEFGH should become HABCDEFG

Two similar methods come to mind, depending on how I might use it. If the byte to be shifted is in A-reg, and needs to remain there, and I don't want to upset any other registers, I can do it like this:

           PHA     save unshifted value
           LSR     get rightmost bit in CARRY
           PLA     restore unshifted value
           ROR     shift again, putting right bit on left

If the byte to be shifted is in memory, and I want the results to be in memory, I might do it like this:

           LDA FLAG
           LSR        RIGHTMOST BIT INTO CARRY
           ROR FLAG   SHIFT BYTE, PUTTING RIGHT INTO LEFT

Note that I can branch according to the value of the bit which moved around by using BMI or BPL, because that bit is the new sign bit.

The last method above can be useful when you have a program that needs to alternate between two paths. For example, suppose I write a program to pick up the "next nybble" from a data area. The first time I call it, I want to get the left nybble of the first byte. Next time, the right nybble of the same byte. Next time the left nybble of the next byte. And so on.

I might store the value $55 in FLAG initially, and then use LDA FLAG, LSR, ROR FLAG, to shift it around. FLAG will alternate between $55 and $AA. My subroutine can alternate between left and right nybbles.

Not to leave you hanging, I wrote "get next nybble" and "put next nybble" subroutines. By the time I finished polishing, yet another technique had surfaced for rotating the $55/$AA flag. I used this new method so as not disturb the contents of the A-register.

To set up either routine, the address of the beginning of the data area must be put into PNTR and PNTR+1, and $55 must be put into FLAG.

      1000 *SAVE NYBBLE GET & PUT
      1010 *--------------------------------
      1020 PNTR   .EQ 0 AND 1
      1030 FLAG   .EQ 2
      1040 *--------------------------------
      1050 *      PUT NEXT NYBBLE AT (PNTR)
      1060 *      IF FLAG = $55, PUT LEFT NYBBLE
      1070 *              = $AA, PUT RIGHT NYBBLE
      1080 *--------------------------------
      1090 PUT.NEXT.NYBBLE
      1100        LDX #0
      1110        LSR FLAG          $55 OR $AA
      1120        BCS .1            ...IT WAS $AA, NOW $54
      1130 *---STORE IN LEFT NYBBLE---------
      1140        ASL          FLAG NOW $AA
      1150        ASL
      1160        ASL
      1170        ASL
      1180        STA (PNTR,X)
      1190        RTS
      1200 *---STORE IN RIGHT NYBBLE--------
      1210 .1     ORA (PNTR,X) MERGE WITH LEFT NYBBLE
      1220        STA (PNTR,X)
      1230        INC FLAG     MAKE $54 INTO $55
      1240        INC PNTR     MOVE PNTR TO NEXT BYTE
      1250        BNE .2
      1260        INC PNTR+1
      1270 .2     RTS
      1280 *--------------------------------
      1290 *      GET NEXT NYBBLE
      1300 *      IF FLAG = $55, GET LEFT NYBBLE
      1310 *              = $AA, GET RIGHT NYBBLE
      1320 *--------------------------------
      1330 GET.NEXT.NYBBLE
      1340        LDX #0
      1350        LSR FLAG          WAS $55 OR $AA
      1360        LDA (PNTR,X)    GET BYTE WITH NYBBLES
      1370        BCS .1            ...WAS $AA, NOW $54
      1380 *---GET LEFT NYBBLE--------------
      1390        LSR
      1400        LSR
      1410        LSR
      1420        LSR
      1430        RTS
      1440 *---GET RIGHT NYBBLE--------------
      1450 .1     INC FLAG     MAKE $54 INTO $55
      1460        INC PNTR     ADVANCE TO NEXT BYTE
      1470        BNE .2
      1480        INC PNTR+1
      1490 .2     AND #$0F     ISOLATE NYBBLE
      1500        RTS
      1510 *--------------------------------

Odds and Ends | Bob Sander-Cederlof

Grappler Interfaces

There should be a leaflet included with this issue describing the Grappler printer interfaces. We now have three of them "in the family" here, and have been very pleased with their performance. Check the brochure for features, the ad on page three for our prices, and let us hear from you.

WICO Track Ball

Several of you have inquired about or ordered the WICO Track Ball that I reviewed a couple of months ago, so we've decided to carry them regularly. WICO has since raised their price from $79.95 to $89.95, so we're going from $75 to $80.

Diskettes

There's getting to be a lot more competition in the diskette business, so prices are falling. After seeing so many ads at such attractive prices, Bob called Verbatim and told them that we had to have a better price, or we would have to change brands. That paid off, so we can now offer the same high- quality Verbatim Datalife diskettes at $45.00 for a package of 20. That's $2.25 each for the best diskettes we've found.

Whatever You Want

If you're shopping for a new peripheral, accessory, or program, give us a call and ask for a quote. We can get nearly anything you might want, and we'd love the chance to serve you.

Some Small Patches | Bill Morgan

We've had several calls requesting the patch addresses for a couple of features in the S-C Macro Assemblers.

Ansert?

In Version 1.1 of the Macro Assembler, Bob changed the CTRL-I (Insert) command in the EDIT mode to CTRL-A (for ADD). This was done because the Apple //e keyboard has the TAB key, which generates a CTRL-I code. It didn't seem to make much sense to have the TAB key do an insert operation, so he added a clear- to-next-tab-stop function for CTRL-I.

Well, a lot of people don't have //e's, or don't much care about the TAB key. A lot of us are used to CTRL-I for Insert, and would like to keep it that way.

The CTRL-A character ($81) is at $1C87 in the $1000 version, and at $DCB7 in the $D000 version. Just change that byte to a $89, and you'll have your good old CTRL-I back. If you want to keep the clear-to-tab-stop function, you can change the $89 at $1CC6 ($DCC6) to a $81. That will make CTRL-A do the clear-to- tab.

.BS Filler Byte

The directive .BS <expr> skips over <expr> bytes when you are assembling to memory, and sends <expr> zero bytes to the target file when you are assembling to disk. Several people have asked how to change the zero to some other value.

For example, a freshly-erased EPROM contains all $FF bytes. When you burn data into the chip, you actually write in just the zero bits. If you are assembling code to be written into an EPROM, you want any fill bytes to be $FF, so you can add patches later without having to erase and re-write the whole chip.

The following table shows the addresses of the zero byte in the various versions of the Macro Assembler. Just change the indicated byte to the value you want to use for filler.

         Version  1.0  |              1.1
                       | 40-col   //e    Videx   STB
          $1000   2D43 |  2D62    2D48   2E37    2E60
          $D000   EE8F |  EE86    EE62   EF5A    EF83

Some More 68000 Boards | Bob Sander-Cederlof

First let me apologize for an erroneous statement in the May '83 issue, in which I juxtaposed two unrelated facts in a cause-effect sentence. Many readers have sent corrections: I am told that grounding the DTACK signal has nothing to do with how much memory you can add. How did I ever get the idea that it did? If you want the straight scoop on this, subscribe to Digital Acoustics' newsletter "DTACK Grounded".

Digital Acoustics has announced a new board, called the "DTACK Grande". Almost sounds like "grounded", but this time it isn't. You get one megabyte of RAM and a 12.5 MHz 68000. RAM refresh is handled by an interrupt routine, with software. The overhead is only 4%, giving an effective speed of 10 MHz. Expansion connectors on the card can connect to another 15.7 megabytes. I'd say Saybrook has been passed by, but Hal Hardenburg beat me to it! (Digital Acoustics, 1415 E. McFadden, Suite F, Santa Ana, CA 92705. (714) 835-4884)

Mike Heckman at Anthro-Digital sent me some literature on another new 68000 board. Enhancement Technology Corporation calls it the "PDQ//". Specs include: 10 MHZ, 256K RAM, UCSD p-system, Applesoft-compatible BASIC. The price will be $1495, available by the end of August. We may be able to make you a deal on one of these. (ETC, P.O.Box 1267, Pittsfield, MA 01202. (413) 445-4219)

Bringing Some Patches Together | Jim Wetzel

Earlier this year I decided to break down and finally buy an 80-column card for my Apple II+. After all, it's cheaper than a IIe. I was just about to type in the Videx patches from AAL Volume 2, No.11, when Bob announced Version 1.1. Well with the Videx patches and all the new features I just couldn't pass up his offer. After a call to Bob and a three day wait I had version 1.1 of the S-C Macro Assembler.

While testing out the new version I soon discovered most of the patches I had applied to version 1.0 would not work properly. The addresses of the routines/tables had all moved. After a few hours work and a lot of dis-assembling I would like to share the new locations with AAL readers and bring some of the patches together.

First I will describe the new addresses and then show how I used them.

The Escape Function Table is now located at $14AB-$14C6 <ESC-@ thru ESC-M>. This is a group of two-byte addresses (minus 1, because they are of the PHA-PHA-RTS variety) of the routines to handle the escape functions.

The Edit Function Table is now located at $1CB4-$1CE3 <ctrl-@ thru ctrl-X>. This table is somewhat different. Each entry is three bytes long and it contains the control character and the address-minus-1 of the routine to handle the function.

Location $14D3 contains the dash count <$26> for the ESC-L function.

Location $13FF contains a JSR to the monitor Bell routine. This is the end of the input checker, the JSR BELL is executed when an invalid character is entered, and a good place to put a JSR to an extended input processor.

These locations are valid for the regular version and the Videx version which load at $1000. For language card users just add $C000 to the address. My hat is off to Bob for adding all the features of Videx and still keeping the assembler looking the same. I have not checked the STB or the IIe versions for compatibility but, with a little bit of work and knowing what to look for it should be an easy process.

Now, what can you do with this information? I have modified Bob's language card loader to show you (figure 1). With the exception of the REM statements, lines 1000-1140 of the file are as Bob supplied; after that the changes begin. I will not spend a lot of time explaining the routines themselves because they are all well documented in the referenced AAL articles.

The first thing I do is load in my extended input processor (figure 2) at $F600. There appears to be about two free pages after the assembler and before monitor in the language card version. For standard version users just move the symbol table up as described AAL Vol. 2, No. 9. My input processor is a combination of Auto Catalog (AAL 2.9) and Toggling Upper/Lower Case (AAL 3.3). Next I modify the JSR BELL to JSR CONTROL.A.

Once you have control you can add any routines you wish (such as R. F. O'Brien's Auto/Manual Toggle AAL 2.11). For now I am only interested in an upper/lower case toggle.

Line 1170 modifies the ESC-C function to JSR to my routine for auto Catalog. Remember this should be the address of the routine - 1. Lines 1180-1190 change the cursor to a blinking underline (as described in AAL 3.5) along with line 1200 which changes the number of "-"'s from 38 to 64 (I found 68 to be too many).

Last but not least is an answer to Steve Mann's request for a upper/lower case toggle in EDIT mode. In version 1.1 Bob changed the ctrl-I key function in EDIT mode and added a ctrl-A key function in its place. He did it so that the //e TAB key, which generates control-I, would really mean TAB.

Well Bob, I like mnemonic commands (like ctrl-I for Insert), and think the older Apples should still take precedence. Line 1210 changes the ctrl-A key to branch to my upper/lower case toggle routine, just past the character check, and line 1220 changes the ctrl-I routine back to its proper function (this was the address found in the ctrl-A area).

I hope these patches will be useful to other AAL readers not only for what they do, but for how they do it.

      1000 REM LOAD S-C MACRO ASSEMBLER (VIDEX)
      1010 REM INTO RAM AT $D000
      1020 REM LOAD PATCHES AT $F600
      1030 REM PATCH INPUT TEST TO CHECK FOR MY COMMANDS BEFORE ERROR
      1040 REM PATCH ESCAPE TABLE ($D4AB-) FOR ESCAPE-C
      1050 REM CHANGE CURSOR TO BLINKING UNDERLINE
      1060 REM PATCH ESC-L DASH LINE COUNT
      1070 REM PATCH EDIT CNTL-A TO MY ROUTINE
      1080 REM PATCH EDIT CNTL-I BACK TO INSERT FUNCTION
      1090 CALL-151
      1100 C081 C081
      1110 F800<F800.FFFFM
      1120 BLOAD S-C.ASM.MACRO.D000.VIDEX
      1130 300:A9 4C CD 00 E0 F0 12 8D 00 E0 A9 00 8D 01 E0 A9 D0 8D 02 E0 A9 CB 8D D1 03 60
      1140 300G
      1150 BLOAD SCM.PATCH
      1160 D3FF:20 00 F6
      1170 D4B1:19 F6
      1180 C0B0:0A 68
      1190 C0B0:0B 08
      1200 D4D3:40
      1210 DCB8:03 F6
      1220 DCC7:0B DC
      1230 C080
      1240 3D3G

      1000 *SAVE WETZEL'S PATCHES TO 1.1
      1010        .OR $F600
      1020        .TF SCM.PATCH
      1030 *----------------------------------------------------------
      1040 CH     .EQ $24
      1050 BASL   .EQ $28
      1060 YSAVE  .EQ $40
      1070 WBUF   .EQ $200
      1080 LCPROT .EQ $C080    LC Protect
      1090 LCWRT  .EQ $C083    LC Write enable
      1100 UCFLAG .EQ $D016    UC/LC Flag
      1110 BELL   .EQ $FF3A    Monitor Bell
      1120 *----------------------------------------------------------
      1130 CONTROL.A
      1140        CMP #$81     Was a CNTL-A entered
      1150        BNE ERROR    No - then signal error
      1160        LDA LCWRT    Write enable Language card
      1170        LDA LCWRT
      1180        LDA UCFLAG   Get upper case flag
      1190        EOR #$FF     Reverse it
      1200        STA UCFLAG   Put it back
      1210        LDA LCPROT   Write protect Language card
      1220        RTS
      1230 ERROR
      1240        JSR BELL     Ring bell to signal error
      1250        RTS          Return
      1260 *----------------------------------------------------------
      1270 ESCAPE.C
      1280        CPX #0       Start of line?
      1290        BNE .2       No, rtn
      1300        LDY #0
      1310 .1     LDA MSG,Y    Get message
      1320        STA WBUF,Y   Put in buffer
      1330        STA (BASL),Y Put on screen (40-column)
      1340        INY
      1350        CPY #7       Finished ?
      1360        BNE .1       Not yet
      1370        STY YSAVE
      1380        INY
      1390        STY CH       Tell assembler
      1400        TSX          this was an
      1410        LDA #$CC     ESC-L so it will
      1420        STA $103,X   exec command
      1430        LDX YSAVE
      1440 .2     RTS
      1450 MSG    .AS -/CATALOG/

"One more beep and you're out!" | Bob Sander-Cederlof

We have uncovered another neat new Apple accessory: a volume control for the speaker! If other people within earshot of your computer are trying to sleep, or just can't take another five minutes of bells, beeps, and buzzes, the WHISPER VOLUME CONTROL is for you. The Apple version works with II, II Plus, //e, or ///. All you have to do to install it is take the case off your Apple, unplug the speaker wire from the board, plug in the WVC cable, and plug the speaker wire into the other end of the WVC connector. You can also get WVC for the IBM/PC. The retail price is $22.95 for the standard version, or $25.95 with a headphone jack, from Information Dynamics Corp., 1251 Exchange Drive, Richardson, TX 75081. Phone (214)783-8090. Or if you like, buy them from us at $21 and $24, respectively.

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