Apple Assembly Line
Volume 3 -- Issue 10July 1983

In This Issue...

Latest 65C02 Word

The 65C02 really does exist, and we now have a couple of them. As reported inside, the chips we received work in an Apple //e, but not in a ][+. Well that seems to be a problem with the NCR chips that I have. Don Lancaster reports that his GTE chips work just fine in all flavors of Apples. I'm swapping an NCR processor for one of his GTE's, and will have more details next month. For the time being, if you buy a 65C02, be sure to get a guarantee that it will work in your Apple.


6502 Mini-Assembler in ApplesoftBob Sander-Cederlof

The original Apple II came with a built-in mini-assembler. By typing "F666G" in the monitor, you entered a new realm. The prompt changed from "*" to "!"; errors not only earned a "beep" but also a printed "?"; and monitor commands were still available by typing an initial "$". I learned 6502 programming using this little tool, together with the handy "L" disassembly command. At the time, none of the other computer systems on the market came with either mini-assembler or "L" command.

A mini-assembler allows you to type in mnemonics rather than converting them "by hand". It also will translate branch addresses to the relative offsets needed in relative branch instructions. It will not retain the source code on a file, and will not handle labels. If you want to modify a program, you have to use patches or retype the whole thing. A full assembler will accept labels and comments, and will have some method for working with stored source programs. The S-C Macro Assembler, for example, includes a co-resident source program editor. The extra features a full assembler can include are limited only by the potential market. But mini-assemblers are free.

A long time ago MICRO published a 6502 mini-assembler written in Commodore or OSI BASIC. I started converting it, just for fun, into Applesoft. It wasn't long before I realized that my thought processes were totally incompatible with the author's programming techniques. So I essentially started over. Last month the partially finished listing appeared out of some long forgotten crack, so I dusted it off and finished the program.

It operates a lot like the old "F666G" mini-assembler by Steve Wozniak. (And, even though it is in Applesoft, it is almost as fast.) The initial display is the address "0300" at the left margin, and the cursor in column 20 of the top line on an otherwise empty screen. You can type RETURN to quit, a colon followed by a hex address to change the assembly address, or an instruction mnemonic to be assembled.

I could go into a long-winded explanation of how the program works, describing each subroutine. But you can probably read the listing easily enough, and there are identifying REM statements with each subroutine. The really interesting part to me is the structure of the opcode tables which are contained as strings in OP$, F$, and E$. These tables are set up in lines 2030 through 2050.

OP$ contains the opcodes names. OP$(1) holds the names of all the single byte opcodes. If the input line has no operand data after the opcode mnemonic, the program will search through OP$(1) and had better find your mnemonic. If not, it is "???" for you! Note that the opcode names are three characters each, packed into one long string. Also note that ASL, LSR, ROL, and ROR appear in this string. These four opcodes can have an operand-less mode, as well as any of four modes with operands.

OP$(2) contains the mnemonics for the relative branches. OP$(3) holds "JMP" and "JSR". And OP$(4) holds all the rest, which I call the complex opcodes. These are the ones which can have a variety of addressing modes.

F$(1) through F$(4) correspond to OP$(1) through OP$(4). Each three digit group in one of the F$ strings is the opcode value (in decimal) for the corresponding mnemonic from OP$. F$(4) contains a base value, which will be augmented to obtain a specific value for the particular address mode chosen.

The complex opcodes can be classified in many different ways...I tried so many I lost count. I finally settled on the scheme shown in the two tables below:

          Imm Zp  Abs Z,X A,X Z,Y A,Y (X) ()Y
       +  08  04  0C  14  1C  --  18  00  10    Base
------------------------------------------------------
ADC    0  69  65  6D  75  7D  --  79  61  71   61  097
AND    0  29  25  2D  35  3D  --  39  21  31   21  033
CMP    0  C9  C5  CD  D5  DD  --  D9  C1  D1   C1  193
EOR    0  49  45  4D  55  5D  --  59  41  51   41  065
LDA    0  A9  A5  AD  B5  BD  --  B9  A1  B1   A1  161
ORA    0  09  05  0D  15  1D  --  19  01  11   01  001
SBC    0  E9  E5  ED  F5  FD  --  F9  E1  F1   E1  225

STA    1  --  85  8D  95  9D  --  99  81  91   81  129

          Imm Zp  Abs Z,X A,X Z,Y A,Y (X) ()Y
       +  00  04  0C  14  1C  14  1C  --  --    Base
------------------------------------------------------
ASL    2  --  06  0E  16  1E  --  --  --  --   02  002
LSR    2  --  46  4E  56  5E  --  --  --  --   42  066
ROL    2  --  26  2E  36  3E  --  --  --  --   22  034
ROR    2  --  66  6E  76  7E  --  --  --  --   62  098

BIT    3  --  24  2C  --  --  --  --  --  --   20  032

CPX    4  E0  E4  EC  --  --  --  --  --  --   E0  224
CPY    4  C0  C4  CC  --  --  --  --  --  --   C0  192

DEC    5  --  C6  CE  D6  DE  --  --  --  --   C2  194
INC    5  --  E6  EE  F6  FE  --  --  --  --   E2  226

LDX    6  A2  A6  AE  --  --  B6  BE  --  --   A2  162

LDY    7  A0  A4  AC  B4  BC  --  --  --  --   A0  160

STX    8  --  86  8E  --  --  96  --  --  --   82  130

STY    9  --  84  8C  94  --  --  --  --  --   80  128

The first column of numbers is the opcode class number. These numbers are stored in E$ (see line 2050). The next nine columns show the hex opcode values for each valid combination of opcode and address mode. The last two columns show the "base" value in both hex and decimal.

The top row of numbers (above the dashed lines) shows the augment needed to transform a "base" opcode value into the value for a specific address mode. I broke the data into two separate tables because the Imm and A,Y columns have one pair of values for class 0 and 1 opcodes and another for classes 2 through 9. The class number is used to select which address modes are legal for a given opcode, as well as in selecting the augment values.

If you have ever studied the listing of Wozniak's mini- assembler, you know that his approach was entirely different. If you look inside the S-C Macro Assembler you will find yet another approach. I suppose there are more approaches than existing assemblers. In our line of Cross Assemblers we use about five or six different techniques. The choice depends on the syntax of the operands and the bit structure of the opcodes, as well as whim.

