Apple Assembly   Line
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...

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.ETo dump memory from S to E on the screen.
S-ETo dump memory from S to E on the printer.
S,ETo 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.
STo 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.)