Apple Assembly Line
Volume 5 -- Issue 7 April 1985

In This Issue...

A New Book Appears

Jim Sather's new book, Understanding the Apple //e, arrived today. We'll have a complete review next month, but at first glance it looks even better than his first book. Check our ad on page 3 for pricing.

And an Old Book Reappears

Roger Wagner Publishing has obtained the rights to Roger's "Assembly Lines -- the Book" from Softalk. A new edition is now available, still at $19.95. We sold hundreds of copies of this book, which in excellent tutorial fashion leads a beginner into the fascinating world of assembly language. "Assembly Lines -- the Disk" is also available, with all the sample source code formatted for the Merlin assembler. If you wish to order the book from us, our price is only $18 plus shipping.

Postage Increases

The recent Post Office rate increases had little effect on the Bulk and First Class rates, only $.015-.03 per piece, or $.18-.36 per year per subscription. We'll accept that much of a cost increase. Foreign Air Mail is another matter, though. Those rates went up by $.16-.19 per piece, or $1.92-2.28 per year per subscription. Therefore, the foreign subscription rate is now $32 per year.

Putting S-C Macro on a QuikLoader Card Jan Eugenides

The QuikLoader by Southern California Research Group is one of those rare devices that causes you to wonder how you ever got along without one. I have had mine for about a year now, and I would never go back to the old way of loading programs!

Briefly, the QuikLoader allows you to put whatever programs you desire on EPROMS, which then plug into the QuikLoader. EPROMS from 2716-27512 can be used, for a possible 512K bytes of program space on one QuikLoader (equivalent to four Apple floppies!). You can have more than one card, of course, so there's lots of room available for just about anything. The QuikLoader also comes with DOS 3.3 already installed, along with FID, and COPYA. When you turn on your machine, you'll hear a little whoop instead of the familiar beep. DOS has just been loaded in about 2 seconds. No more booting! In fact, I seldom put DOS on a disk anymore, and I can use the space for programs instead.

Programs which are on the QuikLoader can be loaded into RAM and executed in about 2 seconds, with just two keystrokes! Since they are loaded into their regular RAM locations, they do NOT need to be modified in any way.

You can see a catalog of the QuikLoader by typing "Q" followed by RESET. The program names appear with letters A-Z next to them. Then you can select and run the programs by typing the letter corresponding to that program. Alternatively, if you want to run the primary routine on a chip, just press the number of the socket it is in followed by RESET. More on this later.

Putting programs on the QuikLoader is somewhat problematical, however. The manual is STILL in it's draft form, although they have been promising a better one for over a year. Oh well...a little trial and error is good for the soul.

In order to put the S-C Macro Assembler on the QuikLoader, it is necessary to write what's known as a "primary" routine. The QuikLoader has a built-in operating system which allows you to move blocks of memory to their RAM locations from the various EPROMS on the QuikLoader card, and then execute them however you wish. The following program is intended to be used on a 27128 EPROM, which will hold the entire S-C Macro Assembler, with driver (I used the Ultraterm driver for this program) and the Fast Bload patches, which I chose to load between DOS and its buffers, rather than actually patch the DOS. You can do it either way, it's up to you.

This program is called the "overhead" for the EPROM. It goes at $FEB0 in the actual chip. The catalog must appear at $FF00. These are the addresses as the Apple would see them, not the absolute addresses relative to the chip. A 27128 will address as though it runs from $C000 to $FFFF as far as the Apple is concerned. In other words, the chip's address $0000 equals the Apple's address $C000. Things are further complicated by the fact that an Apple II+ cannot address the range from $C000 to $C7FF without a small circuit modification. In this case it's no problem, the space from $C800-$FFFF is more than enough to house the entire assembler. If you needed more space, you could put your primary routine in the $C000-$C7FF space.

The rest of the EPROM contains the code for the assembler itself, and the fast Bload patch. The assembler goes from $C800-$EFFF, and the Bload patch from $F000 to $F04D. You must pack these files together in RAM somewhere prior to burning the chip. In other words, Bload the assembler at, say, $2800-4FFF. Put the Bload patch at $5000-504D Then Bload the overhead program at $5EB0. The rest of the EPROM doesn't matter. Then burn all this stuff into the EPROM starting at $800 relative to the chip. Thus, when you install the chip on the card, it will show up at $C800-FFFF like it should. If your EPROM burner won't burn partial chips, just start the burn from $2000 and it'll work out.

That's it. Just install the chip on the QuikLoader in any socket. To run the assembler just type the socket number followed by RESET. In two seconds the assembler will load and start! No more waiting to boot DOS, load the program, etc. You don't even have to look for a disk! Sure speeds up the work.

This should help augment the information in the manual a little, and get you on your way. I have installed the S-C assembler, Rak-ware's DISASM, a modified SOURCEROR (it now ouputs S-C format code, heh heh), the S-C Word Processor, a terminal program of my own design (it's capture buffer exactly coincides with the S-C Word Processor buffer! I can come off-line and begin editing with two keystrokes, and no disk access!), and some other utilities. All stored inside the Apple, available instantly at any time. For $170 (the price from S-C Software), the QuikLoader is a MUST.

By the way, for a reasonable fee I will install programs on EPROMS for you. You supply the programs and EPROMS, and I'll do the rest. Some programs are not suitable...particularly those which access the disk a lot. They would require extensive modification and that's best left to the original author. Also, copy-protected stuff cannot be loaded, because there's no way to ge at the files. Contact me if you're interested, at 11601 NW 18th St., Pembroke Pines, FL 33026.

[ For $20, S-C Software will send registered owners of version 2.0 a 27128 with the S-C Macro Assembler on it. This adds five lines to the QuikLoader menu, allowing you to choose the screen driver you wish. Only the $D000 (language card) version is provided. ]