I have also written a disassembler in Applesoft, and the beginnings of a simulator for 6502 code. Maybe they will see print in the near future. There is a lot to be learned from studying or even writing these kinds of programs, and they can even be useful.

     100  GOTO 2000: REM  MINI-ASSEMBLER FOR APPLE
     110  REM ---------------------------------
     120  REM PRINT BYTE M AS TWO HEX DIGITS
     130 M1 =  INT (M / 16):M2 = M - M1 * 16: HTAB Z:Z = Z + 2: PRINT 
           MID$ (G$,M1 + 1,1); MID$ (G$,M2 + 1,1);: RETURN 
     140  REM ---------------------------------
     150  REM POKE AND PRINT OBJECT BYTE
     160 Z = Z + 1: GOSUB 110: POKE AD,M:AD = AD + 1: RETURN 
     170  REM ---------------------------------
     180  REM SET UP TWO-BYTE ADDRESS FIELD
     190 HI =  INT (X / 256):LO = X - 256 * HI
     200  REM ---------------------------------
     210  REM OUTPUT THE OPCODE AND ADDRESS
     220 Z = 7: VTAB  PEEK (37):M = OP: GOSUB 160:M = LO: GOSUB 160: IF 
          BY = 3 THEN M = HI: GOSUB 160
     225  GOTO 1000
     230  REM ---------------------------------
     240  REM OUTPUT SINGLE-BYTE OPCODES
     250 Z = 7: VTAB  PEEK (37):M = OP: GOSUB 160: GOTO 1000
     260  REM ----------------------------------
     270  REM PRINT NEXT ADDRESS
     280 Z = 1: CALL  - 868:M =  INT (AD / 256): GOSUB 110:M = AD - M * 
          256: GOSUB 110: PRINT ":";: HTAB 20: RETURN 
     290  REM ---------------------------------
     300  REM  CONVERT C$ FROM HEX TO DECIMAL
     310 X = 0:I = 0
     320 CL$ = "": GOSUB 500: IF CC$ = "#" OR CC$ = "(" THEN CL$ = CC$
          : GOSUB 500
     325  IF C < 0 THEN CL$ = "ERR": RETURN 
     330 X = X * 16 + C: GOSUB 500: IF C >  = 0 THEN 330
     340 CL$ = CL$ + CC$: GOSUB 500: IF CC$ <  > "" THEN 340
     350  RETURN 
     500  REM --------------------------------
     510  REM GET NEXT CHAR FROM C$
     520 I = I + 1: IF I >  LEN (C$) THEN CC$ = "":C =  - 1: RETURN 
     530 CC$ =  MID$ (C$,I,1):C =  ASC (CC$) - 48: IF (C > 9 AND C < 17) 
          OR C > 22 THEN C =  - 1: RETURN 
     540 C = C - 7 * (C > 9): RETURN 
     900  REM --------------------------------
     910  VTAB  PEEK (37): HTAB 7: PRINT "???" CHR$ (7): REM    ERROR
     990  REM --------------------------------
     1000  PRINT : CALL  - 868: GOSUB 260: GOSUB 4000: IF IN$ = "" THEN  STOP 
     1010  IF  RIGHT$ (IN$,1) = ":" THEN C$ = IN$: GOSUB 290:AD = X: GOTO 1000
     1020 L =  LEN (IN$) - 3: IF L < 0 THEN 900
     1025  VTAB  PEEK (37): HTAB 6: CALL  - 868: HTAB 20:L$ =  LEFT$ (IN$,3)
           : IF L > 0 THEN  GOTO 1050
     1030 C$ = "":J = 1: PRINT L$: GOSUB 2100: IF K = 0 THEN 900
     1040  GOTO 230
     1050  REM --------------------------------
     1051  REM TRY RELATIVE BRANCHES
     1052 C$ =  RIGHT$ (IN$,L): PRINT L$" "C$: GOSUB 290: IF CL$ = "ERR"
           THEN 900
     1053 J = 2: GOSUB 2100: IF K = 0 THEN 1060
     1054  IF CL$ <  > "" THEN 900
     1056 X = X - AD - 2: IF X <  - 128 OR X > 127 THEN  PRINT "CAN'T B
           RANCH THAT FAR": GOTO 1000
     1057 BY = 2:X = X + 256 * (X < 0): GOTO 190
     1060  REM --------------------------------
     1070  REM TRY JMP AND JSR OPCODES
     1080 J = 3: GOSUB 2100: IF K = 0 THEN 1110
     1090 BY = 3: IF CL$ = "" THEN 190
     1100  IF CL$ = "()" AND OP = 76 THEN OP = 108: GOTO 190
     1105  GOTO 900
     1110  REM --------------------------------
     1115  REM TRY COMPLEX OPCODES
     1120 J = 4: GOSUB 2100: IF K = 0 THEN 900
     1130 CA =  VAL ( MID$ (E$,(K + 2) / 3,1)):BY = 2
     1140  IF CL$ = "" THEN 1600: REM  ZPORABS
     1150  IF CL$ = "#" THEN 1200: REM IMMEDIATE MODE
     1160  IF CL$ = ",X" THEN 1400: REM ZP,X OR ABS,X
     1170  IF CL$ = ",Y" THEN 1500: REM ZP,Y OR ABS,Y
     1180  IF CL$ = "(,X)" THEN 1300: REM (ZP,X)
     1190  IF CL$ = "(),Y" THEN 1350: REM (ZP),Y
     1195  GOTO 900
     1200  REM --------------------------------
     1210  REM IMMEDIATE MODE
     1220  IF X > 255 THEN 900
     1230  IF CA = 0 THEN OP = OP + 8: GOTO 190
     1240  IF CA = 4 OR CA = 6 OR CA = 7 THEN 190
     1250  GOTO 900
     1300  REM --------------------------------
     1310  REM INDIRECT MODE:  (...,X)
     1320  IF CA < 2 THEN 190
     1330  GOTO 900
     1350  REM --------------------------------
     1360  REM INDIRECT MODE:  (...),Y
     1370  IF CA < 2 THEN OP = OP + 16: GOTO 190
     1380  GOTO 900
     1400  REM --------------------------------
     1410  REM ZP,X OR ABS,X
     1420  IF X > 255 THEN 1450: REM ABS,X
     1430  IF CA < 3 OR CA = 5 OR CA = 7 OR CA = 9 THEN OP = OP + 20: GOTO 
           190
     1440  GOTO 900
     1450  IF CA < 3 OR CA = 5 OR CA = 7 THEN OP = OP + 28:BY = 3: GOTO 
           190
     1460  GOTO 900
     1500  REM --------------------------------
     1510  REM ZP,Y OR ABS,Y
     1520  IF X > 255 THEN 1540
     1530  IF CA = 6 OR CA = 8 THEN OP = OP + 20: GOTO 190
     1540 BY = 3: IF CA = 6 THEN OP = OP + 28: GOTO 190
     1550  IF CA < 2 THEN OP = OP + 24: GOTO 190
     1560  GOTO 900
     1600  REM --------------------------------
     1610  REM ZP OR ABS
     1620 OP = OP + 4: IF X > 255 THEN OP = OP + 8:BY = 3
     1630  GOTO 190
     2000  REM --------------------------------
     2010  REM INITIALIZATION
     2020  TEXT : HOME : DIM OP$(4),F$(4)
     2030 OP$(1) = "ASLBRKCLCCLDCLICLVDEXDEYINXINYLSRNOPPHAPHPPLAPLPROL
           RORRTIRTSSECSEDSEITAXTAYTSXTXATXSTYA"
     2032 OP$(2) = "BCCBCSBEQBMIBNEBPLBVCBVS"
     2034 OP$(3) = "JMPJSR"
     2035 OP$(4) = "ADCANDCMPEORLDAORASBCSTAASLLSRROLRORBITCPXCPYDECINC
           LDXLDYSTXSTY"
     2040 F$(1) = "0100000242160881842021362322000742340720081040400421
           06064096056248120170168186138154152"
     2042 F$(2) = "144176240048208016080112"
     2044 F$(3) = "076032"
     2045 F$(4) = "0970331930651610012251290020660340980322241921942261
           62160130128"
     2050 E$ = "000000012222344556789"
     2060 G$ = "0123456789ABCDEF"
     2070 AD = 768: GOTO 1000: REM END OF INITIALIZATION, START AT $030
           0
     2100  REM --------------------------------
     2110  REM SEARCH OPCODE TABLE J
     2120 K = 0: FOR I = 1 TO  LEN (OP$(J)) STEP 3: IF L$ =  MID$ (OP$(
           J),I,3) THEN K = I:I = 200:OP =  VAL ( MID$ (F$(J),K,3))
     2130  NEXT : RETURN 
     4000  REM --------------------------------
     4010  REM INPUT A LINE
     4020 IN$ = "": CALL 64879:I = 511
     4030 I = I + 1: IF I > 550 THEN  RETURN 
     4040 C =  PEEK (I) - 128: IF C = 13 THEN  RETURN 
     4050  IF C > 32 THEN IN$ = IN$ +  CHR$ (C)
     4060  IF C = 3 THEN  STOP 
     4070  GOTO 4030
     59000  PR# 1: PRINT  CHR$ (27)"B" CHR$ (27)"E" CHR$ (27)"L010": PR# 0
     60000  PR# 1: PRINT  CHR$ (9)"80N": LIST : PR# 0: CALL 1002: & : END 

