Volume 1 -- Issue 6 | March 1981

The Apple Assembly Line is still growing! I now am sending out over 300 copies per month! It is also growing in size, as you can see: this is the first 20 page issue.

In This Issue...

- A Beautiful Dump
- So-Called Unused Opcodes
- Complete 6502 Opcode Chart
- EDITASM and COPY on the Language Card
- Commented Listing of DOS 3.2.1 RWTS
- Substring Function for Applesoft

Second "Disk of the Quarter"

The second AALDQ is ready! If you would like to have the source code on disk in S-C Assembler II Version 4.0 format for all the programs which have appeared in AAL issues 4, 5, and 6, then send me $15. I will send you the disk, and you already have the documentation. DQ#1, covering issues 1, 2, and 3, is also still available at the same price.

Some New Books about the 6502

Apple Machine Language, by Don Inman and Kurt Inman, published by Reston (a Prentice-Hall Company). Hard cover, 296 pages, $14.95. If you are an absolute beginner, this is the book for you. You start by typing in an Applesoft program which helps you POKE in machine language code, and CALL it. Most of the examples involve lo-res graphics and sound. One chapter describes the Apple Mini-Assembler (which resides in the Integer BASIC ROMs). They never get around to a real assembler.

Practical Microcomputer Programming: the 6502, by W. J. Weller, published by Northern Technology Books. Hard cover, 459 pages, $32.95. Over 110 pages of the book are devoted to a listing of an assembler and a debugging package. A coupon inside the back cover can be redeemed for a tape copy which will run on the Apple II. By adding $7.50 to the coupon, you can get a disk version. The package can be loaded from the disk, but there is no capability for keeping source or object files on disk.

A Beautiful Dump | Robert H. Bernard

The old saying, "You can't tell the players without a scorecard," is certainly true for program debugging, and sometimes the only way is to look into memory and see what is there. The Apple II Monitor has a memory dump command, but I found it inadequate: it's formatted for a 40-column screen, it doesn't show ASCII codes, and getting output on a printer is a hassle.

So I sat down and wrote a quick assembly language memory dump modeled after a System/360 core dump (remember when computer memory was called "core"?), with both hex and ASCII. My first attempt took up more than one page of memory and was trapped where I assembled it by absolute internal references. I massaged it until it fit in less than a page and made it relocatable ("run anywhere") by making all internal jumps into relative branches. (A "page" in 6502 jargon is 256 bytes, with addresses running from xx00 through xxFF.)

Next I decided to add a printer feature; while I was at it I made it use 80 columns on the printer, 40 on the screen.

Next I made it print the bytes in groups of four, with a space between every four bytes. Sixteen bytes are printed per line on the screen, 32 on an 80-column printer. Spacing in groups of four makes it easier to spot certain address locations. If a byte value is a printable ASCII code, I print the character above the hexadecimal value. (Values $00-$1F and $80-$9F do not print.)

Then I wanted options to browze one screenful at a time, and backup when I passed the place I wanted to look at.

