Apple Assembly Line
Volume 3 -- Issue 7 April 1983

In This Issue...

New Goodies

We have several new products available this month. There are descriptions inside this issue of the new Cross Reference program for the S-C Macro Assembler, and the new book "Apple ][ Circuit Description". Also, the long-awaited RCA 1802 Cross Assembler is now ready, at $32.50.

Version 1.1 of the Macro Assembler is now ready to go! The upgrade from the current Version 1.0 will only cost you $12.50. That gets you //e, Videx, and STB 80-column support, 5 new directives and all the other new features described last month.


DISASM and the //e Bill Morgan

Yesterday afternoon I received two phone call in less than 30 minutes, both reporting that RAK-Ware's disassembler, DISASM, does not work on the Apple //e. The problem occurs when DISASM calls an odd entry into the monitor HOME routine. At several places in the routines to enter address information Bob Kovacs used $FC5A for a sort of combination VTAB and Clear-to-End-of- Page. Well, that won't work on a //e. The following patches change all the calls to $FC5A into $FC58, or the standard HOME routine. This will change the behavior of the program a little, making the screen clear between entries, rather than just tab down, but the program should now work.

    84C:58     94D:58     A79:58
    AD8:58     BBA:58     BFB:58

Patch DOS 3.3 for Fast LOAD and BLOAD Bob Sander-Cederlof

There must be at least a dozen products on the market now to speed up DOS 3.3: Diversi-DOS, David-DOS, The DOS Enhancer, QuickDOS, FastDOS, Hyper-DOS, et cetera. Some of these are unfortunately not compatible with the everyday programs we like to use, such as the S-C Assembler, ES-CAPE, or our favorite word processor. And it can be quite difficult sometimes to determine the degree of compatibity.

For the record, S&H Software's DOS Enhancer is completely compatible with the S-C Macro Assembler. David-DOS works well until you try to use the .TF directive.

Most of the speed-up systems only improve the speed of LOAD, BLOAD, RUN, BRUN, SAVE, and BSAVE. Some also speed up booting into the language card. And two (Diversi-DOS and David-DOS) speed up READing and WRITE-ing TEXT files, as well as offering a lot of minor enhancements in pursuit of more "user- friendliness".

It seems that the more the speed-up system does, the more compatibility problems you can expect. After all, to add a feature you do have to change some code. And many programs on the market expect the DOS image to be un-modified so they can jump into DOS subroutines in strange unexpected places and make their own custom patches to the DOS image.

Paul Schlyter (a subscriber in Sweden) sent me a small patch for DOS 3.3 early in April, 1982. Paul's patch speeds up only RUN, BRUN, LOAD and BLOAD, but it such a small patch that it will almost fit into the interstices (unused bytes) inside DOS. In fact, after I removed one bug and reorganized the code a little, I was able to fit it entirely within two unused areas: $BA69-BA95 and $BCDF-BCFF. [ Not true! See New Version of DOS -- Patcher's Beware" ] I believe the result is completely compatible with all the programs I use around here, except for the ones that use their own modified and protected DOS.

Paul's patch turns out to be functionally equivalent to the much longer patch proposed in HardCore Magazine's HyperDOS, but it leaves the INIT command intact.

I ran some timing tests:

     LOAD   40 sectors  standard 10 sec
                        patched   3.5 sec

     BLOAD  37 sectors  standard 11 sec
                        patched   4 sec

     LOAD  132 sectors  standard 32 seconds
                        patched   7.5 seconds

I didn't try measuring times, but I suspect that SAVE and BSAVE may be just a little faster with this patch installed (during the read-after-write phase).

Since the S-C Assemblers use the LOAD command to process .IN directives, large assemblies with large included files will assemble about three times faster when you install this speed-up patch.

The patch is really rather simple. But before examining the patch, let's review the normal flow inside DOS for LOADing and BLOADing.

DOS is constructed in three layers: the outer layer accepts your commands from the keyboard or from your program. The inner layer, called RWTS, handles the intimate details of reading or writing a specified sector on a specified track. RWTS also does the raw disk initialization when you use the INIT command. The layer between commands and RWTS is called the File Manager (FM).

The command layer calls FM to open, close, rename, lock, unlock, verify, or delete a file; to print a catalog; to initialize a disk; or to position within a file. There are also four kinds of calls for reading and writing files, to read or write one byte or a range of bytes.

When you use the RUN or LOAD command, the command layer calls FM to read the first two bytes. These bytes contain the length of your program. For Integer BASIC or S-C Assembler source files, the length is subtracted from HIMEM to get a loading address. The loading address for Applesoft programs is found in $67,68. Then FM is called to read a range of bytes of that length, to be stored starting at the loading address just determined.

When you use the BRUN or BLOAD command, the first four bytes are read off the front of the file. The first two bytes are the loading address, and the next two are the length. (Of course, you can override the loading address with the "A" parameter after the file name.)

After winding our way through the front end of FM, we finally get to this subroutine (where the range is read):

                1000 READ.RANGE
AC96- 20 B5 B1  1010       JSR DECR.TEST.LENGTH
AC99- 20 A8 AC  1020       JSR READ.BYTE
AC9C- 48        1030       PHA              SAVE THE BYTE
AC9D- 20 A2 B1  1040       JSR GET.ADDRESS.INC
ACA0- A0 00     1050       LDY #0
ACA2- 68        1060       PLA              GET THE BYTE
ACA3- 91 42     1070       STA ($42),Y      STORE IN BUFFER
ACA5- 4C 96 AC  1080       JMP READ.RANGE

The subroutine DECR.TEST.LENGTH breaks out of this loop when the range has been completely read. The READ.BYTE subroutine picks bytes out of the DOS buffer, and reads a sector into that buffer when the buffer is empty.

To understand the speed-up patch, break the reading process into three parts: the first sector, the last sector, and all the in-between sectors. We will let the loop shown above handle the first sector and possibly the last sector, and read the in-between sectors using a faster method. Short files with only one or two data sectors will not have any in-between sectors, and so there will be no improvement in speed.

First we need to read the rest of the first sector of the file. The first two or four bytes were already read to get address and length information. We can let the loop shown above do that job. But we need a way to break into the loop when it is our turn. Let's patch the JMP on the last line to jump to our patch.

Our patch will get control after the loop above has read and stored a byte of data. At that time our patch can look at the current file position in $B5E6; if $B5E6 is non-zero, then there are still bytes in the DOS buffer. As long as there are bytes in the DOS buffer, we will branch back to $AC96 and let FM handle the bytes in its normal way.

Once the first sector has been read and stored, a byte at a time, $B5E6 will have a zero value. Then our patch can look at the remaining length. If the remainging length is at least one whole sector, we can read it faster. If not, FM can read the last partial sector in its normal fashion.

To read a sector faster, we bypass the DOS buffer. We can temporarily patch the actual destination address where the sector must go into the RWTS call block. RWTS can put the entire sector directly into its final destination, rather than into the DOS buffer to be later moved by the rather slow loop above.

The extra time saved by eliminating the middle man will save an entire revolution of the drive to get the next sector (if it is in the same track, and they usually are). A 40 sector file laid out sequentially on three tracks will save 38 revolutions of the disk. The disk spins at 5 revolutions per second, so we will save a hair over 7 seconds. (If the file is not laid out sequentially, the savings will be less.)

