Volume 6 -- Issue 5 | February 1986

In This Issue...

- WildCAT for DOS 3.3
- Mitsubishi 50740 Series Microprocessors
- Faster Cyclic Redundancy Checking
- Correction to Fast Garbage Collection
- DOS Patch: Prevent Direct Commands

Bag of Tricks 2

You've been asking when Bag of Tricks, that very popular and useful disk utility package, will be updated for ProDOS. Well, you can relax now: it's here.

The new ZAP program in "Bag of Tricks 2" adds the ability to access ProDOS blocks, directories, and files; the 80-column display can show most of a block at one view. The new version of FIXCAT can reconstruct a blown ProDOS directory, as far as is possible. You do still need to follow up with ZAP to correct things like file size and load address, which completely disappear when a directory is damaged.

This new, non-copy-protected edition of an old friend costs $49.95, or $45 + shipping from S-C. Owners of the older Bag of Tricks can get an upgrade directly from Quality Software for only $20 by returning your original disk.

Correction to Day of Week Programs

On page 20 of the December 1985 AAL, change lines 130 and 140 to the following: 130 FOR I=0 TO 11 : READ MD(I) : NEXT 140 FOR I=0 TO 6 : READ D$(I) : NEXT

On page 24, same issue, change line 120 to: 120 FOR I=0 TO 6 : READ D$(I) : NEXT

That's what we get for typing a program into the Word Processor rather than printing a LISTing!

WildCAT for DOS 3.3 | Erv Edge

WildCAT is a series of patches to DOS 3.3 which modify the CATALOG command. The new features include:

- A catalog by "wildcard" FILENAME facility.
- A catalog by FILETYPE facility.
- An alternate, short-form: either DIR or CAT.
- Catalog free space patch.
- Ctrl-Q catalog abort.
- TYPE a random or sequential text file.

Lee Reynold's FILEDUMP command has been re-packaged and re-presented as TYPE (see Call-A.P.P.L.E. 6/82 p47). More on this later. WildCAT, along with TYPE, is an attempt to teach new tricks to an old dog, as it were.

The normal DOS CATALOG command allows slot, drive, and volume parameters. I have added a filename parameter, but process it a little differently than the way file names are usually processed. To display the catalog entries for all files whose names contain a particular string, type any of the following:

       CATALOG ^string [,Dn] [,Sn] [,Vn]
       DIR ^string [,Dn] [,Sn] [,Vn]
       CAT ^string [,Dn] [,Sn] [,Vn]