You probably think that by now the program is at least two, and maybe more, pages long. Not so! All the while I was able to keep it in only one page (which doesn't say much for my original code).

The end result (after 21 versions!) is listed here for your examination and pleasure.

Operating Instructions: BRUN the program anywhere in memory that you have a free page (256 bytes). When the "?" prompt appears, enter the address of the memory you want to dump in any of the following ways. After the address or address range, type the return key.

S.E | To dump memory from S to E on the screen.
S-E | To dump memory from S to E on the printer.
S,E | To dump memory from S to E on the screen, but pauses after each screenful; press space bar to continue, or press control-C to stop.
S | To dump from S, pausing after each line; press space bar to dump next line, press letter "B" to back up one line, or press control-C to stop.

     1000  *---------------------------------
     1010  *
     1020  * APPLE II RELOCATABLE MEMORY DUMP PROGRAM
     1030  *      BY ROBERT H. BERNARD
     1040  *         35 DOGWOOD LANE
     1050  *         WESTPORT, CT 06880
     1060  *
     1070  *         JANUARY 17, 1981
     1080  *
     1090  *      COMMERCIAL RIGHTS RESERVED
     1100  *
     1110  *---------------------------------
     1120  *      MONITOR ROM ROUTINES
     1130  *---------------------------------
     1140  MON.COUT   .EQ $FDED
     1150  MON.RDKEY  .EQ $FD0C
     1160  MON.GTLNZ  .EQ $FD67
     1170  MON.ZMODE  .EQ $FFC7
     1180  MON.GETNUM .EQ $FFA7
     1190  MON.CROUT  .EQ $FD8E
     1200  MON.PRNTYX .EQ $F940
     1210  MON.PRBL2  .EQ $F94A
     1220  MON.PRBYTE .EQ $FDDA
     1230  MON.MON    .EQ $FF65
     1240  MON.HOME   .EQ $FC58
     1250  MON.SETMOD .EQ $FE18
     1260  MON.OUTPOR .EQ $FE95    SET OUTPUT PORT TO SLOT (A)
     1270  MON.SETVID .EQ $FE93    SET VIDEO
     1280  *---------------------------------
     1290  *      I/O ADDRESSES
     1300  *---------------------------------
     1310  KBD    .EQ $C000    KEYBOARD
     1320  KBSTRB .EQ $C010    KBD RESET STROBE
     1330  *---------------------------------
     1340  *      PAGE-ZERO VARIABLES
     1350  *---------------------------------
     1360  PGCNT  .EQ $2E      LINES LEFT THIS PAGE
     1370  ITEMCT .EQ $30      ITEMS PER LINE
     1380  OPTION .EQ $31      SAME AS MON "MODE"
     1390  PROMPT .EQ $33      LOC OF GETLN PROMPT CHAR
     1400  YSAV   .EQ $34      POINTER TO IN BUFFER
     1410  FRADRL .EQ $3C      STARTING ADR LO ORDER
     1420  FRADRH .EQ $3D      ..HI ORDER
     1430  TOADRL .EQ $3E      ENDING ADR LO ORDER
     1440  TOADRH .EQ $3F      ..HI ORDER
     1450  *---------------------------------
     1460  *      USER-CHANGEABLE PARAMETERS
     1470  *---------------------------------
     1480  SCITMS .EQ 16       BYTES PER LINE SCREEN
     1490  PRITMS .EQ 32       BYTES PER LINE PRINTER
     1500  ITMSPG .EQ 8        ITEMS PER PAGE
     1510  PRSLOT .EQ 1        PRINTER SLOT
     1520  *---------------------------------
     1530         .OR $0800
     1540  *---------------------------------
     1550  MEMDMP JSR MON.SETVID   SET PR#0
     1560         LDA #$BF     '?' FOR BOUNDS
     1570         STA PROMPT   SET PROMPT CHAR
     1580         JSR MON.GTLNZ    CR, THEN GET INPUT
     1590         JSR MON.ZMODE    SET HEX DECODE MODE
     1600         JSR MON.GETNUM
     1610         STY YSAV     REMEMBER SCAN POS.
     1620         CPX #0       ANY ADR SCANNED?
     1630         BNE .3       YES
     1640         RTS          NO. TERMINATE
     1650         .DA MON.MON      MONITOR ENTRY (IN CASE YOU WANT
     1660  *                   TO CHANGE RETURN TO "JMP MON.MON")
     1670  *
     1680  .3     LDA #-SCITMS  BYTES PER SCREEN LINE
     1690         STA ITEMCT   ITEMS PER LINE
     1700         JSR MON.SETMOD   SET TO SCAN 2ND ARG
     1710         CMP #$AD     IS OPTION = '-' ?
     1720         BNE .2       NO. CHECK OTHERS
     1730         INC OPTION   MAKE '.'
     1740         LDA #PRSLOT  PRINTER SLOT NO
     1750         JSR MON.OUTPOR   SET OUTPUT PORT
     1760         LDA #-PRITMS  BYTES PER PRINTER LINE
     1770         STA ITEMCT   ITEMS PER LINE
     1780         BNE .1       GO GET 2ND ARG
     1790  *
     1800  .2     CMP #$AE     '.' ?
     1810         BEQ .1       YES. 2 ARGS
     1820         CMP #$AC     ','?
     1830         BNE SETPGL   ONLY ONE ARG
     1840  .1     LDY YSAV     PTR TO IN BUFFER
     1850         JSR MON.GETNUM   SCAN 2ND ARG
     1860         STY YSAV     PTR TO IN BUFFER
     1870  SETPGL LDA #ITMSPG  ITEMS PER PAGE
     1880         STA PGCNT
     1890  *
     1900  NEXTLN JSR MON.CROUT    SKIP A LINE
     1910         LDA ITEMCT   -ITEMS PER LINE
     1920         AND FRADRL   STARTING ADR 0 MOD ITEMCT
     1930         STA FRADRL
     1940         TAX
     1950         LDY FRADRH   ..TO PRINT
     1960         JSR MON.PRNTYX   PRINT IT IN HEX
     1970         LDX ITEMCT   NO OF BYTES THIS LINE
     1980         LDY #0       POINTER
     1990         BEQ NOBLNK   DON'T SPACE FIRST TIME
     2000  *
     2010  CHKKEY LDA KBD      KEY DOWN?
     2020         BPL CKDONE   NO
     2030         LDA KBSTRB   YES. CLEAR KEYBOARD
     2040         SEC          PREPARE FOR
     2050  MDMP2  BCS MEMDMP   JMP TO START
     2060  *
     2070  NXTCHR TYA          TEST FOR
     2080         AND #$03       0 MOD 4
     2090         BNE NOBLNK
     2100         LDA #$A0
     2110         JSR MON.COUT PRINT A BLANK
     2120  NOBLNK LDA #$A0
     2130         JSR MON.COUT PRINT A BLANK
     2140         LDA (FRADRL),Y     GET CHAR TO PRINT
     2150         CMP #$20     CNTRL CHAR?
     2160         BCC .1       YES. SUBSTITUTE BLANK
     2170         CMP #$80     CNTRL CHAR?
     2180         BCC .2       NO. OK TO PRINT
     2190         CMP #$A0     CNTRL CHAR?
     2200         BCS .2       NO. OK TO PRINT
     2210  .1     LDA #$A0     SUBSTITUTE BLANK
     2220  .2     JSR MON.COUT
     2230         INY          POINT AT NEXT
     2240         INX          DONE ON THIS LINE?
     2250         BNE NXTCHR   NO
     2260         JSR MON.CROUT    YES. CR
     2270  * PREPARE TO PRINT SAME ITEMS IN HEX
     2280         LDX #3
     2290         JSR MON.PRBL2    OUTPUT (X) BLANKS
     2300         LDX ITEMCT   ITEMS PER LINE
     2310         LDY #0       POINTER
     2320         BEQ NXTHEX   (JMP)
     2330  *
     2340  SETPL1 BCS SETPGL   JUMP TO SET PG LENGTH
     2350  CKOPT  CMP #$AC     NO. OPTION=',' ?
     2360  NXTLN1 BNE NEXTLN   NO. JUMP TO PRINT
     2370  CKDONE LDA FRADRL   TEST IF DONE
     2380         CMP TOADRL
     2390         LDA FRADRH
     2400         SBC TOADRH
     2410         BCC NEXTLN   FROM < TO
     2420  MDMP1  BCS MDMP2    JMP TO START
     2430  *
     2440  NXTHEX TYA          TEST FOR
     2450         AND #$03       0 MOD 4
     2460         BNE .1       IF NOT, SKIP BLANK
     2470         LDA #$A0
     2480         JSR MON.COUT PRINT A BLANK
     2490  .1     LDA (FRADRL),Y BYTE TO OUTPUT
     2500         JSR MON.PRBYTE   OUTPUT IN HEX
     2510         INY          NEXT
     2520         INX          DONE ON THIS LINE?
     2530         BNE NXTHEX   NO
     2540         JSR MON.CROUT    YES. CR
     2550  *      ADVANCE DUMP ADDRESS
     2560         SEC          PREPARE FOR SUBTRACT
     2570         LDA FRADRL   INCREMENT ADDRESS
     2580         SBC ITEMCT   -ITEMS PER LINE
     2590         STA FRADRL
     2600         BCC .2       NO CARRY
     2610         INC FRADRH   PAGE BOUNDARY
     2620         BEQ MDMP1    END OF MEMORY
     2630  .2     LDA OPTION
     2640         CMP #$AE     '.'? (OPTION 1)
     2650         BEQ CHKKEY   NO. CHECK IF KEY DOWN
     2660  CHKPAG DEC PGCNT    PAGE END?
     2670         BNE CKOPT    NO. CHECK OPTION
     2680  PAUSE  JSR MON.RDKEY    GET A CHAR
     2690         CMP #$83     CNTRL-C?
     2700         BEQ MDMP1    YES. START OVER
     2710         CMP #$C2     WAS CHAR READ A 'B'?
     2720         BEQ BACKUP   YES
     2730         LDA OPTION
     2740         CMP #$AC     OPTION=',' ?
     2750         BEQ SETPL1   YES
     2760  ADVNCE INC PGCNT    ONE MORE TIME
     2770         BNE NXTLN1   JMP TO NXTLN
     2780  *
     2790  BACKUP LDA FRADRL   CARRY IS SET
     2800         SBC #144     BACKUP SCITMS*(ITMSPG+1) BYTES
     2810         STA FRADRL   SAVE LO ORDER
     2820         BCS .1       NO CARRY
     2830         DEC FRADRH   PROPOGATE CARRY
     2840  .1     JSR MON.HOME     CLEAR SCREEN
     2850         SEC          SIMULATE JMP
     2860         BCS SETPL1   ..TO SETPGL
     2870  *
     2880  ZZSIZE .EQ *-MEMDMP PROGRAM SIZE
     9999         .LIF

So-Called Unused Opcodes | Bob Sander-Cederlof

The 6502 has 104 so-called unused opcodes. The various charts and reference manuals I have checked either leave them blank or call them "unused", "no-operation", or "future expansion". The 6502 has been around since 1976; I think we have waited long enough to know there will be no "expansion". But are they really unused? Do they have any effect if we try to execute them? Are they really no-ops? If so, how many bytes does the processor assume for each one?

These questions had never bothered me until I was looking through some disassembled memory and thought I found evidence of someone USING the "unused". It turned out they were not, but my curiosity was aroused. Just for fun, I built a little test routine and tried out the $FF opcode. Lo and behold! The 6502 thinks it is a 3-byte instruction, and it changes the A-register and some status bits!

About 45 minutes later I pinned it down: FFxxyy performs exactly the same as the two instructions FExxyy and FDxxyy. It is just as though I had executed one and then the other. In other words, anywhere in a program I find:

         INC VARIABLE,X
         SBC VARIABLE,X

I can substitute:

         .HS FF
         .DA VARIABLE
    !!!!

You might wonder if I will ever find that sequence. I did try writing a program to demonstrate its use. It has the advantage of saving 3 bytes, and 4 clock cycles. (The SBC instruction is executed DURING the 7 cycles of the INC instruction!)

         TEST LDX INDEX
              LDA #10       FOR COUNTER(X)=10 TO 39
              STA COUNTER,X
         .1   LDA COUNTER,X GET COUNTER(X)
              JSR $FDDA     PRINT IT OUT (OR WHATEVER)
              LDA #39       LIMIT
              .HS FF        DO INC AND SBC
              .DA COUNTER   ON COUNTER,X
              BCS .1        NEXT
              RTS

Are there any more? Before I could rest my curiosity, I had spent at least ten more hours, and had figured out what all 104 "unused opcodes" really do!

The center-fold chart shows the fruit of my detective work. The shaded opcodes are the "unused" ones. I don't know if every 6502 behaves the same as mine or not. Mine appears to be made by Synertek, and has a date code of 7720 (20th week of 1977). It could be that later versions or chips from other sources (MOS Technology or Rockwell) are different. If you find yours to be different, please let me know!

Twelve of the opcodes, all in column "x2", hang up the 6502; the only way to get out is to hit RESET or turn off the machine.

There are 27 opcodes which appear to have no effect on any registers or on memory. These could be called "NOP", but some of them are considered by the 6502 to have 2 or 3 bytes. I have labeled them "nop", "nop2", and "nop3" to distinguish how many bytes the 6502 thinks it is using. You could call nop2 "always skip one byte" and nop3 "always skip two bytes".

The action most of the rest perform can be deduced by looking at the other opcodes in the same row. For example, all of the xF column (except 8F and 9F) perform two instructions together: first the corresponding xE opcode, and then the corresponding xD opcode. In the same way, most of the opcodes in column x7 combine the x6 and x5 opcodes. The x3 column mirrors the x7 and xF columns, but with different addressing modes. And finally, the xB column mimics the other three columns, but with more exceptions. Most of the exceptions are in the 8x and 9x rows.

A few of the opcodes seem especially interesting and potentially useful. For example, A3xx performs three steps: first it loads xx into the X-register; then using this new value of X, it moves the byte addressed by (xx,X) into both the A- and X- registers. Another way of looking at this one is to say that whatever value xx has is doubled; then the two pagezero bytes at 2*xx and 2*xx+1 are used as the address for loading the A- and X-registers. You could use this for something, couldn't you?

There are five instructions which form the logical product of the A- and X-registers (without disturbing either register) and store the result in memory. If we call this new instruction "SAX", for "Store A&X", we have:

         83   SAX (z,X)             8F   SAX a
         87   SAX z                 9F   SAX a,X
         97   SAX z,Y

We get seven forms of the combination which shift a memory location using ASL, and then inclusive OR the results into A with an ORA instruction. If we call this new instruction ALO, we have:

         03   ALO (z,X)             1B   ALO a,Y
         13   ALO (z),Y             0F   ALO a
         07   ALO z                 1F   ALO a,X
         17   ALO z,X

The same seven forms occur for the combinations ROL-AND, LSR-EOR, and ROR-ADC. Note that if you don't care what happens to the A-register, and the status register, these 28 instructions make two extra addressing modes available to the shift instructions: (z,X) and (z),Y.

Opcodes 4B and 6B might also be useful. You can do an AND-immediate followed by LSR or ROR on the A-register.

Opcodes 93, 9B, and 9E are really weird! It took a lot of head-scratching to figure out what they do.

         93   Forms the logical product of the A-register
              and byte the at z+1 (which I call "hea")
              and stores it at (z),Y.

         9B   Forms the logical product of the A- and X-
              registers, and stores the result in the S-
              register (stack pointer)!  Ouch!
              Then it takes up the third byte of the
              instruction (yy from 9B xx yy) and adds one
              to it (I call it "hea+1").  Then it forms
              the logical product of the new S-register
              and "hea+1" and stores the result at "a,Y".
              Whew!

         9E   Forms the logical product of the X-register
              and "hea+1" and stores the result at "a,Y".

We get six forms of the new "LAX" instruction, which loads the same value into both the A- and X-registers:

         B3   LAX (z),Y             AB   LAX #v
         A7   LAX z                 AF   LAX a
         B7   LAX z,Y               BF   LAX a,Y

I skipped over BB, because it is another extremely weird one. It forms the logical product of the byte at "a,Y" and S-register, and stores the result in the A-, X-, and S-registers. No wonder they didn't tell us about it!

Right under that one is the CB instruction. Well, good buddy (please excuse the CB talk!), it forms the logical product of the A- and X-registers, subtracts the immediate value (second byte of CB xx), and puts the result into the X-register.

The Cx and Dx rows provide us with seven forms that do a DEC on a memory byte, and then CMP the result with the A-register. Likewise, the Ex and Fx rows give us seven forms that perform INC followed by SBC.

It is a good thing to be aware that the so-called "unused" opcodes can be quite dangerous if they are accidentally executed. If your program goes momentarily wild and executes some data, chances are something somewhere will get strangely clobbered.

Since all of the above information was deduced by testing and observation, I cannot be certain that I am 100% correct. I may have overlooked or mis-interpreted some results, or even made a clerical error. Furthermore, as I said before, my 6502 may be different from yours. You can test your own, to see if it works like mine.

And if the whole exercise seems academic to you, you can at least enjoy the first legible and complete hexadecimal opcode chart for the 6502.

        x0        x1             x2             x3
    -----------------------------------------------------------
    0x  BRK       ORA (z,X)      hang           ASL (z,X)
                                                ORA (z,X)

    1x  BPL r     ORA (z),Y      hang           ASL (z),Y
                                                ORA (z),Y

    2x  JSR a     AND (z,X)      hang           ROL (z,X)
                                                AND (z,X)

    3x  BMI r     AND (z),Y      hang           ROL (z),Y
                                                AND (z),Y

    4x  RTI       EOR (z,X)      hang           LSR (z,X)
                                                EOR (z,X)

    5x  BVC r     EOR (z),Y      hang           LSR (z),Y
                                                EOR (z),Y

    6x  RTS       ADC (z,X)      hang           ROR (z,X)
                                                ADC (z,X)

    7x  BVS r     ADC (z),Y      hang           ROR (z),Y
                                                ADC (z),Y

    8x  nop2      STA (z,X)      nop2           A&X
                                                --> (z,X)

    9x  BCC r     STA (z),Y      hang           A&hea
                                                --> (z),Y

    Ax  LDY #v    LDA (z,X)      LDX #v         LDX #v
                                                LDA (z,X)
                                                LDX (z,X)

    Bx  BCS r     LDA (z),Y      hang           LDA (z),Y
                                                LDX (z),Y

    Cx  CPY #v    CMP (z,X)      nop2           DEC (z,X)
                                                CMP (z,X)

    Dx  BNE r     CMP (z),Y      hang           DEC (z),Y
                                                CMP (z),Y

    Ex  CPX #v    SBC (z,X)      nop2           INC (z,X)
                                                SBC (z,X)

    Fx  BEQ r     SBC (z),Y      hang           INC (z),Y
                                                SBC (z),Y

        x4        x5             x6             x7
    -----------------------------------------------------------
    0x  nop2      ORA z          ASL z          ASL z
                                                ORA z

    1x  nop2      ORA z,X        ASL z,X        ASL z,X
                                                ORA z,X

    2x  BIT z     AND z          ROL z          ROL z
                                                AND z

    3x  nop2      AND z,X        ROL z,X        ROL z,X
                                                AND z,X

    4x  nop2      EOR z          LSR z          LSR z
                                                EOR z

    5x  nop2      EOR z,X        LSR z,X        LSR z,X
                                                EOR z,X

    6x  nop2      ADC z          ROR z          ROR z
                                                ADC z

    7x  nop2      ADC z,X        ROR z,X        ROR z,X
                                                ADC z,X

    8x  STY z     STA z          STX z          A&X
                                                --> z

    9x  STY z,X   STA z,X        STX z,Y        A&X
                                                --> z,Y

    Ax  LDY z     LDA z          LDX z          LDX z
                                                LDA z

    Bx  LDY z,X   LDA z,X        LDX z,Y        LDX z,Y
                                                LDA z,Y

    Cx  CPY z     CMP z          DEC z          DEC z
                                                CMP z

    Dx  nop2      CMP z,X        DEC z,X        DEC z,X
                                                CMP z,X

    Ex  CPX z     SBC z          INC z          INC z
                                                SBC z

    Fx  nop2      SBC z,X        INC z,X        INC z,X
                                                SBC z,X

        x8        x9             xA             xB
    -----------------------------------------------------------
    0x  PHP       ORA #v         ASL            AND #v

    1x  CLC       ORA a,Y        nop            ASL a,Y
                                                ORA a,Y

    2x  PLP       AND #v         ROL            AND #v

    3x  SEC       AND a,Y        nop            ROL a,Y
                                                AND a,Y

    4x  PHA       EOR #v         LSR            AND #v
                                                LSR

    5x  CLI       EOR a,Y        nop            LSR a,Y
                                                EOR a,Y

    6x  PLA       ADC #v         ROR            AND #v
                                                ROR

    7x  SEI       ADC a,Y        nop            ROR a,Y
                                                ADC a,Y

    8x  DEY       nop2           TXA            #v&X
                                                --> A

    9x  TYA       STA a,Y        TXS            A&X-->S
                                                S&hea+1
                                                --> a,Y

    Ax  TAY       LDA #v         TAX            LDA #v
                                                TAX

    Bx  CLV       LDA a,Y        TSX            a,Y & S
                                                -->AXS

    Cx  INY       CMP #v         DEX            A&X-#v
                                                --> X

    Dx  CLD       CMP a,Y        nop            DEC a,Y
                                                CMP a,Y

    Ex  INX       SBC #v         NOP            SBC #v

    Fx  SED       SBC a,Y        nop            INC a,Y
                                                SBC a,Y

        xC        xD             xE             xF
    -----------------------------------------------------------
    0x  nop3      ORA a          ASL a          ASL a
                                                ORA a

    1x  nop3      ORA a,X        ASL a,X        ASL a,X
                                                ORA a,X

    2x  BIT a     AND a          ROL a          ROL a
                                                AND a

    3x  nop3      AND a,X        ROL a,X        ROL a,X
                                                AND a,X

    4x  JMP a     EOR a          LSR a          LSR a
                                                EOR a

    5x  nop3      EOR a,X        LSR a,X        LSR a,X
                                                EOR a,X

    6x  JMP (a)   ADC a          ROR a          ROR a
                                                ADC a

    7x  nop3      ADC a,X        ROR a,X        ROR a,X
                                                ADC a,X

    8x  STY a     STA a          STX a          A&X
                                                --> a

    9x  nop3      STA a,X        X&hea+1        A&X
                                 --> a,Y        --> a,X

    Ax  LDY a     LDA a          LDX a          LDX a
                                                LDA a

    Bx  LDY a,X   LDA a,X        LDX a,Y        LDX a,Y
                                                LDA a,Y

    Cx  CPY a     CMP a          DEC a          DEC a
                                                CMP a

    Dx  nop3      CMP a,X        DEC a,X        DEC a,X
                                                CMP a,X

    Ex  CPX a     SBC a          INC a          INC a
                                                SBC a

    Fx  nop3      SBC a,X        INC a,X        INC a,X
                                                SBC a,X

Key to the instruction table
    A     A-register (Accumulator)
    S     S-register (Stack Pointer)
    X     X-register
    Y     Y-register

    a     2-byte absolute address
    r     1-byte relative address
    v     1-byte immediate value
    z     1-byte pagezero address

    -->   "result is stored in"
    hea   high-byte of effective address
          93:  the byte at z+1
          9B:  3rd byte of instruction
          9E:  3rd byte of instruction

    &     and-function (logical product)

    hang  computer hangs up, only way to
          regain control is to hit RESET

    nop   1-byte instruction, no operation
    nop2  2-byte instruction, no operation
    nop3  3-byte instruction, no operation

EDITASM & COPY on the Language Card | Chuck Welman

I wanted to combine the EDITASM code by Mike Laumer and Lee Meador's COPY command. But to do so I really needed the extra memory available in the RAM card. Here is how I did it.

Assembler Modifications:

1) Address $101C, which originally held a JSR $1F80, now does a JSR $24CC, whee Bank #1 of the language card is turned on with a "dummy" LDY $C088, then the JSR $1F80 is performed and finally a RTS returns control to $101F where the initialization routine continues.

