Volume 6 -- Issue 12 | September 1986

In This Issue...

- Short Symbol Table Listing
- Minuteman 250 UPS
- Automatic Setup for ProDOS S-C Macro Assembler
- More on DOS 3.3 and BRUN
- Important Patch for ProDOS S-C Macro Assembler
- Patch Bob's ProDOS Selector for Videx
- MLI Calls and the Monitor "L" Command
- That Other Integer Square Root
- Thoughts on the ProDOS Bit Map

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

      1000 *SAVE S.SHORTSYM
      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
      1200 LOMEM      .EQ $67,68  WARNING: PRODOS VERSION ONLY
      1210
      1220 USR.VECTOR .EQ $8006   WARNING: PRODOS VERSION ONLY
      1230 *--------------------------------
      1240 IN         .EQ $200
      1250 ALPHTABLE  .EQ $132    ADDRESSES FOR 1ST ENTRY A,B,..
      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
      1340 PRBYTE .EQ $FDDA
      1350 COUT   .EQ $FDED
      1360 *--------------------------------
      1370 *-- BRUN OR "-" COMES HERE ------
      1380 SET.UP.USR.VECTOR
      1390        LDA #USR.PROCESSOR   SET UP USR VECTOR
      1400        STA USR.VECTOR+1
      1410        LDA /USR.PROCESSOR
      1420        STA USR.VECTOR+2
      1430        RTS
      1440 *--------------------------------
      1450 **-- "USR or USR2 comes here ----
      1460 USR.PROCESSOR
      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 ---------
      1570
      1580 SYM1     LDA #0              SET INDEX TO LETTER A
      1590          STA ALPH.INDEX
      1600 .1         LDX ALPH.INDEX    GET ADDR OF 1ST ITEM
      1610            LDA ALPHTABLE,X   OF THIS STARTING LETTER
      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 -----
      1800
      1810 SYM2     LDA LOMEM+1       POINT TO START OF TABLE
      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 ----------------
      1950
      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
      2110          STA NONZERO   USE THIS TO OMIT LEADING 0'S
      2120          LDY #5
      2130          STY YSAVE
      2140 .1         LDA (PTR),Y   GET BYTE OF ADDRESS, HIGH FIRST
      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 ----------------
      2620 PRCHAR   STY YSAVE
      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:

         - PRODRIVE
         BLOAD SCASM.SYSTEM,A$2000,TSYS
         BSAVE /RAM/SCASM.SYSTEM,A$2000,TSYS,L17920
         BLOAD BASIC.SYSTEM,A$2000,TSYS
         BSAVE /RAM/BASIC.SYSTEM,A$2000,TSYS,L10240
         BLOAD FILER
         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:

         :LOAD S.STARTER
         :BLOAD SCASM.SYSTEM,A$2000,TSYS
         :ASM
         :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.

      1000 *SAVE S.STARTER
      1010 *--------------------------------
      1020 WBUF       .EQ $200
      1030
      1040 SC.INIT    .EQ $830F
      1050 DOSCMD     .EQ $BE03
      1060 *--------------------------------
      1070        .OR $206A
      1080        JMP STARTER
      1090
      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
      1190
      1200 .2     JSR DOSCMD   do it!
      1210        JMP $8003    just in case
      1220 *--------------------------------
      1230 COMMAND .AS -/EXEC SETUP/
      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 *--------------------------------
      1030 PITZ.VERSION
      1040        LDA $AA59    SAVE DOS STACK POINTER
      1050        PHA             ON THE STACK
      1060 *--------------------------------
      1070        LDY #0
      1080 .1     LDA MSG,Y    ISSUE DOS CATALOG COMMAND
      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!

      1000 *SAVE S.TEST.FIXTF
      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
      1450 *---SHIFT "ISSUE.DOS.COMMAND" 3 BYTES AHEAD---------
      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
      1770 STRING.SZ .EQ *-STRING
      1780 *--------------------------------
      1790        .DUMMY
      1800        .OR $901C
      1810 ISSUE.DOS.COMMAND
      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
      2033 PATCH2 STX $BE42    ALLOW DEFERRED COMMANDS
      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
      1110 MON.PRBYTE .EQ $FDDA
      1120 MON.COUT   .EQ $FDED
      1130 *--------------------------------
      1140 INSTALL.CTRL.Y.VECTOR
      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 *--------------------------------
      1860 CHECK.FOR.MLI.CALL
      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.

      1000 *SAVE S.INTEGER.SQRT
      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
      1110 PREVIOUS.ROOT .EQ 9
      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 *--------------------------------
      3900 *   METHOD DERIVED FROM 68000 CODE IN DDJ MAY 85
      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.)