Assembly Listing Into a Text FileBill Morgan

"That's not a bug, that's a feature!" We've all heard (or said?) that before, but this time it really seems to be true. We have just discovered an undocumented feature in Version 1.1 of the S-C Macro Assembler.

I was trying to see if a program would assemble, and wanted the assembly to be as fast as possible. For some reason I didn't want to do the obvious thing and just switch the listing off, and using a .TA wasn't convenient. So, I stuck a .DU (DUmmy) directive at the beginning of my program, and a .ED (End Dummy)at the end, figuring that would eliminate the time spent writing object code to the disk. When I typed ASM the assembler paused a moment for pass one, then started listing the beginning of the program. But, when the assembler got to the .TF directive the listing stopped and the disk drive started spinning. That wasn't supposed to happen!

When the assembly finished, and the drive stopped turning, I CATALOGed the disk to see what had happened. There was a Binary file, with the filename from my .TF directive, but instead of being much smaller that the source file, it was about twice as big. What could be in that file?

It seemed dangerous to just BLOAD a file that shouldn't exist, so I booted up a disk zap program and inspected the disk. That Binary file contained the text of the assembly listing, starting with the .TF line. Also, the file had no load address and length bytes. The first four bytes were "A0 A0 A0 A0", or the ASCII codes for four spaces. If I had tried to BLOAD the file, it would have loaded at $A0A0, which would have immediately clobbered DOS!

I was preparing a note to warn everybody not to use .TF within a .DU - .ED block, when Bob reminded me of how often we WANT an assembly listing on a Text file, to read into the S-C Word Processor and merge into an article. Why didn't I find out what the Word Processor would make of this file? Well, it read the file just fine, but discarded the first four bytes, since it expects load address and length bytes in a Binary file. In most cases that is no problem, since the first line is the .TF <filename> directive, and will be discarded anyway.

Now we have a Binary file containing the text. That's fine with the S-C Word Processor, but what about other programs, that might require Text files? As it happens, the Macro Assembler creates a Target File as a Text file, then updates the Catalog to turn it into a Binary file. All we have to do is patch the assembler to prevent that change in the file type. That is only a 1-byte patch.

So, all it takes to send the assembly listing to a disk file is to begin the program with a .DU and a .TF, and end it with a .ED. If you want a real Text file, you only have to patch one byte in the assembler.

To make a long story short, here's how to create a Text file containing an assembly listing:

1) At the beginning of your program, put the lines:

     0000       .DU
     0001       .TF LISTING

and at the end put:

     65535      .ED

2) If there is already another .TF directive in your program, insert a "*" at the beginning of the line, to make it into a comment.

3) Enter one of the following patches:

     $1000 Versions: $29DF:0
     $D000 Versions: $C083 C083 EAF9:0 N C080

4) Type ASM.

5) And restore the patched location:

     $1000 Versions: $29DF:4
     $D000 Versions: $C083 C083 EAF9:4 N C080

Now you can load LISTING into a word processor, delete the first and last lines, and do whatever you want with it!

I tried creating an EXEC file to do all those steps automatically, but ran into trouble. When the assembly ends the EXEC file loses control, and the Text file LISTING doesn't get closed. When I can solve that one I'll let you know.


Speeding-up Text File I/OPaul Schlyter

In the April 1983 AAL (pages 2-8), Bob Sander-Cederlof presented a small patch that I had sent him almost a year earlier. The patch greatly speeded up LOAD/BLOAD of long files. At the moment, I had recreated a lot of very long assembler source files, such as the source code to DOS and Applesoft. The long assembly times grew annoying, especially when I realized how much time was wasted inside RWTS just waiting for the right sector to pass under the R/W head of the disk drive!

Just one note about what was written on the bottom of page 2 of that issue: my patch does not influence SAVE/BSAVE at all. The read-after-write during a SAVE/BSAVE is made using the VERIFY command, and that command already works at top speed; in fact, VERIFY's speed was a major inspiration for my LOAD/BLOAD patch.

Next I tried to speed up SAVE/BSAVE with an equally simple patch. I found it was not so easy, mainly because SAVE/BSAVE might have to allocate new sectors for the file. I also felt it wasn't worth the trouble writing a more complicated patch, since SAVE/BSAVE isn't really used that often.

Next in line was a speedup of text file read and write. Here I found a great "time-hog" in DOS. The innocent-looking routines at $AE68 and $AE7E each require about 800 cycles to execute. All they do is to swap a 45-byte area back and forth between the file buffers and a local workarea inside the file manager. This is of course necessary when you open/close files or switch from file to file. But if you're reading the same text file, the swapping may not be needed. Nevertheless, file manager swaps the buffer in and out for each and every character you read or write! This amounts to 256*(800+800) = roughly 410,000 cycles or 0.4 seconds for each sector you read or write! This is about six seconds for each track! And all it does during those six seconds is needlessly swap the same 45 bytes back and forth!

The principle of my patch is this: When entering or exiting the file manager, first check to see if you're doing something else besides reading/writing. If so, just go on as usual. If you are reading/writing, check to see if the local workarea belongs to the file being read/written. If so, just exit and save 800 clock cycles. If not, check to see if it belongs to another file. If the workarea contains another file's data, put it back into the file buffer where it belongs and then get the workarea for the current file. All occurs this when you enter the file manager.

Upon exit from the file manager, if you're reading/writing, just set a flag to mark that the local workarea is being used, and save the address of the file buffer it came from. This always saves 800 cycles.

Practical tests show that text file reading/writing is done up to about 40% faster with this patch installed. This is slower than Diversi-DOS, but on the other hand this patch is compatible with S-C assemblers (and almost everything else in sight). Also, this patch works equally well for all file types; it even speeds up the loading of type-R files with RBOOT/RLOAD (from DOS Tool Kit). Diversi-DOS treats T type files in a special way, but does nothing to speed up type-R files. And mine is free!