2) Address $1063 (modified from "b.EDIT2") does a JMP $24D3, where the subroutines "NEW.NML" and "MY.NM>" from "B.EDIT2" now reside.

3) Address $1079 does a JMP now instead of a JSR (no change from "B.EDIT2")

4) Address $1125 is now a RTS (no change from "B.EDIT2") I added the two NOPs at $1126 and $1127, because I don't like to leave "strange" code dangling.

5) Address $1246 now contains COPy instead of LOAd as a command and its associated address directs it to $d000, 1 byte before the COPY routine at $D001. The reason that COPY doesn't start at $D000 is obscure and warrants an explanation. If it were to start at $D000, the command table address would be $CFFF, the mere referencing of which is a signal to the APPLE II its peripheral cards! If an 80-column card were in use, for example, it could be turned off each time you tried to do a COPY!

6) Address $126E (incorrectly identified as $2746 in Lee Meador's article, AAL 1/81), now contains EDIt instead of SAVe. It points to $D13B, 1 byte before the EDITASM routine at $D13C. Thanks, Lee, for the terrific idea!

7) Addresses $24D3-$24E3 now contain code which resided at $0824-$0834 in "B.EDIT2".

8) Addresses $24E4-$24EA now contain code which resided at $0835-$083B in "B.EDIT2".

