| Volume 3 -- Issue 11 | August 1983 |
In This Issue...
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.)