The bigger the file, the bigger the percentage improvement. We can save 3 seconds per track. It normally takes FM about 18 revolutions to read a track; with our patch, a track can be read in about 3 revolutions. We save 15 revolutions or 3 seconds on each full track. That is, a full track can be read in .6 seconds instead of 3.6 seconds. The rest of the time required to read the file is spent moving the head from track to track, and reading the catalog and VTOC sectors.

If all 16 sectors of a track are to be read, and if the sectors were allocated the normal DOS 3.3 way, I think this is the way it happens with my patch installed:

F     E   D   C   B   A   9   8     7   6   5   4   3   2   1     0
F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0

The bottom line of numbers shows the physical sector numbers. As you move across the page from left to right, you simulate the disk read head. It may take up to a full revolution of the disk before sector F appears, but once it does we proceed to pick off approximately every other sector as they come by. The top line of numbers shows the DOS 3.3 logical sector numbers. Logical sector E is actually physical sector 2, and so on. So it takes two full revolutions, plus two more sectors, to read all 16.

If you are trying to figure out where the rest of the time is used, keep in mind that DOS first reads the VTOC (track 17, sector 0); then the first catalog sector (track 17, sector 15); if the file specified is not in the first catalog sector, it reads another; and so on. If the file is far down in the catalog, it might have to read all 15 catalog sectors to find the file. Then the track/sector list is read; it is usually in sector 15 of the same track containing the first 15 sectors of data. On the other hand, as the disk fills up the sectors get splattered all over the disk.

Here is the patch code, arranged so that it squeezes into those two interstices I mentioned earlier:

  1000 *--------------------------------
  1010 *   S.FAST LOAD.1
  1020 *
  1030 *      FAST "LOAD" AND "BLOAD"
  1040 *
  1050 *      INSTALLED IN UNUSED AREAS IN DOS 3.3:
  1060 *          $BA69-$BA95   (45 BYTES FREE)
  1070 *          $BCDF-$BCFF   (33 BYTES FREE)
  1080 *--------------------------------
  1090 READ.RANGE          .EQ $AC96
  1100 READ.NEXT.SECTOR    .EQ $B0B6
  1110 END.OF.DATA.ERROR   .EQ $B36F
  1120 RANGE.LENGTH        .EQ $B5C1,C2
  1130 RANGE.ADDRESS       .EQ $B5C3,C4
  1140 BUFFER.ADDRESS      .EQ $B5CB,CC
  1150 SECTOR.COUNT        .EQ $B5E4,E5
  1160 BYTE.OFFSET         .EQ $B5E6
  1170 *--------------------------------
  1180        .OR $BA69
  1190        .TF B.PATCH1
  1200  
  1210 PATCH1 LDA BYTE.OFFSET       LAST BYTE OF
  1220        BNE GO.READ.RANGE     A SECTOR?
  1230        LDA RANGE.LENGTH+1    WHOLE SECTOR LEFT?
  1240        BEQ GO.READ.RANGE     NO.
  1250        LDA BUFFER.ADDRESS    SAVE BUFFER ADDRESS
  1260        PHA
  1270        LDA BUFFER.ADDRESS+1
  1280        PHA
  1290        LDA RANGE.ADDRESS     READ DIRECTLY
  1300        STA BUFFER.ADDRESS    INTO RANGE
  1310        LDA RANGE.ADDRESS+1
  1320        STA BUFFER.ADDRESS+1
  1330  
  1340 READ.LOOP
  1350        JSR READ.NEXT.SECTOR
  1360        BCS .1
  1370        JMP PATCH2
  1380 .1     JMP END.OF.DATA.ERROR
  1390  
  1400 GO.READ.RANGE
  1410        JMP READ.RANGE
  1420 *--------------------------------
  1430        .OR $BCDF
  1440        .TF B.PATCH2
  1450  
  1460 PATCH2 INC SECTOR.COUNT
  1470        BNE .1
  1480        INC SECTOR.COUNT+1
  1490 .1     INC RANGE.ADDRESS+1   NEXT PAGE
  1500        INC BUFFER.ADDRESS+1
  1510        DEC RANGE.LENGTH+1
  1520        BNE .2
  1530        PLA               RESTORE BUFFER
  1540        STA BUFFER.ADDRESS+1
  1550        PLA
  1560        STA BUFFER.ADDRESS
  1570        JMP READ.RANGE    ONE BYTE AT A TIME
  1580  
  1590 .2     JMP READ.LOOP
  1600 *--------------------------------
  1610        .LIF

To install the patches, you need to BLOAD PATCH1 and BLOAD PATCH2. Then patch locations $ACA6-7 to 69 BA, to change the JMP READ.RANGE instruction to a JMP PATCH1. Note that you must BLOAD the patches before changing $ACA6-7. If you change $ACA6-7 first, the system will crash as soon as you try to execute a BLOAD.

Here is an Applesoft program (which you could append to your HELLO program) to poke the patches into DOS.

20000  REM INSTALL FAST DOS LOAD AND BLOAD PATCHES
20010  READ N: IF N = 0 THEN  END
20020  READ A
20030  FOR I = 1 TO N: READ P: POKE A,P:A = A + 1: NEXT 
20040  GOTO 20010
20100  DATA  44,47721,173,230,181,208,36,173,194,181,
       240,31,173,203,181,72,173,204,181,72,173,195,
       181,141,203,181,173,196,181,141,204,181,32,
       182,176,176,3,76,223,188,76,111,179,76,150,172
20110  DATA  33,48351,238,228,181,208,3,238,229,181,
       238,196,181,238,204,181,206,194,181,208,11,
       104,141,204,181,104,141,203,181,76,150,172,
       76,135,186
20120  DATA  2,44198,105,186
20130  DATA  0

Paul mentioned he was working on an equally simple patch to speed up SAVE and BSAVE, but I haven't heard any more from him on that subject.


An "ORG" Macro for Self-Aligning Code Bob Sander-Cederlof

Roger Johnson (Minnesota) called a week or so ago with a plea for an easy way to make program segments align themselves automatically on page boundaries. He was writing a system to be burned into EPROM and run on another computer; it would be easier to debug in the target machine if subroutines and data blocks began on even page boundaries. There was ample room, so the wasted bytes between routines didn't bother him.

Of course, the .OR directive in the S-C Macro Assembler can easily change the origin whenever you wish, but it also changes the target address (.TA directive) or closes any open target file (.TF directive). Therefore a different approach is required.

Bill Morgan and Mike Laumer described how to do this in these pages a few months back, using the .BS directive to reserve enough bytes to reach the next page boundary. But with the help of a simple macro, we can not only make it easier to make self-aligning code: we can also make it generate error messages if the origin we try to set involves backing up over a longer-than-expected predecessor.

Here is the macro definition, and a few lines demonstrating how to call the macro:

     1000        .MA ORG
     1010        .DO *>]1
     1020  !!! ERROR: ORG ]1 RANGE CROSSED !!!
     1030        .ELSE
     1040        .BS ]1-*
     1050        .FIN
     1060        .EM
     1070 *--------------------------------
     1080        .OR $800
     1090 SAMPLE LDA $1234
     1100        RTS
     1110        >ORG $900
     1120        STA $1234
     1130        RTS
     1140        >ORG $980
     1150 DATA   .DA #1,#2,#3