9) I changed Mike Laumer's <ctrl E> to <ctrl N>, to match Neil Konzen's PLE convention.

10) I also wanted an "instant recall" feature for the "last line edited". Typing EDIT without any argument works exactly as described by Mike, UNTIL a line has been edited. Then typing EDIT will cause that last edited line to be re-displayed. It doesn't "forget" that line # until a new line # is used as an EDIt argument.

SO...I have both COPY and EDIT capability, with all of the normal RAM space still available for assembled code! There's plenty of space left on the language card for future expansion (although there's only about $10 bytes unused in the $24EB area!). Well aren't you excited? I sure was! - what are you waiting for? Get coding!!

B.EDIT2 Modifications:

1) Change the following lines:

         1060       .OR $D13C
         1070       .TF EDITASM A$D13C       Please use this name!

2) Delete lines 1360-1700

3) Add the following lines:

          1360 NEW.NML .EQ $24D3
          1370 MY.NML  .EQ $24D9
          1380 NEXT    .EQ $D4E4,$D4E5
          1390 END     .EQ $24E6,$24E7
          1400 CHAR    .EQ $24E8
          1410 EDPTR   .EQ $24E9
          1420 FKEY    .EQ $24EA

4) If you want EDIT to provide "instant recall," change line 1740:

          1740         BMI .4       YES, .4 !