I put the patch at $300, because there's no free area large enough inside DOS where you can put it...especially if you have already installed the LOAD/BLOAD speedup described by Bob last April. The listing which follows includes code to hook in the patches by overwriting the file manager where it calls the two workarea transfer subroutines.

  1000 *SAVE S.FAST TEXT (SCHLYTER)
  1010 *--------------------------------
  1020 *  SPEEDUP OF DOS TEXT FILE READ/WRITE
  1030 *  BY PAUL SCHLYTER, SWEDEN, MAY 1983.
  1040 *--------------------------------
  1050 PNTR   .EQ $42,43   DOS VARIABLE
  1060 *--------------------------------
  1070 GET.WRKAREA.FROM.BUFFER .EQ $AE6A
  1080 SAVE.WRKAREA.TO.BUFFER  .EQ $AE7E
  1090 SAVE.OLD.WRKAREA        .EQ $AE7E+3
  1100 POINT.TO.WRKAREA.BUFFER .EQ $AF08
  1110 FM.OPCODE               .EQ $B5BB
  1120 *--------------------------------
  1130        .OR $300
  1140        JMP INSTALL
  1150 *--------------------------------
  1160 *  PATCH EXECUTED UPON ENTRY TO FILE MANAGER:
  1170 *      1. IF READ/WRITE AND CORRECT WORK AREA, RETURN
  1180 *      2. IF WRONG WORK AREA, SAVE OLD WORK AREA
  1190 *      3. LOAD NEW WORK AREA.
  1200 *--------------------------------
  1210 PATCH1 LDA FM.OPCODE     IF NOT READ OR WRITE,
  1220        CMP #3                DO AS USUAL
  1230        BCC .1            ...LESS THAN READ/WRITE
  1240        CMP #5
  1250        BCS .1            ...HIGHER THAN READ/WRITE
  1260        JSR POINT.TO.WRKAREA.BUFFER
  1270        LDA PNTR     CHECK TO SEE IF CORRECT WORKAREA
  1280        CMP PNTR.S        ALREAD LOADED
  1290        BNE .1            NO
  1300        LDA PNTR+1
  1310        CMP PNTR.S+1
  1320        BNE .1            NO
  1330        RTS               YES, NOTHING ELSE TO DO,
  1340 *                        SO EXIT NOW AND SAVE 800 CYCLES!
  1350 *
  1360 *      OPCODE NOT READ OR WRITE, OR WRONG WORK AREA.
  1370 .1     BIT FLG      NEED TO PUT BACK THIS WORK AREA?
  1380        BPL .2       NO, JUST GET NEW ONE
  1390        CLC          YES, CLEAR FLAG
  1400        ROR FLG
  1410        LDA PNTR.S
  1420        STA PNTR
  1430        LDA PNTR.S+1
  1440        STA PNTR+1
  1450        JSR SAVE.OLD.WRKAREA
  1460 .2     JMP GET.WRKAREA.FROM.BUFFER
  1470 *--------------------------------
  1480 *  PATCH EXECUTED WHEN FILE MANAGER IS FINISHED:
  1490 *      1. IF READ/WRITE, SET FLAG AND SAVE PNTR
  1500 *      2. IF NOT R/W, CLEAR FLAG AND SAVE WORK AREA
  1510 *--------------------------------
  1520 PATCH2 LDA FM.OPCODE     R/W?
  1530        CMP #3
  1540        BCC .1            NO
  1550        CMP #5
  1560        BCS .1            NO
  1570        SEC               YES, SET FLAG
  1580        ROR FLG
  1590        JSR POINT.TO.WRKAREA.BUFFER
  1600        LDA PNTR          AND SAVE POINTER
  1610        STA PNTR.S
  1620        LDA PNTR+1
  1630        STA PNTR.S+1
  1640        RTS               SAVE ANOTHER 800 CYCLES
  1650 .1     CLC               CLEAR FLAG
  1660        ROR FLG
  1670        JMP SAVE.WRKAREA.TO.BUFFER
  1680 *
  1690 PNTR.S .HS 0000
  1700 FLG    .HS 00
  1710 *--------------------------------
  1720 *  TO INSTALL, PATCH DOS LIKE THIS:
  1730 *      .OR $AB0A
  1740 *      JSR PATCH1
  1750 *
  1760 *      .OR $B38E
  1770 *      JSR PATCH2
  1780 *
  1790 *  HERE IS ONE WAY TO DO IT:
  1800 *--------------------------------
  1810 INSTALL
  1820        LDA #$20     JSR OPCODE
  1830        STA $AB0A
  1840        STA $B38E
  1850        LDA #PATCH1
  1860        STA $AB0B
  1870        LDA /PATCH1
  1880        STA $AB0C
  1890        LDA #PATCH2
  1900        STA $B38F
  1910        LDA /PATCH2
  1920        STA $B390
  1930        RTS
  1940 *--------------------------------
Making Paul's Patches Fit in DOSBob Sander-Cederlof

Don't tell me it won't fit! It is so good, it MUST fit!

Let's see...there are 74 bytes available from $B6B3 thru $B6FC. But Paul's patches are 93 bytes long. Maybe if I twist it sideways and then hold my mouth just right....

Ha! It worked!

Let me tell you how, but please don't think I am trying to pick Paul apart. His analysis and creative programming are terrific! He has taught me a lot.

First I noticed some common code in PATCH1 and PATCH2. I made a subroutine called CHECK.OPCODE to test for the read or write command. I used the carry status to pass back the answer to the caller. Then I put the call to POINT.TO.WORKAREA (which loads an address into $42 and $43) at the top of the subroutine. There's no need to duplicate it in the two callers. These changes saved two or three bytes, for a tiny penalty in speed.

I noticed Paul used CLC, ROR FLAG to clear the sign bit of FLAG. I save one byte two times by replacing these with LSR FLAG. I set up the carry status info in CHECK.OPCODE so that carry SET means read/write...this lets me omit the SEC before ROR FLAG when I want to turn on the sign bit.

I noticed that both patches used the current contents of PNTR: PATCH1 compared PNTR to PNTR.SAVE, while PATCH2 copied PNTR into PNTR.SAVE. So I loaded up the contents of PNTR into the A- and X-registers inside my CHECK.OPCODE subroutine. This saves a few more bytes.

At lines 1320-1330 in Paul's program he uses BNE to jump around an RTS. I changed that to BEQ to an existing RTS further down in the program, saving one byte.

I moved the PNTR.SAVE variable, two bytes, to another area. $B5CF and $B5D0 are unused, at the end of the file manager parameter list. Conveniently, the subroutines which load addresses into PNTR refer to three such addresses inside the parameter list. (See the code at $AF08-$AF1C.) The X-register is loaded with 0, 2, or 4 to index into the list. By putting PNTR.SAVE at the end of the list, I can load the X-register with 8 (PNTR.SAVE-$B5C7) and use the same subroutine, entering at $AF12. This takes five bytes instead of twelve for LDA-STA- LDA-STA.

The final shortener I applied was to make the code which clears FLAG and copies the workarea to a buffer into a subroutine. This is called PATCH4 in my listing. The two lines at PATCH4 look just like what was in line inside the PATCH1 code, but different from what was done by the PATCH2 code.

PATCH2 falls into PATCH4 if the opcode was not read/write. This used to clear the flag and call $AE7E; now it is $AE81. Since the difference between $AE7E and $AE81 is a JSR to setup PNTR with the workarea address, and since that was already arranged by CHECK.OPCODE, I can safely enter at $AE81.

No doubt if you followed me this far, you can see even more ways to save bytes. In fact, I see one extra byte myself! But the program is now just the right size for that hole at $B6B3, so enough is enough.