Line 1110 calls the ORG macro with a parameter of "$900". This means that everywhere you find "]1" in the macro definition, the assembler will see "$900". The conditional (.DO) on line 1010 will read ".DO *>$900". Since * equals $804 at this point, it is not greater than $900. Therefore the condition is false, and the lines following line 1010 will be skipped up to line 1030 where there is an ".ELSE". The lines after 1030 through the ".FIN" on line 1050 will be assembled. Line 1040 will be assembled as ".BS $900-*", which will bump the location up to $900.

Here's how the above example assembles:

                    1000        .MA ORG
                    1010        .DO *>]1
                    1020  !!! ERROR: ORG ]1 RANGE CROSSED !!!
                    1030        .ELSE
                    1040        .BS ]1-*
                    1050        .FIN
                    1060        .EM
                    1070 *--------------------------------
                    1080        .OR $800
     0800- AD 34 12 1090 SAMPLE LDA $1234
     0803- 60       1100        RTS
     0804-          1110        >ORG $900
                    0000>        .DO *>$900
                    0000>        .ELSE
     0804-          0000>        .BS $900-*
                    0000>        .FIN
     0900- 8D 34 12 1120        STA $1234
     0903- 60       1130        RTS
     0904-          1140        >ORG $980
                    0000>        .DO *>$980
                    0000>        .ELSE
     0904-          0000>        .BS $980-*
                    0000>        .FIN
     0980- 01 02 03 1150 DATA   .DA #1,#2,#3

If we had written line 1110 as ">ORG $800" the condition on line 1010 would be true, causing line 1020 to be assembled. Line 1020 is illegal syntax for the assembler, so it will be listed after an error message. The "]1" will be filled in to make the line list like this:

     *** BAD OPCODE ERROR
      1110>  !!! ERROR: ORG $800 RANGE CROSSED !!!

That will occur during pass one of the assembly, so no code will be generated. The error message will be the only output.


New S-C Cross Reference Utility Mike Laumer

At last a Cross Reference Utility is available for the S-C Assembler that is fully compatible with the latest releases of the S-C Macro Assembler. It handles all the new directives, shows macro calls, and can even give an optional cross reference on the opcodes! It only takes a few seconds to cross reference even a huge file and begin the listing! It is even faster than the Macro Assembler in processing the source lines.

The Cross Reference Utility also can optionally print a paginated source file listing before printing the cross reference. That way you can be certain that you have a program listing with the same line numbers shown in the cross reference listing.

The price is reasonable: only $20.00 for the object code version and $50.00 for both source and object code. What other company sells source code to their utilities!


Date Processing Modules Brooke Boering
Vagabondo Enterprises

[ in printed copy, the following was an actual copy of a letter ]

VAGABONDO ENTERPRISES
1300 E. Algonquin - 3G
Schaumburg, IL 60195
(312) 397-8705

Over the past few years I have always enjoyed reading AAL and frequently found useful information. I appreciate this type of publication and hope that you will be able to continue its publication indefinitely. In my opinion, this is the "bedrock" support level for programming the Apple.

I have included a contribution for AAL that I have used with a statistical analysis system (never marketed). It's for "DATE" processing, (not "DATA"), and an overview is printed and enclosed herewith. The disk has both the source code and a "BRUNable" copy of the overview.

Again, thanks for a truly useful publication

My best,

[signed] Brooke (W. Boering)