5) If you want <ctrl N> as "go to end of line command", change line 4330:

          4330         .DA #$8E, E.END-1

6) SAVE EDITASM.SOURCE (or any name)

7) ASM the code

COPY Modifications:

1) Add the following lines:

          1292        .OR $D001
          1294        .TF BMC A$D001    Please use this name!

2) SAVE BLOCK MOVE/COPY.SOURCE (or any name)

3) ASM the code

Now...key in "Modifier EXEC Maker" below. If you have an APPLE II Plus, delete lines 40, 45, and 50. SAVE it, then RUN it to create the textfile "ASMDISK 4.0 MODIFIER". Now EXEC the file which will do all the hard work! I have my "Hello" program do the EXECuting! Good luck!

Program to make a file "ASMDISK 4.0 MODIFIER":

    1 REM THIS PROGRAM MAKES A FILE
    2 REM 'ASMDISK 4.0 MODIFIER'
    3 REM WHICH IS THEN EXECUTABLE
    4 REM    CREATED 1/10/81
    5 REM          BY
    6 REM     C. J. WELMAN
    7 REM  SANTA ANA CA 92707
    10 D$ = CHR$(4)
    20 PRINT D$;"OPEN ASMDISK 4.0 MODIFIER"
    30 PRINT D$;"WRITE ASMDISK 4.0 MODIFIER"
    40 REM GET INTO MAIN BOARD ROM--OTHERWISE ASSEMBLER
    45 REM   BOMBS WHEN CALLED
    50 PRINT "INT"
    60 REM TURN ON 'MON' TO SEE ACTION
    70 PRINT "MON C,I,O"
    80 REM BLOAD THE ASSEMBLER
    90 PRINT "BLOAD ASMDISK 4.0"
    100 REM GET INTO THE MONITOR
    110 PRINT "CALL-151"
    120 REM UNLOCK BANK 1 OF LANG CARD
    130 PRINT "C089"
    140 PRINT "C089"
    150 REM BLOAD BLOCK MOVE & COPY
    160 PRINT "BLOAD BMC A$D001,A$D001"
    170 REM BLOAD EDITASM
    180 PRINT "BLOAD EDITASM A$D13C,A$DI3C"
    190 REM WRITE PROTECT LANG CARD
    200 PRINT "C08A"
    210 REM ADD ROUTINE TO TURN ON BANK 1 OF LANGUAGE
    215 REM   CARD EACH TIME $1010 IS CALLED
    220 PRINT "101C:20 CC 24"
    230 PRINT "24CC:AC 88 C0 20 80 1F 60"
    240 REM MODIFY ASSEMBLER TO ADD 'NEW.NML'/'MY.NML'
    242 REM   ROUTINES & LOCAL VARIABLES FROM 'B.EDIT2'
    244 REM   (NOT LOCATED THERE ANY MORE)
    250 PRINT "24D3:20 D9 24 4C 26 10 A0 00 20 8D 12 20 4A 11"
    260 PRINT "24E1:4C 66 10 00 00 00 00 00 00 00"
    270 REM PATCH ASSEMBLER 'NML' SECTION
    280 PRINT "1063:4C D3 24"
    290 PRINT "1078:4C"
    300 PRINT "1125:60 EA EA"
    310 REM MODIFY ASSEMBLER COMMAND TABLE TO REPLACE
    315 REM   'LOAD' WITH 'COPY' & 'SAVE' WITH 'EDIT'
    320 PRINT "1246:43 4F 50 00 D0"
    330 PRINT "126E:45 44 49 3B D1"
    340 REM MODIFY ASSEMBLER TO ADD '.DA WITH COMMA"
    350 PRINT "20D4:4C B0 24"
    360 PRINT "20D7:4C C7 24"
    370 PRINT "20DA:4C B5 24"
    380 PRINT "24B0:A5 DB 20 FA 19 A5 DC 20 FA 19 20 8B 12 C9 2C"
    390 PRINT "24BF:F0 03 4C 8E 18 4C B5 20 A5 DB 18 90 EB"
    400 REM PATCH 'PRT' VECTOR TO POINT TO SYMBOL TABLE AT $1E4E
    410 PRINT "1009:4C 4E 1E"
    420 REM TURN OF 'MON' NOW
    430 PRINT "NOMON C,I,O"
    440 REM JUMP TO ASSEMBLER
    450 PRINT "1000G"
    460 PRINT D$;"CLOSE ASMDISK 4.0 MODIFIER"