where "^string" begins with the "^" or caret symbol (shifted N on the ][+ or shifted 6 on the //e or //c); the string should contain no blanks, although it may "end" with them; the string would normally end with a carriage return or with a comma if a drive or slot number is specified. Only those files that contain the "string" somewhere in the filename will be listed. (Of course you already know that the D, S, and V parameters are shown in brackets above because they are optional; you do not type the brackets.)

For example, "CATALOG ^TEST" would list each file with 'TEST' as part of the filename; while "DIR ^PAY." would list those with 'PAY.' somewhere in the filename; and "CAT^.OBJ,D2" would list filenames on drive 2 that contain the partial string '.OBJ'. "CAT" and "DIR" are simply synonyms for "CATALOG".

I have also arranged things so you can list the catalog entries of a specified file-type. You simply type the file type code in the CATALOG command:

       CATALOG t [,Dn] [,Sn] [,Vn]
       DIR t [,Dn] [,Sn] [,Vn]
       CAT t [,Dn] [,Sn] [,Vn]

where "t" is any of the unadorned, single-letter filetypes: A B I R S T. Only that type of file (if present) will be listed.

For example, "CATALOG T" would list all the text files; "DIR A,D2" would list all of the Applesoft files on drive 2; "CAT B,S5,D1" would list all the binary files on slot 5, drive 1. Yes, "DIRT" works just fine.

I added the TYPE command, which allows you to display the contents of text files. Both CATALOG and TYPE will optionally:

1. Print "hidden" control characters as inverse:
   POKE 234,0 to print as inverse (default)
   POKE 234,255 to function as-is
2. Lower case letters may be shifted to upper case:
   POKE -18700,255 no shift (default)
   POKE -18700,223 to shift lower to upper case.

You can slow down TYPE's output via SPEED=xx or POKE 241,xx; or pause by pressing any key; then Ctrl-Q to abort. Also, TYPE pauses and waits for a keypress when it encounters a hex 00 imbedded in the file or at end of file; press Ctrl-Q to quit. You may TYPE random text files by holding down REPT-SPACE to get past the hex 00's at the end of each logical record.

The listing that follows is intended for information only: it is not BRUNable. My intention is that you prepare the EXEC shown below to actually install the patches. Any word processor that produces a straight, sequential text file may be used to prepare the EXEC. Of course you can also use the S-C Macro Assembler for this purpose. Then, type EXEC WILDCAT to apply the patches to DOS 3.3 in memory. After checking it out and running any other tests you like, put in a new diskette, enter a HELLO program, and type INIT HELLO to "permanently" install WildCAT in the DOS on tracks 0, 1, and 2.

When I wrote WildCAT, I had two main goals in mind: it should be a (mostly in-place) code replacement, and it should be compatible with the known means of using (abusing?) the existing CATALOG code at $AD98-AE69.

One major design consideration was a mechanism for entering the ^string/type parameter. This required merely changing the "keyword parameter table" so CATALOG could have a "filename".

Next, a distinction had to be made between a "wildcard" and a "filetype" parameter. It made sense to 'delimit' the wildcard string; then the single-character filetype would be just that: a single character, entered without a delimiter. But this "phony" name mechanism has it's own problems:

First, "What's in a Name?" (DOS Manual p. 16): a filename has to start with a letter...which automatically eliminates most special characters (eg, equal, pound, slash, colon, etc) as the delimiter. The command parsing routine doesn't really know what it's working on at the time. All it knows is: if a name may be present, it must be valid. The validity test is only that the first character be equal to or greater that $C0 or an @-sign. The @-sign could have been used, but it's a problem on some 80-column boards; the ^ or caret works nicely (and besides, it looks good).

Second, now that we have a name (however, phony) and since the CATALOG command lives in the File Manager (FM) portion of DOS, there will be a buffer allocated for it. Unfortunately, the Command Interpreter (CI) DOCAT routine, which calls the FM, already "knows" that there will not really be a name, so it does not include housekeeping code to deallocate a buffer. So merrily allocating files without closing them...after the third time: NO BUFFERS AVAILABLE. And naively adding CLOSE (even if there were room for it), would have one very undesirable side effect if a "regular" catalog were requested: CATALOG-CLOSE without FNAME will close all open files. WildCAT instead plays a little shell game with DOS: The new DOCAT routine saves the first character of FNAME and substitutes a zero. Thereafter, neither the File Manager nor the rest of DOS ever knows that a name has been entered, so FM never actually allocates a buffer.

Third, what really should happen if a phony name is not entered? A regular catalog, of course, but how would this be indicated to WildCAT? Well, the shell game has a sting. Early on when the CI PARSE routine discovers that a filename is a valid parameter, it first clears FNAME to all blanks, expecting to fill it in with whatever comes in next. If a comma or carriage return comes in next, then FNAME still contains the blank; and that's what WildCAT saves off (under the shell) before it substitutes the zero.

Thus, the "sting" is that the CI "tricks" itself into telling WildCAT what to do in the absence of a ^string/type specifier: WildCAT takes a blank to indicate "do a regular" catalog; just as positively as a "^" indicates "do a wildcard" catalog, and a single character indicates "do a filetype" catalog.

The blank indicator also helps satisfy the second goal above and solves the problem of compatibilty with the "known means" of using/abusing the existing CATALOG code. WildCAT simply has to put a blank under the shell at each of the points where the code could most reasonably be entered without going thru the Command Interpreter's new DOCAT routine. That's exactly what all the JSR's to the routine AllowENTry are doing.

Satisfying that second goal takes up a lot of space, however; and has somewhat undermined the first constraint: WildCAT certainly isn't "in-place" in one place! And I apologize for this rather bizarre, serpentine code; I do hope that now you understand why some things were done the way they were.

Although considerable effort was spent to maintain compatibilty with the existing DOS commands, there were some compromises:

1. While the DOS manual (page 22) states: "To specify drive 1, you use the notation D1 separated from the file name by a comma", you can in fact leave out the comma between CATALOG and D1. With WildCAT that comma is now required; otherwise, it would take the "D" as a filetype and try to find it ... which of course it wouldn't and there would be no files reported. This would also be a problem for Applesoft programs that do something like: PRINT D$"CATALOG D1" without the comma. Therefore, WildCAT issues a (late) "SYNTAX ERROR" message if it encounters an undelimited string of length 2 or more.

2. CATALOG is a favorite routine to execute directly, bypassing the DOS Command Interpreter. FID, for example, provides its CATALOG via the "external" entry to the File Manager, which means that the main entry at CATHNDLR must provide for a "regular" catalog. It is also possible from machine language, however, to bypass both the CI and the FM. This usually involves changing the exit JMP address at DONEXT2 (to return to the user's code) and then jumping directly into almost anywhere in the CATALOG code (see the Listing 1 labels that begin "at"). I believe most of these cases are covered, but you may find some programs, which provide an "internal" CATALOG, that just won't work with WildCAT.

3. In order to both gain some patch space and provide the DIR/CAT short-form command name, the DOS command POSITION was eliminated. You may have to look it up just to find out that it is, much less what it is. Its relative rarity may be due to its implementation: it, like APPEND, finds its way through the file one byte at a time...all day long. Any program that uses it will now get a syntax error. If POSITION is really needed, it can be readily simulated by programming a read-loop to discard N-1 fields before processing the desired Nth field.

The following is a brief commentary on the assembly listing. The paragraph numbers correspond to numbers in comment lines.

The page zero locations I used ($EB thru $EF) are free, i.e. not used by DOS, the Monitor, or the Basics.

(1) In CMDTBL, replace Integer CHAIN address with TYPE and DOCAT address with NewDOCAT.

(2) Rearrange some code (and change both references to it) to add a "print blank" capability. The Command Interpreter uses its own vector to a "COUT" routine via CSW at $36; however, the File Manager (previously) used the Monitor COUT and CROUT routines for printing the catalog. With WildCAT all of DOS now consistently uses the vector at $9FCA for output; plus it has a new BlankOUT routine, all within the original code space.

(3) Recode a very cumbersome form of the "indexed indirect jump" to use register Y and leave X (which is zero by a previous operation) so it can be used in NewDOCAT.

(4) Replace old DOCAT's 12 bytes of code with a JMP to NewDOCAT and use the remainder to space over to column 7 after the file length has been displayed.

(5) NewDOCAT saves the first character of FNAME and substitutes a zero to prevent buffer allocation. It then loads 13, the new Catalog Function Code, and proceeds to CMDHNDLR2. Function 13 enters the catalog code past the "allow for irregular, direct entry".

(6) In the keyword parameter table, change parms to allow a filename with CATALOG and a filename, drive, and slot with DIR. Set new Function 13 address (previously a "no-op" to NOERROR) to WildCAT and change the range check to 14 to allow for it.

(7) Replace the Integer CHAIN code; PrtLOCK displays an asterisk or blank if the file is locked or not.

(8) Shorten the "NO BUFFERS AVAILABLE" message to "NO BUFFER" and re-use the space to decide which Basic is active, then JMP to the appropriate decimal print routine; used to print the free sector value and catalog filesizes. The value to be printed has been previously loaded into A and X.

(9) First, eliminate the need for "NOT DIRECT COMMAND" error message and then re-use the space to check for a "regular" catalog (no filename) or for a catalog by filetype (undelimited, single character). If more than a single, non-blank character is detected (ie, 2nd byte of FNAME is not blank), then "SYNTAX ERROR" message is issued.

(10) At beginning of catalog code allow for most normal points where the code could be directly entered. The new "official" Function 13, WildCAT initializes the FM workarea (per normal) and branches to Read VTOC to "find" the first catalog sector.

(11) Freespace "prolog"; clear carry and branch around another likely "irregular" entry point. Read first/next catalog sector, then lookup and save the filetype. Setup Y with 30 for name length and branch to CkFNAME.

(12) AllowVTOC fakes a "regular" catalog and falls into a JSR to read the VTOC. The BCC to initialize linecount is always taken; only if there had been an I/O error would the carry be set, in which case, control would have passed to the error-message-print exit anyway.

(13) PrtCat displays a catalog line. Note that loc $24, CH, is "POKEd" with 7 for uniform spacing over to the filename. If your printer interface board or 80-column card do not support this convention, then the display will not be properly spaced. The DONEXT routine is unchanged. SKIPLN has been re-arranged to allow init linecount, put out a carriage return, and check for a keypress (Ctrl-Q to quit) after 22 lines. Note: This leaves the cursor in column 37; see below.

(14) CkFNAME "looks under the shell" to figure out what to do. A caret indicates to check for a wildcard string. After JSR to CkCAT, if the equal status is set, then branch to print the catalog line. DoWild checks for the occurence of the wildcard string within the filename. $B4C9,X indexes the name in the Catalog Sector; $AA75,Y indexes the wildcard string; CatNmLen counts from 30 to 0, to scan the whole name.

(15) FreeSpce counts the free sectors, as indicated by the VTOC, loads X and A with the count, and JMPs ToPrtDec.

(16) WaitCk79 provides the "wait" for TYPE; also checks and puts out a carriage return after 79 characters to avoid overprinting long lines on certain printers, such as the MX-80.

(17) TYPE displays the contents of a sequential or random text file. A keypress will pause the display, and Ctrl-Q quits.

(18) InvCOUT is used by both CATALOG and TYPE. It converts hi-bit off characters to proper inverse. It will optionally show control characters as inverse or allow them to "function" as-is; and it will optionally "shift" lower case letters to upper case, if you do not have a lower case adapter; see "...Options" above. Loc $EA, decimal 234, is the Applesoft Hi-Res collision counter; it should always be zero, unless you POKE it.

(19) WaitCQ waits for a keypress and sets the equal status, if Ctrl-Q was pressed.

(20) Replace the inverted phrase DISK VOLUME with FREE SPACE=.

(21) The DOSCMDS list is moved down 6 bytes. AllowENT re-uses these 6 bytes to force a blank in FName1 "under the shell" to ease "irregular" entries into the catalog code; and clears the carry in case the entry was 'atADC9' which also cleared the carry. In the command list, TYPE replaces CHAIN and DIR replaces POSITION; change $A8BF:43 41 D4 to replace with CAT.

(22) Change the two references to DOSCMDS to the new location. These two changes must be done last as the EXEC is changing the very code that is executing.

I would like to thank Lee Reynolds and Art Schumer for their helpful comments and suggestions.

      1000 *SAVE S.WILDCAT
      1010 *--------------------------------
      1020 CatLnCnt   .EQ $EB Catalog Linecount
      1030 FType      .EQ $EC Hold looked-up filetype
      1040 FName1     .EQ $EE Hold FNAME shell 1st char
      1050 CatNmLen   .EQ $ED CatName check-length=30
      1060 CatPtLen   .EQ $EF CatName print-length=30
      1070 *-----(1)----
      1080        .PH $9D26 In CMDTBL, command addresses,
      1090        .DA TYPE-1 change Integer CHAIN to TYPE
      1100        .PH $9D3E In CMDTBL, change address to
      1110        .DA NewDOCAT-1 new DOCAT in POSITION code
      1120 *-----(2)----
      1130        .PH $9FA8 In ECHO, change old COUT ref
      1140        .DA #$CA was JSR $9FC5 now JSR $9FCA
      1150        .PH $9FC5 Cleanup CDI COUT and CROUT
      1160 BlankOUT LDA #" " and add BLANK out routine
      1170        .DA #$2C fake BIT-NOP on fall-thru
      1180 CROUT  LDA #$8D  DOS vectored CROUT; same loc
      1190 COUT   JMP ($36) DOS vectored COUT; new loc
      1200        .PH $A710 In PRTERROR, change old COUT
      1210        .DA #$CA was JSR $9FC5 now JSR $9FCA
      1220 *-----(3)----
      1230        .PH $A186 Cleanup DOCMD; X=0 in NewDOCAT
      1240        LDY $AA5F CMDINDX
      1250        LDA $9D1F,Y CMDTBL+1; use Y instead of X
      1260        PHA
      1270        LDA $9D1E,Y CMDTBL
      1280        PHA
      1290        RTS
      1300        NOP
      1310 *-----(4)----
      1320        .PH $A56E Replace old DOCAT code:
      1330 OldDOCAT JMP NewDOCAT To allow for direct entry
      1340 PrtTYPE LDA FType Print looked-up filetype
      1350        JSR COUT and
      1360        JMP BlankOUT a blank
      1370        NOP
      1380 *-----(5)----
      1390        .PH $A5DD Replace old POSITION code:
      1400 NewDOCAT LDA $AA75 FNAME set by CATALOG command
      1410        STA FName1 save first byte, then zero
      1420        STX $AA75 to avoid buffer allocation
      1430        LDA #13 FM WildCAT Function Code
      1440        JMP $A2AA CMDHNDL2 routine, per usual
      1450        NOP
      1460 *-----(6)----
      1470        .PH $A921 DIR [string] [,Dn] [,Sn]
      1480        .DA #$60,$70 ->First comma: is NOT optional
      1490        .PH $A929 CATALOG [string] <[,Dn] [,Sn]>
      1500        .DA #$60 ->Must be CATALOG,D1 or DIR,D2
      1510        .PH $AAE3 In FM function table, "borrow"
      1520        .DA WildCAT-1 otherwise useless address
      1530        .PH $AB10 Change range check from 13 for
      1540        CMP #14 above now USEFULL address
      1550 *-----(7)----
      1560        .PH $A4F0 Replace Integer CHAIN code
      1570 PrtLOCK LDA #" " blank=unlocked
      1580        LDX $B4C8,Y Catalog Filetype entry
      1590        BPL ToPrint
      1600        LDA #"*" *=locked
      1610 ToPrint JMP COUT Print " " or "*" indicator
      1620 *-----(8)----
      1630        .PH $A9FD Shorten NO BUFFER[S AVAILABLE]
      1640        .AS -"R" to free 11 bytes for ToPrtDec:
      1650 ToPrtDec BIT $E006 Check which Basic...
      1660        BMI ToInt Integer or
      1670        JMP $ED24 Applesoft; use appropriate
      1680 ToInt JMP $E51B print decimal routine
      1690 *-----(9)----
      1700        .PH $A021 Replace JSR ISBASRUN to allow
      1710        NOP  ALL commands entered direct
      1720        NOP  then error msg is redundant so
      1730        NOP  ok to re-use msg space below
      1740        .PH $AA2C Replace NOT DIRECT COMMAND msg
      1750 CkCAT CMP #" " If blank, do regular catalog
      1760        BEQ ToRTS
      1770        LDY #" " Must be single-char filetype
      1780        CPY $AA76 FNAME+1, ie blank afterwards
      1790        BEQ CkType if catalog by filetype; else
      1800        JMP $A6C4 CSYNTAX error
      1810 CkType CMP FType Does filetype match?
      1820 ToRTS RTS
      1830        NOP
      1840        NOP
      1850 *----(10)----
      1860        .PH $AD98
      1870 CATHNDLR JSR AllowENT Allow for non-CDI entry
      1880 WildCAT JSR $ABDC Init File Manager Workarea
      1890        BNE ToRWVTOC
      1900 atADA0 JMP AlowVTOC Allow for non-CDI entry
      1910 atADA3 NOP  Allow for non-CDI entry and
      1920        NOP  alignment
      1930 atADA5 JSR AllowENT Allow for non-CDI entry
      1940 atADA8 JSR AllowENT Allow for non-CDI entry
      1950 atADAB JSR InitCR Init Linecount; output C/R
      1960 *----(11)----
      1970        JSR SKIPLN
      1980        LDX #12
      1990 PrtFreSP LDA FreeMsg-1,X
      2000        JSR COUT Print " FREE SPACE="
      2010        DEX
      2020        BNE PrtFreSP X=0 for PrtFreSP
      2030        JSR FreeSpce Count & print free sectors
      2040        JSR SKIPLN
      2050        JSR SKIPLN
      2060        CLC  Setup for RDNXTDIR to read
      2070        BCC RDNXTDIR first sector; always branch
      2080        NOP  alignment
      2090 atADC9 JSR AllowENT Allow non-CDI, non-FM entry
      2100 RDNXTDIR JSR $B011 RDDIRSEC
      2110        BCS DONEXT2
      2120        LDX #0
      2130 GTRKNUM STX $B39C DIRINDX
      2140        LDA $B4C6,X Track part of T/S list
      2150        BEQ DONEXT2 If End of Catalog, then exit
      2160        BMI DONEXT If Deleted File, then skip it
      2170        LDA $B4C8,X Catalog Filetype
      2180        ASL  ;skip hi-bit LOCK/UNLOCK flag
      2190        LDY #7
      2200 FindTYPE ASL
      2210        BCS GotTYPE
      2220        DEY
      2230        BNE FindTYPE
      2240 GotTYPE LDA $B3A7,Y From filetype table,
      2250        STA FType save looked-up filetype
      2260        LDY #30 Check CatName length and
      2270        STY CatPtLen Print CatName length
      2280        BNE CkFNAME always BNE
      2290 *----(12)----
      2300 AlowVTOC JSR AllowENT Allow for non-CDI entry
      2310 ToRWVTOC JSR $AFF7 RWVTOC read VTOC
      2320        BCC atADAB always; carry set=I/O ERROR
      2330 *----(13)----
      2340        NOP  ;alignment
      2350        NOP
      2360 PrtCAT LDY $B39C Restore Y from DIRINDX
      2370        JSR PrtLOCK Print Lock indicator
      2380        JSR PrtTYPE Print filetype and BlankOUT
      2390        LDX $B4E7,Y Filesize
      2400        LDA $B4E8,Y Filesize+1
      2410        JSR ToPrtDec Print "true" filesize
      2420        LDY #7 "Poke" CH with 7 to "tab"
      2430        STY $24 over for filename spacing
      2440        LDX $B39C Restore X from DIRINDX
      2450 PrtFN LDA $B4C9,X Print Catalog Filename
      2460        JSR InvCOUT with optional conversions
      2470        INX
      2480        DEC CatPtLen CatName print length
      2490        BNE PrtFN
      2500        JSR SKIPLN
      2510 DONEXT JSR $B230 NXTDIREN...atAE25
      2520        BCC GTRKNUM
      2530        BCS RDNXTDIR
      2540 DONEXT2 JMP $B37F NOERROR....atAE2C
      2550 SKIPLN DEC CatLnCnt Linecount..atAE2F
      2560        BNE ToCR If not zero, C/R & return
      2570        JSR WaitCQ else wait for keypress
      2580        BEQ DONEXT2 If Ctrl-Q, exit to NOERROR
      2590 InitCR LDA #22-1 else setup for next 22 lines
      2600        STA CatLnCnt in line count
      2610 ToCR JMP CROUT DOS vectored C/R out
      2620 *----(14)----
      2630 CkFNAME LDA FName1 Holds FNAME first character
      2640        CMP #"^" Wildcard string?
      2650        BEQ DoWild yes...maybe
      2660        JSR CkCAT Regular or by filetype?
      2670        BEQ PrtCAT yes...else
      2680        BNE DONEXT none of the above
      2690 DoWild STY CatNmLen CatName length=30, for NotEQ
      2700        LDY #1 Decr'd to 0; indexes FNAME
      2710 NotEQ DEC CatNmLen Checked all 30 chars?
      2720        BMI DONEXT Yes; no match, do next CatName
      2730 BackDown DEX  Backdown to string match start
      2740        DEY  Backdown to 0, ie. FNAME start
      2750        BNE BackDown
      2760 YesEQ INY  First Y=1, then on past "^"
      2770        INX
      2780        LDA $AA75,Y FNAME
      2790        CMP #" " If blank then wildcard EOS and
      2800        BEQ PrtCAT still =, so we have a match!
      2810        CMP $B4C9,X FNAME = CatName?
      2820        BEQ YesEQ
      2830        INX  No, setup X to backdown 1 past
      2840        BNE NotEQ string match start; always BNE
      2850        NOP
      2860 *----(15)----
      2870        .PH $BA69 Catalog Free Space Patch
      2880 FreeSpce STX $44 X=0
      2890        STX $45 Init Free Sec Count var
      2900        LDY #50*4 VTOC entries * entry length
      2910 NxBitMap LDA $B3F2,Y BITMAP-1 in VTOC buffer
      2920 CkFree ASL  ;shift hi-order bit into CARRY
      2930        BCC CkMore In use, so check if any more
      2940        INC $44 Incr free sector count
      2950        BNE CkFree Zero means > 255, so
      2960        INC $45 incr "page" part of word
      2970 CkMore BNE CkFree More bits in same byte?
      2980        DEY  decr index to next VTOC byte
      2990        BNE NxBitMap All done?
      3000        LDX $44 Yes, so setup count in X & A
      3010        LDA $45 for decimal print via
      3020        JMP ToPrtDec one of the BASICs
      3030 *----(16)----
      3040 WaitCk79 JSR $FCA8 Monitor WAIT routine
      3050        DEC $55 Decr char cnt
      3060        BNE $BA10 Fortuitous RTS; else fall thru
      3070 InitLine LDA #79 TYPE prolog/setup
      3080        STA $55 Init printer 80-col char cnt
      3090        JMP CROUT
      3100        NOP
      3110 *----(17)----
      3120        .PH $B6B3
      3130 TYPE JSR $A2A3 DOS Open file
      3140 DoInitLn JSR InitLine Init char cnt & CROUT
      3150 ToRead JSR $A68C DOS Read char
      3160        BEQ ToWaitCQ EOF maybe...Ctrl-Q quit?
      3170        CMP #$8D Carriage return?
      3180        BEQ DoInitLn Yes, handle immediately
      3190        JSR InvCOUT Optional Ctrls & Hibit=0 INV
      3200        LDA $F1 Applesoft SPEED=nn byte
      3210        JSR WaitCk79 Wait SPEED; 79 chars yet?
      3220        LDA $C000 Has a key been pressed?
      3230        BPL ToRead No, read on
      3240        STA $C010 Reset keyboard strobe
      3250 ToWaitCQ JSR WaitCQ Wait keypress, check Ctrl-Q?
      3260        BNE ToRead If not Ctrl-Q, read on
      3270        JMP $A2FC DOS Close, Deallocate, Exit
      3280 *----(18)----
      3290 InvCOUT TAY  If < $80, then hibit off
      3300        BPL SetINV so set inverse flag & convert
      3310        CMP #$A0 Ctrl-char?
      3320        BCS CkLoCase No
      3330        BIT $EA Usually, loc 234 contains 0:
      3340        BMI CkLoCase POKE 234,255 skips conversion
      3350 SetINV LSR $32 Set Inverse by shifting 0 into
      3360        LSR $32 INVFLG first 2 bits; set carry
      3370        AND #$3F Turn off 1st 2 bits maps down
      3380        ADC #$1F maps up into hibit-on part of
      3390        EOR #$E0 upper-case screen-char range
      3400 CkLoCase CMP #$E0 Lower-case?
      3410        BCC ToCOUT No; but POKE -18700,223 or
      3420        AND #$FF B6F4:DF shifts l.c. to U.C.
      3430 ToCOUT JSR COUT DOS vectored COUT
      3440        LDA #$FF
      3450        STA $32 Set normal video; always
      3460        RTS
      3470 *----(19)----
      3480        .PH $B78D Wait keypress; check Ctrl-Q
      3490 WaitCQ JSR $FD0C Monitor RDKEY
      3500        CMP #$91 Was it Ctrl-Q?
      3510        RTS
      3520 *----(20)----
      3530        .PH $B3AF Replace: DISK VOLUME inverted
      3540 FreeMsg .AS -"=ECAPS EERF " with FREE SPACE=
      3550 *----(21)----
      3560        .PH $A884 Setup FName1 for "irregular"
      3570 AllowENT LDA #" " entry into CATALOG code
      3580        STA FName1 Force blank at CkFNAME above
      3590        CLC  For possible RDNXTDIR entry
      3600        RTS
      3610 DOSCMDS .AT 'INIT' Move down DOSCMDS table and
      3620        .AT 'LOAD' re-use the freed space above
      3630        .AT 'SAVE'
      3640        .AT 'RUN'
      3650        .AT 'TYPE' was CHAIN
      3660        .AT 'DELETE'
      3670        .AT 'LOCK'
      3680        .AT 'UNLOCK'
      3690        .AT 'CLOSE'
      3700        .AT 'READ'
      3710        .AT 'EXEC'
      3720        .AT 'WRITE'
      3730 atA8BF .AT 'DIR' was POSITION; for CAT:43 41 D4
      3740 *----(22)----
      3750        .PH $9FFB In Command Interpreter PARSE
      3760        LDA DOSCMDS,Y DOSCMDS table ref. was $A884
      3770        .PH $9FED Only 2 references to DOSCMDS
      3780        EOR DOSCMDS,Y DO THIS AFTER ABOVE CHANGES!
      3790 *--------------------------------

         MON I
         CALL -151
         9D26:B2 B6
         9D3E:DC A5
         9FA8:CA
         9FC5:A9 A0 2C A9 8D 6C 36 00
         A710:CA
         A186:AC 5F AA B9 1F 9D 48 B9
             :1E 9D 48 60 EA
         A56E:4C DD A5 A5 EC 20 CA 9F
             :4C C5 9F EA
         A5DD:AD 75 AA 85 EE 8E 75 AA
             :A9 0D 4C AA A2 EA
         A921:60 70
         A929:60
         AAE3:9A AD
         AB10:C9 0E
         A4F0:A9 A0 BE C8 B4 10 02 A9
             :AA 4C CA 9F
         A9FD:D2 2C 06 E0 30 03 4C 24
             :ED 4C 1B E5
         A021:EA EA EA
         AA2C:C9 A0 F0 0C A0 A0 CC 76
             :AA F0 03 4C C4 A6 C5 EC
             :60 EA EA
         AD98:20 84 A8 20 DC AB D0 57
             :4C F4 AD EA EA 20 84 A8
             :20 84 A8 20 38 AE
         ADAE:20 2F AE A2 0C BD AE B3
             :20 CA 9F CA D0 F7 20 69
             :BA 20 2F AE 20 2F AE
         ADC5:18 90 04 EA 20 84 A8 20
             :11 B0 B0 5B A2 00 8E 9C
             :B3 BD C6 B4 F0 51 30 48
         ADDD:BD C8 B4 0A A0 07 0A B0
             :03 88 D0 FA
         ADE9:B9 A7 B3 85 EC A0 1E 84
             :EF D0 4B
         ADF4:20 84 A8 20 F7 AF 90 AF
         ADFC:EA EA AC 9C B3 20 F0 A4
             :20 71 A5
         AE07:BE E7 B4 B9 E8 B4 20 FE
             :A9 A0 07 84 24 AE 9C B3
         AE17:BD C9 B4 20 DA B6 E8 C6
             :EF D0 F5 20 2F AE
         AE25:20 30 B2 90 A9 B0 A0 4C
             :7F B3
         AE2F:C6 EB D0 09 20 8D B7 F0
             :F4 A9 15 85 EB 4C C8 9F
         AE3F:A5 EE C9 DE F0 07 20 2C
             :AA F0 B4 D0 D9
         AE4C:84 ED A0 01 C6 ED 30 D1
             :CA 88 D0 FC C8 E8 B9 75
             :AA C9 A0 F0 9D DD C9 B4
             :F0 F2 E8 D0 E7 EA
         BA69:86 44 86 45 A0 C8 B9 F2
             :B3 0A 90 06 E6 44 D0 F9
             :E6 45 D0 F5 88 D0 EF A6
             :44 A5 45 4C FE A9
         BA87:20 A8 FC C6 55 D0 82 A9
             :4F 85 55 4C C8 9F EA
         B6B3:20 A3 A2 20 8E BA 20 8C
             :A6 F0 14 C9 8D F0 F4 20
             :DA B6 A5 F1 20 87 BA AD
             :00 C0 10 EA 8D 10 C0 20
             :8D B7 D0 E2 4C FC A2
         B6DA:A8 10 08 C9 A0 B0 0E 24
             :EA 30 0A 46 32 46 32 29
             :3F 69 1F 49 E0
         B6EF:C9 E0 90 02 29 FF 20 CA
             :9F A9 FF 85 32 60
         B78D:20 0C FD C9 91 60
         B3AF:BD C5 C3 C1 D0 D3 A0 C5
             :C5 D2 C6 A0
         A884:A9 A0 85 EE 18 60
         A88A:49 4E 49 D4 4C 4F 41 C4
             :53 41 56 C5 52 55 CE 54
             :59 50 C5
         A89D:44 45 4C 45 54 C5 4C 4F
             :43 CB 55 4E 4C 4F 43 CB
         A8AD:43 4C 4F 53 C5 52 45 41
             :C4 45 58 45 C3 57 52 49
             :54 C5
         A8BF:44 49 D2
         9FFB:B9 8A A8
         9FED:59 8A A8
         48:04 N 3D0G
         NOMON I

Mitsubishi 50740 Series | Bob Sander-Cederlof

I received information from several sources this week about an interesting new branch of the 6502 tree. Mitsubishi has published specs for eight varieties, all part of the "740 series". The chip is based on the 6502, adds some new addressing modes for some of the standard 6502 opcodes, and adds 13 new opcodes. (Unfortunately, the opcode enhancements are not compatible with any of the other enhanced 6502s.)

The chips in the 740 series are intended for use as microcontrollers. As such, most of them have on-chip RAM and ROM. They all have built-in I/O ports, timers, and other goodies. The most interesting (to Don Lancaster, Nigel Nathan, and me) is the M50734. This chip, said to cost only $12, has four A/D converters, UART, six timers, a serial I/O port, four 8-bit I/O ports, a pair of stepper-motor drivers, and more. It all lives in a 64-pin shrink-DIP package. The M50734 is the only one in the 740 series which has no internal ROM and RAM. It is CMOS. The clock runs at 8 MHz, which in effect runs the opcodes at 2 MHz (that is, two cycle instructions take one microsecond).

To control all these functions, the bytes in page zero from $DA through $FF are used as I/O, control, and status registers.

One of the trickiest enhancements allows direct access (without bank switching or bank registers) to a second 64K memory, for data only. Apparently one of the address modes changes the state of one of the output signals during data memory references; if you use that signal to enable another bank of memory. ALMOST like having direct-addressability of 128K.

The data bus is multiplexed with half of the address bus, so it's a little harder to interface. Naturally, to get all the functions I mentioned above with only 64 pins, there have to be shared pins. Depending on which functions you are using, some of the timers and some of the I/O pins have dedicated uses.

The 6502 has one unused status bit. The 740 series calls this the T-flag, and gives it a use. If T=1, a special address mode is enabled which allows memory-to-memory operations without using the A-register. As I understand it, when T=1, address modes which use X as an index register take on a new meaning: rather than moving data between the indexed address and the A-register, data is moved between the absolute address and the zero page location whose address is in the X-register. If I am correct, ADC $400,X (assume X contains $34) would add the contents of $400 to the contents of $34, and store the result in $34. If T=0, indexing works in the old-fashioned 6502 way.

Another powerful enhancement allows you call subroutines with a two-byte version of the JSR opcode. One variation uses vectors stored in page zero, and the other uses vectors stored $FF00 through $FFF3. JMP can also uses vectors stored in page zero, so you have a two-byte JMP indirect.

Four new opcodes give you the ability to set, clear, or test any bit in the A-register or in page zero. This uses up 64 opcodes, because the bit number and bit state are coded into the opcode byte. Rockwell's version of the 65C02 includes page-zero bit-addressing, but the opcodes are not the same.

There are other new instructions, including several about which I do not have accurate complete information.

           RRF zp     (I think it swaps nybbles in the byte)
           COM zp     (Probably forms 2's complement at zp)
           LDM zp     (Probably loads ABS(zp) into A-register)
           CLT        clear T-bit in status
           SET        set T-bit in status
           STP        stop the clock until reset or interrupt
           WIT        low power mode   "     "   "      "
           SLW        (slow?)
           FST        (fast?)
           INC        increment A-reg
           DEC        decrement A-reg
           BRA rel    branch always.

Of all the extensions, only ONE (BRA) is compatible with the standard 65C02 and 65816 extensions from Western Design Center (the OFFICIAL source for 6502 designs). The others, even if they do the same thing, use a different opcode value. Why?

If you have worked up an appetite for more information on the 740 series, contact Mitsubishi. I don't have all their numbers, but you can get close by calling 1-800-421-1132.

When we get all the data, we will be writing a Cross Assembler so you can use your Apple to develop software for this chip.

Faster Cyclic Redundancy Checking | Bob Sander-Cederlof

In the April 1984 issue of AAL I showed how to compute a cyclic redundancy check code (CRC) for a buffer full of data. I also tried to explain a little of the theory, as much as I understood. In the June 1984 issue Bruce Love explained how to work backward from the computed CRC of a received buffer to correct a single bit error. Both of these programs were written in plain 6502 code.

In the February 1986 "Dr. Dobb's Journal" Terry Ritter writes about "The Great CRC Mystery". He also presents some Pascal programs and 8088 machine code programs for calculating the CRC in various ways. Terry describes very briefly a table driven method (the very fastest way) and a byte-oriented method (almost as fast as table-driven).

I translated Terry's machine-coded byte-oriented method from 8088 to 65802 code, but even after twiddling and tweaking for half a day I could not make it give the correct answers. I don't know if his method is correct or not, but of course it MUST be, since it is printed in Dr. Dobb's and since he claims it works and since he even tells how many milliseconds it takes.

Anyway, I decided to derive my own byte-oriented method. The CRC algorithm is basically a "long division" of the entire bit stream in the buffer as though it were one long binary word. The divisor is $11021 in the CCITT scheme. The check code we use is the remainder of the division. The normal algorithm does "long division" on a bit-by-bit basis. The byte-oriented algorithm does "long division" on a byte-by-byte basis.

I put long division in quotation marks above because it is not EXACTLY long division. The difference is that the subtraction steps are replaced with exclusive-or operations. The exclusive-or is performed whenever the leading bit of the new dividend is a 1-bit. Here is a fully worked out example, for a CRC-so-far = $E1F0, and the next byte = $CC:

           "divide"   $E1F0CC by $11021, "quotient bits" down
           the left edge.  Next CRC is the "remainder"

           1110 0001 1111 0000 1100 1100   (E1F0CC in binary)
    1  eor 1000 1000 0001 0000 1           (11021 in binary)
           ---------------------
            110 1001 1110 0000 01
    1   eor 100 0100 0000 1000 01
            ---------------------
             10 1101 1110 1000 000
    1    eor 10 0010 0000 0100 001
             ---------------------
    0         0 1111 1110 1100 0010
                1111 1110 1100 0010 1
    1     eor   1000 1000 0001 0000 1
                ---------------------
                 111 0110 1101 0010 01
    1      eor   100 0100 0000 1000 01
                 ---------------------
                  11 0010 1101 1010 000
    1       eor   10 0010 0000 0100 001
                  ---------------------
                   1 0000 1101 1110 0010
    1        eor   1 0001 0000 0010 0001
                   ---------------------
                     0001 1101 1100 0011 = $1DC3

Note that the "quotient" is $EF. This "quotient" can always be exactly computed by using just the first byte of the dividend (the high byte of the old CRC code): quotient = crchi .eor. crchi/16. If you carefully study the worked out example above, you should be able to see why this is true. Now, if we use the exclusive-or rather than addition to perform a multiplication of the quotient times $11021, it will look like this:

                          uuuu.vvvv  (symbolic quotient in binary)
                           x $11021  (multiplier in hexadecimal)
                           --------
                          uuuu.vvvv
                   u.uuuu.vvv0
           uuuu.vvvv
      uuuu.vvvv
      -----------------------------
        whatever........

There are several significant things to notice about the multiplication above. First, we only need to save the rightmost 16 bits of the "product". If we exclusive-or those bits with the rightmost 16 bits of the original dividend (which means the low byte of the old CRC followed by the new byte), we will get the next CRC. (This trick relies on the fact that exclusive-or is a reversible operation, so that "adding" and "subtracting" give the same result!)

Furthermore, we can organize those "partial products" in a more efficient way for computation. Now, let's write the original CRC symbolically as "aaaa.bbbb.cccc.dddd", and the next data byte as "eeee.ffff". The "quotient" after "dividing" by $11021 will be "aaaa.bbbb exclusive-or 0000.aaaa"; let's write that symbolically as "aaaa.gggg". Then we can compute the next CRC code by the following very simple steps:

           cccc.dddd.eeee.ffff
      eor  gggg.0000.aaaa.gggg
      eor  000a.aaag.ggg0.0000
           -------------------
           wwww.xxxx.yyyy.zzzz

Believe it or not!

The program that follows implements this algorithm, in lines 1550-1760. I used 65802 code, but it really could be done quite nicely in plain 6502 as well. I leave it as "an exercise for the reader" (as college textbooks are wont to say), should you wish to try the algorithm in a plain-vanilla 6502.

The SEND and RECV programs simulate sending and receiving a buffer-full of data. I chose to put my buffer at $4000, for 258 bytes. This is the same as in the April 1984 article.

The FIND.BAD.BIT program is simply a translation of Bruce Love's 1984 program into 65802 code. Thanks to 16-bit registers, it is significantly faster and shorter.

Speaking of speed, the code for computing the next CRC code for one new byte takes (if I counted correctly) 57 clock cycles. In a normal Apple that means about 56 microseconds. The time for 8088 machine code in Terry Ritter's article was 17 microseconds for the equivalent steps. He was running with a 7.16 MHz clock. If you ran the 65802 code in an Applied Engineering Transwarp card or a Titan Accelerator card with a 4-MHz 65802 (running at 3.58 MHz), the time would be only 15.9 microseconds in an Apple.

      1000 *SAVE S.CRC.GENERATOR
      1010 *--------------------------------
      1020 BUFFER .EQ $4000
      1030 LIMIT  .EQ $4102
      1040 *--------------------------------
      1050 CRC    .EQ $00,01
      1060 PNTR   .EQ $02,03
      1070 TEMP   .EQ $0A,0B
      1080 *--------------------------------
      1090 PRNTAX .EQ $F941
      1100 CROUT  .EQ $FD8E
      1110 *--------------------------------
      1120 *      SIMULATE SENDING A BUFFER-FULL
      1130 *--------------------------------
      1140 SEND
      1150        LDA #0       CLEAR CRC BYTES IN BUFFER
      1160        STA LIMIT-1
      1170        STA LIMIT-2
      1180        JSR NEW.CRC.BUFFER    COMPUTE CRC OF 258 BYTES
      1190        LDX CRC      STORE CRC INTO LAST 2 BYTES
      1200        LDA CRC+1
      1210        STX LIMIT-1
      1220        STA LIMIT-2
      1230        JSR PRNTAX   DISPLAY THE CRC
      1240        JMP CROUT    <RETURN> AND RETURN
      1250 *--------------------------------
      1260 *      SIMULATE RECEIVING A BUFFER-FULL
      1270 *--------------------------------
      1280 RECV
      1290        JSR NEW.CRC.BUFFER    COMPUTE CRC OF 258 BYTES
      1300        LDX CRC      DISPLAY CRC IN HEX
      1310        LDA CRC+1
      1320        JSR PRNTAX
      1330        JMP CROUT
      1340 *--------------------------------
      1350        .OP 65802
      1360 *--------------------------------
      1370 *      CRCH      CRCL      DATA
      1380 *   aaaa.bbbb.cccc.dddd.eeee.ffff
      1390 *  +0000.aaaa
      1400 *   ---------
      1410 *   aaaa.gggg
      1420 *            +gggg.0000.aaaa.gggg
      1430 *            +000a.aaag.ggg0.0000
      1440 *             -------------------
      1450 *             (crchi)   (crclo)
      1460 *--------------------------------
      1470 NEW.CRC.BUFFER
      1480        CLC
      1490        XCE
      1500        REP #$30     M&X BOTH 16-BITS
      1510        LDA ##$FFFF
      1520        STA CRC      INITIALIZE CRC FOR BUFFER
      1530        LDX ##BUFFER POINT TO BUFFER
      1540 *--------------------------------
      1550 .1     SEP #$20     CRC=aaaabbbbccccdddd, DATA=eeeeffff
      1560        LDA CRC+1    aaaabbbb .eor. 0000aaaa = aaaagggg
      1570        LSR
      1580        LSR
      1590        LSR
      1600        LSR          0000aaaa
      1610        EOR CRC+1    aaaabbbb
      1620        XBA          AGXX
      1630        LDA #0       AG00
      1640        REP #$20
      1650        LSR
      1660        LSR
      1670        LSR          000a.aaag.ggg0.0000
      1680        STA TEMP
      1690        LSR          0000.aaaa.gggg.0000
      1700        EOR CRC      aaaa.bbbb.cccc.dddd = aaaa.gggg.kkkk.dddd
      1710        XBA          kkkk.dddd.aaaa.gggg
      1720        EOR TEMP     000a.aaag.ggg0.0000
      1730        SEP #$20
      1740        EOR 0,X        crchi.crclo
      1750        REP #$20
      1760        STA CRC
      1770 *--------------------------------
      1780        INX
      1790        CPX ##LIMIT
      1800        BCC .1
      1810        XCE
      1820        RTS
      1830 *--------------------------------
      1840 *   FIND BAD BIT BY BRUCE LOVE'S METHOD
      1850 *--------------------------------
      1860 DUMMY.CRC  .EQ $10,11
      1870 *--------------------------------
      1880 FIND.BAD.BIT
      1890        JSR RECV     RECEIVE, COMPUTING NEW CRC
      1900 *--------------------------------
      1910        CLC
      1920        XCE          ENTER NATIVE MODE
      1930        REP #$30     X,M 16 BITS
      1940        LDX ##$80F   X=BIT NUMBER
      1950        LDA ##1      START DUMMY CRC IN A-REG
      1960 .1     CMP CRC
      1970        BEQ .2       ...FOUND BAD BIT!
      1980        DEX          DECREMENT BIT NUMBER
      1990        BMI .2       ...WENT TOO FAR, COULDN'T FIND BAD BIT
      2000        ASL          SHIFT DUMY CRC
      2010        BCC .1
      2020        EOR ##$1021
      2030        BCS .1       ...ALWAYS
      2040 *--------------------------------
      2050 .2     TXA          BIT NUMBER
      2060        SEC
      2070        XCE
      2080        XBA
      2090        JMP PRNTAX
      2100 *--------------------------------

Correction to Fast Garbage Collector | Bob Sander-Cederlof

In the March 1984 AAL, Paul Shetler gave us a very fast garbage collector for Applesoft. Last week Keith Satterley called from Australia, and mentioned he thought there was a bug in the handling of strings over 128 characters long. I looked into it, and he is right.

The bug is in the loop in lines 3240-3320, on page 9 of that issue. The loop moves a string from one place in memory to another. The way we printed the code, a string longer than 128 characters would only have one byte moved! Here is the old code and the correct code, side-by-side:

    -----old code------------        -----correct code--------

    3240    LDY STRING.LENGTH        3240    LDY STRING.LENGTH
    3250    DEY                      3250 .3 DEY
    3260 .3 LDA (FRESPC),Y           3260    LDA (FRESPC),Y
    3270    STA (LOWTR),Y            3270    STA (LOWTR),Y
    3280    DEY                      3280    TYA
    3290    BPL .3                   3290    BNE .3
    3300    BMI .1                   3300    BEQ .1

Can you see why the new code works and the old doesn't?

DOS Patch: Prevent Direct Commands | Richard Gendron

I operate a AE/CATFUR line using my Apple and a modem in Montreal, Quebec. I have found that protecting your DOS from illegal entry can be a tough job to say the least.

In searching for ways to protect my system, I came across an interesting address in DOS: at $A026 there is some code which is executed whenever you try to type in a DOS command. The code checks to see if the command you typed is allowed as a direct command, and if not gives you the NOT DIRECT COMMAND message (or ERROR 15 if you are using DiversiDOS).

I have written a little patch that will catch you when you type a DOS command, and re-RUN the Applesoft program. If a sneaky caller finds a way to get out of the executing Applesoft program, at least he/she will be prevented from doing DOS commands.

Now every lock should have a key. You do want to be able to use your own DOS in direct mode, so I have included a way to turn off the protection. If you type "PRINT USR (0)" the system will respond with "PW:". Then enter a two-character password and the protection patch will be removed. Then you can CATALOG, DELETE, or whatever you want to do.

Since I use Diversi-DOS, and in both the 48K and 64K configurations, I set up my patching program so that it will work with both. The code which checks which version is loaded is in lines 1220-1260 and lines 1390-1410. If the output hook at $36,37 points up to $BDxx or higher, the 64K version must be running. Normal 48K DOS points to $9EBD.

These patches worked on my system, but yours may be a little different depending on which version of DOS you use. Examine carefully all the addresses I use inside DOS to see if yours is the same as mine before you try to use these patches.

      1000 *SAVE GENDRON DOS MODS
      1010 *--------------------------------
      1020 *  DOS PROTECTION FOR THE DIRECT COMMAND "ERROR 15"
      1030 *   WRITTEN BY RICHARD GENDRON FOR USE ON TRANSFERS ][
      1040 *  (514) 738-1247 (AE/CAT-FUR)
      1050 *--------------------------------
      1060        .OR $300
      1070 *--------------------------------
      1080 INSTALL
      1090        LDA #$4C     BUILD "USR" VECTOR
      1100        STA $0A      "JMP" OPCODE
      1110        LDA #USR
      1120        STA $0B
      1130        LDA /USR
      1140        STA $0C
      1150 *---MOVE DATA INTO DOS-----------
      1160        LDX #P1-PATCHES      POINT AT OUR PATCHES
      1170 ***    JMP PATCH.DOS
      1180 *--------------------------------
      1190 PATCH.DOS
      1200        LDA #$A026
      1210        STA $00
      1220        LDA $37      48K OR 64K DOS?
      1230        CMP #$BD     CARRY CLEAR IF 48K
      1240        LDA /$A026   ...48K
      1250        BCC .1       ...48K
      1260        LDA /$E026   ...64K
      1270 .1     STA $01
      1280        LDY #4       MOVE 5 BYTES
      1290 .2     LDA PATCHES,X
      1300        STA ($00),Y
      1310        DEX
      1320        DEY
      1330        BPL .2
      1340        RTS
      1350 *--------------------------------
      1360 REBOOT
      1370        SEI                  TURN OFF ANNOYING INTERRUPTS
      1380        JSR $03EA            RESET THE I/O HOOKS
      1390        LDA $37              LETS SEE WHICH DOS WE ARE USING
      1400        CMP #$BD             IS IT 64K DOS ?
      1410        BMI .1               SNIFF, NO IT IS NOT
      1420        BIT $C081            YES IT IS, SO TURN OFF THE LANGUAGE CARD
      1430        BIT $C081            TWICE, EVERYONE KNOWS WHY ?.
      1440        JSR $E316            DOS "CLOSE" ALL FILES
      1450        JMP $D566            NOW LET'S JUMP TO THE APPLESOFT "RUN"
      1460 .1     JSR $A316            DOS "CLOSE" ALL FILES (NO TROUBLE PLS)
      1470        JMP $A4FC            48K INTERNAL "DOS RUN"
      1480 *--------------------------------
      1490 USR
      1500        LDY #0               START OF LOOP COUNTER
      1510 .1     LDA PASSWORD,Y       GET PASSWORD TEXT
      1520        BEQ .2               ...END OF STRING
      1530        JSR PRINT            NO, SO PRINT IT
      1540        INY                  INCREMENT THE LOOP
      1550        BNE .1               FOREVER LOOP (NEVER CAN EXIT)
      1560 *--------------------------------
      1570 .2     JSR INPUT            ALL TEXT PRINTED SO LET'S GET A KEY
      1580        CMP #"*              WAS IT A "*" ? (OR WHATEVER YOU WANT)
      1590        BNE .4               NO IT WAS NOT , SO BYE BYE
      1600        JSR INPUT            YES IT WAS, SO GET ANOTHER KEY
      1610        CMP #".              WAS IT A "." (OR WHATEVER YOU WANT)
      1620        BNE .4               NO IT WAS NOT, SO BYE BYE
      1630 *--------------------------------
      1640        LDX #P2-PATCHES
      1650        JSR PATCH.DOS
      1660 .4     RTS                  WE HAVE FINISHED
      1670 *--------------------------------
      1680 *   TEXT TO BE PRINTED WHEN A
      1690 * "PRINT  USE(0)" COMMAND IS DONE
      1700 *        IN APPLESOFT
      1710 *--------------------------------
      1720 PASSWORD
      1730        .AS -"PW:"
      1740        .HS 00
      1750 *--------------------------------
      1760 *  INPUT AND PRINT SUBROUTINES
      1770 *--------------------------------
      1780 PRINT  JMP ($36)
      1790 INPUT  JMP ($38)
      1800 *--------------------------------
      1810 PATCHES
      1820        JMP REBOOT   CALL OUR NEW CODE
      1830        NOP          NEEDED FOR DIVERSI-DOS
      1840 P1     NOP
      1850 *--------------------------------
      1860        .HS A9023909    ORIGINAL CODE
      1870 P2     .HS A9
      1880 *--------------------------------
      9999        .LIF

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 $18 per year in the USA, sent Bulk Mail; add $3 for First Class postage in USA, Canada, and Mexico; add $14 postage for other countries. Back issues are available for $1.80 each (other countries add $1 per back issue for postage).

All material herein is copyrighted by S-C SOFTWARE CORPORATION, all rights reserved. (Apple is a registered trademark of Apple Computer, Inc.)