My listing includes some code to install the patches. If you assemble my version, and BSAVE it on a binary file (A$300,L$6A), you can BRUN it whenever you want to install the patches. Or, with version 1.1 of the Macro Assembler just add these lines:

     1195       .TF B.FAST TEXT
     1380       .PH $B6B3
     1790       .EP

I also worked out the code for using Applesoft POKEs to patch it all in, and here it is:

     100  REM  TEXT FILE SPEEDUP PATCH
     110  READ N
        : IF N = 0 THEN  END 
     120  READ A
        : FOR I = 0 TO N - 1
        : READ X
        : POKE A + I,X
        : NEXT
        : GOTO 110
     200  DATA 74,46771,32,210,182,144,10,205,207,181,
               208,5,236,208,181,240,51,44,252,182,16,
               8,162,8,32,18,175,32,246,182,76,106,174,
               32,8,175,173
     210  DATA 187,181,56,73,3,240,5,73,7,240,1,24,165,
               66,166,67,96,32,210,182,144,10,110,252,182,
               141,207,181,142,208,181,96,78,252,182,76,
               129,174,0
     220  DATA 2,43787,179,182
     230  DATA 2,45967,231,182
     235  DATA 1,41393,20
     240  DATA 0

I tested the patches on a 24-sector text file. The file was created by using the TEXT command in the S-C Macro Assembler. I used EXEC to read it back in. I also wrote a short Applesoft program which read the whole file with GET A$ in a loop. Here are the results:

            NORMAL  PATCHED  CHANGE
            ---------------------------
     TEXT   24 sec  18 sec   25% faster
     EXEC   52 sec  34 sec   35% faster
     GET A$ 30 sec  21 sec   30% faster

I think you get the most benefit if the un-patched DOS has to work so long between calls to RWTS that the disk motor stops, but the patched DOS keeps the motor alive. You save 0.4 seconds per sector anyway, but you can also save waiting for the motor to come up to speed.

Warning: One danger I noted, and which I am wary of, is that FLAG could get out of sync with reality. For example, if somehow FLAG was set with the sign bit on before ever calling the file manager, it could try to copy the workarea to any-old-place in RAM (or ROM, or I/O space). If you install the patches after booting, there should be no problem. But what happens if you initialize a disk with the patched DOS? I think the flag MIGHT turn out wrong. Maybe a little patch is needed to insure FLAG starts out clear, and is cleared after abnormal exits from file manager (such as RESET).

Last-Minute Warning:
DO NOT DO "BRUN B.FAST TEXT" FROM AN EXEC FILE.
IT'S NOT A GOOD IDEA TO USE A TEXT FILE
TO CHANGE THE WAY TEXT FILES WORK!!!

  1000 *SAVE S.FAST TEXT (RBS-C)
  1010 *--------------------------------
  1020 *      PAUL SCHLYTER'S TEXT FILE SPEED-UP
  1030 *      AS MODIFIED BY BOB SANDER-CEDERLOF
  1040 *                     JUNE 8, 1983
  1050 *--------------------------------
  1060 PNTR   .EQ $42,43
  1070 *--------------------------------
  1080 COPY.BUFFER.TO.WORKAREA .EQ $AE6A
  1090 SAVE.WORKAREA           .EQ $AE81
  1100 POINT.TO.WORKAREA       .EQ $AF08
  1110 SETUP.PNTR              .EQ $AF12
  1120 FM.OPCODE               .EQ $B5BB
  1130 PNTR.SAVE               .EQ $B5CF,B5D0
  1140 *--------------------------------
  1150 PATCH.AREA              .EQ $B6B3
  1160 PATCH.LINK1             .EQ $AB0B
  1170 PATCH.LINK2             .EQ $B38F
  1180 *--------------------------------
  1190        .OR $300
  1200 *--------------------------------
  1210 INSTALL.PATCHES
  1220        LDX #PATCH.SIZE-1
  1230 .1     LDA PATCH.CODE,X
  1240        STA PATCH.AREA,X
  1250        DEX
  1260        BPL .1
  1270        LDA #PATCH1
  1280        STA PATCH.LINK1
  1290        LDA /PATCH1
  1300        STA PATCH.LINK1+1
  1310        LDA #PATCH2
  1320        STA PATCH.LINK2
  1330        LDA /PATCH2
  1340        STA PATCH.LINK2+1
  1342        LDA #20
  1344        STA $A1B1
  1350        RTS
  1360 *--------------------------------
  1370 PATCH.CODE
  1380        .OR $B6B3
  1390        .TA PATCH.CODE
  1400 PATCH1 JSR CHECK.OPCODE
  1410        BCC .1       NOT READ/WRITE
  1420        CMP PNTR.SAVE
  1430        BNE .1       NO
  1440        CPX PNTR.SAVE+1
  1450        BEQ PATCH3   YES, RETURN NOW
  1460 .1     BIT FLAG
  1470        BPL .2
  1480        LDX #PNTR.SAVE-$B5C7
  1490        JSR SETUP.PNTR
  1500        JSR PATCH4   CLEAR FLAG, SAVE WORKAREA
  1510 .2     JMP COPY.BUFFER.TO.WORKAREA
  1520 *--------------------------------
  1530 PATCH2 JSR CHECK.OPCODE
  1540        BCC PATCH4   NOT READ OR WRITE
  1550        ROR FLAG     SET SIGN BIT
  1560        STA PNTR.SAVE
  1570        STX PNTR.SAVE+1
  1580 PATCH3 RTS
  1590 *--------------------------------
  1600 PATCH4 LSR FLAG     CLEAR SIGN BIT
  1610        JMP SAVE.WORKAREA
  1620 *--------------------------------
  1630 CHECK.OPCODE
  1640        JSR POINT.TO.WORKAREA
  1650        LDA FM.OPCODE
  1660        SEC
  1670        EOR #3       READ?
  1680        BEQ .1       YES
  1690        EOR #7       WRITE?
  1700        BEQ .1
  1710        CLC
  1720 .1     LDA PNTR
  1730        LDX PNTR+1
  1740        RTS
  1750 *--------------------------------
  1760 FLAG   .HS 00       MUST START WITH FLAG=0
  1770 *--------------------------------
  1780 PATCH.SIZE .EQ *-PATCH1

65C02 DepartmentBill Morgan

I am holding a brand new NCR65C02A. Now I finally believe that there is such a creature as a 65C02! NCR's version of this processor seems to be the same as GTE's. That is, it has all of the enhancements described in the December '82 issue of AAL, except for the single bit set, reset and branch instructions.

We have tested the chip in the computers here, and there's good news and bad news. As Don Lancaster reported last month, the new chip works perfectly in an Apple //e. You just swap processors and start using new opcodes. However, 65C02 chips do not work in the Apple ][ or Apple ][+.

I am told that the problem lies in the execution of instructions like ASL or INC, which read memory, modify the contents, and write the result back to the same address. The 6502 processor does one read and two writes during such an instruction, which is really incorrect. In the 65C02 this has been changed to the proper combination of two reads and one write.