Here is my HELLO program:

    10 D$ = "": REM   BLIND <CTRL-D>
    20 TEXT : CALL - 936
    30 PRINT "S-C ASSEMBLER II      VERSION 4.0"
    40 PRINT "---------------------------------"
    50 PRINT "S-C SOFTWARE    COPYRIGHT 7--9-80"
    60 VTAB 4
    70 PRINT D$;"EXEC ASMDISK 4.0 MODIFIER"
    80 END

Commented Listing of DOS 3.2.1 RWTS | Bob Sander-Cederlof

I promised in the original AAL flyer that I would print dis-assemblies of things like DOS. Here is the first installment. RWTS is described in some detail in the DOS Reference Manual, pages 94-98.

There are not too many differences between the various versions of RWTS. Each one, from 3.1 to 3.2 to 3.2.1 to 3.3, seems mainly to clean up errors of the previous ones. I will probably print some DOS 3.3 listings in the future, as well as more of 3.2.1.

There is a bug in the 3.2.1 version (a bad address), at line 2200. It works anyway, but it is sloppy. Another problem I have discovered the hard way: the "previous slot #" in the IOB should be a slot that has a disk controller in it. If not, RWTS may do strange things to whatever is in that slot. I put in "0", and it turned on my language card! Zap! No more Applesoft!

     1000  *      .LIF
     1010  *---------------------------------
     1020  *      DOS 3.2.1 DISASSEMBLY $BD00-BE9F
     1030  *      BOB SANDER-CEDERLOF       3-3-81
     1040  *---------------------------------
     1050  CURRENT.TRACK       .EQ $478
     1060  DRIVE.1.TRACK       .EQ $478 THRU 47F (INDEX BY SLOT)
     1070  DRIVE.2.TRACK       .EQ $4F8 THRU 4FF (INDEX BY SLOT)
     1080  SEARCH.COUNT        .EQ $4F8
     1090  RETRY.COUNT         .EQ $578
     1100  SLOT                .EQ $5F8
     1110  SEEK.COUNT          .EQ $6F8
     1120  *---------------------------------
     1130  PHASE.OFF           .EQ $C080
     1140  PHASE.ON            .EQ $C081
     1150  MOTOR.OFF           .EQ $C088
     1160  MOTOR.ON            .EQ $C089
     1170  ENABLE.DRIVE.1      .EQ $C08A
     1180  ENABLE.DRIVE.2      .EQ $C08B
     1190  Q6L                 .EQ $C08C
     1200  Q6H                 .EQ $C08D
     1210  Q7L                 .EQ $C08E
     1220  Q7H                 .EQ $C08F
     1230  *---------------------------------
     1240  SECTOR     .EQ $2D
     1250  TRACK      .EQ $2E
     1260  VOLUME     .EQ $2F
     1270  DRIVE.NO   .EQ $35
     1280  DCT.PNTR   .EQ $3C,3D
     1290  BUF.PNTR   .EQ $3E,3F
     1300  MOTOR.TIME .EQ $46,47
     1310  IOB.PNTR   .EQ $48,49
     1320  *---------------------------------
     1330  PRE.NYBBLE          .EQ $B800
     1340  WRITE.SECTOR        .EQ $B86A
     1350  READ.SECTOR         .EQ $B8FD
     1360  READ.ADDRESS        .EQ $B965
     1370  POST.NYBBLE         .EQ $B9C1
     1380  SEEK.TRACK.ABSOLUTE .EQ $BA1E
     1390  *---------------------------------
     1400  ERR.WRITE.PROTECT   .EQ $10
     1410  ERR.WRONG.VOLUME    .EQ $20
     1420  ERR.BAD.DRIVE       .EQ $40
     1430  *---------------------------------
     1440         .OR $BD00
     1450         .TA $800
     1460  *---------------------------------
     1470  RWTS   STY IOB.PNTR SAVE ADDRESS OF IOB
     1480         STA IOB.PNTR+1
     1490         LDY #2
     1500         STY SEEK.COUNT  UP TO 2 RE-CALIBRATIONS
     1510         LDY #4
     1520         STY SEARCH.COUNT
     1530         LDY #1       POINT AT SLOT# IN IOB
     1540         LDA (IOB.PNTR),Y  SLOT# FOR THIS OPERATION
     1550         TAX
     1560         LDY #15      POINT AT PREVIOUS SLOT#
     1570         CMP (IOB.PNTR),Y  SAME SLOT?
     1580         BEQ .3       YES
     1590         TXA          SAVE NEW SLOT ON STACK
     1600         PHA
     1610         LDA (IOB.PNTR),Y  GET OLD SLOT#
     1620         TAX
     1630         PLA          STORE NEW SLOT #
     1640         PHA          INTO OLD SLOT# SPOT
     1650         STA (IOB.PNTR),Y
     1660  *---------------------------------
     1670  *      SEE IF OLD MOTOR STILL SPINNING
     1680  *---------------------------------
     1690         LDA Q7L,X    GO INTO READ MODE
     1700  .1     LDY #8       IF DATA DOES NOT CHANGE
     1710         LDA Q6L,X       FOR 96 MICROSECONDS,
     1720  .2     CMP Q6L,X       THEN THE DRIVE IS STOPPED
     1730         BNE .1       WOOPS! IT CHANGED!
     1740         DEY          TIME UP YET?
     1750         BNE .2       NO, KEEP CHECKING
     1760         PLA          GET NEW SLOT # AGAIN
     1770         TAX
     1780  *---------------------------------
     1790  .3     LDA Q7L,X    SET UP TO READ
     1800         LDA Q6L,X
     1810         LDA Q6L,X    GET CURRENT DATA
     1820         PHA          7 CYCLE DELAY
     1830         PLA
     1840         STX SLOT
     1850         CMP Q6L,X    SEE IF DATA CHANGED
     1860         PHP          SAVE ANSWER ON STACK
     1870         LDA MOTOR.ON,X   TURN ON MOTOR
     1880         LDY #6       COPY POINTERS INTO PAGE ZERO
     1890  .4     LDA (IOB.PNTR),Y
     1900         STA DCT.PNTR-6,Y
     1910         INY          DCT.PNTR .EQ $3C,3D
     1920         CPY #10      BUF.PNTR .EQ $3E,3F
     1930         BNE .4
     1940         LDY #3       GET MOTOR ON TIME FROM DCT
     1950         LDA (DCT.PNTR),Y
     1960         STA MOTOR.TIME+1  HIGH BYTE ONLY
     1970         LDY #2       GET DRIVE #
     1980         LDA (IOB.PNTR),Y
     1990         LDY #16      SEE IF SAME AS OLD DRIVE#
     2000         CMP (IOB.PNTR),Y
     2010         BEQ .5       YES
     2020         STA (IOB.PNTR),Y  UPDATE OLD DRIVE #
     2030         PLP          SET Z STATUS
     2040         LDY #0       TO FLAG MOTOR OFF
     2050         PHP
     2060  .5     ROR          CHECK LSB OF DRIVE #
     2070         BCC .6       DRIVE 2
     2080         LDA ENABLE.DRIVE.1,X
     2090         BCS .7       ...ALWAYS
     2100  .6     LDA ENABLE.DRIVE.2,X
     2110  .7     ROR DRIVE.NO SET SIGN BIT IF DRIVE 1
     2120         PLP          WAS MOTOR PROBABLY OFF?
     2130         PHP
     2140         BNE .9       NO, DEFINITELY ON
     2150  *---------------------------------
     2160  *      DELAY FROM 150 TO 180 MILLISECONDS,
     2170  *      DEPENDING ON WHAT GARBAGE IS IN A-REG
     2180  *---------------------------------
     2190         LDY #7       YES, WAIT A WHILE
     2200  .8     JSR $BA7F    ***BUG!!!*** SHOULD BE $BA7B
     2210         DEY          BUT IT WORKS ANYWAY....
     2220         BNE .8
     2230         LDX SLOT     RESTORE SLOT#
     2240  *---------------------------------
     2250  .9     LDY #4       GET TRACK #
     2260         LDA (IOB.PNTR),Y
     2270         JSR SEEK.TRACK
     2280         PLP          WAS MOTOR DEFINITELY ON?
     2290         BNE PROCESS.COMMAND  YES, MOTOR ON
     2300  *---------------------------------
     2310  *      MOTOR WAS OFF, SO WAIT REST OF MOTOR ON TIME
     2320  *      FOR APPLE DISK II, MOTOR ON TIME IS 1 SECOND.
     2330  *      PART OF THIS TIME IS COUNTED DOWN WHILE SEEKING
     2340  *      FOR THE TRACK.
     2350  *---------------------------------
     2360  .10    LDY #18      ABOUT 100 MICROSECONDS PER TRIP
     2370  .11    DEY
     2380         BNE .11
     2390         INC MOTOR.TIME
     2400         BNE .10
     2410         INC MOTOR.TIME+1
     2420         BNE .10
     2430  *---------------------------------
     2440  *      MOTOR ON AND UP TO SPEED, SO LET'S
     2450  *      FIND OUT WHAT THE COMMAND IS AND DO IT!
     2460  *---------------------------------
     2470  PROCESS.COMMAND
     2480         LDY #12      GET COMMAND
     2490         LDA (IOB.PNTR),Y
     2500         BEQ .8       NULL COMMAND, LET'S LEAVE
     2510         CMP #4       FORMAT?
     2520         BEQ .9       YES
     2530         ROR          SET CARRY=1 IF READ, =0 IF WRITE
     2540         PHP          SAVE ON STACK
     2550         BCS .1       READ
     2560         JSR PRE.NYBBLE  WRITE
     2570  .1     LDY #48      UP TO 48 RETRIES
     2580         STY RETRY.COUNT
     2590  .2     LDX SLOT     GET SLOT NUMBER AGAIN
     2600         JSR READ.ADDRESS
     2610         BCC .5       GOOD ADDRESS READ
     2620  .21    DEC RETRY.COUNT
     2630         BPL .2       KEEP TRYING
     2640  .3     LDA CURRENT.TRACK  GET TRACK WE WANTED
     2650         PHA          SAVE IT
     2660         LDA #96      PRETEND TO BE ON TRACK 96
     2670         JSR SETUP.TRACK
     2680         DEC SEEK.COUNT
     2690         BEQ .6       NO MORE RE-CALIBRATES
     2700         LDA #4
     2710         STA SEARCH.COUNT
     2720         LDA #0       LOOK FOR TRACK 0
     2730         JSR SEEK.TRACK
     2740         PLA          GET TRACK WE REALLY WANT
     2750  .4     JSR SEEK.TRACK
     2760         JMP .1
     2770  *---------------------------------
     2780  .5     LDY $2E      TRACK# IN ADDRESS HEADER
     2790         CPY CURRENT.TRACK
     2800         BEQ .10      FOUND RIGHT TRACK
     2810         LDA CURRENT.TRACK
     2820         PHA          SAVE TRACK WE REALLY WANT
     2830         TYA          SET UP TRACK WE ACTUALLY FOUNG
     2840         JSR SETUP.TRACK
     2850         PLA          TRACK WE WANT
     2860         DEC SEARCH.COUNT
     2870         BNE .4       TRY AGAIN
     2880         BEQ .3       TRY TO RE-CALIBRATE AGAIN
     2890  *---------------------------------
     2900  *      DRIVE ERROR, CANNOT FIND TRACK
     2910  *---------------------------------
     2920  .6     PLA          REMOVE CURRENT.TRACK
     2930         LDA #ERR.BAD.DRIVE
     2940  .7     PLP
     2950         JMP ERROR.HANDLER
     2960  *---------------------------------
     2970  *      NULL COMMAND, ON THE WAY OUT....
     2980  *---------------------------------
     2990  .8     BEQ RWTS.EXIT
     3000  *---------------------------------
     3010  *      FORMAT COMMAND
     3020  *---------------------------------
     3030  .9     LDY #3       GET VOLUME# WANTED
     3040         LDA (IOB.PNTR),Y
     3050         STA VOLUME   SET IN PLACE AND GO FORMAT
     3060         JMP FORMAT
     3070  *---------------------------------
     3080  *      READ OR WRITE COMMAND
     3090  *---------------------------------
     3100  .10    LDY #3       GET VOLUME# WANTED
     3110         LDA (IOB.PNTR),Y
     3120         PHA          SAVE DESIRED VOLUME# ON STACK
     3130         LDA VOLUME
     3140         LDY #14      STORE ACTUAL VOLUME NUMBER FOUND
     3150         STA (IOB.PNTR),Y
     3160         PLA          GET DESIRED VOLUME# AGAIN
     3170         BEQ .11      IF =0, DON'T CARE
     3180         CMP VOLUME   SEE IF RIGHT VOLUME
     3190         BEQ .11      YES
     3200         LDA #ERR.WRONG.VOLUME
     3210         BNE .7       UH OH!
     3220  *---------------------------------
     3230  .11    LDY #5       GET SECTOR# WANTED
     3240         LDA SECTOR   AND THE ONE WE FOUND
     3250         CMP (IOB.PNTR),Y   AND COMPARE THEM.
     3260         BNE .21      NOT THE RIGHT SECTOR
     3270         PLP          GET COMMAND FLAG AGAIN
     3280         BCC WRITE
     3290         JSR READ.SECTOR
     3300         PHP          SAVE RESULT; IF BAD, WILL BE COMMAND
     3310         BCS .21      BAD READ
     3320         PLP          THROW AWAY
     3330         JSR POST.NYBBLE
     3340         LDX SLOT
     3350  RWTS.EXIT
     3360         CLC
     3370         .HS 24       "BIT" TO SKIP NEXT INSTRUCTION
     3380  *---------------------------------
     3390  ERROR.HANDLER
     3400         SEC          INDICATE AN ERROR
     3410         LDY #13      STORE ERROR CODE
     3420         STA (IOB.PNTR),Y
     3430         LDA MOTOR.OFF,X
     3440         RTS
     3450  *---------------------------------
     3460  WRITE  JSR WRITE.SECTOR
     3470         BCC RWTS.EXIT
     3480         LDA #ERR.WRITE.PROTECT
     3490         BCS ERROR.HANDLER   ...ALWAYS
     3500  *---------------------------------
     3510  *      SEEK TRACK SUBROUTINE
     3520  *      (A) = TRACK# TO SEEK
     3530  *      (DRIVE.NO) IS NEGATIVE IF DRIVE 1
     3540  *                AND POSITIVE IF DRIVE 2
     3550  *---------------------------------
     3560  SEEK.TRACK
     3570         PHA          SAVE TRACK#
     3580         LDY #1       CHECK DEVICE CHARACTERISTICS TABLE
     3590         LDA (DCT.PNTR),Y   FOR TYPE OF DISK
     3600         ROR          SET CARRY IF TWO PHASES PER TRACK
     3610         PLA          GET TRACK# AGAIN
     3620         BCC .1       ONE PHASE PER TRACK
     3630         ASL          TWO PHASES PER TRACK, SO DOUBLE IT
     3640         JSR .1       FIND THE TRACK
     3650         LSR CURRENT.TRACK  DIVIDE IT BACK DOWN
     3660         RTS
     3670  *---------------------------------
     3680  .1     STA TRACK
     3690         JSR GET.SLOT.IN.Y
     3700         LDA DRIVE.1.TRACK,Y
     3710         BIT DRIVE.NO   WHICH DRIVE?
     3720         BMI .2       DRIVE 1
     3730         LDA DRIVE.2.TRACK,Y
     3740  .2     STA CURRENT.TRACK   WHERE WE ARE RIGHT NOW
     3750         LDA TRACK    WHERE WE WANT TO BE
     3760         BIT DRIVE.NO WHICH DRIVE?
     3770         BMI .3       DRIVE 1
     3780         STA DRIVE.2.TRACK,Y   DRIVE 2
     3790         BPL .4       ...ALWAYS
     3800  .3     STA DRIVE.1.TRACK,Y
     3810  .4     JMP SEEK.TRACK.ABSOLUTE
     3820  *---------------------------------
     3830  *      CONVERT SLOT*16 TO SLOT IN Y-REG
     3840  *---------------------------------
     3850  GET.SLOT.IN.Y
     3860         TXA          SLOT*16 FROM X-REG
     3870         LSR
     3880         LSR
     3890         LSR
     3900         LSR
     3910         TAY          SLOT INTO Y
     3920         RTS
     3930  *---------------------------------
     3940  *      SET UP CURRENT TRACK LOCATION
     3950  *      IN DRIVE.1.TRACK OR DRIVE.2.TRACK VECTORS,
     3960  *      INDEXED BY SLOT NUMBER.
     3970  *
     3980  *      (A) = TRACK# TO BE SET UP
     3990  *---------------------------------
     4000  SETUP.TRACK
     4010         PHA          SAVE TRACK # WE WANT TO SET UP
     4020         LDY #2       GET DRIVE NUMBER FROM IOB
     4030         LDA (IOB.PNTR),Y
     4040         ROR          SET CARRY IF DRIVE 1, CLEAR IF 2
     4050         ROR DRIVE.NO MAKE NEGATIVE IF 1, POSITIVE IF 2
     4060         JSR GET.SLOT.IN.Y
     4070         PLA          GET TRACK #
     4080         ASL          DOUBLE IT
     4090         BIT DRIVE.NO  WHICH DRIVE?
     4100         BMI .1       DRIVE 1
     4110         STA DRIVE.2.TRACK,Y
     4120         BPL .2       ...ALWAYS
     4130  .1     STA DRIVE.1.TRACK,Y
     4140  .2     RTS
     4150  *---------------------------------
     4160  FORMAT

