Apple Assembly Line
Volume 6 -- Issue 12 September 1986

In This Issue...

What About the New Apple //?

The cloud of rumors surrounding a new, improved, much more powerful Apple // machine is beginning to condense, but there is still no solid public information and no data coming out of Apple. The latest hints indicate that there will be a major announcement sometime this month, so we might all know the answers by the time you read these words.

There is one thing you can be certain of: As soon as we can come out with reliable and accurate details, Apple Assembly Line will be the place to read about how to explore and program this new successor to the computer that all of us have devoted so much to and gotten so much from.

Many of the people we talk to are anticipating an explosion of excitement much like the "good old days" of the original Apple II. They expect the unveiling of such accessable power to rekindle the spirit that drew many of us into computing in the first place: a new world to explore. We hope that's true, and we're going to do our part to help it happen.

A Short Symbol Table Listing for the
ProDOS S-C Macro Assembler
Harvey R. Brown

The symbol table printed by the S-C Macro Assembler for a long program can be 20 or 30 pages long. Since the assembler allows for labels up to 32 characters long, and values up to 8 hexadecimal digits long, it only prints one label and value per line. Local labels are printed seven to a line, but I am not usually interested in their values anyway. Many times I would like a nice compact listing of only the named labels.

I personally try to stick to relatively short label names, so there would normally be room for four columns of labels in a compact listing. If we say the line length is up to 79 characters (calling it 80 might produce double spacing), that leaves 18 characters per column. I hardly ever have any values which require more than four digits to print in hexadecimal. Allowing for at least one blank between columns, and for a dash between label name and value, that means I have room for names of up to 12 characters long.

I wrote a USR command for the ProDOS version of the S-C Macro Assembler. After it is installed, typing USR causes the named labels to be listed in four columns in alphabetical order. Typing USR2 causes them to be listed in the order of their definition, which for the sake of this discussion I am calling "numerical" order.

I analyzed several symbol tables in memory after different assemblies, and figured out most of the data. The symbol table begins at $1000, with the symbols in the order of their definition in the source code. Each entry has a 2-byte pointer to the next entry beginning with the same letter in alphabetical order. Next is a 4-byte value, with the low byte first. Next is a key byte, which contains a flag bit for whether or not there are local labels under this label, and the length of the label name. Following the key byte there are from 1 to 32 ASCII characters for the label name. If there are any local labels, there are up to 100 pairs of bytes following the label name, terminated by a single $00 byte. The first byte of each pair is the label number in binary + $80. Since local labels are numbered from .0 to .99, the first byte of each pair can have $80 through $E3 in it. The second byte of each pair can have any value from $00 through $FF in it, and is the offset from the named label value.

The pointers at the beginning of each entry are chained alphabetically. There is a separate chain for each starting letter, A through Z. A table beginning at $0132 holds the address of the first symbol for each letter of the alphabet. This makes it easy for my program to list the symbols in alphabetical order, without doing any sorting.

There are two main routines, SYM1 and SYM2, to handle the alphabetic and numeric order. DO.ITEM outputs the name and address for a symbol. NEXT.ITEM.A moves a pointer to the next entry in alphabetical order, while NEXT.ITEM.N does the same in "numerical" order.

I chose $7400 as the origin. The area from $7400 through $77FF is only used by the EXEC command in the ProDOS S-C Macro Assembler. When you assemble the program, the object code will be automatically written on the binary file B.SHORTSYM (because of the .TF directive in line 1030). Thereafter, you can install the USR and USR2 commands by typing "-B.SHORTSYM". It will remain installed until you use the EXEC command or leave the assembler system.