Unfortunately, the Apple ][s rely on the timing of the read-write-write cycle, and the read-read-write cycle is just different enough to cause the system to fail. Hopefully some of the hardware specialists can come up with a modification to the older Apples to allow the use of the enhanced processors.

Let's talk about programming the 65C02. With the new chip in a //e, Bob and I started tearing into the S-C Word Processor. We just went through the code, looking for places to substitute a new instruction for several old ones. Come to find out, the most useful change is the true Indirect addressing mode, in place of Indexed Indirect. That means replacing

     STY YSAVE
     LDY #0
     LDA (POINTER),Y
     LDY YSAVE          with     LDA (POINTER).

That's replacing 8 bytes with 2 bytes. BRA (BRanch Always) and STZ (STore Zero) also came in very handy.

All things considered, Bob has decided to wait for the Rockwell version of the 65C02, because he really wants those single bit set, reset, and branch instructions. At last word Rockwell was expecting to start shipping in August, so it will be at least that long before we have any. NCR's chip costs about $10. The Rockwell chip may cost a little more, if and when. We have noticed ads offering 65C02's for $35, which just goes to show how expensive advertising can be.


Revised Monitor Patch for ASCII DisplayBob Sander-Cederlof

Peter Bartlett gave us a nice patch to the Apple Monitor to add ASCII display to the memory dump command. It was published in the Dec 1981 issue of Apple Assembly Line, pages 18-20. You may remember that Peter's patch over-wrote the cassette tape code. Last summer I received two suggested modifications to Peter's code, and at last I pass them on to you.

Bruce Field, from Rockville, Maryland: "I finally got around to building my own EPROM burner the other day, and one of the first things I did was to modify my F8 ROM to include an ASCII listing with the hex dump. I used the routine originally submitted by Peter Bartlett. I found a minor problem with this code.

"The problem is that I have the modified ROM on an Integer BASIC card, and an unmodified ROM on the mother board. If I am in the modified ROM and want to soft-switch back to the mother board, typing 'C081' should do it. But with Peter's patch location C081 is accessed inside the patch itself, so the card switches off with PC pointing inside the cassette tape code!

"My solution is to leave the loading of the memory location in its original position. This makes the patch slightly longer, but it still fits inside the cassette tape space. Also, since I detest flashing characters, I filter these out. I force control characters to inverse mode, and all others to normal video."

  1000 *SAVE S.MON ASCII DISPLAY (FIELD)
  1010 *---------------------------------
  1020 *   PATCHES TO ADD ASCII DUMP TO APPLE MONITOR
  1030 *   ORIGINAL BY PETER BARTLETT
  1040 *   MODIFIED BY BRUCE FIELD
  1050 *---------------------------------
  1060 A1L        .EQ $3C
  1070 COUT       .EQ $FDED
  1080 PRBYTE     .EQ $FDDA
  1090 *---------------------------------
  1100        .OR $FDBD
  1110        .TA $0DBD
  1120        JSR PATCH    CALL MY PATCH CODE
  1130 *---------------------------------
  1140        .OR $FCC9
  1150        .TA $0CC9
  1160 PATCH  PHA          SAVE BYTE 
  1170        LDA A1L      LOW BYTE OF DUMP ADDRESS
  1180        AND #7       MASK LINE POSITION
  1190        CLC
  1200        ADC #31      COMPUTE HORIZONTAL OFFSET
  1210        TAY
  1220        PLA          GET BYTE FROM STACK
  1230        PHA          KEEP COPY ON STACK
  1240        ORA #$80     FORCE NORMAL VIDEO
  1250        CMP #$A0     MAKE CONTROL-CHARS INVERSE
  1260        BCS .1       ...NOT CTRL
  1270        AND #$7F     ...CTRL
  1280 .1     STA ($28),Y  STORE IT ON THE SCREEN
  1290        LDY #0       RESTORE Y
  1300        PLA          RECOVER BYTE AGAIN
  1310        JMP PRBYTE

Brooke Boering, from Schaumburg, Illinois: "Here is a slightly modified version of Peter Bartlett's monitor patch. I modify control characters to display as an underline character, and lower case codes to inverse video. Other characters display in normal video."

  1000 *SAVE S.MON ASCII DISPLAY (BOERING)
  1010 *---------------------------------
  1020 *   PATCHES TO ADD ASCII DUMP TO APPLE MONITOR
  1030 *   ORIGINAL BY PETER BARTLETT
  1040 *   MODIFIED BY BRUCE FIELD
  1050 *   MODIFIED AGAIN BY BROOKE BOERING
  1060 *---------------------------------
  1070 A1L        .EQ $3C
  1080 COUT       .EQ $FDED
  1090 PRBYTE     .EQ $FDDA
  1100 *---------------------------------
  1110        .OR $FDBD
  1120        .TA $0DBD
  1130        JSR PATCH    CALL MY PATCH CODE
  1140 *---------------------------------
  1150        .OR $FCC9
  1160        .TA $0CC9
  1170 PATCH  PHA          SAVE BYTE 
  1180        LDA A1L      LOW BYTE OF DUMP ADDRESS
  1190        AND #7       MASK LINE POSITION
  1200        CLC
  1210        ADC #31      COMPUTE HORIZONTAL OFFSET
  1220        TAY
  1230        PLA          GET BYTE FROM STACK
  1240        PHA          KEEP COPY ON STACK
  1250        ORA #$80     FORCE NORMAL VIDEO
  1260        CMP #$A0     MAKE CONTROL-CHARS INVERSE
  1270        BCS .1       ...NOT CTRL
  1280        LDA #$DF     MAKE CONTROL INTO UNDERLINE
  1290 .1     CMP #$E0     IN LOWER-CASE RANGE?
  1300        BCC .2       ...NO, DISPLAY NORMAL VIDEO
  1310        AND #$1F     ...YES, FORCE INVERSE VIDEO
  1320 .2     STA ($28),Y  STORE IT ON THE SCREEN
  1330        LDY #0       RESTORE Y
  1340        PLA          RECOVER BYTE AGAIN
  1350        JMP PRBYTE
  1360 *--------------------------------

After assembling Bruce's version above, using the S-C Macro Assembler resident in my language card, I installed the patch by typing:

     $C083 C083     (write enable RAM card)
     $FCC9<CC9.CE3M (move the patch into the
                    cassette space)
     $FDBE:C9 FC    (install patch address in JSR)

And it worked! To install Brooke's code I had to move a few more bytes:

     $FCC9<CC9.CE9M

If you have an Apple //e, or a lower case display adapter in an older Apple, you will not want to display lower case characters in inverse mode. Everyone seems to have their own preferences about how to display the 256 possible hex values on Apple's screen. Choose your own favorite!


Answered PrayerBob Sander-Cederlof

Last month's headlines bemoaned our burglary, with equipment worth over $11000 missing from our offices. And un-measurable amounts of software. And a damaged Spinwriter. And no insurance. We didn't even have all of the serial numbers recorded. The police indicated we should have no hope of recovering anything.

I know that God, who made the heavens and the earth and all that is in them, is sovereign. I said, "Thank you for this, too. And thank you that we still have enough left to continue business. And that nothing irreplaceable was taken."

And we tried to put the pieces back together. We bought insurance, and recorded all the remaining serial numbers. We made backup copies of critical software to be kept at other locations. We engraved our driver's license numbers on our equipment. We even installed an alarm system.

After about two hours with a screwdriver and needlenose pliers the Spinwriter was back in working condition. Almost as good as new...just one crippled foot where it landed when dropped. NEC makes durable gear. I spent another 8 hours figuring out how to talk to it with a serial interface card (with no documentation), and writing the driver program. Once it all worked, we were able to print the mailing labels for last month's AAL.

The burglary occured sometime after 8:30 pm, Wednesday night, May 25th. The next Wednesday night, after choir practice, we took some time to pray. Among other concerns, we prayed about the burglary. I suggested, "Let's pray that the burglars be caught and the things they took be recovered. It can't hurt to ask!" So we did.

The next day the police received a tip from an informer. They went to investigate, just in time to catch two 18-year-olds carrying computers from apartment to car. One of them was a well-known burglar, with at least six-year record. The equipment matched the description I had given them. Friday morning the investigator called: "We have some of your computers. You can come and pick them up at noon." Although a little dirty, none of the equipment or software was damaged. Two thirds of all that had been stolen was recovered! "A miracle", the police said. "Amen."

The following Monday the police called again. "We have some more." The third computer system, a brand new Apple //e with extended 80-column card, two disk drives, monitor, and Epson printer had been sold to a technically-minded friend (of the burglars) for only $100. Responding to the alternatives offered by our excellent police ("Return the computer, or go to jail"), the friend brought in all he had bought. Almost everything was back in our office!

Thursday, June 16th, I was called a third time. "We have another disk drive." They also had another FlipFile with about 15 more diskettes. Now all that is missing is a TI Programmer calculator and an old Panasonic Cassette Recorder.

Yes, God is sovereign, and also He cares about us as individuals. He allowed our things to be taken, but not everything. He gave us faith to ask for them to be returned. And He caused them to be returned. "Trust in the Lord with all your heart, and do not lean on your own understanding. In all your ways acknowledge Him, and He shall direct your paths." [Proverbs 3-5,6]


Eighty-Column SHOW CommandRobert Bragner
Istanbul, Turkey

I make frequent use of the SHOW command for text files (see AAL July 1982), and I wanted to see it in 80-column glory on my shiny new //e. If you've tried it, you will have noticed that the command places a character in every other column on the 80-column screen, so you still only see 40-columns of data per line!

The reason is that the SHOW command code calls COUT1 at $FDF0 for its character output, and COUT1 knows nothing about 80-column output. By calling COUT ($FDED) instead, the text file output will be routed to whatever your current output device happens to be (including printer, 80-column display, etc.).

If you use the Applesoft on page 27 of that issue to load SHOW, all you need to do is change the ninth item on line 100 from 240 to 237.

Here is the modified POKEr, complete with the additions made by Bil Morgan in the June 83 issue, to save you hunting through all those back issues:

     100 DATA 21,42319,32,163,162,169,141,32,237,253,32,142,
              174,240,5,32,140,166,208,243,76,252,162
     110 DATA 23,44686,173,0,192,16,17,141,16,192,201,141,
              240,10,173,0,192,16,251,141,16,192,201,141,96
     115 DATA 13,44709,224,0,240,4,162,2,208,2,162,4,76,3,171
     116 DATA 3,43773,76,165,174
     120 DATA 4,43140,83,72,79,215
     130 DATA 2,43273,32,48
     140 DATA 0
     150 READ N : IF N THEN READ A : FOR I = 1 TO N
         : READ D : POKE A+I-1,D : NEXT : GO TO 150

Explanation of the new DOS Append BugTom Weishaar
Overland Park, Kansas

[ Tom is author of ProntoDOS, published by Beagle Bros, an excellent speed-enhanced DOS which happens to be compatible with nearly everything. He also writes the monthly DOStalk column in Softalk Magazine. ]

I was behind on my reading when I wrote, in the April Softalk DOStalk, about the changes Apple made to DOS 3.3 in the new //e release. At that time I noticed the routine used to calculate random access file position at $B331 had been modified, but the change looked insignificant to me.

It turns out this change was supposed to fix another bug in the Append command! The change was very well documented by Art Schumer in the August 1982 Call APPLE, page 57.

In pre-//e DOS, Append called on this random-access file position calculator to reset the position-in-file pointer. As you know, Append simply looks through a file byte-by-byte until it finds the end, which can be indicated either by a zero byte or by a lack of additional sectors.

When Append finds a zero byte in the file, it knows it has reached the end, but by then the position-in-file pointer is one byte beyond the zero and has to be backed up. Somebody once thought a call to the random-access file position calculator would be a good way to do this.

But on sequential files (the only kind you can append to) the File Manager uses a record length of one. Thus files longer than 32767 bytes come to this routine with more than 32767 "records", which is beyond what DOS normally allows. The calculation fails.

Schumer's patch gets it to calculate correctly right up to 65535. At that point it stops working for good. Apple tried to get around this in //e-DOS by throwing out Append's reliance on the random-access calculator. Instead they go back in and change the position-in-file pointer directly, then trick the File Manager into re-saving his workarea.

Problem: they only decrement the low byte of the position-in- file pointer. If the file-ending zero comes in the last byte of a sector, the high byte will have been advanced to point at the next sector. Since they don't decrement it, the position- in-file pointer is 256 bytes beyond where it should be. Uh Oh...!

I've been trying to get folks at Apple to recognize the problem, but Append doesn't appear to be one of their priorities. If they don't do something soon I'll publish a patch in Softalk. I'd do it now, but I fear treading where so many have failed before me.


The new 1983 edition of DOS 3.3Bob Sander-Cederlof

Co-incident with the release of the //e, Apple started shipping a slightly modified version of DOS 3.3. Three changes are evident: the sample programs have been moved to a separate diskette; a few instructions to kill 80-column display during a boot were added; and yet another patch to the APPEND command.

I booted an old DOS 3.3, and then used monitor move to make a copy in memory running from 5D00-7FFF of the DOS image. Then I booted the new DOS, which loaded into 9D00-BFFF. Using the monitor "V" command, I located all of the changes. It was a little tricky skipping over the variables and buffers, but with the aid of a well-worn copy of "Beneath Apple DOS" I managed. Here are all the changes I found:

      Old DOS 3.3                New DOS 3.3
     ----------------------     ----------------------
     A6BB:EA       NOP          A6BB:20 69 BA JSR $BA69
     A6BC:EA       NOP
     A6BD:EA       NOP
     A6BE:A2 00    LDX #0       A6BE:unchanged
     A6C0:8E C3 B5 STX $B5C3
     A6C3:60       RTS

The code above is jumped to from one of the older APPEND patches at $B6A8. It used to be JMP $A6BC, and has been changed to JMP $A6BB to pick up the new JSR there.

The latter part of the file position calculator has been re-written to assure carry is clear before adding record size to previous position.

      Old DOS 3.3                New DOS 3.3
     ----------------------     ----------------------
     B33E:AD BF B5 LDA $B5BF    B33E:18       CLC
     B341:8D EC B5 STA $B5EC    B33F:AD BF B5 LDA $B5BF
     B344:6D E6 B5 ADC $B5E6    B342:8D EC B5 STA $B5EC
     B347:8D E6 B5 STA $B5E6    B345:6D E6 B5 ADC $B5E6
     B34A:AD C0 B5 LDA $B5C0    B348:8D E6 B5 STA $B5E6
     B34D:8D ED B5 STA $B5ED    B34B:AD C0 B5 LDA $B5C0
     B350:6D E4 B5 ADC $B5E4    B34E:8D ED B5 STA $B5ED
     B353:8D E4 B5 STA $B5E4    B351:6D E4 B5 ADC $B5E4
     B356:A9 00    LDA #0       B354:8D E4 B5 STA $B5E4
     B358:6D E5 B5 ADC $B5E6    BE57:90 03    BCC $B35C
     B35B:8D E5 B5 STA $B5E5    BE59:EE E5 B5 INC $B5E5
     B35E:60       RTS          BE5C:60       RTS
                                BE5D:00 00    filler

Note that there was room for adding the CLC at the top, because of the in-efficiency of the original code.

Code executed at the end of a boot has been modified to clear 80-column mode in case you are booting in an Apple //e.

      Old DOS 3.3                New DOS 3.3
     ----------------------     ----------------------
     BFD6:4C 44 B7 JMP $B744    BFD6:20 76 BA JSR $BA76
                                BFD9:4C 44 B7 JMP $B744

Three patches were stuffed into the hole at $BA69.

            Called from $A6BB:

     BA69:AE 5F AA LDX $AA5F   If last command was
     BA6C:E0 1C    CPX #$1C         APPEND, clear flag
     BA6E:FO 05    BEQ $BA75        Not APPEND
     BA70:A2 00    LDX #0           Yes, APPEND
     BA72:8E 5D B6 STX $B65D        Clear APPEND flag
     BA75:60       RTS

            Called from $BFD6:

     BA76:A9 FF    LDA #$FF
     BA78:8D FB 04 STA $04FB        MODE = $FF
     BA7B:8D 0C C0 STA $C00C        80-column display OFF
     BA7E:8D 0E C0 STA $C00E        Alternate Char Set OFF
     BA81:4C 2F FB JMP $FB2F        Exit via monitor INIT

            Called from $B683:

     BA84:AD BD B5 LDA $B5BD        Previous file position
     BA87:8D E6 B5 STA $B5E6        LSB of fle position
     BA8A:8D EA B5 STA $B5EA        Record #
     BA8D:BA       TSX
     BA8E:8E 9B B3 STX $B39B        Save stack position
     BA91:4C 7F B3 JMP $B37F        Leave File Manager

Note that this last patch jumps into the file manager exit routine even though the file manager had not been entered. The purpose is to save a copy of the file manager workarea in the file buffer after patching the file position low-order byte. Seems to me that jumping directly to $AE7E, without the two lines saving the stack pointer above, would avoid the very dangerous step of jumping into the middle of a subroutine. But in any case, as Tom Weishaar points out, the code is wrong in that it does not recover the higher bytes of the file position. Will APPEND ever really be fixed?

A few months back I published a patch for faster LOAD, etc) in these pages which used the space from $BA69 through $BA95. I suggest you use the older version of DOS 3.3 for the time being. But eventually you may be forced to find another home for the fast LOAD patch.