& Command Interface for S-C Assembler II | Bob Sander-Cederlof

Here is yet another way to add new commands to Version 4.0. You are somewhat familiar with the use of the & in Applesoft. This little program patches the assembler so that you can add as many new commands as you wish.

I have shown as examples the EDIT, COPY, and SYM commands. You need to fill in the correct starting address in lines 1250 and 1260.

Use the .TF directive to direct the object code to a file. Then use BRUN to install the patch. Lines 1100-1120 patch the assembler to hook in the code at lines 3010-3100. After it is hooked in, make a new copy of the assembler by using BSAVE ASMDISK 4.0 WITH &,A$FD7,L$.... (Fill in the appropriate length, depending on what else you have added to the assembler in the past.)

     1000  *---------------------------------
     1010  *      & COMMAND INTERFACE
     1020  *
     1030  *      &<COMMAND STRING>
     1040  *
     1050  *---------------------------------
     1060  *
     1070  *      ORIGIN MUST BE SET SO THAT LAST BYTE
     1080  *      IS AT $0FFF.
     1085         .OR $FD1
     1090  *---------------------------------
     1100         LDA #AMPERSAND.INTERFACE-$103D
     1110         STA $103C
     1120         RTS
     1130  *---------------------------------
     1140         JMP $1000
     1150  *---------------------------------
     1160  AOPTBL .HS 0503
     1170         .AS /EDI/
     1180         .DA EDIT-1
     1190         .AS /COP/
     1200         .DA COPY-1
     1210         .AS /SYM/
     1220         .DA STPRNT-1
     1230         .HS 00       END OF TABLE
     1240  *---------------------------------
     1250  EDIT   .EQ $1010
     1260  COPY   .EQ $1010
     1270  STPRNT .EQ $1E4E
     3000  *---------------------------------
     3010  AMPERSAND.INTERFACE
     3020         CMP #'&
     3030         BEQ .1
     3040         JMP $1063
     3050  .1     LDA #AOPTBL
     3060         STA $02
     3070         LDA /AOPTBL
     3080         STA $03
     3090         LDA #1
     3100         JMP $1047

Apple Assembly Line is published monthly by S-C SOFTWARE, P. O. Box 5537, Richardson, TX 75080. Subscription rate is $12/year, in the U.S.A., Canada, and Mexico. Other countries add $6/year for extra postage. All material herein is copyrighted by S-C SOFTWARE, all rights reserved. Unless otherwise indicated, all material herein is authored by Bob Sander-Cederlof. (Apple is a registered trademark of Apple Computer, Inc.)