Here's the overhead program, with GETSLOT overhead taken from the QuikLoader manual.

  1010 *--------------------------------
  1020 *1/31/85
  1030 *--------------------------------
  1040 *
  1060 *               by Jan Eugenides
  1070 * 3/9/85
  1080 *
  1090 *--------------------------------
  1110 *--------------------------------
  1120 *Y-register indexes of the chip 0 routines
  1130 *--------------------------------
  1140 *
  1150 MOVEBLK    .EQ 0       Move data block to RAM
  1160 GOMRBRD    .EQ 8       Go to motherboard
  1170 *--------------------------------
  1180 *
  1200 *
  1210 *--------------------------------
  1220 PRISLOT    .EQ $26  Storage for primary slot
  1230 QLMAP      .EQ $2D  bitmap of QL slots
  1240 SRCL       .EQ $3A  indirect source
  1250 SAVCTRL    .EQ $20A save control word
  1260 QLCTRL     .EQ $C081  QL control register
  1270 *--------------------------------
  1280 *
  1300 *
  1310 *--------------------------------
  1320 QLOFF      .EQ $18  00011000 QLOFF; CHIP 0
  1340 GSCL       .EQ $40  GET SLOT C PARAMETER.
  1350 GSCH       .EQ $41
  1360 GSEL       .EQ $42  GET SLOT E PARM 
  1370 GSEH       .EQ $43
  1380 SLTXROM    .EQ $C006     IIE SOFT SWITCH
  1390 INT3ROM    .EQ $C00A         "
  1400 SLT3ROM    .EQ $C00B         "
  1410 CLRROM     .EQ $CFFF
  1420 *--------------------------------
  1430        .OR $FEB0 
  1440        .TF ASM.2.0.OH
  1450 *--------------------------------
  1460 * This program will start the assembler in 80x32         
  1470 * mode with ultraterm.  Assumes that assembler has
  1480 * been patched at $DBC9 and $DC11 for 32 line mode,
  1490 * i.e. the normal $17 is now $1F.  If mode is changed
  1500 * these bytes must be re-patched. ($2F for 48 line mode)
  1510 * For S-C assember 2.0 March 1985 version with Bob's
  1520 * ultraterm driver attached at $F700.
  1530 *--------------------------------
  1540 START.PROG LDA #0    Turn on Ultraterm             
  1550            JSR $C300
  1560            LDA #22   bring up in 80x32 mode
  1570            JSR $FDED
  1580            LDA #"5   Mode 5
  1590            JSR $FDED
  1600            LDA #$CB
  1610            STA $3D1  set warmstart vector
  1620            LDA #0 
  1630            STA $9D00 make room between DOS a buffers 
  1640            JSR $A7D4 for fast BLOAD patch
  1650            LDA #$30
  1660            STA $ACA6 patch dos to call fast Bload
  1670            LDA #$9C
  1680            STA $ACA7 which is now at $9C30
  1690            LDA #$4C
  1700            STA $E000
  1710            LDA #0
  1720            STA $E001  put assembler coldstart vector at $E000
  1730            LDA #$D0
  1740            STA $E002
  1750            LDA $C080 select ram card
  1760            JMP $D000 coldstart assembler
  1770 SP.END
  1780 *--------------------------------
  1790        .BS $FF00-*   SKIP TO FF00
  1800 *--------------------------------
  1820 *--------------------------------
  1830 ASMK   .DA #$90     PRIMARY
  1840        .DA N.RESET SOURCE 
  1850        .DA $0000    LENGTH
  1860        .DA $0000    DESTINATION
  1870        .AS -"ASM"  
  1880 *--------------------------------
  1890        .DA #$86     END OF KAT RECORD
  1900 *--------------------------------
  1910 ASMPARM1   .DA $C800     SOURCE  assembler + driver goes here
  1920            .DA $27FF     LENGTH  will load from $D000-$F7FF
  1930            .DA $D000     DESTINATION
  1940 ASMPARM2   .DA $F000     SOURCE  fast bload routine
  1950            .DA $004D     LENGTH
  1960            .DA $9C30 
  1970 *--------------------------------
  1980 INVERT     LSR
  1990            ROR
  2000            ROR
  2010            ROR
  2020            AND #$E0
  2030            STA SAVCTRL
  2040            RTS
  2050 *--------------------------------
  2060        .BS $FF53-*   SKIP TO FF53
  2080        STA QLCTRL,X      TURN OFF THE QL
  2100        BNE OFFLP
  2110 *--------------------------------
  2120 *
  2160 *--------------------------------
  2180            STA SLT3ROM
  2190            LDA #0
  2200            STA GSCL
  2210            STA GSEL
  2220 TRYAGEN    LDA #$C1      START WITH SLOT 1
  2230            STA GSCH
  2240            LDA #$E1
  2250            STA GSEH      DESTINATION = $EN00
  2270 LOOKLP     LDA (GSCL),Y
  2280            CMP (GSEL),Y
  2300            DEY
  2310            BNE LOOKLP
  2320            LDA GSCH
  2330            TAY
  2340            ASL           GET SLOTNUM TIMES $10 TO X
  2350            ASL
  2360            ASL
  2370            ASL
  2380            TAX
  2390            LDA $FE86,Y  GET BIT MAP 
  2400            ORA QLMAP
  2410            STA QLMAP      SET BIT IN QLMAP
  2430 *--------------------------------
  2460 *--------------------------------
  2480        RTS
  2500            INC GSEH      CHECK IN NEXT SLOT
  2510            BNE LOOKLP    BRANCH ALWAYS
  2520 *--------------------------------
  2540 *--------------------------------
  2550 MAP    .DA #$80
  2560        .DA #$40
  2570        .DA #$20
  2580        .DA #$10
  2590        .DA #$08
  2600        .DA #$04
  2610        .DA #$02
  2620 *--------------------------------
  2640 *--------------------------------
  2650 N.RESET    JSR INVERT       Invert the control word
  2660            LDY #5
  2670 .1         LDA ASMPARM1,Y   Move ASSEMBLER parms
  2680            STA SRCL,Y
  2690            DEY
  2700            BPL .1
  2710            LDA SAVCTRL      get control word 
  2720            LDX PRISLOT      slot in X reg
  2730            LDY #MOVEBLK     Command index for move block routine
  2740            JSR GOCHIP0      Call chip 0 to move block
  2750            LDY #5
  2760 .2         LDA ASMPARM2,Y   Move Fast Bload routine parms
  2770            STA SRCL,Y
  2780            DEY
  2790            BPL .2
  2800            LDA SAVCTRL      get control word
  2810            LDX PRISLOT      Slot in X reg
  2820            LDY #MOVEBLK     Command index - move block
  2830            JSR GOCHIP0      Call chip 0
  2840            LDY #SP.END-START.PROG 
  2850 .3         LDA START.PROG,Y Move startup program to $300
  2860            STA $300,Y
  2870            DEY
  2880            BPL .3
  2890            LDA #$02        put address-1 on stack
  2900            PHA
  2910            LDA #$FF
  2920            PHA
  2930            LDY #GOMRBRD     jmp to $300 to start
  2940            LDA SAVCTRL
  2950            LDX PRISLOT
  2960            JMP GOCHIP0
  2970 *--------------------------------
  2980        .BS $FFEC-*    SKIP TO FFEC
  3010            .BS 3
  3020            RTS
  3030            .BS 2
  3040            .DA ASMK      FIRST KATALOG LOCATION
  3050            .DA $3FB      NMI VECTOR
  3060            .LIST OFF