More opcodes for the S-C MACRO ASSEMBLERR.F. O'Brien

While using the assembler I felt that it was a pity that the BGE and BLT instructions had not been incorporated especially as it would only have meant an extra 6 bytes of code. This minimal extra overhead is because of the way opcodes are handled in the assembler.

Take for example the BRANCH opcode table, which resides in locations $EF5B-EF93. ($2E29-2E47 for RAM version.) [ These addresses are for version 1.0 ]

This table is preceded by a 2-byte descriptor and ends as one would expect with a 00 as end-of-table marker. The descriptor in this case is 0302, i.e. 3-byte entries having a 2-byte name. The table holds the standard 8 6502-opcodes and the 10 Sweet-16 opcodes, interestingly the B of each instruction name has been dropped, saving 18 bytes.

The entries in the table consist of the last 2 letters of the instruction name followed by the hex code. In the case of 2-letter names the entry consists of the second letter plus a space ($20) followed by its hex code.

I decided that I could dispense with the SW-16 codes BM1 and BNM1 without suffering too much if I wanted to write Sweet-16 code in my programs. However, I found that to incorporate the new codes they would have to be placed between the 6502 codes and the SW-16 codes in the table.

It was just a matter of pushing the code for BR to BNZ up in RAM 6 bytes and slotting in the code for BLT and BGE.