PS.   Bill Morgan's CATALOG ARRANGER was particularly revealing of this part of DOS. Please thank him for me if convenient.

  1000 *--------------------------------
  1010 *    DATE PROCESSING MODULES
  1020 *       BY BROOKE BOERING
  1030 *--------------------------------
  1040        .OR $800
  1050 *--------------------------------
  1060 *         JUMP TABLE            *
  1070  JMP CONV1  MM/DD/YY -> STD FMT
  1080  JMP CONV2  STD FMT -> MM/DD/YY
  1090  JMP CONV3  STD FMT -> CENTURY
  1100 *           DAY & WEEKDAY CODE
  1110  JMP CONV4  KICK STD FMT DATE UP
  1120 *           (FROM 1 TO 225 DAYS)
  1130 *--------------------------------
  1140 *       MONITOR EQUATES
  1150  
  1160 COUT   .EQ $FDED
  1170 PRBYTE .EQ $FDDA
  1180 *--------------------------------
  1190 *         LOCAL EQUATES
  1200 
  1210 LOC0    .EQ $40  (A3L)
  1220 LOC1    .EQ $41  (A3H)
  1230 LOC2    .EQ $42  (A5L)
  1240 LOC3    .EQ $43  (A5H)
  1250 ACL     .EQ $50
  1260 ACH     .EQ $51
  1270 XTNDL   .EQ $52
  1280 XTNDH   .EQ $53
  1290 AUXL    .EQ $54
  1300 AUXH    .EQ $55
  1310 ANSLO   .EQ $50
  1320 PLIER   .EQ $51
  1330 CAND    .EQ $52
  1340 SAVER   .EQ $53
  1350 SLASH   .EQ $AF (/)
  1360 *--------------------------------
  1370 * - - - - LOCAL WORKING - - - - *
  1380 WKG   .HS 0000000000000000
  1390 BINYY .EQ WKG+0
  1400 BINMM .EQ WKG+1
  1410 BINDD .EQ WKG+2
  1420 CENTURY.DAY.HI  .EQ WKG+4
  1430 CENTURY.DAY.LO  .EQ WKG+5
  1440 *--------------------------------
  1450 *     USER ALTERABLE CONTROLS
  1460 
  1470 * LOWEST ACCEPTABLE YEAR
  1480 *   DEFAULT= 75
  1490 * HIGHEST ACCEPTABLE YEAR
  1500 *   DEFAULT= 84
  1510 * DAY-OF-WEEK SKIP
  1520 *   DEFAULT= SUNDAY & SATURDAY
  1530 *--------------------------------
  1540 *      CONVERT EXTERNAL FORMAT
  1550 *   MM/DD/YY TO STANDARD INTERNAL
  1560 *   FORMAT; BITS YYYYYYYMMMMDDDDD
  1570 *
  1580 * ENTRY: RA= DATA ADDRESS-LO
  1590 *        RY=   "      "  -HI
  1600 *  EXIT: CC= EQUAL IF OK 
  1610 *          RA= YYYYYYYM BYTE
  1620 *          RX= MMMMDDDD BYTE
  1630 *        CC= NEQ IF ERROR
  1635        .PG
  1640 CONV1
  1650  STA LOC2     SET INDIRECT ADDR
  1660  STY LOC3       :
  1670  LDA #0       INIT WKG
  1680  STA BINMM
  1690  STA BINDD
  1700  STA BINYY
  1710 *-- DO 'MM'
  1720  JSR GET.DOUBLE
  1730  BNE BADATE
  1740  TAY          ZERO?
  1750  BEQ BADATE
  1760  CMP #13      TOO HI?
  1770  BCS BADATE
  1780  STA BINMM    ITS OK
  1790  INC LOC2     KICK PAST '/'
  1800 *-- DO 'DD'
  1810  JSR GET.DOUBLE
  1820  BNE BADATE
  1830  TAY          ZERO?
  1840  BEQ BADATE
  1850  LDX BINMM    RX= INDEX TO LIST
  1860  DEX
  1870  CMP DAYS.COUNT,X
  1880  BCC .3       G-A IF OK
  1890  BEQ .3       G-A IF OK
  1900  CMP #29      29TH (OF FEB)?
  1910  BNE BADATE   NO, ERR!
  1920  STY BINYY    YES, SET YY-FLAG
  1930 * (ACCEPT TEMPORARILY)
  1940 .3
  1950  STY BINDD    ITS OK (PROBABLY)
  1960  INC LOC2     KICK PAST '/'
  1970 *-- DO 'YY'
  1980  JSR GET.DOUBLE
  1990  BNE BADATE
  2000  CMP OLDEST.YEAR
  2010  BCC BADATE
  2020   LDX BINYY   RX= FEB 29TH FLAG
  2030  STA BINYY    = 0YYYYYYY
  2040   BEQ .6      G-A IF NOT FEB 29
  2050  AND #$03     LEAP YEAR?
  2060  BNE BADATE   ERR IF NOT LEAPYEAR
  2070 *-- SET EXIT CONDITIONS
  2080 .6
  2090  LDA BINMM
  2100  ASL
  2110  ASL
  2120  ASL
  2130  ASL
  2140  ASL
  2150  ORA BINDD
  2160  TAX          RX= MMMDDDDD
  2170  LDA BINYY
  2180  ROL          RA= YYYYYYYM
  2190  LDY #0       EXIT OK
  2200  RTS
  2210 
  2220 BADATE
  2230  LDY #$FF     DATE ERROR EXIT
  2240  RTS
  2245        .PG
  2250 *********************************
  2260 * S/R TO GET NEXT DOUBLE DIGIT
  2270 *   (MAINLY USED FOR DATE INPUT)
  2280 * ENTRY: LOC2/3= DATA ADDRESS
  2290 GET.DOUBLE
  2300  LDY #0
  2310  LDA (LOC2),Y
  2320  TAX          RX= TENS DIGIT
  2330  INC LOC2
  2340  LDA (LOC2),Y RA= UNITS DIGIT
  2350  INC LOC2
  2360  JSR ASC2BIN
  2370 * (CC= ERROR STATUS; PASS BACK)
  2380  RTS
  2390 *********************************
  2400 * S/R TO CONVERT 2 ASCII DIGITS
  2410 *   TO SINGLE BINARY BYTE
  2420 *
  2430 * ENTRY: RA= UNITS ASCII DIGIT
  2440 *        RX= TENS ASCII DIGIT
  2450 *
  2460 *  EXIT: CC= EQUAL IF OK
  2470 *          RA= BINARY EQUIV
  2480 *        CC= NEQ IF NON DIGIT
  2490 ASC2BIN
  2500  STA LOC1     (SAVE TEMP)
  2510  TXA          RA= TENS
  2520  CMP #0
  2530  BCC NOTNUM
  2540  CMP #10
  2550  BCS NOTNUM
  2560  AND #$0F
  2570  BEQ .4
  2580  TAX
  2590  LDA #0
  2600  CLC
  2610 .3
  2620  ADC #10
  2630  DEX
  2640  BNE .3
  2650 .4
  2660  STA LOC0
  2670  LDA LOC1     RA= UNITS
  2680  CMP #0
  2690  BCC NOTNUM
  2700  CMP #10
  2710  BCS NOTNUM
  2720  AND #$0F
  2730  CLC
  2740  ADC LOC0
  2750  LDX #0       SET EXIT= OK
  2760  RTS
  2770 
  2780 NOTNUM
  2790  LDX #$FF
  2800  RTS
  2805        .PG
  2810 *--------------------------------
  2820 *      CONVERT STANDARD INTERNAL
  2830 *   DATE FORMAT, YYYYYYYMMMMDDDDD
  2840 *   TO EXTERNAL FORMAT MM/DD/YY.
  2850 *
  2860 * ENTRY: RA= HI BYTE (YYYYYYYM)
  2870 *        RX= LO BYTE (MMMDDDDD)
  2880 *        CV/CH PRESUMED PRESET
  2890 CONV2
  2900 *-- EXPLODE TO BINYY,BINMM,BINDD
  2910  JSR EXPLODE.STANDARD.FORMAT
  2920  LDA BINMM
  2930  JSR DATE.MM  PRINT MM
  2940  LDA #SLASH   PRINT '/'
  2950  JSR COUT
  2960  LDA BINDD
  2970  JSR DATE.DD  PRINT DD
  2980  LDA #SLASH   PRINT '/'
  2990  JSR COUT
  3000  LDA BINYY
  3010  JSR DATE.YY  PRINT YY
  3020  RTS
  3030 *********************************
  3040 * S/R TO CONVERT YY BYTE TO DECI-
  3050 *   MAL, THEN TO ASCII & DISPLAY.
  3060 DATE.YY
  3070  CMP #100     OVFLO PROTECT
  3080  BCC .4         :
  3090  LDA #99        :
  3100 .4
  3110  JMP DATE.DD  GOTO COMMON
  3120 *********************************
  3130 * S/R TO CONVERT MM BYTE TO DECI-
  3140 *   MAL, THEN TO ASCII & DISPLAY.
  3150 DATE.MM
  3160  CMP #12      OVFLO PROTECT
  3170  BCC .4         :
  3180  LDA #12        :
  3190 .4
  3200  JMP DATE.DD  GOTO COMMON
  3210 *********************************
  3220 * S/R TO CONVERT DD BYTE TO DECI-
  3230 *   MAL, THEN TO ASCII & DISPLAY.
  3240 DATE.DD
  3250  LDX #0      RX= 10'S CTR
  3260 .2
  3270  CMP #$A     < 10 ?
  3280  BCC .3      YES, JUMP OUT
  3290  SEC
  3300  SBC #$A     MINUS 10
  3310  INX         KICK 10'S CTR
  3320  BNE .2      LOOP BACK
  3330 *JMP^^^
  3340 .3
  3350  STA LOC0    SAVE TEMP
  3360  TXA         GET 10'S CTR
  3370  ASL         POSN HI
  3380  ASL           :
  3390  ASL           :
  3400  ASL           :
  3410  ORA LOC0    'OR' TOGETHER
  3420  JMP PRBYTE  PRINT IT
  3430 *RTS*
  3435        .PG
  3440 *--------------------------------
  3450 *     CONVERT STANDARD FORMAT TO
  3460 *     CENTURY DAY & WEEKDAY CODE
  3470 *
  3480 * ENTRY: RA= YYYYYYYM
  3490 *        RX= MMMMDDDD
  3500 *
  3510 *  EXIT: RA= CENTURY DAY (HI)
  3520 *        RX= CENTURY DAY (LO)
  3530 *        RY= WEEKDAY CODE
  3540 *          1= MONDAY
  3550 *          2= TUESDAY
  3560 *          3= WEDNESDAY
  3570 *          4= THURSDAY
  3580 *          5= FRIDAY
  3590 *          6= SATURDAY
  3600 *          7= SUNDAY
  3610 *          0= UNKNOWABLE
  3620 CONV3
  3630 *-- EXPLODE TO BINYY,BINMM,BINDD
  3640  JSR EXPLODE.STANDARD.FORMAT
  3650 *-- CALCULATE DAYS OF PRIOR YEARS
  3660  LDY BINYY        STORE 256 DAYS
  3670  DEY                : FOR EACH
  3680  STY CENTURY.DAY.HI : PRIOR YEAR
  3690  TYA              STORE 1 DAY
  3700  LSR                : FOR EACH
  3710  LSR                : PRIOR
  3720  STA CENTURY.DAY.LO : LEAP YEAR
  3730  LDA #109         STORE 109 DAYS
  3740  JSR MULTIPLY.8X8   : FOR EACH
  3750  CLC          A     : PRIOR
  3760  ADC CENTURY.DAY.LO : YEAR
  3770  STA CENTURY.DAY.LO :
  3780  TYA                :
  3790  ADC CENTURY.DAY.HI :
  3800  STA CENTURY.DAY.HI :
  3810 
  3820 *-- CALCULATE DAYS OF THIS YEAR
  3830   LDY BINDD   RY= DD
  3840  TYA          (IN CASE WAS JAN)
  3850  LDX BINMM    RX= MM
  3860  DEX          RX= MM-1
  3870  BEQ .7       G-A IF WAS JAN
  3880  CPX #1
  3890  BEQ .3       G-A IF WAS FEB
  3900  LDA BINYY    (WAS MAR - DEC)
  3910  AND #$03     LEAP YEAR?
  3920  BNE .3       NO, G-A
  3930  INY          YES, KICK DAY CTR
  3940 .3
  3950  TYA          RA= DD (OR DD+1)
  3960 .4
  3970  CLC          ADD A MONTH'S DAYS
  3980  ADC DAYS.COUNT-1,X :
  3990  BCC .5       G-A IF > 255 DAYS
  4000  INC CENTURY.DAY.HI
  4010 .5
  4020  DEX          DECR CTR
  4030  BNE .4       LOOP TIL DONE
  4035        .PG
  4040 .7
  4050 *-- ADD THIS YEAR'S DAYS
  4060 *     TO PRIOR YEARS' DAYS
  4070 *RA= DAYS THIS YEAR
  4080  CLC
  4090  ADC CENTURY.DAY.LO  :
  4100  STA CENTURY.DAY.LO  :
  4110  BCC .8              :
  4120  INC CENTURY.DAY.HI  :
  4130 .8
  4140 *-- CALCULATE WEEKDAY CODE
  4150  TAX          RX= CENTURY.DAY.LO
  4160  LDA CENTURY.DAY.HI
  4170  JSR GET.WEEKDAY
  4180 *             RY= WEEKDAY CODE
  4190  RTS
  4200 *********************************
  4210 *    CALCULATE WEEKDAY CODE FROM
  4220 *    CENTURY DATE
  4230 *
  4240 * ENTRY: RA= CENTURY DATE-HI
  4250 *        RX= CENTURY DATE-LO
  4260 *
  4270 *  EXIT: RA/RX= AS ON ENTRY
  4280 *        RY= WEEKDAY CODE
  4290 *          1= MONDAY
  4300 *          2= TUESDAY
  4310 *          3= WEDNESDAY
  4320 *          4= THURSDAY
  4330 *          5= FRIDAY
  4340 *          6= SATURDAY
  4350 *          7= SUNDAY
  4360 *          0= UNKNOWABLE
  4370 GET.WEEKDAY
  4380  STA ACH
  4390  STX ACL
  4400  PHA          SAVE RA
  4410  TXA          SAVE RX
  4420  PHA            :
  4430  LDA #0
  4440  STA XTNDH    SET DIV'D (HIHI)
  4450  STA XTNDL    SET DIV'D (LOLO)
  4460  STA AUXH     SET DIVISOR(LO)
  4470  LDA #7       SET DIVISOR(HI)
  4480  STA AUXL       :
  4490  LDY #8       SET FOR 8BIT DIVSR
  4500  JSR DIVIDE.32X16
  4510  LDA XTNDL
  4520  CLC          REMAINDER + WEEKDAY
  4530  ADC #0       : OF 12/31/1900
  4540   TAY         (PRESET)
  4550  SEC    
  4560  SBC #7
  4570  BCC .4       G-A IF RY OK
  4580   TAY         (RESET)
  4590 .4
  4600  INY          ADJ: ANS+1 = CODE
  4610  PLA          RESTORE RA/RX
  4620  TXA            :
  4630  PLA            :
  4640  RTS
  4645        .PG
  4650 *--------------------------------
  4660 *     ADD FROM 1 TO 225 DAYS TO
  4670 *     A GIVEN STD FORMAT DATE
  4680 *
  4690 * ENTRY: RA= YYYYYYYM
  4700 *        RX= MMMMDDDD
  4710 *        RY= # DAYS TO ADD
  4720 *  EXIT: RA/RX UPDATED
  4730 CONV4
  4740 *-- SAVE RY TO STACK
  4750  STA LOC0
  4760  TYA
  4770  PHA
  4780  LDA LOC0
  4790 *-- EXPLODE TO BINYY,BINMM,BINDD
  4800  JSR EXPLODE.STANDARD.FORMAT
  4810 *-- INIT FOR LOOP
  4820  PLA          = # DAYS TO KICK
  4830  CLC
  4840  ADC BINDD    RA= WKG CTR
  4850  LDX BINMM    RX= WKG MM
  4860 .2
  4870 * IN THIS LOOP:
  4880 *   RY= UTILITY REGISTER
  4890 *   RX= WKG MM TO BE INCREMENTED
  4900 *   RA= WKG CTR TO BE DECREMENTED
  4910 * LOC3= WKG DAY COUNT FOR THE
  4920 *       CURRENT MM (IN RX)
  4930   LDY DAYS.COUNT-1,X
  4940   STY LOC3    = MM'S DAY COUNT
  4950  CPX #2       IS MM FEB?
  4960  BNE .4       NO, G-A
  4970 *-- DO FEB
  4980  PHA          SAVE WKG CTR
  4990  LDA BINYY
  5000  AND #$03     LEAP YEAR?
  5010  BNE .3       NO, G-A
  5020  LDA #29      RESET DAY COUNT
  5030  STA LOC3     :
  5040 .3
  5050  PLA          RESTORE WKG CTR
  5060 .4
  5070  CMP LOC3
  5080  BCC .7       G-A IF DONE
  5090  BEQ .7       : (ALSO DONE)
  5100  SEC          WKG CTR MINUS
  5110  SBC LOC3     : WKG DAY COUNT
  5120  INX          MM+1
  5130  CPX #13      OVFLO?
  5140  BCC .2       NO, LOOP BACK
  5150  LDX #1       YES, SET MM= JAN
  5160  INC BINYY    : AND SET YY+1
  5170  JMP .2       : AND LOOP BACK
  5180 .7
  5190  STA BINDD
  5200  STX BINMM
  5210  JSR IMPLODE.STANDARD.FORMAT
  5220  RTS
  5225        .PG
  5230 *********************************
  5240 * S/R TO EXPLODE STD FORMAT TO
  5250 *   BINYY, BINMM & BINDD
  5260 * ENTRY: RA= YYYYYYYM
  5270 *        RX= MMMMDDDD
  5280 *  EXIT: BINYY,BINMM,BINDD SET
  5290 EXPLODE.STANDARD.FORMAT
  5300  LSR          RA= 0YYYYYYY CC=M
  5310  STA BINYY
  5320  TXA          RA= MMMDDDDD
  5330  PHA         SAVE MMMDDDDD
  5340  ROR          RA= MMMMDDDD
  5350  LSR              0MMMMDDD
  5360  LSR              00MMMMDD
  5370  LSR              000MMMMD
  5380  LSR              0000MMMM
  5390  STA BINMM
  5400  PLA         PULL MMMDDDDD
  5410  AND #$1F     RA= 000DDDDD
  5420  STA BINDD
  5430  RTS
  5440 *********************************
  5450 * S/R TO IMPLODE BINYY, BINMM &
  5460 *   BINDD TO STD FORMAT
  5470 * ENTRY: BINYY,BINMM,BINDD PRESET
  5480 *  EXIT: RA= YYYYYYYM
  5490 *        RX= MMMMDDDD
  5500 IMPLODE.STANDARD.FORMAT
  5510  LDA BINMM    RA= 0000MMMM
  5520  ASL              000MMMM0
  5530  ASL              00MMMM00
  5540  ASL              0MMMM000
  5550  ASL              MMMM0000
  5560  ASL              MMM00000 (CC=M)
  5570  ORA BINDD        MMMDDDDD
  5580  TAX          RX= MMMDDDDD (CC=M)
  5590  LDA BINYY    RA= 0YYYYYYY (CC=M)
  5600  ROL          RA= YYYYYYYM
  5610  RTS
  5620 *********************************
  5630 
  5640 OLDEST.YEAR
  5650  .DA #75
  5660 HIGHEST.YEAR
  5670  .DA #84
  5680 DAYS.COUNT
  5690  .DA #31 (JAN)
  5700  .DA #28 (FEB)
  5710  .DA #31 (MAR)
  5720  .DA #30 (APR)
  5730  .DA #31 (MAY)
  5740  .DA #30 (JUN)
  5750  .DA #31 (JUL)
  5760  .DA #31 (AUG)
  5770  .DA #30 (SEP)
  5780  .DA #31 (OCT)
  5790  .DA #30 (NOV)
  5800  .DA #31 (DEC)
  5805        .PG
  5810 *********************************
  5820 *
  5830 *       8 X 8 MULTIPLY
  5840 *
  5850 *  ENTRY: RY= MULTIPLCAND
  5860 *         RA= MULTIPLIER
  5870 *
  5880 *   EXIT: RY= ANSWER-HI
  5890 *         RA= ANSWER-LO
  5900 *
  5910 *  TIMING: 212 US - MAX
  5920 *          180 US - MIN
  5930 *          192 US - AVER
  5940 * NOTE: KEEP CLOSE TO SGN8X8
  5950 MULTIPLY.8X8
  5960  STA PLIER   SAVE (MULTI)PLIER
  5970  STY CAND    SAVE (MULTIPL)CAND
  5980  LDA #0      RA= ANSWER-HI
  5990  LDY #8      SET 8-BIT CTR
  6000 MUL1
  6010  LSR PLIER   TEST NEXT BIT
  6020  BCC MUL2    IF OFF, GO ROUND
  6030  CLC
  6040  ADC CAND    IF ON, ADD
  6050 MUL2
  6060  ROR         SHIFT ANSWER 1 BIT
  6070  ROR ANSLO   :
  6080  DEY         DECR POSITION CTR
  6090  BNE MUL1    LOOP TIL DONE 8 BITS
  6100  TAY         RY= ANSWER-HI
  6110  LDA ANSLO   RA= ANSWER-LO
  6120  RTS
  6130 *********************************
  6140 *
  6150 *        32 X 16 DIVIDE
  6160 *
  6170 *  PRE-ENTRY:
  6180 *    DIVIDEND IN:
  6190 *      XTNDH,XTNDL,ACH,ACL
  6200 *    DIVISOR --> AUXL,AUXH
  6210 *
  6220 *   EXIT: QUOTIENT -> ACL,ACH
  6230 *    REMAINDER -> XTNDL,XTNDH
  6240 DIVIDE.32X16
  6250  LDY #$10      INDEX FOR 16 BITS
  6260 .2
  6270  ASL ACL
  6280  ROL ACH
  6290  ROL XTNDL     XTND/AUX
  6300  ROL XTNDH     : -> ACCUM
  6310  SEC
  6320  LDA XTNDL
  6330  SBC AUXL      MOD TO XTND.
  6340  TAX
  6350  LDA XTNDH
  6360  SBC AUXH
  6370  BCC .3
  6380  STX XTNDL
  6390  STA XTNDH
  6400  INC ACL
  6410 .3
  6420  DEY
  6430  BNE .2
  6440  RTS
  6450 *********************************