New Book: Inside the Apple //c Bob Sander-Cederlof

What Gary Little did for the //e he has repeated for the //c. Of course a lot of the material is the same for both computers and both books, but there is much new material. If you have a //c and not a //e, then this book will be much more helpful.

For one thing, when explaining assembly language he includes the new opcodes and address modes of the 65C02. For another, the chapter on Disk Operating Systems is now 100% ProDOS, and includes more detail on ProDOS than the //e book. Naturally, since the //c has no cassette port or I/O slots, that material has been left out. On the other hand there is a lot of new data about the Apple mouse port and the built-in serial ports.

The book is published by Brady (Prentice-Hall), is 363 + xv pages, and sells for $19.95. (We'll send you one for a little less, see page 3 of this newsletter.)

Volume Catalog for Corvus and Sider Bob Sander-Cederlof

When I have a stack of floppies, I can quickly shuffle through them reading labels to find the two or three most likely to have the elusive file I want. On a hard disk it is hard to read the labels....

The last time I had a Corvus sitting in this room, there was a program on the utility disk which would list the first file name from each volume. If you were careful about making the first file name descriptive, it could act like a label. Of course, nearly every floppy around here has a first file named HELLO. Not too helpful.

Several years ago Bill Morgan wrote a program we published in AAL called the Catalog Arranger. It allows you to re-arrange the filenames in any catalog to any order you wish, and to rename the files using any combination of upper/lower case, inverse, flashing, and control-characters. I use Catalog Arranger to make a "title" file at the beginning of each hard disk volume. (If you never heard of Catalog Arranger, you can type it in from AALs of October 1982 and January 1983. It is also available on a Quarterly disk for only $15.)

Now that I don't have the Corvus, or its handy program for listing the names of the first file in each volume, I decided to write my own. The program that follows prints out the volume number, two spaces, and then the name of the first file. If the volume is empty, it prints "<<<EMPTY VOLUME>>>". You can abort the listing by pressing RETURN or ESCAPE, or pause it by pressing any other key.

Lines 1090-1100 set the origin at $803 and cause the object program to be written on a BRUNnable file called CAT. We write it at $803 rather than $800 so that Applesoft will work correctly after CAT is finished. Applesoft gets upset if $800 has any non-zero value in it.

I used two monitor routines. $FD8E prints a carriage return, and $FDED prints any character from the A-register.

I also used routines inside DOS. $AFF7 reads the VTOC of the current volume, using the inverse volume number from the variable R.VOLUME. If there is any error in trying to read the VTOC, DOS would normally go through its procedure of printing the message and returning to Applesoft. We cannot allow that, so I install a temporary patch to make the error condition cause a return to my code with carry set. If there is no error, carry will be clear. The only likely error is that I am asking for the VTOC of a non-existing volume, which means I have already processed them all. The patching, call, and de-patching take place in lines 1160-1220. Line 1230 branches to my exit routine if there was an error reported.

I also call on $B011 to read the first sector of the catalog. If you call $B011 with carry clear it reads the first sector of the catalog; with carry set, it reads the next sector of the catalog. The sector is read into a standard buffer at $B4BB-B5BA. See "Beneath Apple DOS" for a complete description of the catalog sectors.

Lines 1270-1440 convert the volume number to decimal and print it out. Lines 1450-1480 check for an empty directory. If it is empty, lines 1740-1800 print the empty volume message. Otherwise, lines 1490-1550 print the file name. Right here my program could use some improvement. It is possible for an empty volume to not look empty, because deleted files are not physically removed from the catalog. The byte we check for an empty volume could have $FF in it, signifying a deleted file. In this case my program should continue searching through the catalog for either the end or a non-deleted file. I didn't think it was absolutely necessary, since I was using Catalog Arranger to remove all deleted files from the catalog and position the title line at the very top.

Line 1730 returns back to DOS by JMP $3D0. This reminds me of glitch we all run into from time to time. If you intend to BRUN a program from the command level of the assembler or of Applesoft, it needs to end with JMP $3D0. Ending with an RTS will not do, because BRUN does not leave any return address on the stack. On the other hand, if you intend to start the program by using a CALL or MGO or $...G command, it is all right to end with an RTS. In fact, with a CALL from inside a running Applesoft program you MUST use an RTS. Just something to watch out for.

  1010 *--------------------------------
  1020 RWTS       .EQ $03D9
  1030 GETIOB     .EQ $03E3
  1040 *--------------------------------
  1060 *--------------------------------
  1070 R.VOLUME   .EQ $B5F9
  1080 *--------------------------------
  1090        .OR $803
  1100        .TF CAT
  1110 *--------------------------------
  1120 HARD.CAT
  1130        JSR $FD8E
  1140        LDA #$FE     FOR VOLUME=1 TO 254
  1150        STA R.VOLUME      (.EOR.FF OF VOLUME #)
  1160 *---PATCH DOS TO TRAP ERROR------
  1170 .1     LDA #$60     'RTS'
  1180        STA $B09E
  1190        JSR $AFF7    READ VTOC OF VOLUME
  1200 *---REMOVE PATCH-----------------
  1210        LDA #$B0     'BCS'
  1220        STA $B09E
  1230        BCS .7       OUT OF LOOP, BEYOD LAST VOLUME
  1240 *---READ 1ST CATALOG SECTOR------
  1250        CLC
  1260        JSR $B011
  1270 *---PRINT VOLUME #---------------
  1280        LDA R.VOLUME      INVERSE OF #
  1290        EOR #$FF          BACK TO NORMAL FORM
  1300        LDX #"0"          CONVERT TO DECIMAL
  1310 .2     CMP #10           ANY 10'S?
  1320        BCC .3            ...NONE LEFT
  1330        SBC #10           ...YES, DIMINISH
  1340        INX                   AND COUNT IT
  1350        BNE .2            ...ALWAYS
  1360 .3     PHA               SAVE UNITS
  1370        TXA               PRINT TENS
  1380        JSR $FDED
  1390        PLA               GET UNITS
  1400        ORA #"0"          AND PRINT IT
  1410        JSR $FDED
  1420        LDA #" "          PRINT "  "
  1430        JSR $FDED
  1440        JSR $FDED
  1450 *---PRINT NAME OF FIRST FILE-----
  1460        LDY #11
  1470        LDA $B4BB,Y
  1480        BEQ .8       ...EMPTY VOLUME
  1490        LDX #0
  1500 .4     LDA $B4BB+3,Y
  1510        INY
  1520        JSR $FDED
  1530        INX
  1540        CPX #30
  1550        BCC .4
  1560 *---PRINT CARRIAGE RETURN--------
  1570 .5     JSR $FD8E
  1580 *---NEXT VOLUME------------------
  1590        DEC R.VOLUME
  1600 *---POSSIBLE PAUSE OR ABORT------
  1610        LDA $C000    ANY KEY PAUSES
  1620        BPL .1       NO KEY
  1630        STA $C010
  1640        CMP #$8D     <RETURN> ABORTS
  1650        BEQ .7
  1660 .6     LDA $C000    PAUSE LOOP
  1670        BPL .6
  1680        STA $C010
  1690        CMP #$8D     AGAIN, RETURN AGORTS
  1700        BNE .1
  1710 *--------------------------------
  1720 .7     JSR $FD8E    <RETURN>
  1730        JMP $3D0     BACK TO DOS
  1740 *---EMPTY VOLUME-----------------
  1750 .8     LDX #0
  1760 .9     LDA MT,X     PRINT STRING BELOW
  1770        BEQ .5
  1780        JSR $FDED
  1790        INX
  1800        BNE .9       ...ALWAYS
  1810 *--------------------------------
  1820 MT     .AS -/<<<EMPTY VOLUME>>>/
  1830        .HS 00
  1840 *--------------------------------

Shrinking Code Inside ProDOS Bob Sander-Cederlof

David Johnson challenged me a few days ago. We were talking about ProDOS: the need for a ProDOS version of the S-C Macro Assembler, the merits vs. enhanced DOS 3.3, and the rash of recent articles on shrinking various routines inside DOS to make room for more features.

I've been avoiding ProDOS as much as possible, trying not to notice its ever-increasing market-share. Dave's comment, "ProDOS is a fertile field for your shrinking talent," may have finally pushed me into action.

I am trying to make the ProDOS version of the S-C Macro Assembler, but is hard. I have Apple's manuals, Beneath Apple ProDOS, and the supplement to the latter book which explains almost every line of ProDOS code. Nevertheless, version 1.1.1 of ProDOS doesn't seem to conform to all these descriptions in every particular. I spent four hours last night chasing one little discrepancy. (Turned out to be my own bug, though.)

In the process, I ran across the subroutine ProDOS uses to convert binary numbers to decimal for printing. In version 1.1.1 it starts at $A62F, and with comments looks like this.

  1010 *--------------------------------
  1020        .OR $A62F
  1030        .TA $800
  1040 *--------------------------------
  1060 *   STORE UNITS DIGIT AT $201,Y
  1080 *
  1090 *      Note:  it is assumed and required that
  1100 *             ACCUM+2 already by zeroed!
  1110 *             Either that, or already set to the
  1120 *             highest byte of a 24-bit value.
  1130 *--------------------------------
  1150        STX ACCUM+1
  1160        STA ACCUM
  1180        LDA REMAINDER
  1190        ORA #"0"
  1200        STA BUFFER+1,Y
  1210        DEY
  1230        ORA ACCUM+1
  1240        ORA ACCUM+2
  1250        BNE .1
  1260        RTS
  1270 *--------------------------------
  1290        LDX #24      24 BITS IN DIVIDEND
  1300        LDA #0       START WITH REM=0
  1310        STA REMAINDER
  1320 .1     JSR SHIFT.ACCUM.LEFT
  1330        ROL REMAINDER
  1340        SEC          REDUCE REMAINDER MOD 10
  1350        LDA REMAINDER
  1360        SBC #10
  1370        BCC .2       STILL < 10
  1380        STA REMAINDER
  1390        INC ACCUM    QUOTIENT BIT
  1400 .2     DEX          NEXT BIT
  1410        BNE .1
  1420        RTS
  1430 *--------------------------------
  1440 ACCUM      .EQ $BCAF,BCB0,BCB1
  1460 BUFFER     .EQ $0200
  1470 *--------------------------------
  1480        .OR $AAD7
  1490        .TA $900
  1500 *--------------------------------
  1520        ASL ACCUM
  1530        ROL ACCUM+1
  1540        ROL ACCUM+2
  1550        RTS
  1560 *--------------------------------
  1570        .LIF

The conversion routine is designed to handle values between 0 and $FFFFFF. The heghest byte must already have been stored at ACCUM+2 before calling CONVERT.TO.DECIMAL. The middle byte must be in the X-register, and the low byte in the A-register. The decimal digits will be stored in ASCII in the $200 buffer, starting and $201+Y and working backwards.

One way of converting from binary to decimal is to perform a series of divide-by-ten operations. After each division, the remainder will be the next digit of the decimal value, working from right to left. That is the technique ProDOS uses, and the division is done by the subroutine in lines 1280-1420.

The dividend is in ACCUM, a 3-byte variable. The low byte is first, then the middle, and finally the high byte. One more byte is set aside for the remainder. A 24-step loop is set up to process all 24 bits of ACCUM. In the loop ACCUM and REMAINDER are shifted left. If REMAINDER is 10 or more, it is reduced by ten and the next quotient bit set to 1; otherwise the next quotient bit is 0.

The first possible improvement I noted was in the area of lines 1330-1360. the ROL REMAINDER will always leave carry status clear, because we never let REMAINDER get larger than 9. If we delete the SEC instruction, and change SBC #10 to SBC #9 (because carry clear means we need to borrow), we can save one byte. But that's not really worth the effort.

Next I realized that REMAINDER could be carried in the A-register within the 24-step loop, and not stored until the end of the loop. Here is that version, which saves seven bytes (original = 31 bytes, this one = 24 bytes):

  1270        LDX #24      24 BITS IN DIVIDEND
  1280        LDA #0       START WITH REM=0
  1290 .1     JSR SHIFT.ACCUM.LEFT
  1300        ROL
  1310        CMP #10
  1320        BCC .2       STILL < 10
  1330        SBC #10
  1340        INC ACCUM    QUOTIENT BIT
  1350 .2     DEX          NEXT BIT
  1360        BNE .1
  1370        STA REMAINDER
  1380        RTS

To make sure my version really worked, I re-assembled the conversion program with an origin of $800, and appended a little test program. Here is my test program, which converts the value at $0000...0002 and prints it out.

  1510 T      LDA 0
  1520        STA ACCUM+2
  1530        LDX 1
  1540        LDA 2
  1550        LDY #10
  1570 .1     INY
  1580        LDA BUFFER+1,Y
  1590        JSR $FDED
  1600        CPY #10
  1610        BCC .1
  1620        RTS

My best version is yet to come. I considered the fact that we could SHIFT the next quotient bit into the low end of ACCUM rather than using INC ACCUM to set a one-bit. I rearranged the loop so that the remainder reduction was done first, followed by the shift-left operation. I had to change the remainder reduction to work modulo 5 rather than 10, because the shifting operation came afterwards. I also had to inlcude my own three lines of code to ROL ACCUM, since the little subroutine in ProDOS started with ASL ACCUM. The result is still shorter than 31 bytes, but only four bytes shorter. Nevertheless, it is faster and neater, in my opinion.

  1650        LDX #24      24 BITS IN DIVIDEND
  1660        LDA #0       START WITH REM=0
  1670 .1     CMP #5 
  1680        BCC .2       STILL < 10
  1690        SBC #5 
  1700 .2     ROL ACCUM
  1710        ROL ACCUM+1
  1720        ROL ACCUM+2
  1730        ROL
  1740        DEX          NEXT BIT
  1750        BNE .1
  1760        STA REMAINDER
  1770        RTS

Fast Text Windows for Applesoft Michael Ching
2118 Kula Street, Honolulu, HI 96817

The program WINDER by Mike Seeds in the January 1985 NIBBLE was found to be very interesting. This was especially so because we, coincidentally, had been working on a similar routine for use in an upcoming strategy sports game.

The main difference between our programs was that the routines used in WINDER are written completely in Applesoft, and thus suffer from the relatively slow speed of the Applesoft interpreter. This is especially evident in the opening of the windows. Our routine, on the other hand, is written in assembly language and executes more quickly.

There are a couple of other major differences. Seeds' routine saves the text, to be overwritten by the window, in a string array WS$. Our routine saves the text in the secondary text page (memory locations $800 through $BFF). One advantage of doing this is that more than one window can be opened at the same time, (although the windows may not overlap). A disadvantage is that the secondary text page occupies the same space that an Applesoft program normally would start at. This makes it necessary to relocate the Applesoft program above the secondary text page.

Another difference is that WINDER specifies the window dimensions with the width and height of the window, along with the top and left coordinates. We chose to specify directly the top, bottom, left, and right boundaries.

The assembly language routine is called by the familiar & followed by the appropriate parameters. The format is & WT,WB,WL,WR,TP where WT is the top coordinate of the window, WB is the bottom coordinate, WL is the left coordinate, WR is the right coordinate, and TP is the text page number. If TP is set to 1, the text to be replaced by the window is saved to the secondary text page and the window is formed. If TP is set to 2, the text is restored to the primary text page from the secondary text page. At present, there is no error checking of the parameter values, and care must be taken to ensure that WB is set greater than WT, and WR greater than WL.

The program is assembled to load into the tail end of the input buffer and the free space in page 3 ($2F5-3C9). The portion inside page 2 is only used to set up the ampersand hook, so it is not a problem if this code gets wiped out by long input lines after loading. This setup is done in lines 1250-1290.

Lines 1320-1470 perform the task of getting the parameter values from Applesoft and placing them into temporary storage. The routines GETBYT and COMBYTE are used, and will evaluate expressions used in the calling Applesoft program. The width of the window is also calculated here. The text page value is decremented by one for ease of future manipulation. Line 1340 initializes the beginning of a loop which will copy the characters in the designated text page to the opposite text page.

Lines 1500-1510 call the monitor routine BASCALC. BASCALC calculates the starting (leftmost) memory address of the screenline, and stores it in the pointers BASL and BASH.

Lines 1520-1640 set up two pointers, one in the real screen and one in the alternate screen area. The pointers point to the beginning of the current line starting at the left edge of the caller's window. A1 points at the source, and A2 at the destination, for a move loop which will copy the characters within the window on the current line.

The destination address is the source address offset by $400 (up or down depending on the source text page). The calculation is done by exclusive ORing the source address with #$0C (or 00001100 in binary). For example, if BASH was $07, exclusive ORing will yield $0B. If it was $0B, exclusive ORing will yield $07.

Lines 1660-1700 comprise the move loop.

Lines 1720-1850 check to see if the frame of the window needs to be drawn. If the text page is being restored (window being closed), then the frame routine is skipped. If the window is being cleared, the frame is drawn.

First I store an inverse blank at each end of the line, which is sufficient for all except the top and bottom lines. Then I check: if it is the top or bottom line, I fill in the rest of the line with inverse blanks.

Lines 1870-1900 check whether the entire window has been processed. If not, the program loops back to process the next line.

Lines 1920-2050 check to see whether the window boundaries need to be set. If the window is being opened (TPAGE = 0), then they are set, and HOME clears out the window. Note that the window parameters are set so that the frame is outside it.

  1010 *--------------------------------
  1020 * MOVE WINDOW
  1030 * by Mike Ching, Kula Software
  1040 *    2118 Kula Street, Honolulu, HI 96817
  1050 *--------------------------------
  1060 WNDLFT   .EQ $20
  1070 WNDWDTH  .EQ $21
  1080 WNDTOP   .EQ $22
  1090 WNDBTM   .EQ $23
  1100 BASL     .EQ $28
  1110 BASH     .EQ $29
  1120 A1       .EQ $18,19     MEMORY SOURCE START
  1130 A2       .EQ $1A,1B     MEMORY SOURCE END
  1140 *--------------------------------
  1150 AMPERV   .EQ $3F5
  1160 *--------------------------------
  1170 GETBYT   .EQ $E6F8
  1180 COMBYTE  .EQ $E74C
  1190 BASCALC  .EQ $FBC1
  1200 HOME     .EQ $FC58
  1210 *--------------------------------
  1220          .OR $2F5
  1230          .TF B.WINDOWS
  1240 *--------------------------------
  1260        STA AMPERV+1
  1270        LDA /MOVE.WINDOW
  1280        STA AMPERV+2
  1290        RTS
  1300 *--------------------------------
  1330        STX TOP
  1340        STX LINE
  1350        JSR COMBYTE
  1360        STX BOTTOM
  1370        JSR COMBYTE
  1380        STX LEFT
  1390        JSR COMBYTE
  1400        STX RIGHT
  1410        SEC          WIDTH = RIGHT-LEFT
  1420        TXA
  1430        SBC LEFT
  1440        STA WIDTH
  1450        JSR COMBYTE  GET DIRECTION (1 OR 2)
  1460        DEX
  1470        STX TPAGE
  1480 *--------------------------------
  1490 MOVE.LINE
  1500        LDA LINE     BASL,H = BASCALC(LINE)
  1510        JSR BASCALC
  1520        CLC
  1530        LDA BASH
  1540        LDX TPAGE
  1550        BEQ .1       ...SOURCE IS REAL SCREEN
  1560        EOR #$0C     ...SOURCE IS SAVED SCREEN
  1570 .1     STA A1+1     SOURCE HI BYTE
  1580        EOR #$0C     FLIP TEXT PAGE
  1590        STA A2+1     DESTINATION HI BYTE
  1600        CLC          MEMSTART = BASL,H + LEFT
  1610        LDA BASL
  1620        ADC LEFT
  1630        STA A1       SOURCE LO BYTE
  1640        STA A2       DESTINATION LO BYTE
  1650 *---MOVE THE LINE SEGMENT--------
  1660        LDY WIDTH
  1670 .2     LDA (A1),Y
  1680        STA (A2),Y
  1690        DEY
  1700        BPL .2
  1710 *---IF CLEARING, DRAW FRAME------
  1720        LDY TPAGE
  1730        BNE .4       ...NOT CLEAR, DO NOT DRAW FRAME
  1740        LDA #$20     INVERSE BLANK
  1750        STA (A1),Y   LEFT SIDE
  1760        LDY WIDTH
  1770        STA (A1),Y   RIGHT SIDE
  1780        LDX LINE
  1790        CPX TOP
  1800        BEQ .3       ...TOP LINE
  1810        CPX BOTTOM
  1820        BNE .4       ...NEITHER TOP NOR BOTTOM
  1830 .3     STA (A1),Y
  1840        DEY
  1850        BNE .3
  1860 *---NEXT LINE--------------------
  1870 .4     INC LINE     UNTIL LINE > BOTTOM
  1880        LDA BOTTOM
  1890        CMP LINE
  1910 *---IF CLEARING, SET WINDOW------
  1920        LDA TPAGE
  1930        BNE .5
  1940        LDX LEFT
  1950        INX
  1960        STX WNDLFT
  1970        LDX WIDTH
  1980        DEX
  1990        STX WNDWDTH
  2000        LDX TOP
  2010        INX
  2020        STX WNDTOP
  2030        LDX BOTTOM
  2040        STX WNDBTM
  2050        JSR HOME
  2060 .5     RTS
  2070 *--------------------------------
  2080 TOP    .BS 1        PROGRAM STORAGE
  2090 BOTTOM .BS 1
  2100 LEFT   .BS 1
  2110 RIGHT  .BS 1
  2120 WIDTH  .BS 1
  2130 LINE   .BS 1
  2140 TPAGE  .BS 1
  2150 *--------------------------------

The next listing shows the revised WINDER routine using the assembly language routines. Line 40 checks to see if the program has been relocated above the secondary text page. If not, the start of program pointers are changed and the program is re-RUN. This causes DOS to position the program above the secondary text page. Line 50 BRUNS the assembly language routine.

The program is really quite different from that of Mike Seeds, as you can see if you compare them. Clearing and restoring windows is now very efficient, due to the &-routine. I moved the delay and closing logic into a common subroutine. I also added a randomly sized and positioned window in lines 400-410.

     30  REM  -----------------------
     40 P = 12: IF  PEEK (104) < P THEN  POKE 104,P: POKE P * 256,0: PRINT 
          CHR$ (4)"RUN WINDOW DEMO"
     50  PRINT  CHR$ (4)"BRUN B.WINDOWS"
     60  REM  -----------------------
     100  TEXT : HOME 
     110  FOR I = 1024 TO 2047 STEP 128: FOR J = 0 TO 119: POKE I + J,
           RND (1) * 26 + 193: NEXT J,I
     120  PRINT "         WINDOW DEMONSTRATION";: CALL  - 868: PRINT :
           CALL  - 868
     130  VTAB 22: CALL  - 958: PRINT : PRINT "     PRESS ANY KEY TO H
     140  REM   -------------------------
     150 T = 10:B = 14:L = 12:R = 21: & T,B,L,R,1: REM  OPEN WINDOW
     170  REM ----------------------
     200 T = 2:B = 7:L = 6:R = 31: & T,B,L,R,1
     220  GOSUB 1000
     230  REM ---------------------
     260 T = 10:B = 19: & T,B,L,R,1
     270  FOR J = 1 TO 25: PRINT "  ";J,J * J: NEXT J
     290  GOSUB 1000
     330  REM --------------------------
     400 W =  RND (1) * 20 + 5:H =  RND (1) * 10 + 5:T =  RND (1) * (2
          4 - H):B = T + H:L =  RND (1) * (40 - W):R = L + W
     420  GOTO 150
     1000  FOR D = 1 TO 1500: NEXT 
     1010  & T,B,L,R,2: REM CLOSE WINDOW
     1020  IF  PEEK ( - 16384) < 128 THEN  RETURN 
     1030  POP : POKE  - 16368,0: TEXT : HOME : END 

An 8086/8088 Cross Assembler Don Rindsberg

As one of S-C's avid fans, I have developed an 8086/8088 Cross Assembler for your Apple which will enable you to generate code to run on the IBM PC's and their clones as well as many other 16-bit machines. All the 8086/8088 instructions are covered as well as the multiplicity of addressing modes. The mnemonics are based on Microsoft's assembler. This assembler is based on S-C Assembler II Version 4.0 (the one before Macro Assembler), so it doesn't include the newer features like macros or the EDIT command. Documentation covering the differences from the 6502 version is included.

With Bob's permission, XSM 8086/8088 is available to owners of the S-C 6502 assembler (Version 4.0 or later) for $80.00 post- paid. Included on the disk are sample source programs so you can become familiar with the syntax. Send personal check or money order (no credit cards or purchase orders) to:

The Bit Stop
5958 S. Shenandoah Rd.
Mobile, AL 36608
Attn: Don Rindsberg
(205) 342-1653

A Powerful 65816 Board on the Horizon Bob Sander-Cederlof

Some of you may have heard of Micro Magic, a company in Mary- land that is planning to produce a plug-in card for your Apple with fast RAM and a fast 65816. Well, if not, now you have.

I spoke yesterday with Will Troxell, and got an overview of their plans. He and Frank Krol are working together on the project. Their goal is to produce the most powerful and flexible card they can and yet still bring it in for a low price. The card will basically be similar to the Accelerator //e, in that it consists of a fast microprocessor, fast RAM, and the logic to take control away from the 6502 or 65C02 on your Apple motherboard.

But instead of a 65C02 running at 3.58 MHz, you will get a 65816 running at 6 MHz. Instead of one row of RAM chips, you get two. Troxell's board will probably come with 64K or 128K of 6MHz dynamic RAM, but later this year they have been promised that 256K RAMs fast enough for 6 MHz operation will be in production; then you will be able to expand your board to 256K or 512K bytes of RAM.

There is a firmware socket on the board which can accept a 27128 (16K bytes of firmware, the same as you find in a //c). They do not plan to include any firmware at the beginning, but it certainly can be filled up with your own goodies.

There are two external connectors on the board. One of these allows you to add another 512K RAM. Remember, this is directly addressable RAM, not bank-switched. The 65816 can directly address up to 16 megabytes, with its 24-bit address bus.

It is also exciting to remember that a plain ol 6502 running at 1 MHz (what you have now) is roughly equivalent in speed to most of the 8088 and Z-80 computers on the market. A 6 MHz 6502 could beat a 20MHz Z-80 (were they to make one so fast). A 6 MHz 65816 will beat out 68000's, 80286's, and so on. Why is this true? Because all those other chips use micro- programmed instruction sets, taking many clock cycles for each instruction. The 6502 and its progeny are fully implemented in hardware gates, so only a handful of clock cycles are needed.

Furthermore, a 65816 instruction will take from one to four bytes of memory, while a 68000 instruction will take 2, 4, 6, 8, or 10 bytes. Now I am not trying to deny the power of some of those 68000 instructions. One of them may take many steps in 65816 code. Especially if you need to deal with 32-bit operands. But it is my experience that those super instructions are relatively infrequent in practical programs. Most programs spend most of their time just moving bytes from here to there and back again.

Now if we could only get one! For about fifteen months we have been hearing "in two to four weeks". We could despair, were it not for our historical perspective. The same thing happened with the 65C02, and now we really do have them in abundance. By this time next year, you may be hearing solid confirmation of the rumor (heard this week) that Apple and GTE are discussing large orders of 65816s.

But I digress. Back to Troxell and Krol. There new board will be called the MAX-816, and a new operating system they are designing for it will be MAX-OS. A special circuit on the card will optimize memory re-mapping for both DOS and ProDOS, automatically, so that maximum possible use is made of the fast RAM on the card. THe fewer times the card has to slow down to use motherboard RAM, the faster your programs fly.

MAX-OS will not be necessary for you to get a bang out of MAX-816, because it will work like the Accelerator //e and make most existing programs six times faster (exclusive of I/O). But when it is ready, it will open up new vistas, with RAM stretching out in every direction as far as the eye can see. In a design reminiscent of one from a certain large phone company, the kernel is written in assembly language, with a C-shell wrapped around it.

Personally, I am no great fan of complex operating systems. The simpler and smaller the better, in my book. I still like DOS 3.3, especially with enhancements I regularly patch in. Nevertheless it does take more management when you have the magnitude and variety of resources that will be in the Apple of the future. Maybe MAX-OS will be the winner.

If Will and Frank are whetting your appetite, you can write to them at Micro Magic, Box 281, Millersville, MD 21108. Or you might be able to reach them at (301) 987-6083.

USR Command to List Major Labels Only Bob Sander-Cederlof

Sometimes when I am working with a large source file in the S-C Macro Assembler it would be nice to be able to list only those lines that define major labels. Seeing only them would give an overview of an entire file, and enable me to quickly find the section I want to work on.

A major label is one that starts with a letter. Local labels start with a period, macro private labels start with a colon. Lines might also start with an asterisk or semicolon, if they are comments, or with blank.

You can add commands to the Macro Assembler in several ways. One easy built in one is the USR command. A vector at $D007 (or $1007 with the low memory version) can point to the code to process a command of your own making. Lines 1080-1140 in the following listing set up the vector for my special USR command. Since it is in the high RAM area (sometimes called "language card"), I reference $C083 twice to write enable the RAM.

Once the USR vector is loaded, typing a command "USR" will execute my code. When this happens, the entire command I typed will be in a buffer starting at $200. Some routines exist inside S-C Macro which can help in parsing the command further and in implementing its functions, and I will use them in this example. If you have the source code to one of the S-C Macro versions, it is not too difficult to find these routines. And if you don't have it, you can always disassemble and analyze, a true form of adventure. The addresses shown in lines 1040-1060 correspond to version 2.0 of the S-C Macro Assembler.

Line 1165 calls on a subroutine I call PARSE.LINE.RANGE (PLR). PLR starts by setting up SRCP to point to the beginning of the source program, and ENDP to the end of same. Then it looks at the command line for various forms of line numbers. You might have none at all, in which case PLR is finished. You might have one number alone, or a period. (A period is shorthand for the last remembered line number.) That might be preceded by or followed by a comma. You might have two numbers separated by a comma. Here is a table showing what happens in each case:

               SRCP    ENDP    CARRY
               ----    ----    -----
       none    pstart  pend    set
       #       #start  #end    clear
       #,      #start  pend    clear
       ,#      pstart  #end    clear
       #1,#2   #1start #2end   clear

       where # means number or "."
             pstart = address of start of source code
             pend = address of end of source code
             #start = address of starting line #
             #end = address of ending line #

Line 1170 call a routine in the assembler to compare SRCP and ENDP to see if we are finished or not. The code is simply:

               LDA SRCP
               CMP ENDP
               LDA SRCP+1
               SBC ENDP+1

Lines 1200-1210 pick up the first character after the line number. The source line format in memory is one byte for a byte count, two bytes for the line number, the text of the line, and a final terminating 00 byte. The blank which follows just after the line number in listings is not actually stored.

Characters in a source line are stored in "low" ASCII, values between $01 and $7F. Values from $81 through $BF indicate 1 to 63 blanks. The value $C0 indicates repetitions of some other character. The byte following a $C0 is the repetition count, and the byte after that is the character to be repeated. Lines 1220-1240 check for blanks and repeat tokens. Lines 1340-1350 pick up the repeated character if we found a repeat token.

Lines 1360-1390 check if the first character is a letter. If not, this line will not be listed. Lines 1250-1320 are executed to skip over the current line without listing it. Since the first byte of the line has a byte count, it is added to SRCP to move up the next line.

At line 1400 I call LIST.CURRENT.LINE to ... you guessed it. This subroutine also advances SRCP, so after it is finished I jump back to the top to check pointers and get the next line.

After assembling the program, I type MGO INIT to hook it in. Then "USR 1070," would list just lines 1080 and 1160.

  1010 *--------------------------------
  1020 SRCP   .EQ $DD,DE
  1030 *--------------------------------
  1050 CMP.SRCP.ENDP       .EQ $DF11 OR 1F11
  1060 LIST.CURRENT.LINE   .EQ $D737 OR 1737
  1070 *---LINK COMMAND-----------------
  1090        LDA $C083
  1100        LDA #USR.LIST    SET UP USR VECTOR
  1110        STA $D007
  1120        LDA /USR.LIST
  1130        STA $D008
  1140        RTS
  1150 *---USR COMES HERE---------------
  1160 USR.LIST
  1165        JSR PARSE.LINE.RANGE
  1170 .1     JSR CMP.SRCP.ENDP
  1180        BCC .2
  1190        RTS
  1200 .2     LDY #3       POINT TO FIRST CHAR
  1210        LDA (SRCP),Y
  1220        BPL .5       NOT TOKEN
  1230        CMP #$C0
  1240        BCS .4       REPEAT TOKEN
  1250 .3     LDY #0       SKIP TO NEXT LINE
  1260        LDA (SRCP),Y LINE LENGTH
  1270        CLC
  1280        ADC SRCP
  1290        STA SRCP
  1300        BCC .1
  1310        INC SRCP+1
  1320        BNE .1       ...ALWAYS
  1330 *--------------------------------
  1340 .4     LDY #5       POINT AT RPTD CHAR
  1350        LDA (SRCP),Y
  1360 .5     CMP #'A'
  1370        BCC .3       NOT LETTER
  1380        CMP #'Z'+1
  1390        BCS .3       NOT LETTER
  1410        JMP .1
  1420 *--------------------------------

Review of the FCP Hard Disk Bob Sander-Cederlof

First Class Peripherals has been advertising for some months now their 10 megabyte hard disk system (The Sider) for the Apple. At only $695, including drive, controller, cable, and software, it sounds too good to be true. We called them and asked for a chance to write a review, and they loaned us one for a month.

I first tried hooking it up to an Apple II Plus, the same one we have used with hard disks in the past. However, after 5 or 6 wasted hours, it still would not function. We could not even get the disk to completely initialize. I finally called the 800 number for customer service, and found out that there have been problems hooking the Sider to some II+'s. They suggested trying it on a //e before giving up. Sure enough, it worked perfectly on our //e. The Sider is sold subject to a 15-day trial period, so there is plenty of time to find out if it will work with your II+.

I am very pleased. The Sider works well, looks good, and is not too noisy. We have heard of at least one customer who did complain of the noise level, but I have never listened to a quieter one. Because of the venting design there is no internal fan, so the only noise is the spinning disk. Anyway, my office already has two fans going on Apples and another in a Minolta copier. The Sider nicely masks them all.

The size and shape are nice, too. It is somewhat smaller than I expected: less than 4x8x16 inches. At first I set it along side of my Apple (after all it is called the Sider), but now it is along the back edge of my work table. This way it takes practically no space at all, yet I can still easily reach the on/off switch.

The installation software that comes with the Sider initializes the 10 megabytes into four separate partitions. One is for DOS, one for ProDOS, one for CP/M, and one for Pascal. You can vary the partition size for each one, although a certain minimum amount must be allocated; you cannot squeeze one all the way out. The DOS partition allows a combination of floppy size volumes and large volumes. The large volumes give you three times the amount of a regular Apple floppy. I set mine up with 32 small volumes and one large volume.

The ProDOS partition divides the allocated space into two equal size volumes, designated /HARD1/ and /HARD2/. Since I shrank CP/M and Pascal to the minimum, the ProDOS volumes are about 2.5 megabytes each.

If you want to change the partitions, you have to completely re-initialize. That means all your files will disappear. Of course you can restore them from your backup floppy copies.

The only modification to DOS 3.3 that the Sider makes is to put a call to their firmware at $BD00. I decided to apply my own set of patches, which among other things speed up LOAD, BLOAD, RUN, and BRUN. They were not only compatible, they even speeded up the hard disk! Here is a table comparing the Sider with floppies, both with and without my patches:

BLOAD             ----floppies-----  ----The Sider----
       # sectors  standard  patched  standard  patched
          22         7.7      3.8       3.0      1.3
          69        18.7      5.6       6.7      2.4
         131        32.6      8.6      12.3      3.8

I also timed the assembly of a large program, whose source was on two disks (the S-C Macro Assembler itself, in fact). With my speed up patches the floppy assembly took 4 minutes 50 seconds; the Sider with standard DOS took 3 minutes 50 seconds; the Sider with my patches took only 2 minutes 32 seconds.

All these times are under DOS 3.3 of course. ProDOS is about the same as my patched version of DOS in speed, but has other advantages like larger volumes and files.

The main competition for the Sider comes from the two most popular companies, Apple and Corvus. Apple's ProFILE hard disk is sleek and nice, and only costs three times what the Sider does. Since you are paying more, you also get less: Apple only supports ProDOS. The ProFILE doesn't work with CP/M, Pascal, or DOS 3.3. (Unless there is a new ProDOS compatible Pascal.) Corvus costs even more than ProFILE, last time I checked. On the other hand, they have an excellent reputation.

Its always hard to trust some new little company, even when they have a great product and price. Just who is First Class Peripherals, anyway? Well, they are a subsidiary of Xebec, one of the bigger makers of hard disks. Xebec has been around a long time (over ten years) and has a first class reputation. I think we can depend on them. The Sider comes with a one-year limited warranty, which I think means that if it breaks you send it in and they will fix it or replace it. (Note: a whole year, not just 90 days!) After the warranty has expired there is a flat $150 charge for repairs.

The only way to buy a Sider is directly from First Class Peri- pherals. You can call them at 1-800-538-1307, or write to 2158 Avenue C, Bethlehem, PA 18001. If you are in a user group of significant size, I understand someone at FCP might want to visit with a demo unit. You might give them a call.

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