In This Issue...
Book, Books, Books
Inside this issue you will find a review of Jules Gilder's new book on intermediate-level Apple assembly language programming, and the details on those long-awaited Addison-Wesley editions of Apple's Technical Manuals. We're now offering these items for sale, and the details are in our ad.
The latest word from Prentice-Hall is that David Eyes' "Programming the 65816" will be shipped on October 29, so we may actually have copies by the time you read this. Bob will have a full review next month, and we are beginning to get orders already. The list price is expected to be $22.95. If that holds, our price will be $21.00 + postage.
A Rumor Regarding the Next Apple II
We have heard from two sources now a rumor that Apple does not plan to use the 65816 in its next Apple II. Nor the 65802, nor the 65C02. Instead, we heard, they will use a custom version of the 68000 family with 65C02 emulation capability. I think that I hope that the rumor is groundless, but I'll keep my ear to the ground anyway.
This past week I have been working on a project which involved creating a new device driver for a disk-like device. In the process of debugging my driver, I had to write a "snooper" program.
By "snooper", I mean a program which will make a list of all calls to the driver, recording the origin of the call and the parameters of the call.
ProDOS keeps a table of the addresses of the device drivers assigned to each slot and drive between $BF10 and $BF2F. There are two bytes for each slot and drive. $BF10-1F is for drive 1, and $BF20-2F is for drive 2. For example, the address of the device driver for slot 6 drive 1 is at $BF1C,1D. (Normally this address is $D000.)
I have a Sider drive in slot 7. The device driver address for the Sider is $C753, and is kept at $BF1E,1F and $BF2E,2F.
By patching the device driver address to point to my own code, I can get control whenever ProDOS tries to read or write or whatever. If I save and restore all the registers, and jump to the REAL device driver after I am finished, ProDOS will never be the wiser. But I will!
While my program has control, I can capture all the information I am interested in. Unfortunately I cannot print it out at this time, because if I try to ProDOS will get stuck in a loop. Instead I will save the data in a buffer so I can look at it later.
The program which follows has three distinct parts. Lines 1140-1290 are an installation and removal tool. If the program has just been BLOADed or LOADed and ASMed, running INSTALL.SNOOPER will (you guessed it!) install the snooper. The actual device driver address for the slot (which you specified in line 1060 before assembling the program) will be saved in my two-byte variable DRIVER. The previous contents of DRIVER, which is the address of my snoop routine, will be copied into ProDOS's table. The value of DRIVES, which you specified before assembling the program at line 1070, will determine whether SNOOPER is connected to drive 2 or not. It will always be connected to drive 1.
If SNOOPER has already been installed, running INSTALL.SNOOPER will reverse the installation process, returning ProDOS to its original state. INSTALL.SNOOPER also resets the buffer I use to keep the captured information. To make it easy to run INSTALL.SNOOPER, I put a JMP to it at $300. After assembly you can type "$300G" to install the snooper, and type the same again to dis-install it.
The JMP at $303 (line 1120) goes to the display program. After SNOOPER has been installed, all disk accesses on the installed slot will cause information to be accumulated in BUFFER. Typing "$303G" will cause the contents of BUFFER to be displayed in an easy-to-read format.
I set up SNOOPER to capture eight bytes of information each time it is activated. You might decide to save more or less. I save the return address from the stack, to get some idea of which routine inside ProDOS is trying to access the disk. I also save the six bytes at $42-47, which are the calling parameters for the device driver. Page 6-8 of Beneath Apple ProDOS describes these parameters; you can also find out about them in Apple's ProDOS Technical Reference Manual and in Gary Little's "Apple ProDOS--Advanced Features".
$42 contains the command code: 00=status, 01=read, 02=write, and 03=format. $43 contains the unit number, in the format DSSS0000 (where SSS=slot and D=0 for drive 1, D=1 for drive 2). $44-45 contain the address of the memory buffer, lo-byte first; the buffer is 512 bytes long. $46-47 contain the block number to be read or written.
My DISPLAY program displays each group of eight bytes on a separate line, in the following format:
hhll:cc.uu.buff.blok
where hhll is the return address from the stack, hi-byte first; cc is the command code; uu is the unit number; buff is the buffer address, hi-byte first; blok is the block number, hi-byte first.
If you get into figuring out more of what ProDOS is doing, you might want to save more information from the stack. You can look behind the immediate return address to get more return addresses and other data which have been saved on the stack before calling the device driver.
A word of explanation about lines 1040, 1360, 1370, 1490, and 1500. Line 1040 tells the S-C Macro Assembler that it is OK to assemble opcodes legal in the 65C02. The PHX, PHY, PLX and PLY opcodes are in the 65C02, 65802, and 65816; however, they are not in the 6502. If you have only the 6502 in your Apple, you will need to substitute the longer code shown in the comments. Leave out line 1040, and use the following:
1360 TYA 1365 PHA 1370 TXA 1375 PHA . . . 1490 PLA 1495 TAX 1500 PLA 1505 TAY
In the process of "snooping" I was able to debug my new device drivers for the project I was developing. I also discovered what appear to be some gross in-efficiencies in ProDOS. In the course of even simple CATALOGs, LOADs, and SAVEs the same blocks are read into the same buffers over and over, at times when it would appear to be totally unnecessary. If there was some mechanism inside MLI to keep track of the fact that a complete un-spoiled copy of a particular block was already in RAM, it could save a lot of time. On the other hand, it could be that the current approach is safer. I think it is a potentially fruitful area for further investigation. Any takers?
1010 *SAVE PRODOS.SNOOPER 1020 *-------------------------------- 1030 .OR $300 1040 .OP 65C02 (If you have one) 1050 *-------------------------------- 1060 SLOT .EQ 6 1070 DRIVES .EQ 2 1080 *-------------------------------- 1090 BUFFER .EQ $800 1100 *-------------------------------- 1110 A300 JMP INSTALL.SNOOPER 1120 A303 JMP DISPLAY 1130 *-------------------------------- 1140 INSTALL.SNOOPER 1150 LDX #1 1160 .1 LDA 2*SLOT+$BF10,X 1170 PHA SAVE CURRENT DRIVER ADDRESS 1180 LDA DRIVER,X INSTALL NEW DRIVER ADDRESS 1190 STA 2*SLOT+$BF10,X 1200 .DO DRIVES=2 1210 STA 2*SLOT+$BF20,X 1220 .FIN 1230 PLA REMEMBER OLD DRIVER 1240 STA DRIVER,X 1250 LDA BUFFER.ADDR,X 1260 STA A+1,X 1270 DEX 1280 BPL .1 NOW THE OTHER BYTE 1290 RTS 1300 *-------------------------------- 1310 DRIVER .DA SNOOPER 1320 BUFFER.ADDR .DA BUFFER 1330 *-------------------------------- 1340 SNOOPER 1350 PHA 1360 PHY (If no 65C02 use TYA, PHA) 1370 PHX (If no 65C02 use TXA, PHA) 1380 TSX 1390 LDA $104,X LO-BYTE OF RETURN ADDR 1400 JSR STORE.BYTE 1410 LDA $105,X HI-BYTE OF RETURN ADDR 1420 JSR STORE.BYTE 1430 LDX #0 $42...47 1440 .1 LDA $42,X WHICH ARE THE PARAMETERS 1450 JSR STORE.BYTE FOR THE CALL 1460 INX 1470 CPX #6 1480 BCC .1 1490 PLX (If no 65C02 use PLA, TAX) 1500 PLY (If no 65C02 use PLA, TAY) 1510 PLA 1520 JMP (DRIVER) CONTINUE IN DRIVER 1530 *-------------------------------- 1540 STORE.BYTE 1550 A STA BUFFER THIS ADDRESS IS MODIFIED 1560 INC A+1 BUMP PNTR TO NEXT ADDRESS 1570 BNE .1 1580 INC A+2 1590 .1 RTS 1600 *-------------------------------- 1610 COUT .EQ $FDED 1620 CROUT .EQ $FD8E 1630 PRBYTE .EQ $FDDA 1640 PNTR .EQ $00,01 1650 *-------------------------------- 1660 DISPLAY 1670 LDA #BUFFER SET UP PNTR INTO BUFFER 1680 STA PNTR 1690 LDA /BUFFER 1700 STA PNTR+1 1710 *---CHECK IF FINISHED------------ 1720 .1 LDA PNTR 1730 CMP A+1 1740 LDA PNTR+1 1750 SBC A+2 1760 BCC .2 1770 RTS 1780 *---DISPLAY NEXT 8 BYTES--------- 1790 .2 LDY #1 1800 JSR WORD DISPLAY RETURN ADDRESS 1810 LDA #":" "XXXX:" 1820 JSR COUT 1830 JSR BYTE DISPLAY ($42)=OPCODE 1840 JSR BYTE DISPLAY ($43)=UNIT NUMBER 1850 INY 1860 JSR WORD DISPLAY ($44,45)=BUFFER ADDR 1870 JSR DOT 1880 JSR WORD DISPLAY ($46,47)=BLOCK NUMBER 1890 JSR CROUT CARRIAGE RETURN 1900 LDA PNTR ADVANCE PNTR TO NEXT 1910 CLC GROUP OF 8 BYTES 1920 ADC #8 1930 STA PNTR 1940 BCC .1 1950 INC PNTR+1 1960 BNE .1 ...ALWAYS 1970 *-------------------------------- 1980 WORD LDA (PNTR),Y DISPLAY HI-BYTE 1990 JSR PRBYTE 2000 DEY DISPLAY LO-BYTE 2010 LDA (PNTR),Y 2020 INY 2030 INY ADVANCE INDEX 2040 JMP PRBYTE 2060 *-------------------------------- 2070 BYTE LDA (PNTR),Y DISPLAY BYTE 2080 JSR PRBYTE 2090 DOT LDA #"." PRINT "." 2100 INY ADVANCE INDEX 2110 JMP COUT 2120 *-------------------------------- |
Since my earlier letter (Jun 84) on the 65C02 and the Apple II+ I was interested and gratified to read Andrew Jackson's (Dec 84) and Jim Sather's (Mar 85) letters on the same subject. However, two things began to worry me. First, the smallness of the time gain in the F257 chips (around 7 nanoseconds, I understand). That did not seem enough to be very reliable. Second, a friend in town has an Apple whose speed was not sufficiently improved to allow the 65C02 to work (although there was some noticeable improvement).
After reading the first few chapters of Jim Sather's book, "Understanding the Apple II", I was able to come up with a new solution. As I figure it, this new solution yields an improvement of around 70 nanoseconds, more than enough. Simply put, just replace the -RAS line inputs to the 74LS174 chips at B5 and B8 with AX. AX rises 70 nsec earlier than -RAS, enabling those chips to latch RAM output 70 nsec earlier. It is a simple patch and may be done either with or without altering the motherboard.
I tried it first without altering my motherboard, on a Rev 44-1 Apple using 200 nsec 16K RAM chips. I was surprised to see it work, as I had expected that 200 nsec RAM chips would be too slow for the patch. (I haven't tried it yet with 250 nsec RAM chips.) Actually, this particular Apple did not need any speed-up -- the 65C02 was already working in it.
To do this patch: remove the chips at B5 and B8; seat an extra socket under each of them; pin 9 on these sockets should be bent out so they do not go into the motherboard sockets; remove the chip at C2 and put an extra socket under it; connect a wire from pin 14 of the C2 socket to the bent out pins 9 of B5 and B8. Pin 14 of the 74S195 at C2 is a source of the AX signal; pin 9 of B5 and B8 was previously connected to -RAS.
I have another Apple (Rev 4) which has 24 150 nsec 64K RAM chips (using the Cramapple mod). This Apple already had F257's in it with a 65C02. I put the old LS257's back in, and sure enough the 65C02 began to stumble. Then I removed the motherboard and on the underside cut the trace to -RAS and soldered in a jumper wire to pin 14 of C2. It worked perfectly!
Naturally those who try any of these patches do so at their own risk.
I must thank Jim Sather for his book; it was only by studying the timing diagrams in that book and staring at the circuit diagram published by Apple that I was able to do this. I hope some of the hardware types will be able to tell me if I have built a time bomb. I am also very interested to hear whether the problem with the 65802 is the same.
Of course if I want to look around in ProDOS the same curiosity certainly applies to DOS 3.3. The fact of the matter is, I started snooping in DOS first; nevertheless, the ProDOS article took precedence in these pages.
There are several nice places to patch a snooper into DOS 3.3. One is right at the beginning of RWTS, $BD00. This position is usually taken by hard disks, however. For example, Sider and Corvus use $BD00. I could skip down below $BD00, but Sider for one expects several bytes after $BD00 to be normal DOS code. Looking backward, $BD00 is normally called only from a subroutine which starts at $B7B5. This subroutine, in turn, is normally only called from $B090. Your own programs may call RWTS differently, but DOS itself almost always goes through $B090. (The exceptions are the reading and writing of the DOS image during boot or INITialization.)
Therefore...I patched my SNOOPER program in at $B090. The INSTALL.SNOOPER code in lines 1060-1160 is very similar to that in the ProDOS snooper. It swaps the address currently in my variable DRIVER with the address at $B091,2. Typing "$800G" will install SNOOPER, and typing it again will dis-install SNOOPER.
The DOS snooper prints out each line of information as it goes along, without storing the data. Each line contains the two most recent return address from the stack, so you can trace who is calling RWTS. I also print out the RWTS command, the track and sector, and the buffer address.
Here is an example of the printout, in this case during a SAVE operation:
:LOAD S.RWTS.SNOOPER :ASM Assembler SNOOPER 0000 ERRORS IN ASSEMBLY :$800G install SNOOPER :SAVE S.RWTS.SNOOPER sample DOS command AB24.AD45.01.11.00.B3BB read VTOC AB45.B1E6.01.11.0F.B4BB read Catalog sector A6AA.AB24.01.1F.0F.9700 T/S list C3E9.ACDD.01.1F.0E.9600 read 1st data sector ACDD.B0C8.02.1F.0E.9600 write 1st data sector D349.ACDD.01.1F.0D.9600 read 2nd data sector ACDD.B0C8.02.1F.0D.9600 write 2nd data sector D328.ACDD.01.1F.0C.9600 read 3rd data sector ACDD.B0C8.02.1F.0C.9600 write 3rd data sector D352.ACDD.01.1F.0B.9600 read 4th data sector ACDD.B0C8.02.1F.0B.9600 write 4th data sector A2F8.A6AA.01.11.00.B3BB read VTOC A6AA.AC1E.01.11.0F.B4BB read catalog sector A2F8.A6AA.02.11.0F.B4BB write catalog sector AD1A.AB45.01.11.00.B3BB read VTOC AB45.B1E6.01.11.0F.B4BB read catalog sector A6AA.AD1A.01.1F.0F.9700 read T/S list A6AA.AD1D.01.1F.0E.9600 read 4 data sectors A6AA.AD1D.01.1F.0D.9600 to VERIFY the file A6AA.AD1D.01.1F.0C.9600 A6AA.AD1D.01.1F.0B.9600 :$800G dis-install SNOOPER
1000 *SAVE S.RWTS.SNOOPER 1010 *-------------------------------- 1020 PRBYTE .EQ $FDDA 1030 CROUT .EQ $FD8E 1040 COUT .EQ $FDED 1050 *-------------------------------- 1060 INSTALL.SNOOPER 1070 LDX #1 1080 .1 LDA DRIVER,X 1090 PHA 1100 LDA $B091,X 1110 STA DRIVER,X 1120 PLA 1130 STA $B091,X 1140 DEX 1150 BPL .1 1160 RTS 1170 *-------------------------------- 1180 DRIVER .DA SNOOPER MODIFIED DURING OPERATION 1190 *-------------------------------- 1200 SNOOPER 1210 LDA $778 1220 STA SAVE778 1230 LDA $7F8 1240 STA SAVE7F8 1250 *-------------------------------- 1260 TSX 1270 JSR CROUT 1280 JSR PRADDR PRINT RETURN ADDR FROM STACK 1290 JSR PRADDR AND ANOTHER ONE 1300 *-------------------------------- 1310 LDA $B7F4 COMMAND 1320 JSR BYTE 1330 LDA $B7EC TRACK 1340 JSR BYTE 1350 LDA $B7ED SECTOR 1360 JSR BYTE 1370 LDA $B7F1 BUFFER ADDRESS 1380 JSR PRBYTE 1390 LDA $B7F0 1400 JSR PRBYTE 1410 *-------------------------------- 1420 LDA SAVE778 1430 STA $778 1440 LDA SAVE7F8 1450 STA $7F8 1460 LDA $AAC2 1470 LDY $AAC1 1480 JMP (DRIVER) 1490 *-------------------------------- 1500 PRADDR 1510 LDA $108,X 1520 JSR PRBYTE 1530 LDA $107,X 1540 DEX SET UP FOR NEXT ADDRESS 1550 DEX 1560 BYTE JSR PRBYTE 1570 LDA #"." 1580 JMP COUT 1590 *-------------------------------- 1600 SAVEX .BS 1 1610 SAVEY .BS 1 1620 SAVE778 .BS 1 1630 SAVE7F8 .BS 1 1640 *-------------------------------- |
So the Sieve lives! Bob's article last month misses some of the facts, however. He states that my improved 68000 version on my 12.5 MHz DTACK Grounded board ran in .4 seconds; the actual time was .33 seconds. This is proportional to the .49 seconds claimed in the later Byte article for an 8 MHz 68000. My DTACK Grounded board uses 120 nanosecond static RAM and runs at a full 12.5 MHz speed (DTACK grounded means that the processor CANNOT wait for memory).
Hal Hardenburgh (editor of the now sadly no more DTACK newsletter and no slouch when it comes to assembly programming on the 68000) produced his own version of the original algorithm, essentially hand-compiled BASIC since that was what he wanted to compare to, and that ran in 1.29 secs for 10 iterations on a 10MHz board.
My faster 68000 sieve was my first 68000 program, so in light of my now more extended experience I tried to tighten it up even further. The result runs in .28 seconds for ten iterations on my DTACK board, and .72 seconds on a Macintosh. The main speed improvement comes from loading two extra registers for comparisons rather than doing CMPI's. The use of MOVEM for clearing the array was pointed out to me by Hal Hardenburgh and accounts for about .02 secs saved, at the expense of a large amount of elegance (oh well, what price aesthetics?).
In trying to guess the comparisons of the 65816 systems of the future with existing 68000 systems, two questions come to mind. First, if 6 or 8 MHz 65816s become available in quantity, how fast will the memory have to be to keep up? The 68000 can automatically adjust for slower memories, but is this true of the 65816? Second, and more importantly, is the question of memory addressing.
I wrote a version of the sieve that sifts the first 262143 integers. This took 13.5 seconds for 10 iterations on a Macintosh (this should equate to 5.3 seconds on my DTACK board, but I don't have enough memory to test it.) The program is only minimally different from the original (some constants changed and some address modes changed from word to long.)
How about writing a 65816 program to handle this large of an array? How much extra baggage is required to test page boundaries, move base addresses, etc? My point is that the restriction of 64K banks can really hurt in accessing large data arrays. Memory is getting cheaper all the time, so using more bytes for a 68000 program may well be no penalty, compared with the extra difficulty of writing 65816 code to handle large amounts of data.
I think I have come up with an interesting puzzle. Pretend that your Apple has only 48K of RAM: no ROM, no soft switches, no memory cards, just 48152 bytes of contiguous RAM from $0000 through $BFFF. Now, write a program which will store one number (of your choosing) into each and every one of these 49152 locations. The stumper here is creating a program which can overwrite itself completely, and which will not go running off through the I/O area causing disks to spin, etc.
There are certain limitations to actually implementing this on an Apple. When you hit <RESET> to examine the contents of memory after running your program, memory will be changed before you can look at it. It is unavoidable that page zero, the stack, and text screen memory will all get disrupted as soon as <RESET> is pressed. You still need to include these areas in your program, but you just will not be able to check them.
You will have to figure out some way of stopping the program before it runs off into the $Cxxx space. I decided to accept this limitation by allowing three bytes at $BFFD-F to contain a JMP instruction, not stuffing my favorite number in them. So my solution actually only stuffs my number into $0000-$BFFC.
Bob Sander-Cederlof has a solution that stuffs the same number in every byte from $0000 through $BFFF, but depends on two locations in the I/O area to stop the program from rampaging around $Cxxx space.
Try your hand at this puzzle! Next month we'll show some of the best solutions.
AAAA Applesoft A CALL Utility for Applesoft....................David Johnson... 6/85/24-27 Correction to Line Number XREF....................Bill Morgan...10/84/18 Double Precision Arithmetic ...see Double Precision Floating Point Package Fast Text Windows for Applesoft.................Michael Ching... 4/85/16-20 80-Column Window Utility for //e and //c............Bill Reed... 5/85/11-15 BBBB Benchmarks Prime Benchmark for the 65802.........................Bob S-C... 9/85/2-9 Book Reviews "Apple II+/IIe Troubleshooting & Repair Guide"..................11/84/1 "Apple ProDOS: Advanced Features for Programmers".............. 5/85/18-19 "Applevisions".................................................. 6/85/21 "Assembly Language for the Applesoft Programmer"................ 2/85/20 "Enhancing Your Apple II and //e, vol. 2"....................... 5/85/1 "Inside the Apple //c".......................................... 4/85/7 "Inside the Apple //e"..........................................12/84/16-18 "Open Apple"....................................................12/84/1 Out of Print..........................................Bob S-C...10/84/16 The Boyer-Morris String Search Algorithm............Bob Bernard... 6/85/2-12 Buffering //c + Z-RAM = 576K Printer Buffer...............David Johnson... 8/85/2-10 CCCC Conversions Convert Two Decimal Digits to Binary..................Bob S-C...11/84/15-16 Generic Conversion Routines...........................Bob S-C... 8/85/17-21 Improving the Single-Byte Converter................Bruce Love... 6/85/21 Short Binary-Decimal Conversion in 65802..............Bob S-C... 9/85/24-28 Short Single-Byte Hex-to-Decimal Printer..............Bob S-C... 1/85/31-32 Sly Hex Conversion....................................Bob S-C...12/84/21-22 Corrections Correction to DP18, part 5......................Paul Schlyter...10/84/10 Correction to Line Number XREF....................Bill Morgan...10/84/18 Correction to Symbol Table Source Maker...............Bob S-C... 2/85/25 Improvements to 80-Column Monitor Dump..........Jan Eugenides...11/84/22-23 Cross Assemblers 6800/6801/6301 Cross Assembler Version 2.0...................... 1/85/1 6800/6801/6301 Cross Assembler ProDOS........................... 8/85/1 An 8086/8088 Cross Assembler....................Don Rindsberg... 4/85/21 DDDD Disassemblers Adapting the Output Format of RAK-Ware DISASM......Bob Kovacs... 5/85/21-22 A Disassembler for the 65816..........................Bob S-C... 3/85/20-28 Generating Cross Reference Text File with DISASM...Bob Kovacs...11/84/23 How Many Bytes for Each Opcode?.......................Bob S-C... 8/85/12-16 DOS Enhancements and Patches Improved DOS 3.3 Number Parsing & Lower-Case Commands.Bob S-C... 3/85/15-18 Making DOS-Less Disks.................................Bob S-C... 2/85/21-25 New Catalog for DOS 3.3.....................Robert F. O'Brien... 5/85/2-11 New Catalog Revisited.......................Robert F. O'Brien... 7/85/32 Put DOS and ProDOS Files on the Same Disk.............Bob S-C... 9/85/11-20 Reading DOS 3.3 Disks with ProDOS.....................Bob S-C... 7/85/2-14 Shortening the DOS File Buffer Builder................Bob S-C... 3/85/2-9 A Solution to Overlapping DOS Patches..............Paul Lewis...12/84/27 Volume Catalog for Corvus and Sider...................Bob S-C... 4/85/9-11 Wildcard Filename Search..............................Bob S-C... 8/85/22-28 Double Precision Floating Point Package Correction to DP18, part 5......................Paul Schlyter...10/84/10 New DP18 Square Root Subroutine.......................Bob S-C...11/84/20-21 Part 6, VAL, INT, ABS, SGN, and SQR Functions.........Bob S-C...10/84/2-9 Part 7, LOG and EXP Functions.........................Bob S-C...11/84/2-13 Part 8, Trig Functions................................Bob S-C...12/84/2-14 Part 9, PRINT.........................................Bob S-C... 1/85/2-24 Part 10, INPUT........................................Bob S-C... 2/85/2-14 Some Final DP18 Subroutines...........................Bob S-C... 5/85/28 GGGG Graphics Building Hi-Res Pre-Shift Tables.............Gianluca Pomponi... 2/85/26-28 Generating Tables for Faster Hi-Res...................Bob S-C...12/84/24-26 Short Integer Square Root Subroutine..................Bob S-C... 6/85/13 HHHH Hardware Reviews The Oki 6203 Multiply/Divide Chip.....................Bob S-C... 3/85/19 Review of the FCP Hard Disk (The Sider)...............Bob S-C... 4/85/27-28 Review of the M-c-T SpeedDemon........................Bob S-C... 7/85/16-22 A Whole Megabyte for Your Apple //e...................Bob S-C...11/84/18 Write Guard Disk Modification Kit............................... 2/85/19 IIII Interrupt Trace...............................Charles H. Putney... 6/85/16-20 MMMM Macro Information by Example....................Sandy Greenfarb...11/84/24-25 Monitor Enhancements and Patches Two ROM Sets in One Apple //e.........................Bob S-C... 6/85/22-23 NNNN New Product Announcements 6800/6801/6301 Cross Assembler Version 2.0...................... 1/85/1 6800/6801/6301 Cross Assembler ProDOS........................... 8/85/1 Blind Word Processor............................................10/84/1 S-C Macro Assembler Version 2.0.................................11/84/14 S-C Macro Assembler Version 2.0 DOS Source Code................. 9/85/1 S-C Macro Assembler ProDOS...................................... 6/85/1 PPPP Prime Benchmark for the 65802...........................Bob S-C... 9/85/2-9 ProDOS Allow BSAVE to New Non-Binary Files in BASIC.SYSTEM......... ......Mark Jackson... 7/85/30-31 DATE Command for ProDOS...........................Bill Morgan... 5/85/23-32 Finding Memory Size in ProDOS.........................Bob S-C... 3/85/28 Multi-Level ProDOS Catalog............................Bob S-C... 7/85/23-30 Put DOS and ProDOS Files on the Same Disk.............Bob S-C... 9/85/11-20 Reading DOS 3.3 Disks with ProDOS.....................Bob S-C... 7/85/2-14 Shrinking Code Inside ProDOS..........................Bob S-C... 4/85/12-14 RRRR Remembering When........................................Bob S-C...12/84/23 Reviews, see "Book Reviews", "Hardware Reviews", "Software Reviews" SSSS S-C Macro Assembler 32-bit Values in Version 2.0 -- A Mixed Blessing......Bob S-C... 5/85/32 AUTO/MANUAL Toggle Update for Version 2.0...Robert F. O'Brien... 5/85/15-16 Patches for Time/Date in Titles....................R. M. Yost... 2/85/18 Putting S-C Macro on a QuikLoader Card..........Jan Eugenides... 4/85/2-7 Questions and Answers........................................... 2/85/16-18 Reading DOS 3.3 Disks with ProDOS.....................Bob S-C... 7/85/2-14 S-C Macro Assembler Version 2.0...................Bill Morgan...11/84/14 Symbol Table Source Maker......Peter McInerney and Bruce Love... 1/85/25-30 USR Command to List Major Labels Only.................Bob S-C... 4/85/24-27 Videx UltraTerm Driver.......................................... 3/85/1 Videx VideoTerm Driver Revision................................. 7/85/1 Searching Boyer-Morris String Search Algorithm..............Bob Bernard... 6/85/2-12 Wildcard Filename Search..............................Bob S-C... 8/85/22-28 Software Reviews Blankenship's BASIC...................................Bob S-C...12/84/26 Macintosh Assemblers...............................Lane Hauck...10/84/24-28 Software Sources for the 65802 and 65816..............Bob S-C... 9/85/21-23 String Search Algorithm, Boyer-Morris...............Bob Bernard... 6/85/2-12 Symbol Table Source Maker........Peter McInerney and Bruce Love... 1/85/25-30 Correction to Symbol Table Source Maker...............Bob S-C... 2/85/25 TTTT Techniques The Boyer-Morris String Search Algorithm..........Bob Bernard... 6/85/2-12 Building Hi-Res Pre-Shift Tables.............Gianluca Pomponi... 2/85/26-28 Even Trickier "Index to Masks"...... ......Charles Putney, Bruce Love, and David Eisler...10/84/9-10 Generating Tables for Faster Hi-Res...................Bob S-C...12/84/24-26 Making DOS-Less Disks.................................Bob S-C... 2/85/21-25 Short Integer Square Root Subroutine..................Bob S-C... 6/85/13 Strange Way to Divide by 7............................Bob S-C...12/84/19-20 Turning Bit-Masks into Indices........................Bob S-C...11/84/26-28 Two ROM Sets in One Apple //e...........................Bob S-C... 6/85/22-23 UUUU Utility Programs A CALL Utility for Applesoft....................David Johnson... 6/85/24-27 A Disassembler for the 65816..........................Bob S-C... 3/85/20-28 Interrupt Trace.............................Charles H. Putney... 6/85/16-20 Making DOS-Less Disks.................................Bob S-C... 2/85/21-25 Multi-Level ProDOS Catalog............................Bob S-C... 7/85/23-30 Put DOS and ProDOS Files on the Same Disk.............Bob S-C... 9/85/11-20 Reading DOS 3.3 Disks with ProDOS.....................Bob S-C... 7/85/2-14 Symbol Table Source Maker......Peter McInerney and Bruce Love... 1/85/25-30 VVVV Volume Catalog for Corvus and Sider.....................Bob S-C... 4/85/9-11 WWWW Wildcard Filename Search................................Bob S-C... 8/85/22-28 65C02 65C02s in Old Apples.................................Jim Sather... 3/85/10-14 More on Using 65C02's in Old Apples..............Andrew Jackson...12/84/15 65802/65816 The 65802 is Here!....................................Bob S-C...10/84/12-16 65816 News........................................Bill Morgan...11/84/19 Correction re MVN and MVP in 65802....................Bob S-C...12/84/18 A Disassembler for the 65816..........................Bob S-C... 3/85/20-28 How Many Bytes for Each Opcode?.......................Bob S-C... 8/85/12-16 Note on the TXS Instruction in the 65802..............Bob S-C... 6/85/14-15 A Powerful 65816 Board on the Horizon.................Bob S-C... 4/85/22-23 Prime Benchmark for the 65802.........................Bob S-C... 9/85/2-9 Problems with 65802's in Apple II+....................Bob S-C... 9/85/23 Short Binary-Decimal Conversion in 65802..............Bob S-C... 9/85/24-28 Shortening the DOS File Buffer Builder................Bob S-C... 3/85/2-9 Software Sources for the 65802 and 65816..............Bob S-C... 9/85/21-23
When I'm writing and debugging a program, I always use a lot of printer paper as I list and re-list version after version of my creation. Using the Apple monitor's 'L' command wastes a lot of that paper, too. Since each disassembled line takes at most 36 characters, I end up wasting half of each page!. I know I could feed the paper through a second time with the right hand side now on the left, but the left hand listing isn't always the same length as the right, so I end up with listings that span several separate lengths of paper. I've written a program to solve this dilemma (as if you hadn't guessed!), and I call it PolyCol.
PolyCol will be of use no matter what type of printer you have: daisywheel printer and 80-column video card owners will get two columns per page (screen), 80-column dot matrix owners can get up to four columns per page by using compressed printing, and those with wider carriages can get even more! In addition, by compressing the print size vertically as well, it is possible to get a disassembly of all the ROMs in the Apple onto only 16 pages! (It's also possible to go blind trying to read it!)
Note that rather than creating all the text in memory, and then dumping an entire page at once, PolyCol calculates which opcode to disassemble where, 'on-the-fly'. You might think that this would slow things down appreciably; but in fact unless you require tens of columns, the listing is done relatively quickly.
As you will see from the listing, seven zero-page locations are used to hold the parameters which the user must specify. You must store the starting and ending addresses of the area to be dis-assembled into locations $00-03. Locations $04-07 control the number of lines per page and columns per line, as well as several other features. Here are some examples to show what you can do with different parameter settings:
$04 $05 $06 --- --- --- $01 $14 $FE - Standard monitor 'L' listing. Press any key to see the next page. $02 $36 $FF - Two column, 54 line page with a form feed in between pages $04 $4C $0C - Four column, 76 line page with 12 spaces between pages. Don't forget to set elite typeface and compressed print. $04 $70 $FF - Four column, 112 lines per page! To do this I had to use compressed elite super- script, with a line spacing of 1/12th in.
You can add just a little code to POLYCOL to set it up as a control-Y command. Then you could set the starting and ending addresses as in normal monitor commands. The other four parameters could also be specified in the control-Y command format, if you really get serious about modifications.
1000 *SAVE S.POLYCOL 1010 *-------------------------------- 1020 * PolyCol 1030 * Produces multi-column Apple monitor dis-assemblies. 1040 * Copyright (c) 1986 Adam Levin 1050 *-------------------------------- 1060 .OR $800 1070 *---User parameters-------------- 1080 STRTL .EQ $00 Starting address 1090 STRTH .EQ $01 1100 ENDL .EQ $02 Ending address 1110 ENDH .EQ $03 1120 NCPP .EQ $04 # Columns per page 1130 * (0 <= NCPP <= FF) 1140 * (each column takes 34 chars.) 1150 NLPP .EQ $05 # Lines printed per page 1160 * (0 <= NLPP <= FF) 1170 NSKP .EQ $06 # Blank lines between pages 1180 * (0 <= NSKP <= FF) 1190 * (FF = Form feed) 1200 * (FE = pause between pages) 1210 SLOT .EQ $07 Slot # to direct output to 1220 * (0 <= SLOT <= 7) 1230 * (0 = use currently active device) 1240 *---Program variables------------ 1250 BRUNFX .EQ $08 Holds the DOS stack pointer 1260 TOFARL .EQ $09 Adrs of 1st opcode in col 2; 1270 TOFARH .EQ $0A 1st column ends just before it. 1280 TCSWL .EQ $0B Holds the 'other' CSWL address 1290 TCSWH .EQ $0C 1300 COLCNT .EQ $0D Current column 1310 TEMPL .EQ $0E Temporary storage 1320 TEMPH .EQ $0F " " 1330 *---Monitor variables------------- 1340 FORMAT .EQ $2E Holds addressing mode code 1350 CSWL .EQ $36 Character Output SWitch Low address 1360 CSWH .EQ $37 " " " High " 1370 PCL .EQ $3A Adrs of opcode currently being 1380 PCH .EQ $3B dis-assembled. 1390 STKPTR .EQ $AA59 DOS 3.3 stack pointer save loc't'n 1400 KBD .EQ $C000 Keyboard 1410 STROBE .EQ $C010 Clear keyboard strobe 1420 *---Monitor ROM Subroutines------ 1430 INSDS2 .EQ $F88C Formats each disassembly line 1440 INSTDSPA .EQ $F8D3 Print opcode & operand 1450 PRBL2 .EQ $F94A Prints (X-reg) many blank spaces 1460 PCADJ .EQ $F953 Adjusts A,Y (PCL,H) after each line 1470 RDKEY .EQ $FD0C Get an input character 1480 CROUT .EQ $FD8E Print a <RETURN> 1490 PRYX2A .EQ $FD99 Print 'adrs-' 1500 COUT .EQ $FDED Print Acc as a character 1510 *---Macro definitions------------ 1520 .MA CMPD Double byte CMP 1530 LDA ]1 From the S-C 1540 CMP ]2 MACRO LIBRARY file. 1550 LDA ]1+1 1560 SBC ]2+1 1570 .EM 1580 * 1590 .MA MOVD Double byte MOV 1600 LDA ]1 1610 STA ]2 1620 LDA ]1+1 1630 LDA ]2+1 1640 .EM 1650 * 1660 .MA MSG MESSAGE PRINT MACRO 1670 LDX #]1 1680 JSR PRINT.MESSAGE 1690 .EM 1700 *--------------------------------- 1710 POLYCOL 1720 LDA STKPTR Save stack pointer now, 1730 STA BRUNFX restore it at the end. 1740 LDA SLOT Send the output to another device? 1750 BEQ .1 No. 1760 ORA #$C0 Use $Cn00 (n=SLOT) so we can simulate a 1770 LDX #0 PR#n when we swap CSWL,H & TCSWL,H. 1780 BEQ .2 This creates a problem if SLOT <> 0 & 1790 .1 LDA CSWH SLOT contains an 80-col card since PR# 1800 LDX CSWL can activate card, but not de-activate. 1810 .2 STA TCSWH No harm done, but it can be confusing. 1820 STX TCSWL 1830 JMP PAUSE2 Start out by waiting for a keypress. 1840 *-------------------------------- 1850 STRT LDA NLPP 'CALC' NLPP lines from STRTL,H. 1860 STA TEMPL Adrs of the opcode just after the last 1870 LDA #0 one in column one. Store in TOFARL,H 1880 STA TEMPH to keep STRTL,H from going beyond it. 1890 JSR CALC 1900 >MOVD PCL,TOFARL 1910 COLM1 LDA #1 Always start in column one. 1920 STA COLCNT Set COLCNT to 1 1930 >CMPD ENDL,STRTL Have we finished? 1940 BCS NOESC No, ENDL,H >= STRTL,H 1950 JSR CROUT Yes, purge last printed line. 1960 ESC JSR SWAP <ESC> brings you here, too. 1970 >MSG M.BYE Print end message. 1980 LDA BRUNFX Restore the stack pointer 1990 STA STKPTR 2000 RTS All done. 2010 NOESC >CMPD STRTL,TOFARL About to pass col 2? 2020 BCC NULINE No, so continue 2030 LDX NCPP Yes, so find the new first 2040 JSR MULT line for the new first column. 2050 JSR CALC 2060 >MOVD PCL,STRTL 2070 NUPAGE LDX NSKP Page breaks 2080 CPX #$FE 2090 BEQ PAUSE Pause 2100 BCS FRMFD Form feed 2110 CPX #0 2120 .1 BEQ STRT No break - solid listing 2130 JSR CROUT Yes, print NSKP lines 2140 DEX 2150 JMP .1 2160 *-------------------------------- 2170 FRMFD LDA #$8C 2180 JSR COUT 2190 JMP STRT 2200 *-------------------------------- 2210 PAUSE JSR CROUT Print a <RETURN> 2220 JSR SWAP Swap TCSWL,H & CSWL 2230 PAUSE2 >MSG M.PAUSE Print PAUSE msg 2240 JSR RDKEY 2250 JSR SWAP Swap back 2260 JMP STRT Do it all again 2270 *-------------------------------- 2280 NULINE JSR CROUT Print a <RETURN> 2290 LDA KBD A key might have been pressed 2300 EOR #$9B It might have been <ESC> 2310 BNE OFFSET It wasn't; continue 2320 BIT STROBE It was! ESCape! 2330 JMP ESC 2340 OFFSET LDX COLCNT Compute which opcode to 2350 JSR MULT Disassemble next. 2360 JSR CALC 2370 >CMPD ENDL,PCL Is adrs be beyond ENDL,H? 2380 BCC NEXTOP Yes, don't bother with it 2390 LDX PCL No, so disassemble it 2400 LDY PCH 2410 JSR PRYX2A Print the opcode address 2420 LDX #1 2430 JSR PRBL2 Print 1 blank. Monitor puts three 2440 * here, but if each column is no more 2450 * than 34 chars long, can fit 4 columns 2460 * onto a printer with 132 chars/line. 2470 JSR INSDS2 Format it 2480 JSR INSTDSPA Print it 2490 LDA COLCNT If last column, don't pad. 2500 CMP NCPP 2510 BEQ NXTCOL It is, get out 2520 LDX #0 Isn't, so pad with blanks so that each 2530 * column takes exactly 34 characters. 2540 JSR INSDS2 Calculate the format code 2550 LDX #10 ASSUME 10 SPACES 2560 LDA FORMAT Get it 2570 BEQ SPACE 1 byte code requires 10 spaces 2580 LDX #7 ASSUME 7 SPACES 2590 CMP #$81 Z-page 2600 BEQ SPACE 2610 DEX ASSUME 6 SPACES 2620 CMP #$21 Immediate 2630 BEQ SPACE 2640 DEX ASSUME 5 SPACES 2650 CMP #$82 Absolute 2660 BEQ SPACE 5 SPACES 2670 CMP #$85 Zpage,Y 2680 BEQ SPACE 5 SPACES 2690 CMP #$91 Zpage,X 2700 BEQ SPACE 5 SPACES 2710 CMP #$9D Relative 2720 BEQ SPACE 5 SPACES 2730 LDX #3 All others 2740 SPACE JSR PRBL2 Print (X-reg) many blanks 2750 NXTCOL INC COLCNT Go to next column 2760 LDA NCPP 2770 CMP COLCNT Have we gone too far? 2780 BCS OFFSET No, do OFFSET 2790 NEXTOP LDA #1 Jump over the line 2800 STA TEMPL just done. 2810 LDA #0 2820 STA TEMPH 2830 JSR CALC 2840 >MOVD PCL,STRTL Store it in STRTL,H 2850 JMP COLM1 And do it all again 2860 *--------------------------------- 2870 * CALC returns the opcode adrs that is TEMPL,H 2880 * disassembled (!) lines from STRTL,H 2890 * It returns this address in PCL,H 2900 CALC >MOVD STRTL,PCL Put STRTL,H into PCL,H for INSDS1 2910 .1 LDA TEMPL If TEMPL,H = 0 then done 2920 ORA TEMPH 2930 BEQ .3 2940 LDX #0 2950 JSR INSDS2 Get end of the next opcode & operand 2960 JSR PCADJ Get the new address from PCADJ 2970 STA PCL Store the resulting address in PCL,H 2980 STY PCH 2990 LDA TEMPL DEC TEMPL,H - with help 3000 BNE .2 from the MACRO LIBRARY again! 3010 DEC TEMPH 3020 .2 DEC TEMPL 3030 CLV Exit from top of loop, not here 3040 BVC .1 Always taken 3050 .3 RTS 3060 *-------------------------------- 3070 * MULT returns (NLPP * n-1). N is usually 3080 * COLCNT, and as such is usually a small 3090 * number (almost always smaller than NLPP). 3100 * So MULT simply adds NLPP to itself n times. 3110 * Returns with result in TEMPL,H 3120 MULT LDA #0 Zero TEMPL,H 3130 STA TEMPL 3140 STA TEMPH 3150 .1 CLC 3160 .2 DEX Exit loop from top, so call with n+1 3170 BEQ .3 Anything times 0 equals 0 3180 LDA TEMPL Add NLPP to TEMPL,H 3190 ADC NLPP 3200 STA TEMPL 3210 BCC .1 ...NO CARRY, KEEP ADDING 3220 INC TEMPH ...CARRY 3230 BCS .1 ...ALWAYS 3240 .3 RTS 3250 *-------------------------------- 3260 SWAP LDA CSWL Swap output device adrses. They are 3270 LDX TCSWL the same if SLOT = 0, but swap anyway. 3280 STX CSWL 3290 STA TCSWL 3300 LDA CSWH 3310 LDX TCSWH 3320 STX CSWH 3330 STA TCSWH 3340 RTS 3350 *-------------------------------- 3360 PM.1 JSR COUT 3370 INX 3380 PRINT.MESSAGE 3390 LDA MSGS,X 3400 BMI PM.1 3410 RTS 3420 *-------------------------------- 3430 MSGS 3440 M.PAUSE .EQ *-MSGS 3450 .AT -'PRESS A KEY ' 3460 M.BYE .EQ *-MSGS 3470 .AT -'*** END OF LISTING ' 3480 *-------------------------------- |
Those elusive Apple technical manuals are finally coming out of hiding! As we reported some months ago, Addison-Wesley is beginning to distribute Apple's manuals, and we can now supply them for you. The ones we have seen are at least as good as Apple's own editions, and in some cases better.
Here are the titles that we can order for you:
Applesoft Tutorial - $29.95, disk. Beginner's introduction to Applesoft, with a disk of examples.
Applesoft BASIC Programmer's Reference Manual - $22.95, 373+xxv pages. Complete reference manual for Applesoft, documenting all features with many examples.
BASIC Programming with ProDOS - $29.95, 264+xxix pages, disk Covers using ProDOS from BASIC, including command and file handling. The disk includes lots of examples, and the useful Applesoft Programmer's Assistant program, which includes RENUMBER, MERGE, AUTOmatic line numbering, REM deletion, variable cross reference, and other features.
And here are the ones that look most important, that we expect to keep in stock here at S-C:
Apple //e Technical Reference manual - $24.95, 409+xxxii pages. Here's Apple's documentation of all the internals of the //e, including I/O devices and firmware, memory organi- zation, the System Monitor, peripheral-card programming, the Super Serial Card, and hardware implementation. The new edition includes all the new features of the Enhanced //e and a complete source listing of the ROMs. This book is essential for serious //e programming.
Apple //c Technical Reference Manual - $24.95. And here is the same detailed coverage of the //c, and more. Additional topics documented in this book are the built-in serial I/O ports, the mouse input, and interrupt handling. If you want to use these features of the //c, get this book.
ProDOS Technical Reference Manual- $29.95, 186+xvii pages, disk. This is the official book on ProDOS, covering files, MLI calls, System programs, interrupt handling, and more. The disk is the ProDOS Exerciser, which allows you to experiment with all of the MLI calls without writing special programs. This book completes a ProDOS programmer's reference shelf, along with Beneath Apple ProDOS, and Apple ProDOS: Advanced Features.
The //e manual was scheduled for July publication: we just received it and the ProDOS manual today. The //c manual is scheduled for November delivery: we'll accept orders and ship the book as soon as A-W comes through.
Many thanks to Apple and to Addison-Wesley for making these important documents so easily available.
Do you know the difference between LDA LABEL,X and LDA (LABEL),Y but wonder when to use which? Are you confused by the way PHA, PHA, RTS doesn't go home, but jumps somewhere else entirely? Do you know what the 6502 opcodes do, but still feel lost when it comes time to combine them into a program?
Jules Gilder, a long-time contributor to several of the Apple Magazines, has written a book just for you. He spends about 190 pages covering the intermediate level of assembly language programming in the Apple II computer. His programs are very well commented, and the accompanying text contains almost a line-by-line discussion of how and why each program works.
Gilder concentrates on the Apple-specific features of 6502 programming: input and output hooks, the internal speaker, and basic linkage to Applesoft. This combination should make this book especially appealing to those of you who have learned 6502 from a "generic" book and want to find out how to apply your new knowledge to your Apple II's.
Here is a summary of each chapter of Now That You Know...:
1) Before You Get Started -- This is an introduction to assemblers and their conventions.
2) Getting Information out of Your Computer -- This chapter covers simple output, including message printing and decimal number display.
3) Getting Information into Your Computer -- Here we get into reading keystrokes and lines, handling decimal input, and also menu control structures.
4) Stealing Control of the Output -- This one goes into taking over the output hook to do custom printer setup codes and drivers, output filtering, and formatting.
5) Stealing Control of the Input -- Learn how to grab the input hook to add a custom cursor, numeric keypad, an in-memory EXEC simulator, an Applesoft keyboard macro facility, and a lower-case input driver using the shift-key modification.
6) Using Sound in Your Programs -- How to use the Apple's built-in speaker to create a variety of sounds.
7) Learning to Use the Ampersand -- Here are techniques for hooking into the &-vector to do hexadecimal input and output in Applesoft, find a program line in memory, append two Applesoft programs, and revive a program lost by the NEW command.
8) Expanding Applesoft BASIC -- Now we can have computed GOTO, GOSUB and LIST, do double-byte PEEKs and POKEs, switch between two Applesoft programs sharing memory and variables, and add function keys to control output modes.
The only real weakness in this book is the complete lack of attention to the Apple's graphic display possibilities, and comparatively little coverage of dealing with DOS (and only one small appendix covering conversion to ProDOS.) I suppose Gilder regards these as more advanced topics. Hopefully he will see fit to focus on such subjects in a future book.
Gilder's company, Redlig Sytems, Inc., also has diskettes of all the programs in the book, in either source or object form.
We'll be carrying Now That You Know... for only $18 + shipping.
Apple Software Protection Digest
Gilder is also starting a newsletter on the subject of Apple software protection. This publication is devoted both to protecting your own programs and defeating the protection on others'. Here is part of Jules' description:
Apple computer owners need a place where they can get more information about software protection. They need a forum where they can exchange ideas with others who face the same or similar problems. They need to know what software protection is, how it's implemented, what are the consequences of it, how it can be overcome if necessary and if there are any comparable unprotected alternatives to particular protected software packages.
Apple Software Protection Digest will provide you with this information and more. It will show you new ways to protect, unprotect and backup your programs. It will teach you how to prevent others from accessing your programs and it will show you how to make them more difficult to copy. In addition, you'll learn how to overcome these and other protection schemes that are in use. You'll learn how to use the powerful, but compli- cated nibble copy programs. You'll also learn how to crack or remove protection entirely from many programs.
In the first issue he covers hiding Applesoft program lines (and finding them once they're hidden), making a machine language program automatically execute when BLOADed, protecting a disk by adding extra tracks and leaving some tracks unformatted, backing up The Print Shop, and he reviews the Copy II Plus nibble copier.
As a special offer for AAL subscribers, Gilder will give you a free copy of the first issue of Apple Software Protection Digest. Just send your name and address to Redlig Systems, Inc., 2068) 79th St., Brooklyn, NY, 11214. Be sure to mention that you are an AAL reader. The subscription rate is $24 for one year, or $42 for two years.
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 $18 per year in the USA, sent Bulk Mail; add $3 for First Class postage in USA, Canada, and Mexico; add $14 postage for other countries. Back issues are available for $1.80 each (other countries add $1 per back issue for postage).
All material herein is copyrighted by S-C SOFTWARE CORPORATION,
all rights reserved. (Apple is a registered trademark of Apple Computer, Inc.)