The Apple ][ Circuit Description: A Review Bill Morgan

"Have you ever wanted to know the detailed circuit operation of your Apple ][ computer? Perhaps you were designing a peripheral or making a modification. Maybe you were repairing an Apple. You may have just been curious about how it works."

That's the first paragraph of a new book called The Apple ][ Circuit Description, by Winston D. Gayler. If the answer to that question is "yes", you need to look at this book. Circuit Description contains about 160 pages of text describing the operation of every component on the Apple's motherboard and keyboard. There are also 44 large fold-out pages of easy-to- read block diagrams, schematics, timing diagrams, and waveform drawings. The enlarged, readable schematics alone will be worth the price of the book to some users!

One of the first things Mr. Gayler handles is identifying the various revisions of the Apple ][, from the original Rev. 0 through last year's RFI treated motherboard, Rev. D. The body of the book covers that last version, while an appendix goes into the differences in all earlier revisions, and the diagrams show all revisions. The very latest thing, the Apple //e, is not mentioned, since that's a radical departure from all others.

The book is intended for engineers, technicians, students, and serious hobbyists. The descriptions, schematics, timing diagrams, and waveform drawings can be an invaluable help in designing peripherals and modifications, troubleshooting, studying practical circuit design, and just understanding how your Apple works.

Each chapter has two sections, Overview, and Detailed Circuit Description. You can cruise the Overview sections to get an idea of what's going on in each piece of your Apple, or you can sit down with the Detailed Circuit Description, the schematics, your Apple, and your TTL Data Book, and figure out each and every signal in the computer.

Here is a chapter-by-chapter summary:

1. Introduction and overview of the book.

2. Block-diagram discussion of the whole computer's structure, introducing concepts like "address multiplexer" and "video address generator". Apple's unique patented power supply is also covered here.

3. Clocks: the master oscillator, clock generator, and the horizontal portion of the video address generator. Clocks are especially important in the Apple due to their interplay with the video circuitry.

4. The vertical portion of the video address generator and the sync, blanking, and color burst signals.

5. RAM memory, the 4116's and their addressing, as well as the shared access scheme for the video memory.

6. The 6502 processor and its internal cycles, including read cycles, write cycles, RAM and ROM cycles, I/O and keyboard cycles, interrupts, and DMA (direct memory access).

7. On-board I/O devices, including cassette I/O, the game port, the speaker, and the current two-piece keyboard.

8. Video generator hardware, how it creates TEXT, LORES, and HIRES displays under software control.

Appendices:

A. Introduction to standard video signal techniques, for those of us who know even less about video than about digital.

B. Various revisions of the Apple motherboard. The main text of the book describes the RFI, Rev. D board. This appendix covers the differences in all earlier boards, as well as the old one-piece keyboard.

C. Schematics. Pages and pages of enlarged diagrams of all versions of the motherboard and keyboards.

In the Introduction, Gayler says that the reader should be familiar with TTL (gates, flip-flops, shift registers, and multiplexers) and should have a basic knowledge of micro- processor and microcomputer architecture. Well, I have a very basic knowledge of architectures, and almost no familiarity with TTL details. This book looks like it will be a great tool for learning about TTL, because I will be able to relate what the data books say about a chip to a knowledge of what that chip is doing in my very own Apple.

One thing I would like to see is a sort of cross-reference by motherboard coordinate. It would be nice to be able to ask the book "What is the function of that 74LS20 at location D2?" As it is, I had to look through several foldouts for a chip symbol labelled "D2". It is a NAND gate in "Fig. C-2. Clock Generator (all revisions)" Since it's part of a clock circuit, it must be covered in chapter 3. Several minutes of poking around in chapter 3 tells me that chip is part of one of the Apple's most unique features! Every 65th CPU cycle is slightly stretched (1117 us vs. 978 us) to maintain sync with the color signals, and D2 is responsible for triggering that stretch.

That last paragraph started out to describe a shortcoming of the book, and turned into yet another example of the kind of great information contained in The Apple ][ Circuit Description. If you're doing any hardware work with the Apple, or if you want to learn more about what's going on in there, you need this book.

The Apple ][ Circuit Description, by Winston D. Gayler. Published by Howard W. Sams. 8 1/2 by 11 comb binding. 172 pp. text, 44 fold-out diagrams. Shipping weight 3 lbs. List price is $22.95, our price will be $21 + shipping ($2 domestic, $12 overseas).


New Version of DOS -- Patchers Beware

When Apple released the //e they apparently also slipped in a slightly revised version of DOS, called DOS 3.3e (or 3.3c. Reports differ.) The following information about the changes is from Tom Weishaar's DOStalk column in the April issue of Softalk.

The boot routine now throws a couple of new soft switches ($C00C and $C00E) and stores $FF in location $4FB. These steps turn off the //e's 80-column mode during boot-up.

A routine at $B331 that calculates position in a random access file is now simplified.

Now for the biggie: Another APPEND fix! (attempted) According to Weishaar, they eliminated a bug that occurred maybe once in 10,000 tries by introducing a new bug that bites once every 256 calls. Tom says that the most reliable method is to use the old DOS 3.3 and POKE -18851,0 before each APPEND.

The most significant thing about the APPEND change is where they put the patch: at $BA69! That used to be empty space and a popular place to install patches. No more! As a matter of fact, Bob's Fast Load patch in this issue goes into that area, and therefore should not be used with DOS 3.3e.

This means that //e users should be especially careful about installing published patches into DOS 3.3e, and all of us should quit using $BA69-BA95 for patches that will be distributed.


PATCHER: A General-Purpose Patch Installer Bill Morgan

My favorite new feature in Version 1.1 of the S-C Macro Assembler is the .PH directive. When Bob first described the new directive to me, I didn't quite see how to use it. Then he showed me a program like this one, and now I don't see how I did without it!

The directive .PH <expr> in an assembly causes the origin to be reset to <expr>, but the code continues to be stored in successive bytes of the same area as before. The result is much like the following lines all rolled into one:

    2000 LABEL
    2010        .OR SOMEWHERE.ELSE
    2020        .TA LABEL

The difference is that the above lines would close an open Target File, whereas .PH SOMEWHERE.ELSE continues to direct code into the same file. The end of an offset block is marked with a .EP directive, that restores the origin to match the target address.

With this feature is so easy to assemble one program to create some patches and move them into place, all in one step. Anyway, here's the general purpose PATCHER, with some dummy code to show it off.

  1000 *SAVE S.PATCHER
  1010 *--------------------------------
  1020 PNTR   .EQ $00,01
  1030 PATCH  .EQ $02,03
  1040 *--------------------------------
  1050        .OR $300
  1060        .TF B.PATCHER
  1070 *--------------------------------
  1080 PATCHER
  1090        LDA #PATCHES-1
  1100        STA PNTR
  1110        LDA /PATCHES-1
  1120        STA PNTR+1
  1130        LDY #0
  1140  
  1150 .1     JSR GET.BYTE LENGTH OF NEXT PATCH
  1160        BEQ .4       FINISHED
  1170        TAX          SAVE LENGTH IN X
  1180        JSR GET.BYTE ADDRESS OF PATCH
  1190        STA PATCH
  1200        JSR GET.BYTE
  1210        STA PATCH+1
  1220  
  1230 .2     JSR GET.BYTE
  1240        STA (PATCH),Y
  1250        INC PATCH
  1260        BNE .3
  1270        INC PATCH+1
  1280 .3     DEX
  1290        BNE .2
  1300        BEQ .1    ...ALWAYS
  1310  
  1320 .4     RTS
  1330 *--------------------------------
  1340 GET.BYTE
  1350        INC PNTR
  1360        BNE .1
  1370        INC PNTR+1
  1380 .1     LDA (PNTR),Y
  1390        RTS
  1400 *--------------------------------
  1410 P1.ORIGIN .EQ $1000
  1420 P2.ORIGIN .EQ $2000 
  1430 P3.ORIGIN .EQ $3000
  1440  
  1450 *  OTHER .EQUATES HERE
  1460  
  1470 *--------------------------------
  1480 PATCHES
  1490  
  1500        .DA #P1.LENGTH,P1.ORIGIN 
  1510        .PH P1.ORIGIN
  1520  
  1530 PATCH1
  1540 *      PATCH1 CODE HERE 
  1550        JMP PATCH2
  1560  
  1570 P1.LENGTH .EQ *-PATCH1
  1580        .EP
  1590 *--------------------------------
  1600        .DA #P2.LENGTH,P2.ORIGIN 
  1610        .PH P2.ORIGIN 
  1620  
  1630 PATCH2
  1640 *      PATCH2 CODE HERE 
  1650        JMP PATCH3
  1660  
  1670 P2.LENGTH .EQ *-PATCH2
  1680        .EP 
  1690 *--------------------------------
  1700        .DA #P3.LENGTH,P3.ORIGIN 
  1710        .PH P3.ORIGIN 
  1720  
  1730 PATCH3
  1740 *      PATCH3 CODE HERE 
  1750        JMP PATCH1
  1760  
  1770 P3.LENGTH .EQ *-PATCH3 
  1780        .EP
  1790 *--------------------------------
  1800        .DA #0      END OF PATCHES
  1810 *--------------------------------
  1820        .DO *>$3D0
  1830  !!! PATCHER IS TOO BIG !!!
  1840        .FIN

Notice that the object code columns show the bytes to be all over pages 3, 10, 20, and 30. The labels in the Symbol Table show the same thing. But, if you look around in memory, all this is in page 3. Once you type $300G, the JMP instructions will be moved to their true destinations.

Bob's DOS Fast Load patches elsewhere in this issue are an ideal example of how to use PATCHER. Here's all it takes:

1> Make the following changes to lines 1410-1430 of PATCHER:

     1410 P1.ORIGIN .EQ $BA69
     1420 P2.ORIGIN .EQ $BCDF
     1430 P3.ORIGIN .EQ $ACAF

2> Substitute Lines 1090-1160 of Fast Load for Line 1450 of PATCHER.

3> Substitute Lines 1210-1410 of Fast Load for Lines 1530-1550 of PATCHER.

4> Substitute Lines 1460-1590 of Fast Load for Lines 1630-1650 of PATCHER.

5> And substitute the following line for Lines 1740-1750 of PATCHER:

             .DA PATCH1

Now you have a BRUNnable program which will quickly install the Fast Load patches into DOS. And if you want to add other DOS patches to the same program, just tack them in between lines 1790 & 1800.

If you want to patch something running in a RAM card, like the Macro Assembler, you just need to add the following lines:

    1082        LDA $C083
    1084        LDA $C083

    1315 .4     LDA $C080
    1320        RTS

And that's how I expect to handle patches from now on. Hope you find it useful!


More about the PRAWM Board Bob Sander-Cederlof

Advanced Peripheral Enterprises has introduced their PRAWM board, and is advertising elsewhere in this issue of AAL.

The PRAWM board contains from 2K to 8K of EEPROM. Data or programs can be written into the memory on the card, just as though it were RAM. Yet the memory is non-volatile, as in ROM, PROM, or EPROM. If you turn of your Apple, remove the card, ship it around the world...when you plug it back in the bytes will still be there!

EEPROM stands for "Electrically Eraseable PROM"; circuitry on the card allows you to individually write any bytes you wish, without erasing the rest of the memory. You do not need a separate EPROM programmer and ultraviolet EPROM eraser. There are no batteries either. The card is priced about the same as an EPROM card, but you save a lot of money on accessories. You will also save a lot of time, since you don't have to erase for 30-60 minutes, program chips for 5-20 minutes, and plug and unplug countless times. (You can program the entire 8K on a fully loaded PRAWM board in less than 25 seconds!)

The PRAWM card contains from 1 to 4 EEPROM chips, providing from 2K to 8K bytes. Each chip maps into the address space from $C800-$CFFF, and is accessed by switching in one chip at a time. On-board firmware makes it easy to move blocks of data between any chip and RAM.

By installing a jumper strap, you can even have the program stored in the first 2K chip automatically start up when you turn on your Apple, before or instead of booting a floppy. Just think of the possibilities: set up special commands, execute security procedures, power fail recovery, "boot" a mini-DOS of your own creation from PRAWM, eliminate the need for disk drives in turn-key monitoring applications...! Other strap options allow you to write-protect the board and to disable the $CFFF de-select function.

If you do a lot of development work involving EPROMs now, I think this card would be a big help. See Advanced Peripheral Enterprises' ad for price and ordering information.


FLASH! Compiler note Mike Laumer

The FLASH! Integer Basic Compiler was recently reviewed by PEELINGS magazine and received an A+. It is currently the highest rated Integer compiler (the competition is rated only A). The price? Just $79.00 ($70 less than the competition)!


S-C Word Processor note Mike Laumer

We recently had one customer give us a great compliment on the S-C Word Processor. He has given up on WORDSTAR! He found that the S-C Word Processor can read and write large text files 20 times faster than WORDSTAR and that scrolling was much quicker. He can be in and out of the S-C Word Processor before WORDSTAR even lets him type a single key. The S-C Word Processor is also much less expensive than WORDSTAR and you don't have to buy a Z-80 card!

His only desire was to have an 80 column version of the Word Processor. However, that wouldn't be nearly so fast since SCWP re-writes the screen on every keystroke. I have noticed also that the 40 column display never causes me eye strain, but all the 80 column displays do.


Full Screen Editor for S-C Macro Assembler Bill Morgan

Laumer Research has recently introduced a new utility for the S-C Macro Assembler. This month seems to be the time for new utilities.

The Full Screen Editor is used with a language card and a 48K Apple. It runs in the spare 4K memory bank of a language card and is entered from the S-C Macro Assembler by typing "/" optionally followed by a line number. The neat thing is that all of the assembler regular editing commands COPY, REPlace, EDIt, FINd etc. are also availiable at the same time. It is almost a Macro Assembler Upgrade by itself.

It functions similar to the EDIt command in the macro assembler except that you can move forward and backward though the lines with cursor moves or move with paging keys a whole screen at a time. One intresting new edit command is control-C which can copy characters from the line above the cursor to the next tab stop of the current line. What a handy feature! How many times have you had to comment a routine that had no comments in it? With a control-W key a new left margin can be set at the comment area so every time you type the RETURN key you are all set to type the next comment line. This makes commenting a routine is as easy as eating apple pie!

The Screen Editor really cleans up a display because long lines are not wrapped arround on the display. Instead they are shown in a "window" on the display and the window can be moved up and down though a file and left or right to view long lines. As you type over the right side of the screen the "window" tracks over to always keep the cursor in the "window" of the screen.

It is very fast! Flipping though the pages of a source file to the routine you want to look at is just a few taps of a key. I hardly ever use the LISt command any more because the full screen editor is so easy to use: "/2400" for example will enter the editor and move to line 2400 at the top of the display.

For my own use I have made a Macro Assembler diskette that I boot on when I need the assembler. It loads up the Assembler and Screen Editor at the same time and applies several of the more useful patches published in the Apple Assembly Line for the Macro Assembler. An EXEC file is provided on the program diskette which can load the screen editor in to the langauge card from the assembler.

One of the most unusual features of the Screen Editor is that it comes with a SYSGEN program to help you create different customized versions of the screen editor for STB80 or VIDEX 80 column cards or the regular 40 column Apple II display. This keeps a user from performing a complicated series of BLOADs, POKEs and BSAVEs to modify the tab tables, screen width, margin settings and scroll values.

Some of the parameter settings are settable within the editor while you are editing like tab stops and the left margin. Others however are not accessable without re-running the Applesoft SYSGEN program and thats somewhat of a problem. I can't complain too much though because the source code comes with it and I can make it do anything extra that I want it to.

The Screen Editor can be used with the S-C Macro Cross Assemblers except for the 68000 version. Only the Z-80 cross assembler requires a slight adjustment to the small 20 byte patch for the "/" command. Provided with the program diskette is a tidy 9 page manual that describes the Screen Editor features and the patches to the assembler required.

We only have one machine here at S-C Software with an 80 column board but we use the Screen Editor mostly with the regular Apple II driver module. Bob S-C is still holding out on using it but the rest of us counted how many times we typed the LISt command and decided to screen edit instead. The Full Screen editor does for S-C Macro Assembler programmers what ES-CAPE does for Applesoft programmers. They both make my job a lot easier!

The price for this little jem is $49.00 for both source and object code.


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