Volume 3 -- Issue 7 | April 1983

In This Issue...

- Patch DOS 3.3 for Fast LOAD and BLOAD
- An "ORG" Macro for Self-Aligning Code
- New S-C Cross Reference Utility
- Date Processing Modules
- The Apple ][ Circuit Description (Review)
- New Version of DOS -- Patchers Beware
- PATCHER: A General-Purpose Patch Installer
- More About the PRAWM Board
- FLASH! Compiler note
- S-C Word Processor note
- Full Screen Editor for S-C Macro Assembler

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