[ It turns out to be quite easy to adapt Harvey's fine program for the DOS version of the assembler. You just need to make the following changes or additions:

     1020            .OR $800    or whatever
     1200 LOMEM      .EQ $4A,4B
     1220 USR.VECTOR .EQ $D006

     1381            LDA $C083
     1382            LDA $C083
     1421            LDA $C080

And that's all there is to it! Thanks, Harvey. Bill M. ]

  1010 *--------------------------------
  1020            .OR $7400
  1030            .TF B.SHORTSYM
  1040 *--------------------------------
  1050 * SHORTSYM by Harvey R. Brown
  1060 *      August 3, 1986
  1070 *--------------------------------
  1080 NO.COLUMNS   .EQ 4
  1090 LINE.LENGTH  .EQ 79
  1100 *--------------------------------
  1110 PTR        .EQ 0,1
  1120 ALPH.INDEX .EQ 2
  1130 NONZERO    .EQ 3
  1140 HORIZ      .EQ 4
  1150 KEY        .EQ 5
  1160 LENGTH     .EQ 6
  1170 YSAVE      .EQ 7
  1180 *--------------------------------
  1190 END.TABLE  .EQ $CC,CD
  1230 *--------------------------------
  1240 IN         .EQ $200
  1260 *--------------------------------
  1270 KEYBD  .EQ $C000
  1280 STROBE .EQ $C010
  1290 *--------------------------------
  1300 PRNTAX .EQ $F941
  1310 PRBL2  .EQ $F94A
  1320 RDKEY  .EQ $FD0C
  1330 CROUT  .EQ $FD8E
  1350 COUT   .EQ $FDED
  1360 *--------------------------------
  1370 *-- BRUN OR "-" COMES HERE ------
  1400        STA USR.VECTOR+1
  1410        LDA /USR.PROCESSOR   
  1420        STA USR.VECTOR+2
  1430        RTS
  1440 *--------------------------------
  1450 **-- "USR or USR2 comes here ----
  1470        LDY #0 
  1480        STY HORIZ       0 HORIZ POSITION
  1490 .1       INY           CHECK INPUT BUFFER FOR OPTION
  1500          LDA IN,Y
  1510          BEQ SYM1      =$00 is CR (NO OPTION); USE ALPH.
  1520          CMP #'2'
  1530          BNE .1        OPTION 2 IS SYM2
  1540        JMP SYM2
  1550 *--------------------------------
  1560 **---SYM1 - ALPH. ORDER ---------
  1580 SYM1     LDA #0              SET INDEX TO LETTER A 
  1590          STA ALPH.INDEX
  1600 .1         LDX ALPH.INDEX    GET ADDR OF 1ST ITEM
  1620            STA PTR           FROM S-C ASM TABLE
  1630            INX
  1640            LDA ALPHTABLE,X  HIGH BYTE
  1650             PHP
  1660            STA PTR+1
  1670            INX
  1680            STX ALPH.INDEX   READY FOR NEXT
  1690             PLP
  1700            BEQ .3           SKIP IF NO ITEMS THIS LETTER
  1710 .2           JSR DO.ITEM    PRINT NAME & ADDRESS
  1720              JSR NEXT.ITEM.A
  1730              BNE .2         FOR EACH ITEM, THIS LETTER
  1740 .3         LDX ALPH.INDEX
  1750            CPX #50          
  1760            BCC .1           LOOP 'TILL DONE Z
  1770          JMP CROUT         PRINT LAST LINE IN PRINTER 
  1780 *--------------------------------
  1790 **-- SYM2 - NUMERICAL ORDER -----
  1820          STA PTR+1
  1830          LDA LOMEM
  1840          STA PTR 
  1850 .1         JSR DO.ITEM     PRINT NAME & ADDRESS
  1860            JSR NEXT.ITEM.N
  1870            LDA PTR         CHECK FOR END 
  1880            CMP END.TABLE
  1890            LDA PTR+1
  1900            SBC END.TABLE+1
  1910            BCC .1          LOOP TILL END OF TABLE
  1920          JMP CROUT
  1930 *--------------------------------
  1940 **------ DO.ITEM ----------------
  1960 DO.ITEM  LDY #6        GET KEY
  1970          LDA (PTR),Y
  1980 *------- PRINT NAME -------------
  1990          AND #%00111111 LOW 6-BITS IS LENGTH
  2000          STA LENGTH
  2010 .0         INY
  2020            LDA (PTR),Y  GET CHAR FROM NAME
  2030            ORA #$80     HI BIT ON
  2040            JSR PRCHAR   PRINT IT
  2050            DEC LENGTH
  2060            BNE .0       LOOP TO END OF NAME
  2070          LDA #"-"
  2080          JSR PRCHAR
  2090 *------ PRINT ADDRESS -----------
  2100          LDA #0        NOTE:32 BITS
  2120          LDY #5
  2130          STY YSAVE
  2150            BNE .2       
  2160            LDA NONZERO   SKIP LEADING 0
  2170            BEQ .3
  2180 .2         JSR PRBYTE     PRINT BYTE
  2190            INC HORIZ
  2200            INC HORIZ
  2210            INC NONZERO
  2220 .3         DEC YSAVE     NEXT BYTE LOWER
  2230            LDY YSAVE
  2240            CPY #3
  2250            BCS .1
  2260          LDA (PTR),Y   ALWAYS DO LOWEST BYTE
  2270          JSR PRBYTE
  2280          INC HORIZ
  2290          INC HORIZ
  2300 *----------- TAB ----------------
  2310          LDX #NO.COLUMNS-1
  2320          CLC
  2330          LDA #0
  2340 .4         ADC #LINE.LENGTH/NO.COLUMNS
  2350            CMP HORIZ
  2360            BEQ .45
  2370            BCS .5      FOUND
  2380 .45        DEX
  2390            BNE .4      TRY NEXT TAB 
  2400          JSR CROUT     MOVE ON TO NEXT LINE
  2410          LDA #0
  2420          STA HORIZ
  2430          BEQ .6          ...ALWAYS
  2440 .5       PHA           SPACE TO NEXT TAB
  2450          SEC
  2460          SBC HORIZ
  2470          TAX
  2480          JSR PRBL2
  2490          PLA
  2500          STA HORIZ
  2510 *------ STOP/START/QUIT ---------
  2520 .6       LDA KEYBD     STOP UPON KEYPRESS
  2530          BPL .7
  2540          STA STROBE
  2550          JSR RDKEY     WAIT FOR 2ND KEYPRESS
  2560          CMP #$8D
  2570          BNE .7
  2580          PLA           EXIT ON RETURN
  2590          PLA
  2600 .7       RTS
  2610 **------- PRCHAR ----------------
  2630          JSR COUT
  2640          INC HORIZ
  2650          LDY YSAVE
  2660          RTS
  2670 **---- NEXT.ITEM.A --------------
  2680 NEXT.ITEM.A
  2690          LDY #1        GET ADDR OF NEXT ITEM FROM THIS ONE
  2700          LDA (PTR),Y   (LEFT BY S-C ASM)
  2710          PHA
  2720          DEY
  2730          LDA (PTR),Y   AND LOW
  2740          STA PTR
  2750          PLA
  2760          STA PTR+1
  2770          RTS
  2780 **---- NEXT.ITEM.N --------------
  2790 NEXT.ITEM.N
  2800          LDY #6        GET KEY FROM THIS ITEM
  2810          LDA (PTR),Y
  2820          PHP           SAVE +/- STATUS
  2830          AND #%00111111   GET LENGTH OF SYMBOL
  2840          CLC
  2850          ADC #6
  2860          TAY
  2870          PLP
  2880          BPL .2        SKIP IF NO LOCAL LABELS  
  2890 .1         INY
  2900            LDA (PTR),Y
  2910            BEQ .2
  2920            INY
  2930            BNE .1      ...ALWAYS
  2940 *---
  2950 .2       TYA
  2960          SEC
  2970          ADC PTR
  2980          STA PTR
  2990          BCC .4
  3000          INC PTR+1
  3010 .4       RTS
  3020 *--------------------------------

Minuteman 250 UPS Bob Sander-Cederlof

For years I have been wanting an uninterruptible power supply. Now with a Sider and a large RAMWORKS card, it is almost an imperative. A short interruption of power could easily destroy a full day's work or more. If it occurred while I am writing on the Sider or even on a floppy, it could result in a lot more damage. Other power problems, like spikes which occur during thunderstorms, can cause physical damage to the power supplies in the Apple or its peripherals. I might be able to blame the recent $177 replacement of my Sider power supply on just such a storm.

The reason I haven't bought a UPS before now is the price. Almost all of them are over $500. At last I have found one with most of the features I want, for only $359.

The Minuteman 250, from Para Systems (a local Dallas company), is just right for an Apple II system. It may be right for yours as well. If so, we will send you one for $350 plus freight. Normal freight inside the USA should be under $10. Para Systems makes a full line of UPS products, up to 1000 watts. The Minuteman 250 is rated at 250 watts, and is more than adequate for an Apple II system.

The unit is about an inch larger than a standard Disk II drive in each dimension (it fits nicely under the drive on my system), and weighs 19 pounds. It is heavy for its size, because there is a lot inside: sealed maintenance-free 12-volt battery, inverter and charger electronics, line surge protection, and so on. Normally, power from the AC-line passes through a 3-stage EMI/RFI filter and surge protector directly to your equipment. When the AC-power drops below 95 volts, a battery-powered inverter takes over within four milliseconds. The inverter output is a stepped rectangular wave form, which approximates a sine wave. (Pure sine-wave output costs a lot more, and is not necessary for any equipment I am using.)

There are two outlets, so I plugged my Sider into one and my Apple //e into the other. Usually I have a fan on the side of my //e, from RH Electronics or Kensington Microware. The fan unit plugs into the Minuteman UPS, and powers the Apple //e, an Apple monochrome monitor, and a dot matrix printer. The printer is rated about 60 watts, Sider about 40 watts, monitor about 30 watts, and Apple about 60 watts. That is a total of 190 watts, if the printer is running, or 130 when it is not running. Minuteman can handle a 250-watt load, and maintain full operation for five minutes after the AC input power goes away. If I am not printing, it should maintain full operation of everything else for 15 minutes. That is plenty of time to back up whatever I am working on and turn off the system.

There are a few disadvantages. When AC input power goes away, there is an audible alarm. The alarm is a continuous tone, sounding for the entire time that the AC is off and the battery is powering the system. When the battery has two minutes of charge remaining, the alarm changes to a beep-beep-beep sound. There is no way to shut off the alarm until either AC power comes back on, or you turn off your computer and the UPS. It gets very tiresome. I think there should be a way to either turn off the audible alarm, until the last two minutes of battery power, or at least change it to a short blip once per half-minute or so.

However, in the nine years I have been using Apples, I have not had a serious power outage while my computer was in use. Maybe as many as ten times in nine years there have been very short power outages, most as short as one or two seconds. There have been occasional annoying problems we have blamed on power glitches, spikes, or whatever. The Minuteman should take care of all of these.

The other disadvantage is that when you are leaving the system off and unattended for a long time, you are supposed to remember to turn off the Minuteman. If you leave it on, and AC power goes off for a long time, the battery could be damaged. I don't know how long power would have to be off to damage the battery, since the only power used would be that to run the inverter, but I am guessing it would be at least several hours. It seems to me that there should be a circuit built in to the Minuteman to detect the no-external-load condition, and shut itself off before battery damage could occur.

Even with these disadvantages, I heartily recommend the Minuteman 250. If it even saves me from ONE catastrophic situation, it could pay for itself. As I mentioned above, we will send you one for only $350 plus freight.

Automatic SETUP for ProDOS S-C Macro Assembler Bill Morgan

Several readers have asked how to automatically execute some file upon starting the ProDOS S-C Macro Assembler, perhaps the Full Screen Editor, perhaps a RAMdisk program, or maybe an EXEC file to install several features. What people want is something analogous to BASIC.SYSTEM's automatic "-STARTUP" feature.

We should be able to patch the assembler's installation code to issue a ProDOS command by stuffing the command into the input buffer, terminated with a Carriage Return, and then calling $BE03 to execute the command. However, not all commands function properly under this approach. The problem here is that the "-" command doesn't work, and the BRUN command seems to depend on how the called program exits. Specifically, when I tried to install my RAMdisk by sending BRUN PRODRIVE the program ran OK, but then crashed into the monitor rather than starting the assembler. A "-" command seemed to be simply ignored. I did find that BRUN FSE to install the Full Screen Editor worked correctly.

The ProDOS books say that you cannot issue the "-" and EXEC commands this way under BASIC.SYSTEM, so I assumed that EXEC would also fail for the assembler. The first version of this article therefore talked only about installing FSE, and suggested carefully testing other programs. At the last minute I decided to actually test EXEC before printing this. IT WORKED!

So, all you have to do is add the following patch to the assembler's installation code and create a text file to issue the commands you want. Here's the SETUP file I use:

     BSAVE /RAM/FILER,A$1000,L25600

If you want to try this technique with other programs, be sure to start out with a test disk in case of unpredictable results.

You can confirm the address of the SC.INIT routine by checking the JSR instruction at $8000 when the assembler is running. In the assembler's installation routine, $206A is the address of the JMP $8000 instruction that actually starts the assembler.

To install this into the assembler, first boot into the ProDOS S-C Macro Assembler, then do these steps:

     :BSAVE SCASM.SYSTEM,A$2000,L17920

If the file length of the assembler is different in the catalog of your disk, use that length in the L parameter.

  1010 *--------------------------------
  1020 WBUF       .EQ $200
  1040 SC.INIT    .EQ $830F
  1050 DOSCMD     .EQ $BE03
  1060 *--------------------------------
  1070        .OR $206A
  1080        JMP STARTER
  1100        .OR $21B0
  1110 STARTER
  1120        JSR SC.INIT  get assembler ready
  1130        LDX #0
  1140 .1     LDA COMMAND,X
  1150        BEQ .2
  1160        STA WBUF,X   stuff command into buffer
  1170        INX
  1180        BNE .1       always
  1200 .2     JSR DOSCMD   do it!
  1210        JMP $8003    just in case
  1220 *--------------------------------
  1240         .HS 8D00

More on DOS 3.3 and BRUN Louis Pitz

In the June 1986 issue of AAL Bob tried to give the final word on the problem of using BRUN to execute machine language programs which themselves issue DOS commands. His last example, on page 12, still falls short of a complete solution. By adding some code I found in "Beneath Apple DOS", page 6-17, the solution can be complete. The following code can be BRUN either from the keyboard or from within an Applesoft program:

  1000        .OR $300
  1010        .TF B.SHOW.OFF
  1020 *--------------------------------
  1040        LDA $AA59    SAVE DOS STACK POINTER
  1050        PHA             ON THE STACK
  1060 *--------------------------------
  1070        LDY #0
  1090        JSR $FDED
  1100        INY
  1110        CPY #MSGSZ
  1120        BNE .1
  1130 *--------------------------------
  1140        LDA #0       EQUIVALENT TO "NOMON C"
  1150        STA $AA5E
  1160        PLA          RESTORE DOS STACK POINTER
  1170        STA $AA59
  1180 *--------------------------------
  1190        LDY $76      MSB OF APPLESOFT LINE NUMBER
  1200        INY          IF WAS $FF, MAKE $00
  1210        BEQ .2       ...NOT IN APPLESOFT RUN MODE
  1220        LDY $33      PROMPT CHARACTER
  1230        CPY #"]"     IS IT THE APPLESOFT PROMPT?
  1240        BEQ .2       ...YES, SO NOT IN RUN MODE
  1250        RTS          PROGRAM RUNNING, EXIT WITH "RTS"
  1260 .2     JMP $3D0     NOT RUNNING, EXIT THE OTHER WAY
  1270 *--------------------------------
  1280 MSG    .HS 8D.84    <RETURN>, CTRL-D
  1290        .AS -/CATALOG/
  1300        .HS 8D
  1310 MSGSZ  .EQ *-MSG
  1320 *--------------------------------

An Important Patch for ProDOS S-C Macro Assembler Bob Sander-Cederlof

For over a year now a design error has been lurking inside the ProDOS version of the S-C Macro Assembler. Both the assembler and ProDOS itself make extensive use of the standard system input buffer, $200-2FF. During assembly, if you try to direct the object code to more than one target file (using the .TF directive more than one time), things did not go well. The DOS 3.3 version had no such problem.

Following is an example of such a source file. If you type it in and try to assemble it with the ProDOS version, the second and third ".OR" lines will not list properly. In fact, if you have a ProDOS-compatible clock installed, you will see the date and time information instead!

  1010 *--------------------------------
  1020        .OR $300
  1030        .TF B1
  1040 X      LDA #3
  1050 *--------------------------------
  1060        .OR $310
  1070        .TF B2
  1080 Y      LDA #3
  1090 *--------------------------------
  1100        .OR $320
  1110        .TF B3
  1120 Z      LDA #3
  1130 *--------------------------------

After much thought, the only way I can think of to "fix" it is to save the contents of the buffer each time the assembler issues a ProDOS command, and restore the contents afterward. There just happens to be enough room in a "patch" area between $BC00 and $BCFF to do this. The code that needs to be patched may not be in exactly the same location in every copy of the ProDOS version we have sold, so I have written a patching program which will automatically find the exact location and install the patches.

In the following program, a "dummy" section at lines 1800-1940 shows the patched routine. The addresses shown correspond to the latest version. The code shown at $901F-9034 was originally located three bytes lower, at $901C-9031. My patcher moves the code three bytes higher, as shown, and inserts the JSR PATCH1 and JMP PATCH2 code. The PATCH code goes into a free space at $BC00, and the save area is from $BC80 through $BCFF. The patches are actually installed on the image of the SCASM.SYSTEM file, as BLOADed into $2000-$65FF.

Once you have the patching program typed in, the procedure to install the patches is as shown in the comments at the beginning of the program (lines 1020-1060). Just to be sure you have it all right, don't save the patched version on an important disk! Try it out first on a scratch disk, and if everything still works you can update your master copies.

On the other hand, if the whole process seems to laborious or dangerous, send us the original disk of the ProDOS S-C Macro Assembler and we will update it for you. Or, if we have your registration on file you may send $5 and we will send you a fresh disk with the updated version on it.

Many thanks to Richard A. Sims for pointing out this problem to us.

  1000 *SAVE FIX.TF.9.8.86
  1010 *--------------------------------
  1020 *    :LOAD FIX.TF.9.8.86
  1030 *    :ASM
  1040 *    :BLOAD SCASM.SYSTEM,TSYS,A$2000
  1050 *    :$800G
  1060 *    :BSAVE SCASM.SYSTEM,TSYS,A$2000,L$4600
  1070 *--------------------------------
  1080 PNTR   .EQ $00,01
  1090 *--------------------------------
  1100 PATCH.SC
  1110 *---COPY PATCH1, PATCH2 TO $5D00 (IMAGE OF $BC00)---
  1120        LDY #0
  1130 .1     LDA BC00,Y
  1140        STA $5D00,Y
  1150        INY
  1160        CPY #BC00.SZ
  1170        BCC .1
  1180 *---FIND A2.FF.E8.BD.CE BTWN 2000.65FF--------------
  1190        LDA #$2000
  1200        STA PNTR
  1210        LDA /$2000
  1220        STA PNTR+1
  1230 .2     LDY #0
  1240 .3     LDA (PNTR),Y
  1250        CMP STRING,Y
  1260        BEQ .4       ...MATCHES SO FAR
  1270        INC PNTR
  1280        BNE .2
  1290        INC PNTR+1
  1300        LDA PNTR+1
  1310        CMP /$6600
  1320        BCC .2
  1330        BRK          COULD NOT FIND STRING
  1340 ***
  1350 .4     INY
  1360        CPY #STRING.SZ
  1370        BCC .3
  1380 *---COPY ADDRESS OF PASS.CMD.TO.PRODOS--------------
  1390        LDY #$1A
  1400        LDA (PNTR),Y
  1410        STA PATCH2-$BC00+$5D00+4
  1420        INY
  1430        LDA (PNTR),Y
  1440        STA PATCH2-$BC00+$5D00+5
  1460        LDY #$15
  1470 .5     LDA (PNTR),Y
  1480        INY
  1490        INY
  1500        INY
  1510        STA (PNTR),Y
  1520        DEY
  1530        DEY
  1540        DEY
  1550        DEY
  1560        BPL .5
  1570 *---BUILD "JSR PATCH1"------------------------------
  1580        LDY #0
  1590        LDA #$20
  1600        STA (PNTR),Y
  1610        INY
  1620        LDA #PATCH1
  1630        STA (PNTR),Y
  1640        INY
  1650        LDA /PATCH1
  1660        STA (PNTR),Y
  1670 *---BUILD "JMP PATCH2"------------------------------
  1680        LDY #$1A
  1690        LDA #PATCH2
  1700        STA (PNTR),Y
  1710        INY
  1720        LDA /PATCH2
  1730        STA (PNTR),Y
  1740        RTS
  1750 *--------------------------------
  1760 STRING .HS A2.FF.E8.BD.CE
  1780 *--------------------------------
  1790        .DUMMY
  1800        .OR $901C
  1820        JSR PATCH1
  1830        LDX #-1
  1840 .1     INX
  1850        LDA $2CE,X
  1860        STA $205,X
  1870        BNE .1
  1880        TAX
  1890 .2     INX
  1900        INY
  1910        LDA $904B,Y
  1920        STA $1FF,X
  1930        BPL .2
  1940        JMP PATCH2
  1950        .ED
  1960 *--------------------------------
  1970 BC00   .PH $BC00
  1980 PATCH1 LDX #0
  1990 .1     LDA $200,X
  2000        STA $BC80,X
  2010        INX
  2020        BPL .1
  2030        RTS
  2040        JSR *-*  $84C2
  2050        LDX #127
  2060 .3     LDA $BC80,X
  2070        STA $200,X
  2080        DEX
  2090        BPL .3
  2100        RTS
  2110        .EP
  2120 BC00.SZ .EQ *-BC00
  2130 *--------------------------------

Patch Bob's ProDOS Selector for Videx Garth O'Donnell

The new ProDOS program selector code published in the July 1986 AAL works very well in most configurations, but not in a slot 3 80-column card such as the Videx card I have. The following modifications allow it to work on an Apple II Plus with a Videx 80-column card:

               Original        Videx Version

       1425    LDA #$99        LDA #$8C
       1640    JSR HOME        LDA #$8C
       1641    --------        JSR COUT
       3460    LDA #$FF        LDA #$8E
       3470    STA INVFLG      JSR COUT
       4500    LDA #$3F        LDA #$8F
       4510    STA INVFLG      JSR COUT

These same changes may work with most other 80-column cards, including the //c and //e. The only place I am sure they do not work is in 40-columns. Perhaps by squeezing the code somewhere, we could find room to test the byte at $37. If ($37) is $C3, then we are most probably in an 80-column mode, and should use the patched version above; if not $C3, then do it the way Bob originally wrote it.

MLI Calls and the Monitor "L" Command Bob Sander-Cederlof

The "L" command in Wozniak's monitor is one of the great secrets behind Apple's success. "L" has been the key to unlocking many secret doors, enabling programmers to stand on each other's shoulders in their efforts to write all the wonderful software we now enjoy.

Nevertheless, "L" can be improved. We have published at least once before a way to add the ability to specify starting and ending addresses, rather than just living with the built in 20-lines-at-a-time feature. Now that ProDOS is so prevalent, it would be nice if the "L" command could properly handle MLI calls. The three bytes which follow any "JSR $BF00" instruction should be dis-assembled as one hex byte and an address.

The following program adds both of these improvements. It sets up the control-Y monitor command, so that you can disassemble a range of memory. The command can be entered in several formats. In the following examples, "^Y" means "control-Y"

       *2000^Y        disassemble one instruction
       *2000.20FF^Y   disassemble 2000..20FF
       *.2300^Y       continue and go thru 2300

In the listing which follows, lines 1140-1210 install the control-Y vector, so that that monitor command will call DISASM.BF00.

Lines 1240-1300 move the starting address into PC for the disassembler code, and increment the ending address so it will be easier to check later.

Lines 1320-1400 and 1780-1840 handle normal disassembly, but allow for the option of pausing by pressing any key, or aborting by pressing <RETURN>. If the line disassembled was "JSR $BF00", then lines 1420-1760 disassemble the MLI call number and the address of the MLI parameter block. For example, a disassembled call may look like this:

       2000- 20 00 BF  JSR $BF00
       2003- C1 34 20  .DA #$C1,$2034

Some of you enterprising people who have the source code to the Rak-Ware DISASM may want to add a feature like this to that product, too.

  1000 *SAVE S.DISASM.BF00
  1010 *--------------------------------
  1020 PC     .EQ $3A,3B
  1030 A1     .EQ $3C,3D
  1040 A2     .EQ $3E,3F
  1050 PARMS  .EQ $40,41,42
  1060 *--------------------------------
  1070 MON.INSTDP .EQ $F8D0
  1080 MON.PRBLNK .EQ $F948
  1090 MON.PCADJ  .EQ $F953
  1100 MON.PRYX2  .EQ $FD96
  1120 MON.COUT   .EQ $FDED
  1130 *--------------------------------
  1150        LDA #$4C     JMP OPCODE
  1160        STA $3F8
  1170        LDA #DISASM.BF00
  1180        STA $3F9
  1190        LDA /DISASM.BF00
  1200        STA $3FA
  1210        RTS
  1220 *--------------------------------
  1230 DISASM.BF00
  1240        LDA A1       LOAD STARTING ADDRESS
  1250        STA PC
  1260        LDA A1+1
  1270        STA PC+1
  1280        INC A2       ADJUST END ADDRESS
  1290        BNE .1
  1300        INC A2+1
  1310 *--------------------------------
  1320 .1     JSR PAUSE
  1330        JSR CHECK.FOR.MLI.CALL
  1340        PHP          SAVE ANSWER
  1350        JSR MON.INSTDP
  1360        JSR MON.PCADJ
  1370        STA PC
  1380        STY PC+1
  1390        PLP          WAS IT "JSR $BF00"?
  1400        BNE .2       ...NO
  1410 *--------------------------------
  1420        TAX                   DO PARMS LINE
  1430        JSR MON.PRYX2         ADDR-
  1440        JSR MON.PRBLNK
  1450        LDY #0
  1460        JSR MY.PRBYTE         XX XX XX
  1470        JSR MY.PRBYTE
  1480        JSR MY.PRBYTE
  1490        JSR MON.PRBLNK
  1500        LDA #"."              ".DA"
  1510        JSR MON.COUT
  1520        LDA #"D"
  1530        JSR MON.COUT
  1540        LDA #"A"
  1550        JSR MON.COUT
  1560        JSR MON.PRBLNK
  1570        LDA #"#"
  1580        JSR MON.COUT
  1590        LDA #"$"
  1600        JSR MON.COUT
  1610        LDA PARMS
  1620        JSR MON.PRBYTE
  1630        LDA #","
  1640        JSR MON.COUT
  1650        LDA #"$"
  1660        JSR MON.COUT
  1670        LDA PARMS+2
  1680        JSR MON.PRBYTE
  1690        LDA PARMS+1
  1700        JSR MON.PRBYTE
  1710        CLC
  1720        LDA PC
  1730        ADC #3
  1740        STA PC
  1750        BCC .2
  1760        INC PC+1
  1770 *--------------------------------
  1780 .2     STA A1       (SET UP FOR ".ENDADDR^Y" CALL)
  1790        CMP A2       CHECK IF FINISHED
  1800        LDA PC+1
  1810        STA A1+1
  1820        SBC A2+1
  1830        BCC .1
  1840        RTS
  1850 *--------------------------------
  1870        LDY #0       LOOK AHEAD FOR "JSR $BF00"
  1880        LDA (PC),Y
  1890        CMP #$20     JSR?
  1900        BNE .1       ...NO
  1910        INY
  1920        LDA (PC),Y
  1930        BNE .1       ...NOT JSR $BF00
  1940        INY
  1950        LDA (PC),Y
  1960        CMP #$BF
  1970 .1     RTS
  1980 *--------------------------------
  1990 MY.PRBYTE
  2000        LDA (PC),Y
  2010        STA PARMS,Y
  2020        JSR MON.PRBYTE
  2030        LDA #" "
  2040        JSR MON.COUT
  2050        INY
  2060        RTS
  2070 *--------------------------------
  2080 PAUSE  LDA $C000
  2090        BPL .3
  2100        STA $C010
  2110        CMP #$8D
  2120        BEQ .4       ...ABORT
  2130 .1     LDA $C000
  2140        BPL .1
  2150        STA $C010
  2160        CMP #$8D
  2170        BNE .3
  2180 .4     PLA
  2190        PLA
  2200 .3     RTS
  2210 *--------------------------------

That Other Integer Square Root Bob Sander-Cederlof

As I mentioned last month, just as we were wrapping up the August issue I found a reference to another implementation of the "high school" method of taking square roots. By the time I got it ready there was no room left in that issue, so we postponed it 'til now. Most of the variables are the same as those used in the various routines presented last month.

In the May, 1985 issue of Dr. Dobb's Journal, in the 16-Bit Software Toolbox column, Jim Cathey offered a 68000 16-bit edition of the algorithm. What follows is my 6502 8-bit rendition of his approach.

  1010        .LIST CON
  1020 *--------------------------------
  1030 ARGLO  .EQ 0
  1040 ARGHI  .EQ 1
  1050 GUESS  .EQ 2
  1060 QUOT   .EQ 3
  1070 REM    .EQ 4
  1080 ROOT   .EQ 5
  1090 PROD   .EQ 6,7
  1100 TRIPS  .EQ 8
  1120 BITHI  .EQ 10
  1130 BITLO  .EQ 11
  1140 SUBHI  .EQ 12
  1150 SUBLO  .EQ 13
  1160 WORKHI .EQ 14
  1170 WORKLO .EQ 15
  3860 *--------------------------------
  3870 ERRHI  .EQ 16
  3880 ERRLO  .EQ 17
  3890 *--------------------------------
  3910 *      6502 VERSION AVERAGES 737 CYCLES
  3920 *--------------------------------
  3930 SQR3   LDA ARGHI    Save working copy of argument
  3940        STA WORKHI
  3950        LDA ARGLO
  3960        STA WORKLO
  3970        LDA #0
  3980        STA ROOT     Start with ROOT = 0
  3990        STA ERRHI           and ERR  = 0
  4000        STA ERRLO
  4010 *--------------------------------
  4020        LDY #8       8 pairs of bits in argument
  4030 .1     ASL WORKLO   Two bits out of WORK into ERR
  4040        ROL WORKHI
  4050        ROL ERRLO
  4060        ROL ERRHI
  4070        ASL WORKLO
  4080        ROL WORKHI
  4090        ROL ERRLO
  4100        ROL ERRHI
  4110        ASL ROOT     ROOT = ROOT*2
  4120        LDA ROOT     BIT = ROOT*2
  4130        ASL
  4140        STA BITLO
  4150        LDA #0
  4160        ROL
  4170        STA BITHI
  4180        LDA ERRLO    (CARRY IS CLEAR)
  4190        SBC BITLO    COMPUTE:  ERR-BIT-1
  4200        TAX          SAVE LO DIFFERENCE
  4210        LDA ERRHI
  4220        SBC BITHI
  4230        BCC .2       ERR < BIT
  4240        STA ERRHI
  4250        STX ERRLO
  4260        INC ROOT     ROOT = ROOT+1
  4270 .2     DEY
  4280        BNE .1
  4290        RTS
  4300 *--------------------------------

Thoughts on the ProDOS Bit Map Louis Pitz

I recently learned some more about ProDOS, the hard way. Yes, sometimes catastrophe is indeed the mother of invention, or at least of learning. I was trying to finish typing and saving a program when an electrical storm started. When I did a CATALOG, all the files seemed to be okay, but the footer info at the end about blocks free, used, and total was goofed up. Where I expected 86, 58, and 144, there was instead 681, 64999, and 144.

As an aside, there were only 144 total blocks because the disk is a combination of ProDOS and DOS 3.3, as described in AAL Sep 85 (page 11). But the lesson I learned would apply on regular ProDOS-only disks as well.

Note the logic in the goofed-up numbers: 681+64999 = 144 mod 65536. I suspected that, since everything else was okay, the volume bit map had been messed up. So I inspected the blocks on disk and confirmed my suspicion.

Further, the garbage in the volume bit map block was clearly extraneous, and none of the the good data (the first 144/8=18 bytes) had been changed. The garbage was $DC's in bytes $14A-1C0, inclusive. This is way past the end of the 'real' bytes even for a ProDOS-only disk (35 bytes). But ProDOS must have counted the 1-bits in the $DC bytes as free blocks. Then, subtracting this erroneously large number from 144, it got 64999. Yes! $DC=%11011100, and there are $77=119 such bytes, so that is 5*119=595 more "free" blocks to add to the 86 really free to get 681.

I've read Sandy Mossberg's article about the ProDOS CAT and CATALOG commands (Nibble, May 86), but the arithmetic counting used sectors must be buried deep in the MLI, associated with the GET-FILE-INFO call, according to my Beneath Apple ProDOS book. Apparently ProDOS must count all the 1-bits in the volume bit map blocks as free, regardless of the number of total blocks on the disk. In a way this seems like a bug, but I guess it was just a shortcut in coding.

The lesson I have learned is not to use the "unused" part of the volume bit map to store code, messages, or anything. For a ProDOS-only floppy, only 35 bytes are really used, and 477 bytes are wasted. Nevertheless, do not be tempted to use them. They are set to 0 upon formatting the disk, and ProDOS depends upon them staying that way! I've used the extra bytes in the DOS 3.3 VTOC before, but I had better resist this impulse in ProDOS.

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