To install the code for the two new opcodes just enter the following at any convenient location e.g.$4000 and BSAVE as BLT/BGE.CODE,A$4000,L$1F

     :$4000:47 45 B0 4C 54 90     ("G E B0  L T 90")
     :$:52 20 01 4E 43 02 43 20 03 50 20 04
     :$:4D 20 05 5A 20 06 4E 5A 07 53 20 0C 00
To install in LC-Version just enter:
     :$C083 C083        write enable card.
     :BLOAD BLT/BGE.CODE,A$EF75
     :$C080             write protect card.

To install in RAM-Version just enter:

     :BLOAD BLT/BGE.CODE,A$2E29
If you never use Sweet-16 you only need to use the first 6 bytes of the above code. However, this will wipe out the BR and BNC codes in the table.

Now you can use either BCC or its synonym BLT (Branch if Less Than) and BCS or BGE (Branch if Greater than or Equal to) in your programs and have them assembled correctly without using macro definitions.

The load address for the patch file for version 1.1 will vary depending on which of the 8 versions you are patching:

                    40-col  //e    Videx  STB-80
     Motherboard    $31A9   318D   3274   329D

     RAM Card       $F2C3   F2A7   F397   F3C0

Bobby Deen's Latest Stuff

Bobby Deen is a name you may remember seeing in these pages in several past issues. He will be entering Texas A & M University this fall. Bobby programmed most of the cross assembler modules for the S-C Macro Assembler, some parts of the S-C Word Processor, about half of the yet-to-be-released 18-digit commercial math package (S-C DP18), and parts of the CPR Training System we did for the American Heart Association. A man of many interests, Bobby also has produced some excellent music disks for the ALF music synthesizers (or any Alf compatibles, such as Applied Engineering), and now a fantastic "Othello" game.

His six-voice renditions of the William Tell Overture by Rossini and Tchaikovsky's Nutcracker Suite are outstanding, and the price is only $10. If you have a synthesizer, you ought to have Bobby's music.

Bobby's Othello program is available now for an introductory price of only $20. Of course he wrote it in assembly language, so it is FAST, and has excellent hi-res graphics. You select among six skill levels; Apple can suggest your next move; you can swap sides with the computer; you can modify the board in mid-game (cheat?); you can pit the computer against itself. Whenever two or more moves tie for the machine's best next move, Apple randomizes its choice. This way you never play the same identical game twice.

Order either of these disks from S-C Software.

Osborne Raises Book Prices

Osborne/McGraw-Hill has raised the prices of most of their books. In particular, all of their books which we carry have new higher prices. They are still bargains when you consider how good they are, and how packed with information:

     Title                     Was     Is Now  Our Price

     6502 Assembly Lang Prog  $16.99   $18.95   $18.00
     6502 Subroutines         $15.95   $17.95   $17.00
     Z-80 Assembly Lang Prog  $16.99   $18.95   $18.00
     Z-80 Subroutines         $15.95   $17.95   $17.00

Apple Assembly Line is published monthly by S-C SOFTWARE CORPORATION, P.O. Box 280300, Dallas, Texas 75228. Phone (214) 324-2050. Subscription rate is $15 per year in the USA, sent Bulk Mail; add $3 for First Class postage in USA, Canada, and Mexico; add $13 postage for other countries. Back issues are available for $1.50 each (other countries add $1 per back issue for 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.)